mirror of
https://github.com/node-red/node-red.git
synced 2025-12-27 15:34:26 +01:00
Merge branch 'dev' into export-module-info
This commit is contained in:
@@ -46,12 +46,12 @@
|
||||
|
||||
<div class="form-row inject-time-row hidden" id="inject-time-row-interval">
|
||||
<span data-i18n="inject.every"></span>
|
||||
<input id="inject-time-interval-count" class="inject-time-count" value="1"></input>
|
||||
<input id="inject-time-interval-count" class="inject-time-count" value="1">
|
||||
<select style="width:100px" id="inject-time-interval-units">
|
||||
<option value="s" data-i18n="inject.seconds"></option>
|
||||
<option value="m" data-i18n="inject.minutes"></option>
|
||||
<option value="h" data-i18n="inject.hours"></option>
|
||||
</select><br/>
|
||||
</select><br>
|
||||
</div>
|
||||
|
||||
<div class="form-row inject-time-row hidden" id="inject-time-row-interval-time">
|
||||
@@ -68,46 +68,46 @@
|
||||
<option value="20">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="0">60</option>
|
||||
</select> <span data-i18n="inject.minutes"></span><br/>
|
||||
</select> <span data-i18n="inject.minutes"></span><br>
|
||||
<span data-i18n="inject.between"></span> <select id="inject-time-interval-time-start" class="inject-time-times"></select>
|
||||
<span data-i18n="inject.and"></span> <select id="inject-time-interval-time-end" class="inject-time-times"></select><br/>
|
||||
<span data-i18n="inject.and"></span> <select id="inject-time-interval-time-end" class="inject-time-times"></select><br>
|
||||
<div id="inject-time-interval-time-days" class="inject-time-days" style="margin-top:5px">
|
||||
<div style="display:inline-block; vertical-align:top; margin-right:5px;" data-i18n="inject.on">on</div>
|
||||
<div style="display:inline-block;">
|
||||
<div>
|
||||
<label><input type='checkbox' checked value='1'/> <span data-i18n="inject.days.0"></span></label>
|
||||
<label><input type='checkbox' checked value='2'/> <span data-i18n="inject.days.1"></span></label>
|
||||
<label><input type='checkbox' checked value='3'/> <span data-i18n="inject.days.2"></span></label>
|
||||
<label><input type='checkbox' checked value='1'> <span data-i18n="inject.days.0"></span></label>
|
||||
<label><input type='checkbox' checked value='2'> <span data-i18n="inject.days.1"></span></label>
|
||||
<label><input type='checkbox' checked value='3'> <span data-i18n="inject.days.2"></span></label>
|
||||
</div>
|
||||
<div>
|
||||
<label><input type='checkbox' checked value='4'/> <span data-i18n="inject.days.3"></span></label>
|
||||
<label><input type='checkbox' checked value='5'/> <span data-i18n="inject.days.4"></span></label>
|
||||
<label><input type='checkbox' checked value='6'/> <span data-i18n="inject.days.5"></span></label>
|
||||
<label><input type='checkbox' checked value='4'> <span data-i18n="inject.days.3"></span></label>
|
||||
<label><input type='checkbox' checked value='5'> <span data-i18n="inject.days.4"></span></label>
|
||||
<label><input type='checkbox' checked value='6'> <span data-i18n="inject.days.5"></span></label>
|
||||
</div>
|
||||
<div>
|
||||
<label><input type='checkbox' checked value='0'/> <span data-i18n="inject.days.6"></span></label>
|
||||
<label><input type='checkbox' checked value='0'> <span data-i18n="inject.days.6"></span></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row inject-time-row hidden" id="inject-time-row-time">
|
||||
<span data-i18n="inject.at"></span> <input type="text" id="inject-time-time" value="12:00"></input><br/>
|
||||
<span data-i18n="inject.at"></span> <input type="text" id="inject-time-time" value="12:00"><br>
|
||||
<div id="inject-time-time-days" class="inject-time-days">
|
||||
<div style="display:inline-block; vertical-align:top; margin-right:5px;" data-i18n="inject.on"></div>
|
||||
<div style="display:inline-block;">
|
||||
<div>
|
||||
<label><input type='checkbox' checked value='1'/> <span data-i18n="inject.days.0"></span></label>
|
||||
<label><input type='checkbox' checked value='2'/> <span data-i18n="inject.days.1"></span></label>
|
||||
<label><input type='checkbox' checked value='3'/> <span data-i18n="inject.days.2"></span></label>
|
||||
<label><input type='checkbox' checked value='1'> <span data-i18n="inject.days.0"></span></label>
|
||||
<label><input type='checkbox' checked value='2'> <span data-i18n="inject.days.1"></span></label>
|
||||
<label><input type='checkbox' checked value='3'> <span data-i18n="inject.days.2"></span></label>
|
||||
</div>
|
||||
<div>
|
||||
<label><input type='checkbox' checked value='4'/> <span data-i18n="inject.days.3"></span></label>
|
||||
<label><input type='checkbox' checked value='5'/> <span data-i18n="inject.days.4"></span></label>
|
||||
<label><input type='checkbox' checked value='6'/> <span data-i18n="inject.days.5"></span></label>
|
||||
<label><input type='checkbox' checked value='4'> <span data-i18n="inject.days.3"></span></label>
|
||||
<label><input type='checkbox' checked value='5'> <span data-i18n="inject.days.4"></span></label>
|
||||
<label><input type='checkbox' checked value='6'> <span data-i18n="inject.days.5"></span></label>
|
||||
</div>
|
||||
<div>
|
||||
<label><input type='checkbox' checked value='0'/> <span data-i18n="inject.days.6"></span></label>
|
||||
<label><input type='checkbox' checked value='0'> <span data-i18n="inject.days.6"></span></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -148,7 +148,7 @@ module.exports = function(RED) {
|
||||
var st = (typeof output === 'string') ? output : util.inspect(output);
|
||||
var fill = "grey";
|
||||
var shape = "dot";
|
||||
if (typeof output === 'object' && hasOwnProperty.call(output, "fill") && hasOwnProperty.call(output, "shape") && hasOwnProperty.call(output, "text")) {
|
||||
if (typeof output === 'object' && output?.fill && output?.shape && output?.text) {
|
||||
fill = output.fill;
|
||||
shape = output.shape;
|
||||
st = output.text;
|
||||
|
||||
@@ -511,9 +511,10 @@ RED.debug = (function() {
|
||||
typeHint: format,
|
||||
hideKey: false,
|
||||
path: path,
|
||||
sourceId: sourceNode&&sourceNode.id,
|
||||
sourceId: sourceNode && sourceNode.id,
|
||||
rootPath: path,
|
||||
nodeSelector: config.messageSourceClick,
|
||||
enablePinning: true
|
||||
});
|
||||
// Do this in a separate step so the element functions aren't stripped
|
||||
debugMessage.appendTo(el);
|
||||
|
||||
@@ -197,14 +197,6 @@
|
||||
// object that maps from library name to its descriptor
|
||||
var allLibs = [];
|
||||
|
||||
function moduleName(module) {
|
||||
var match = /^([^@]+)@(.+)/.exec(module);
|
||||
if (match) {
|
||||
return [match[1], match[2]];
|
||||
}
|
||||
return [module, undefined];
|
||||
}
|
||||
|
||||
function getAllUsedModules() {
|
||||
var moduleSet = new Set();
|
||||
for (var id in knownFunctionNodes) {
|
||||
@@ -302,7 +294,7 @@
|
||||
if (val === "_custom_") {
|
||||
val = $(this).val();
|
||||
}
|
||||
var varName = val.trim().replace(/^@/,"").replace(/@.*$/,"").replace(/[-_/\.].?/g, function(v) { return v[1]?v[1].toUpperCase():"" });
|
||||
var varName = val.trim().replace(/^node:/,"").replace(/^@/,"").replace(/@.*$/,"").replace(/[-_/\.].?/g, function(v) { return v[1]?v[1].toUpperCase():"" });
|
||||
fvar.val(varName);
|
||||
fvar.trigger("change");
|
||||
|
||||
|
||||
@@ -111,8 +111,6 @@ module.exports = function(RED) {
|
||||
throw new Error(RED._("function.error.externalModuleNotAllowed"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
var functionText = "var results = null;"+
|
||||
"results = (async function(msg,__send__,__done__){ "+
|
||||
"var __msgid__ = msg._msgid;"+
|
||||
@@ -166,7 +164,13 @@ module.exports = function(RED) {
|
||||
Buffer:Buffer,
|
||||
Date: Date,
|
||||
RED: {
|
||||
util: RED.util
|
||||
util: {
|
||||
...RED.util,
|
||||
getSetting: function (_node, name, _flow) {
|
||||
// Ensure `node` argument is the Function node and do not allow flow to be overridden.
|
||||
return RED.util.getSetting(node, name);
|
||||
}
|
||||
}
|
||||
},
|
||||
__node__: {
|
||||
id: node.id,
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="switch.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width: calc(100% - 105px)"/>
|
||||
<input type="hidden" id="node-input-outputs"/>
|
||||
<input type="text" id="node-input-property" style="width: calc(100% - 105px)">
|
||||
<input type="hidden" id="node-input-outputs">
|
||||
</div>
|
||||
<div class="form-row node-input-rule-container-row">
|
||||
<ol id="node-input-rule-container"></ol>
|
||||
@@ -35,7 +35,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-input-repair" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label style="width: auto;" for="node-input-repair"><span data-i18n="switch.label.repair"></span></label></input>
|
||||
<label style="width: auto;" for="node-input-repair"><span data-i18n="switch.label.repair"></span></label>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
@@ -352,7 +352,9 @@ module.exports = function(RED) {
|
||||
if (msgs.length === 0) {
|
||||
done()
|
||||
} else {
|
||||
drainMessageGroup(msgs,count,done);
|
||||
setImmediate(() => {
|
||||
drainMessageGroup(msgs,count,done);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -505,7 +507,9 @@ module.exports = function(RED) {
|
||||
if (err) {
|
||||
node.error(err,nextMsg);
|
||||
}
|
||||
processMessageQueue()
|
||||
setImmediate(() => {
|
||||
processMessageQueue()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<script type="text/html" data-template-name="range">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:calc(70% - 1px)"/>
|
||||
<input type="text" id="node-input-property" style="width:calc(70% - 1px)">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-action"><i class="fa fa-dot-circle-o"></i> <span data-i18n="range.label.action"></span></label>
|
||||
@@ -13,23 +13,23 @@
|
||||
<option value="drop" data-i18n="range.scale.drop"></option>
|
||||
</select>
|
||||
</div>
|
||||
<br/>
|
||||
<br>
|
||||
<div class="form-row"><i class="fa fa-sign-in"></i> <span data-i18n="range.label.inputrange"></span>:</div>
|
||||
<div class="form-row"><label></label>
|
||||
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minin" data-i18n="[placeholder]range.placeholder.min" style="width:100px;"/>
|
||||
<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxin" data-i18n="[placeholder]range.placeholder.maxin" style="width:100px;"/>
|
||||
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minin" data-i18n="[placeholder]range.placeholder.min" style="width:100px;">
|
||||
<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxin" data-i18n="[placeholder]range.placeholder.maxin" style="width:100px;">
|
||||
</div>
|
||||
<div class="form-row"><i class="fa fa-sign-out"></i> <span data-i18n="range.label.resultrange"></span>:</div>
|
||||
<div class="form-row"><label></label>
|
||||
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minout" data-i18n="[placeholder]range.placeholder.min" style="width:100px;"/>
|
||||
<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxout" data-i18n="[placeholder]range.placeholder.maxout" style="width:100px;"/>
|
||||
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minout" data-i18n="[placeholder]range.placeholder.min" style="width:100px;">
|
||||
<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxout" data-i18n="[placeholder]range.placeholder.maxout" style="width:100px;">
|
||||
</div>
|
||||
<br/>
|
||||
<br>
|
||||
<div class="form-row"><label></label>
|
||||
<input type="checkbox" id="node-input-round" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label style="width: auto;" for="node-input-round"><span data-i18n="range.label.roundresult"></span></label></input>
|
||||
<label style="width: auto;" for="node-input-round"><span data-i18n="range.label.roundresult"></span></label>
|
||||
</div>
|
||||
<br/>
|
||||
<br>
|
||||
<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">
|
||||
|
||||
@@ -253,7 +253,13 @@ module.exports = function(RED) {
|
||||
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate))) {
|
||||
node.rate = m.rate;
|
||||
}
|
||||
send(m);
|
||||
if (msg.hasOwnProperty("reset")) {
|
||||
if (msg.hasOwnProperty("flush")) {
|
||||
node.buffer.push({msg: m, send: send, done: done});
|
||||
}
|
||||
}
|
||||
else { send(m); }
|
||||
|
||||
node.reportDepth();
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
done();
|
||||
@@ -285,42 +291,23 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
else if (!msg.hasOwnProperty("reset")) {
|
||||
if (maxKeptMsgsCount(node) > 0) {
|
||||
if (node.intervalID === -1) {
|
||||
node.send(msg);
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
} else {
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
|
||||
node.rate = msg.rate;
|
||||
clearInterval(node.intervalID);
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
}
|
||||
if (node.buffer.length < _maxKeptMsgsCount) {
|
||||
var m = RED.util.cloneMessage(msg);
|
||||
node.buffer.push({msg: m, send: send, done: done});
|
||||
} else {
|
||||
node.trace("dropped due to buffer overflow. msg._msgid = " + msg._msgid);
|
||||
node.droppedMsgs++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
|
||||
node.rate = msg.rate;
|
||||
}
|
||||
var timeSinceLast;
|
||||
if (node.lastSent) {
|
||||
timeSinceLast = process.hrtime(node.lastSent);
|
||||
}
|
||||
if (!node.lastSent) { // ensuring that we always send the first message
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
}
|
||||
else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
} else if (node.outputs === 2) {
|
||||
send([null,msg])
|
||||
}
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
|
||||
node.rate = msg.rate;
|
||||
}
|
||||
var timeSinceLast;
|
||||
if (node.lastSent) {
|
||||
timeSinceLast = process.hrtime(node.lastSent);
|
||||
}
|
||||
if (!node.lastSent) { // ensuring that we always send the first message
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
}
|
||||
else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
}
|
||||
else if (node.outputs === 2) {
|
||||
send([null,msg])
|
||||
}
|
||||
done();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<li><span data-i18n="trigger.label.resetPayload"></span> <input type="text" id="node-input-reset" style="width:150px" data-i18n="[placeholder]trigger.label.resetprompt"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<br/>
|
||||
<br>
|
||||
<div class="form-row">
|
||||
<label data-i18n="trigger.for" for="node-input-bytopic"></label>
|
||||
<select id="node-input-bytopic" style="width:120px;">
|
||||
@@ -71,12 +71,12 @@
|
||||
<option value="topic" data-i18n="trigger.bytopics"></option>
|
||||
</select>
|
||||
<span class="form-row" id="node-stream-topic">
|
||||
<input type="text" id="node-input-topic" style="width:46%;"/>
|
||||
<input type="text" id="node-input-topic" style="width:46%;">
|
||||
</span>
|
||||
</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"></input>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
<input type="hidden" id="node-input-outputs" value="1">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
@@ -24,6 +24,14 @@ module.exports = function(RED) {
|
||||
this.op2 = n.op2 || "0";
|
||||
this.op1type = n.op1type || "str";
|
||||
this.op2type = n.op2type || "str";
|
||||
// If the op1/2type is 'date', then we need to leave op1/2 alone so that
|
||||
// evaluateNodeProperty works as expected.
|
||||
if (this.op1type === 'date' && this.op1 === '1') {
|
||||
this.op1 = ''
|
||||
}
|
||||
if (this.op2type === 'date' && this.op2 === '0') {
|
||||
this.op2 = ''
|
||||
}
|
||||
this.second = (n.outputs == 2) ? true : false;
|
||||
this.topic = n.topic || "topic";
|
||||
|
||||
@@ -193,7 +201,7 @@ module.exports = function(RED) {
|
||||
if (node.op2type !== "nul") {
|
||||
var promise = Promise.resolve();
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
if (node.op2type === "flow" || node.op2type === "global" || node.op2type === "date") {
|
||||
promise = new Promise((resolve,reject) => {
|
||||
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
|
||||
if (err) {
|
||||
@@ -213,7 +221,6 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
if (node.op2type === "date") { msg2.payload = Date.now(); }
|
||||
if (node.second === true) { msgInfo.send([null,msg2]); }
|
||||
else { msgInfo.send(msg2); }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
<input type="text" id="node-input-property" style="width:70%;">
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom: 0px;">
|
||||
<label> </label>
|
||||
@@ -34,7 +34,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="text" id="node-input-topi" style="width:70%;"/>
|
||||
<input type="text" id="node-input-topi" style="width:70%;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="rbe.label.name"></span></label>
|
||||
|
||||
@@ -104,14 +104,14 @@ module.exports = function(RED) {
|
||||
if (this.credentials && this.credentials.passphrase) {
|
||||
opts.passphrase = this.credentials.passphrase;
|
||||
}
|
||||
if (this.servername) {
|
||||
opts.servername = this.servername;
|
||||
}
|
||||
if (this.alpnprotocol) {
|
||||
opts.ALPNProtocols = [this.alpnprotocol];
|
||||
}
|
||||
opts.rejectUnauthorized = this.verifyservercert;
|
||||
}
|
||||
if (this.servername) {
|
||||
opts.servername = this.servername;
|
||||
}
|
||||
if (this.alpnprotocol) {
|
||||
opts.ALPNProtocols = [this.alpnprotocol];
|
||||
}
|
||||
opts.rejectUnauthorized = this.verifyservercert;
|
||||
return opts;
|
||||
}
|
||||
|
||||
|
||||
@@ -158,9 +158,16 @@ module.exports = function(RED) {
|
||||
if(!keys || !keys.length) return null;
|
||||
keys.forEach(key => {
|
||||
let val = srcUserProperties[key];
|
||||
if(typeof val == "string") {
|
||||
if(typeof val === "string") {
|
||||
count++;
|
||||
_clone[key] = val;
|
||||
} else if (val !== undefined && val !== null) {
|
||||
try {
|
||||
_clone[key] = JSON.stringify(val)
|
||||
count++;
|
||||
} catch (err) {
|
||||
// Silently drop property
|
||||
}
|
||||
}
|
||||
});
|
||||
if(count) properties.userProperties = _clone;
|
||||
@@ -673,6 +680,8 @@ module.exports = function(RED) {
|
||||
delete node.options.protocolId; //V4+ default
|
||||
delete node.options.protocolVersion; //V4 default
|
||||
delete node.options.properties;//V5 only
|
||||
|
||||
|
||||
if (node.compatmode == "true" || node.compatmode === true || node.protocolVersion == 3) {
|
||||
node.options.protocolId = 'MQIsdp';//V3 compat only
|
||||
node.options.protocolVersion = 3;
|
||||
@@ -691,6 +700,21 @@ module.exports = function(RED) {
|
||||
setIntProp(node,node.options.properties,"sessionExpiryInterval");
|
||||
}
|
||||
}
|
||||
// Ensure will payload, if set, is a string
|
||||
if (node.options.will && Object.hasOwn(node.options.will, 'payload')) {
|
||||
let payload = node.options.will.payload
|
||||
if (payload === null || typeof payload === 'undefined') {
|
||||
payload = "";
|
||||
} else if (!Buffer.isBuffer(payload)) {
|
||||
if (typeof payload === "object") {
|
||||
payload = JSON.stringify(payload);
|
||||
} else if (typeof payload !== "string") {
|
||||
payload = "" + payload;
|
||||
}
|
||||
}
|
||||
node.options.will.payload = payload
|
||||
}
|
||||
|
||||
if (node.usetls && n.tls) {
|
||||
var tlsNode = RED.nodes.getNode(n.tls);
|
||||
if (tlsNode) {
|
||||
@@ -725,6 +749,7 @@ module.exports = function(RED) {
|
||||
};
|
||||
|
||||
node.deregister = function(mqttNode, done, autoDisconnect) {
|
||||
setStatusDisconnected(mqttNode, false);
|
||||
delete node.users[mqttNode.id];
|
||||
if (autoDisconnect && !node.closing && node.connected && Object.keys(node.users).length === 0) {
|
||||
node.disconnect(done);
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</div>
|
||||
|
||||
<div id="node-row-newline" class="form-row hidden" style="padding-left:110px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br/>
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br>
|
||||
<input type="checkbox" id="node-input-trim" style="display:inline-block; width:auto; vertical-align:top;"> <span data-i18n="tcpin.label.reattach"></span>
|
||||
</div>
|
||||
|
||||
@@ -317,7 +317,7 @@
|
||||
<span id="node-units"></span>
|
||||
</div>
|
||||
<div id="node-row-newline" class="form-row hidden" style="padding-left:162px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br/>
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br>
|
||||
<input type="checkbox" id="node-input-trim" style="display:inline-block; width:auto; vertical-align:top;"> <span data-i18n="tcpin.label.reattach"></span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
|
||||
@@ -35,21 +35,21 @@
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<hr align="middle"/>
|
||||
<hr align="middle">
|
||||
<div class="form-row">
|
||||
<label style="width:100%;"><span data-i18n="csv.label.c2o"></span></label>
|
||||
</div>
|
||||
<div class="form-row" style="padding-left:20px;">
|
||||
<label><i class="fa fa-sign-in"></i> <span data-i18n="csv.label.input"></span></label>
|
||||
<span data-i18n="csv.label.skip-s"></span> <input type="text" id="node-input-skip" style="width:40px; height:25px;"/> <span data-i18n="csv.label.skip-e"></span><br/>
|
||||
<span data-i18n="csv.label.skip-s"></span> <input type="text" id="node-input-skip" style="width:40px; height:25px;"> <span data-i18n="csv.label.skip-e"></span><br>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-hdrin"><label style="width:auto; margin-top:7px;" for="node-input-hdrin"><span data-i18n="csv.label.firstrow"></span></label><br/>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-hdrin"><label style="width:auto; margin-top:7px;" for="node-input-hdrin"><span data-i18n="csv.label.firstrow"></span></label><br>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-strings"><label style="width:auto; margin-top:7px;" for="node-input-strings"><span data-i18n="csv.label.usestrings"></span></label><br/>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-strings"><label style="width:auto; margin-top:7px;" for="node-input-strings"><span data-i18n="csv.label.usestrings"></span></label><br>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_empty_strings"><label style="width:auto; margin-top:7px;" for="node-input-include_empty_strings"><span data-i18n="csv.label.include_empty_strings"></span></label><br/>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_empty_strings"><label style="width:auto; margin-top:7px;" for="node-input-include_empty_strings"><span data-i18n="csv.label.include_empty_strings"></span></label><br>
|
||||
<label> </label>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_null_values"><label style="width:auto; margin-top:7px;" for="node-input-include_null_values"><span data-i18n="csv.label.include_null_values"></span></label><br/>
|
||||
<input style="width:20px; vertical-align:baseline; margin-right:5px;" type="checkbox" id="node-input-include_null_values"><label style="width:auto; margin-top:7px;" for="node-input-include_null_values"><span data-i18n="csv.label.include_null_values"></span></label><br>
|
||||
</div>
|
||||
<div class="form-row" style="padding-left:20px;">
|
||||
<label><i class="fa fa-sign-out"></i> <span data-i18n="csv.label.output"></span></label>
|
||||
|
||||
@@ -367,20 +367,21 @@ module.exports = function(RED) {
|
||||
const sendHeadersAlways = node.hdrout === "all"
|
||||
const sendHeaders = !dontSendHeaders && (sendHeadersOnce || sendHeadersAlways)
|
||||
const quoteables = [node.sep, node.quo, "\n", "\r"]
|
||||
const templateQuoteables = [',', '"', "\n", "\r"]
|
||||
const templateQuoteables = [node.sep, node.quo, "\n", "\r"]
|
||||
const templateQuoteablesStrict = [',', '"', "\n", "\r"]
|
||||
let badTemplateWarnOnce = true
|
||||
|
||||
const columnStringToTemplateArray = function (col, sep) {
|
||||
// NOTE: enforce strict column template parsing in RFC4180 mode
|
||||
const parsed = csv.parse(col, { separator: sep, quote: node.quo, outputStyle: 'array', strict: true })
|
||||
if (parsed.headers.length > 0) { node.goodtmpl = true } else { node.goodtmpl = false }
|
||||
return parsed.headers.length ? parsed.headers : null
|
||||
if (parsed.data?.length === 1) { node.goodtmpl = true } else { node.goodtmpl = false }
|
||||
return node.goodtmpl ? parsed.data[0] : null
|
||||
}
|
||||
const templateArrayToColumnString = function (template, keepEmptyColumns) {
|
||||
// NOTE: enforce strict column template parsing in RFC4180 mode
|
||||
const parsed = csv.parse('', {headers: template, headersOnly:true, separator: ',', quote: node.quo, outputStyle: 'array', strict: true })
|
||||
const templateArrayToColumnString = function (template, keepEmptyColumns, separator = ',', quotables = templateQuoteablesStrict) {
|
||||
// NOTE: defaults to strict column template parsing (commas and double quotes)
|
||||
const parsed = csv.parse('', {headers: template, headersOnly:true, separator, quote: node.quo, outputStyle: 'array', strict: true })
|
||||
return keepEmptyColumns
|
||||
? parsed.headers.map(e => addQuotes(e || '', { separator: ',', quoteables: templateQuoteables}))
|
||||
? parsed.headers.map(e => addQuotes(e || '', { separator, quoteables: quotables })).join(separator)
|
||||
: parsed.header // exclues empty columns
|
||||
// TODO: resolve inconsistency between CSV->JSON and JSON->CSV
|
||||
// CSV->JSON: empty columns are excluded
|
||||
@@ -447,7 +448,7 @@ module.exports = function(RED) {
|
||||
template = Object.keys(inputData[0]) || ['']
|
||||
}
|
||||
}
|
||||
stringBuilder.push(templateArrayToColumnString(template, true))
|
||||
stringBuilder.push(templateArrayToColumnString(template, true, node.sep, templateQuoteables)) // use user set separator for output data.
|
||||
if (sendHeadersOnce) { node.hdrSent = true }
|
||||
}
|
||||
|
||||
@@ -483,6 +484,7 @@ module.exports = function(RED) {
|
||||
node.warn(RED._("csv.errors.obj_csv"))
|
||||
badTemplateWarnOnce = false
|
||||
}
|
||||
template = Object.keys(row) || ['']
|
||||
const rowData = []
|
||||
for (let header in inputData[0]) {
|
||||
if (row.hasOwnProperty(header)) {
|
||||
@@ -518,7 +520,7 @@ module.exports = function(RED) {
|
||||
|
||||
// join lines, don't forget to add the last new line
|
||||
msg.payload = stringBuilder.join(node.ret) + node.ret
|
||||
msg.columns = templateArrayToColumnString(template)
|
||||
msg.columns = templateArrayToColumnString(template) // always strict commas + double quotes for
|
||||
if (msg.payload !== '') { send(msg) }
|
||||
done()
|
||||
}
|
||||
@@ -615,16 +617,15 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (msg.parts.index + 1 === msg.parts.count) {
|
||||
msg.payload = node.store
|
||||
msg.columns = csvParseResult.header
|
||||
// msg._mode = 'RFC4180 mode'
|
||||
// msg.columns = csvParseResult.header
|
||||
msg.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
|
||||
delete msg.parts
|
||||
send(msg)
|
||||
node.store = []
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.columns = csvParseResult.header
|
||||
// msg._mode = 'RFC4180 mode'
|
||||
msg.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
|
||||
msg.payload = data
|
||||
send(msg); // finally send the array
|
||||
}
|
||||
@@ -633,7 +634,8 @@ module.exports = function(RED) {
|
||||
const len = data.length
|
||||
for (let row = 0; row < len; row++) {
|
||||
const newMessage = RED.util.cloneMessage(msg)
|
||||
newMessage.columns = csvParseResult.header
|
||||
// newMessage.columns = csvParseResult.header
|
||||
newMessage.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
|
||||
newMessage.payload = data[row]
|
||||
if (!has_parts) {
|
||||
newMessage.parts = {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<label for="node-input-chr" style="width: 230px;"><i class="fa fa-tag"></i> <span data-i18n="html.label.prefix"></span></label>
|
||||
<input type="text" id="node-input-chr" style="text-align:center; width: 40px;" placeholder="_">
|
||||
</div>
|
||||
<br/>
|
||||
<br>
|
||||
<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" style="width:70%" data-i18n="[placeholder]common.label.name">
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="json.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
<input type="text" id="node-input-property" style="width:70%;">
|
||||
</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">
|
||||
</div>
|
||||
<hr align="middle"/>
|
||||
<hr align="middle">
|
||||
<div class="form-row node-json-to-json-options">
|
||||
<label style="width:100%;"><span data-i18n="json.label.o2j"></span></label>
|
||||
</div>
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<script type="text/html" data-template-name="xml">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
<input type="text" id="node-input-property" style="width:70%;">
|
||||
</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">
|
||||
</div>
|
||||
<hr align="middle"/>
|
||||
<hr align="middle">
|
||||
<div class="form-row">
|
||||
<label style="width:100%;"><span data-i18n="xml.label.x2o"></span></label>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<script type="text/html" data-template-name="yaml">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
<input type="text" id="node-input-property" style="width:70%;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-forward"></i> <span data-i18n="split.splitThe"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
<input type="text" id="node-input-property" style="width:70%;">
|
||||
</div>
|
||||
<div class="form-row"><span data-i18n="[html]split.strBuff"></span></div>
|
||||
<div class="form-row">
|
||||
@@ -202,7 +202,7 @@
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-reduceRight" style="display:inline-block; width:auto; vertical-align:top; margin-left:10px;">
|
||||
<label for="node-input-reduceRight" style="width:70%;" data-i18n="join.reduce.right" style="margin-left:10px;"/>
|
||||
<label for="node-input-reduceRight" data-i18n="join.reduce.right" style="width:70%; margin-left:10px;"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-tips form-tips-auto hide" data-i18n="[html]join.tip"></div>
|
||||
|
||||
@@ -339,7 +339,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
msg.filename = filename;
|
||||
var lines = Buffer.from([]);
|
||||
const bufferArray = [];
|
||||
var spare = "";
|
||||
var count = 0;
|
||||
var type = "buffer";
|
||||
@@ -397,7 +397,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
lines = Buffer.concat([lines,chunk]);
|
||||
bufferArray.push(chunk);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -413,10 +413,11 @@ module.exports = function(RED) {
|
||||
})
|
||||
.on('end', function() {
|
||||
if (node.chunk === false) {
|
||||
const buffer = Buffer.concat(bufferArray);
|
||||
if (node.format === "utf8") {
|
||||
msg.payload = decode(lines, node.encoding);
|
||||
msg.payload = decode(buffer, node.encoding);
|
||||
}
|
||||
else { msg.payload = lines; }
|
||||
else { msg.payload = buffer; }
|
||||
nodeSend(msg);
|
||||
}
|
||||
else if (node.format === "lines") {
|
||||
|
||||
Reference in New Issue
Block a user