@node-red/nodes 3.0.0-beta.1 → 3.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -69,7 +69,7 @@
69
69
  outputs:1, // set the number of outputs - 0 to n
70
70
  color: "#ddd", // set icon color
71
71
  // set the icon (held in icons dir below where you save the node)
72
- icon: "myicon.png", // saved in icons/myicon.png
72
+ icon: "myicon.svg", // saved in icons/myicon.svg
73
73
  label: function() { // sets the default label contents
74
74
  return this.name||this.topic||"sample";
75
75
  },
@@ -118,7 +118,7 @@
118
118
  .inject-time-row {
119
119
  padding-left: 110px;
120
120
  }
121
- .inject-time-row select {
121
+ .inject-time-row:not(#inject-time-row-interval) select {
122
122
  margin: 3px 0;
123
123
  }
124
124
  .inject-time-days label {
@@ -109,9 +109,10 @@ module.exports = function(RED) {
109
109
  if (!property) return;
110
110
 
111
111
  if (valueType === "jsonata") {
112
- if (p.exp) {
112
+ if (p.v) {
113
113
  try {
114
- var val = RED.util.evaluateJSONataExpression(p.exp, msg);
114
+ var exp = RED.util.prepareJSONataExpression(p.v, node);
115
+ var val = RED.util.evaluateJSONataExpression(exp, msg);
115
116
  RED.util.setMessageProperty(msg, property, val, true);
116
117
  }
117
118
  catch (err) {
@@ -499,7 +499,7 @@
499
499
  types:['msg', fullType, "jsonata"],
500
500
  typeField: $("#node-input-targetType")
501
501
  });
502
- if (this.targetType === "jsonata") {
502
+ if (this.targetType === "jsonata") {
503
503
  var property = this.complete || "";
504
504
  $("#node-input-typed-complete").typedInput('type','jsonata');
505
505
  $("#node-input-typed-complete").typedInput('value',property);
@@ -530,7 +530,6 @@
530
530
  if (type !== 'full') {
531
531
  comp = $("#node-input-typed-complete").typedInput('value');
532
532
  }
533
- console.log('hihi')
534
533
  that.statusType = "auto";
535
534
  that.statusVal = comp;
536
535
  }
@@ -559,7 +558,7 @@
559
558
  onadd: function() {
560
559
  if (this.name === '_DEFAULT_') {
561
560
  this.name = ''
562
- RED.actions.invoke("core:generate-node-names", this)
561
+ RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
563
562
  }
564
563
  }
565
564
  });
@@ -221,7 +221,7 @@
221
221
  function onAdd() {
222
222
  if (this.name === '_DEFAULT_') {
223
223
  this.name = ''
224
- RED.actions.invoke("core:generate-node-names", this)
224
+ RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
225
225
  }
226
226
  for (var i=0;i<this.links.length;i++) {
227
227
  var n = RED.nodes.node(this.links[i]);
@@ -302,7 +302,6 @@
302
302
  return this.name?"node_label_italic":"";
303
303
  },
304
304
  oneditprepare: function() {
305
- console.log("link call oneditprepare")
306
305
  const updateVisibility = function() {
307
306
  const static = $('#node-input-linkType').val() !== "dynamic";
308
307
  if(static) {
@@ -109,16 +109,13 @@ module.exports = function(RED) {
109
109
  },
110
110
  remove(node) {
111
111
  const target = generateTarget(node);
112
- const tn = this.getTarget(target.name, target.flowId);
113
- if (tn) {
114
- const targs = this.getTargets(tn.name);
115
- const idx = getIndex(targs, tn.id);
116
- if (idx > -1) {
117
- targs.splice(idx, 1);
118
- }
119
- if (targs.length === 0) {
120
- delete registry.name[tn.name];
121
- }
112
+ const targs = this.getTargets(target.name);
113
+ const idx = getIndex(targs, target.id);
114
+ if (idx > -1) {
115
+ targs.splice(idx, 1);
116
+ }
117
+ if (targs.length === 0) {
118
+ delete registry.name[tn.name];
122
119
  }
123
120
  delete registry.id[target.id];
124
121
  },
@@ -582,7 +582,7 @@ RED.debug = (function() {
582
582
  $('<span class="red-ui-debug-msg-date">'+ getTimestamp()+'</span>').appendTo(metaRow);
583
583
  if (sourceNode) {
584
584
 
585
- var nodeLink = $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text("node: "+(o.name||sourceNode.name||sourceNode.id))
585
+ var nodeLink = $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text(RED._("node-red:debug.node")+": "+(o.name||sourceNode.name||sourceNode.id))
586
586
  .appendTo(metaRow)
587
587
  .on("click", function(evt) {
588
588
  evt.preventDefault();
@@ -460,7 +460,7 @@
460
460
  }
461
461
  });
462
462
 
463
- var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs) {
463
+ var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs, offset) {
464
464
  var editor = RED.editor.createEditor({
465
465
  id: id,
466
466
  mode: 'ace/mode/nrjavascript',
@@ -484,14 +484,14 @@
484
484
  extraLibs: extraLibs
485
485
  });
486
486
  if (defaultValue && value === "") {
487
- editor.moveCursorTo(defaultValue.split("\n").length - 1, 0);
487
+ editor.moveCursorTo(defaultValue.split("\n").length +offset, 0);
488
488
  }
489
489
  editor.__stateId = stateId;
490
490
  return editor;
491
491
  }
492
- this.initEditor = buildEditor('node-input-init-editor', this.id + "/" + "initEditor", false, $("#node-input-initialize").val(), RED._("node-red:function.text.initialize"))
493
- this.editor = buildEditor('node-input-func-editor', this.id + "/" + "editor", true, $("#node-input-func").val(), undefined, that.libs || [])
494
- this.finalizeEditor = buildEditor('node-input-finalize-editor', this.id + "/" + "finalizeEditor", false, $("#node-input-finalize").val(), RED._("node-red:function.text.finalize"))
492
+ this.initEditor = buildEditor('node-input-init-editor', this.id + "/" + "initEditor", false, $("#node-input-initialize").val(), RED._("node-red:function.text.initialize"), undefined, 0);
493
+ this.editor = buildEditor('node-input-func-editor', this.id + "/" + "editor", true, $("#node-input-func").val(), undefined, that.libs || [], undefined, -1);
494
+ this.finalizeEditor = buildEditor('node-input-finalize-editor', this.id + "/" + "finalizeEditor", false, $("#node-input-finalize").val(), RED._("node-red:function.text.finalize"), undefined, 0);
495
495
 
496
496
  RED.library.create({
497
497
  url:"functions", // where to get the data from
@@ -639,7 +639,7 @@
639
639
  onadd: function() {
640
640
  if (this.name === '_DEFAULT_') {
641
641
  this.name = ''
642
- RED.actions.invoke("core:generate-node-names", this)
642
+ RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
643
643
  }
644
644
  }
645
645
  });
@@ -146,13 +146,13 @@
146
146
 
147
147
  function createTypeValueField(row, defaultType){
148
148
  return $('<input/>',{class:"node-input-rule-type-value",type:"text",style:"width: 100%;"}).appendTo(row).typedInput({default:defaultType || 'string',types:[
149
- {value:"string",label:RED._("common.type.string"),hasValue:false,icon:"red/images/typedInput/az.png"},
150
- {value:"number",label:RED._("common.type.number"),hasValue:false,icon:"red/images/typedInput/09.png"},
151
- {value:"boolean",label:RED._("common.type.boolean"),hasValue:false,icon:"red/images/typedInput/bool.png"},
152
- {value:"array",label:RED._("common.type.array"),hasValue:false,icon:"red/images/typedInput/json.png"},
153
- {value:"buffer",label:RED._("common.type.buffer"),hasValue:false,icon:"red/images/typedInput/bin.png"},
154
- {value:"object",label:RED._("common.type.object"),hasValue:false,icon:"red/images/typedInput/json.png"},
155
- {value:"json",label:RED._("common.type.jsonString"),hasValue:false,icon:"red/images/typedInput/json.png"},
149
+ {value:"string",label:RED._("common.type.string"),hasValue:false,icon:"red/images/typedInput/az.svg"},
150
+ {value:"number",label:RED._("common.type.number"),hasValue:false,icon:"red/images/typedInput/09.svg"},
151
+ {value:"boolean",label:RED._("common.type.boolean"),hasValue:false,icon:"red/images/typedInput/bool.svg"},
152
+ {value:"array",label:RED._("common.type.array"),hasValue:false,icon:"red/images/typedInput/json.svg"},
153
+ {value:"buffer",label:RED._("common.type.buffer"),hasValue:false,icon:"red/images/typedInput/bin.svg"},
154
+ {value:"object",label:RED._("common.type.object"),hasValue:false,icon:"red/images/typedInput/json.svg"},
155
+ {value:"json",label:RED._("common.type.jsonString"),hasValue:false,icon:"red/images/typedInput/json.svg"},
156
156
  {value:"undefined",label:RED._("common.type.undefined"),hasValue:false},
157
157
  {value:"null",label:RED._("common.type.null"),hasValue:false}
158
158
  ]});
@@ -247,14 +247,16 @@
247
247
  var row2 = $('<div/>',{style:"display: flex; padding-top: 5px; padding-left: 175px;"}).appendTo(inputRows);
248
248
  var row3 = $('<div/>',{style:"display: flex; padding-top: 5px; align-items: center"}).appendTo(inputRows);
249
249
 
250
+ var row4 = $('<div/>',{style:"visibility: hidden; height: 0px;"}).appendTo(inputRows);
251
+ var textSpan = $("<span/>").appendTo(row4);
250
252
  var selectField = $('<select/>',{style:"width:120px; text-align: center;"}).appendTo(row);
251
- var group0 = $('<optgroup/>', { label: "value rules" }).appendTo(selectField);
253
+ var group0 = $('<optgroup/>', { label: RED._("node-red:switch.label.value-rules") }).appendTo(selectField);
252
254
  for (var d in operators) {
253
255
  if(operators[d].kind === 'V') {
254
256
  group0.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
255
257
  }
256
258
  }
257
- var group1 = $('<optgroup/>', { label: "sequence rules" }).appendTo(selectField);
259
+ var group1 = $('<optgroup/>', { label: RED._("node-red:switch.label.sequence-rules") }).appendTo(selectField);
258
260
  for (var d in operators) {
259
261
  if(operators[d].kind === 'S') {
260
262
  group1.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
@@ -340,9 +342,12 @@
340
342
  row3.hide();
341
343
  }
342
344
  var selectedLabel = selectField.find("option:selected").text();
343
- if (selectedLabel.length <= 5) {
345
+
346
+ textSpan.text(selectedLabel);
347
+ var width = textSpan.width();
348
+ if (width <= 30) {
344
349
  selectField.outerWidth(60);
345
- } else if (selectedLabel.length < 12) {
350
+ } else if (width <= 85) {
346
351
  selectField.outerWidth(120);
347
352
  } else {
348
353
  selectField.width("auto")
@@ -44,6 +44,14 @@ module.exports = function(RED) {
44
44
  return undefined;
45
45
  }
46
46
 
47
+ function parseEnv(key) {
48
+ var match = /^env\.(.+)/.exec(key);
49
+ if (match) {
50
+ return match[1];
51
+ }
52
+ return undefined;
53
+ }
54
+
47
55
  /**
48
56
  * Custom Mustache Context capable to collect message property and node
49
57
  * flow and global context
@@ -74,6 +82,11 @@ module.exports = function(RED) {
74
82
  return value;
75
83
  }
76
84
 
85
+ // try env
86
+ if (parseEnv(name)) {
87
+ return this.cachedContextTokens[name];
88
+ }
89
+
77
90
  // try flow/global context:
78
91
  var context = parseContext(name);
79
92
  if (context) {
@@ -156,6 +169,17 @@ module.exports = function(RED) {
156
169
  var tokens = extractTokens(mustache.parse(template));
157
170
  var resolvedTokens = {};
158
171
  tokens.forEach(function(name) {
172
+ var env_name = parseEnv(name);
173
+ if (env_name) {
174
+ var promise = new Promise((resolve, reject) => {
175
+ var val = RED.util.evaluateNodeProperty(env_name, 'env', node)
176
+ resolvedTokens[name] = val;
177
+ resolve();
178
+ });
179
+ promises.push(promise);
180
+ return;
181
+ }
182
+
159
183
  var context = parseContext(name);
160
184
  if (context) {
161
185
  var type = context.type;
@@ -275,18 +275,22 @@ module.exports = function(RED) {
275
275
  if (msg.hasOwnProperty("flush")) {
276
276
  var len = node.buffer.length;
277
277
  if (typeof(msg.flush) == 'number') { len = Math.min(Math.floor(msg.flush),len); }
278
- while (len > 0) {
279
- const msgInfo = node.buffer.shift();
280
- if (Object.keys(msgInfo.msg).length > 1) {
281
- node.send(msgInfo.msg);
282
- msgInfo.done();
283
- }
284
- len = len - 1;
285
- }
286
- if (node.buffer.length === 0) {
278
+ if (len === 0) {
287
279
  clearInterval(node.intervalID);
288
280
  node.intervalID = -1;
289
281
  }
282
+ else {
283
+ while (len > 0) {
284
+ const msgInfo = node.buffer.shift();
285
+ if (Object.keys(msgInfo.msg).length > 1) {
286
+ node.send(msgInfo.msg);
287
+ msgInfo.done();
288
+ }
289
+ len = len - 1;
290
+ }
291
+ clearInterval(node.intervalID);
292
+ node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
293
+ }
290
294
  node.status({fill:"blue",shape:"dot",text:node.buffer.length});
291
295
  done();
292
296
  }
@@ -453,6 +453,7 @@ module.exports = function(RED) {
453
453
  node.options = {};
454
454
  node.queue = [];
455
455
  node.subscriptions = {};
456
+ node.clientListeners = []
456
457
  /** @type {mqtt.MqttClient}*/ this.client;
457
458
  node.setOptions = function(opts, init) {
458
459
  if(!opts || typeof opts !== "object") {
@@ -591,7 +592,7 @@ module.exports = function(RED) {
591
592
  // Only for ws or wss, check if proxy env var for additional configuration
592
593
  if (node.brokerurl.indexOf("wss://") > -1 || node.brokerurl.indexOf("ws://") > -1) {
593
594
  // check if proxy is set in env
594
- let prox, noprox;
595
+ let prox, noprox, noproxy;
595
596
  if (process.env.http_proxy) { prox = process.env.http_proxy; }
596
597
  if (process.env.HTTP_PROXY) { prox = process.env.HTTP_PROXY; }
597
598
  if (process.env.no_proxy) { noprox = process.env.no_proxy.split(","); }
@@ -718,11 +719,16 @@ module.exports = function(RED) {
718
719
  setStatusConnecting(node, true);
719
720
  try {
720
721
  node.serverProperties = {};
722
+ if(node.client) {
723
+ //belt and braces to avoid left over clients
724
+ node.client.end(true);
725
+ node._clientRemoveListeners();
726
+ }
721
727
  node.client = mqtt.connect(node.brokerurl, node.options);
722
728
  node.client.setMaxListeners(0);
723
- let callbackDone = false; //prevent re-connects causing node.client.on('connect' firing callback multiple times
729
+ let callbackDone = false; //prevent re-connects causing node._clientOn('connect' firing callback multiple times
724
730
  // Register successful connect or reconnect handler
725
- node.client.on('connect', function (connack) {
731
+ node._clientOn('connect', function (connack) {
726
732
  node.closing = false;
727
733
  node.connecting = false;
728
734
  node.connected = true;
@@ -754,7 +760,7 @@ module.exports = function(RED) {
754
760
  }
755
761
  setStatusConnected(node, true);
756
762
  // Remove any existing listeners before resubscribing to avoid duplicates in the event of a re-connection
757
- node.client.removeAllListeners('message');
763
+ node._clientRemoveListeners('message');
758
764
 
759
765
  // Re-subscribe to stored topics
760
766
  for (var s in node.subscriptions) {
@@ -766,7 +772,7 @@ module.exports = function(RED) {
766
772
  if (node.subscriptions[s].hasOwnProperty(r)) {
767
773
  qos = Math.max(qos,node.subscriptions[s][r].qos);
768
774
  _options = node.subscriptions[s][r].options;
769
- node.client.on('message',node.subscriptions[s][r].handler);
775
+ node._clientOn('message',node.subscriptions[s][r].handler);
770
776
  }
771
777
  }
772
778
  _options.qos = _options.qos || qos;
@@ -779,11 +785,11 @@ module.exports = function(RED) {
779
785
  node.publish(node.birthMessage);
780
786
  }
781
787
  });
782
- node.client.on("reconnect", function() {
788
+ node._clientOn("reconnect", function() {
783
789
  setStatusConnecting(node, true);
784
790
  });
785
791
  //Broker Disconnect - V5 event
786
- node.client.on("disconnect", function(packet) {
792
+ node._clientOn("disconnect", function(packet) {
787
793
  //Emitted after receiving disconnect packet from broker. MQTT 5.0 feature.
788
794
  const rc = (packet && packet.properties && packet.reasonCode) || packet.reasonCode;
789
795
  const rs = packet && packet.properties && packet.properties.reasonString || "";
@@ -797,7 +803,7 @@ module.exports = function(RED) {
797
803
  setStatusDisconnected(node, true);
798
804
  });
799
805
  // Register disconnect handlers
800
- node.client.on('close', function () {
806
+ node._clientOn('close', function () {
801
807
  if (node.connected) {
802
808
  node.connected = false;
803
809
  node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
@@ -809,7 +815,7 @@ module.exports = function(RED) {
809
815
 
810
816
  // Register connect error handler
811
817
  // The client's own reconnect logic will take care of errors
812
- node.client.on('error', function (error) {
818
+ node._clientOn('error', function (error) {
813
819
  });
814
820
  }catch(err) {
815
821
  console.log(err);
@@ -822,7 +828,7 @@ module.exports = function(RED) {
822
828
  if(node.connected || node.connecting) {
823
829
  setStatusDisconnected(node, true);
824
830
  }
825
- if(node.client) { node.client.removeAllListeners(); }
831
+ if(node.client) { node._clientRemoveListeners(); }
826
832
  node.connecting = false;
827
833
  node.connected = false;
828
834
  callback && typeof callback == "function" && callback();
@@ -836,8 +842,12 @@ module.exports = function(RED) {
836
842
  if(!client) {
837
843
  resolve();
838
844
  } else {
839
- const t = setTimeout(reject, ms);
840
- client.end(() => {
845
+ const t = setTimeout(() => {
846
+ //clean end() has exceeded WAIT_END, lets force end!
847
+ client && client.end(true);
848
+ reject();
849
+ }, ms);
850
+ client.end(() => {
841
851
  clearTimeout(t);
842
852
  resolve()
843
853
  });
@@ -894,7 +904,7 @@ module.exports = function(RED) {
894
904
  };
895
905
  node.subscriptions[topic][ref] = sub;
896
906
  if (node.connected) {
897
- node.client.on('message',sub.handler);
907
+ node._clientOn('message',sub.handler);
898
908
  node.client.subscribe(topic, options);
899
909
  }
900
910
  };
@@ -905,7 +915,7 @@ module.exports = function(RED) {
905
915
  if (sub) {
906
916
  if (sub[ref]) {
907
917
  if(node.client) {
908
- node.client.removeListener('message',sub[ref].handler);
918
+ node._clientRemoveListeners('message',sub[ref].handler);
909
919
  }
910
920
  delete sub[ref];
911
921
  }
@@ -995,13 +1005,40 @@ module.exports = function(RED) {
995
1005
 
996
1006
  node.on('close', function(done) {
997
1007
  node.disconnect(function() {
998
- if(node.client) {
999
- node.client.removeAllListeners();
1000
- }
1001
1008
  done();
1002
1009
  });
1003
1010
  });
1004
1011
 
1012
+ /**
1013
+ * Add event handlers to the MQTT.js client and track them so that
1014
+ * we do not remove any handlers that the MQTT client uses internally.
1015
+ * Use {@link node._clientRemoveListeners `node._clientRemoveListeners`} to remove handlers
1016
+ * @param {string} event The name of the event
1017
+ * @param {function} handler The handler for this event
1018
+ */
1019
+ node._clientOn = function(event, handler) {
1020
+ node.clientListeners.push({event, handler})
1021
+ node.client.on(event, handler)
1022
+ }
1023
+
1024
+ /**
1025
+ * Remove event handlers from the MQTT.js client & only the events
1026
+ * that we attached in {@link node._clientOn `node._clientOn`}.
1027
+ * * If `event` is omitted, then all events matching `handler` are removed
1028
+ * * If `handler` is omitted, then all events named `event` are removed
1029
+ * * If both parameters are omitted, then all events are removed
1030
+ * @param {string} [event] The name of the event (optional)
1031
+ * @param {function} [handler] The handler for this event (optional)
1032
+ */
1033
+ node._clientRemoveListeners = function(event, handler) {
1034
+ node.clientListeners = node.clientListeners.filter((l) => {
1035
+ if (event && event !== l.event) { return true; }
1036
+ if (handler && handler !== l.handler) { return true; }
1037
+ node.client.removeListener(l.event, l.handler)
1038
+ return false; //found and removed, filter out this one
1039
+ })
1040
+ }
1041
+
1005
1042
  }
1006
1043
 
1007
1044
  RED.nodes.registerType("mqtt-broker",MQTTBrokerNode,{
@@ -129,7 +129,7 @@
129
129
  var headerTypes = [
130
130
  {value:"content-type",label:"Content-Type",hasValue: false},
131
131
  {value:"location",label:"Location",hasValue: false},
132
- {value:"other",label:RED._("node-red:httpin.label.other"),icon:"red/images/typedInput/az.png"}
132
+ {value:"other",label:RED._("node-red:httpin.label.other"),icon:"red/images/typedInput/az.svg"}
133
133
  ]
134
134
  var contentTypes = [
135
135
  {value:"application/json",label:"application/json",hasValue: false},
@@ -139,7 +139,7 @@
139
139
  {value:"text/plain",label:"text/plain",hasValue: false},
140
140
  {value:"image/gif",label:"image/gif",hasValue: false},
141
141
  {value:"image/png",label:"image/png",hasValue: false},
142
- {value:"other",label:RED._("node-red:httpin.label.other"),icon:"red/images/typedInput/az.png"}
142
+ {value:"other",label:RED._("node-red:httpin.label.other"),icon:"red/images/typedInput/az.svg"}
143
143
  ];
144
144
 
145
145
  RED.nodes.registerType('http response',{
@@ -180,7 +180,7 @@
180
180
  var propertyValue = $('<input/>',{class:"node-input-header-value",type:"text",style:"width: 100%"})
181
181
  .appendTo(propertyValueCell)
182
182
  .typedInput({types:
183
- header.h === 'content-type'?contentTypes:[{value:"other",label:"other",icon:"red/images/typedInput/az.png"}]
183
+ header.h === 'content-type'?contentTypes:[{value:"other",label:"other",icon:"red/images/typedInput/az.svg"}]
184
184
  });
185
185
 
186
186
  var matchedType = headerTypes.filter(function(ht) {
@@ -223,7 +223,7 @@
223
223
  if (type === 'content-type') {
224
224
  propertyValue.typedInput('types',contentTypes);
225
225
  } else {
226
- propertyValue.typedInput('types',[{value:"other",label:"other",icon:"red/images/typedInput/az.png"}]);
226
+ propertyValue.typedInput('types',[{value:"other",label:"other",icon:"red/images/typedInput/az.svg"}]);
227
227
  }
228
228
  });
229
229
  },
@@ -127,12 +127,14 @@
127
127
  { value: "Cache-Control", label: "Cache-Control", hasValue: false },
128
128
  { value: "User-Agent", label: "User-Agent", hasValue: false },
129
129
  { value: "Location", label: "Location", hasValue: false },
130
- { value: "other", label: "other", hasValue: true, icon: "red/images/typedInput/az.png" },
130
+ { value: "other", label: RED._("node-red:httpin.label.other"),
131
+ hasValue: true, icon: "red/images/typedInput/az.svg" },
131
132
  { value: "msg", label: "msg.", hasValue: true },
132
133
  ]
133
134
  const headerOptions = {};
134
135
  const defaultOptions = [
135
- { value: "other", label: "other", hasValue: true, icon: "red/images/typedInput/az.png" },
136
+ { value: "other", label: RED._("node-red:httpin.label.other"),
137
+ hasValue: true, icon: "red/images/typedInput/az.svg" },
136
138
  { value: "msg", label: "msg.", hasValue: true },
137
139
  ];
138
140
  headerOptions["accept"] = [
@@ -435,7 +435,7 @@ module.exports = function(RED) {
435
435
  });
436
436
  }
437
437
  else {
438
- var connectedSockets = [];
438
+ const connectedSockets = new Set();
439
439
  node.status({text:RED._("tcpin.status.connections",{count:0})});
440
440
  let srv = net;
441
441
  let connOpts;
@@ -456,16 +456,16 @@ module.exports = function(RED) {
456
456
  });
457
457
  socket.on('close',function() {
458
458
  node.log(RED._("tcpin.status.connection-closed",{host:socket.remoteAddress, port:socket.remotePort}));
459
- connectedSockets.splice(connectedSockets.indexOf(socket),1);
460
- node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
459
+ connectedSockets.delete(socket);
460
+ node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
461
461
  });
462
462
  socket.on('error',function() {
463
463
  node.log(RED._("tcpin.errors.socket-error",{host:socket.remoteAddress, port:socket.remotePort}));
464
- connectedSockets.splice(connectedSockets.indexOf(socket),1);
465
- node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
464
+ connectedSockets.delete(socket);
465
+ node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
466
466
  });
467
- connectedSockets.push(socket);
468
- node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
467
+ connectedSockets.add(socket);
468
+ node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
469
469
  });
470
470
 
471
471
  node.on("input", function(msg, nodeSend, nodeDone) {
@@ -478,10 +478,10 @@ module.exports = function(RED) {
478
478
  } else {
479
479
  buffer = Buffer.from(""+msg.payload);
480
480
  }
481
- for (var i = 0; i < connectedSockets.length; i += 1) {
482
- if (node.doend === true) { connectedSockets[i].end(buffer); }
483
- else { connectedSockets[i].write(buffer); }
484
- }
481
+ connectedSockets.forEach(soc => {
482
+ if (node.doend === true) { soc.end(buffer); }
483
+ else { soc.write(buffer); }
484
+ })
485
485
  }
486
486
  nodeDone();
487
487
  });
@@ -498,12 +498,10 @@ module.exports = function(RED) {
498
498
  } else {
499
499
  node.log(RED._("tcpin.status.listening-port",{port:node.port}));
500
500
  node.on('close', function() {
501
- for (var c in connectedSockets) {
502
- if (connectedSockets.hasOwnProperty(c)) {
503
- connectedSockets[c].end();
504
- connectedSockets[c].unref();
505
- }
506
- }
501
+ connectedSockets.forEach(soc => {
502
+ soc.end();
503
+ soc.unref();
504
+ })
507
505
  server.close();
508
506
  node.log(RED._("tcpin.status.stopped-listening",{port:node.port}));
509
507
  });
@@ -89,6 +89,9 @@ module.exports = function(RED) {
89
89
  else if (msg.payload[s][t].toString().indexOf(node.sep) !== -1) { // add quotes if any "commas"
90
90
  msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
91
91
  }
92
+ else if (msg.payload[s][t].toString().indexOf("\n") !== -1) { // add quotes if any "\n"
93
+ msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
94
+ }
92
95
  }
93
96
  ou += msg.payload[s].join(node.sep) + node.ret;
94
97
  }
@@ -112,7 +115,7 @@ module.exports = function(RED) {
112
115
  q = q.replace(/"/g, '""');
113
116
  ou += node.quo + q + node.quo + node.sep;
114
117
  }
115
- else if (q.indexOf(node.sep) !== -1) { // add quotes if any "commas"
118
+ else if (q.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
116
119
  ou += node.quo + q + node.quo + node.sep;
117
120
  }
118
121
  else { ou += q + node.sep; } // otherwise just add
@@ -134,7 +137,7 @@ module.exports = function(RED) {
134
137
  p = p.replace(/"/g, '""');
135
138
  ou += node.quo + p + node.quo + node.sep;
136
139
  }
137
- else if (p.indexOf(node.sep) !== -1) { // add quotes if any "commas"
140
+ else if (p.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
138
141
  ou += node.quo + p + node.quo + node.sep;
139
142
  }
140
143
  else { ou += p + node.sep; } // otherwise just add
@@ -247,7 +247,7 @@
247
247
  var jsonata_or_empty = {
248
248
  value: "jsonata",
249
249
  label: "expression",
250
- icon: "red/images/typedInput/expr.png",
250
+ icon: "red/images/typedInput/expr.svg",
251
251
  validate: function(v) {
252
252
  try{
253
253
  if(v !== "") {
@@ -314,11 +314,13 @@ module.exports = function(RED) {
314
314
  if (err) {
315
315
  return done(err);
316
316
  }
317
- msgInfo.send({payload: result});
317
+ msgInfo.msg.payload = result;
318
+ msgInfo.send(msgInfo.msg);
318
319
  done();
319
320
  });
320
321
  } else {
321
- msgInfo.send({payload: result});
322
+ msgInfo.msg.payload = result;
323
+ msgInfo.send(msgInfo.msg);
322
324
  done();
323
325
  }
324
326
  } else {