Merge branch 'dev' into pr_2490

This commit is contained in:
Nick O'Leary
2020-05-22 15:43:17 +01:00
232 changed files with 12254 additions and 2817 deletions

View File

@@ -16,14 +16,12 @@
<script type="text/html" data-template-name="inject">
<div class="form-row">
<label for="node-input-payload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input type="text" id="node-input-payload" style="width:70%">
<input type="hidden" id="node-input-payloadType">
<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>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic">
<div class="form-row node-input-property-container-row">
<ol id="node-input-property-container"></ol>
</div>
<div class="form-row" id="node-once">
@@ -114,12 +112,7 @@
</div>
</div>
</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>
<div class="form-tips" data-i18n="[html]inject.tip"></div>
</script>
<style>
.inject-time-row {
@@ -155,37 +148,76 @@
</style>
<script type="text/javascript">
(function() {
function resizeDialog(size) {
size = size || { height: $(".red-ui-tray-content form").height() }
var rows = $("#dialog-form>div:not(.node-input-property-container-row):visible");
var height = size.height;
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-property-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-property-container").editableList('height',height);
}
RED.nodes.registerType('inject',{
category: 'common',
color:"#a6bbcf",
defaults: {
name: {value:""},
topic: {value:""},
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
payloadType: {value:"date"},
props:{value:[{p:"payload"},{p:"topic",vt:"str"}]},
repeat: {value:"", validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
crontab: {value:""},
once: {value:false},
onceDelay: {value:0.1}
onceDelay: {value:0.1},
topic: {value:""},
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
payloadType: {value:"date"},
},
icon: "inject.svg",
inputs:0,
outputs:1,
outputLabels: function(index) {
var lab = this.payloadType;
if (lab === "json") {
try {
lab = typeof JSON.parse(this.payload);
if (lab === "object") {
if (Array.isArray(JSON.parse(this.payload))) { lab = "Array"; }
}
} catch(e) {
return this._("inject.label.invalid"); }
var lab = '';
// if only payload and topic - display payload type
// if only one property - show it's type
// if more than one property (other than payload and topic) - show "x properties" where x is the number of properties.
// this.props will not be an array for legacy inject nodes until they are re-deployed
//
var props = this.props;
if (!Array.isArray(props)) {
props = [
{ p:"payload", v: this.payload, vt: this.payloadType },
{ p:"topic", v: this.topic, vt: "str" }
]
}
var name = "inject.label."+lab;
var label = this._(name);
if (name !== label) {
return label;
if (props) {
for (var i=0,l=props.length; i<l; i++) {
if (i > 0) lab += "\n";
if (i === 5) {
lab += " + "+(props.length-4);
break;
}
lab += props[i].p+": ";
var propType = props[i].p === "payload"? this.payloadType : props[i].vt;
if (propType === "json") {
try {
var parsedProp = JSON.parse(props[i].p === "payload"? this.payload : props[i].v);
propType = typeof parsedProp;
if (propType === "object" && Array.isArray(parsedProp)) {
propType = "Array";
}
} catch(e) {
propType = "invalid";
}
}
lab += this._("inject.label."+propType);
}
}
return lab;
},
@@ -201,27 +233,33 @@
}
if (this.name) {
return this.name+suffix;
} else if (this.payloadType === "string" ||
this.payloadType === "str" ||
this.payloadType === "num" ||
this.payloadType === "bool" ||
this.payloadType === "json") {
if ((this.topic !== "") && ((this.topic.length + this.payload.length) <= 32)) {
return this.topic + ":" + this.payload+suffix;
} else if (this.payload.length > 0 && this.payload.length < 24) {
return this.payload+suffix;
}
var payload = this.payload || "";
var payloadType = this.payloadType || "str";
var topic = this.topic || "";
if (payloadType === "string" ||
payloadType === "str" ||
payloadType === "num" ||
payloadType === "bool" ||
payloadType === "json") {
if ((topic !== "") && ((topic.length + payload.length) <= 32)) {
return topic + ":" + payload+suffix;
} else if (payload.length > 0 && payload.length < 24) {
return payload+suffix;
} else {
return this._("inject.inject")+suffix;
}
} else if (this.payloadType === 'date') {
if ((this.topic !== "") && (this.topic.length <= 16)) {
return this.topic + ":" + this._("inject.timestamp")+suffix;
} else if (payloadType === 'date' || payloadType === 'bin' || payloadType === 'env') {
if ((topic !== "") && (topic.length <= 16)) {
return topic + ":" + this._('inject.label.'+payloadType)+suffix;
} else {
return this._("inject.timestamp")+suffix;
return this._('inject.label.'+payloadType)+suffix;
}
} else if (this.payloadType === 'flow' || this.payloadType === 'global') {
var key = RED.utils.parseContextKey(this.payload);
return this.payloadType+"."+key.key+suffix;
} else if (payloadType === 'flow' || payloadType === 'global') {
var key = RED.utils.parseContextKey(payload);
return payloadType+"."+key.key+suffix;
} else {
return this._("inject.inject")+suffix;
}
@@ -239,13 +277,6 @@
} else if (this.payloadType === 'string' || this.payloadType === 'none') {
this.payloadType = "str";
}
$("#node-input-payloadType").val(this.payloadType);
$("#node-input-payload").typedInput({
default: 'str',
typeField: $("#node-input-payloadType"),
types:['flow','global','str','num','bool','json','bin','date','env']
});
$("#inject-time-type-select").on("change", function() {
$("#node-input-crontab").val('');
@@ -259,6 +290,11 @@
$("#node-once").hide();
$("#node-input-once").prop('checked', false);
}
// Scroll down
var scrollDiv = $("#dialog-form").parent();
scrollDiv.scrollTop(scrollDiv.prop('scrollHeight'));
resizeDialog();
});
$("#node-input-once").on("change", function() {
@@ -378,7 +414,70 @@
$("#inject-time-type-select").val(repeattype);
$("#inject-time-row-"+repeattype).show();
$("#node-input-payload").typedInput('type',this.payloadType);
/* */
$('#node-input-property-container').css('min-height','120px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var prop = opt;
if (!prop.hasOwnProperty('p')) {
prop = {p:"",v:"",vt:"str"};
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
var row = $('<div/>').appendTo(container);
var propertyName = $('<input/>',{class:"node-input-prop-property-name",type:"text"})
.css("width","30%")
.appendTo(row)
.typedInput({types:['msg']});
$('<div/>',{style: 'display:inline-block; padding:0px 6px;'})
.text('=')
.appendTo(row);
var propertyValue = $('<input/>',{class:"node-input-prop-property-value",type:"text"})
.css("width","calc(70% - 30px)")
.appendTo(row)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
propertyName.typedInput('value',prop.p);
propertyValue.typedInput('value',prop.v);
propertyValue.typedInput('type',prop.vt);
},
removable: true,
sortable: true
});
if (!this.props) {
var payload = {
p:'payload',
v: this.payload ? this.payload : '',
vt:this.payloadType ? this.payloadType : 'date'
};
var topic = {
p:'topic',
v: this.topic ? this.topic : '',
vt:'string'
}
this.props = [payload,topic];
}
for (var i=0; i<this.props.length; i++) {
var prop = this.props[i];
var newProp = { p: prop.p, v: prop.v, vt: prop.vt };
if (newProp.v === undefined) {
if (prop.p === 'payload') {
newProp.v = this.payload ? this.payload : '';
newProp.vt = this.payloadType ? this.payloadType : 'date';
} else if (prop.p === 'topic' && prop.vt === "str") {
newProp.v = this.topic ? this.topic : '';
}
}
$("#node-input-property-container").editableList('addItem',newProp);
}
$("#inject-time-type-select").trigger("change");
$("#inject-time-interval-time-start").trigger("change");
@@ -474,6 +573,34 @@
$("#node-input-repeat").val(repeat);
$("#node-input-crontab").val(crontab);
/* Gather the injected properties of the msg object */
var props = $("#node-input-property-container").editableList('items');
var node = this;
node.props= [];
delete node.payloadType;
delete node.payload;
delete node.topic;
props.each(function(i) {
var prop = $(this);
var p = {
p:prop.find(".node-input-prop-property-name").typedInput('value')
};
if (p.p) {
p.v = prop.find(".node-input-prop-property-value").typedInput('value');
p.vt = prop.find(".node-input-prop-property-value").typedInput('type');
if (p.p === "payload") { // save payload to old "legacy" property
node.payloadType = p.vt;
node.payload = p.v;
delete p.v;
delete p.vt;
} else if (p.p === "topic" && p.vt === "str") {
node.topic = p.v;
delete p.v;
}
node.props.push(p);
}
});
},
button: {
enabled: function() {
@@ -483,12 +610,7 @@
if (this.changed) {
return RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.undeployedChanges")}),"warning");
}
var payload = this.payload;
if ((this.payloadType === 'flow') ||
(this.payloadType === 'global')) {
var key = RED.utils.parseContextKey(payload);
payload = this.payloadType+"."+key.key;
}
var label = this._def.label.call(this);
if (label.length > 30) {
label = label.substring(0,50)+"...";
@@ -514,7 +636,8 @@
}
});
}
}
},
oneditresize: resizeDialog
});
})();
</script>

View File

@@ -20,9 +20,32 @@ module.exports = function(RED) {
function InjectNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.payload = n.payload;
this.payloadType = n.payloadType;
/* Handle legacy */
if(!Array.isArray(n.props)){
n.props = [];
n.props.push({
p:'payload',
v:n.payload,
vt:n.payloadType
});
n.props.push({
p:'topic',
v:n.topic,
vt:'str'
});
} else {
for (var i=0,l=n.props.length; i<l; i++) {
if (n.props[i].p === 'payload' && !n.props[i].hasOwnProperty('v')) {
n.props[i].v = n.payload;
n.props[i].vt = n.payloadType;
} else if (n.props[i].p === 'topic' && n.props[i].vt === 'str' && !n.props[i].hasOwnProperty('v')) {
n.props[i].v = n.topic;
}
}
}
this.props = n.props;
this.repeat = n.repeat;
this.crontab = n.crontab;
this.once = n.once;
@@ -31,65 +54,83 @@ module.exports = function(RED) {
this.cronjob = null;
var node = this;
node.props.forEach(function (prop) {
if (prop.vt === "jsonata") {
try {
var val = prop.v ? prop.v : "";
prop.exp = RED.util.prepareJSONataExpression(val, node);
}
catch (err) {
node.error(RED._("inject.errors.invalid-expr", {error:err.message}));
prop.exp = null;
}
}
});
if (node.repeat > 2147483) {
node.error(RED._("inject.errors.toolong", this));
delete node.repeat;
}
node.repeaterSetup = function () {
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000;
if (RED.settings.verbose) {
this.log(RED._("inject.repeat", this));
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000;
if (RED.settings.verbose) {
this.log(RED._("inject.repeat", this));
}
this.interval_id = setInterval(function() {
node.emit("input", {});
}, this.repeat);
} else if (this.crontab) {
if (RED.settings.verbose) {
this.log(RED._("inject.crontab", this));
}
this.cronjob = new cron.CronJob(this.crontab, function() { node.emit("input", {}); }, null, true);
}
this.interval_id = setInterval(function() {
node.emit("input", {});
}, this.repeat);
} else if (this.crontab) {
if (RED.settings.verbose) {
this.log(RED._("inject.crontab", this));
}
this.cronjob = new cron.CronJob(this.crontab, function() { node.emit("input", {}); }, null, true);
}
};
if (this.once) {
this.onceTimeout = setTimeout( function() {
node.emit("input",{});
node.repeaterSetup();
node.emit("input",{});
node.repeaterSetup();
}, this.onceDelay);
} else {
node.repeaterSetup();
node.repeaterSetup();
}
this.on("input",function(msg) {
msg.topic = this.topic;
if (this.payloadType !== 'flow' && this.payloadType !== 'global') {
try {
if ( (this.payloadType == null && this.payload === "") || this.payloadType === "date") {
msg.payload = Date.now();
} else if (this.payloadType == null) {
msg.payload = this.payload;
} else if (this.payloadType === 'none') {
msg.payload = "";
} else {
msg.payload = RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg);
}
this.send(msg);
msg = null;
} catch(err) {
this.error(err,msg);
}
} else {
RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg, function(err,res) {
if (err) {
node.error(err,msg);
} else {
msg.payload = res;
node.send(msg);
}
this.on("input", function(msg) {
var errors = [];
});
this.props.forEach(p => {
var property = p.p;
var value = p.v ? p.v : '';
var valueType = p.vt ? p.vt : 'str';
if (!property) return;
if (valueType === "jsonata") {
if (p.exp) {
try {
var val = RED.util.evaluateJSONataExpression(p.exp, msg);
RED.util.setMessageProperty(msg, property, val, true);
}
catch (err) {
errors.push(err.message);
}
}
return;
}
try {
RED.util.setMessageProperty(msg,property,RED.util.evaluateNodeProperty(value, valueType, this, msg),true);
} catch (err) {
errors.push(err.toString());
}
});
if (errors.length) {
node.error(errors.join('; '), msg);
} else {
node.send(msg);
}
});
}

View File

@@ -6,25 +6,30 @@
<input id="node-input-complete" type="hidden">
<input id="node-input-targetType" type="hidden">
</div>
<div class="form-row">
<label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
<label for="node-input-tosidebar" style="width:70%">
<input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toSidebar"></span>
<input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toSidebar"></span>
</label>
</div>
<div class="form-row">
<label for="node-input-console"> </label>
<label for="node-input-console" style="width:70%">
<input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toConsole"></span>
<input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toConsole"></span>
</label>
</div>
<div class="form-row" id="node-tostatus-line">
<div class="form-row">
<label for="node-input-tostatus"> </label>
<label for="node-input-tostatus" style="width:70%">
<input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toStatus"></span>
<input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toStatus"></span>
</label>
</div>
<div class="form-row" id="node-tostatus-line">
<label for="node-input-typed-status"><i class="fa fa-ellipsis-h"></i> <span data-i18n="debug.status"></span></label>
<input id="node-input-typed-status" type="text" style="width: 70%">
<input id="node-input-statusVal" type="hidden">
<input id="node-input-statusType" type="hidden">
</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">
@@ -45,7 +50,9 @@
console: {value:false},
tostatus: {value:false},
complete: {value:"false", required:true},
targetType: {value:undefined}
targetType: {value:undefined},
statusVal: {value:""},
statusType: {value:"auto"}
},
label: function() {
var suffix = "";
@@ -308,10 +315,20 @@
window.removeEventListener("message",this.handleWindowMessage);
RED.actions.remove("core:show-debug-tab");
RED.actions.remove("core:clear-debug-messages");
delete RED._debug;
},
oneditprepare: function() {
var autoType = {
value: "auto",
label: RED._("node-red:debug.autostatus"),
hasValue: false
};
$("#node-input-typed-status").typedInput({
default: "auto",
types:[autoType, "msg", "jsonata"],
typeField: $("#node-input-statusType")
});
var that = this;
var none = {
value: "none",
label: RED._("node-red:debug.none"),
@@ -321,6 +338,14 @@
this.tosidebar = true;
$("#node-input-tosidebar").prop('checked', true);
}
if (this.statusVal === undefined) {
this.statusVal = (this.complete === "false") ? "payload" : ((this.complete === "true") ? "payload" : this.complete+"");
$("#node-input-typed-status").typedInput('value',this.statusVal || "");
}
if (this.statusType === undefined) {
this.statusType = this.targetType;
$("#node-input-typed-status").typedInput('type',this.statusType || "auto");
}
if (typeof this.console === "string") {
this.console = (this.console == 'true');
$("#node-input-console").prop('checked', this.console);
@@ -331,6 +356,7 @@
label: RED._("node-red:debug.msgobj"),
hasValue: false
};
$("#node-input-typed-complete").typedInput({
default: "msg",
types:['msg', fullType, "jsonata"],
@@ -354,17 +380,29 @@
) {
$("#node-input-typed-complete").typedInput('value','payload');
}
if ($("#node-input-typed-complete").typedInput('type') === 'full') {
$("#node-tostatus-line").hide();
} else {
});
$("#node-input-tostatus").on('change',function() {
if ($(this).is(":checked")) {
if (!that.hasOwnProperty("statusVal") || that.statusVal === "") {
var type = $("#node-input-typed-complete").typedInput('type');
var comp = "payload";
if (type !== 'full') {
comp = $("#node-input-typed-complete").typedInput('value');
}
that.statusType = "auto";
that.statusVal = comp;
}
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
$("#node-tostatus-line").show();
}
});
$("#node-input-complete").on('change',function() {
if ($("#node-input-typed-complete").typedInput('type') === 'full') {
else {
$("#node-tostatus-line").hide();
} else {
$("#node-tostatus-line").show();
that.statusType = "auto";
that.statusVal = "";
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
}
});
},
@@ -375,6 +413,7 @@
} else {
$("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
}
$("#node-input-statusVal").val($("#node-input-typed-status").typedInput('value'));
}
});
})();

View File

@@ -2,7 +2,7 @@ module.exports = function(RED) {
"use strict";
var util = require("util");
var events = require("events");
var path = require("path");
//var path = require("path");
var debuglength = RED.settings.debugMaxLength || 1000;
var useColors = RED.settings.debugUseColors || false;
util.inspect.styles.boolean = "red";
@@ -15,36 +15,20 @@ module.exports = function(RED) {
this.complete = hasEditExpression ? null : (n.complete||"payload").toString();
if (this.complete === "false") { this.complete = "payload"; }
this.console = ""+(n.console || false);
this.tostatus = (this.complete !== "true") && (n.tostatus || false);
this.tostatus = n.tostatus || false;
this.statusType = n.statusType || "msg";
this.statusVal = n.statusVal || this.complete;
this.tosidebar = n.tosidebar;
if (this.tosidebar === undefined) { this.tosidebar = true; }
this.severity = n.severity || 40;
this.active = (n.active === null || typeof n.active === "undefined") || n.active;
if (this.tostatus) { this.status({fill:"grey", shape:"ring"}); }
else { this.status({}); }
var hasStatExpression = (n.statusType === "jsonata");
var statExpression = hasStatExpression ? n.statusVal : null;
var node = this;
var levels = {
off: 1,
fatal: 10,
error: 20,
warn: 30,
info: 40,
debug: 50,
trace: 60,
audit: 98,
metric: 99
};
var colors = {
"0": "grey",
"10": "grey",
"20": "red",
"30": "yellow",
"40": "grey",
"50": "green",
"60": "blue"
};
var preparedEditExpression = null;
var preparedStatExpression = null;
if (editExpression) {
try {
preparedEditExpression = RED.util.prepareJSONataExpression(editExpression, this);
@@ -54,16 +38,22 @@ module.exports = function(RED) {
return;
}
}
if (statExpression) {
try {
preparedStatExpression = RED.util.prepareJSONataExpression(statExpression, this);
}
catch (e) {
node.error(RED._("debug.invalid-exp", {error: editExpression}));
return;
}
}
function prepareValue(msg, done) {
// Either apply the jsonata expression or...
if (preparedEditExpression) {
RED.util.evaluateJSONataExpression(preparedEditExpression, msg, (err, value) => {
if (err) {
done(RED._("debug.invalid-exp", {error: editExpression}));
} else {
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value});
}
if (err) { done(RED._("debug.invalid-exp", {error: editExpression})); }
else { done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value}); }
});
} else {
// Extract the required message property
@@ -71,17 +61,67 @@ module.exports = function(RED) {
var output = msg[property];
if (node.complete !== "false" && typeof node.complete !== "undefined") {
property = node.complete;
try {
output = RED.util.getMessageProperty(msg,node.complete);
} catch(err) {
output = undefined;
}
try { output = RED.util.getMessageProperty(msg,node.complete); }
catch(err) { output = undefined; }
}
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, property:property, msg:output});
}
}
function prepareStatus(msg, done) {
if (node.statusType === "auto") {
if (node.complete === "true") {
done(null,{msg:msg.payload});
}
else {
prepareValue(msg,function(err,debugMsg) {
if (err) { node.error(err); return; }
done(null,{msg:debugMsg.msg});
});
}
}
else {
// Either apply the jsonata expression or...
if (preparedStatExpression) {
RED.util.evaluateJSONataExpression(preparedStatExpression, msg, (err, value) => {
if (err) { done(RED._("debug.invalid-exp", {error:editExpression})); }
else { done(null,{msg:value}); }
});
}
else {
// Extract the required message property
var output;
try { output = RED.util.getMessageProperty(msg,node.statusVal); }
catch(err) { output = undefined; }
done(null,{msg:output});
}
}
}
this.on("input", function(msg, send, done) {
if (node.tostatus === true) {
prepareStatus(msg, function(err,debugMsg) {
if (err) { node.error(err); return; }
var output = debugMsg.msg;
var st = (typeof output === 'string') ? output : util.inspect(output);
var fill = "grey";
var shape = "dot";
if (node.statusType === "auto") {
if (msg.hasOwnProperty("error")) {
fill = "red";
st = msg.error.message;
}
if (msg.hasOwnProperty("status")) {
if (msg.status.hasOwnProperty("fill")) { fill = msg.status.fill; }
if (msg.status.hasOwnProperty("shape")) { shape = msg.status.shape; }
if (msg.status.hasOwnProperty("text")) { st = msg.status.text; }
}
}
if (st.length > 32) { st = st.substr(0,32) + "..."; }
node.status({fill:fill, shape:shape, text:st});
});
}
if (this.complete === "true") {
// debug complete msg object
if (this.console === "true") {
@@ -91,7 +131,8 @@ module.exports = function(RED) {
sendDebug({id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:msg});
}
done();
} else {
}
else {
prepareValue(msg,function(err,debugMsg) {
if (err) {
node.error(err);
@@ -107,12 +148,6 @@ module.exports = function(RED) {
node.log(util.inspect(output, {colors:useColors}));
}
}
if (node.tostatus === true) {
var st = (typeof output === 'string')?output:util.inspect(output);
var severity = node.severity;
if (st.length > 32) { st = st.substr(0,32) + "..."; }
node.status({fill:colors[severity], shape:"dot", text:st});
}
if (node.active) {
if (node.tosidebar == true) {
sendDebug(debugMsg);

View File

@@ -89,7 +89,8 @@
node: n,
label: label,
sublabel: sublabel,
selected: isChecked
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});

View File

@@ -104,7 +104,8 @@
node: n,
label: label,
sublabel: sublabel,
selected: isChecked
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});

View File

@@ -92,7 +92,8 @@
node: n,
label: label,
sublabel: sublabel,
selected: isChecked
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});

View File

@@ -83,7 +83,8 @@
id: n.id,
node: n,
label: n.name||n.id,
selected: isChecked
selected: isChecked,
checkbox: true
})
}
});

View File

@@ -457,7 +457,7 @@ RED.debug = (function() {
var metaRow = $('<div class="red-ui-debug-msg-meta"></div>').appendTo(msg);
$('<span class="red-ui-debug-msg-date">'+ getTimestamp()+'</span>').appendTo(metaRow);
if (sourceNode) {
$('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text('node: '+sanitize(o.name||sourceNode.name||sourceNode.id))
$('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text('node: '+(o.name||sourceNode.name||sourceNode.id))
.appendTo(metaRow)
.on("click", function(evt) {
evt.preventDefault();

View File

@@ -4,19 +4,54 @@
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
</div>
<div class="form-row" style="margin-bottom: 0px;">
<label for="node-input-func"><i class="fa fa-wrench"></i> <span data-i18n="function.label.function"></span></label>
<input type="hidden" id="node-input-func" autofocus="autofocus">
<input type="hidden" id="node-input-noerr">
<div class="form-row">
<ul style="min-width: 600px; margin-bottom: 20px;" id="func-tabs"></ul>
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom:calc(100% + 3px);"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
</div>
<div class="form-row" style="margin-bottom: 0px">
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="function.label.outputs"></span></label>
<input id="node-input-outputs" style="width: 60px;" value="1">
<div id="func-tabs-content" style="min-height: calc(100% - 95px);">
<div id="func-tab-init" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-initialize" autofocus="autofocus">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 250px; min-height:150px; margin-top: 30px;" class="node-text-editor" id="node-input-init-editor" ></div>
</div>
</div>
<div id="func-tab-body" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-func" autofocus="autofocus">
<input type="hidden" id="node-input-noerr">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 220px; min-height:120px; margin-top: 30px;" class="node-text-editor" id="node-input-func-editor" ></div>
</div>
<div class="form-row" style="margin-bottom: 0px">
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="function.label.outputs"></span></label>
<input id="node-input-outputs" style="width: 60px;" value="1">
</div>
</div>
<div id="func-tab-finalize" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-finalize" autofocus="autofocus">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 250px; min-height:150px; margin-top: 30px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
</div>
</div>
</div>
</script>
<script type="text/javascript">
@@ -27,7 +62,9 @@
name: {value:""},
func: {value:"\nreturn msg;"},
outputs: {value:1},
noerr: {value:0,required:true,validate:function(v) { return !v; }}
noerr: {value:0,required:true,validate:function(v) { return !v; }},
initialize: {value:""},
finalize: {value:""}
},
inputs:1,
outputs:1,
@@ -40,6 +77,28 @@
},
oneditprepare: function() {
var that = this;
var tabs = RED.tabs.create({
id: "func-tabs",
onchange: function(tab) {
$("#func-tabs-content").children().hide();
$("#" + tab.id).show();
}
});
tabs.addTab({
id: "func-tab-init",
label: that._("function.label.initialize")
});
tabs.addTab({
id: "func-tab-body",
label: that._("function.label.function")
});
tabs.addTab({
id: "func-tab-finalize",
label: that._("function.label.finalize")
});
tabs.activateTab("func-tab-body");
$( "#node-input-outputs" ).spinner({
min:0,
change: function(event, ui) {
@@ -50,75 +109,145 @@
}
});
this.editor = RED.editor.createEditor({
id: 'node-input-func-editor',
mode: 'ace/mode/nrjavascript',
value: $("#node-input-func").val(),
globals: {
msg:true,
context:true,
RED: true,
util: true,
flow: true,
global: true,
console: true,
Buffer: true,
setTimeout: true,
clearTimeout: true,
setInterval: true,
clearInterval: true
var buildEditor = function(id, value, defaultValue) {
var editor = RED.editor.createEditor({
id: id,
mode: 'ace/mode/nrjavascript',
value: value || defaultValue || "",
globals: {
msg:true,
context:true,
RED: true,
util: true,
flow: true,
global: true,
console: true,
Buffer: true,
setTimeout: true,
clearTimeout: true,
setInterval: true,
clearInterval: true
}
});
if (defaultValue && value === "") {
editor.moveCursorTo(defaultValue.split("\n").length - 1, 0);
}
});
return editor;
}
this.initEditor = buildEditor('node-input-init-editor',$("#node-input-initialize").val(),RED._("node-red:function.text.initialize"))
this.editor = buildEditor('node-input-func-editor',$("#node-input-func").val())
this.finalizeEditor = buildEditor('node-input-finalize-editor',$("#node-input-finalize").val(),RED._("node-red:function.text.finalize"))
RED.library.create({
url: "functions", // where to get the data from
type: "function", // the type of object the library is for
editor: this.editor, // the field name the main text body goes to
nodeInfoEditor: this.nodeInfoEditor,
mode: "ace/mode/nrjavascript",
fields: ['name', 'outputs', 'info'],
ext: "js"
url:"functions", // where to get the data from
type:"function", // the type of object the library is for
editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/nrjavascript",
fields:[
'name', 'outputs',
{
name: 'initialize',
get: function() {
return that.initEditor.getValue();
},
set: function(v) {
that.initEditor.setValue(v||RED._("node-red:function.text.initialize"), -1);
}
},
{
name: 'finalize',
get: function() {
return that.finalizeEditor.getValue();
},
set: function(v) {
that.finalizeEditor.setValue(v||RED._("node-red:function.text.finalize"), -1);
}
},
{
name: 'info',
get: function() {
return that.infoEditor.getValue();
},
set: function(v) {
that.infoEditor.setValue(v||"", -1);
}
}
],
ext:"js"
});
this.editor.focus();
RED.popover.tooltip($("#node-function-expand-js"), RED._("node-red:common.label.expand"));
$("#node-function-expand-js").on("click", function(e) {
e.preventDefault();
var value = that.editor.getValue();
RED.editor.editJavaScript({
value: value,
width: "Infinity",
cursor: that.editor.getCursorPosition(),
mode: "ace/mode/nrjavascript",
complete: function(v,cursor) {
that.editor.setValue(v, -1);
that.editor.gotoLine(cursor.row+1,cursor.column,false);
setTimeout(function() {
that.editor.focus();
},300);
}
})
})
},
oneditsave: function() {
var annot = this.editor.getSession().getAnnotations();
this.noerr = 0;
$("#node-input-noerr").val(0);
for (var k=0; k < annot.length; k++) {
//console.log(annot[k].type,":",annot[k].text, "on line", annot[k].row);
if (annot[k].type === "error") {
$("#node-input-noerr").val(annot.length);
this.noerr = annot.length;
var expandButtonClickHandler = function(editor) {
return function(e) {
e.preventDefault();
var value = editor.getValue();
RED.editor.editJavaScript({
value: value,
width: "Infinity",
cursor: editor.getCursorPosition(),
mode: "ace/mode/nrjavascript",
complete: function(v,cursor) {
editor.setValue(v, -1);
editor.gotoLine(cursor.row+1,cursor.column,false);
setTimeout(function() {
editor.focus();
},300);
}
})
}
}
$("#node-input-func").val(this.editor.getValue());
this.editor.destroy();
delete this.editor;
$("#node-init-expand-js").on("click", expandButtonClickHandler(this.initEditor));
$("#node-function-expand-js").on("click", expandButtonClickHandler(this.editor));
$("#node-finalize-expand-js").on("click", expandButtonClickHandler(this.finalizeEditor));
RED.popover.tooltip($("#node-init-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-function-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-finalize-expand-js"), RED._("node-red:common.label.expand"));
},
oneditsave: function() {
var node = this;
var noerr = 0;
$("#node-input-noerr").val(0);
var disposeEditor = function(editorName,targetName,defaultValue) {
var editor = node[editorName];
var annot = editor.getSession().getAnnotations();
for (var k=0; k < annot.length; k++) {
if (annot[k].type === "error") {
noerr += annot.length;
break;
}
}
var val = editor.getValue();
if (defaultValue && val == defaultValue) {
val = "";
}
editor.destroy();
delete node[editorName];
$("#"+targetName).val(val);
}
disposeEditor("editor","node-input-func");
disposeEditor("initEditor","node-input-initialize", RED._("node-red:function.text.initialize"));
disposeEditor("finalizeEditor","node-input-finalize", RED._("node-red:function.text.finalize"));
$("#node-input-noerr").val(noerr);
this.noerr = noerr;
},
oneditcancel: function() {
this.editor.destroy();
delete this.editor;
var node = this;
node.editor.destroy();
delete node.editor;
node.initEditor.destroy();
delete node.initEditor;
node.finalizeEditor.destroy();
delete node.finalizeEditor;
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
@@ -130,6 +259,16 @@
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
this.editor.resize();
var height = size.height;
$("#node-input-init-editor").css("height", (height -105)+"px");
$("#node-input-func-editor").css("height", (height -145)+"px");
$("#node-input-finalize-editor").css("height", (height -105)+"px");
this.initEditor.resize();
this.editor.resize();
this.finalizeEditor.resize();
}
});
</script>

View File

@@ -57,17 +57,50 @@ module.exports = function(RED) {
}
}
function createVMOpt(node, kind) {
var opt = {
filename: 'Function node'+kind+':'+node.id+(node.name?' ['+node.name+']':''), // filename for stack traces
displayErrors: true
// Using the following options causes node 4/6 to not include the line number
// in the stack output. So don't use them.
// lineOffset: -11, // line number offset to be used for stack traces
// columnOffset: 0, // column number offset to be used for stack traces
};
return opt;
}
function updateErrorInfo(err) {
if (err.stack) {
var stack = err.stack.toString();
var m = /^([^:]+):([^:]+):(\d+).*/.exec(stack);
if (m) {
var line = parseInt(m[3]) -1;
var kind = "body:";
if (/setup/.exec(m[1])) {
kind = "setup:";
}
if (/cleanup/.exec(m[1])) {
kind = "cleanup:";
}
err.message += " ("+kind+"line "+line+")";
}
}
}
function FunctionNode(n) {
RED.nodes.createNode(this,n);
var node = this;
this.name = n.name;
this.func = n.func;
node.name = n.name;
node.func = n.func;
node.ini = n.initialize ? n.initialize : "";
node.fin = n.finalize ? n.finalize : "";
var handleNodeDoneCall = true;
// Check to see if the Function appears to call `node.done()`. If so,
// we will assume it is well written and does actually call node.done().
// Otherwise, we will call node.done() after the function returns regardless.
if (/node\.done\s*\(\s*\)/.test(this.func)) {
if (/node\.done\s*\(\s*\)/.test(node.func)) {
handleNodeDoneCall = false;
}
@@ -87,11 +120,13 @@ module.exports = function(RED) {
"send:function(msgs,cloneMsg){ __node__.send(__send__,__msgid__,msgs,cloneMsg);},"+
"done:__done__"+
"};\n"+
this.func+"\n"+
node.func+"\n"+
"})(msg,send,done);";
this.topic = n.topic;
this.outstandingTimers = [];
this.outstandingIntervals = [];
var finScript = null;
var finOpt = null;
node.topic = n.topic;
node.outstandingTimers = [];
node.outstandingIntervals = [];
var sandbox = {
console:console,
util:util,
@@ -182,12 +217,12 @@ module.exports = function(RED) {
arguments[0] = function() {
sandbox.clearTimeout(timerId);
try {
func.apply(this,arguments);
func.apply(node,arguments);
} catch(err) {
node.error(err,{});
}
};
timerId = setTimeout.apply(this,arguments);
timerId = setTimeout.apply(node,arguments);
node.outstandingTimers.push(timerId);
return timerId;
},
@@ -203,12 +238,12 @@ module.exports = function(RED) {
var timerId;
arguments[0] = function() {
try {
func.apply(this,arguments);
func.apply(node,arguments);
} catch(err) {
node.error(err,{});
}
};
timerId = setInterval.apply(this,arguments);
timerId = setInterval.apply(node,arguments);
node.outstandingIntervals.push(timerId);
return timerId;
},
@@ -226,35 +261,46 @@ module.exports = function(RED) {
sandbox.setTimeout(function(){ resolve(value); }, after);
});
};
sandbox.promisify = util.promisify;
}
var context = vm.createContext(sandbox);
try {
this.script = vm.createScript(functionText, {
filename: 'Function node:'+this.id+(this.name?' ['+this.name+']':''), // filename for stack traces
displayErrors: true
// Using the following options causes node 4/6 to not include the line number
// in the stack output. So don't use them.
// lineOffset: -11, // line number offset to be used for stack traces
// columnOffset: 0, // column number offset to be used for stack traces
});
this.on("input", function(msg,send,done) {
var iniScript = null;
var iniOpt = null;
if (node.ini && (node.ini !== "")) {
var iniText = "(async function () {\n"+node.ini +"\n})();";
iniOpt = createVMOpt(node, " setup");
iniScript = new vm.Script(iniText, iniOpt);
}
node.script = vm.createScript(functionText, createVMOpt(node, ""));
if (node.fin && (node.fin !== "")) {
var finText = "(function () {\n"+node.fin +"\n})();";
finOpt = createVMOpt(node, " cleanup");
finScript = new vm.Script(finText, finOpt);
}
var promise = Promise.resolve();
if (iniScript) {
promise = iniScript.runInContext(context, iniOpt);
}
function processMessage(msg, send, done) {
try {
var start = process.hrtime();
context.msg = msg;
context.send = send;
context.done = done;
this.script.runInContext(context);
sendResults(this,send,msg._msgid,context.results,false);
node.script.runInContext(context);
sendResults(node,send,msg._msgid,context.results,false);
if (handleNodeDoneCall) {
done();
}
var duration = process.hrtime(start);
var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100;
this.metric("duration", msg, converted);
node.metric("duration", msg, converted);
if (process.env.NODE_RED_FUNCTION_TIME) {
this.status({fill:"yellow",shape:"dot",text:""+converted});
node.status({fill:"yellow",shape:"dot",text:""+converted});
}
} catch(err) {
if ((typeof err === "object") && err.hasOwnProperty("stack")) {
@@ -295,22 +341,66 @@ module.exports = function(RED) {
done(JSON.stringify(err));
}
}
}
const RESOLVING = 0;
const RESOLVED = 1;
const ERROR = 2;
var state = RESOLVING;
var messages = [];
node.on("input", function(msg,send,done) {
if(state === RESOLVING) {
messages.push({msg:msg, send:send, done:done});
}
else if(state === RESOLVED) {
processMessage(msg, send, done);
}
});
this.on("close", function() {
node.on("close", function() {
if (finScript) {
try {
finScript.runInContext(context, finOpt);
}
catch (err) {
node.error(err);
}
}
while (node.outstandingTimers.length > 0) {
clearTimeout(node.outstandingTimers.pop());
}
while (node.outstandingIntervals.length > 0) {
clearInterval(node.outstandingIntervals.pop());
}
this.status({});
node.status({});
});
} catch(err) {
promise.then(function (v) {
var msgs = messages;
messages = [];
while (msgs.length > 0) {
msgs.forEach(function (s) {
processMessage(s.msg, s.send, s.done);
});
msgs = messages;
messages = [];
}
state = RESOLVED;
}).catch((error) => {
messages = [];
state = ERROR;
node.error(error);
});
}
catch(err) {
// eg SyntaxError - which v8 doesn't include line number information
// so we can't do better than this
this.error(err);
updateErrorInfo(err);
node.error(err);
}
}
RED.nodes.registerType("function",FunctionNode);
RED.library.register("functions");
};

View File

@@ -1,5 +1,10 @@
<script type="text/html" data-template-name="change">
<style>
ol#node-input-rule-container .red-ui-typedInput-container {
flex:1;
}
</style>
<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">
@@ -76,11 +81,6 @@
var replace = this._("change.action.replace");
var regex = this._("change.label.regex");
function resizeRule(rule) {
var newWidth = rule.width();
rule.find('.red-ui-typedInput').typedInput("width",newWidth-130);
}
$('#node-input-rule-container').css('min-height','150px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var rule = opt;
@@ -106,10 +106,11 @@
overflow: 'hidden',
whiteSpace: 'nowrap'
});
var row1 = $('<div/>').appendTo(container);
var row2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container);
var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container);
var row4 = $('<div/>',{style:"margin-top:8px;"}).appendTo(container);
let fragment = document.createDocumentFragment();
var row1 = $('<div/>',{style:"display:flex;"}).appendTo(fragment);
var row2 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(fragment);
var row3 = $('<div/>',{style:"margin-top:8px;"}).appendTo(fragment);
var row4 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(fragment);
var selectField = $('<select/>',{class:"node-input-rule-type",style:"width:110px; margin-right:10px;"}).appendTo(row1);
var selectOptions = [{v:"set",l:set},{v:"change",l:change},{v:"delete",l:del},{v:"move",l:move}];
@@ -124,41 +125,82 @@
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(to)
.appendTo(row2);
var propertyValue = $('<input/>',{class:"node-input-rule-property-value",type:"text"})
function createPropertyValue() {
return $('<input/>',{class:"node-input-rule-property-value",type:"text"})
.appendTo(row2)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
}
var row3_1 = $('<div/>').appendTo(row3);
var row3_1 = $('<div/>', {style:"display:flex;"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(search)
.appendTo(row3_1);
var fromValue = $('<input/>',{class:"node-input-rule-property-search-value",type:"text"})
function createFromValue() {
return $('<input/>',{class:"node-input-rule-property-search-value",type:"text"})
.appendTo(row3_1)
.typedInput({default:'str',types:['msg','flow','global','str','re','num','bool','env']});
}
var row3_2 = $('<div/>',{style:"margin-top:8px;"}).appendTo(row3);
var row3_2 = $('<div/>',{style:"display:flex;margin-top:8px;"}).appendTo(row3);
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(replace)
.appendTo(row3_2);
var toValue = $('<input/>',{class:"node-input-rule-property-replace-value",type:"text"})
function createToValue() {
return $('<input/>',{class:"node-input-rule-property-replace-value",type:"text"})
.appendTo(row3_2)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','env']});
}
$('<div/>',{style:"display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;"})
.text(to)
.appendTo(row4);
var moveValue = $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
function createMoveValue() {
return $('<input/>',{class:"node-input-rule-property-move-value",type:"text"})
.appendTo(row4)
.typedInput({default:'msg',types:['msg','flow','global']});
}
let propertyValue = null;
let fromValue = null;
let toValue = null;
let moveValue = null;
selectField.on("change", function() {
var width = $("#node-input-rule-container").width();
var type = $(this).val();
if (propertyValue) {
propertyValue.typedInput('hide');
}
if (fromValue) {
fromValue.typedInput('hide');
}
if (toValue) {
toValue.typedInput('hide');
}
if (moveValue) {
moveValue.typedInput('hide');
}
if (type == "set") {
if(!propertyValue) {
propertyValue = createPropertyValue();
}
propertyValue.typedInput('show');
row2.show();
row3.hide();
row4.hide();
} else if (type == "change") {
if(!fromValue) {
fromValue = createFromValue();
}
fromValue.typedInput('show');
if(!toValue) {
toValue = createToValue();
}
toValue.typedInput('show');
row2.hide();
row3.show();
row4.hide();
@@ -167,30 +209,48 @@
row3.hide();
row4.hide();
} else if (type == "move") {
if(!moveValue) {
moveValue = createMoveValue();
}
moveValue.typedInput('show');
row2.hide();
row3.hide();
row4.show();
}
resizeRule(container);
});
selectField.val(rule.t);
propertyName.typedInput('value',rule.p);
propertyName.typedInput('type',rule.pt);
propertyValue.typedInput('value',rule.to);
propertyValue.typedInput('type',rule.tot);
moveValue.typedInput('value',rule.to);
moveValue.typedInput('type',rule.tot);
fromValue.typedInput('value',rule.from);
fromValue.typedInput('type',rule.fromt);
toValue.typedInput('value',rule.to);
toValue.typedInput('type',rule.tot);
if (rule.t == "set") {
if(!propertyValue) {
propertyValue = createPropertyValue();
}
propertyValue.typedInput('value',rule.to);
propertyValue.typedInput('type',rule.tot);
}
if (rule.t == "move") {
if(!moveValue) {
moveValue = createMoveValue();
}
moveValue.typedInput('value',rule.to);
moveValue.typedInput('type',rule.tot);
}
if (rule.t == "change") {
if(!fromValue) {
fromValue = createFromValue();
}
fromValue.typedInput('value',rule.from);
fromValue.typedInput('type',rule.fromt);
if (!toValue) {
toValue = createToValue();
}
toValue.typedInput('value',rule.to);
toValue.typedInput('type',rule.tot);
}
selectField.change();
var newWidth = $("#node-input-rule-container").width();
resizeRule(container);
container[0].appendChild(fragment);
},
resizeItem: resizeRule,
removable: true,
sortable: true
});

View File

@@ -18,7 +18,7 @@
<div class="form-row">
<label data-i18n="trigger.send" for="node-input-op1"></label>
<input type="hidden" id="node-input-op1type">
<input style="width: 70%" type="text" id="node-input-op1" placeholder="1">
<input style="width:70%" type="text" id="node-input-op1" placeholder="1">
</div>
<div class="form-row">
<label data-i18n="trigger.then"></label>
@@ -40,13 +40,17 @@
</div>
<div class="form-row node-type-wait">
<label></label>
<input type="checkbox" id="node-input-extend" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;" for="node-input-extend" data-i18n="trigger.extend"></label>
<input type="checkbox" id="node-input-extend" style="margin-left:0px; vertical-align:top; width:auto !important;"> <label style="width:auto !important;" for="node-input-extend" data-i18n="trigger.extend"></label>
</div>
<div class="form-row node-type-wait">
<label data-i18n="trigger.then-send"></label>
<input type="hidden" id="node-input-op2type">
<input style="width: 70%" type="text" id="node-input-op2" placeholder="0">
<input style="width:70%" type="text" id="node-input-op2" placeholder="0">
</div>
<div class="form-row" id="node-second-output">
<label></label>
<input type="checkbox" id="node-input-second" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;" for="node-input-second" data-i18n="trigger.second"></label>
</div>
<div class="form-row">
<label data-i18n="trigger.label.reset" style="width:auto"></label>
<div style="display:inline-block; width:70%;vertical-align:top">
@@ -58,10 +62,13 @@
<br/>
<div class="form-row">
<label data-i18n="trigger.for" for="node-input-bytopic"></label>
<select id="node-input-bytopic">
<select id="node-input-bytopic" style="width:120px;">
<option value="all" data-i18n="trigger.alltopics"></option>
<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%;"/>
</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>
@@ -74,6 +81,7 @@
category: 'function',
color:"#E6E0F8",
defaults: {
name: {value:""},
op1: {value:"1", validate: RED.validators.typedInput("op1type")},
op2: {value:"0", validate: RED.validators.typedInput("op2type")},
op1type: {value:"val"},
@@ -82,8 +90,9 @@
extend: {value:"false"},
units: {value:"ms"},
reset: {value:""},
bytopic: {value: "all"},
name: {value:""}
bytopic: {value:"all"},
topic: {value:"topic",required:true},
outputs: {value:1}
},
inputs:1,
outputs:1,
@@ -103,17 +112,48 @@
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var that = this;
if (this.topic === undefined) { $("#node-input-topic").val("topic"); }
$("#node-input-topic").typedInput({default:'msg',types:['msg']});
$("#node-input-bytopic").on("change", function() {
if ($("#node-input-bytopic").val() === "all") {
$("#node-stream-topic").hide();
} else {
$("#node-stream-topic").show();
}
});
if (this.outputs == 2) { $("#node-input-second").prop('checked', true) }
else { $("#node-input-second").prop('checked', false) }
$("#node-input-second").change(function() {
if ($("#node-input-second").is(":checked")) {
that.outputs = 2;
}
else {
that.outputs = 1;
}
});
$("#node-then-type").on("change", function() {
if ($(this).val() == "block") {
$(".node-type-wait").hide();
$(".node-type-duration").hide();
$("#node-second-output").hide();
$("#node-input-second").prop('checked', false);
that.outputs = 1;
}
else if ($(this).val() == "loop") {
if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); }
$(".node-type-wait").hide();
$(".node-type-duration").show();
$("#node-second-output").hide();
$("#node-input-second").prop('checked', false);
that.outputs = 1;
} else {
if ($("#node-input-duration").val() == 0) { $("#node-input-duration").val(250); }
$(".node-type-wait").show();
$(".node-type-duration").show();
$("#node-second-output").show();
}
});
@@ -176,8 +216,6 @@
if ($("#node-then-type").val() == "loop") {
$("#node-input-duration").val($("#node-input-duration").val() * -1);
}
}
});
</script>

View File

@@ -24,6 +24,8 @@ module.exports = function(RED) {
this.op2 = n.op2 || "0";
this.op1type = n.op1type || "str";
this.op2type = n.op2type || "str";
this.second = (n.outputs == 2) ? true : false;
this.topic = n.topic || "topic";
if (this.op1type === 'val') {
if (this.op1 === 'true' || this.op1 === 'false') {
@@ -76,6 +78,7 @@ module.exports = function(RED) {
var node = this;
node.topics = {};
var npay = {};
var pendingMessages = [];
var activeMessagePromise = null;
var processMessageQueue = function(msg) {
@@ -106,14 +109,19 @@ module.exports = function(RED) {
});
}
var npay;
this.on('input', function(msg) {
if (node.op2type === "payl") { npay = RED.util.cloneMessage(msg); }
processMessageQueue(msg);
});
var stat = function() {
var l = Object.keys(node.topics).length;
if (l === 0) { return {} }
else if (l === 1) { return {fill:"blue",shape:"dot"} }
else return {fill:"blue",shape:"dot",text:l};
}
var processMessage = function(msg) {
var topic = msg.topic || "_none";
var topic = RED.util.getMessageProperty(msg,node.topic) || "_none";
var promise;
if (node.bytopic === "all") { topic = "_none"; }
node.topics[topic] = node.topics[topic] || {};
@@ -121,9 +129,10 @@ module.exports = function(RED) {
if (node.loop === true) { clearInterval(node.topics[topic].tout); }
else { clearTimeout(node.topics[topic].tout); }
delete node.topics[topic];
node.status({});
node.status(stat());
}
else {
if (node.op2type === "payl") { npay[topic] = RED.util.cloneMessage(msg); }
if (((!node.topics[topic].tout) && (node.topics[topic].tout !== 0)) || (node.loop === true)) {
promise = Promise.resolve();
if (node.op2type === "pay") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
@@ -188,23 +197,30 @@ module.exports = function(RED) {
});
}
promise.then(() => {
msg2.payload = node.topics[topic].m2;
if (node.op2type === "payl") {
if (node.second === true) { node.send([null,npay[topic]]); }
else { node.send(npay[topic]); }
delete npay[topic];
}
else {
msg2.payload = node.topics[topic].m2;
if (node.second === true) { node.send([null,msg2]); }
else { node.send(msg2); }
}
delete node.topics[topic];
if (node.op2type === "payl") { node.send(npay); }
else { node.send(msg2); }
node.status({});
node.status(stat());
}).catch(err => {
node.error(err);
});
} else {
delete node.topics[topic];
node.status({});
node.status(stat());
}
}, node.duration);
}
}
node.status({fill:"blue",shape:"dot",text:" "});
node.status(stat());
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
});
});
@@ -240,8 +256,9 @@ module.exports = function(RED) {
}
}
delete node.topics[topic];
node.status({});
node.send(msg2);
node.status(stat());
if (node.second === true) { node.send([null,msg2]); }
else { node.send(msg2); }
}).catch(err => {
node.error(err);
});
@@ -262,7 +279,7 @@ module.exports = function(RED) {
delete node.topics[t];
}
}
node.status({});
node.status(stat());
});
}
RED.nodes.registerType("trigger",TriggerNode);

View File

@@ -145,7 +145,7 @@ module.exports = function(RED) {
if (error.signal) { msg3.payload.signal = error.signal; }
if (error.code === null) { node.status({fill:"red",shape:"dot",text:"killed"}); }
else { node.status({fill:"red",shape:"dot",text:"error:"+error.code}); }
node.log('error:' + error);
if (RED.settings.verbose) { node.log('error:' + error); }
}
else if (node.oldrc === "false") {
msg3 = RED.util.cloneMessage(msg);

View File

@@ -303,7 +303,7 @@
return this.name;
}
var b = this.broker;
if (b === "") { b = "undefined"; }
if (!b) { b = "undefined"; }
var lab = "";
lab = (this.clientid?this.clientid+"@":"")+b;
if (b.indexOf("://") === -1){

View File

@@ -153,7 +153,12 @@ module.exports = function(RED) {
this.brokerurl="mqtt://";
}
if (this.broker !== "") {
this.brokerurl = this.brokerurl+this.broker+":";
//Check for an IPv6 address
if (/(?:^|(?<=\s))(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(?=\s|$)/.test(this.broker)) {
this.brokerurl = this.brokerurl+"["+this.broker+"]:";
} else {
this.brokerurl = this.brokerurl+this.broker+":";
}
// port now defaults to 1883 if unset.
if (!this.port){
this.brokerurl = this.brokerurl+"1883";
@@ -464,6 +469,7 @@ module.exports = function(RED) {
this.broker = n.broker;
this.brokerConn = RED.nodes.getNode(this.broker);
var node = this;
var chk = /[\+#]/;
if (this.brokerConn) {
this.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
@@ -482,6 +488,7 @@ module.exports = function(RED) {
}
if ( msg.hasOwnProperty("payload")) {
if (msg.hasOwnProperty("topic") && (typeof msg.topic === "string") && (msg.topic !== "")) { // topic must exist
if (chk.test(msg.topic)) { node.warn(RED._("mqtt.errors.invalid-topic")); }
this.brokerConn.publish(msg, done); // send the message
} else {
node.warn(RED._("mqtt.errors.invalid-topic"));

View File

@@ -163,7 +163,7 @@
if (root === "") {
$("#node-config-ws-tip").hide();
} else {
$("#node-config-ws-path").html(root);
$("#node-config-ws-path").html(RED._("node-red:websocket.tip.path2", { path: root }));
$("#node-config-ws-tip").show();
}
}
@@ -235,7 +235,7 @@
</div>
<div class="form-tips">
<span data-i18n="[html]websocket.tip.path1"></span>
<p id="node-config-ws-tip"><span data-i18n="[html]websocket.tip.path2"></span><code><span id="node-config-ws-path"></span></code>.</p>
<p id="node-config-ws-tip"><span id="node-config-ws-path"></span></p>
</div>
</script>

View File

@@ -170,15 +170,14 @@
$("#node-input-port-row").hide();
$("#node-input-host-row").hide();
$("#node-input-end-row").hide();
} else if (sockettype == "client"){
$("#node-input-port-row").show();
$("#node-input-host-row").show();
$("#node-input-end-row").show();
} else {
$("#node-input-port-row").show();
$("#node-input-end-row").show();
}
if (sockettype == "client") {
$("#node-input-host-row").show();
} else {
$("#node-input-host-row").hide();
$("#node-input-end-row").show();
}
};
updateOptions();

View File

@@ -74,7 +74,7 @@ module.exports = function(RED) {
buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
node.connected = true;
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
});
client.setKeepAlive(true,120000);
connectionPool[id] = client;
@@ -121,7 +121,7 @@ module.exports = function(RED) {
client.on('close', function() {
delete connectionPool[id];
node.connected = false;
node.status({fill:"red",shape:"ring",text:"common.status.disconnected"});
node.status({fill:"red",shape:"ring",text:"common.status.disconnected",_session:{type:"tcp",id:id}});
if (!node.closing) {
if (end) { // if we were asked to close then try to reconnect once very quick.
end = false;

View File

@@ -180,6 +180,10 @@ module.exports = function(RED) {
node.tout = setTimeout(function() {
if (udpInputPortsInUse[p]) {
sock = udpInputPortsInUse[p];
if (node.multicast != "false") {
sock.setBroadcast(true);
sock.setMulticastLoopback(false);
}
node.log(RED._("udp.status.re-use",{outport:node.outport,host:node.addr,port:node.port}));
if (node.iface) { node.status({text:n.iface+" : "+node.iface}); }
}

View File

@@ -28,11 +28,15 @@
</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>&nbsp;<input type="text" id="node-input-skip" style="width:30px; height:25px;"/>&nbsp;<span data-i18n="csv.label.skip-e"></span><br/>
<span data-i18n="csv.label.skip-s"></span>&nbsp;<input type="text" id="node-input-skip" style="width:40px; height:25px;"/>&nbsp;<span data-i18n="csv.label.skip-e"></span><br/>
<label>&nbsp;</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/>
<label>&nbsp;</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/>
<label>&nbsp;</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/>
<label>&nbsp;</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/>
</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>
@@ -45,8 +49,13 @@
<label style="width:100%;"><span data-i18n="csv.label.o2c"></span></label>
</div>
<div class="form-row" style="padding-left:20px;">
<label><i class="fa fa-sign-in"></i> <span data-i18n="csv.label.output"></span></label>
<input style="width:20px; vertical-align:top; margin-right:5px;" type="checkbox" id="node-input-hdrout"><label style="width:auto;" for="node-input-hdrout"><span data-i18n="csv.label.includerow"></span></span>
<label><i class="fa fa-sign-out"></i> <span data-i18n="csv.label.output"></span></label>
<!-- <input style="width:20px; vertical-align:top; margin-right:5px;" type="checkbox" id="node-input-hdrout"><label style="width:auto;" for="node-input-hdrout"><span data-i18n="csv.label.includerow"></span></span> -->
<select style="width:60%" id="node-input-hdrout">
<option value="none" data-i18n="csv.hdrout.none"></option>
<option value="all" data-i18n="csv.hdrout.all"></option>
<option value="once" data-i18n="csv.hdrout.once"></option>
</select>
</div>
<div class="form-row" style="padding-left:20px;">
<label></label>
@@ -69,12 +78,14 @@
sep: {value:',',required:true,validate:RED.validators.regex(/^.{1,2}$/)},
//quo: {value:'"',required:true},
hdrin: {value:""},
hdrout: {value:""},
hdrout: {value:"none"},
multi: {value:"one",required:true},
ret: {value:'\\n'},
temp: {value:""},
skip: {value:"0"},
strings: {value:true}
strings: {value:true},
include_empty_strings: {value:""},
include_null_values: {value:""}
},
inputs:1,
outputs:1,
@@ -86,6 +97,8 @@
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.hdrout === false) { this.hdrout = "none"; $("#node-input-hdrout").val("none"); }
if (this.hdrout === true) { this.hdrout = "all"; $("#node-input-hdrout").val("all");}
if (this.strings === undefined) { this.strings = true; $("#node-input-strings").prop('checked', true); }
if (this.skip === undefined) { this.skip = 0; $("#node-input-skip").val("0");}
$("#node-input-skip").spinner({ min:0 });

View File

@@ -26,12 +26,16 @@ module.exports = function(RED) {
this.lineend = "\n";
this.multi = n.multi || "one";
this.hdrin = n.hdrin || false;
this.hdrout = n.hdrout || false;
this.hdrout = n.hdrout || "none";
this.goodtmpl = true;
this.skip = parseInt(n.skip || 0);
this.store = [];
this.parsestrings = n.strings;
this.include_empty_strings = n.include_empty_strings || false;
this.include_null_values = n.include_null_values || false;
if (this.parsestrings === undefined) { this.parsestrings = true; }
if (this.hdrout === false) { this.hdrout = "none"; }
if (this.hdrout === true) { this.hdrout = "all"; }
var tmpwarn = true;
var node = this;
@@ -49,14 +53,22 @@ module.exports = function(RED) {
return col;
}
node.template = clean(node.template);
node.hdrSent = false;
this.on("input", function(msg) {
if (msg.hasOwnProperty("reset")) {
node.hdrSent = false;
}
if (msg.hasOwnProperty("payload")) {
if (typeof msg.payload == "object") { // convert object to CSV string
try {
var ou = "";
if (node.hdrout) {
if (node.hdrout !== "none" && node.hdrSent === false) {
if ((node.template.length === 1) && (node.template[0] === '') && (msg.hasOwnProperty("columns"))) {
node.template = clean((msg.columns || "").split(","));
}
ou += node.template.join(node.sep) + node.ret;
if (node.hdrout === "once") { node.hdrSent = true; }
}
if (!Array.isArray(msg.payload)) { msg.payload = [ msg.payload ]; }
for (var s = 0; s < msg.payload.length; s++) {
@@ -75,13 +87,15 @@ module.exports = function(RED) {
ou += msg.payload[s].join(node.sep) + node.ret;
}
else {
if ((node.template.length === 1) && (node.template[0] === '') && (msg.hasOwnProperty("columns"))) {
node.template = clean((msg.columns || "").split(","));
}
if ((node.template.length === 1) && (node.template[0] === '')) {
/* istanbul ignore else */
if (tmpwarn === true) { // just warn about missing template once
node.warn(RED._("csv.errors.obj_csv"));
tmpwarn = false;
}
ou = "";
for (var p in msg.payload[0]) {
/* istanbul ignore else */
if (msg.payload[0].hasOwnProperty(p)) {
@@ -125,6 +139,7 @@ module.exports = function(RED) {
}
}
msg.payload = ou;
msg.columns = node.template.join(',');
if (msg.payload !== '') { node.send(msg); }
}
catch(e) { node.error(e,msg); }
@@ -173,20 +188,29 @@ module.exports = function(RED) {
}
else if ((line[i] === node.sep) && f) { // if it is the end of the line then finish
if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "" ) ) {
if ( (node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
o[node.template[j]] = k[j];
if ( node.template[j] && (node.template[j] !== "") ) {
// if no value between separators ('1,,"3"...') or if the line beings with separator (',1,"2"...') treat value as null
if (line[i-1] === node.sep || line[i-1].includes('\n','\r')) k[j] = null;
if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
if (node.include_null_values && k[j] === null) o[node.template[j]] = k[j];
if (node.include_empty_strings && k[j] === "") o[node.template[j]] = k[j];
if (k[j] !== null && k[j] !== "") o[node.template[j]] = k[j];
}
j += 1;
k[j] = "";
// if separator is last char in processing string line (without end of line), add null value at the end - example: '1,2,3\n3,"3",'
k[j] = line.length - 1 === i ? null : "";
}
else if ((line[i] === "\n") || (line[i] === "\r")) { // handle multiple lines
else if (((line[i] === "\n") || (line[i] === "\r")) && f) { // handle multiple lines
//console.log(j,k,o,k[j]);
if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "") ) {
if ( (node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
else { k[j].replace(/\r$/,''); }
o[node.template[j]] = k[j];
if ( node.template[j] && (node.template[j] !== "") ) {
// if separator before end of line, set null value ie. '1,2,"3"\n1,2,\n1,2,3'
if (line[i-1] === node.sep) k[j] = null;
if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
else { if (k[j] !== null) k[j].replace(/\r$/,''); }
if (node.include_null_values && k[j] === null) o[node.template[j]] = k[j];
if (node.include_empty_strings && k[j] === "") o[node.template[j]] = k[j];
if (k[j] !== null && k[j] !== "") o[node.template[j]] = k[j];
}
if (JSON.stringify(o) !== "{}") { // don't send empty objects
a.push(o); // add to the array
@@ -202,17 +226,21 @@ module.exports = function(RED) {
}
}
// Finished so finalize and send anything left
//console.log(j,k,o,k[j]);
if (f === false) { node.warn(RED._("csv.errors.bad_csv")); }
if (!node.goodtmpl) { node.template[j] = "col"+(j+1); }
if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "") ) {
if ( (node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
else { k[j].replace(/\r$/,''); }
o[node.template[j]] = k[j];
if ( node.template[j] && (node.template[j] !== "") ) {
if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
else { if (k[j] !== null) k[j].replace(/\r$/,''); }
if (node.include_null_values && k[j] === null) o[node.template[j]] = k[j];
if (node.include_empty_strings && k[j] === "") o[node.template[j]] = k[j];
if (k[j] !== null && k[j] !== "") o[node.template[j]] = k[j];
}
if (JSON.stringify(o) !== "{}") { // don't send empty objects
a.push(o); // add to the array
}
var has_parts = msg.hasOwnProperty("parts");
if (node.multi !== "one") {
msg.payload = a;
if (has_parts) {
@@ -221,12 +249,14 @@ module.exports = function(RED) {
}
if (msg.parts.index + 1 === msg.parts.count) {
msg.payload = node.store;
msg.columns = node.template.filter(val => val).join(',');
delete msg.parts;
node.send(msg);
node.store = [];
}
}
else {
msg.columns = node.template.filter(val => val).join(',');
node.send(msg); // finally send the array
}
}
@@ -234,6 +264,7 @@ module.exports = function(RED) {
var len = a.length;
for (var i = 0; i < len; i++) {
var newMessage = RED.util.cloneMessage(msg);
newMessage.columns = node.template.filter(val => val).join(',');
newMessage.payload = a[i];
if (!has_parts) {
newMessage.parts = {
@@ -259,7 +290,11 @@ module.exports = function(RED) {
}
else { node.warn(RED._("csv.errors.csv_js")); }
}
else { node.send(msg); } // If no payload - just pass it on.
else {
if (!msg.hasOwnProperty("reset")) {
node.send(msg); // If no payload and not reset - just pass it on.
}
}
});
}
RED.nodes.registerType("csv",CSVNode);

View File

@@ -292,7 +292,6 @@ module.exports = function(RED) {
reduceMessageGroup(node,msgs,exp,fixup,count,result,done);
}
});
}
function reduceAndSendGroup(node, group, done) {
var is_right = node.reduce_right;
@@ -331,7 +330,7 @@ module.exports = function(RED) {
var pending_count = node.pending_count;
var gid = msg.parts.id;
var count;
if(!pending.hasOwnProperty(gid)) {
if (!pending.hasOwnProperty(gid)) {
if(parts.hasOwnProperty('count')) {
count = msg.parts.count;
}
@@ -361,7 +360,6 @@ module.exports = function(RED) {
}
return done();
}
if (msgs.length === group.count) {
delete pending[gid];
pending_count -= msgs.length;
@@ -408,7 +406,7 @@ module.exports = function(RED) {
if (this.joinerType === "str") {
this.joiner = this.joiner.replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t").replace(/\\e/g,"\e").replace(/\\f/g,"\f").replace(/\\0/g,"\0");
} else if (this.joinerType === "bin") {
var joinArray = JSON.parse(n.joiner)
var joinArray = JSON.parse(n.joiner || "[]");
if (Array.isArray(joinArray)) {
this.joiner = Buffer.from(joinArray);
} else {
@@ -429,7 +427,7 @@ module.exports = function(RED) {
var completeSend = function(partId) {
var group = inflight[partId];
clearTimeout(group.timeout);
if (group.timeout) { clearTimeout(group.timeout); }
if ((node.accumulate !== true) || group.msg.hasOwnProperty("complete")) { delete inflight[partId]; }
if (group.type === 'array' && group.arrayLen > 1) {
var newArray = [];
@@ -448,6 +446,9 @@ module.exports = function(RED) {
buffers.push(joinBuffer);
bufferLen += joinBuffer.length;
}
if (!Buffer.isBuffer(group.payload[i])) {
group.payload[i] = Buffer.from(group.payload[i]);
}
buffers.push(group.payload[i]);
bufferLen += group.payload[i].length;
}
@@ -629,7 +630,13 @@ module.exports = function(RED) {
var group = inflight[partId];
if (payloadType === 'buffer') {
if (property !== undefined) {
inflight[partId].bufferLen += property.length;
if (Buffer.isBuffer(property) || (typeof property === "string") || Array.isArray(property)) {
inflight[partId].bufferLen += property.length;
}
else {
node.error(RED._("join.errors.invalid-type",{error:(typeof property)}),msg);
return;
}
}
}
if (payloadType === 'object') {

View File

@@ -179,6 +179,11 @@ module.exports = function(RED) {
}
node.pending = [];
this.on("input", function(msg) {
if (msg.hasOwnProperty("reset")) {
node.pending = [];
node.pending_count = 0;
return;
}
var queue = node.pending;
queue.push(msg);
node.pending_count++;
@@ -204,11 +209,26 @@ module.exports = function(RED) {
var interval = Number(n.interval || "0") *1000;
var allow_empty_seq = n.allowEmptySequence;
node.pending = []
var timer = setInterval(function() {
function msgHandler() {
send_interval(node, allow_empty_seq);
node.pending_count = 0;
}, interval);
}
var timer = undefined;
if (interval > 0) {
timer = setInterval(msgHandler, interval);
}
this.on("input", function(msg) {
if (msg.hasOwnProperty("reset")) {
if (timer !== undefined) {
clearInterval(timer);
}
node.pending = [];
node.pending_count = 0;
if (interval > 0) {
timer = setInterval(msgHandler, interval);
}
return;
}
node.pending.push(msg);
node.pending_count++;
var max_msgs = max_kept_msgs_count(node);
@@ -219,7 +239,9 @@ module.exports = function(RED) {
}
});
this.on("close", function() {
clearInterval(timer);
if (timer !== undefined) {
clearInterval(timer);
}
node.pending = [];
node.pending_count = 0;
});
@@ -230,6 +252,11 @@ module.exports = function(RED) {
});
node.pending = {};
this.on("input", function(msg) {
if (msg.hasOwnProperty("reset")) {
node.pending = {};
node.pending_count = 0;
return;
}
concat_msg(node, msg);
});
this.on("close", function() {

View File

@@ -397,7 +397,7 @@
"message" : "gesamte Nachricht",
"tip" : {
"path1" : "Standardmäßig enthält <code> Nutzdaten </code> die Daten, die über einen Websocket gesendet oder von einem Websocket empfangen werden. Der Listener kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge sendet oder empfängt.",
"path2" : "Dieser Pfad ist relativ zu ",
"path2" : "Dieser Pfad ist relativ zu <code>__path__</code>.",
"url1" : "URL sollte ws: &#47; & #47; oder wss: &#47; & #47; Schema verwenden und auf einen vorhandenen Websocket-Listener verweisen.",
"url2" : "Standardmäßig enthält <code> Nutzdaten </code> die Daten, die über einen Websocket gesendet oder von einem Websocket empfangen werden. Der Client kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge sendet oder empfängt."
},

View File

@@ -23,13 +23,13 @@
<script type="text/html" data-help-name="websocket out">
<p>WebSocket Ausgabe-Node.</p>
<p>Standardmäßig wird <code>msg.payload</code> über den WebSocket gesendet.
<p>Standardmäßig wird <code>msg.payload</code> über den WebSocket gesendet.
Der Socket kann so konfiguriert werden, dass er das gesamte <code>msg</code> Objekt als JSON-String kodiert und über den WebSocket sendet.</p>
<p>Wenn die an diesem Node ankommende Nachricht an einem WebSocket-Eingangs-Node begann,
wird die Nachricht an den Client zurückgesendet, der den Flow ausgelöst hat.
wird die Nachricht an den Client zurückgesendet, der den Flow ausgelöst hat.
Andernfalls wird die Nachricht an alle verbundenen Clients gesendet..</p>
<p>Wenn eine Nachricht, die an einem WebSocket-Eingangsnoten gestartet wurde, an alle verbunden Clients gesendet werden soll,
<p>Wenn eine Nachricht, die an einem WebSocket-Eingangsnoten gestartet wurde, an alle verbunden Clients gesendet werden soll,
muss die Eigenschaft <code>msg._session</code> innerhalb des Flow gelöscht werden.</p>
</script>
@@ -37,30 +37,6 @@
<p>Dieser Konfigurations-Node erstellt einen WebSocket Server-Endpunkt unter Verwendung des angegebenen Pfades.</p>
</script>
<!-- WebSocket Client configuration node -->
<script type="text/html" data-template-name="websocket-client">
<div class="form-row">
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
<input id="node-config-input-path" type="text" placeholder="ws://example.com/ws">
</div>
<div class="form-row node-config-row-tls hide">
<label for="node-config-input-tls" data-i18n="httpin.tls-config"></label>
<input type="text" id="node-config-input-tls">
</div>
<div class="form-row">
<label for="node-config-input-wholemsg" data-i18n="websocket.sendrec"></label>
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
<option value="false" data-i18n="websocket.payload"></option>
<option value="true" data-i18n="websocket.message"></option>
</select>
</div>
<div class="form-tips">
<p><span data-i18n="[html]websocket.tip.url1"></span></p>
<span data-i18n="[html]websocket.tip.url2"></span>
</div>
</script>
<script type="text/html" data-help-name="websocket-client">
<p>Dieser Konfigurations-Node verbindet einen WebSocket-Client mit der angegebenen URL.</p>
</script>

View File

@@ -20,6 +20,10 @@
<dl class="message-properties">
<dt>payload<span class="property-type">Objekt | String</span></dt>
<dd>Ein JavaScript Objekt oder ein XML String.</dd>
<dt class="optional">options <span class="property-type">Objekt</span></dt>
<dd>This optional property can be used to pass in any of the options supported by the underlying
library used to convert to and from XML. See <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a>
for more information.</dd>
</dl>
<h3>Ausgaben</h3>
<dl class="message-properties">
@@ -30,10 +34,6 @@
<li>Wenn die Eingabe ein JavaScript-Objekt ist, wird versucht ein XML-String zu erstellen.</li>
</ul>
</dd>
<dt class="optional">Optionen <span class="property-type">Objekt</span></dt>
<dd>This optional property can be used to pass in any of the options supported by the underlying
library used to convert to and from XML. See <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a>
for more information.</dd>
</dl>
<h3>Details</h3>
<p>Bei der Konvertierung zwischen XML und einem Objekt werden standardmäßig alle XML-Attribute als Eigenschaft namens <code>$</code> hinzugefügt.

View File

@@ -15,12 +15,14 @@
-->
<script type="text/html" data-help-name="function">
<p>A JavaScript function block to run against the messages being received by the node.</p>
<p>A JavaScript function to run against the messages being received by the node.</p>
<p>The messages are passed in as a JavaScript object called <code>msg</code>.</p>
<p>By convention it will have a <code>msg.payload</code> property containing
the body of the message.</p>
<p>The function is expected to return a message object (or multiple message objects), but can choose
to return nothing in order to halt a flow.</p>
<p>The <b>Setup</b> tab contains code that will be run whenever the node is started.
The <b>Close</b> tab contains code that will be run when the node is stopped.</p>
<h3>Details</h3>
<p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
for more information on writing functions.</p>

View File

@@ -40,6 +40,8 @@
progress will be cleared and no message triggered.</p>
<p>The node can be configured to resend a message at a regular interval until it
is reset by a received message.</p>
<p>Optionally, the node can be configured to treat messages with <code>msg.topic</code> as if they
are separate streams.</p>
<p>Optionally, the node can be configured to treat messages as if they are separate streams,
using a msg property to identify each stream. Default <code>msg.topic</code>.</p>
<p>The status indicates the node is currently active. If multiple streams are used the status
indicates the number of streams being held.</p>
</script>

View File

@@ -37,6 +37,7 @@
"stopped": "stopped",
"failed": "Inject failed: __error__",
"label": {
"properties": "Properties",
"repeat": "Repeat",
"flow": "flow context",
"global": "global context",
@@ -51,7 +52,7 @@
"string": "string",
"boolean": "boolean",
"number": "number",
"Array": "Array",
"Array": "array",
"invalid": "Invalid JSON Object"
},
"timestamp": "timestamp",
@@ -79,11 +80,11 @@
"on": "on",
"onstart": "Inject once after",
"onceDelay": "seconds, then",
"tip": "<b>Note:</b> \"interval between times\" and \"at a specific time\" will use cron.<br/>\"interval\" should be 596 hours or less.<br/>See info box for details.",
"success": "Successfully injected: __label__",
"errors": {
"failed": "inject failed, see log for details",
"toolong": "Interval too large"
"toolong": "Interval too large",
"invalid-expr": "Invalid JSONata expression: __error__"
}
},
"catch": {
@@ -117,10 +118,12 @@
},
"debug": {
"output": "Output",
"status": "status",
"none": "None",
"invalid-exp": "Invalid JSONata expression: __error__",
"msgprop": "message property",
"msgobj": "complete msg object",
"autostatus": "automatic",
"to": "To",
"debtab": "debug tab",
"tabcon": "debug tab and console",
@@ -207,8 +210,14 @@
"function": "",
"label": {
"function": "Function",
"initialize": "Setup",
"finalize": "Close",
"outputs": "Outputs"
},
"text": {
"initialize": "// Code added here will be run once\n// whenever the node is deployed.\n",
"finalize": "// Code added here will be run when the\n// node is being stopped or re-deployed.\n"
},
"error": {
"inputListener":"Cannot add listener to 'input' event within Function",
"non-message-returned":"Function tried to send a message of type __type__"
@@ -302,7 +311,7 @@
"wait-for": "wait for",
"wait-loop": "resend it every",
"for": "Handling",
"bytopics": "each msg.topic independently",
"bytopics": "each",
"alltopics": "all messages",
"duration": {
"ms": "Milliseconds",
@@ -311,6 +320,7 @@
"h": "Hours"
},
"extend": " extend delay if new message arrives",
"second": " send second message to separate output",
"label": {
"trigger": "trigger",
"trigger-block": "trigger & block",
@@ -455,7 +465,7 @@
"message": "entire message",
"tip": {
"path1": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The listener can be configured to send or receive the entire message object as a JSON formatted string.",
"path2": "This path will be relative to ",
"path2": "This path will be relative to <code>__path__</code>.",
"url1": "URL should use ws:&#47;&#47; or wss:&#47;&#47; scheme and point to an existing websocket listener.",
"url2": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The client can be configured to send or receive the entire message object as a JSON formatted string."
},
@@ -698,7 +708,9 @@
"output": "Output",
"includerow": "include column name row",
"newline": "Newline",
"usestrings": "parse numerical values"
"usestrings": "parse numerical values",
"include_empty_strings": "include empty strings",
"include_null_values": "include null values"
},
"placeholder": {
"columns": "comma-separated column names"
@@ -721,9 +733,15 @@
"mac": "Mac (\\r)",
"windows": "Windows (\\r\\n)"
},
"hdrout": {
"none": "never send column headers",
"all": "always send column headers",
"once": "send headers once, until msg.reset"
},
"errors": {
"csv_js": "This node only handles CSV strings or js objects.",
"obj_csv": "No columns template specified for object -> CSV."
"obj_csv": "No columns template specified for object -> CSV.",
"bad_csv": "Malformed CSV data - output probably corrupt."
}
},
"html": {
@@ -894,7 +912,8 @@
"fixup": "Fix-up exp"
},
"errors": {
"invalid-expr": "Invalid JSONata expression: __error__"
"invalid-expr": "Invalid JSONata expression: __error__",
"invalid-type": "Cannot join __error__ to buffer"
}
},
"sort" : {

View File

@@ -41,5 +41,5 @@
wait a fixed timeout from first reply and then return, sit and wait for data, or send then close the connection
immediately, without waiting for a reply.</p>
<p>The response will be output in <code>msg.payload</code> as a buffer, so you may want to .toString() it.</p>
<p>If you leave tcp host or port blank they must be set by using the <code>msg.host</code> and <code>msg.port</code> properties.</p>
<p>If you leave tcp host or port blank they must be set by using the <code>msg.host</code> and <code>msg.port</code> properties in every message sent to the node.</p>
</script>

View File

@@ -38,8 +38,13 @@
<p>The column template can contain an ordered list of column names. When converting CSV to an object, the column names
will be used as the property names. Alternatively, the column names can be taken from the first row of the CSV.</p>
<p>When converting to CSV, the column template is used to identify which properties to extract from the object and in what order.</p>
<p>If the template is blank then the node can use a simple comma separated list of properties supplied in <code>msg.columns</code> to
determine what to extract. If that is not present then all the object properties are ouput in the order in which they are found.</p>
<p>If the input is an array then the columns template is only used to optionally generate a row of column titles.</p>
<p>The node can accept a multi-part input as long as the <code>parts</code> property is set correctly.</p>
<p>If 'parse numerical values' option is checked, string numerical values will be returned as numbers, ie. middle value '1,"1.5",2'.</p>
<p>If 'include empty strings' option is checked, empty strings will be returned in result, ie. middle value '"1","",3'.</p>
<p>If 'include null values' option is checked, null values will be returned in result, ie. middle value '"1",,3'.</p>
<p>The node can accept a multi-part input as long as the <code>parts</code> property is set correctly, for example from a file-in node or split node.</p>
<p>If outputting multiple messages they will have their <code>parts</code> property set and form a complete message sequence.</p>
<p><b>Note:</b> the column template must be comma separated - even if a different separator is chosen for the data.</p>
</script>

View File

@@ -20,6 +20,10 @@
<dl class="message-properties">
<dt>payload<span class="property-type">object | string</span></dt>
<dd>A JavaScript object or XML string.</dd>
<dt class="optional">options <span class="property-type">object</span></dt>
<dd>This optional property can be used to pass in any of the options supported by the underlying
library used to convert to and from XML. See <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a>
for more information.</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
@@ -30,10 +34,6 @@
<li>If the input is a JavaScript object it tries to build an XML string.</li>
</ul>
</dd>
<dt class="optional">options <span class="property-type">object</span></dt>
<dd>This optional property can be used to pass in any of the options supported by the underlying
library used to convert to and from XML. See <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a>
for more information.</dd>
</dl>
<h3>Details</h3>
<p>When converting between XML and an object, any XML attributes are added as a property named <code>$</code> by default.

View File

@@ -91,7 +91,8 @@
</ul>
</dd>
<dt class="optional">complete</dt>
<dd>If set, the node will send its output message in its current state.</dd>
<dd>If set, the node will append the payload, and then send the output message in its current state.
If you don't wish to append the payload, delete it from the msg.</dd>
</dl>
<h3>Details</h3>

View File

@@ -39,4 +39,5 @@
<p>This node will buffer messages internally in order to work across sequences. The
runtime setting <code>nodeMessageBufferMaxLength</code> can be used to limit how many messages nodes
will buffer.</p>
<p>If a message is received with the <b>msg.reset</b> property set, the buffered messages are deleted and not sent.</p>
</script>

View File

@@ -49,12 +49,6 @@
<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
@@ -65,11 +59,5 @@
<p>When split into multiple messages, each message will have a <code>parts</code>
property set, forming a complete message sequence.</p>
<p>Encoding of input data can be specified from list of encodings if output format is string.</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>

View File

@@ -15,10 +15,11 @@
-->
<script type="text/html" data-help-name="function">
<p>受信メッセージに対して処理を行うJavaScriptコード(関数の本体)定義しま</p>
<p>受信メッセージに対して処理を行うJavaScriptコード(関数の本体)<b>Function</b></p>
<p>入力メッセージは<code>msg</code>JavaScript</p>
<p><code>msg</code><code>msg.payload</code></p>
<p>通常コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します後続フローの実行を停止したい場合はオブジェクトを返却しなくてもかまいません</p>
<p>Node-REDの開始時もしくはフローの設定をデプロイした際実行される初期化コードを<b>初期化処理</b><b></b></p>
<h3>詳細</h3>
<p>コードの書き方の詳細については<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a></p>
<h4>メッセージの送信</h4>

33
packages/node_modules/@node-red/nodes/locales/ja/messages.json vendored Executable file → Normal file
View File

@@ -37,6 +37,7 @@
"stopped": "stopped",
"failed": "inject失敗: __error__",
"label": {
"properties": "プロパティ",
"repeat": "繰り返し",
"flow": "フローコンテクスト",
"global": "グローバルコンテクスト",
@@ -79,11 +80,11 @@
"on": "曜日",
"onstart": "Node-RED起動の",
"onceDelay": "秒後、以下を行う",
"tip": "<b>注釈:</b> 「指定した時間間隔、日時」と「指定した日時」はcronを使用します。<br/>「時間間隔」には596時間より小さな値を指定します。<br/>詳細はノードの「情報」を確認してください。",
"success": "inject処理を実行しました: __label__",
"errors": {
"failed": "inject処理が失敗しました。詳細はログを確認してください。",
"toolong": "時間間隔が大き過ぎます"
"toolong": "時間間隔が大き過ぎます",
"invalid-expr": "JSONata式が不正: __error__"
}
},
"catch": {
@@ -207,8 +208,14 @@
"function": "",
"label": {
"function": "コード",
"initialize": "初期化処理",
"finalize": "終了処理",
"outputs": "出力数"
},
"text": {
"initialize": "// ここのコードはノードのデプロイ時に一度実行されます。\n",
"finalize": "// ここのコードはノードの停止もしくは再デプロイ時に実行されます。\n"
},
"error": {
"inputListener": "コード内で'input'イベントのリスナを設定できません",
"non-message-returned": "Functionードが __type__ 型のメッセージ送信を試みました"
@@ -302,7 +309,7 @@
"wait-for": "指定した時間待機",
"wait-loop": "指定した時間間隔毎に送信を繰り返す",
"for": "処理対象",
"bytopics": "msg.topic毎",
"bytopics": "毎",
"alltopics": "全メッセージ",
"duration": {
"ms": "ミリ秒",
@@ -310,7 +317,8 @@
"m": "分",
"h": "時間"
},
"extend": " 新たなメッセージを受け取った時に遅延を延長",
"extend": "新たなメッセージを受け取った時に遅延を延長",
"second": "2つ目の出力端子に2番目のメッセージを送信",
"label": {
"trigger": "trigger",
"trigger-block": "trigger & block",
@@ -455,7 +463,7 @@
"message": "メッセージ全体を送信/受信",
"tip": {
"path1": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。",
"path2": "This path will be relative to ",
"path2": "このパスは <code>__path__</code> の相対パスになります。",
"url1": "URLには ws:&#47;&#47; または wss:&#47;&#47; スキーマを使用して、存在するwebsocketリスナを設定してください。",
"url2": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。"
},
@@ -696,7 +704,9 @@
"output": "出力",
"includerow": "1行目を列名とする",
"newline": "改行コード",
"usestrings": "数値を変換する"
"usestrings": "数値を変換する",
"include_empty_strings": "空の文字を含む",
"include_null_values": "null値を含む"
},
"placeholder": {
"columns": "コンマ区切りで列名を入力"
@@ -719,9 +729,15 @@
"mac": "Mac (\\r)",
"windows": "Windows (\\r\\n)"
},
"hdrout": {
"none": "カラムヘッダを送信しない",
"all": "カラムヘッダを常に送信する",
"once": "ヘッダを一度だけ送信する(msg.resetの受け付けると再送)"
},
"errors": {
"csv_js": "本ードが処理できる形式は、CSV文字列またはJSONのみです",
"obj_csv": "オブジェクトをCSVへ変換する際の列名が設定されていません"
"obj_csv": "オブジェクトをCSVへ変換する際の列名が設定されていません",
"bad_csv": "不正なCSVデータ - 出力の修正を試みました"
}
},
"html": {
@@ -892,7 +908,8 @@
"fixup": "最終調整式"
},
"errors": {
"invalid-expr": "JSONata式が不正: __error__"
"invalid-expr": "JSONata式が不正: __error__",
"invalid-type": "__error__ をバッファに連結できません"
}
},
"sort": {

View File

@@ -26,8 +26,7 @@
<dt>payload<span class="property-type">オブジェクト | 配列 | 文字列</span></dt>
<dd>
<ul>
<li>入力が文字列の場合CSVとして解釈しCSVの各行をキー/バリューとしたJavaScriptオブジェクトを生成します
各行毎にメッセージを送信するかオブジェクトの配列からなる一つのメッセージを送信するかを選択できます</li>
<li>入力が文字列の場合CSVとして解釈しCSVの各行をキー/バリューとしたJavaScriptオブジェクトを生成します各行毎にメッセージを送信するかオブジェクトの配列からなる一つのメッセージを送信するかを選択できます</li>
<li>入力がJavaScriptオブジェクトの場合CSV文字列への変換を行います</li>
<li>入力が基本型の配列の場合1行のCSV文字列へ変換します</li>
<li>入力が配列の配列もしくはオブジェクトの配列の場合複数行のCSV文字列へ変換します</li>
@@ -37,8 +36,12 @@
<h3>詳細</h3>
<p>列名にカラム名のリストを指定することができますCSVからオブジェクトに変換を行う際カラム名をプロパティ名として使用します列名の代わりにCSVデータの1行目にカラム名を含めることもできます</p>
<p>CSVへの変換を行う際にはオブジェクトから取り出すべきプロパティとその順序を列名を参照して決めます</p>
<p>列名がない場合本ノードは<code>msg.columns</code>使</p>
<p>入力が配列の場合には列名はカラム名を表す行の出力指定がされた場合だけ用います</p>
<p><code>parts</code></p>
<p>数値を変換するオプションがチェックされている場合文字列型の数値が数値として返されますつまり1,"1.5",2の真ん中の値が数値になりま</p>
<p>空の文字を含むオプションがチェックされている場合空の文字列が結果に返されますつまり"1","",3の真ん中の値が空の文字列になります</p>
<p>null値を含むオプションがチェックされている場合null値が結果に返されますつまり"1",,3の真ん中の値がnullになります</p>
<p>file-inードやsplitードが出力するメッセージの様に<code>parts</code></p>
<p>CSVを複数のメッセージに変換して出力する場合出力がメッセージ列となるよう<code>parts</code></p>
<p><b>:</b> </p>
</script>

View File

@@ -20,6 +20,8 @@
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>JavaScriptオブジェクトもしくはXML文字列</dd>
<dt class="optional">options <span class="property-type">オブジェクト</span></dt>
<dd>内部で用いているXMLへの変換ライブラリに対してオプションを渡すことができます詳しくは<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a></dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
@@ -30,8 +32,6 @@
<li>入力がJavaScriptオブジェクトの場合XML文字列に変換します</li>
</ul>
</dd>
<dt class="optional">options <span class="property-type">オブジェクト</span></dt>
<dd>内部で用いているXMLへの変換ライブラリに対してオプションを渡すことができます詳しくは<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a></dd>
</dl>
<h3>詳細</h3>
<p>XMLとオブジェクトの間での変換を行う場合デフォルトではXML属性は<code>$</code>

View File

@@ -79,7 +79,7 @@
</ul>
</dd>
<dt class="optional">complete</dt>
<dd>設定されている場合保持しているメッセージを結合して送信します</dd>
<dd>設定されている場合本ノードはペイロードを追加し保持しているメッセージを送信しますペイロードを追加したくない場合はmsgから削除してください</dd>
</dl>
<h3>詳細</h3>

View File

@@ -31,4 +31,6 @@
</dl>
<h4>メッセージの蓄積</h4>
<p>このノードの処理ではメッセージ列の処理のためメッセージを内部に蓄積します<b>settings.js</b><code>nodeMessageBufferMaxLength</code></p>
<p>メッセージが<b>msg.reset</b></p>
</script>

View File

@@ -44,8 +44,6 @@
<dd>ファイルの内容を文字列もしくはバッファで表現します</dd>
<dt class="optional">filename <span class="property-type">文字列</span></dt>
<dd>読み出し対象のファイル名をノードに設定していない場合このプロパティでファイルを指定します</dd>
<dt class="optional">error <span class="property-type">オブジェクト</span></dt>
<dd><i>非推奨</i>: <code>payload</code><code>error</code></dd>
</dl>
<h3>詳細</h3>
<p>ファイルネームは絶対パスでの指定を推奨します絶対パスを指定しない場合はNode-REDプロセスのワーキングディレクトリからの相対パスとして扱います</p>
@@ -53,7 +51,5 @@
<p>テキストファイルの場合行毎に分割して各々メッセージを送信することができますまたバイナリファイルの場合小さな塊のバッファに分割して送信できますバッファの分割単位はオペレーティングシステム依存ですが一般に64k(Linux/Mac)もしくは41k(Windows)です</p>
<p>複数のメッセージに分割する場合各メッセージには<code>parts</code></p>
<p>出力形式が文字列の場合入力データのエンコーディングをエンコーディングリストから選択できます</p>
<h4>旧式のエラー処理</h4>
<p>Node-RED 0.17より前の版ではファイルの読み込み時にエラーが発生すると<code>payload</code><code>error</code></p>
<p>エラーはcatchードで補足して処理することを推奨します</p>
</script>

View File

@@ -446,7 +446,7 @@
"message": "메세지 전체를 송신/수신",
"tip": {
"path1": "표준으로는 <code>payload</code> 가 websocket에서 송신, 수신된 데이터를 기다립니다. 클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다.",
"path2": "This path will be relative to ",
"path2": "This path will be relative to <code>__path__</code>.",
"url1": "URL에는 ws:&#47;&#47; 또는 wss:&#47;&#47; 스키마를 사용하여, 존재하는 websocket리스너를 설정해 주세요.",
"url2": "표준으로는 <code>payload</code> 가 websocket에서 송신,수신될 데이터를 기다립니다.클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다."
},

View File

@@ -20,6 +20,8 @@
<dl class="message-properties">
<dt>payload<span class="property-type">오브젝트 | 문자열</span></dt>
<dd>JavaScript오브젝트 혹은 XML문자열</dd>
<dt class="optional">options <span class="property-type">오브젝트</span></dt>
<dd>내부에서 사용중인 XML로의 변환 라이브러리에 대해 옵션을 전달할 있습니다. 자세한 사항은 <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a> .</dd>
</dl>
<h3>출력</h3>
<dl class="message-properties">
@@ -30,8 +32,6 @@
<li>입력이 JavaScript오브젝트인 경우, XML문자열로 변환합니다.</li>
</ul>
</dd>
<dt class="optional">options <span class="property-type">오브젝트</span></dt>
<dd>내부에서 사용중인 XML로의 변환 라이브러리에 대해 옵션을 전달할 있습니다. 자세한 사항은 <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a> .</dd>
</dl>
<h3>상세</h3>
<p>XML와 오브젝트의 사이에서의 변환을 수행할 경우, 기본값으로는 XML속성은 <code>$</code> .

View File

@@ -455,7 +455,7 @@
"message": "完整信息",
"tip": {
"path1": "默认情况下,<code>payload</code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.",
"path2": "这条路径将相对于 ",
"path2": "这条路径将相对于 <code>__path__</code>.",
"url1": "URL 应该使用ws:&#47;&#47;或者wss:&#47;&#47;方案并指向现有的websocket侦听器.",
"url2": "默认情况下,<code>payload</code> 将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象."
},
@@ -698,7 +698,7 @@
"output": "输出",
"includerow": "包含列名行",
"newline": "换行符",
"usestrings": "parse numerical values"
"usestrings": "解析数值"
},
"placeholder": {
"columns": "用逗号分割列名"
@@ -898,7 +898,7 @@
}
},
"sort" : {
"sort": "sort",
"sort": "排序",
"target" : "排序属性",
"seq" : "信息队列",
"key" : "键值",
@@ -907,9 +907,9 @@
"ascending" : "升序",
"descending" : "降序",
"as-number" : "作为数值",
"invalid-exp" : "sort节点中存在无效的JSONata表达式",
"too-many" : "sort节点中有太多待定信息",
"clear" : "清空sort节点中的待定信息"
"invalid-exp" : "排序节点中存在无效的JSONata表达式",
"too-many" : "排序节点中有太多待定信息",
"clear" : "清空排序节点中的待定信息"
},
"batch" : {
"batch": "batch",

View File

@@ -20,6 +20,8 @@
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串</span></dt>
<dd>JavaScript对象或XML字符串</dd>
<dt class="optional">options <span class="property-type">object</span></dt>
<dd>可以将选项传递给内部使用的XML转换库请参见<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank"> xml2js文档</a> </dd>
</dl>
<h3>输出</h3>
<dl class="message-properties">
@@ -30,8 +32,6 @@
<li>如果输入是JavaScript对象它将尝试构建XML字符串</li>
</ul>
</dd>
<dt class="optional">options <span class="property-type">object</span></dt>
<dd>可以将选项传递给内部使用的XML转换库请参见<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank"> xml2js文档</a> </dd>
</dl>
<h3>详细</h3>
<p>在XML和对象之间进行转换时默认情况下XML属性会添加到名为<code>$</code><code>_</code></p>

View File

@@ -14,7 +14,7 @@
limitations under the License.
-->
<script type="text/x-red" data-help-name="file">
<script type="text/html" data-help-name="file">
<p><code>msg.payload</code></p>
<h3>输入</h3>
<dl class="message-properties">
@@ -31,7 +31,7 @@
<p>您可以将此节点配置为删除文件</p>
</script>
<script type="text/x-red" data-help-name="file in">
<script type="text/html" data-help-name="file in">
<p>以字符串或二进制缓冲区的形式读取文件的内容</p>
<h3>输入</h3>
<dl class="message-properties">
@@ -44,8 +44,6 @@
<dd>文件的内容可以是字符串也可以是二进制的buffer</dd>
<dt class="optional">filename <span class="property-type">字符串</span></dt>
<dd>如果未在节点配置中设置该属性可以选择要读取的文件名</dd>
<dt class="optional">error <span class="property-type">object</span></dt>
<dd><i>已不推荐使用</i>: <code></code><code>error</code> </dd>
</dl>
<h3>详细</h3>
<p>文件名应该是绝对路径否则将相对于Node-RED进程的工作目录</p>
@@ -53,7 +51,5 @@
<p>可以选择将文本文件拆分为几行每行输出一条消息或者将二进制文件拆分为较小的buffer块-块大小取决于操作系统但通常为64kLinux/Mac或41kWindows</p>
<p>当拆分为多条消息时每条消息将具有<code>parts</code></p>
<p>如果输出格式为字符串则可以从编码列表中指定输入数据的编码</p>
<h4>旧版的错误处理</h4>
<p>在Node-RED 0.17之前如果此节点在读取文件时遇到错误它将发送一条不包含<code>msg.payload</code><code>msg.error</code><code>msg.error</code></p>
<p>应该使用Catch节点来捕获并处理错误</p>
</script>

View File

@@ -0,0 +1,35 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="inject">
<p>手動或定期得將消息注入流程中消息的有效荷載可以為多種類型包括字符串JavaScript對象或當前時間</p>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">various</span></dt>
<dd>指定的消息的有效荷載</dd>
<dt class="optional">topic <span class="property-type">字符串</span></dt>
<dd>可以在節點中配置的可選屬性</dd>
</dl>
<h3>詳細</h3>
<p>通過使用特定的有效荷載注入節點可以啟動流程默認有效荷載是當前時間的時間戳以毫秒為單位自1970年1月1日起</p>
<p>該節點還支持注入字符串數字布林值JavaScript對象或流程/全局上下文值</p>
<p>默認情況下節點可以通過在編輯器中單擊節點按鈕來手動觸發同時也可以被設置為定期或按計劃注入</p>
<p>另一個可選的設置是在每次啟動流程時注入一次</p>
<p>可以指定的最大<i>間隔</i>596/24 使scheduler</p>
<p><b>注意</b>:選項<i>“時間間隔” </i><i>特定時間 </i>使用了標準cron系統。這意味著因此“20分鐘”並不表示在此之後20分鐘而是每小時的20分鐘40分鐘。如果您希望設定為從現在開始的每20分鐘那麽請使用<i>“間隔” </i>選項</p>
<p><b>注意</b>: 使</p>
</script>

View File

@@ -0,0 +1,25 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="debug">
<p>調試側邊欄選項卡和運行時日志中顯示選定的消息屬性 默認情況下它會顯示<code>msg.payload</code>JSONata</p>
<h3>詳細</h3>
<p>調試側邊欄會提供已發消息的結構化視圖方便您查詢消息的結構</p>
<p>JavaScript對象和數組可以根據需要來折疊或擴展緩衝區對象可以顯示爲原始數據也可以顯示爲字符串</p>
<p>對任意條消息調試側邊欄還會顯示接收消息的時間發送消息的節點以及消息類型等信息單擊源節點ID將在工作區中顯示該節點</p>
<p>節點上的按鈕可用于啓用或禁用其輸出建議禁用或刪除所有未使用的調試節點</p>
<p>還可以通過配置節點將所有消息發送到運行時的日志或將簡短的數據32個字符內在調試節點下的狀態文本上顯示</p>
</script>

View File

@@ -0,0 +1,24 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="complete">
<p>當另一個節點完成對消息的處理時觸發流程</p>
<h3>詳細</h3>
<p>如果一個節點通知運行時它已完成消息的處理該節點可用于觸發第二個流程</p>
<p>這個節點可以與沒有輸出端口的節點一起使用例如在使用電子郵件發送節點來發送郵件後觸發一個流程</p>
<p>此節點只能被設置爲處理流程中某個所選節點的事件與Catch節點不同您不能指定所有節點模式並以流程中的所有節點爲目標</p>
<p>並非所有節點都會觸發此事件這取決于它們是否支持于Node-RED 1.0中引入的此功能</p>
</script>

View File

@@ -0,0 +1,36 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="catch">
<p>捕獲由同一標簽頁上的節點引發的錯誤</p>
<h3>輸出</h3>
<dl class="message-properties">
<dt>error.message <span class="property-type">字符串</span></dt>
<dd>錯誤消息</dd>
<dt>error.source.id <span class="property-type">字符串</span></dt>
<dd>引發錯誤的節點的ID</dd>
<dt>error.source.type <span class="property-type">字符串</span></dt>
<dd>引發錯誤的節點的類型</dd>
<dt>error.source.name <span class="property-type">字符串</span></dt>
<dd>引發錯誤的節點的名稱如果已設置</dd>
</dl>
<h3>詳細</h3>
<p>如果節點在處理消息時抛出錯誤則流程通常會停止該節點可用于捕獲那些錯誤並通過專用流程進行處理</p>
<p>默認情況下該節點將捕獲同一標簽頁上任何節點抛出的錯誤或者它可以針對特定節點或配置爲僅捕獲另一個目標捕獲節點尚未捕獲的錯誤</p>
<p>當錯誤發生時所有匹配的catch節點都會收到錯誤消息</p>
<p>如果在子流程中發送了錯誤則該錯誤將由子流程中的任意捕獲節點處理如果子流程中不存在捕獲節點則那錯誤將被傳播到子流程實例所在的標簽頁</p>
<p>如果消息已經具有<code>error</code><code>error</code><code>_error</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="status">
<p>獲取在同一標簽頁上的其他節點的狀態消息</p>
<h3>輸出</h3>
<dl class="message-properties">
<dt>status.text <span class="property-type">字符串</span></dt>
<dd>狀態文本</dd>
<dt>status.source.type <span class="property-type">字符串</span></dt>
<dd>報告狀態的節點的類型</dd>
<dt>status.source.id <span class="property-type">字符串</span></dt>
<dd>報告狀態的節點的ID</dd>
<dt>status.source.name <span class="property-type">字符串</span></dt>
<dd>報告狀態的節點的名稱如果已設置</dd>
</dl>
<h3>詳細</h3>
<p>該節點不包含<code>有效荷載</code></p>
<p>默認情況下節點會獲取同一工作空間標簽頁上報告所有節點的狀態可以通過配置來設定目標節點</p>
</script>

View File

@@ -0,0 +1,31 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="link in">
<p>在流程之間創建虛擬連線</p>
<h3>詳細</h3>
<p>該節點可以連接到任何標簽頁上存在的任何<code>link out</code></p>
<p>僅當選擇鏈接節點時才會顯示鏈接節點之間的鏈接如果有指向另一個選項卡的鏈接則顯示一個虛擬節點單擊該虛擬節點將帶您到相應的選項卡</p>
<p><b>注意</b></p>
</script>
<script type="text/x-red" data-help-name="link out">
<p>在流程之間創建虛擬連線</p>
<h3>詳細</h3>
<p>該節點可以連接到任何標簽頁上存在的任何<code>link in</code></p>
<p>僅當選擇鏈接節點時才會顯示鏈接節點之間的鏈接如果有指向另一個選項卡的鏈接則顯示一個虛擬節點單擊該虛擬節點將帶您到相應的選項卡</p>
<p><b>注意</b></p>
</script>

View File

@@ -0,0 +1,21 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="comment">
<p>可用于向流程添加注釋的節點</p>
<h3>詳細</h3>
<p>編輯面板接受Markdown語法輸入的文本將在信息側面板中顯示</p>
</script>

View File

@@ -0,0 +1,24 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="unknown">
<p>您安裝的Node-RED無法識別該節點的類型</p>
<h3>詳細</h3>
<p><i>如果在此狀態下部署節點其配置會被保存但是在安裝缺少的類型之前流程不會開始</i></p>
<p>使用<code> Menu-Manage Palette </code>使<b>npm install &lt;module&gt;</b>Node-Red</p>
<p>另一種可能是您已經安裝了此節點類型但是缺少必須的依賴項您應檢查Node-RED的啓動日志中是否有與缺少節點有關的錯誤消息</p>
<p>以上方法都不適用時您可以聯系該流程的作者以獲取缺少的節點類型的副本</p>
</script>

View File

@@ -0,0 +1,51 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="function">
<p>定義對接收到的消息進行處理的JavaScript代碼函數的主體</p>
<p>輸入消息在名爲<code>msg</code>JavaScript</p>
<p>通常<code>msg</code><code>msg.payload</code></p>
<p>該函數一般會返回一個消息對象或多個消息對象但也可以爲了停止流程而什麽都不返回</p>
<h3>詳細</h3>
<p>請參見<a target="_blank" href="http://nodered.org/docs/writing-functions.html">在線文檔</a></p>
<h4>傳送消息</h4>
<p>要將消息傳遞到流程中的下一個節點請返回消息或調用<code>node.send(messages)</code></p>
<p>它將返回/send:</p>
<ul>
<li>單個消息對象 - 傳遞給連接到第一個輸出的節點</li>
<li>消息對象數組傳遞給連接到相應輸出的節點</li>
</ul>
<p>如果數組元素是數組則將多個消息發送到相應的輸出</p>
<p>無論return方法是單個值還是數組元素如果返回值爲null則不會發送任何消息</p>
<h4>日志輸出和錯誤處理</h4>
<p>使用以下功能輸出日志信息和輸出錯誤</p>
<ul>
<li><code>node.log("Log message")</code></li>
<li><code>node.warn("Warning")</code></li>
<li><code>node.error("Error")</code></li>
</ul>
</p>
<p>使用catch節點可以進行錯誤處理 要由catch節點處理請將<code>msg</code><code>node.error</code></p>
<pre>node.error("Error",msg);</pre>
<h4>訪問節點信息</h4>
<p>您可以使用以下屬性來在代碼中引用節點ID和名稱</p>
<ul>
<li><code>node.id</code> - ID</li>
<li><code>node.name</code> - </li>
</ul>
<h4>使用環境變量</h4>
<p>環境變量可以通過<code>env.get("MY_ENV_VAR")</code></p>
</script>

View File

@@ -0,0 +1,37 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="switch">
<p>按屬性值來分配消息的傳送路線</p>
<h3>詳細</h3>
<p>根據接收到的消息評估指定的規則然後將消息發送到與匹配的規則相對應的輸出端口</p>
<p>可以將節點設置爲一旦發現一個匹配的規則則停止後續的匹配</p>
<p>對于評估規則可以使用消息屬性流程上下文/全局上下文屬性環境變量和JSONata表達式的評估結果</p>
<h4>規則</h4>
<p>有四種規則</p>
<ol>
<li><b></b></li>
<li><b>順序</b></li>
<li><b>JSONata表達式</b></li>
<li><b>其他</b></li>
</ol>
<h4>注釋</h4>
<p><code>is true/false</code><code>is null</code> </p>
<p><code>is empty</code><code>null</code><code>undefined</code></p>
<h4>處理消息序列</h4>
<p>默認情況下節點不會修改<code>msg.parts</code></p>
<p>可以啓用<b>重建消息序列</b><code>nodeMessageBufferMaxLength</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="change">
<p>設置更改刪除或移動消息流程上下文或全局上下文的屬性</p>
<p>如果指定了多個規則則將按定義的順序來應用它們</p>
<h3>詳細</h3>
<p>可用的操作有</p>
<dl class="message-properties">
<dt>設置</dt>
<dd>設置一個屬性該值可以是多種不同類型也可以從現有消息或上下文屬性中獲取</dd>
<dt>置換</dt>
<dd>搜索並替換屬性 如果啓用了正則表達式則可以爲replace with屬性指定捕獲組例如<code>$1</code> </dd>
<dt>刪除</dt>
<dd>刪除一個屬性</dd>
<dt>移動</dt>
<dd>移動或者重命名一個屬性</dd>
</dl>
<p>類型"expression"使用<a href="http://jsonata.org/" target="_new">JSONata</a></p>
</script>

View File

@@ -0,0 +1,40 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="range">
<p>將數值映射爲另一個區間的數值</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">數值</span></dt>
<dd>有效荷載<i>一定</i>. </dd>
</dl>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">數值</span></dt>
<dd>被映射到新區間的數值</dd>
</dl>
<h3>詳細</h3>
<p>該節點將線性縮放所接收到的數值在默認情況下結果不限于節點中定義的範圍</p>
<p><i>縮放並限制到目標範圍</i></p>
<p><i>在目標範圍內縮放並折疊</i></p>
<p>例如輸入0-10映射到0-100</p>
<table style="outline-width:#888 solid thin">
<tr><th width="80px">模式</th><th width="80px"></th><th width="80px"></th></tr>
<tr><td><center>scale</center></td><td><center>12</center></td><td><center>120</center></td></tr>
<tr><td><center>limit</center></td><td><center>12</center></td><td><center>100</center></td></tr>
<tr><td><center>wrap</center></td><td><center>12</center></td><td><center>20</center></td></tr>
</table>
</script>

View File

@@ -0,0 +1,46 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="template">
<p>根據提供的模板設置屬性</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">object</span></dt>
<dd>一個msg對象其中包含著用于填充模板的信息</dd>
<dt class="optional">template <span class="property-type">string</span></dt>
<dd><code>msg.payload</code>msg</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">object</span></dt>
<dd>由來自傳入msg的屬性來填充已配置的模板後輸出的帶有屬性的msg</dd>
</dl>
<h3>詳細</h3>
<p>默認情況下使用<i><a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache</a></i>格式如有需要也可以切換其他格式</p>
<p>例如:
<pre>Hello {{payload.name}}. Today is {{date}}</pre>
<p>receives a message containing:
<pre>{
date: "Monday",
payload: {
name: "Fred"
}
}</pre>
<p>輸出的消息將會是:
<pre>Hello Fred. Today is Monday</pre>
<p>也可以使用流程上下文或全局上下文中的屬性<code>{{flow.name}}</code><code>{{global.name}}</code><code>store</code>使<code>{{flow[store].name}}</code><code>{{global[store].name}}</code>
<p><b>注意</b>默認情況下,<i>mustache</i>將在其替換的值中轉義任何非字母數字或HTML實體爲了防止這種情況請使用<code>{{{triple}}}</code>
</script>

View File

@@ -0,0 +1,32 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="delay">
<p>對通過節點的消息進行延遲發送或限制</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">數值</span></dt>
<dd>設置要應用于消息的延遲以毫秒爲單位僅當節點配置爲允許消息去覆蓋配置的默認延遲間隔時此選項才適用</dd>
<dt class="optional">reset</dt>
<dd>如果接收到的消息將此屬性設置爲任何值則將清空該節點保留的所有的未發送消息</dd>
<dt class="optional">flush</dt>
<dd>如果接收到的消息的此屬性設置爲任何值則將立即發送該節點保留的所有未發送消息</dd>
</dl>
<h3>詳細</h3>
<p>當配置爲延遲發送消息時延遲間隔可以是一個固定值一個範圍內的隨機值或爲每個消息動態設置</p>
<p>當配置爲對消息進行限制時它們的傳遞將分散在配置的時間段內狀態顯示隊列中當前的消息數可以選擇在中間消息到達時丟棄它們</p>
<p>速率限制可以應用于所有消息也可以根據<code>msg.topic</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="trigger">
<p>触发后将会发送一条消息如果被拓展或重置则可以选择发送第二条消息</p>
<h3>输入</h3>
<dl class="message-properties">
<dt class="optional">reset</dt>
<dd>如果收到带有此属性的消息则将清除当前正在进行的任何超时或重复且不会触发任何消息</dd>
</dl>
<h3>详细</h3>
<p>该节点可用于在流程中创建一个超时 默认情况下当它收到一条消息时它将发送一条带有<code>1</code>250<code>0</code>使Raspberry Pi GPIOLED</p>
<p>可以将发送的每个消息的有效荷载配置为各种值包括不发送任何内容的选项例如将初始消息设置为<i>nothing</i></p>
<p>如果设置为<i>字符串</i>类型,则该节点支持<i>mustache</i>模板语法</p>
<p>如果节点收到具有<code>reset</code><code></code></p>
<p>可以将节点配置为以固定的时间间隔重新发送消息直到被收到的消息重置为止</p>
<p>可选可以将节点配置为将带有<code>msg.topic</code></p>
</script>

View File

@@ -0,0 +1,74 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="exec">
<p>運行系統命令並返回其輸出</p>
<p>可以將節點配置爲等待命令完成或者在命令生成時發送其輸出</p>
<p>運行的命令可以在節點中配置也可以由收到的消息提供</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt class="optional">payload <span class="property-type">字符串</span></dt>
<dd>如果這樣配置則將被附加到執行命令中</dd>
<dt class="optional">kill <span class="property-type">字符串</span></dt>
<dd>指定發送到現有的exec節點進程的kill信號類型</dd>
<dt class="optional">pid <span class="property-type">數值|字符串</span></dt>
<dd>要殺死的現有exec節點進程的進程ID</dd>
</dl>
<h3>輸出</h3>
<ol class="node-ports">
<li>標准輸出(stdout)
<dl class="message-properties">
<dt>payload <span class="property-type">字符串</span></dt>
<dd>命令的標准輸出</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">object</span></dt>
<dd>僅執行模式一個返回代碼對象的副本在端口3上也可用</dd>
</dl>
</li>
<li>標准error輸出(stderr)
<dl class="message-properties">
<dt>payload <span class="property-type">字符串</span></dt>
<dd>命令的標准錯誤輸出</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">object</span></dt>
<dd>僅執行模式一個返回代碼對象的副本在端口3上也可用</dd>
</dl>
</li>
<li>返回代碼
<dl class="message-properties">
<dt>payload <span class="property-type">object</span></dt>
<dd>一個包含返回代碼以及<code>message</code><code>signal</code></dd>
</dl>
</li>
</ol>
<h3>詳細</h3>
<p>默認情況下使用<code>exec</code>調調<code>{code0}</code></p>
<p>可選可以選擇使用<code>spawn</code>stdoutstderr<code>{code0}</code></p>
<p>錯誤可能會在第三個端口<code>msg.payload</code><code>message</code><code>signal</code></p>
<p>運行的命令是在節點內定義的帶有附加<code>msg.payload</code></p>
<p>帶空格的命令或參數應該用引號引起來<code>這是一個參數</code></p>
<p>返回的<code>有效荷載</code>通常是<i>字符串</i>類型除非檢測到非UTF8字符在這種情況下它會是<i>buffer</i></p>
<p>節點處于活動狀態時該節點的狀態圖標和PID將可見對此更改可以通過<code>Status</code></p>
<h4>殺死進程</h4>
<p>發送<code>msg.kill</code><code>msg.kill</code><code>SIGINT</code><code>SIGQUIT</code><code>SIGHUP</code><code>SIGTERM</code></p>
<p>如果節點有多個進程在運行則還必須設置<code>msg.pid</code>PID</p>
<p>如果<code>超時</code></p>
<p>提示如果運行Python應用程序則可能需要使用<code>-u</code></p>
</script>

View File

@@ -6,7 +6,9 @@
"name": "名稱",
"username": "使用者名稱",
"password": "密碼",
"property": "屬性"
"property": "屬性",
"selectNodes": "選擇節點...",
"expand": "擴展"
},
"status": {
"connected": "已連接",
@@ -35,7 +37,22 @@
"stopped": "停止",
"failed": "注入失敗: __error__",
"label": {
"repeat": "重複"
"repeat": "重複",
"flow": "流上下午",
"global": "全局上下文",
"str": "字符串",
"num": "數值",
"bool": "布爾值",
"json": "JSON對象",
"bin": "buffer",
"date": "時間戳",
"env": "環境變量",
"object": "對象",
"string": "字符串",
"boolean": "布爾值",
"number": "數值",
"Array": "數組",
"invalid": "無效的JSON對象"
},
"timestamp": "時間戳記",
"none": "無",
@@ -72,13 +89,11 @@
"catch": {
"catch": "監測所有節點",
"catchNodes": "監測__number__個節點",
"catchUncaught": "捕獲:未捕獲",
"label": {
"source": "監測範圍",
"node": "節點",
"type": "類型",
"selectAll": "全選",
"sortByLabel": "按名稱排序",
"sortByType": "按類型排序"
"uncaught": "忽略其他捕獲節點處理的錯誤"
},
"scope": {
"all": "所有節點",
@@ -90,10 +105,6 @@
"statusNodes": "報告__number__個節點狀態",
"label": {
"source": "報告狀態範圍",
"node": "節點",
"type": "類型",
"selectAll": "全選",
"sortByLabel": "按名稱排序",
"sortByType": "按類型排序"
},
"scope": {
@@ -101,8 +112,13 @@
"selected": "指定節點"
}
},
"complete": {
"completeNodes": "完成: __number__個節點"
},
"debug": {
"output": "輸出",
"none": "None",
"invalid-exp": "無效的JSONata表達式: __error__",
"msgprop": "資訊屬性",
"msgobj": "完整資訊",
"to": "目標",
@@ -124,7 +140,11 @@
"filterCurrent": "當前流程",
"debugNodes": "除錯節點",
"clearLog": "清空日誌",
"openWindow": "在新視窗打開"
"filterLog": "過濾日誌",
"openWindow": "在新視窗打開",
"copyPath": "復制路徑",
"copyPayload": "復制值",
"pinPath": "固定展開"
},
"messageMenu": {
"collapseAll": "折疊所有路徑",
@@ -146,26 +166,33 @@
"key": "私密金鑰",
"passphrase": "密碼",
"ca": "CA證書",
"verify-server-cert":"驗證伺服器憑證"
"verify-server-cert": "驗證伺服器憑證",
"servername": "服務器名"
},
"placeholder": {
"cert":"憑證路徑 (PEM 格式)",
"key":"私密金鑰路徑 (PEM 格式)",
"ca":"CA憑證路徑 (PEM 格式)",
"passphrase":"私密金鑰密碼 (可選)"
"cert": "憑證路徑 (PEM 格式)",
"key": "私密金鑰路徑 (PEM 格式)",
"ca": "CA憑證路徑 (PEM 格式)",
"passphrase": "私密金鑰密碼 (可選)",
"servername": "用於SNI"
},
"error": {
"missing-file": "未提供證書/金鑰檔案"
}
},
"exec": {
"exec": "exec",
"spawn": "spawn",
"label": {
"command": "命令",
"append": "追加",
"timeout": "超時",
"timeoutplace": "可選填",
"return": "輸出",
"seconds": "秒"
"seconds": "秒",
"stdout": "標準輸出",
"stderr": "標準錯誤輸出",
"retcode": "返回碼"
},
"placeholder": {
"extraparams": "額外的輸入參數"
@@ -177,16 +204,18 @@
"oldrc": "使用舊式輸出 (相容模式)"
},
"function": {
"function": "函數",
"label": {
"function": "函數",
"outputs": "輸出"
},
"error": {
"inputListener":"無法在函數中監聽對'注入'事件",
"non-message-returned":"函數節點嘗試返回類型為 __type__ 的資訊"
"inputListener": "無法在函數中監聽對'注入'事件",
"non-message-returned": "函數節點嘗試返回類型為 __type__ 的資訊"
}
},
"template": {
"template": "模板",
"label": {
"template": "模版",
"property": "屬性",
@@ -233,21 +262,21 @@
"limit": "限制",
"limitTopic": "限制主題",
"random": "隨機",
"units" : {
"units": {
"second": {
"plural" : "秒",
"plural": "秒",
"singular": "秒"
},
"minute": {
"plural" : "分鐘",
"plural": "分鐘",
"singular": "分鐘"
},
"hour": {
"plural" : "小時",
"plural": "小時",
"singular": "小時"
},
"day": {
"plural" : "天",
"plural": "天",
"singular": "天"
}
}
@@ -272,6 +301,9 @@
"wait-reset": "等待被重置",
"wait-for": "等待",
"wait-loop": "週期性重發",
"for": "處理",
"bytopics": "每個msg.topic",
"alltopics": "所有消息",
"duration": {
"ms": "毫秒",
"s": "秒",
@@ -284,12 +316,13 @@
"trigger-block": "觸發並阻止",
"trigger-loop": "週期性重發",
"reset": "重置觸發節點條件 如果:",
"resetMessage":"msg.reset已設置",
"resetPayload":"msg.payload等於",
"resetMessage": "msg.reset已設置",
"resetPayload": "msg.payload等於",
"resetprompt": "可選填"
}
},
"comment": {
"comment": "注釋"
},
"unknown": {
"label": {
@@ -303,26 +336,32 @@
"example": "e.g. localhost",
"output": "輸出",
"qos": "QoS",
"retain": "保持",
"clientid": "使用者端ID",
"port": "埠",
"keepalive": "Keepalive計時(秒)",
"cleansession": "使用新的會話",
"use-tls": "使用安全連接 (SSL/TLS)",
"tls-config":"TLS 設置",
"verify-server-cert":"驗證伺服器憑證",
"tls-config": "TLS 設置",
"verify-server-cert": "驗證伺服器憑證",
"compatmode": "使用舊式MQTT 3.1支援"
},
"sections-label": {
"birth-message": "連接時發送的消息(出生消息)",
"will-message": "意外斷開連接時的發送消息Will消息",
"close-message": "斷開連接前發送的消息(關閉消息)"
},
"tabs-label": {
"connection": "連接",
"security": "安全",
"will": "Will信息",
"birth": "Birth信息"
"messages": "消息"
},
"placeholder": {
"clientid": "留白則自動隨機生成",
"clientid-nonclean":"如非新會話必須設置使用者端ID",
"clientid-nonclean": "如非新會話必須設置使用者端ID",
"will-topic": "留白將禁止Will資訊",
"birth-topic": "留白將禁止Birth資訊"
"birth-topic": "留白將禁止Birth資訊",
"close-topic": "留白以禁用關閉消息"
},
"state": {
"connected": "已連接到服務端: __broker__",
@@ -333,7 +372,9 @@
"output": {
"buffer": "Buffer",
"string": "字串",
"base64": "Base64編碼字串"
"base64": "Base64編碼字串",
"auto": "自動檢測 (字符串或buffer)",
"json": "解析的JSON對象"
},
"true": "是",
"false": "否",
@@ -342,7 +383,9 @@
"not-defined": "主題未設置",
"missing-config": "未設置服務端",
"invalid-topic": "主題無效",
"nonclean-missingclientid": "使用者端ID未設定使用新會話"
"nonclean-missingclientid": "使用者端ID未設定使用新會話",
"invalid-json-string": "無效的JSON字符串",
"invalid-json-parse": "無法解析JSON字符串"
}
},
"httpin": {
@@ -354,12 +397,26 @@
"upload": "接受檔案上傳?",
"status": "狀態碼",
"headers": "Header",
"other": "其他"
"other": "其他",
"paytoqs": "將msg.payload附加為查詢字符串參數",
"utf8String": "UTF8格式的字符串",
"binaryBuffer": "二進制buffer",
"jsonObject": "解析的JSON對象",
"authType": "類型",
"bearerToken": "Token"
},
"setby": "- 用 msg.method 設定 -",
"basicauth": "基本認證",
"use-tls": "使用安全連接 (SSL/TLS) ",
"tls-config":"TLS 設置",
"tls-config": "TLS 設置",
"basic": "基本認證",
"digest": "摘要認證",
"bearer": "bearer認證",
"use-proxy": "使用代理服務器",
"persist": "對連接啟用keep-alive",
"proxy-config": "代理服務器設置",
"use-proxyauth": "使用代理身份驗證",
"noproxy-hosts": "代理例外",
"utf8": "UTF-8 字串",
"binary": "二進位資料",
"json": "JSON對象",
@@ -375,8 +432,11 @@
"no-response": "無響應物件",
"json-error": "JSON 解析錯誤",
"no-url": "未設定 URL",
"deprecated-call":"__method__方法已棄用",
"invalid-transport":"非HTTP傳輸請求"
"deprecated-call": "__method__方法已棄用",
"invalid-transport": "非HTTP傳輸請求",
"timeout-isnan": "超時值不是有效數字,忽略",
"timeout-isnegative": "超時值為負,忽略",
"invalid-payload": "無效的有效載荷"
},
"status": {
"requesting": "請求中"
@@ -395,17 +455,23 @@
"message": "完整資訊",
"tip": {
"path1": "預設情況下,<code>payload</code>將包含要發送或從Websocket接收的資料。偵聽器可以配置為以JSON格式的字串發送或接收整個消息物件.",
"path2": "這條路徑將相對於 ",
"path2": "這條路徑將相對於 <code>__path__</code>.",
"url1": "URL 應該使用ws:&#47;&#47;或者wss:&#47;&#47;方案並指向現有的websocket監聽器.",
"url2": "預設情況下,<code>payload</code> 將包含要發送或從Websocket接收的資料。可以將使用者端配置為以JSON格式的字串發送或接收整個消息物件."
},
"status": {
"connected": "連接數 __count__",
"connected_plural": "連接數 __count__"
},
"errors": {
"connect-error": "ws連接發生了錯誤: ",
"send-error": "發送時發生了錯誤: ",
"missing-conf": "未設置伺服器"
"missing-conf": "未設置伺服器",
"duplicate-path": "同一路徑上不能有兩個WebSocket偵聽器: __path__"
}
},
"watch": {
"watch": "watch",
"label": {
"files": "文件",
"recursive": "遞迴所有子資料夾"
@@ -458,14 +524,12 @@
"connection-closed": "連接已關閉 __host__:__port__",
"connections": "__count__ 個連接",
"connections_plural": "__count__ 個連接"
},
"errors": {
"connection-lost": "連接中斷 __host__:__port__",
"timeout": "超時關閉通訊端連接,埠 __port__",
"cannot-listen": "無法監聽埠 __port__, 錯誤: __error__",
"error": "錯誤: __error__",
"socket-error": "通訊端連接錯誤來自 __host__:__port__",
"no-host": "主機位址或埠未設定",
"connect-timeout": "連接逾時",
@@ -480,14 +544,15 @@
"output": "輸出",
"group": "組",
"interface": "本地IP",
"interfaceprompt": "(可選)本地 IP 綁定到",
"send": "發送一個",
"toport": "到埠",
"address": "地址",
"decode-base64": "是否解碼Base64編碼的資訊?"
"decode-base64": "是否解碼Base64編碼的資訊?",
"interfaceprompt": "(可選)本地 IP 綁定到"
},
"placeholder": {
"interface": "可選eth0的IP地址",
"interfaceprompt": "(可選) 要綁定的本地接口或地址",
"address": "目標IP位址"
},
"udpmsgs": "udp信息",
@@ -529,36 +594,43 @@
"ip-notset": "udp: IP地址未設定",
"port-notset": "udp: 埠未設定",
"port-invalid": "udp: 無效埠號碼",
"alreadyused": "udp: 埠已被佔用"
"alreadyused": "udp: 埠已被佔用",
"ifnotfound": "udp: 接口 __iface__ 未發現"
}
},
"switch": {
"switch": "switch",
"label": {
"property": "屬性",
"rule": "規則",
"repair" : "重建資訊佇列"
"repair": "重建資訊佇列"
},
"previous": "先前值",
"and": "與",
"checkall": "全選所有規則",
"stopfirst": "接受第一條匹配資訊後停止",
"ignorecase": "忽略大小寫",
"rules": {
"btwn":"在之間",
"cont":"包含",
"regex":"匹配規則運算式",
"true":"為真",
"false":"為假",
"null":"為空",
"nnull":"非空",
"head":"head",
"tail":"tail",
"index":"index between",
"exp":"JSONata運算式",
"else":"除此以外"
"btwn": "在之間",
"cont": "包含",
"regex": "匹配規則運算式",
"true": "為真",
"false": "為假",
"null": "為空",
"nnull": "非空",
"istype": "類型是",
"empty": "為空",
"nempty": "非空",
"head": "head",
"tail": "tail",
"index": "index between",
"exp": "JSONata運算式",
"else": "除此以外",
"hask": "擁有鍵"
},
"errors": {
"invalid-expr": "無效的JSONata運算式: __error__",
"too-many" : "Switch節點中有太多待定信息"
"too-many": "Switch節點中有太多待定信息"
}
},
"change": {
@@ -588,6 +660,7 @@
}
},
"range": {
"range": "range",
"label": {
"action": "操作",
"inputrange": "映射輸入資料",
@@ -623,7 +696,8 @@
"firstrow": "第一行包含列名",
"output": "輸出",
"includerow": "包含列名行",
"newline": "分行符號"
"newline": "分行符號",
"usestrings": "解析數值"
},
"placeholder": {
"columns": "用逗號分割列名"
@@ -654,7 +728,8 @@
"html": {
"label": {
"select": "選取項",
"output": "輸出"
"output": "輸出",
"in": "in"
},
"output": {
"html": "選定元素的html內容",
@@ -670,7 +745,9 @@
"errors": {
"dropped-object": "忽略非物件格式的有效負載",
"dropped": "忽略不支援格式的有效負載類型",
"dropped-error": "轉換有效負載失敗"
"dropped-error": "轉換有效負載失敗",
"schema-error": "JSON架構錯誤",
"schema-error-compile": "JSON架構錯誤: 未能編譯架構"
},
"label": {
"o2j": "對象至JSON",
@@ -679,8 +756,8 @@
"property": "屬性",
"actions": {
"toggle": "JSON字串與物件互轉",
"str":"總是轉為JSON字串",
"obj":"總是轉為JS對象"
"str": "總是轉為JSON字串",
"obj": "總是轉為JS對象"
}
}
},
@@ -702,76 +779,6 @@
"xml_js": "此節點僅處理XML字串或JS物件."
}
},
"rpi-gpio": {
"label": {
"gpiopin": "GPIO",
"selectpin": "選擇引腳",
"resistor": "電阻?",
"readinitial": "在部署/重啟時讀取引腳的初始狀態?",
"type": "類型",
"initpin": "初始化引腳狀態?",
"debounce": "去抖動",
"freq": "頻率",
"button": "按鈕",
"pimouse": "Pi滑鼠",
"pikeyboard": "Pi鍵盤",
"left": "左",
"right": "右",
"middle": "中"
},
"resistor": {
"none": "無",
"pullup": "上拉電阻",
"pulldown": "下拉電阻"
},
"digout": "數位輸出",
"pwmout": "PWM輸出",
"servo": "伺服輸出",
"initpin0": "初始引腳電平 - 低(0)",
"initpin1": "初始引腳電平 - 高(1)",
"left": "左",
"right": "右",
"middle": "中",
"any": "任何",
"pinname": "引腳",
"alreadyuse": "已被使用",
"alreadyset": "已被設為",
"tip": {
"pin": "<b>正在使用引腳</b>: ",
"in": "提示: 僅接受數位輸入 - 輸出必須為0或1.",
"dig": "提示: 如用數位輸出 - 輸入必須為0或1.",
"pwm": "提示: 如用PWM輸出 - 輸入必須為0至100之間; 如用高頻率可能會比預期佔用更多CPU資源.",
"ser": "<b>提示</b>: 如用伺服輸出 - 輸入必須為0至100之間. 50為中間值."
},
"types": {
"digout": "數位輸出",
"input": "輸入",
"pullup": "含有上拉電阻的輸入",
"pulldown": "含有下拉電阻的輸入",
"pwmout": "PWM輸出",
"servo": "伺服輸出"
},
"status": {
"stopped": "已停止",
"closed": "已關閉",
"not-running": "不運行"
},
"errors": {
"ignorenode": "忽略樹莓派的特定節點",
"version": "版本命令失敗",
"sawpitype": "查看Pi類型",
"libnotfound": "找不到樹莓派RPi.GPIO的python庫",
"alreadyset": "GPIO引腳 __pin__ 已經被設定為類型: __type__",
"invalidpin": "無效GPIO引腳",
"invalidinput": "無效輸入",
"needtobeexecutable": "__command__須為可運行命令",
"mustbeexecutable": "nrgpio須為可運行",
"commandnotfound": "nrgpio命令不存在",
"commandnotexecutable": "nrgpio命令不可運行",
"error": "錯誤: __error__",
"pythoncommandnotfound": "nrpgio python命令未處於運行狀態"
}
},
"file": {
"label": {
"filename": "檔案名",
@@ -783,7 +790,10 @@
"breaklines": "分拆成行",
"filelabel": "文件",
"sendError": "發生錯誤時發送消息(傳統模式)",
"deletelabel": "刪除 __file__"
"deletelabel": "刪除 __file__",
"encoding": "編碼",
"utf8String": "UTF8字符串",
"binaryBuffer": "二進制buffer"
},
"action": {
"append": "追加至文件",
@@ -801,6 +811,21 @@
"deletedfile": "刪除檔: __file__",
"appendedfile": "追加至文件: __file__"
},
"encoding": {
"none": "默認",
"native": "Native",
"unicode": "Unicode",
"japanese": "日本",
"chinese": "中國",
"korean": "韓國",
"taiwan": "臺灣/香港",
"windows": "Windows代碼頁",
"iso": "ISO代碼頁",
"ibm": "IBM代碼頁",
"mac": "Mac代碼頁",
"koi8": "KOI8代碼頁",
"misc": "其它"
},
"errors": {
"nofilename": "未指定檔案名",
"invaliddelete": "警告:無效刪除。請在配置對話方塊中使用特定的刪除選項",
@@ -812,50 +837,53 @@
"tip": "提示: 檔案名應該是絕對路徑否則它將相對於Node-RED進程的工作目錄。"
},
"split": {
"intro":"基於以下類型拆分<code>msg.payload</code>:",
"object":"<b>對象</b>",
"objectSend":"每個鍵值對作為單個消息發送",
"strBuff":"<b>字串</b> / <b>Buffer</b>",
"array":"<b>陣列</b>",
"splitUsing":"拆分使用",
"splitLength":"固定長度",
"stream":"作為消息流處理",
"addname":" 複製鍵到 "
"split": "split",
"intro": "基於以下類型拆分<code>msg.payload</code>:",
"object": "<b>對象</b>",
"objectSend": "每個鍵值對作為單個消息發送",
"strBuff": "<b>字串</b> / <b>Buffer</b>",
"array": "<b>陣列</b>",
"splitUsing": "拆分使用",
"splitLength": "固定長度",
"stream": "作為消息流處理",
"addname": " 複製鍵到 "
},
"join":{
"mode":{
"mode":"模式",
"auto":"自動",
"merge":"合併序列",
"reduce":"縮減序列",
"custom":"手動"
"join": {
"join": "join",
"mode": {
"mode": "模式",
"auto": "自動",
"merge": "合併序列",
"reduce": "縮減序列",
"custom": "手動"
},
"combine":"合併每個",
"create":"輸出為",
"type":{
"string":"字串",
"array":"陣列",
"buffer":"Buffer",
"object":"鍵值對對象",
"merged":"合併對象"
"combine": "合併每個",
"completeMessage": "完整的消息",
"create": "輸出為",
"type": {
"string": "字串",
"array": "陣列",
"buffer": "Buffer",
"object": "鍵值對對象",
"merged": "合併對象"
},
"using":"使用此值",
"key":"作為鍵",
"joinedUsing":"合併符號",
"send":"發送資訊:",
"afterCount":"達到一定數量的資訊時",
"count":"數量",
"subsequent":"和每個後續的消息",
"afterTimeout":"第一條消息的若時間後",
"seconds":"秒",
"complete":"在收到存在<code>msg.complete</code>的消息後",
"tip":"此模式假定此節點與<i>split</i>相連, 或者接收到的消息有正確配置的<code>msg.parts</code>屬性.",
"too-many" : "join節點中有太多待定信息",
"using": "使用此值",
"key": "作為鍵",
"joinedUsing": "合併符號",
"send": "發送資訊:",
"afterCount": "達到一定數量的資訊時",
"count": "數量",
"subsequent": "和每個後續的消息",
"afterTimeout": "第一條消息的若時間後",
"seconds": "秒",
"complete": "在收到存在<code>msg.complete</code>的消息後",
"tip": "此模式假定此節點與<i>split</i>相連, 或者接收到的消息有正確配置的<code>msg.parts</code>屬性.",
"too-many": "join節點中有太多待定信息",
"merge": {
"topics-label":"合併主題",
"topics":"主題",
"topic" : "主題",
"on-change":"當收到一個新主題時發送已合併資訊"
"topics-label": "合併主題",
"topics": "主題",
"topic": "主題",
"on-change": "當收到一個新主題時發送已合併資訊"
},
"reduce": {
"exp": "Reduce運算式",
@@ -868,43 +896,45 @@
"invalid-expr": "無效的JSONata運算式: __error__"
}
},
"sort" : {
"target" : "排序屬性",
"seq" : "資訊佇列",
"key" : "鍵值",
"elem" : "元素值",
"order" : "順序",
"ascending" : "昇冪",
"descending" : "冪",
"as-number" : "作為數值",
"invalid-exp" : "sort節點中存在無效的JSONata運算式",
"too-many" : "sort節點中有太多待定信息",
"clear" : "清空sort節點中的待定資訊"
"sort": {
"sort": "排序",
"target": "排序屬性",
"seq": "資訊佇列",
"key": "值",
"elem": "元素值",
"order": "順序",
"ascending": "冪",
"descending": "降冪",
"as-number": "作為數值",
"invalid-exp": "排序節點中存在無效的JSONata運算式",
"too-many": "排序節點中有太多待定信息",
"clear": "清空排序節點中的待定資訊"
},
"batch" : {
"batch": {
"batch": "batch",
"mode": {
"label" : "模式",
"num-msgs" : "按指定數量分組",
"interval" : "按時間間隔分組",
"concat" : "按主題分組"
"label": "模式",
"num-msgs": "按指定數量分組",
"interval": "按時間間隔分組",
"concat": "按主題分組"
},
"count": {
"label" : "分組數量",
"overlap" : "隊末隊首重疊數量",
"count" : "數量",
"invalid" : "無效的分組數量或重疊數量"
"label": "分組數量",
"overlap": "隊末隊首重疊數量",
"count": "數量",
"invalid": "無效的分組數量或重疊數量"
},
"interval": {
"label" : "時間間隔",
"seconds" : "秒",
"empty" : "無數據到達時發送空資訊"
"label": "時間間隔",
"seconds": "秒",
"empty": "無數據到達時發送空資訊"
},
"concat": {
"topics-label": "主題",
"topic" : "主題"
"topic": "主題"
},
"too-many" : "batch節點中有太多待定信息",
"unexpected" : "未知模式",
"no-parts" : "資訊中沒有parts屬性"
"too-many": "batch節點中有太多待定信息",
"unexpected": "未知模式",
"no-parts": "資訊中沒有parts屬性"
}
}

View File

@@ -0,0 +1,19 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="tls-config">
<p>TLS連接的配置選項</p>
</script>

View File

@@ -0,0 +1,22 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="http proxy">
<p>HTTP代理的配置選項</p>
<h3>詳細</h3>
<p>訪問代理例外列表中的主機時將不使用任何代理</p>
</script>

View File

@@ -0,0 +1,70 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="mqtt in">
<p>連接到MQTT代理並訂閱來自指定主題的消息</p>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">字符串 | buffer</span></dt>
<dd>如果不是二進制buffer的話就是字符串</dd>
<dt>topic <span class="property-type">字符串</span></dt>
<dd>MQTT主題使用<code>/</code></dd>
<dt>qos <span class="property-type">數值</span> </dt>
<dd>QoS服務質量0, 最多一次 1, 最少一次 2, 只一次</dd>
<dt>retain <span class="property-type">布爾值</span></dt>
<dd>值爲true時表示消息已保留且可能是舊的</dd>
</dl>
<h3>詳細</h3>
<p>訂閱主題可以包括MQTT通配符+一個級別多個級別</p>
<p>使用該節點您首先需要建立與MQTT代理的連接通過單擊鉛筆圖標來進行配置</p>
<p>如有需要幾個MQTT節點輸入或輸出可以共享相同的代理連接</p>
</script>
<script type="text/x-red" data-help-name="mqtt out">
<p>連接到MQTT代理並發布消息</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">字符串 | buffer</span></dt>
<dd>要發布的有效負載如果未設置此屬性則不會發送任何消息要發送空白消息請將此屬性設置爲空字符串</dd>
<dt class="optional">topic <span class="property-type">字符串</span></dt>
<dd>要發布的MQTT主題</dd>
<dt class="optional">qos <span class="property-type">number</span></dt>
<dd>QoS服務質量0, 最多一次 1, 最少一次 2, 只一次默認值爲0</dd>
<dt class="optional">retain <span class="property-type">布爾值</span></dt>
<dd>設置爲<code>true</code><code>false</code></dd>
</dl>
<h3>詳細</h3>
<p><code>msg.payload</code>ObjectJSONbuffer</p>
<p>可以在節點中配置所使用的主題或者如果留爲空白則可以通過<code>msg.topic</code></p>
<p>同樣可以在節點中配置QoS和保留值或者如果保留空白則分別由<code>msg.qos</code><code>msg.retain</code></p>
<p>該節點需要與要配置的MQTT代理的連接通過單擊鉛筆圖標進行配置</p>
<p>如果需要幾個MQTT節點輸入或輸出可以共享相同的代理連接</p>
</script>
<script type="text/x-red" data-help-name="mqtt-broker">
<p>與MQTT代理的連接設置</p>
<p>創建與代理的連接設置可以在<code>MQTT In</code><code>MQTT Out</code></p>
<p>如果未爲該節點設置客戶端ID並且設置了會話初始化則將生成一個隨機客戶端ID設置客戶端ID時請確保它對于連接目標處的代理是唯一的</p>
<h4>Birth Message</h4>
<p>建立連接後發布在以配置主題中的消息</p>
<h4>Close Message</h4>
<p>在連接正常結束之前重新部署或者關閉了節點時發布在以配置主題中的消息</p>
<h4>Will Message</h4>
<p>當節點意外丟失連接時由代理發布的消息</p>
<h4>WebSockets</h4>
<p>可以將節點配置成使用WebSocket連接使用WebSocket時請在服務器字段中以完整格式描述連接目標的URI 例如</p>
<pre>ws://example.com:4000/mqtt</pre>
</script>

View File

@@ -0,0 +1,81 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="http in">
<p>創建用于創建Web服務的HTTP端點</p>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload</dt>
<dd>GET請求包含任何查詢字符串參數的對象或者包含HTTP請求正文</dd>
<dt>req<span class="property-type">object</span></dt>
<dd>HTTP請求對象該對象包含有關請求信息的多個屬性
<ul>
<li><code>body</code> - </li>
<li><code>headers</code> - HTTP</li>
<li><code>query</code> - </li>
<li><code>params</code> - </li>
<li><code>cookies</code> - cookie</li>
<li><code>files</code> - </li>
</ul>
</dd>
<dt>res<span class="property-type">object</span></dt>
<dd>HTTP響應對象此屬性不應直接使用<code>HTTP Response</code></dd>
</dl>
<h3>詳細</h3>
<p>節點將在配置的路徑上監聽特定類型的請求路徑可以完全指定例如<code>/user</code><code>/user/:name</code> 使<code>msg.req.params</code></p>
<p>對于包含正文的請求例如POST或PUT請求的內容將作爲<code>msg.payload</code></p>
<p>如果可以確定請求的內容類型則正文將被解析爲任何適當的類型例如<code>application/json</code>JavaScript</p>
<p><b>注意</b>HTTP</p>
</script>
<script type="text/x-red" data-help-name="http response">
<p>將響應發送回從HTTP輸入節點接收的請求</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">string</span></dt>
<dd>響應的正文</dd>
<dt class="optional">statusCode <span class="property-type">數值</span></dt>
<dd>如果設置則用作響應狀態代碼默認值200</dd>
<dt class="optional">headers <span class="property-type">object</span></dt>
<dd>如果設置則提供HTTP頭以包含在響應中</dd>
<dt class="optional">cookies <span class="property-type">object</span></dt>
<dd>如果設置則可用于設置或刪除cookie</dd>
</dl>
<h3>詳細</h3>
<p>還可以在節點本身內設置<code>statusCode</code><code>headers</code>message</p>
<h4>Cookie處理</h4>
<p><code>cookies</code>/使cookieoptions<p>
<p>下面的示例設置兩個cookie-一個名爲<code>name</code><code>nick</code><code>session</code><code>1234</code>15</p>
<pre>
msg.cookies = {
name: 'nick',
session: {
value: '1234',
maxAge: 900000
}
}</pre>
<p>有效選項包括</p>
<ul>
<li><code>domain</code> - () Cookie</li>
<li><code>expires</code> - () GMT0cookie</li>
<li><code>maxAge</code> - () </li>
<li><code>path</code> - (字符串) Cookie的路徑。默認爲/</li>
<li><code>value</code> - () Cookie使</li>
</ul>
<p>要刪除Cookie請將其<code>value</code><code>null</code></p>
</script>

View File

@@ -0,0 +1,78 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="http request">
<p>發送HTTP請求並返回響應</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt class="optional">url <span class="property-type">字符串</span></dt>
<dd>如果未在節點中配置則此可選屬性設置請求的url</dd>
<dt class="optional">method <span class="property-type">字符串</span></dt>
<dd>如果未在節點中配置則此可選屬性設置請求的HTTP方法必須是<code>GET</code>,<code>PUT</code>,<code>POST</code>,<code>PATCH</code><code>DELETE</code></dd>
<dt class="optional">headers <span class="property-type">object</span></dt>
<dd>設置請求的HTTP頭</dd>
<dt class="optional">cookies <span class="property-type">object</span></dt>
<dd>如果設置則可用于發送帶有請求的cookie</dd>
<dt class="optional">payload</dt>
<dd>發送爲請求的正文</dd>
<dt class="optional">rejectUnauthorized</dt>
<dd>如果設置爲<code>false</code>使https</dd>
<dt class="optional">followRedirects</dt>
<dd>如果設置爲<code>false</code>HTTP 301<code>true</code></dd>
<dt class="optional">requestTimeout</dt>
<dd>如果設置爲正數毫秒將覆蓋全局設置的<code>httpRequestTimeout</code></dd>
</dl>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">字符串 | object | buffer</span></dt>
<dd>響應的正文可以將節點配置爲以字符串形式返回主體嘗試將其解析爲JSON字符串或將其保留爲二進制buffer</dd>
<dt>statusCode <span class="property-type">數值</span></dt>
<dd>響應的狀態碼如果請求無法完成則返回錯誤碼</dd>
<dt>headers <span class="property-type">object</span></dt>
<dd>包含響應頭的對象</dd>
<dt>responseUrl <span class="property-type">字符串</span></dt>
<dd>如果在處理請求時發生任何重定向則此屬性爲最終重定向的URL否則則爲原始請求的URL</dd>
<dt>responseCookies <span class="property-type">object</span></dt>
<dd>如果響應包含cookie則此屬性是每個cookie的名稱/鍵值對的對象</dd>
<dt>redirectList <span class="property-type">數組</span></dt>
<dd>如果請求被重定向了一次或多次則累積的信息將被添加到此屬性location是下一個重定向目標cookie是從重定向源返回的cookie</dd>
</dl>
<h3>詳細</h3>
<p>在節點內配置後URL屬性可以包含<a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache樣式</a>標簽。 這些標簽允許使用傳入消息的值來構造url。例如如果url設置爲<code>example.com/{{{{topic}}}</code><code>msg.topic</code>使{{{...}}}mustache/ &</p>
<p>節點可以選擇自動將<code>msg.payload</code>GET<code>msg.payload</code></p>
<p><b>注意</b>使<code>http_proxy=...</code>Node-RED使</p>
<h4>使用多個HTTP請求節點</h4>
<p>爲了在一個流程中多次使用該節點必須要注意<code>msg.headers</code>使<code>msg.headers</code><code>msg.headers</code><code>{}</code></p>
<h4>Cookie處理</h4>
<p>傳遞給節點的<code>cookies</code>/cookie<code>value</code></p>
<p>請求返回的所有cookie都將在<code>responseCookies</code></p>
<h4>內容類型處理</h4>
<p>如果<code>msg.payload</code><code>application/json</code></p>
<p>要將請求編碼爲表單數據應將<code>msg.headers[content-type]</code><code>application/x-www-form-urlencoded</code></p>
<h4>文件上傳</h4>
<p>要執行文件上傳應將<code>msg.headers["content-type"]</code><code>multipart/form-data</code><code>msg.payload</code></p>
<pre><code>{
"KEY": {
"value": FILE_CONTENTS,
"options": {
"filename": "FILENAME"
}
}
}</code></pre>
<p><code>KEY</code>,<code>FILE_CONTENTS</code><code>FILENAME</code></p>
</script>

View File

@@ -0,0 +1,35 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="websocket in">
<p>WebSocket輸入節點</p>
<p>默認情況下從WebSocket接收的數據將位于<code>msg.payload</code>JSONJSON</p>
</script>
<script type="text/x-red" data-help-name="websocket out">
<p>WebSocket輸出節點</p>
<p>默認情況下<code>msg.payload</code>WebSocket<code>msg</code>JSONWebSocket</p>
<p>如果到達此節點的消息是從WebSocket In節點開始的則該消息將發送回觸發流程的客戶端否則消息將廣播給所有連接的客戶端</p>
<p>如果要廣播從WebSocket輸入節點開始的消息則可以應該刪除流中的<code>msg._session</code></p>
</script>
<script type="text/x-red" data-help-name="websocket-listener">
<p>此配置節點使用指定的路徑創建WebSocket服務器端點</p>
</script>
<script type="text/x-red" data-help-name="websocket-client">
<p>此配置節點將WebSocket客戶端連接到指定的URL</p>
</script>

View File

@@ -0,0 +1,35 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="tcp in">
<p>提供TCP輸入選擇可以連接到遠程TCP端口或接受傳入連接</p>
<p><b>注意</b>root1024</p>
</script>
<script type="text/x-red" data-help-name="tcp out">
<p>提供TCP輸出的選擇可以連接到遠程TCP端口接受傳入的連接或回複從TCP In節點收到的消息</p>
<p>僅發送<code>msg.payload</code></p>
<p>如果<code>msg.payload</code>Base64Base64</p>
<p>如果不存在<code>msg._session</code><b></b></p>
<p><b>注意</b>root1024</p>
</script>
<script type="text/x-red" data-help-name="tcp request">
<p>一個簡單的TCP請求節點<code>msg.payload</code>tcp</p>
<p>連接到服務器發送請求並接收響應 可以從固定數量的字符與指定字符匹配的字符中選擇操作從第一個答複到達起等待指定的時間等待數據到達發送數據並立即取消連接而無需等待答複等操作中進行選擇</p>
<p>響應將在<code>msg.payload</code>buffer<code>.toString()</code></p>
<p>如果將tcp主機或端口留空則必須使用<code>msg.host</code><code>msg.port</code></p>
</script>

View File

@@ -0,0 +1,28 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="udp in">
<p>UDP輸入節點<code>msg.payload</code>BufferBase64</p>
<p><code>msg.ip</code><code>msg.port</code>IP</p>
<p><b>注意</b>root使1024</p>
</script>
<script type="text/x-red" data-help-name="udp out">
<p>該節點將<code>msg.payload</code>UDP</p>
<p>您也可以使用<code>msg.ip</code><code>msg.port</code></p>
<p>如果選擇廣播則將地址設置爲本地廣播IP地址或者也可以嘗試使用全局廣播地址255.255.255.255</p>
<p><b>注意</b>root使1024</p>
</script>

View File

@@ -0,0 +1,43 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="csv">
<p>在CSV格式的字符串及其JavaScript對象表示形式之間進行相互轉換</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 數組 | 字符串</span></dt>
<dd>JavaScript對象數組或CSV字符串</dd>
</dl>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 數組 | 字符串</span></dt>
<dd>
<ul>
<li>如果輸入是字符串它將嘗試將其解析爲CSV並爲每行創建鍵/值對的JavaScript對象然後該節點將爲每行發送一條消息或者發送一條包含對象數組的消息</li>
<li>如果輸入是JavaScript對象它將嘗試構建CSV字符串</li>
<li>如果輸入是簡單值的數組則將構建單行CSV字符串</li>
<li>如果輸入是數組數組或對象數組則會創建多行CSV字符串</li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>列模板可以包含列名稱的有序列表將CSV轉換爲對象時列名將用作屬性名稱或者也可以從CSV的第一行中獲取列名稱</p>
<p>轉換爲CSV時列模板用于標識從對象中提取的屬性以及提取的順序</p>
<p>如果輸入是數組則列模板僅用于有選擇地生成一行列標題</p>
<p>只要正確設置<code>parts</code></p>
<p>如果輸出多個消息則將設置其<code>parts</code></p>
<p><b>注意</b>使</p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="html">
<p>使用CSS選擇器從<code>msg.payload</code>html</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">字符串</span></dt>
<dd>從中提取元素的html字符串</dd>
<dt class="optional">select <span class="property-type">字符串</span></dt>
<dd>如果未在編輯面板中配置則可以將選擇器設置爲msg的屬性</dd>
</dl>
<h3>Output</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">數組 | 字符串</span></dt>
<dd>結果可以是有效載荷中包含匹配元素的數組的單個消息也可以是多條消息每條消息都包含匹配元素發送多條消息時需要爲消息設置<code>parts</code></dd>
</dl>
<h3>詳細</h3>
<p>該節點支持CSS和jQuery選擇器的組合查看<a href="https://github.com/fb55/CSSselect#user-content-supported-selectors" target="_blank">css-select documentation</a> </p>
</script>

View File

@@ -0,0 +1,43 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="json">
<p>在JSON字符串及其JavaScript對象表示形式之間相互轉換</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串</span></dt>
<dd>JavaScript對象或JSON字符串</dd>
<dt>schema<span class="property-type">object</span></dt>
<dd>可選的JSON Schema對象用于驗證有效負載在將<code>msg</code></dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串</span></dt>
<dd>
<ul>
<li>如果輸入是JSON字符串它將嘗試將其解析爲JavaScript對象</li>
<li>如果輸入是JavaScript對象它將創建一個JSON字符串並可以選擇對此JSON字符串進行整形</li>
</ul>
</dd>
<dt>schemaError<span class="property-type">數組</span></dt>
<dd>如果JSON模式驗證失敗則catch節點將具有包含錯誤數組的<code>schemaError</code></dd>
</dl>
<h3>詳細</h3>
<p>默認的轉換目標是<code>msg.payload</code></p>
<p>您可以將其設置爲僅執行特定的轉換而不是自動選擇雙向轉換例如即使對<code>HTTP In</code>content-type使JSONJavaScript</p>
<p>如果指定了轉換爲JSON字符串則不會對收到的字符串進行進一步的檢查也就是說即使指定了格式化選項它也不會檢查字符串是否正確爲JSON或對JSON執行整形</p>
<p>有關JSON模式的更多詳細信息請查閱<a href="http://json-schema.org/latest/json-schema-validation.html">規範</a>.</p>
</script>

View File

@@ -0,0 +1,48 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="xml">
<p>在XML字符串及其JavaScript對象表示形式之間進行相互轉換</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串</span></dt>
<dd>JavaScript對象或XML字符串</dd>
<dt class="optional">options <span class="property-type">object</span></dt>
<dd>可以將選項傳遞給內部使用的XML轉換庫請參見<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank"> xml2js文檔</a> </dd>
</dl>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串</span></dt>
<dd>
<ul>
<li>如果輸入是字符串它將嘗試將其解析爲XML並創建一個JavaScript對象</li>
<li>如果輸入是JavaScript對象它將嘗試構建XML字符串</li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>在XML和對象之間進行轉換時默認情況下XML屬性會添加到名爲<code>$</code><code>_</code></p>
<p>例如將如下所示轉換以下XML</p>
<pre>&lt;p class="tag"&gt;Hello World&lt;/p&gt;</pre>
<pre>{
"p": {
"$": {
"class": "tag"
},
"_": "Hello World"
}
}</pre>
</script>

View File

@@ -0,0 +1,34 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="yaml">
<p>在YAML格式的字符串及其JavaScript對象表示形式之間相互轉換</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串</span></dt>
<dd>JavaScript對象或YAML字符串</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串</span></dt>
<dd>
<ul>
<li>如果輸入是YAML字符串它將嘗試將其解析爲JavaScript對象</li>
<li>如果輸入是JavaScript對象它將創建一個YAML字符串</li>
</ul>
</dd>
</dl>
</script>

View File

@@ -0,0 +1,133 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="split">
<p>將一條消息拆分爲一系列消息</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object | 字符串 | 數組 | buffer</span></dt>
<dd>節點的行爲由<code>msg.payload</code>:
<ul>
<li><b>字符串</b>/<b>buffer</b> - 使<code>\n</code></li>
<li><b>數組</b> - </li>
<li><b>object</b> - /</li>
</ul>
</dd>
</dl>
<h3>輸出</h3>
<dl class="message-properties">
<dt>parts<span class="property-type">object</span></dt>
<dd>此屬性包含有關如何將消息與原始消息分開的信息如果傳遞給<b>join</b>
<ul>
<li><code>id</code> - </li>
<li><code>index</code> - </li>
<li><code>count</code> - </li>
<li><code>type</code> - -///buffer</li>
<li><code>ch</code> - buffer</li>
<li><code>key</code> - <code>msg.topic</code></li>
<li><code>len</code> - 使</li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>在使用<b>join</b>使</p>
<p>它使用<code>msg.parts</code></p>
<h4>流媒體模式</h4>
<p>該節點還可以用于重排消息流例如發送換行符終止命令的串行設備可能會傳遞一條消息並在其末尾帶有部分命令 流模式此節點將拆分一條消息並發送每個完整的段如果末尾有部分片段則該節點將保留該片段並將其添加到收到的下一條消息之前</p>
<p>在此模式下運行時該節點將不會設置<code>msg.parts.count</code><b>join</b>使</p>
</script>
<script type="text/x-red" data-help-name="join">
<p>將消息序列合並爲一條消息.</p>
<p>共有三種模式</p>
<dl>
<dt>自動模式</dt>
<dd><b>split</b></dd>
<dt>手動模式</dt>
<dd>手動地以各種方式合並消息序列</dd>
<dt>列聚合模式</dt>
<dd>對消息列中的所有消息應用表達式以將其簡化爲單個消息</dd>
</dl>
<h3>輸入</h3>
<dl class="message-properties">
<dt class="optional">parts<span class="property-type">object</span></dt>
<dd>使用自動模式時所有的消息都應包含此屬性<b>split</b>
<ul>
<li><code>id</code> - </li>
<li><code>index</code> - </li>
<li><code>count</code> - </li>
<li><code>type</code> - -///buffer</li>
<li><code>ch</code> - buffer</li>
<li><code>key</code> - <code>msg.topic</code>/li>
<li><code>len</code> - 使</li>
</ul>
</dd>
<dt class="optional">complete</dt>
<dd>如果設置則節點將以其當前狀態發送其輸出消息</dd>
</dl>
<h3>詳細</h3>
<h4>自動模式</h4>
<p>自動模式使用傳入消息的<code>parts</code>使<b>split</b></p>
<h4>手動模式</h4>
<p>設置爲以手動模式時該節點能以各種不同的方法來處理消息</p>
<ul>
<li><b>字符串</b><b></b>-</li>
<li><b>數組</b> - </li>
<li><b>/值對象</b> - 使</li>
<li><b>merged object</b> - </li>
</ul>
<p>輸出消息的其他屬性都取自發送結果前的最後一條消息</p>
<p>可以用<i>計數</i></p>
<p>可以用<i>超時</i></p>
<p>如果收到設置了<b>msg.complete</b></p>
<p>如果收到設置了<b>msg.reset</b></p>
<h4>列聚合模式</h4>
<p>選擇列聚合模式時將表達式應用于組成消息列的每條消息並使用聚合值組成一條消息</p>
<dl class="message-properties">
<dt>初始值</dt>
<dd>累積值的初始值(<code>$A</code>)</dd>
<dt>聚合表達式</dt>
<dd>序列中的每個消息調用的JSONata表達式結果將作爲累加值傳遞到表達式的下一個調用在表達式中可以使用以下特殊變量
<ul>
<li><code>$A</code>: </li>
<li><code>$I</code>: </li>
<li><code>$N</code>: </li>
</ul>
</dd>
<dt>最終調整式子</dt>
<dd>可選的JSONata表達式在將聚合表達式應用于序列中的所有消息之後應用在表達式中可以使用以下特殊變量
<ul>
<li><code>$A</code>: </li>
<li><code>$N</code>: </li>
</ul>
</dd>
<p>默認情況下按順序從序列的第一條消息到最後一條消息應用聚合表達式也可以選擇以相反的順序應用聚合表達式</p>
</dl>
<p><b>例子</b>
<ul>
<li><b>聚合表達式</b>: <code>$A+payload</code></li>
<li><b>初始值</b>: <code>0</code></li>
<li><b>最終調整式</b>: <code>$A/$N</code></li>
</ul>
</p>
<h4>儲存訊息</h4>
<p>該節點將在內部緩存消息以便跨序列工作運行時設置<code>nodeMessageBufferMaxLength</code></p>
</script>

View File

@@ -0,0 +1,41 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="sort">
<p>對消息屬性或消息序列進行排序的函數</p>
<p>當配置爲對消息屬性進行排序時節點將對指定消息屬性所指向的數組數據進行排序</p>
<p>當配置爲對消息序列排序時它將對消息重新排序</p>
<p>排序順序可以是</p>
<ul>
<li><b>升序</b></li>
<li><b>降序</b></li>
</ul>
<p>對于數字可以通過複選框指定數字順序</p>
<p>排序鍵可以是元素值也可以是JSONata表達式來對屬性值進行排序還可以是message屬性或JSONata表達式來對消息序列進行排序<p>
<p>在對消息序列進行排序時排序節點依賴于接收到的消息來設置<code>msg.parts</code></p>
<p>
<ul>
<li><code>id</code> - </li>
<li><code>index</code> - </li>
<li><code>count</code> - </li>
</ul>
</p>
<p><b>注意</b>使
<ul>
<li><code>nodeMessageBufferMaxLength</code><b>settings.js</b></li>
</ul>
</p>
</script>

View File

@@ -0,0 +1,34 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="batch">
<p>根據各種規則創建消息序列</p>
<h3>詳細</h3>
<p>有三種創建消息序列的模式</p>
<dl>
<dt>訊息數</dt>
<dd>將消息分組爲給定長度的序列 <b>overlap</b></dd>
<dt>時間間隔</dt>
<dd>對在指定時間間隔內到達的郵件進行分組如果在該時間間隔內沒有消息到達則該節點可以選擇發送空消息</dd>
<dt>串聯序列</dt>
<dd>通過串聯輸入序列來創建消息序列每條消息必須具有<code>msg.topic</code><code>msg.parts</code><code>topic</code>
</dd>
</dl>
<h4>儲存訊息</h4>
<p>該節點將在內部緩衝消息以便跨序列工作運行時設置<code>nodeMessageBufferMaxLength</code></p>
</script>

View File

@@ -0,0 +1,55 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/html" data-help-name="file">
<p><code>msg.payload</code></p>
<h3>輸入</h3>
<dl class="message-properties">
<dt class="optional">filename<span class="property-type">字符串</span></dt>
<dd>如果未在節點中配置則此可選屬性可以設置文件名</dd>
</dl>
<h3>輸出</h3>
<p>寫入完成後輸入消息將發送到輸出端口</p>
<h3>詳細</h3>
<p>每個消息的有效荷載將添加到文件的末尾可以選擇在每個消息之間添加一個換行符\n</p>
<p>如果使用<code>msg.filename</code>使</p>
<p>可以將其配置爲覆蓋整個文件而不是在文件後添加段落例如在將二進制數據寫入文件例如圖像應使用此選項並且應禁用添加換行符的選項</p>
<p>可以從編碼列表中指定寫入文件的數據的編碼</p>
<p>您可以將此節點配置爲刪除文件</p>
</script>
<script type="text/html" data-help-name="file in">
<p>以字符串或二進制緩衝區的形式讀取文件的內容</p>
<h3>輸入</h3>
<dl class="message-properties">
<dt class="optional">filename<span class="property-type">字符串</span></dt>
<dd>如果未在節點配置中設置該屬性可以選擇要讀取的文件名</dd>
</dl>
<h3>輸出</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">字符串 | buffer</span></dt>
<dd>文件的內容可以是字符串也可以是二進制的buffer</dd>
<dt class="optional">filename <span class="property-type">字符串</span></dt>
<dd>如果未在節點配置中設置該屬性可以選擇要讀取的文件名</dd>
</dl>
<h3>詳細</h3>
<p>文件名應該是絕對路徑否則將相對于Node-RED進程的工作目錄</p>
<p>在Windows上可能需要使用轉義路徑分隔符例如<code>\\Users\\myUser</code></p>
<p>可以選擇將文本文件拆分爲幾行每行輸出一條消息或者將二進制文件拆分爲較小的buffer塊-塊大小取決于操作系統但通常爲64kLinux/Mac或41kWindows</p>
<p>當拆分爲多條消息時每條消息將具有<code>parts</code></p>
<p>如果輸出格式爲字符串則可以從編碼列表中指定輸入數據的編碼</p>
<p>應該使用Catch節點來捕獲並處理錯誤</p>
</script>

View File

@@ -0,0 +1,25 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="watch">
<p>監視目錄或文件中的更改</p>
<p>您可以輸入用逗號分隔的目錄和/或文件的列表您需要在所有帶有空格的地方加上引號...</p>
<p>在Windows上必須在任何目錄名稱中使用雙反斜杠<code>\\</code></p>
<p>實際更改的文件的完整文件名將放入<code>msg.payload</code><code>msg.filename</code><code>msg.topic</code></p>
<p><code>msg.file</code><code>msg.type</code><i>file</i><i>directory</i><code>msg.size</code></p>
<p>當然在Linux中<i>everything</i></p>
<p><b>注意</b>使</p>
</script>

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "1.0.3",
"version": "1.1.0",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -15,11 +15,11 @@
}
],
"dependencies": {
"ajv": "6.10.2",
"ajv": "6.12.0",
"body-parser": "1.19.0",
"cheerio": "0.22.0",
"content-type": "1.0.4",
"cookie-parser": "1.4.4",
"cookie-parser": "1.4.5",
"cookie": "0.4.0",
"cors": "2.8.5",
"cron": "1.7.2",
@@ -27,18 +27,18 @@
"fs-extra": "8.1.0",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
"https-proxy-agent": "2.2.4",
"https-proxy-agent": "5.0.0",
"is-utf8": "0.2.1",
"js-yaml": "3.13.1",
"media-typer": "1.1.0",
"mqtt": "2.18.8",
"multer": "1.4.2",
"mustache": "3.0.2",
"mustache": "4.0.1",
"on-headers": "1.0.2",
"raw-body": "2.4.1",
"request": "2.88.0",
"ws": "6.2.1",
"xml2js": "0.4.22",
"iconv-lite": "0.5.0"
"xml2js": "0.4.23",
"iconv-lite": "0.5.1"
}
}