mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge branch 'master' into dev
This commit is contained in:
@@ -320,7 +320,7 @@
|
||||
}
|
||||
// but replace with repeat one if set to repeat
|
||||
if ((this.repeat && this.repeat != 0) || this.crontab) {
|
||||
suffix = " ↻";
|
||||
suffix = "\t↻";
|
||||
}
|
||||
if (this.name) {
|
||||
return this.name+suffix;
|
||||
|
@@ -109,9 +109,8 @@ module.exports = function(RED) {
|
||||
}
|
||||
const p = props.shift()
|
||||
const property = p.p;
|
||||
const value = p.v ? p.v : '';
|
||||
const valueType = p.vt ? p.vt : 'str';
|
||||
|
||||
const value = p.v !== undefined ? p.v : '';
|
||||
const valueType = p.vt !== undefined ? p.vt : 'str';
|
||||
if (property) {
|
||||
if (valueType === "jsonata") {
|
||||
if (p.v) {
|
||||
|
@@ -86,7 +86,7 @@
|
||||
},
|
||||
label: function() {
|
||||
var suffix = "";
|
||||
if (this.console === true || this.console === "true") { suffix = " ⇲"; }
|
||||
if (this.console === true || this.console === "true") { suffix = "\t⇲"; }
|
||||
if (this.targetType === "jsonata") {
|
||||
return (this.name || "JSONata") + suffix;
|
||||
}
|
||||
@@ -195,6 +195,119 @@
|
||||
node.dirty = true;
|
||||
});
|
||||
RED.view.redraw();
|
||||
},
|
||||
requestDebugNodeList: function(filteredNodes) {
|
||||
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
||||
var workspaceOrderMap = {};
|
||||
workspaceOrder.forEach(function(ws,i) {
|
||||
workspaceOrderMap[ws] = i;
|
||||
});
|
||||
|
||||
var candidateNodes = [];
|
||||
var candidateSFs = [];
|
||||
var subflows = {};
|
||||
RED.nodes.eachNode(function (n) {
|
||||
var nt = n.type;
|
||||
if (nt === "debug") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateNodes.push(n);
|
||||
}
|
||||
else {
|
||||
var sf = RED.nodes.subflow(n.z);
|
||||
if (sf) {
|
||||
subflows[sf.id] = {
|
||||
debug: true,
|
||||
subflows: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nt.substring(0, 8) === "subflow:") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateSFs.push(n);
|
||||
}
|
||||
else {
|
||||
var psf = RED.nodes.subflow(n.z);
|
||||
if (psf) {
|
||||
var sid = nt.substring(8);
|
||||
var item = subflows[psf.id];
|
||||
if (!item) {
|
||||
item = {
|
||||
debug: undefined,
|
||||
subflows: {}
|
||||
};
|
||||
subflows[psf.id] = item;
|
||||
}
|
||||
item.subflows[sid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
candidateSFs.forEach(function (sf) {
|
||||
var sid = sf.type.substring(8);
|
||||
if (containsDebug(sid, subflows)) {
|
||||
candidateNodes.push(sf);
|
||||
}
|
||||
});
|
||||
|
||||
candidateNodes.sort(function(A,B) {
|
||||
var wsA = workspaceOrderMap[A.z];
|
||||
var wsB = workspaceOrderMap[B.z];
|
||||
if (wsA !== wsB) {
|
||||
return wsA-wsB;
|
||||
}
|
||||
var labelA = RED.utils.getNodeLabel(A,A.id);
|
||||
var labelB = RED.utils.getNodeLabel(B,B.id);
|
||||
return labelA.localeCompare(labelB);
|
||||
});
|
||||
var currentWs = null;
|
||||
var data = [];
|
||||
var currentFlow;
|
||||
var currentSelectedCount = 0;
|
||||
candidateNodes.forEach(function(node) {
|
||||
if (currentWs !== node.z) {
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
currentSelectedCount = 0;
|
||||
currentWs = node.z;
|
||||
var parent = RED.nodes.workspace(currentWs) || RED.nodes.subflow(currentWs);
|
||||
currentFlow = {
|
||||
label: RED.utils.getNodeLabel(parent, currentWs),
|
||||
}
|
||||
if (!parent.disabled) {
|
||||
currentFlow.children = [];
|
||||
currentFlow.checkbox = true;
|
||||
} else {
|
||||
currentFlow.class = "disabled"
|
||||
}
|
||||
data.push(currentFlow);
|
||||
}
|
||||
if (currentFlow.children) {
|
||||
if (!filteredNodes[node.id]) {
|
||||
currentSelectedCount++;
|
||||
}
|
||||
currentFlow.children.push({
|
||||
label: RED.utils.getNodeLabel(node,node.id),
|
||||
node: {
|
||||
id: node.id
|
||||
},
|
||||
checkbox: true,
|
||||
selected: !filteredNodes[node.id]
|
||||
});
|
||||
}
|
||||
});
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
if (subWindow) {
|
||||
try {
|
||||
subWindow.postMessage({event:"refreshDebugNodeList", nodes:data},"*");
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
RED.debug.refreshDebugNodeList(data)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -396,6 +509,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
function containsDebug(sid, map) {
|
||||
var item = map[sid];
|
||||
if (item) {
|
||||
if (item.debug === undefined) {
|
||||
var sfs = Object.keys(item.subflows);
|
||||
var contain = false;
|
||||
for (var i = 0; i < sfs.length; i++) {
|
||||
var sf = sfs[i];
|
||||
if (containsDebug(sf, map)) {
|
||||
contain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item.debug = contain;
|
||||
}
|
||||
return item.debug;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$("#red-ui-sidebar-debug-open").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
|
||||
@@ -427,6 +560,8 @@
|
||||
options.messageSourceClick(msg.id,msg._alias,msg.path);
|
||||
} else if (msg.event === "clear") {
|
||||
options.clear();
|
||||
} else if (msg.event === "requestDebugNodeList") {
|
||||
options.requestDebugNodeList(msg.filteredNodes)
|
||||
}
|
||||
};
|
||||
window.addEventListener('message',this.handleWindowMessage);
|
||||
|
@@ -275,7 +275,7 @@
|
||||
value: [],
|
||||
type: "link in[]",
|
||||
validate: function (v, opt) {
|
||||
if ((this.linkType === "static" && v.length > 0)
|
||||
if (((this.linkType || "static") === "static" && v.length > 0)
|
||||
|| this.linkType === "dynamic") {
|
||||
return true;
|
||||
}
|
||||
|
@@ -167,19 +167,13 @@ RED.debug = (function() {
|
||||
var menu = RED.popover.menu({
|
||||
options: options,
|
||||
onselect: function(item) {
|
||||
if (item.value !== filterType) {
|
||||
filterType = item.value;
|
||||
$('#red-ui-sidebar-debug-filter span').text(RED._('node-red:debug.sidebar.'+filterType));
|
||||
refreshMessageList();
|
||||
RED.settings.set("debug.filter",filterType)
|
||||
}
|
||||
setFilterType(item.value)
|
||||
if (filterType === 'filterSelected') {
|
||||
refreshDebugNodeList();
|
||||
config.requestDebugNodeList(filteredNodes);
|
||||
filterDialog.slideDown(200);
|
||||
filterDialogShown = true;
|
||||
debugNodeTreeList.focus();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
menu.show({
|
||||
@@ -254,131 +248,7 @@ RED.debug = (function() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function containsDebug(sid, map) {
|
||||
var item = map[sid];
|
||||
if (item) {
|
||||
if (item.debug === undefined) {
|
||||
var sfs = Object.keys(item.subflows);
|
||||
var contain = false;
|
||||
for (var i = 0; i < sfs.length; i++) {
|
||||
var sf = sfs[i];
|
||||
if (containsDebug(sf, map)) {
|
||||
contain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item.debug = contain;
|
||||
}
|
||||
return item.debug;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function refreshDebugNodeList() {
|
||||
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
||||
var workspaceOrderMap = {};
|
||||
workspaceOrder.forEach(function(ws,i) {
|
||||
workspaceOrderMap[ws] = i;
|
||||
});
|
||||
|
||||
var candidateNodes = [];
|
||||
var candidateSFs = [];
|
||||
var subflows = {};
|
||||
RED.nodes.eachNode(function (n) {
|
||||
var nt = n.type;
|
||||
if (nt === "debug") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateNodes.push(n);
|
||||
}
|
||||
else {
|
||||
var sf = RED.nodes.subflow(n.z);
|
||||
if (sf) {
|
||||
subflows[sf.id] = {
|
||||
debug: true,
|
||||
subflows: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nt.substring(0, 8) === "subflow:") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateSFs.push(n);
|
||||
}
|
||||
else {
|
||||
var psf = RED.nodes.subflow(n.z);
|
||||
if (psf) {
|
||||
var sid = nt.substring(8);
|
||||
var item = subflows[psf.id];
|
||||
if (!item) {
|
||||
item = {
|
||||
debug: undefined,
|
||||
subflows: {}
|
||||
};
|
||||
subflows[psf.id] = item;
|
||||
}
|
||||
item.subflows[sid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
candidateSFs.forEach(function (sf) {
|
||||
var sid = sf.type.substring(8);
|
||||
if (containsDebug(sid, subflows)) {
|
||||
candidateNodes.push(sf);
|
||||
}
|
||||
});
|
||||
|
||||
candidateNodes.sort(function(A,B) {
|
||||
var wsA = workspaceOrderMap[A.z];
|
||||
var wsB = workspaceOrderMap[B.z];
|
||||
if (wsA !== wsB) {
|
||||
return wsA-wsB;
|
||||
}
|
||||
var labelA = RED.utils.getNodeLabel(A,A.id);
|
||||
var labelB = RED.utils.getNodeLabel(B,B.id);
|
||||
return labelA.localeCompare(labelB);
|
||||
});
|
||||
var currentWs = null;
|
||||
var data = [];
|
||||
var currentFlow;
|
||||
var currentSelectedCount = 0;
|
||||
candidateNodes.forEach(function(node) {
|
||||
if (currentWs !== node.z) {
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
currentSelectedCount = 0;
|
||||
currentWs = node.z;
|
||||
var parent = RED.nodes.workspace(currentWs) || RED.nodes.subflow(currentWs);
|
||||
currentFlow = {
|
||||
label: RED.utils.getNodeLabel(parent, currentWs),
|
||||
}
|
||||
if (!parent.disabled) {
|
||||
currentFlow.children = [];
|
||||
currentFlow.checkbox = true;
|
||||
} else {
|
||||
currentFlow.class = "disabled"
|
||||
}
|
||||
data.push(currentFlow);
|
||||
}
|
||||
if (currentFlow.children) {
|
||||
if (!filteredNodes[node.id]) {
|
||||
currentSelectedCount++;
|
||||
}
|
||||
currentFlow.children.push({
|
||||
label: RED.utils.getNodeLabel(node,node.id),
|
||||
node: node,
|
||||
checkbox: true,
|
||||
selected: !filteredNodes[node.id]
|
||||
});
|
||||
}
|
||||
});
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
|
||||
function refreshDebugNodeList(data) {
|
||||
debugNodeTreeList.treeList("data", data);
|
||||
}
|
||||
|
||||
@@ -401,7 +271,7 @@ RED.debug = (function() {
|
||||
},200);
|
||||
}
|
||||
function _refreshMessageList(_activeWorkspace) {
|
||||
if (_activeWorkspace) {
|
||||
if (typeof _activeWorkspace === 'string') {
|
||||
activeWorkspace = _activeWorkspace.replace(/\./g,"_");
|
||||
}
|
||||
if (filterType === "filterAll") {
|
||||
@@ -479,12 +349,12 @@ RED.debug = (function() {
|
||||
filteredNodes[n.id] = true;
|
||||
});
|
||||
delete filteredNodes[sourceId];
|
||||
$("#red-ui-sidebar-debug-filterSelected").trigger("click");
|
||||
RED.settings.set('debug.filteredNodes',Object.keys(filteredNodes))
|
||||
setFilterType('filterSelected')
|
||||
refreshMessageList();
|
||||
}},
|
||||
{id:"red-ui-debug-msg-menu-item-clear-filter",label:RED._("node-red:debug.messageMenu.clearFilter"),onselect:function(){
|
||||
$("#red-ui-sidebar-debug-filterAll").trigger("click");
|
||||
clearFilterSettings()
|
||||
refreshMessageList();
|
||||
}}
|
||||
);
|
||||
@@ -713,9 +583,17 @@ RED.debug = (function() {
|
||||
if (!!clearFilter) {
|
||||
clearFilterSettings();
|
||||
}
|
||||
refreshDebugNodeList();
|
||||
config.requestDebugNodeList(filteredNodes);
|
||||
}
|
||||
|
||||
function setFilterType(type) {
|
||||
if (type !== filterType) {
|
||||
filterType = type;
|
||||
$('#red-ui-sidebar-debug-filter span').text(RED._('node-red:debug.sidebar.'+filterType));
|
||||
refreshMessageList();
|
||||
RED.settings.set("debug.filter",filterType)
|
||||
}
|
||||
}
|
||||
function clearFilterSettings() {
|
||||
filteredNodes = {};
|
||||
filterType = 'filterAll';
|
||||
@@ -728,6 +606,7 @@ RED.debug = (function() {
|
||||
init: init,
|
||||
refreshMessageList:refreshMessageList,
|
||||
handleDebugMessage: handleDebugMessage,
|
||||
clearMessageList: clearMessageList
|
||||
clearMessageList: clearMessageList,
|
||||
refreshDebugNodeList: refreshDebugNodeList
|
||||
}
|
||||
})();
|
||||
|
@@ -12,6 +12,9 @@ $(function() {
|
||||
},
|
||||
clear: function() {
|
||||
window.opener.postMessage({event:"clear"},'*');
|
||||
},
|
||||
requestDebugNodeList: function(filteredNodes) {
|
||||
window.opener.postMessage({event: 'requestDebugNodeList', filteredNodes},'*')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +29,8 @@ $(function() {
|
||||
RED.debug.refreshMessageList(evt.data.activeWorkspace);
|
||||
} else if (evt.data.event === "projectChange") {
|
||||
RED.debug.clearMessageList(true);
|
||||
} else if (evt.data.event === "refreshDebugNodeList") {
|
||||
RED.debug.refreshDebugNodeList(evt.data.nodes)
|
||||
}
|
||||
},false);
|
||||
} catch(err) {
|
||||
|
@@ -103,7 +103,6 @@
|
||||
} else if (type === "istype") {
|
||||
r.v = rule.find(".node-input-rule-type-value").typedInput('type');
|
||||
r.vt = rule.find(".node-input-rule-type-value").typedInput('type');
|
||||
r.vt = (r.vt === "number") ? "num" : "str";
|
||||
} else if (type === "jsonata_exp") {
|
||||
r.v = rule.find(".node-input-rule-exp-value").typedInput('value');
|
||||
r.vt = rule.find(".node-input-rule-exp-value").typedInput('type');
|
||||
@@ -168,7 +167,33 @@
|
||||
label:RED._("node-red:common.label.payload"),
|
||||
validate: RED.validators.typedInput("propertyType", false)},
|
||||
propertyType: { value:"msg" },
|
||||
rules: {value:[{t:"eq", v:"", vt:"str"}]},
|
||||
rules: {
|
||||
value:[{t:"eq", v:"", vt:"str"}],
|
||||
validate: function (rules, opt) {
|
||||
let msg;
|
||||
const errors = []
|
||||
if (!rules || rules.length === 0) { return true }
|
||||
for (var i=0;i<rules.length;i++) {
|
||||
const opt = { label: RED._('node-red:switch.label.rule')+' '+(i+1) }
|
||||
const r = rules[i];
|
||||
if (r.hasOwnProperty('v')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v,r.vt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
if (r.hasOwnProperty('v2')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v2,r.v2t,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors.length) {
|
||||
console.log(errors)
|
||||
return errors
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
checkall: {value:"true", required:true},
|
||||
repair: {value:false},
|
||||
outputs: {value:1}
|
||||
@@ -218,7 +243,11 @@
|
||||
if (i > 0) {
|
||||
var lastRule = $("#node-input-rule-container").editableList('getItemAt',i-1);
|
||||
var exportedRule = exportRule(lastRule.element);
|
||||
opt.r.vt = exportedRule.vt;
|
||||
if (exportedRule.t === "istype") {
|
||||
opt.r.vt = (exportedRule.vt === "number") ? "num" : "str";
|
||||
} else {
|
||||
opt.r.vt = exportedRule.vt;
|
||||
}
|
||||
opt.r.v = "";
|
||||
// We could copy the value over as well and preselect it (see the 'activeElement' code below)
|
||||
// But not sure that feels right. Is copying over the last value 'expected' behaviour?
|
||||
|
@@ -19,71 +19,42 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
function isInvalidProperty(v,vt) {
|
||||
if (/msg|flow|global/.test(vt)) {
|
||||
if (!RED.utils.validatePropertyExpression(v)) {
|
||||
return RED._("node-red:change.errors.invalid-prop", {
|
||||
property: v
|
||||
});
|
||||
}
|
||||
} else if (vt === "jsonata") {
|
||||
try{ jsonata(v); } catch(e) {
|
||||
return RED._("node-red:change.errors.invalid-expr", {
|
||||
error: e.message
|
||||
});
|
||||
}
|
||||
} else if (vt === "json") {
|
||||
try{ JSON.parse(v); } catch(e) {
|
||||
return RED._("node-red:change.errors.invalid-json-data", {
|
||||
error: e.message
|
||||
});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RED.nodes.registerType('change', {
|
||||
color: "#E2D96E",
|
||||
category: 'function',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
rules:{value:[{t:"set",p:"payload",pt:"msg",to:"",tot:"str"}],validate: function(rules, opt) {
|
||||
var msg;
|
||||
if (!rules || rules.length === 0) { return true }
|
||||
for (var i=0;i<rules.length;i++) {
|
||||
var r = rules[i];
|
||||
if (r.t === 'set') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
rules:{
|
||||
value:[{t:"set",p:"payload",pt:"msg",to:"",tot:"str"}],
|
||||
validate: function(rules, opt) {
|
||||
let msg;
|
||||
const errors = []
|
||||
if (!rules || rules.length === 0) { return true }
|
||||
for (var i=0;i<rules.length;i++) {
|
||||
const opt = { label: RED._('node-red:change.label.rule')+' '+(i+1) }
|
||||
const r = rules[i];
|
||||
if (r.t === 'set' || r.t === 'change' || r.t === 'delete' || r.t === 'move') {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.p,r.pt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
if (msg = isInvalidProperty(r.to,r.tot)) {
|
||||
return msg;
|
||||
if (r.t === 'set' || r.t === 'change' || r.t === 'move') {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.to,r.tot,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
} else if (r.t === 'change') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
}
|
||||
if(msg = isInvalidProperty(r.from,r.fromt)) {
|
||||
return msg;
|
||||
}
|
||||
if(msg = isInvalidProperty(r.to,r.tot)) {
|
||||
return msg;
|
||||
}
|
||||
} else if (r.t === 'delete') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
}
|
||||
} else if (r.t === 'move') {
|
||||
if (msg = isInvalidProperty(r.p,r.pt)) {
|
||||
return msg;
|
||||
}
|
||||
if (msg = isInvalidProperty(r.to,r.tot)) {
|
||||
return msg;
|
||||
if (r.t === 'change') {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.from,r.fromt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors.length) {
|
||||
return errors
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}},
|
||||
},
|
||||
// legacy
|
||||
action: {value:""},
|
||||
property: {value:""},
|
||||
|
@@ -57,7 +57,12 @@
|
||||
action: {value:"scale"},
|
||||
round: {value:false},
|
||||
property: {value:"payload",required:true,
|
||||
label:RED._("node-red:common.label.property")},
|
||||
label:RED._("node-red:common.label.property"),
|
||||
validate: RED.validators.typedInput({ type: 'msg' })
|
||||
},
|
||||
|
||||
|
||||
// RED.validators.typedInput("propertyType", false)},
|
||||
name: {value:""}
|
||||
},
|
||||
inputs: 1,
|
||||
|
@@ -153,7 +153,7 @@
|
||||
}
|
||||
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
||||
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
$("#dialog-form .node-text-editor").css("height",height+"px");
|
||||
this.editor.resize();
|
||||
}
|
||||
});
|
||||
|
@@ -284,7 +284,7 @@ module.exports = function(RED) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (!msg.hasOwnProperty("reset")) {
|
||||
if (maxKeptMsgsCount(node) > 0) {
|
||||
if (node.intervalID === -1) {
|
||||
node.send(msg);
|
||||
|
@@ -56,7 +56,7 @@
|
||||
color:"darksalmon",
|
||||
defaults: {
|
||||
command: {value:""},
|
||||
addpay: {value:""},
|
||||
addpay: {value:"", validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })},
|
||||
append: {value:""},
|
||||
useSpawn: {value:"false"},
|
||||
timer: {value:""},
|
||||
|
@@ -56,9 +56,11 @@
|
||||
inout: {value:"out"},
|
||||
septopics: {value:true},
|
||||
property: {value:"payload", required:true,
|
||||
label:RED._("node-red:rbe.label.property")},
|
||||
label:RED._("node-red:rbe.label.property"),
|
||||
validate: RED.validators.typedInput({ type: 'msg' })},
|
||||
topi: {value:"topic", required:true,
|
||||
label:RED._("node-red:rbe.label.topic")}
|
||||
label:RED._("node-red:rbe.label.topic"),
|
||||
validate: RED.validators.typedInput({ type: 'msg' })}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
|
@@ -104,6 +104,7 @@ module.exports = function(RED) {
|
||||
* @returns `true` if it is a valid topic
|
||||
*/
|
||||
function isValidPublishTopic(topic) {
|
||||
if (topic.length === 0) return false;
|
||||
return !/[\+#\b\f\n\r\t\v\0]/.test(topic);
|
||||
}
|
||||
|
||||
@@ -219,8 +220,8 @@ module.exports = function(RED) {
|
||||
*/
|
||||
function subscriptionHandler(node, datatype ,topic, payload, packet) {
|
||||
const msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain};
|
||||
const v5 = (node && node.brokerConn)
|
||||
? node.brokerConn.v5()
|
||||
const v5 = (node && node.brokerConn)
|
||||
? node.brokerConn.v5()
|
||||
: Object.prototype.hasOwnProperty.call(packet, "properties");
|
||||
if(v5 && packet.properties) {
|
||||
setStrProp(packet.properties, msg, "responseTopic");
|
||||
@@ -451,7 +452,7 @@ module.exports = function(RED) {
|
||||
|
||||
/**
|
||||
* Perform the disconnect action
|
||||
* @param {MQTTInNode|MQTTOutNode} node
|
||||
* @param {MQTTInNode|MQTTOutNode} node
|
||||
* @param {Function} done
|
||||
*/
|
||||
function handleDisconnectAction(node, done) {
|
||||
@@ -611,7 +612,7 @@ module.exports = function(RED) {
|
||||
node.brokerurl = node.url;
|
||||
} else {
|
||||
// if the broker is ws:// or wss:// or tcp://
|
||||
if (node.broker.indexOf("://") > -1) {
|
||||
if ((typeof node.broker === 'string') && node.broker.indexOf("://") > -1) {
|
||||
node.brokerurl = node.broker;
|
||||
// Only for ws or wss, check if proxy env var for additional configuration
|
||||
if (node.brokerurl.indexOf("wss://") > -1 || node.brokerurl.indexOf("ws://") > -1) {
|
||||
@@ -865,7 +866,7 @@ module.exports = function(RED) {
|
||||
* Call end and wait for the client to end (or timeout)
|
||||
* @param {mqtt.MqttClient} client The broker client
|
||||
* @param {number} ms The time to wait for the client to end
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
let waitEnd = (client, ms) => {
|
||||
return new Promise( (resolve, reject) => {
|
||||
@@ -905,7 +906,7 @@ module.exports = function(RED) {
|
||||
node.subid = 1;
|
||||
|
||||
//typedef for subscription object:
|
||||
/**
|
||||
/**
|
||||
* @typedef {Object} Subscription
|
||||
* @property {String} topic - topic to subscribe to
|
||||
* @property {Object} [options] - options object
|
||||
@@ -933,7 +934,7 @@ module.exports = function(RED) {
|
||||
const ref = _ref || 0;
|
||||
let options
|
||||
let qos = 1 // default to QoS 1 (AWS and several other brokers don't support QoS 2)
|
||||
|
||||
|
||||
// if options is an object, then clone it
|
||||
if (typeof _options == "object") {
|
||||
options = RED.util.cloneMessage(_options || {})
|
||||
@@ -947,7 +948,7 @@ module.exports = function(RED) {
|
||||
if (typeof qos === "number" && qos >= 0 && qos <= 2) {
|
||||
options.qos = qos;
|
||||
}
|
||||
|
||||
|
||||
subscription.topic = _topic;
|
||||
subscription.qos = qos;
|
||||
subscription.options = RED.util.cloneMessage(options);
|
||||
@@ -957,16 +958,16 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
/**
|
||||
* If topic is a subscription object, then use that, otherwise look up the topic in
|
||||
* If topic is a subscription object, then use that, otherwise look up the topic in
|
||||
* the subscriptions object. If the topic is not found, then create a new subscription
|
||||
* object and add it to the subscriptions object.
|
||||
* @param {Subscription|String} topic
|
||||
* @param {*} options
|
||||
* @param {*} callback
|
||||
* @param {*} ref
|
||||
* @param {Subscription|String} topic
|
||||
* @param {*} options
|
||||
* @param {*} callback
|
||||
* @param {*} ref
|
||||
*/
|
||||
node.subscribe = function (topic, options, callback, ref) {
|
||||
/** @type {Subscription} */
|
||||
/** @type {Subscription} */
|
||||
let subscription
|
||||
let doCompare = false
|
||||
let changesFound = false
|
||||
@@ -1004,7 +1005,7 @@ module.exports = function(RED) {
|
||||
_brokerConn.unsubscribe(sub.topic, sub.ref, true)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// if subscription is found (or sent in as a parameter), then check for changes.
|
||||
// if there are any changes requested, tidy up the old subscription
|
||||
if (subscription) {
|
||||
@@ -1091,7 +1092,7 @@ module.exports = function(RED) {
|
||||
delete sub[ref]
|
||||
}
|
||||
}
|
||||
// if instructed to remove the actual MQTT client subscription
|
||||
// if instructed to remove the actual MQTT client subscription
|
||||
if (unsub) {
|
||||
// if there are no more subscriptions for the topic, then remove the topic
|
||||
if (Object.keys(sub).length === 0) {
|
||||
|
@@ -452,10 +452,6 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
||||
formData.append(opt, val);
|
||||
} else if (typeof val === 'object' && val.hasOwnProperty('value')) {
|
||||
formData.append(opt,val.value,val.options || {});
|
||||
} else if (Array.isArray(val)) {
|
||||
for (var i=0; i<val.length; i++) {
|
||||
formData.append(opt, val[i])
|
||||
}
|
||||
} else {
|
||||
formData.append(opt,JSON.stringify(val));
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ module.exports = function(RED) {
|
||||
if (!(notemplate && (msg.hasOwnProperty("parts") && msg.parts.hasOwnProperty("index") && msg.parts.index > 0))) {
|
||||
template = clean(node.template);
|
||||
}
|
||||
var ou = "";
|
||||
const ou = [];
|
||||
if (!Array.isArray(msg.payload)) { msg.payload = [ msg.payload ]; }
|
||||
if (node.hdrout !== "none" && node.hdrSent === false) {
|
||||
if ((template.length === 1) && (template[0] === '')) {
|
||||
@@ -74,7 +74,7 @@ module.exports = function(RED) {
|
||||
template = Object.keys(msg.payload[0]);
|
||||
}
|
||||
}
|
||||
ou += template.map(v => v.indexOf(node.sep)!==-1 ? '"'+v+'"' : v).join(node.sep) + node.ret;
|
||||
ou.push(template.map(v => v.indexOf(node.sep)!==-1 ? '"'+v+'"' : v).join(node.sep));
|
||||
if (node.hdrout === "once") { node.hdrSent = true; }
|
||||
}
|
||||
for (var s = 0; s < msg.payload.length; s++) {
|
||||
@@ -93,7 +93,7 @@ module.exports = function(RED) {
|
||||
msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
|
||||
}
|
||||
}
|
||||
ou += msg.payload[s].join(node.sep) + node.ret;
|
||||
ou.push(msg.payload[s].join(node.sep));
|
||||
}
|
||||
else {
|
||||
if ((template.length === 1) && (template[0] === '') && (msg.hasOwnProperty("columns"))) {
|
||||
@@ -105,6 +105,7 @@ module.exports = function(RED) {
|
||||
node.warn(RED._("csv.errors.obj_csv"));
|
||||
tmpwarn = false;
|
||||
}
|
||||
const row = [];
|
||||
for (var p in msg.payload[0]) {
|
||||
/* istanbul ignore else */
|
||||
if (msg.payload[s].hasOwnProperty(p)) {
|
||||
@@ -118,21 +119,22 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (q.indexOf(node.quo) !== -1) { // add double quotes if any quotes
|
||||
q = q.replace(/"/g, '""');
|
||||
ou += node.quo + q + node.quo + node.sep;
|
||||
row.push(node.quo + q + node.quo);
|
||||
}
|
||||
else if (q.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
|
||||
ou += node.quo + q + node.quo + node.sep;
|
||||
row.push(node.quo + q + node.quo);
|
||||
}
|
||||
else { ou += q + node.sep; } // otherwise just add
|
||||
else { row.push(q); } // otherwise just add
|
||||
}
|
||||
}
|
||||
}
|
||||
ou = ou.slice(0,-1) + node.ret;
|
||||
ou.push(row.join(node.sep)); // add separator
|
||||
}
|
||||
else {
|
||||
const row = [];
|
||||
for (var t=0; t < template.length; t++) {
|
||||
if (template[t] === '') {
|
||||
ou += node.sep;
|
||||
row.push('');
|
||||
}
|
||||
else {
|
||||
var tt = template[t];
|
||||
@@ -146,19 +148,20 @@ module.exports = function(RED) {
|
||||
p = RED.util.ensureString(p);
|
||||
if (p.indexOf(node.quo) !== -1) { // add double quotes if any quotes
|
||||
p = p.replace(/"/g, '""');
|
||||
ou += node.quo + p + node.quo + node.sep;
|
||||
row.push(node.quo + p + node.quo);
|
||||
}
|
||||
else if (p.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
|
||||
ou += node.quo + p + node.quo + node.sep;
|
||||
row.push(node.quo + p + node.quo);
|
||||
}
|
||||
else { ou += p + node.sep; } // otherwise just add
|
||||
else { row.push(p); } // otherwise just add
|
||||
}
|
||||
}
|
||||
ou = ou.slice(0,-1) + node.ret; // remove final "comma" and add "newline"
|
||||
ou.push(row.join(node.sep)); // add separator
|
||||
}
|
||||
}
|
||||
}
|
||||
msg.payload = ou;
|
||||
// join lines, don't forget to add the last new line
|
||||
msg.payload = ou.join(node.ret) + node.ret;
|
||||
msg.columns = template.map(v => v.indexOf(',')!==-1 ? '"'+v+'"' : v).join(',');
|
||||
if (msg.payload !== '') { send(msg); }
|
||||
done();
|
||||
|
@@ -41,8 +41,8 @@
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload"},
|
||||
outproperty: {value:"payload"},
|
||||
property: {value:"payload", validate: RED.validators.typedInput({ type: 'msg' }) },
|
||||
outproperty: {value:"payload", validate: RED.validators.typedInput({ type: 'msg' }) },
|
||||
tag: {value:""},
|
||||
ret: {value:"html"},
|
||||
as: {value:"single"}
|
||||
|
@@ -32,6 +32,7 @@
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload",required:true,
|
||||
validate: RED.validators.typedInput({ type: 'msg' }),
|
||||
label:RED._("node-red:json.label.property")},
|
||||
action: {value:""},
|
||||
pretty: {value:false}
|
||||
|
@@ -27,7 +27,8 @@
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload",required:true,
|
||||
label:RED._("node-red:common.label.property")},
|
||||
label:RED._("node-red:common.label.property"),
|
||||
validate: RED.validators.typedInput({ type: 'msg' })},
|
||||
attr: {value:""},
|
||||
chr: {value:""}
|
||||
},
|
||||
|
@@ -16,6 +16,7 @@
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
property: {value:"payload",required:true,
|
||||
validate: RED.validators.typedInput({ type: 'msg' }),
|
||||
label:RED._("node-red:common.label.property")},
|
||||
name: {value:""}
|
||||
},
|
||||
|
@@ -57,7 +57,7 @@
|
||||
arraySplt: {value:1},
|
||||
arraySpltType: {value:"len"},
|
||||
stream: {value:false},
|
||||
addname: {value:""}
|
||||
addname: {value:"", validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
@@ -208,7 +208,22 @@
|
||||
validate:RED.validators.typedInput("propertyType", false)
|
||||
},
|
||||
propertyType: { value:"msg"},
|
||||
key: {value:"topic"},
|
||||
key: {value:"topic", validate: (function () {
|
||||
const typeValidator = RED.validators.typedInput({ type: 'msg' })
|
||||
return function(v, opt) {
|
||||
const joinMode = $("#node-input-mode").val() || this.mode
|
||||
if (joinMode !== 'custom') {
|
||||
return true
|
||||
}
|
||||
const buildType = $("#node-input-build").val() || this.build
|
||||
if (buildType !== 'object') {
|
||||
return true
|
||||
} else {
|
||||
return typeValidator(v, opt)
|
||||
}
|
||||
}
|
||||
})()
|
||||
},
|
||||
joiner: { value:"\\n"},
|
||||
joinerType: { value:"str"},
|
||||
accumulate: { value:"false" },
|
||||
|
@@ -198,7 +198,7 @@
|
||||
category: 'storage',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filename: {value:""},
|
||||
filename: {value:"", validate: RED.validators.typedInput({ typeField: 'filenameType' })},
|
||||
filenameType: {value:"str"},
|
||||
appendNewline: {value:true},
|
||||
createDir: {value:false},
|
||||
@@ -297,7 +297,7 @@
|
||||
category: 'storage',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filename: {value:""},
|
||||
filename: {value:"", validate: RED.validators.typedInput({ typeField: 'filenameType' }) },
|
||||
filenameType: {value:"str"},
|
||||
format: {value:"utf8"},
|
||||
chunk: {value:false},
|
||||
|
Reference in New Issue
Block a user