Compare commits

...

40 Commits

Author SHA1 Message Date
Nick O'Leary
5324244c55 Bump for 0.17.4 2017-07-10 13:16:13 +01:00
Nick O'Leary
993f1dc853 Add request node test case for POSTing 0 2017-07-09 12:18:05 +01:00
Patrik Åkerfeldt
d8a4e9e1ab Allow false and 0 in payload for httprequest (#1334) 2017-07-09 12:17:54 +01:00
Kazuhito Yokoi
b3ffd33507 Add file extension into flow name of library automatically (#1331) 2017-07-09 11:58:17 +01:00
Nick O'Leary
c93870316c Fix accessing global context from jsonata expressions
Fixes #1335
2017-07-09 10:40:23 +01:00
Nick O'Leary
fc9906624e Disable editor whilst a deploy is inflight
Fixes #1332
2017-07-08 21:16:52 +01:00
Nick O'Leary
ba6209ba54 Replace Unknown nodes with their real versions when node loaded 2017-07-08 17:30:17 +01:00
Nick O'Leary
f9769a73fe Retry auto-install of modules that fail
- introduces autoInstallModulesRetry - default 30000
 - backs off interval if repeated failures
 - fixes notification to the editor of an auto-reinstall
2017-07-08 17:30:17 +01:00
Kazuhito Yokoi
3a2f56cb95 Fix column name in link nodes to refer language file (#1330) 2017-07-07 11:43:07 +01:00
Nick O'Leary
a4d33879dc Use namespaces with link node title attributes i18n name
Fixes #1329
2017-07-06 17:57:53 +01:00
Nick O'Leary
e2a91d1ea9 Tidy up GPIO pin table presentation
Fixes #1328
2017-07-06 00:00:08 +01:00
Nick O'Leary
f30f80d117 Join: count of 0 should not send on every msg 2017-07-05 14:12:28 +01:00
Nick O'Leary
266274135e Handle importing only one end of a link node pair 2017-07-04 23:40:37 +01:00
Nick O'Leary
a10439b67c Make sending to Debug synchronous again
Fixes #1323

Being asynchronous meant the msg that was eventually sent to
Debug could be a modified version from later in the flow, if
the flow was other synchronous.
2017-07-04 23:30:51 +01:00
Nick O'Leary
0fd8d0e2bf Make send-error behaviour optional in file node
Existing nodes will have sendError enabled. New instances
will default to it being disabled.
2017-07-04 20:12:53 +01:00
Nick O'Leary
47e2707fd3 Restore File In node behaviour of sending msg on error 2017-07-04 19:55:09 +01:00
Nick O'Leary
f7bb4a7d60 Expose context.keys within Function node 2017-07-04 14:52:14 +01:00
Nick O'Leary
6102a31a31 JSON parser default should be not formatting output
If its a checkbox, then the default value should be a boolean,
not a string. Because "false" is truthy.
2017-07-04 13:44:37 +01:00
Nick O'Leary
1692c3b102 Update changelog/package for 0.17.3 2017-07-04 10:06:24 +01:00
Kazuhito Yokoi
ac60725d2a Fix flow library in menu to support period characters as flow name (#1320) 2017-07-04 10:02:24 +01:00
Nick O'Leary
1542f73fa5 Fix global leaks in theme.js 2017-07-04 09:43:16 +01:00
Nick O'Leary
70a22187f7 editorTheme not setting custom css/scripts properly 2017-07-04 09:33:27 +01:00
Kazuki Nakanishi
347e598715 Fix missing icons for some nodes (#1321) 2017-07-04 09:04:27 +01:00
Nick O'Leary
a737810c50 Add reformat button to JSONata test data editor 2017-07-03 21:57:55 +01:00
Nick O'Leary
92654a71fb Remove unused oldDepth from Delay node 2017-07-03 21:27:45 +01:00
Nick O'Leary
18615640e0 Update delay node status without spawning unecessary intervals 2017-07-03 21:23:14 +01:00
Nick O'Leary
b8c80a2310 Avoid stringify ServerResponse and Socket in Debug node
Fixes #1311
2017-07-03 20:55:04 +01:00
Kazuki Nakanishi
c34c98386e Fix creating userDir other than system drive on Windows (#1317) 2017-07-03 15:22:49 +01:00
Nick O'Leary
d8a3d2793f Trigger node not handling a duration of 0 as block mode
Fixes #1316
2017-07-03 15:20:37 +01:00
Dave Conway-Jones
360b0d9997 correct gpis pin 13 typo
to address #1314
2017-07-02 20:53:27 +01:00
Nick O'Leary
356f46aaf4 Bump 0.17.2 2017-07-02 11:15:09 +01:00
Dave Conway-Jones
87ac0507d9 and finally fix the gpio labels 2017-07-02 11:07:11 +01:00
Nick O'Leary
63657c18e2 Bump 0.17.1 2017-07-02 10:57:45 +01:00
Dave Conway-Jones
817f92a50e refix GPIO - more correctly - backwards compatible
existing installations now keep working
2017-07-02 09:59:37 +01:00
Dave Conway-Jones
304be96dd6 stop gpis node reporting bad status message on slow Pi 2017-07-02 00:50:55 +01:00
Dave Conway-Jones
9639081e7e re-sort package dev dips 2017-07-01 22:42:48 +01:00
Dave Conway-Jones
dca553048a Fix PI gpio to use BCM 2017-07-01 22:42:13 +01:00
Nick O'Leary
6201ed4d55 Prevent event thread contention when sending to Debug node
Closes #1311
2017-07-01 22:01:56 +01:00
Nguyen Thai Vinh
6db2c04585 Fix Bug: Can not display node icon when npm package has scope (#1305) (#1309) 2017-06-30 21:49:35 +01:00
Nick O'Leary
f3840512ba Clear moved flag when nodes are deployed 2017-06-30 21:48:38 +01:00
48 changed files with 723 additions and 326 deletions

View File

@@ -1,3 +1,47 @@
#### 0.17.4: Maintenance Release
- Add request node test case for POSTing 0
- Allow false and 0 in payload for httprequest (#1334)
- Add file extension into flow name of library automatically (#1331)
- Fix accessing global context from jsonata expressions Fixes #1335
- Disable editor whilst a deploy is inflight Fixes #1332
- Replace Unknown nodes with their real versions when node loaded
- Retry auto-install of modules that fail
- Fix column name in link nodes to refer language file (#1330)
- Use namespaces with link node title attributes i18n name Fixes #1329
- Tidy up GPIO pin table presentation Fixes #1328
- Join: count of 0 should not send on every msg
- Handle importing only one end of a link node pair
- Make sending to Debug synchronous again Fixes #1323
- Make send-error behaviour optional in file node
- Restore File In node behaviour of sending msg on error
- Expose context.keys within Function node
- JSON parser default should be not formatting output
#### 0.17.3: Maintenance Release
- Fix flow library in menu to support period characters as flow name (#1320)
- editorTheme not setting custom css/scripts properly
- Fix missing icons for some nodes (#1321)
- Add reformat button to JSONata test data editor
- Update delay node status without spawning unnecessary intervals
- Avoid stringify ServerResponse and Socket in Debug node Fixes #1311
- Fix creating userDir other than system drive on Windows (#1317)
- Trigger node not handling a duration of 0 as block mode Fixes #1316
- Unable to config GPIO Pin 13 Fixes #1314
#### 0.17.2: Maintenance Release
- Fix GPIO node labels
#### 0.17.1: Maintenance Release
- Fix PI gpio to use BCM
- Prevent event thread contention when sending to Debug node Closes #1311
- Fix Bug: Can not display node icon when npm package has scope (#1305) (#1309)
- Clear moved flag when nodes are deployed
#### 0.17: Milestone Release
Runtime

View File

@@ -37,7 +37,25 @@ RED.i18n = (function() {
},
loadCatalog: function(namespace,done) {
i18n.loadNamespace(namespace,done);
var languageList = i18n.functions.toLanguages(i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
$.ajax({
headers: {
"Accept":"application/json"
},
cache: false,
url: 'locales/'+namespace+'?lng='+lang,
success: function(data) {
i18n.addResourceBundle(lang,namespace,data);
toLoad--;
if (toLoad === 0) {
done();
}
}
});
})
},
loadNodeCatalogs: function(done) {

View File

@@ -72,6 +72,10 @@
// handled in ui/deploy.js
return;
}
if (notificationId === "node") {
// handled below
return;
}
if (msg.text) {
var text = RED._(msg.text,{default:msg.text});
if (!persistentNotifications.hasOwnProperty(notificationId)) {
@@ -98,11 +102,11 @@
RED.view.redraw();
}
});
RED.comms.subscribe("node/#",function(topic,msg) {
RED.comms.subscribe("notification/node/#",function(topic,msg) {
var i,m;
var typeList;
var info;
if (topic == "node/added") {
if (topic == "notification/node/added") {
var addedTypes = [];
msg.forEach(function(m) {
var id = m.id;
@@ -118,7 +122,7 @@
typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
} else if (topic == "node/removed") {
} else if (topic == "notification/node/removed") {
for (i=0;i<msg.length;i++) {
m = msg[i];
info = RED.nodes.removeNodeSet(m.id);
@@ -127,7 +131,7 @@
RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success");
}
}
} else if (topic == "node/enabled") {
} else if (topic == "notification/node/enabled") {
if (msg.types) {
info = RED.nodes.getNodeSet(msg.id);
if (info.added) {
@@ -142,7 +146,7 @@
});
}
}
} else if (topic == "node/disabled") {
} else if (topic == "notification/node/disabled") {
if (msg.types) {
RED.nodes.disableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
@@ -249,13 +253,12 @@
RED.deploy.init(RED.settings.theme("deployButton",null));
RED.actions.add("core:show-about", showAbout);
RED.nodes.init();
RED.comms.connect();
$("#main-container").show();
$(".header-toolbar").show();
loadNodeList();
}

View File

@@ -1217,6 +1217,50 @@ RED.nodes = (function() {
}
return {
init: function() {
RED.events.on("registry:node-type-added",function(type) {
var def = registry.getNodeType(type);
var replaced = false;
var replaceNodes = [];
RED.nodes.eachNode(function(n) {
if (n.type === "unknown" && n.name === type) {
replaceNodes.push(n);
}
});
RED.nodes.eachConfig(function(n) {
if (n.type === "unknown" && n.name === type) {
replaceNodes.push(n);
}
});
if (replaceNodes.length > 0) {
var reimportList = [];
replaceNodes.forEach(function(n) {
if (configNodes.hasOwnProperty(n.id)) {
delete configNodes[n.id];
} else {
nodes.splice(nodes.indexOf(n),1);
}
reimportList.push(convertNode(n));
});
RED.view.redraw(true);
var result = importNodes(reimportList,false);
var newNodeMap = {};
result[0].forEach(function(n) {
newNodeMap[n.id] = n;
});
RED.nodes.eachLink(function(l) {
if (newNodeMap.hasOwnProperty(l.source.id)) {
l.source = newNodeMap[l.source.id];
}
if (newNodeMap.hasOwnProperty(l.target.id)) {
l.target = newNodeMap[l.target.id];
}
});
RED.view.redraw(true);
}
});
},
registry:registry,
setNodeList: registry.setNodeList,

View File

@@ -361,6 +361,10 @@ RED.deploy = (function() {
}
deployInflight = true;
$("#header-shade").show();
$("#editor-shade").show();
$("#palette-shade").show();
$("#sidebar-shade").show();
$.ajax({
url:"flows",
type: "POST",
@@ -385,6 +389,10 @@ RED.deploy = (function() {
node.dirty = true;
node.changed = false;
}
if (node.moved) {
node.dirty = true;
node.moved = false;
}
if(node.credentials) {
delete node.credentials;
}
@@ -420,6 +428,10 @@ RED.deploy = (function() {
setTimeout(function() {
$(".deploy-button-content").css('opacity',1);
$(".deploy-button-spinner").hide();
$("#header-shade").hide();
$("#editor-shade").hide();
$("#palette-shade").hide();
$("#sidebar-shade").hide();
},delta);
});
}

View File

@@ -1943,6 +1943,17 @@ RED.editor = (function() {
}
});
$("#node-input-example-reformat").click(function(evt) {
evt.preventDefault();
var v = testDataEditor.getValue()||"";
try {
v = JSON.stringify(JSON.parse(v),null,4);
} catch(err) {
// TODO: do an optimistic auto-format
}
testDataEditor.getSession().setValue(v||"",-1);
});
testExpression();
},
close: function() {
@@ -2009,7 +2020,7 @@ RED.editor = (function() {
mode:"ace/mode/json"
});
expressionEditor.getSession().setValue(value||"",-1);
$("#node-input-expression-reformat").click(function(evt) {
$("#node-input-json-reformat").click(function(evt) {
evt.preventDefault();
var v = expressionEditor.getValue()||"";
try {

View File

@@ -482,7 +482,7 @@ RED.view = (function() {
try {
nn._def.onadd.call(nn);
} catch(err) {
console.log("onadd:",err);
console.log("Definition error: "+nn.type+".onadd:",err);
}
}
} else {
@@ -2581,7 +2581,7 @@ RED.view = (function() {
try {
node.n._def.onadd.call(node.n);
} catch(err) {
console.log("onadd:",err);
console.log("Definition error: "+node.n.type+".onadd:",err);
}
}

View File

@@ -188,7 +188,10 @@
</div>
<div id="node-input-expression-tab-test" class="node-input-expression-tab-content hide">
<div>
<span style="display: inline-block; width: calc(50% - 5px);" data-i18n="expressionEditor.data"></span>
<span style="display: inline-block; width: calc(50% - 5px);">
<span data-i18n="expressionEditor.data"></span>
<button style="float: right; margin-right: 5px;" id="node-input-example-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
</span>
<span style="display: inline-block; width: calc(50% - 5px);" data-i18n="expressionEditor.result"></span>
</div>
<div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-data"></div>
@@ -200,7 +203,7 @@
</script>
<script type="text/x-red" data-template-name="_json">
<div class="form-row" style="margin-bottom: 3px; text-align: right;">
<button id="node-input-expression-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
<button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
</div>
<div class="form-row node-text-editor-row">
<div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div>

View File

@@ -29,7 +29,7 @@ module.exports = function(RED) {
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
}
if (this.active) {
sendDebug({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path});
sendDebug({id:node.id,name:node.name,topic:msg.topic,msg:msg,_path:msg._path});
}
} else {
// debug user defined msg property
@@ -53,7 +53,7 @@ module.exports = function(RED) {
}
}
if (this.active) {
sendDebug({id:this.id,z:this.z,name:this.name,topic:msg.topic,property:property,msg:output,_path:msg._path});
sendDebug({id:node.id,z:node.z,name:node.name,topic:msg.topic,property:property,msg:output,_path:msg._path});
}
}
});
@@ -137,11 +137,17 @@ module.exports = function(RED) {
if (value.length > debuglength) {
value = value.substring(0,debuglength)+"...";
}
} else if (value !== null && typeof value === 'object' && value.type === "Buffer") {
value.__encoded__ = true;
value.length = value.data.length;
if (value.length > debuglength) {
value.data = value.data.slice(0,debuglength);
} else if (value && value.constructor) {
if (value.constructor.name === "Buffer") {
value.__encoded__ = true;
value.length = value.data.length;
if (value.length > debuglength) {
value.data = value.data.slice(0,debuglength);
}
} else if (value.constructor.name === "ServerResponse") {
value = "[internal]"
} else if (value.constructor.name === "Socket") {
value = "[internal]"
}
}
return value;

View File

@@ -118,8 +118,8 @@
$('<div id="node-input-link-container-div" style="min-height: 100px;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;">'+
' <div style="display: inline-block;margin-left: 5px;"><a id="node-input-link-sort-label" href="#" data-i18n="[title]link.label.sortByLabel"><span data-i18n="link.label.node">name</span> <i class="node-input-link-sort-label-a fa fa-caret-down"></i><i class="node-input-link-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-link-sort-type" href="#" data-i18n="[title]link.label.sortByFlow"><i class="node-input-link-sort-sublabel-a fa fa-caret-down"></i><i class="node-input-link-sort-sublabel-d fa fa-caret-up"></i> <span data-i18n="link.label.type">flow</span></a></div>'+
' <div style="display: inline-block;margin-left: 5px;"><a id="node-input-link-sort-label" href="#" data-i18n="[title]node-red:link.label.sortByLabel"><span data-i18n="node-red:link.label.node">name</span> <i class="node-input-link-sort-label-a fa fa-caret-down"></i><i class="node-input-link-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-link-sort-type" href="#" data-i18n="[title]node-red:link.label.sortByFlow"><i class="node-input-link-sort-sublabel-a fa fa-caret-down"></i><i class="node-input-link-sort-sublabel-d fa fa-caret-up"></i> <span data-i18n="node-red:link.label.type">flow</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-link-container" style=" list-style-type:none; margin: 0;"></ul>'+
@@ -251,7 +251,7 @@
function onAdd() {
for (var i=0;i<this.links.length;i++) {
var n = RED.nodes.node(this.links[i]);
if (n.links.indexOf(this.id) === -1) {
if (n && n.links.indexOf(this.id) === -1) {
n.links.push(this.id);
}
}

View File

@@ -111,6 +111,9 @@ module.exports = function(RED) {
get: function() {
return node.context().get.apply(node,arguments);
},
keys: function() {
return node.context().keys.apply(node,arguments);
},
get global() {
return node.context().global;
},
@@ -124,6 +127,9 @@ module.exports = function(RED) {
},
get: function() {
return node.context().flow.get.apply(node,arguments);
},
keys: function() {
return node.context().flow.keys.apply(node,arguments);
}
},
global: {
@@ -132,6 +138,9 @@ module.exports = function(RED) {
},
get: function() {
return node.context().global.get.apply(node,arguments);
},
keys: function() {
return node.context().global.keys.apply(node,arguments);
}
},
setTimeout: function () {

View File

@@ -121,29 +121,37 @@ module.exports = function(RED) {
node.on("close", function() { clearDelayList(); });
}
else if (node.pauseType === "rate") {
var olddepth = 0;
node.busy = setInterval(function() {
if (node.buffer.length > 0) {
node.status({text:node.buffer.length});
node.reportDepth = function() {
if (!node.busy) {
node.busy = setTimeout(function() {
if (node.buffer.length > 0) {
node.status({text:node.buffer.length});
} else {
node.status({});
}
node.busy = null;
},500);
}
},333);
}
node.on("input", function(msg) {
if (!node.drop) {
if ( node.intervalID !== -1) {
node.buffer.push(msg);
node.reportDepth();
}
else {
node.send(msg);
node.reportDepth();
node.intervalID = setInterval(function() {
if (node.buffer.length === 0) {
clearInterval(node.intervalID);
node.intervalID = -1;
node.status({});
olddepth = 0;
}
if (node.buffer.length > 0) {
node.send(node.buffer.shift());
}
node.reportDepth();
},node.rate);
}
}
@@ -169,7 +177,7 @@ module.exports = function(RED) {
});
node.on("close", function() {
clearInterval(node.intervalID);
clearInterval(node.busy);
clearTimeout(node.busy);
node.buffer = [];
node.status({});
});

View File

@@ -172,8 +172,7 @@
}
else if ((this.duration * 1) < 0) {
$("#node-then-type").val("loop");
this.duration = this.duration * -1;
$("#node-input-duration").val(this.duration);
$("#node-input-duration").val(this.duration*-1);
} else {
$("#node-then-type").val("wait");
}
@@ -194,6 +193,7 @@
$("#node-input-duration").val($("#node-input-duration").val() * -1);
}
}
});
</script>

View File

@@ -47,7 +47,10 @@ module.exports = function(RED) {
this.extend = n.extend || "false";
this.units = n.units || "ms";
this.reset = n.reset || '';
this.duration = n.duration || 250;
this.duration = parseInt(n.duration);
if (isNaN(this.duration)) {
this.duration = 250;
}
if (this.duration < 0) {
this.loop = true;
this.duration = this.duration * -1;

View File

@@ -1,142 +1,151 @@
<style>
.rpi-gpio-pinTable {
width: 340px;
display: inline-table;
font-size: 13px;
height: 380px;
min-height: 380px;
max-height: 380px;
}
.rpi-gpio-pinTable input[type="radio"] {
width: auto;
margin: 2px 2px;
}
.rpi-gpio-pinTable label {
width: auto;
margin: 0;
display: block;
}
.rpi-gpio-pinTable .pinTableBody {
width: 340px;
display: table-row-group;
line-height: 12px;
}
.rpi-gpio-pinTable .pinTableRow {
width: 340px;
display: table-row;
height: 14px;
}
.rpi-gpio-pinTable .pinTableCellL {
width: 170px;
display: table-cell;
text-align: right;
padding-right: 4px;
vertical-align: top;
border: 1px solid #444;
}
.rpi-gpio-pinTable .pinTableCellR {
width: 170px;
display: table-cell;
text-align: left;
padding-left: 4px;
vertical-align: top;
border: 1px solid #000;
}
.rpi-gpio-pinTable .pinColorPower {
background-color:#FECBCE;
}
.rpi-gpio-pinTable .pinColorGround {
background-color:#DDDDDD;
}
.rpi-gpio-pinTable .pinColorGPIO {
background-color:#BFEBBF;
}
.rpi-gpio-pinTable .pinColorDual {
background-color:#D0E6F4;
}
.rpi-gpio-pinTable .pinColorSD {
background-color:#FFFDD0;
}
</style>
<script type="text/x-red" data-template-name="rpi-gpio in">
<style>
.pinTable {
width: 300px;
display: inline-table;
font-size: 13px;
height: 380px;
min-height: 380px;
max-height: 380px;
}
.pinTableBody {
width: 300px;
display: table-row-group;
line-height: 12px;
}
.pinTableRow {
width: 300;
display: table-row;
height: 14px;
}
.pinTableCellL {
width: 150px;
display: table-cell;
text-align: right;
padding-right: 4px;
vertical-align: top;
border: 1px solid #444;
}
.pinTableCellR {
width: 150px;
display: table-cell;
text-align: left;
padding-left: 4px;
vertical-align: top;
border: 1px solid #000;
}
.pinColorPower {
background-color:#FECBCE;
}
.pinColorGround {
background-color:#DDDDDD;
}
.pinColorGPIO {
background-color:#BFEBBF;
}
.pinColorDual {
background-color:#D0E6F4;
}
.pinColorSD {
background-color:#FFFDD0;
}
</style>
<div class="form-row">
<div class="form-row" style="min-width: 540px">
<label><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.pinname"></span></label>
<input type="text" id="node-input-pin" style="display:none;">
<div class="pinTable">
<div class="pinTableBody"><form id="pinform" style="height:380px; max-height:380px; margin:initial;">
<div class="rpi-gpio-pinTable">
<div class="pinTableBody" id="pinform">
<div class="pinTableRow">
<div class="pinTableCellL pinColorPower">3.3V Power - 1 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorPower"><input disabled type="radio" name="pins" value="" style="width:auto;"> 2 - 5V Power</div>
<div class="pinTableCellL pinColorPower"><label>3.3V Power - 1 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorPower"><label><input disabled type="radio" name="pins" value=""> 2 - 5V Power</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">SDA1 - GPIO02 - 3 <input type="radio" name="pins" value="2" style="width:auto;"></div>
<div class="pinTableCellR pinColorPower"><input disabled type="radio" name="pins" value="" style="width:auto;"> 4 - 5V Power</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-3">SDA1 - GPIO02 - 3 <input id="pinTable-pin-3" type="radio" name="pins" value="3"></label></div>
<div class="pinTableCellR pinColorPower"><label><input disabled type="radio" name="pins" value=""> 4 - 5V Power</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">SCL1 - GPIO03 - 5 <input type="radio" name="pins" value="3" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 6 - Ground</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-5">SCL1 - GPIO03 - 5 <input id="pinTable-pin-5" type="radio" name="pins" value="5"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 6 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO04 - 7 <input type="radio" name="pins" value="4" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="14" style="width:auto;"> 8 - GPIO14 - TxD</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-7">GPIO04 - 7 <input id="pinTable-pin-7" type="radio" name="pins" value="7"></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-8"><input id="pinTable-pin-8" type="radio" name="pins" value="8"> 8 - GPIO14 - TxD</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGround">Ground - 9 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="15" style="width:auto;"> 10 - GPIO15 - RxD</div>
<div class="pinTableCellL pinColorGround"><label>Ground - 9 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-10"><input id="pinTable-pin-10" type="radio" name="pins" value="10"> 10 - GPIO15 - RxD</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO17 - 11 <input type="radio" name="pins" value="17" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="18" style="width:auto;"> 12 - GPIO18</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-11">GPIO17 - 11 <input id="pinTable-pin-11" type="radio" name="pins" value="11"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-12"><input id="pinTable-pin-12" type="radio" name="pins" value="12"> 12 - GPIO18</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO27 - 13 <input type="radio" name="pins" value="27" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 14 - Ground</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-13">GPIO27 - 13 <input id="pinTable-pin-13" type="radio" name="pins" value="13"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 14 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO22 - 15 <input type="radio" name="pins" value="22" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="23" style="width:auto;"> 16 - GPIO23</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-15">GPIO22 - 15 <input id="pinTable-pin-15" type="radio" name="pins" value="15"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-16"><input id="pinTable-pin-16" type="radio" name="pins" value="16"> 16 - GPIO23</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorPower">3.3V Power - 17 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="24" style="width:auto;"> 18 - GPIO24</div>
<div class="pinTableCellL pinColorPower"><label>3.3V Power - 17 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-18"><input id="pinTable-pin-18" type="radio" name="pins" value="18"> 18 - GPIO24</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">MOSI - GPIO10 - 19 <input type="radio" name="pins" value="10" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 20 - Ground</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-19">MOSI - GPIO10 - 19 <input id="pinTable-pin-19" type="radio" name="pins" value="19"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 20 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">MISO - GPIO09 - 21 <input type="radio" name="pins" value="9" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="25" style="width:auto;"> 22 - GPIO25</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-21">MISO - GPIO09 - 21 <input id="pinTable-pin-21" type="radio" name="pins" value="21"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-22"><input id="pinTable-pin-22" type="radio" name="pins" value="22"> 22 - GPIO25</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">SCLK - GPIO11 - 23 <input type="radio" name="pins" value="11" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="8" style="width:auto;"> 24 - GPIO8 - CE0</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-23">SCLK - GPIO11 - 23 <input id="pinTable-pin-23" type="radio" name="pins" value="23"></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-24"><input id="pinTable-pin-24" type="radio" name="pins" value="24"> 24 - GPIO8 - CE0</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGround">Ground - 25 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="7" style="width:auto;"> 26 - GPIO7 - CE1</div>
<div class="pinTableCellL pinColorGround"><label>Ground - 25 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-26"><input id="pinTable-pin-26" type="radio" name="pins" value="26"> 26 - GPIO7 - CE1</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorSD">SD - 27 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorSD"><input disabled type="radio" name="pins" value="" style="width:auto;"> 28 - SC</div>
<div class="pinTableCellL pinColorSD"><label>SD - 27 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorSD"><label><input disabled type="radio" name="pins" value=""> 28 - SC</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO05 - 29 <input type="radio" name="pins" value="5" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 30 - Ground</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-29">GPIO05 - 29 <input id="pinTable-pin-29" type="radio" name="pins" value="29"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 30 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO06 - 31 <input type="radio" name="pins" value="6" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="12" style="width:auto;"> 32 - GPIO12</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-31">GPIO06 - 31 <input id="pinTable-pin-31" type="radio" name="pins" value="31"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-32"><input id="pinTable-pin-32" type="radio" name="pins" value="32"> 32 - GPIO12</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO13 - 33 <input type="radio" name="pins" value="13" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 34 - Ground</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-33">GPIO13 - 33 <input id="pinTable-pin-33" type="radio" name="pins" value="33"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 34 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO19 - 35 <input type="radio" name="pins" value="19" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="16" style="width:auto;"> 36 - GPIO16</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-35">GPIO19 - 35 <input id="pinTable-pin-35" type="radio" name="pins" value="35"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-36"><input id="pinTable-pin-36" type="radio" name="pins" value="36"> 36 - GPIO16</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO26 - 37 <input type="radio" name="pins" value="26" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="20" style="width:auto;"> 38 - GPIO20</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-37">GPIO26 - 37 <input id="pinTable-pin-37" type="radio" name="pins" value="37"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-38"><input id="pinTable-pin-38" type="radio" name="pins" value="38"> 38 - GPIO20</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGround">Ground - 39 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="21" style="width:auto;"> 40 - GPIO21</div>
<div class="pinTableCellL pinColorGround"><label>Ground - 39 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-40"><input id="pinTable-pin-40" type="radio" name="pins" value="40"> 40 - GPIO21</label></div>
</div>
</form></div>
</div>
</div>
</div>
<div class="form-row">
@@ -207,7 +216,7 @@
var suf = "";
if (this.intype === "up") { suf = "↑ "}
if (this.intype === "down") { suf = "↓ "}
return this.name || "PIN: "+suf+bcm2pin[this.pin] ;
return this.name || "PIN: "+suf+this.pin ;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
@@ -251,143 +260,92 @@
</script>
<script type="text/x-red" data-template-name="rpi-gpio out">
<style>
.pinTable {
width: 300px;
display: inline-table;
font-size: 13px;
height: 380px;
min-height: 380px;
max-height: 380px;
}
.pinTableBody {
width: 300px;
display: table-row-group;
line-height: 12px;
}
.pinTableRow {
width: 300;
display: table-row;
height: 14px;
}
.pinTableCellL {
width: 150px;
display: table-cell;
text-align: right;
padding-right: 4px;
vertical-align: top;
border: 1px solid #444;
}
.pinTableCellR {
width: 150px;
display: table-cell;
text-align: left;
padding-left: 4px;
vertical-align: top;
border: 1px solid #000;
}
.pinColorPower {
background-color:#FECBCE;
}
.pinColorGround {
background-color:#DDDDDD;
}
.pinColorGPIO {
background-color:#BFEBBF;
}
.pinColorDual {
background-color:#D0E6F4;
}
.pinColorSD {
background-color:#FFFDD0;
}
</style>
<div class="form-row">
<div class="form-row" style="min-width: 540px">
<label><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.pinname"></span></label>
<input type="text" id="node-input-pin" style="display:none;">
<div class="pinTable">
<div class="pinTableBody"><form id="pinform" style="height:380px; max-height:380px; margin:initial;">
<div class="rpi-gpio-pinTable">
<div class="pinTableBody" id="pinform">
<div class="pinTableRow">
<div class="pinTableCellL pinColorPower">3.3V Power - 1 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorPower"><input disabled type="radio" name="pins" value="" style="width:auto;"> 2 - 5V Power</div>
<div class="pinTableCellL pinColorPower"><label>3.3V Power - 1 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorPower"><label><input disabled type="radio" name="pins" value=""> 2 - 5V Power</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">SDA1 - GPIO02 - 3 <input type="radio" name="pins" value="2" style="width:auto;"></div>
<div class="pinTableCellR pinColorPower"><input disabled type="radio" name="pins" value="" style="width:auto;"> 4 - 5V Power</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-3">SDA1 - GPIO02 - 3 <input id="pinTable-pin-3" type="radio" name="pins" value="3"></label></div>
<div class="pinTableCellR pinColorPower"><label><input disabled type="radio" name="pins" value=""> 4 - 5V Power</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">SCL1 - GPIO03 - 5 <input type="radio" name="pins" value="3" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 6 - Ground</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-5">SCL1 - GPIO03 - 5 <input id="pinTable-pin-5" type="radio" name="pins" value="5"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 6 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO04 - 7 <input type="radio" name="pins" value="4" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="14" style="width:auto;"> 8 - GPIO14 - TxD</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-7">GPIO04 - 7 <input id="pinTable-pin-7" type="radio" name="pins" value="7"></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-8"><input id="pinTable-pin-8" type="radio" name="pins" value="8"> 8 - GPIO14 - TxD</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGround">Ground - 9 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="15" style="width:auto;"> 10 - GPIO15 - RxD</div>
<div class="pinTableCellL pinColorGround"><label>Ground - 9 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-10"><input id="pinTable-pin-10" type="radio" name="pins" value="10"> 10 - GPIO15 - RxD</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO17 - 11 <input type="radio" name="pins" value="17" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="18" style="width:auto;"> 12 - GPIO18</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-11">GPIO17 - 11 <input id="pinTable-pin-11" type="radio" name="pins" value="11"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-12"><input id="pinTable-pin-12" type="radio" name="pins" value="12"> 12 - GPIO18</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO27 - 13 <input type="radio" name="pins" value="27" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 14 - Ground</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-13">GPIO27 - 13 <input id="pinTable-pin-13" type="radio" name="pins" value="13"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 14 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO22 - 15 <input type="radio" name="pins" value="22" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="23" style="width:auto;"> 16 - GPIO23</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-15">GPIO22 - 15 <input id="pinTable-pin-15" type="radio" name="pins" value="15"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-16"><input id="pinTable-pin-16" type="radio" name="pins" value="16"> 16 - GPIO23</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorPower">3.3V Power - 17 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="24" style="width:auto;"> 18 - GPIO24</div>
<div class="pinTableCellL pinColorPower"><label>3.3V Power - 17 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-18"><input id="pinTable-pin-18" type="radio" name="pins" value="18"> 18 - GPIO24</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">MOSI - GPIO10 - 19 <input type="radio" name="pins" value="10" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 20 - Ground</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-19">MOSI - GPIO10 - 19 <input id="pinTable-pin-19" type="radio" name="pins" value="19"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 20 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">MISO - GPIO09 - 21 <input type="radio" name="pins" value="9" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="25" style="width:auto;"> 22 - GPIO25</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-21">MISO - GPIO09 - 21 <input id="pinTable-pin-21" type="radio" name="pins" value="21"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-22"><input id="pinTable-pin-22" type="radio" name="pins" value="22"> 22 - GPIO25</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorDual">SCLK - GPIO11 - 23 <input type="radio" name="pins" value="11" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="8" style="width:auto;"> 24 - GPIO8 - CE0</div>
<div class="pinTableCellL pinColorDual"><label for="pinTable-pin-23">SCLK - GPIO11 - 23 <input id="pinTable-pin-23" type="radio" name="pins" value="23"></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-24"><input id="pinTable-pin-24" type="radio" name="pins" value="24"> 24 - GPIO8 - CE0</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGround">Ground - 25 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorDual"><input type="radio" name="pins" value="7" style="width:auto;"> 26 - GPIO7 - CE1</div>
<div class="pinTableCellL pinColorGround"><label>Ground - 25 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorDual"><label for="pinTable-pin-26"><input id="pinTable-pin-26" type="radio" name="pins" value="26"> 26 - GPIO7 - CE1</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorSD">SD - 27 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorSD"><input disabled type="radio" name="pins" value="" style="width:auto;"> 28 - SC</div>
<div class="pinTableCellL pinColorSD"><label>SD - 27 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorSD"><label><input disabled type="radio" name="pins" value=""> 28 - SC</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO05 - 29 <input type="radio" name="pins" value="5" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 30 - Ground</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-29">GPIO05 - 29 <input id="pinTable-pin-29" type="radio" name="pins" value="29"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 30 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO06 - 31 <input type="radio" name="pins" value="6" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="12" style="width:auto;"> 32 - GPIO12</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-31">GPIO06 - 31 <input id="pinTable-pin-31" type="radio" name="pins" value="31"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-32"><input id="pinTable-pin-32" type="radio" name="pins" value="32"> 32 - GPIO12</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO13 - 33 <input type="radio" name="pins" value="13" style="width:auto;"></div>
<div class="pinTableCellR pinColorGround"><input disabled type="radio" name="pins" value="" style="width:auto;"> 34 - Ground</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-33">GPIO13 - 33 <input id="pinTable-pin-33" type="radio" name="pins" value="33"></label></div>
<div class="pinTableCellR pinColorGround"><label><input disabled type="radio" name="pins" value=""> 34 - Ground</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO19 - 35 <input type="radio" name="pins" value="19" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="16" style="width:auto;"> 36 - GPIO16</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-35">GPIO19 - 35 <input id="pinTable-pin-35" type="radio" name="pins" value="35"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-36"><input id="pinTable-pin-36" type="radio" name="pins" value="36"> 36 - GPIO16</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGPIO">GPIO26 - 37 <input type="radio" name="pins" value="26" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="20" style="width:auto;"> 38 - GPIO20</div>
<div class="pinTableCellL pinColorGPIO"><label for="pinTable-pin-37">GPIO26 - 37 <input id="pinTable-pin-37" type="radio" name="pins" value="37"></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-38"><input id="pinTable-pin-38" type="radio" name="pins" value="38"> 38 - GPIO20</label></div>
</div>
<div class="pinTableRow">
<div class="pinTableCellL pinColorGround">Ground - 39 <input disabled type="radio" name="pins" value="" style="width:auto;"></div>
<div class="pinTableCellR pinColorGPIO"><input type="radio" name="pins" value="21" style="width:auto;"> 40 - GPIO21</div>
<div class="pinTableCellL pinColorGround"><label>Ground - 39 <input disabled type="radio" name="pins" value=""></label></div>
<div class="pinTableCellR pinColorGPIO"><label for="pinTable-pin-40"><input id="pinTable-pin-40" type="radio" name="pins" value="40"> 40 - GPIO21</label></div>
</div>
</form></div>
</div>
</div>
</div>
<div class="form-row" id="node-set-pwm">
@@ -469,12 +427,12 @@
},
align: "right",
label: function() {
if (this.out === "pwm") { return this.name || "PWM: "+bcm2pin[this.pin]; }
else if (this.out === "ser") { return this.name || "Servo: "+bcm2pin[this.pin]; }
if (this.out === "pwm") { return this.name || "PWM: "+this.pin; }
else if (this.out === "ser") { return this.name || "Servo: "+this.pin; }
else {
var suf = "";
if (this.set == true) { suf = (this.level === "1") ? " ¹" : " ₀"; }
return this.name||"PIN: "+ bcm2pin[this.pin] + suf ;
return this.name||"PIN: "+ this.pin + suf ;
}
},
labelStyle: function() {

View File

@@ -69,6 +69,7 @@ module.exports = function(RED) {
node.child.stdout.on('data', function (data) {
var d = data.toString().trim().split("\n");
for (var i = 0; i < d.length; i++) {
if (d[i] === '') { return; }
if (node.running && node.buttonState !== -1 && !isNaN(Number(d[i])) && node.buttonState !== d[i]) {
node.send({ topic:"pi/"+node.pin, payload:Number(d[i]) });
}

View File

@@ -35,7 +35,7 @@ if len(sys.argv) > 2:
if cmd == "pwm":
#print "Initialised pin "+str(pin)+" to PWM"
try:
try:
freq = int(sys.argv[3])
except:
freq = 100

View File

@@ -135,7 +135,7 @@ module.exports = function(RED) {
}
var payload = null;
if (msg.payload && (method == "POST" || method == "PUT" || method == "PATCH" ) ) {
if (typeof msg.payload !== "undefined" && (method == "POST" || method == "PUT" || method == "PATCH" ) ) {
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
payload = msg.payload;
} else if (typeof msg.payload == "number") {

View File

@@ -127,7 +127,11 @@
"linkIn": "link in",
"linkOut": "link out",
"label": {
"event": "Event name"
"event": "Event name",
"node": "name",
"type": "flow",
"sortByFlow":"Sort by flow",
"sortByLabel": "Sort by name"
}
},
"tls": {
@@ -762,6 +766,7 @@
"breakchunks": "Break into chunks",
"breaklines": "Break into lines",
"filelabel": "file",
"sendError": "Send message on error (legacy mode)",
"deletelabel": "delete __file__"
},
"action": {

View File

@@ -457,7 +457,7 @@ module.exports = function(RED) {
group.msg = msg;
var tcnt = group.targetCount;
if (msg.hasOwnProperty("parts")) { tcnt = group.targetCount || msg.parts.count; }
if (group.currentCount >= tcnt || msg.hasOwnProperty('complete')) {
if ((tcnt > 0 && group.currentCount >= tcnt) || msg.hasOwnProperty('complete')) {
completeSend(partId);
}
} catch(err) {

View File

@@ -38,7 +38,7 @@
color:"#DEBD5C",
defaults: {
name: {value:""},
pretty: {value:"false"}
pretty: {value:false}
},
inputs:1,
outputs:1,

View File

@@ -40,7 +40,7 @@
<h3>Details</h3>
<p>Each message payload will be added to the end of the file, optionally appending
a newline (\n) character between each one.</p>
<p>If <code>msg.filename</code> is used the file will be closed after every write.
<p>If <code>msg.filename</code> is used the file will be closed after every write.
For best performance use a fixed filename.</p>
<p>It can be configured to overwrite the entire file rather than append. For example,
when writing binary data to a file, such as an image, this option should be used
@@ -62,6 +62,11 @@
<option value="stream" data-i18n="file.output.stream"></option>
</select>
</div>
<div class="form-row">
<label></label>
<input type="checkbox" id="node-input-sendError" style="width:auto">
<label style="width:auto; margin-bottom:0; vertical-align: middle;" for="node-input-sendError" data-i18n="file.label.sendError"></label>
</div>
<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">
@@ -82,6 +87,12 @@
<dd>The contents of the file as either a string or binary buffer.</dd>
<dt class="optional">filename <span class="property-type">string</span></dt>
<dd>If not configured in the node, this optional property sets the name of the file to be read.</dd>
<dt class="optional">error <span class="property-type">object</span></dt>
<dd><i>deprecated</i>: If enabled in the node, when the node hits an error
reading the file, it will send a message with no <code>payload</code>
and this <code>error</code> property set to the error details. This
mode of behaviour is deprecated and not enabled by default for new
instances of the node. See below for more information.</dd>
</dl>
<h3>Details</h3>
<p>The filename should be an absolute path, otherwise it will be relative to
@@ -89,6 +100,13 @@
<p>On Windows, path separators may need to be escaped, for example: <code>\\Users\\myUser</code>.</p>
<p>Optionally, a text file can be split into lines, outputting one message per line, or a binary file
file into smaller buffer chunks, the chunk size is operating system dependant, but typically 64k (linux/mac) or 41k (Windows).</p>
<h4>Legacy error handling</h4>
<p>Before Node-RED 0.17, if this node hit an error whilst reading the file, it would
send a message with no <code>msg.payload</code> and <code>msg.error</code> set to the
details of the error. This is a deprecated mode of behaviour for the node that new
instances will not do. If required, this mode can be re-enabled within the node
configuration.</p>
<p>Errors should be caught and handled using a Catch node.</p>
</script>
<script type="text/javascript">
@@ -130,7 +148,8 @@
name: {value:""},
filename: {value:""},
format: {value:"utf8"},
chunk: {value:false}
chunk: {value:false},
sendError: {value: false}
},
color:"BurlyWood",
inputs:1,
@@ -146,6 +165,9 @@
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.sendError === undefined) {
$("#node-input-sendError").prop("checked",true);
}
$("#node-input-format").on("change",function() {
if ($("#node-input-format").val() === "utf8") {
$("#buffer-input-type").hide();

View File

@@ -98,6 +98,11 @@ module.exports = function(RED) {
this.filename = n.filename;
this.format = n.format;
this.chunk = false;
if (n.sendError === undefined) {
this.sendError = true;
} else {
this.sendError = n.sendError;
}
if (this.format === "lines") { this.chunk = true; }
if (this.format === "stream") { this.chunk = true; }
var node = this;
@@ -172,7 +177,13 @@ module.exports = function(RED) {
}
})
.on('error', function(err) {
node.error('Error while reading file.', msg);
node.error(err, msg);
if (node.sendError) {
var sendMessage = RED.util.cloneMessage(msg);
delete sendMessage.payload;
sendMessage.error = err;
node.send(sendMessage);
}
})
.on('end', function() {
if (node.chunk === false) {

View File

@@ -1,6 +1,6 @@
{
"name" : "node-red",
"version" : "0.17.0",
"version" : "0.17.4",
"description" : "A visual tool for wiring the Internet of Things",
"homepage" : "http://nodered.org",
"license" : "Apache-2.0",
@@ -83,15 +83,15 @@
"grunt-contrib-uglify": "~3.0.1",
"grunt-contrib-watch":"~1.0.0",
"grunt-jsonlint":"~1.1.0",
"grunt-mocha-istanbul": "5.0.2",
"grunt-nodemon":"~0.4.2",
"grunt-sass":"~1.2.1",
"grunt-simple-mocha": "~0.4.1",
"grunt-mocha-istanbul": "5.0.2",
"istanbul": "0.4.5",
"mocha": "~3.4.2",
"should": "^8.4.0",
"sinon": "1.17.7",
"supertest": "3.0.0",
"istanbul": "0.4.5"
"supertest": "3.0.0"
},
"engines": {
"node": ">=4"

5
red.js
View File

@@ -87,8 +87,11 @@ if (parsedArgs.settings) {
if (fs.existsSync(path.join(process.env.NODE_RED_HOME,".config.json"))) {
// NODE_RED_HOME contains user data - use its settings.js
settingsFile = path.join(process.env.NODE_RED_HOME,"settings.js");
} else if (process.env.HOMEPATH && fs.existsSync(path.join(process.env.HOMEPATH,".node-red",".config.json"))) {
// Consider compatibility for older versions
settingsFile = path.join(process.env.HOMEPATH,".node-red","settings.js");
} else {
var userDir = parsedArgs.userDir || path.join(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE,".node-red");
var userDir = parsedArgs.userDir || path.join(process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH,".node-red");
var userSettingsFile = path.join(userDir,"settings.js");
if (fs.existsSync(userSettingsFile)) {
// $HOME/.node-red/settings.js exists

View File

@@ -33,7 +33,7 @@ function handleStatus(event) {
publish("status/"+event.id,event.status,true);
}
function handleRuntimeEvent(event) {
publish("notification/"+event.id,event,true);
publish("notification/"+event.id,event.payload||{},event.retain);
}
function init(_server,runtime) {
server = _server;

View File

@@ -95,6 +95,7 @@ function init(_server,_runtime) {
}
editorApp.get("/",ensureRuntimeStarted,ui.ensureSlash,ui.editor);
editorApp.get("/icons/:module/:icon",ui.icon);
editorApp.get("/icons/:scope/:module/:icon",ui.icon);
theme.init(runtime);
editorApp.use("/theme",theme.app());
editorApp.use("/",ui.editorResources);

View File

@@ -15,12 +15,12 @@
**/
var when = require("when");
var comms = require("./comms");
var locales = require("./locales");
var redNodes;
var log;
var i18n;
var settings;
var events;
module.exports = {
init: function(runtime) {
@@ -28,6 +28,7 @@ module.exports = {
log = runtime.log;
i18n = runtime.i18n;
settings = runtime.settings;
events = runtime.events;
},
getAll: function(req,res) {
if (req.get("accept") == "application/json") {
@@ -72,9 +73,9 @@ module.exports = {
}
promise.then(function(info) {
if (isUpgrade) {
comms.publish("node/upgraded",{module:node.module,version:node.version},false);
events.emit("runtime-event",{id:"node/upgraded",retain:false,payload:{module:node.module,version:node.version}});
} else {
comms.publish("node/added",info.nodes,false);
events.emit("runtime-event",{id:"node/added",retain:false,payload:info.nodes});
}
if (node.module) {
log.audit({event: "nodes.install",module:node.module,version:node.version},req);
@@ -113,7 +114,7 @@ module.exports = {
}
promise.then(function(list) {
comms.publish("node/removed",list,false);
events.emit("runtime-event",{id:"node/removed",retain:false,payload:list});
log.audit({event: "nodes.remove",module:mod},req);
res.status(204).end();
}).otherwise(function(err) {
@@ -245,7 +246,7 @@ function putNode(node, enabled) {
return promise.then(function(info) {
if (info.enabled === enabled && !info.err) {
comms.publish("node/"+(enabled?"enabled":"disabled"),info,false);
events.emit("runtime-event",{id:"node/"+(enabled?"enabled":"disabled"),retain:false,payload:info});
log.info(" "+log._("api.nodes."+(enabled?"enabled":"disabled")));
for (var i=0;i<info.types.length;i++) {
log.info(" - "+info.types[i]);

View File

@@ -67,8 +67,8 @@ function serveFilesFromTheme(themeValue, themeApp, directory) {
array = [array];
}
for (i=0;i<array.length;i++) {
url = serveFile(themeApp,directory,array[i]);
for (var i=0;i<array.length;i++) {
var url = serveFile(themeApp,directory,array[i]);
if (url) {
result.push(url);
}
@@ -98,11 +98,11 @@ module.exports = {
if (theme.page) {
themeContext.page.css = serveFilesFromTheme(
themeContext.page.css,
theme.page.css,
themeApp,
"/css/")
themeContext.page.scripts = serveFilesFromTheme(
themeContext.page.scripts,
theme.page.scripts,
themeApp,
"/scripts/")

View File

@@ -44,7 +44,8 @@ module.exports = {
},
icon: function(req,res) {
var icon = req.params.icon;
var module = req.params.module;
var scope = req.params.scope;
var module = scope ? scope + '/' + req.params.module : req.params.module;
var iconPath = redNodes.getNodeIconPath(module,icon);
res.sendFile(iconPath);
},

View File

@@ -106,7 +106,7 @@ function start() {
log.error("*****************************************************************");
log.error("* "+log._("runtime.unsupported_version",{component:"Node.js",version:process.version,requires: ">=4"})+" *");
log.error("*****************************************************************");
events.emit("runtime-event",{id:"runtime-unsupported-version",type:"error",text:"notification.errors.unsupportedVersion"});
events.emit("runtime-event",{id:"runtime-unsupported-version",payload:{type:"error",text:"notification.errors.unsupportedVersion"},retain:true});
}
log.info(os.type()+" "+os.release()+" "+os.arch()+" "+os.endianness());
return redNodes.load().then(function() {
@@ -133,21 +133,23 @@ function start() {
}
missingModules[missing.module].types = missingModules[missing.module].types.concat(missing.types);
}
var moduleList = [];
var promises = [];
var installingModules = [];
for (i in missingModules) {
if (missingModules.hasOwnProperty(i)) {
log.warn(" - "+i+" ("+missingModules[i].version+"): "+missingModules[i].types.join(", "));
if (settings.autoInstallModules && i != "node-red") {
redNodes.installModule(i,missingModules[i].version).otherwise(function(err) {
// Error already reported. Need the otherwise handler
// to stop the error propagating any further
});
installingModules.push({id:i,version:missingModules[i].version});
}
}
}
if (!settings.autoInstallModules) {
log.info(log._("server.removing-modules"));
redNodes.cleanModuleList();
} else if (installingModules.length > 0) {
reinstallAttempts = 0;
reinstallModules(installingModules);
}
}
if (settings.settingsFile) {
@@ -161,6 +163,36 @@ function start() {
});
}
var reinstallAttempts;
var reinstallTimeout;
function reinstallModules(moduleList) {
var promises = [];
var failedModules = [];
for (var i=0;i<moduleList.length;i++) {
if (settings.autoInstallModules && i != "node-red") {
promises.push(redNodes.installModule(moduleList[i].id,moduleList[i].version));
}
}
when.settle(promises).then(function(results) {
var reinstallList = [];
for (var i=0;i<results.length;i++) {
if (results[i].state === 'rejected') {
reinstallList.push(moduleList[i]);
} else {
events.emit("runtime-event",{id:"node/added",retain:false,payload:results[i].value.nodes});
}
}
if (reinstallList.length > 0) {
reinstallAttempts++;
// First 5 at 1x timeout, next 5 at 2x, next 5 at 4x, then 8x
var timeout = (settings.autoInstallModulesRetry||30000) * Math.pow(2,Math.min(Math.floor(reinstallAttempts/5),3));
reinstallTimeout = setTimeout(function() {
reinstallModules(reinstallList);
},timeout);
}
});
}
function reportMetrics() {
var memUsage = process.memoryUsage();
@@ -186,6 +218,9 @@ function stop() {
clearInterval(runtimeMetricInterval);
runtimeMetricInterval = null;
}
if (reinstallTimeout) {
clearTimeout(reinstallTimeout);
}
started = false;
return redNodes.stopFlows();
}

View File

@@ -58,7 +58,7 @@ function init(runtime) {
log.info(log._("nodes.flows.registered-missing", {type:type}));
activeFlowConfig.missingTypes.splice(i,1);
if (activeFlowConfig.missingTypes.length === 0 && started) {
events.emit("runtime-event",{id:"runtime-state"});
events.emit("runtime-event",{id:"runtime-state",retain: true});
start();
}
}
@@ -135,13 +135,13 @@ function setFlows(_config,type,muteLog) {
return stop(type,diff,muteLog).then(function() {
context.clean(activeFlowConfig);
start(type,diff,muteLog).then(function() {
events.emit("runtime-event",{id:"runtime-deploy",revision:flowRevision});
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true});
});
return flowRevision;
}).otherwise(function(err) {
})
} else {
events.emit("runtime-event",{id:"runtime-deploy",revision:flowRevision});
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true});
}
});
}
@@ -251,7 +251,7 @@ function start(type,diff,muteLog) {
log.info(log._("nodes.flows.missing-type-install-2"));
log.info(" "+settings.userDir);
}
events.emit("runtime-event",{id:"runtime-state",type:"warning",text:"notification.warnings.missing-types"});
events.emit("runtime-event",{id:"runtime-state",payload:{type:"warning",text:"notification.warnings.missing-types"},retain:true});
return when.resolve();
}
if (!muteLog) {
@@ -310,7 +310,7 @@ function start(type,diff,muteLog) {
}
}
events.emit("nodes-started");
events.emit("runtime-event",{id:"runtime-state"});
events.emit("runtime-event",{id:"runtime-state",retain:true});
if (!muteLog) {
if (type !== "full") {

View File

@@ -30,8 +30,6 @@ var library = require("./library");
var events = require("../events");
var child_process = require('child_process');
var settings;
/**

View File

@@ -131,7 +131,7 @@ function installModule(module,version) {
resolve(require("./index").addModule(module).then(reportAddedModules));
} else {
log.info(log._("server.install.upgraded",{name:module, version:version}));
events.emit("runtime-event",{id:"restart-required",type:"warning",text:"notification.warnings.restartRequired"});
events.emit("runtime-event",{id:"restart-required",payload:{type:"warning",text:"notification.warnings.restartRequired"},retain:true});
resolve(require("./registry").setModulePendingUpdated(module,version));
}
}

View File

@@ -128,7 +128,7 @@ function saveNodeList() {
}
}
if (hadPending && !hasPending) {
events.emit("runtime-event",{id:"restart-required"});
events.emit("runtime-event",{id:"restart-required",retain: true});
}
if (settings.available()) {
return settings.set("nodes",moduleList);
@@ -599,6 +599,9 @@ function getNodeIconPath(module,icon) {
}
}
}
if (module !== "node-red") {
return getNodeIconPath("node-red", icon);
}
return defaultIcon;
}

View File

@@ -196,7 +196,7 @@ function listFlows(path) {
if (r.value.fn) {
var name = r.value.name;
if (!name) {
name = r.value.fn.split(".")[0];
name = r.value.fn.replace(/\.json$/, "");
}
result.f = result.f || [];
result.f.push(name);

View File

@@ -186,9 +186,19 @@ var localfilesystem = {
fs.statSync(fspath.join(process.env.NODE_RED_HOME,".config.json"));
settings.userDir = process.env.NODE_RED_HOME;
} catch(err) {
settings.userDir = fspath.join(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE || process.env.NODE_RED_HOME,".node-red");
if (!settings.readOnly) {
promises.push(promiseDir(fspath.join(settings.userDir,"node_modules")));
try {
// Consider compatibility for older versions
if (process.env.HOMEPATH) {
fs.statSync(fspath.join(process.env.HOMEPATH,".node-red",".config.json"));
settings.userDir = fspath.join(process.env.HOMEPATH,".node-red");
}
} catch(err) {
}
if (!settings.userDir) {
settings.userDir = fspath.join(process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH || process.env.NODE_RED_HOME,".node-red");
if (!settings.readOnly) {
promises.push(promiseDir(fspath.join(settings.userDir,"node_modules")));
}
}
}
}
@@ -409,6 +419,9 @@ var localfilesystem = {
if (settings.readOnly) {
return when.resolve();
}
if (type === "flows" && !path.endsWith(".json")) {
path += ".json";
}
var fn = fspath.join(libDir, type, path);
var headers = "";
for (var i in meta) {

View File

@@ -338,7 +338,7 @@ function prepareJSONataExpression(value,node) {
return node.context().flow.get(val);
});
expr.assign('globalContext',function(val) {
return node.context().global(val);
return node.context().global.get(val);
});
expr._legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(value);
return expr;

View File

@@ -47,7 +47,7 @@ describe('trigger node', function() {
});
it("should be able to set delay in seconds", function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"s", duration:1, "wires":[[]]}];
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"s", duration:"1", "wires":[[]]}];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
n1.should.have.property('duration', 1000);
@@ -56,7 +56,7 @@ describe('trigger node', function() {
});
it("should be able to set delay in minutes", function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"min", duration:1, "wires":[[]]}];
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"min", duration:"1", "wires":[[]]}];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
n1.should.have.property('duration', 60000);
@@ -65,7 +65,7 @@ describe('trigger node', function() {
});
it("should be able to set delay in hours", function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"hr", duration:1, "wires":[[]]}];
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"hr", duration:"1", "wires":[[]]}];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
n1.should.have.property('duration', 3600000);
@@ -74,7 +74,7 @@ describe('trigger node', function() {
});
it('should output 1 then 0 when triggered (default)', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:20, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"20", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -95,7 +95,7 @@ describe('trigger node', function() {
});
it('should ignore any other inputs while triggered if extend is false', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:50,wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"50",wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -137,7 +137,7 @@ describe('trigger node', function() {
});
it('should handle true and false as strings and delay of 0', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"true",op1type:"val",op2:"false",op2type:"val",duration:30, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"true",op1type:"val",op2:"false",op2type:"val",duration:"30", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -162,7 +162,7 @@ describe('trigger node', function() {
});
it('should be able to not output anything on first trigger', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"nul", op1:"true",op2:"false",op2type:"val",duration:30, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"nul", op1:"true",op2:"false",op2type:"val",duration:"30", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -180,7 +180,7 @@ describe('trigger node', function() {
});
it('should be able to not output anything on second edge', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op2type:"nul", op1:"true",op1type:"val", op2:"false", duration:30, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op2type:"nul", op1:"true",op1type:"val", op2:"false", duration:"30", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -199,7 +199,7 @@ describe('trigger node', function() {
});
it('should be able to extend the delay', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op1:"false", op2:"true", duration:100, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op1:"false", op2:"true", duration:"100", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -226,7 +226,7 @@ describe('trigger node', function() {
});
it('should be able to extend the delay (but with no 2nd output)', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op2type:"nul", op1:"false", op2:"true", duration:50, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op2type:"nul", op1:"false", op2:"true", duration:"50", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -256,7 +256,7 @@ describe('trigger node', function() {
});
it('should be able to extend the delay and output the 2nd payload', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"nul", op2type:"payl", op1:"false", op2:"true", duration:50, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"nul", op2type:"payl", op1:"false", op2:"true", duration:"50", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -285,7 +285,7 @@ describe('trigger node', function() {
});
it('should be able output the 2nd payload', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"false", op1type:"nul", op2type:"payl", op1:"false", op2:"true", duration:50, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"false", op1type:"nul", op2type:"payl", op1:"false", op2:"true", duration:"50", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -314,7 +314,7 @@ describe('trigger node', function() {
});
it('should be able to apply mustache templates to payloads', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"val", op1:"{{payload}}", op2:"{{topic}}", duration:50, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"val", op1:"{{payload}}", op2:"{{topic}}", duration:"50", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -335,7 +335,7 @@ describe('trigger node', function() {
});
it('should handle string null as null', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"pay", op1:"null", op2:"null", duration:40, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"pay", op1:"null", op2:"null", duration:"40", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -356,7 +356,7 @@ describe('trigger node', function() {
});
it('should be able to set infinite timeout, and clear timeout', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:0, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"0", extend: false, wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -368,6 +368,9 @@ describe('trigger node', function() {
});
setTimeout( function() {
if (c === 2) { done(); }
else {
done(new Error("Too many messages received"));
}
},20);
n1.emit("input", {payload:null}); // trigger
n1.emit("input", {payload:null}); // blocked
@@ -378,7 +381,7 @@ describe('trigger node', function() {
});
it('should be able to set infinite timeout, and clear timeout by message', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"boo", duration:0, wires:[["n2"]] },
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"boo", duration:"0", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -390,6 +393,9 @@ describe('trigger node', function() {
});
setTimeout( function() {
if (c === 2) { done(); }
else {
done(new Error("Too many messages received"));
}
},20);
n1.emit("input", {payload:null}); // trigger
n1.emit("input", {payload:null}); // blocked

View File

@@ -328,6 +328,30 @@ describe('HTTP Request Node', function() {
});
});
it('send a payload of 0 as the body of a POST as text/plain', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}];
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('payload');
msg.payload.body.should.eql('0');
msg.payload.headers.should.have.property('content-length','1');
msg.payload.headers.should.have.property('content-type').which.startWith('text/plain');
msg.should.have.property('statusCode',200);
msg.should.have.property('headers');
done();
} catch(err) {
done(err);
}
});
n1.receive({payload:0, headers: { 'content-type': 'text/plain'}});
});
});
it('send an Object payload as the body of a POST', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}];

View File

@@ -426,7 +426,7 @@ describe('JOIN node', function() {
});
it('should accumulate a merged object', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"merged",mode:"custom",accumulate:true},
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"merged",mode:"custom",accumulate:true, count:1},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -455,7 +455,7 @@ describe('JOIN node', function() {
});
it('should be able to reset an accumulation', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"merged",accumulate:true,mode:"custom"},
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"merged",accumulate:true,mode:"custom", count:1},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -519,7 +519,7 @@ describe('JOIN node', function() {
});
it('should join strings with a specifed character after a timeout', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"string", timeout:0.05, count:10, joiner:",",mode:"custom"},
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"string", timeout:0.05, count:"", joiner:",",mode:"custom"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
@@ -539,7 +539,7 @@ describe('JOIN node', function() {
});
it('should join strings with a specifed character and complete when told to', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"string", timeout:5, count:100, joiner:"\n",mode:"custom"},
var flow = [{id:"n1", type:"join", wires:[["n2"]], build:"string", timeout:5, count:0, joiner:"\n",mode:"custom"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");

View File

@@ -495,21 +495,31 @@ describe('file Nodes', function() {
});
it('should handle a file read error', function(done) {
var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":"badfile", "format":""}];
var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":"badfile", "format":"", wires:[["n2"]]},
{id:"n2", type:"helper"}
];
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileInNode1");
setTimeout(function() {
var logEvents = helper.log().args.filter(function(evt) {
return evt[0].type == "file in";
});
logEvents.should.have.length(1);
logEvents[0][0].should.have.a.property('msg');
logEvents[0][0].msg.toString().should.startWith("Error");
done();
},wait);
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.not.have.property('payload');
msg.should.have.property("error");
msg.error.should.have.property("code","ENOENT");
var logEvents = helper.log().args.filter(function(evt) {
return evt[0].type == "file in";
});
logEvents.should.have.length(1);
logEvents[0][0].should.have.a.property('msg');
logEvents[0][0].msg.toString().should.startWith("Error");
done();
} catch(err) {
done(err);
}
});
n1.receive({payload:""});
});
});
});
});

View File

@@ -22,7 +22,6 @@ var sinon = require('sinon');
var when = require('when');
var nodes = require("../../../red/api/nodes");
var comms = require("../../../red/api/comms");
var locales = require("../../../red/api/locales");
describe("nodes api", function() {
@@ -35,6 +34,9 @@ describe("nodes api", function() {
info: function(){},
warn: function(){}
}
runtime.events = {
emit: function(){}
}
nodes.init(runtime);
}
@@ -49,15 +51,11 @@ describe("nodes api", function() {
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.putModule);
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.putSet);
app.delete("/nodes/:id",nodes.delete);
sinon.stub(comms,"publish");
sinon.stub(locales,"determineLangFromHeaders", function() {
return "en-US";
});
});
after(function() {
comms.publish.restore();
});
describe('get nodes', function() {
it('returns node list', function(done) {

View File

@@ -55,7 +55,7 @@ describe("theme handler", function() {
page: {
title: "Test Page Title",
favicon: "/absolute/path/to/theme/icon",
css: "/absolute/path/to/custom/css/file",
css: "/absolute/path/to/custom/css/file.css",
scripts: "/absolute/path/to/script.js"
},
header: {
@@ -69,10 +69,6 @@ describe("theme handler", function() {
icon: "/absolute/path/to/deploy/button/image" // or null to remove image
},
customScripts: [
"/absolute/path/to/script.js"
],
menu: { // Hide unwanted menu items by id. see editor/js/main.js:loadEditor for complete list
"menu-item-import-library": false,
"menu-item-export-library": false,
@@ -92,14 +88,19 @@ describe("theme handler", function() {
}});
theme.app();
var context = theme.context();
context.should.have.a.property("page");
context.page.should.have.a.property("title","Test Page Title");
context.should.have.a.property("header");
context.header.should.have.a.property("title","Test Header Title");
context.page.should.have.a.property("css");
context.page.css.should.have.lengthOf(1);
context.page.css[0].should.eql('theme/css/file.css');
context.page.should.have.a.property("scripts");
context.page.scripts.should.have.lengthOf(1);
context.page.scripts[0].should.eql('theme/scripts/script.js');
var settings = theme.settings();
settings.should.have.a.property("deployButton");

View File

@@ -141,7 +141,7 @@ describe("runtime", function() {
{ module:"node-red",enabled:true,loaded:false,types:["typeC","typeD"]} // missing
].filter(cb);
});
var serverInstallModule = sinon.stub(redNodes,"installModule",function(name) { return when.resolve();});
var serverInstallModule = sinon.stub(redNodes,"installModule",function(name) { return when.resolve({nodes:[]});});
runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return when.resolve();}});
sinon.stub(console,"log");
runtime.start().then(function() {

View File

@@ -497,6 +497,12 @@ describe("red/nodes/registry/registry",function() {
var iconPath = typeRegistry.getNodeIconPath('test-module','test_icon.png');
iconPath.should.eql(testIcon);
});
it('returns the debug icon when getting an unknown module', function() {
var debugIcon = path.resolve(__dirname+'/../../../../../public/icons/debug.png');
var iconPath = typeRegistry.getNodeIconPath('unknown-module', 'debug.png');
iconPath.should.eql(debugIcon);
});
});
});

View File

@@ -43,7 +43,7 @@ describe('LocalFileSystem', function() {
});
it('should set userDir to NRH is .config.json present',function(done) {
it('should set userDir to NRH if .config.json presents',function(done) {
var oldNRH = process.env.NODE_RED_HOME;
process.env.NODE_RED_HOME = path.join(userDir,"NRH");
fs.mkdirSync(process.env.NODE_RED_HOME);
@@ -65,11 +65,39 @@ describe('LocalFileSystem', function() {
});
});
it('should set userDir to HOMEPATH/.node-red if .config.json presents',function(done) {
var oldNRH = process.env.NODE_RED_HOME;
process.env.NODE_RED_HOME = path.join(userDir,"NRH");
var oldHOMEPATH = process.env.HOMEPATH;
process.env.HOMEPATH = path.join(userDir,"HOMEPATH");
fs.mkdirSync(process.env.HOMEPATH);
fs.mkdirSync(path.join(process.env.HOMEPATH,".node-red"));
fs.writeFileSync(path.join(process.env.HOMEPATH,".node-red",".config.json"),"{}","utf8");
var settings = {};
localfilesystem.init(settings).then(function() {
try {
fs.existsSync(path.join(process.env.HOMEPATH,".node-red","lib")).should.be.true();
fs.existsSync(path.join(process.env.HOMEPATH,".node-red","lib",'flows')).should.be.true();
settings.userDir.should.equal(path.join(process.env.HOMEPATH,".node-red"));
done();
} catch(err) {
done(err);
} finally {
process.env.NODE_RED_HOME = oldNRH;
process.env.NODE_HOMEPATH = oldHOMEPATH;
}
}).otherwise(function(err) {
done(err);
});
});
it('should set userDir to HOME/.node-red',function(done) {
var oldNRH = process.env.NODE_RED_HOME;
process.env.NODE_RED_HOME = path.join(userDir,"NRH");
var oldHOME = process.env.HOME;
process.env.HOME = path.join(userDir,"HOME");
var oldHOMEPATH = process.env.HOMEPATH;
process.env.HOMEPATH = path.join(userDir,"HOMEPATH");
fs.mkdirSync(process.env.HOME);
var settings = {};
@@ -84,6 +112,38 @@ describe('LocalFileSystem', function() {
} finally {
process.env.NODE_RED_HOME = oldNRH;
process.env.HOME = oldHOME;
process.env.HOMEPATH = oldHOMEPATH;
}
}).otherwise(function(err) {
done(err);
});
});
it('should set userDir to USERPROFILE/.node-red',function(done) {
var oldNRH = process.env.NODE_RED_HOME;
process.env.NODE_RED_HOME = "";
var oldHOME = process.env.HOME;
process.env.HOME = "";
var oldHOMEPATH = process.env.HOMEPATH;
process.env.HOMEPATH = path.join(userDir,"HOMEPATH");
var oldUSERPROFILE = process.env.USERPROFILE;
process.env.USERPROFILE = path.join(userDir,"USERPROFILE");
fs.mkdirSync(process.env.USERPROFILE);
var settings = {};
localfilesystem.init(settings).then(function() {
try {
fs.existsSync(path.join(process.env.USERPROFILE,".node-red","lib")).should.be.true();
fs.existsSync(path.join(process.env.USERPROFILE,".node-red","lib",'flows')).should.be.true();
settings.userDir.should.equal(path.join(process.env.USERPROFILE,".node-red"));
done();
} catch(err) {
done(err);
} finally {
process.env.NODE_RED_HOME = oldNRH;
process.env.HOME = oldHOME;
process.env.HOMEPATH = oldHOMEPATH;
process.env.USERPROFILE = oldUSERPROFILE;
}
}).otherwise(function(err) {
done(err);
@@ -527,9 +587,13 @@ describe('LocalFileSystem', function() {
fs.mkdirSync(path.join(objLib,"A"));
fs.mkdirSync(path.join(objLib,"B"));
fs.mkdirSync(path.join(objLib,"B","C"));
fs.writeFileSync(path.join(objLib,"file1.js"),"// abc: def\n// not a metaline \n\n Hi",'utf8');
fs.writeFileSync(path.join(objLib,"B","file2.js"),"// ghi: jkl\n// not a metaline \n\n Hi",'utf8');
fs.writeFileSync(path.join(objLib,"B","flow.json"),"Hi",'utf8');
if (type === "functions" || type === "object") {
fs.writeFileSync(path.join(objLib,"file1.js"),"// abc: def\n// not a metaline \n\n Hi",'utf8');
fs.writeFileSync(path.join(objLib,"B","file2.js"),"// ghi: jkl\n// not a metaline \n\n Hi",'utf8');
}
if (type === "flows" || type === "object") {
fs.writeFileSync(path.join(objLib,"B","flow.json"),"Hi",'utf8');
}
}
it('should return a directory listing of library objects',function(done) {
@@ -584,17 +648,17 @@ describe('LocalFileSystem', function() {
});
});
it('should return a newly saved library object',function(done) {
it('should return a newly saved library function',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
createObjectLibrary();
localfilesystem.getLibraryEntry('object','B').then(function(flows) {
flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' }, {fn:'flow.json'} ]);
createObjectLibrary("functions");
localfilesystem.getLibraryEntry('functions','B').then(function(flows) {
flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]);
var ft = path.join("B","D","file3.js");
localfilesystem.saveLibraryEntry('object',ft,{mno:'pqr'},"// another non meta line\n\n Hi There").then(function() {
localfilesystem.saveLibraryEntry('functions',ft,{mno:'pqr'},"// another non meta line\n\n Hi There").then(function() {
setTimeout(function() {
localfilesystem.getLibraryEntry('object',path.join("B","D")).then(function(flows) {
localfilesystem.getLibraryEntry('functions',path.join("B","D")).then(function(flows) {
flows.should.eql([ { mno: 'pqr', fn: 'file3.js' } ]);
localfilesystem.getLibraryEntry('object',ft).then(function(body) {
localfilesystem.getLibraryEntry('functions',ft).then(function(body) {
body.should.eql("// another non meta line\n\n Hi There");
done();
}).otherwise(function(err) {
@@ -615,4 +679,35 @@ describe('LocalFileSystem', function() {
});
});
it('should return a newly saved library flow',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
createObjectLibrary("flows");
localfilesystem.getLibraryEntry('flows','B').then(function(flows) {
flows.should.eql([ 'C', {fn:'flow.json'} ]);
var ft = path.join("B","D","file3");
localfilesystem.saveLibraryEntry('flows',ft,{mno:'pqr'},"Hi").then(function() {
setTimeout(function() {
localfilesystem.getLibraryEntry('flows',path.join("B","D")).then(function(flows) {
flows.should.eql([ { mno: 'pqr', fn: 'file3.json' } ]);
localfilesystem.getLibraryEntry('flows',ft+".json").then(function(body) {
body.should.eql("Hi");
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
})}
, 50);
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
});

View File

@@ -381,4 +381,48 @@ describe("red/util", function() {
it('pass http request',function() { normalise("http request", "httpRequest") });
it('pass HttpRequest',function() { normalise("HttpRequest", "httpRequest") });
});
describe('prepareJSONataExpression', function() {
it('prepares an expression', function() {
var result = util.prepareJSONataExpression('payload',{});
result.should.have.property('evaluate');
result.should.have.property('assign');
result.should.have.property('_legacyMode', false);
});
it('prepares a legacyMode expression', function() {
var result = util.prepareJSONataExpression('msg.payload',{});
result.should.have.property('evaluate');
result.should.have.property('assign');
result.should.have.property('_legacyMode', true);
});
});
describe('evaluateJSONataExpression', function() {
it('evaluates an expression', function() {
var expr = util.prepareJSONataExpression('payload',{});
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
result.should.eql("hello");
});
it('evaluates a legacyMode expression', function() {
var expr = util.prepareJSONataExpression('msg.payload',{});
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
result.should.eql("hello");
});
it('accesses flow context from an expression', function() {
var expr = util.prepareJSONataExpression('$flowContext("foo")',{context:function() { return {flow:{get: function(key) { return {'foo':'bar'}[key]}}}}});
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
result.should.eql("bar");
});
it('handles non-existant flow context variable', function() {
var expr = util.prepareJSONataExpression('$flowContext("nonExistant")',{context:function() { return {flow:{get: function(key) { return {'foo':'bar'}[key]}}}}});
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
should.not.exist(result);
});
it('handles non-existant global context variable', function() {
var expr = util.prepareJSONataExpression('$globalContext("nonExistant")',{context:function() { return {global:{get: function(key) { return {'foo':'bar'}[key]}}}}});
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
should.not.exist(result);
});
});
});