@node-red/nodes 3.0.0-beta.2 → 3.0.0

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.
@@ -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) {
@@ -245,44 +245,37 @@
245
245
  // complete parentage of the node that generated this message.
246
246
  // flow-id/subflow-A-instance/subflow-B-instance
247
247
 
248
- // If it has one id, that is a top level flow
248
+ // If it has one id, that is a top level flow or config node/global
249
249
  // each subsequent id is the instance id of a subflow node
250
250
  //
251
251
  pathParts = o.path.split("/");
252
252
  if (pathParts.length === 1) {
253
- // The source node is on a flow - so can use its id to find
253
+ // The source node is on a flow or is a global/config - so can use its id to find
254
254
  sourceNode = RED.nodes.node(o.id);
255
255
  } else if (pathParts.length > 1) {
256
256
  // Highlight the subflow instance node.
257
257
  sourceNode = RED.nodes.node(pathParts[1]);
258
258
  }
259
+ const getNodeLabel = (n) => n.name || (typeof n.label === "function" && n.label()) || (typeof n.label === "string" && n.label) || (n.type + ":" + n.id);
259
260
  pathHierarchy = pathParts.map((id,index) => {
260
261
  if (index === 0) {
261
- return {
262
- id: id,
263
- label: RED.nodes.workspace(id).label
264
- }
262
+ if (id === "global") {
263
+ return { id: sourceNode.id, label: getNodeLabel(sourceNode) }
264
+ }
265
+ return { id: id, label: RED.nodes.workspace(id).label } //flow id + name
265
266
  } else {
266
- var instanceNode = RED.nodes.node(id)
267
- return {
268
- id: id,
269
- label: (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
270
- }
267
+ const instanceNode = RED.nodes.node(id)
268
+ const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
269
+ return { id: id, label: pathLabel }
271
270
  }
272
271
  })
273
- if (pathParts.length === 1) {
274
- pathHierarchy.push({
275
- id: o.id,
276
- label: sourceNode.name || sourceNode.type+":"+sourceNode.id
277
- })
272
+ if (pathParts.length === 1 && pathParts[0] !== "global") {
273
+ pathHierarchy.push({ id: o.id, label: getNodeLabel(sourceNode) })
278
274
  }
279
275
  if (o._alias) {
280
276
  let aliasNode = RED.nodes.node(o._alias)
281
277
  if (aliasNode) {
282
- pathHierarchy.push({
283
- id: o._alias,
284
- label: aliasNode.name || aliasNode.type+":"+aliasNode.id
285
- })
278
+ pathHierarchy.push({ id: o._alias, label: getNodeLabel(aliasNode) })
286
279
  }
287
280
  }
288
281
  } else {
@@ -499,7 +492,7 @@
499
492
  types:['msg', fullType, "jsonata"],
500
493
  typeField: $("#node-input-targetType")
501
494
  });
502
- if (this.targetType === "jsonata") {
495
+ if (this.targetType === "jsonata") {
503
496
  var property = this.complete || "";
504
497
  $("#node-input-typed-complete").typedInput('type','jsonata');
505
498
  $("#node-input-typed-complete").typedInput('value',property);
@@ -558,7 +551,7 @@
558
551
  onadd: function() {
559
552
  if (this.name === '_DEFAULT_') {
560
553
  this.name = ''
561
- RED.actions.invoke("core:generate-node-names", this)
554
+ RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
562
555
  }
563
556
  }
564
557
  });
@@ -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]);
@@ -29,23 +29,23 @@ module.exports = function(RED) {
29
29
  "use strict";
30
30
  const crypto = require("crypto");
31
31
  const targetCache = (function () {
32
- const registry = { id: {}, name: {} };
33
- function getIndex(/** @type {[LinkTarget]}*/ targets, id) {
32
+ let registry = { id: {}, name: {} }
33
+ function getIndex (/** @type {[LinkTarget]} */ targets, id) {
34
34
  for (let index = 0; index < (targets || []).length; index++) {
35
- const element = targets[index];
35
+ const element = targets[index]
36
36
  if (element.id === id) {
37
- return index;
37
+ return index
38
38
  }
39
39
  }
40
- return -1;
40
+ return -1
41
41
  }
42
42
  /**
43
43
  * Generate a target object from a node
44
- * @param {LinkInNode} node
44
+ * @param {LinkInNode} node
45
45
  * @returns {LinkTarget} a link target object
46
46
  */
47
- function generateTarget(node) {
48
- const isSubFlow = node._flow.TYPE === "subflow";
47
+ function generateTarget (node) {
48
+ const isSubFlow = node._flow.TYPE === 'subflow'
49
49
  return {
50
50
  id: node.id,
51
51
  name: node.name || node.id,
@@ -58,75 +58,72 @@ module.exports = function(RED) {
58
58
  /**
59
59
  * Get a list of targets registerd to this name
60
60
  * @param {string} name Name of the target
61
- * @param {boolean} [excludeSubflows] set `true` to exclude
61
+ * @param {boolean} [excludeSubflows] set `true` to exclude
62
62
  * @returns {[LinkTarget]} Targets registerd to this name.
63
63
  */
64
- getTargets(name, excludeSubflows) {
65
- const targets = registry.name[name] || [];
64
+ getTargets (name, excludeSubflows) {
65
+ const targets = registry.name[name] || []
66
66
  if (excludeSubflows) {
67
- return targets.filter(e => e.isSubFlow != true);
67
+ return targets.filter(e => e.isSubFlow !== true)
68
68
  }
69
- return targets;
69
+ return targets
70
70
  },
71
71
  /**
72
72
  * Get a single target by registered name.
73
73
  * To restrict to a single flow, include the `flowId`
74
74
  * If there is no targets OR more than one target, null is returned
75
75
  * @param {string} name Name of the node
76
- * @param {string} [flowId]
76
+ * @param {string} [flowId]
77
77
  * @returns {LinkTarget} target
78
78
  */
79
- getTarget(name, flowId) {
80
- /** @type {[LinkTarget]}*/
81
- let possibleTargets = this.getTargets(name);
82
- /** @type {LinkTarget}*/
83
- let target;
79
+ getTarget (name, flowId) {
80
+ /** @type {[LinkTarget]} */
81
+ let possibleTargets = this.getTargets(name)
82
+ /** @type {LinkTarget} */
83
+ let target
84
84
  if (possibleTargets.length && flowId) {
85
- possibleTargets = possibleTargets.filter(e => e.flowId == flowId);
85
+ possibleTargets = possibleTargets.filter(e => e.flowId === flowId)
86
86
  }
87
87
  if (possibleTargets.length === 1) {
88
- target = possibleTargets[0];
88
+ target = possibleTargets[0]
89
89
  }
90
- return target;
90
+ return target
91
91
  },
92
92
  /**
93
93
  * Get a target by node ID
94
94
  * @param {string} nodeId ID of the node
95
95
  * @returns {LinkTarget} target
96
96
  */
97
- getTargetById(nodeId) {
98
- return registry.id[nodeId];
97
+ getTargetById (nodeId) {
98
+ return registry.id[nodeId]
99
99
  },
100
- register(/** @type {LinkInNode} */ node) {
101
- const target = generateTarget(node);
102
- const tByName = this.getTarget(target.name, target.flowId);
100
+ register (/** @type {LinkInNode} */ node) {
101
+ const target = generateTarget(node)
102
+ const tByName = this.getTarget(target.name, target.flowId)
103
103
  if (!tByName || tByName.id !== target.id) {
104
- registry.name[target.name] = registry.name[target.name] || [];
104
+ registry.name[target.name] = registry.name[target.name] || []
105
105
  registry.name[target.name].push(target)
106
106
  }
107
- registry.id[target.id] = target;
108
- return target;
107
+ registry.id[target.id] = target
108
+ return target
109
109
  },
110
- remove(node) {
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
- }
110
+ remove (node) {
111
+ const target = generateTarget(node)
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[target.name]
122
119
  }
123
- delete registry.id[target.id];
120
+ delete registry.id[target.id]
124
121
  },
125
- clear() {
126
- registry = { id: {}, name: {} };
122
+ clear () {
123
+ registry = { id: {}, name: {} }
127
124
  }
128
125
  }
129
- })();
126
+ })()
130
127
 
131
128
  function LinkInNode(n) {
132
129
  RED.nodes.createNode(this,n);
@@ -459,30 +459,38 @@ RED.debug = (function() {
459
459
  function showMessageMenu(button,dbgMessage,sourceId) {
460
460
  activeMenuMessage = dbgMessage;
461
461
  if (!menuOptionMenu) {
462
- menuOptionMenu = RED.menu.init({id:"red-ui-debug-msg-option-menu",
463
- options: [
464
- {id:"red-ui-debug-msg-menu-item-collapse",label:RED._("node-red:debug.messageMenu.collapseAll"),onselect:function(){
465
- activeMenuMessage.collapse();
466
- }},
462
+ var opts = [
463
+ {id:"red-ui-debug-msg-menu-item-collapse",label:RED._("node-red:debug.messageMenu.collapseAll"),onselect:function(){
464
+ activeMenuMessage.collapse();
465
+ }},
466
+ ];
467
+ if (activeMenuMessage.clearPinned) {
468
+ opts.push(
467
469
  {id:"red-ui-debug-msg-menu-item-clear-pins",label:RED._("node-red:debug.messageMenu.clearPinned"),onselect:function(){
468
470
  activeMenuMessage.clearPinned();
469
471
  }},
470
- null,
471
- {id:"red-ui-debug-msg-menu-item-filter", label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
472
- var candidateNodes = RED.nodes.filterNodes({type:'debug'});
473
- candidateNodes.forEach(function(n) {
474
- filteredNodes[n.id] = true;
475
- });
476
- delete filteredNodes[sourceId];
477
- $("#red-ui-sidebar-debug-filterSelected").trigger("click");
478
- RED.settings.set('debug.filteredNodes',Object.keys(filteredNodes))
479
- refreshMessageList();
480
- }},
481
- {id:"red-ui-debug-msg-menu-item-clear-filter",label:RED._("node-red:debug.messageMenu.clearFilter"),onselect:function(){
482
- $("#red-ui-sidebar-debug-filterAll").trigger("click");
483
- refreshMessageList();
484
- }}
485
- ]
472
+ );
473
+ }
474
+ opts.push(
475
+ null,
476
+ {id:"red-ui-debug-msg-menu-item-filter", label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
477
+ var candidateNodes = RED.nodes.filterNodes({type:'debug'});
478
+ candidateNodes.forEach(function(n) {
479
+ filteredNodes[n.id] = true;
480
+ });
481
+ delete filteredNodes[sourceId];
482
+ $("#red-ui-sidebar-debug-filterSelected").trigger("click");
483
+ RED.settings.set('debug.filteredNodes',Object.keys(filteredNodes))
484
+ refreshMessageList();
485
+ }},
486
+ {id:"red-ui-debug-msg-menu-item-clear-filter",label:RED._("node-red:debug.messageMenu.clearFilter"),onselect:function(){
487
+ $("#red-ui-sidebar-debug-filterAll").trigger("click");
488
+ refreshMessageList();
489
+ }}
490
+ );
491
+
492
+ menuOptionMenu = RED.menu.init({id:"red-ui-debug-msg-option-menu",
493
+ options: opts
486
494
  });
487
495
  menuOptionMenu.css({
488
496
  position: "absolute"
@@ -582,7 +590,7 @@ RED.debug = (function() {
582
590
  $('<span class="red-ui-debug-msg-date">'+ getTimestamp()+'</span>').appendTo(metaRow);
583
591
  if (sourceNode) {
584
592
 
585
- var nodeLink = $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text("node: "+(o.name||sourceNode.name||sourceNode.id))
593
+ var nodeLink = $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text(RED._("node-red:debug.node")+": "+(o.name||sourceNode.name||sourceNode.id))
586
594
  .appendTo(metaRow)
587
595
  .on("click", function(evt) {
588
596
  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
  });
@@ -168,9 +168,9 @@ module.exports = function(RED) {
168
168
  return getFromValueType(RED.util.getMessageProperty(msg,rule.from),done);
169
169
  } else if (rule.fromt === 'flow' || rule.fromt === 'global') {
170
170
  var contextKey = RED.util.parseContextStore(rule.from);
171
- if (/\[msg\./.test(context.key)) {
171
+ if (/\[msg\./.test(contextKey.key)) {
172
172
  // The key has a nest msg. reference to evaluate first
173
- context.key = RED.util.normalisePropertyExpression(contextKey.key,msg,true);
173
+ contextKey.key = RED.util.normalisePropertyExpression(contextKey.key,msg,true);
174
174
  }
175
175
  node.context()[rule.fromt].get(contextKey.key, contextKey.store, (err,fromValue) => {
176
176
  if (err) {
@@ -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
  }
@@ -592,7 +592,7 @@ module.exports = function(RED) {
592
592
  // Only for ws or wss, check if proxy env var for additional configuration
593
593
  if (node.brokerurl.indexOf("wss://") > -1 || node.brokerurl.indexOf("ws://") > -1) {
594
594
  // check if proxy is set in env
595
- let prox, noprox;
595
+ let prox, noprox, noproxy;
596
596
  if (process.env.http_proxy) { prox = process.env.http_proxy; }
597
597
  if (process.env.HTTP_PROXY) { prox = process.env.HTTP_PROXY; }
598
598
  if (process.env.no_proxy) { noprox = process.env.no_proxy.split(","); }
@@ -215,6 +215,7 @@ module.exports = function(RED) {
215
215
  delete listenerNodes[node.fullPath];
216
216
  node.server.close();
217
217
  node._inputNodes = [];
218
+ done();
218
219
  }
219
220
  else {
220
221
  node.closing = true;
@@ -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
@@ -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 {
@@ -198,8 +198,8 @@
198
198
  category: 'storage',
199
199
  defaults: {
200
200
  name: {value:""},
201
- filename: {value:"filename"},
202
- filenameType: {value:"msg"},
201
+ filename: {value:""},
202
+ filenameType: {value:"str"},
203
203
  appendNewline: {value:true},
204
204
  createDir: {value:false},
205
205
  overwriteFile: {value:"false"},
@@ -236,8 +236,8 @@
236
236
  label: node._("file.encoding.setbymsg")
237
237
  }).text(label).appendTo(encSel);
238
238
  $("#node-input-filename").typedInput({
239
- default: "msg",
240
- types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"],
239
+ default: "str",
240
+ types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
241
241
  typeField: $("#node-input-filenameType")
242
242
  });
243
243
  if(typeof node.filenameType == 'undefined') {
@@ -297,8 +297,8 @@
297
297
  category: 'storage',
298
298
  defaults: {
299
299
  name: {value:""},
300
- filename: {value:"filename"},
301
- filenameType: {value:"msg"},
300
+ filename: {value:""},
301
+ filenameType: {value:"str"},
302
302
  format: {value:"utf8"},
303
303
  chunk: {value:false},
304
304
  sendError: {value: false},
@@ -341,8 +341,8 @@
341
341
  label: label
342
342
  }).text(label).appendTo(encSel);
343
343
  $("#node-input-filename").typedInput({
344
- default: "msg",
345
- types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"],
344
+ default: "str",
345
+ types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
346
346
  typeField: $("#node-input-filenameType")
347
347
  });
348
348
  if(typeof node.filenameType == 'undefined') {