@node-red/nodes 2.2.2 → 3.0.0-beta.3

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.
Files changed (55) hide show
  1. package/99-sample.html.demo +1 -1
  2. package/core/common/05-junction.html +5 -0
  3. package/core/common/05-junction.js +12 -0
  4. package/core/common/20-inject.html +25 -13
  5. package/core/common/20-inject.js +3 -2
  6. package/core/common/21-debug.html +58 -5
  7. package/core/common/21-debug.js +57 -27
  8. package/core/common/60-link.html +65 -29
  9. package/core/common/60-link.js +169 -20
  10. package/core/common/lib/debug/debug-utils.js +34 -1
  11. package/core/function/10-function.html +58 -22
  12. package/core/function/10-switch.html +19 -12
  13. package/core/function/10-switch.js +1 -0
  14. package/core/function/15-change.html +40 -12
  15. package/core/function/16-range.html +14 -5
  16. package/core/function/80-template.html +16 -12
  17. package/core/function/89-delay.html +46 -6
  18. package/core/function/89-trigger.html +12 -4
  19. package/core/function/rbe.html +7 -3
  20. package/core/network/05-tls.html +10 -4
  21. package/core/network/06-httpproxy.html +10 -1
  22. package/core/network/10-mqtt.html +73 -17
  23. package/core/network/10-mqtt.js +239 -91
  24. package/core/network/21-httpin.html +10 -6
  25. package/core/network/21-httprequest.html +219 -12
  26. package/core/network/21-httprequest.js +98 -17
  27. package/core/network/22-websocket.html +19 -5
  28. package/core/network/22-websocket.js +16 -13
  29. package/core/network/31-tcpin.html +47 -10
  30. package/core/network/31-tcpin.js +23 -20
  31. package/core/network/32-udp.html +14 -2
  32. package/core/parsers/70-CSV.html +4 -1
  33. package/core/parsers/70-JSON.html +3 -2
  34. package/core/parsers/70-XML.html +2 -1
  35. package/core/parsers/70-YAML.html +2 -1
  36. package/core/sequence/17-split.html +6 -2
  37. package/core/sequence/19-batch.html +28 -4
  38. package/core/storage/10-file.html +66 -6
  39. package/core/storage/10-file.js +46 -3
  40. package/core/storage/23-watch.html +2 -1
  41. package/core/storage/23-watch.js +21 -43
  42. package/locales/de/messages.json +1 -0
  43. package/locales/en-US/common/60-link.html +19 -3
  44. package/locales/en-US/messages.json +136 -83
  45. package/locales/en-US/network/21-httprequest.html +1 -1
  46. package/locales/en-US/storage/10-file.html +6 -2
  47. package/locales/ja/common/60-link.html +13 -0
  48. package/locales/ja/messages.json +85 -32
  49. package/locales/ja/network/21-httprequest.html +1 -1
  50. package/locales/ja/storage/10-file.html +8 -6
  51. package/locales/ko/messages.json +1 -0
  52. package/locales/ru/messages.json +1 -0
  53. package/locales/zh-CN/messages.json +1 -0
  54. package/locales/zh-TW/messages.json +1 -0
  55. package/package.json +13 -13
@@ -18,7 +18,7 @@
18
18
  <option value="handlebars">mustache</option>
19
19
  <option value="html">HTML</option>
20
20
  <option value="json">JSON</option>
21
- <option value="javascript">Javascript</option>
21
+ <option value="javascript">JavaScript</option>
22
22
  <option value="css">CSS</option>
23
23
  <option value="markdown">Markdown</option>
24
24
  <option value="python">Python</option>
@@ -56,7 +56,9 @@
56
56
  category: 'function',
57
57
  defaults: {
58
58
  name: {value:""},
59
- field: {value:"payload", validate:RED.validators.typedInput("fieldType")},
59
+ field: {value:"payload",
60
+ label:"payload",
61
+ validate:RED.validators.typedInput("fieldType", false)},
60
62
  fieldType: {value:"msg"},
61
63
  format: {value:"handlebars"},
62
64
  syntax: {value:"mustache"},
@@ -73,7 +75,8 @@
73
75
  return this.name?"node_label_italic":"";
74
76
  },
75
77
  oneditprepare: function() {
76
- var that = this;
78
+ const that = this;
79
+ const stateId = RED.editor.generateViewStateId("node", this, "");
77
80
  if (!this.field) {
78
81
  this.field = 'payload';
79
82
  $("#node-input-field").val("payload");
@@ -90,10 +93,10 @@
90
93
  types: ['msg','flow','global'],
91
94
  typeField: $("#node-input-fieldType")
92
95
  });
93
-
94
96
  this.editor = RED.editor.createEditor({
95
97
  id: 'node-input-template-editor',
96
98
  mode: 'ace/mode/html',
99
+ stateId: stateId,
97
100
  value: $("#node-input-template").val()
98
101
  });
99
102
  RED.library.create({
@@ -103,7 +106,6 @@
103
106
  fields:['name','format','output','syntax'],
104
107
  ext: "txt"
105
108
  });
106
- this.editor.focus();
107
109
 
108
110
  $("#node-input-format").on("change", function() {
109
111
  var mod = "ace/mode/"+$("#node-input-format").val();
@@ -113,20 +115,22 @@
113
115
  });
114
116
  });
115
117
  RED.popover.tooltip($("#node-template-expand-editor"), RED._("node-red:common.label.expand"));
116
- $("#node-template-expand-editor").on("click", function(e) {
118
+ $("#node-template-expand-editor").on("click", function (e) {
117
119
  e.preventDefault();
118
- var value = that.editor.getValue();
120
+ const value = that.editor.getValue();
121
+ that.editor.saveView();
119
122
  RED.editor.editText({
120
123
  mode: $("#node-input-format").val(),
121
124
  value: value,
125
+ stateId: stateId,
122
126
  width: "Infinity",
123
- cursor: that.editor.getCursorPosition(),
124
- complete: function(v,cursor) {
127
+ focus: true,
128
+ complete: function (v, cursor) {
125
129
  that.editor.setValue(v, -1);
126
- that.editor.gotoLine(cursor.row+1,cursor.column,false);
127
- setTimeout(function() {
130
+ setTimeout(function () {
131
+ that.editor.restoreView();
128
132
  that.editor.focus();
129
- },300);
133
+ }, 250);
130
134
  }
131
135
  })
132
136
  })
@@ -111,14 +111,54 @@
111
111
  defaults: {
112
112
  name: {value:""},
113
113
  pauseType: {value:"delay", required:true},
114
- timeout: {value:"5", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
114
+ timeout: {
115
+ value:"5", required:true,
116
+ label:RED._("node-red:delay.label.delay"),
117
+ validate:function(v,opt) {
118
+ if (RED.validators.number(v) && (v >= 0)) {
119
+ return true;
120
+ }
121
+ return RED._("node-red:delay.errors.invalid-timeout");
122
+ }},
115
123
  timeoutUnits: {value:"seconds"},
116
- rate: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
117
- nbRateUnits: {value:"1", required:false,
118
- validate:function(v) { return v === undefined || (RED.validators.number(v) && (v >= 0)); }},
124
+ rate: {
125
+ value:"1",
126
+ required:true,
127
+ label:RED._("node-red:delay.label.rate"),
128
+ validate:function(v,opt) {
129
+ if (RED.validators.number(v) && (v >= 0)) {
130
+ return true;
131
+ }
132
+ return RED._("node-red:delay.errors.invalid-rate");
133
+ }
134
+ },
135
+ nbRateUnits: {
136
+ value:"1",
137
+ required:false,
138
+ validate:function(v,opt) {
139
+ if (v === undefined || (RED.validators.number(v) && (v >= 0))) {
140
+ return true;
141
+ }
142
+ return RED._("node-red:delay.errors.invalid-rate-unit");
143
+ }
144
+ },
119
145
  rateUnits: {value: "second"},
120
- randomFirst: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
121
- randomLast: {value:"5", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
146
+ randomFirst: {
147
+ value:"1", required:true,
148
+ validate:function(v,opt) {
149
+ if (RED.validators.number(v) && (v >= 0)) {
150
+ return true;
151
+ }
152
+ return RED._("node-red:delay.errors.invalid-random-first");
153
+ }},
154
+ randomLast: {
155
+ value:"5", required:true,
156
+ validate:function(v,opt) {
157
+ if (RED.validators.number(v) && (v >= 0)) {
158
+ return true;
159
+ }
160
+ return RED._("node-red:delay.errors.invalid-random-last");
161
+ }},
122
162
  randomUnits: {value: "seconds"},
123
163
  drop: {value:false},
124
164
  allowrate: {value:false},
@@ -87,17 +87,25 @@
87
87
  color:"#E6E0F8",
88
88
  defaults: {
89
89
  name: {value:""},
90
- op1: {value:"1", validate: RED.validators.typedInput("op1type")},
91
- op2: {value:"0", validate: RED.validators.typedInput("op2type")},
90
+ op1: {value:"1",
91
+ label: RED._("node-red:trigger.send"),
92
+ validate: RED.validators.typedInput("op1type", false)},
93
+ op2: {value:"0",
94
+ label: RED._("node-red:trigger.then-send"),
95
+ validate: RED.validators.typedInput("op2type", false)},
92
96
  op1type: {value:"val"},
93
97
  op2type: {value:"val"},
94
- duration: {value:"250",required:true,validate:RED.validators.number()},
98
+ duration: {
99
+ value:"250", required:true,
100
+ label:RED._("node-red:trigger.label.duration"),
101
+ validate:RED.validators.number(false)},
95
102
  extend: {value:"false"},
96
103
  overrideDelay: {value:"false"},
97
104
  units: {value:"ms"},
98
105
  reset: {value:""},
99
106
  bytopic: {value:"all"},
100
- topic: {value:"topic",required:true},
107
+ topic: {value:"topic", required:true,
108
+ label:RED._("node-red:trigger.label.topic")},
101
109
  outputs: {value:1}
102
110
  },
103
111
  inputs:1,
@@ -49,12 +49,16 @@
49
49
  defaults: {
50
50
  name: {value:""},
51
51
  func: {value:"rbe"},
52
- gap: {value:"",validate:RED.validators.regex(/^(\d*[.]*\d*|)(%|)$/)},
52
+ gap: {value:"",
53
+ label: RED._("node-red:rbe.label.gap"),
54
+ validate:RED.validators.regex(/^(\d*[.]*\d*|)(%|)$/)},
53
55
  start: {value:""},
54
56
  inout: {value:"out"},
55
57
  septopics: {value:true},
56
- property: {value:"payload",required:true},
57
- topi: {value:"topic",required:true}
58
+ property: {value:"payload", required:true,
59
+ label:RED._("node-red:rbe.label.property")},
60
+ topi: {value:"topic", required:true,
61
+ label:RED._("node-red:rbe.label.topic")}
58
62
  },
59
63
  inputs:1,
60
64
  outputs:1,
@@ -83,19 +83,25 @@
83
83
  category: 'config',
84
84
  defaults: {
85
85
  name: {value:""},
86
- cert: {value:"", validate: function(v) {
86
+ cert: {value:"", validate: function(v,opt) {
87
87
  var currentKey = $("#node-config-input-key").val();
88
88
  if (currentKey === undefined) {
89
89
  currentKey = this.key;
90
90
  }
91
- return currentKey === '' || v != '';
91
+ if (currentKey === '' || v != '') {
92
+ return true;
93
+ }
94
+ return RED._("node-red:tls.error.invalid-cert");
92
95
  }},
93
- key: {value:"", validate: function(v) {
96
+ key: {value:"", validate: function(v,opt) {
94
97
  var currentCert = $("#node-config-input-cert").val();
95
98
  if (currentCert === undefined) {
96
99
  currentCert = this.cert;
97
100
  }
98
- return currentCert === '' || v != '';
101
+ if (currentCert === '' || v != '') {
102
+ return true;
103
+ }
104
+ return RED._("node-red:tls.error.invalid-key");
99
105
  }},
100
106
  ca: {value:""},
101
107
  certname: {value:""},
@@ -50,7 +50,16 @@
50
50
  category: 'config',
51
51
  defaults: {
52
52
  name: {value:''},
53
- url: {value:'',validate:function(v) { return (v && (v.indexOf('://') !== -1) && (v.trim().indexOf('http') === 0)); }},
53
+ url: {
54
+ value:'',
55
+ validate:function(v, opt) {
56
+ if ((v && (v.indexOf('://') !== -1) &&
57
+ (v.trim().indexOf('http') === 0))) {
58
+ return true;
59
+ }
60
+ return RED._("node-red:httpin.errors.invalid-url");
61
+ }
62
+ },
54
63
  noproxy: {value:[]}
55
64
  },
56
65
  credentials: {
@@ -65,6 +65,11 @@
65
65
  /* opacity: 0.3;
66
66
  pointer-events: none; */
67
67
  }
68
+ .form-row.form-row-mqtt-datatype-tip > .form-tips {
69
+ width: calc(70% - 18px);
70
+ display: inline-block;
71
+ margin-top: -8px;
72
+ }
68
73
 
69
74
  </style>
70
75
 
@@ -121,6 +126,7 @@
121
126
  <div class="form-row">
122
127
  <label for="node-input-datatype"><i class="fa fa-sign-out"></i> <span data-i18n="mqtt.label.output"></span></label>
123
128
  <select id="node-input-datatype" style="width:70%;">
129
+ <option value="auto-detect" data-i18n="mqtt.output.auto-detect"></option>
124
130
  <option value="auto" data-i18n="mqtt.output.auto"></option>
125
131
  <option value="buffer" data-i18n="mqtt.output.buffer"></option>
126
132
  <option value="utf8" data-i18n="mqtt.output.string"></option>
@@ -128,6 +134,10 @@
128
134
  <option value="base64" data-i18n="mqtt.output.base64"></option>
129
135
  </select>
130
136
  </div>
137
+ <div class="form-row form-row-mqtt-datatype-tip">
138
+ <label> &nbsp; </label>
139
+ <div class="form-tips" id="mqtt-in-datatype-depreciated-tip"><span data-i18n="mqtt.label.auto-mode-depreciated"></span></div>
140
+ </div>
131
141
  <div class="form-row">
132
142
  <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
133
143
  <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@@ -442,44 +452,67 @@
442
452
  }
443
453
  return defaultContentType || 'none'
444
454
  }
445
-
455
+ /**
456
+ * Test a topic string is valid for publishing
457
+ * @param {string} topic
458
+ * @returns `true` if it is a valid topic
459
+ */
460
+ function validateMQTTPublishTopic(topic, opts) {
461
+ if(!topic || topic == "" || !/[\+#\b\f\n\r\t\v\0]/.test(topic)) {
462
+ return true;
463
+ }
464
+ return RED._("node-red:mqtt.errors.invalid-topic");
465
+ }
446
466
  RED.nodes.registerType('mqtt-broker',{
447
467
  category: 'config',
448
468
  defaults: {
449
469
  name: {value:""},
450
470
  broker: {value:"",required:true},
451
- port: {value:1883,required:false,validate:RED.validators.number(true)},
452
- tls: {type:"tls-config",required: false},
453
- clientid: {value:"", validate: function(v) {
471
+ port: {
472
+ value:1883,required:false,
473
+ label: RED._("node-red:mqtt.label.port"),
474
+ validate:RED.validators.number(true)},
475
+ tls: {type:"tls-config",required: false,
476
+ label:RED._("node-red:mqtt.label.use-tls") },
477
+ clientid: {value:"", validate: function(v, opt) {
478
+ var ok = false;
454
479
  if ($("#node-config-input-clientid").length) {
455
480
  // Currently editing the node
456
- return $("#node-config-input-cleansession").is(":checked") || (v||"").length > 0;
481
+ ok = $("#node-config-input-cleansession").is(":checked") || (v||"").length > 0;
457
482
  } else {
458
- return (this.cleansession===undefined || this.cleansession) || (v||"").length > 0;
483
+ ok = (this.cleansession===undefined || this.cleansession) || (v||"").length > 0;
459
484
  }
485
+ if (ok) {
486
+ return ok;
487
+ }
488
+ return RED._("node-red:mqtt.errors.invalid-client-id");
460
489
  }},
461
490
  autoConnect: {value: true},
462
491
  usetls: {value: false},
463
492
  verifyservercert: { value: false},
464
493
  compatmode: { value: false},
465
494
  protocolVersion: { value: 4},
466
- keepalive: {value:60,validate:RED.validators.number()},
495
+ keepalive: {
496
+ value:60,
497
+ label: RED._("node-red:mqtt.label.keepalive"),
498
+ validate:RED.validators.number(false)},
467
499
  cleansession: {value: true},
468
- birthTopic: {value:""},
500
+ birthTopic: {value:"", validate:validateMQTTPublishTopic},
469
501
  birthQos: {value:"0"},
470
502
  birthRetain: {value:false},
471
503
  birthPayload: {value:""},
472
504
  birthMsg: { value: {}},
473
- closeTopic: {value:""},
505
+ closeTopic: {value:"", validate:validateMQTTPublishTopic},
474
506
  closeQos: {value:"0"},
475
507
  closeRetain: {value:false},
476
508
  closePayload: {value:""},
477
509
  closeMsg: { value: {}},
478
- willTopic: {value:""},
510
+ willTopic: {value:"", validate:validateMQTTPublishTopic},
479
511
  willQos: {value:"0"},
480
512
  willRetain: {value:false},
481
513
  willPayload: {value:""},
482
514
  willMsg: { value: {}},
515
+ userProps: { value: ""},
483
516
  sessionExpiry: {value:0}
484
517
  },
485
518
  credentials: {
@@ -609,6 +642,7 @@
609
642
  default: !this.userProps ? 'none':'json',
610
643
  types: [typedInputNoneOpt, 'json']
611
644
  });
645
+ $("#node-config-input-userProps").typedInput('value',this.userProps);
612
646
  if (typeof this.keepalive === 'undefined') {
613
647
  this.keepalive = 15;
614
648
  $("#node-config-input-keepalive").val(this.keepalive);
@@ -718,6 +752,14 @@
718
752
  }
719
753
 
720
754
  if (v5) {
755
+ this.userProps = "";
756
+ const userPropsType = $("#node-config-input-userProps").typedInput("type");
757
+ if(userPropsType == "json") {
758
+ const userProps = $("#node-config-input-userProps").val();
759
+ if (userProps && typeof userProps === "string") {
760
+ this.userProps = userProps.trim();
761
+ }
762
+ }
721
763
  this.birthMsg = saveV5Message("birth");
722
764
  this.closeMsg = saveV5Message("close");
723
765
  this.willMsg = saveV5Message("will");
@@ -740,18 +782,21 @@
740
782
  name: {value:""},
741
783
  topic: {
742
784
  value:"",
743
- validate: function(v) {
785
+ validate: function(v, opt) {
744
786
  var isDynamic = this.inputs === 1;
745
787
  var topicTypeSelect = $("#node-input-topicType");
746
788
  if (topicTypeSelect.length) {
747
789
  isDynamic = topicTypeSelect.val()==='dynamic'
748
790
  }
749
- return isDynamic || ((!!v) && RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)(v));
791
+ if (isDynamic || ((!!v) && RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)(v))) {
792
+ return true;
793
+ }
794
+ return RED._("node-red:mqtt.errors.invalid-topic");
750
795
  }
751
796
  },
752
797
  qos: {value: "2"},
753
- datatype: {value:"auto",required:true},
754
- broker: {type:"mqtt-broker", required:true},
798
+ datatype: {value:"auto-detect",required:true},
799
+ broker: {type:"mqtt-broker", required:true, label:RED._("node-red:mqtt.label.broker")},
755
800
  // subscriptionIdentifier: {value:0},
756
801
  nl: {value:false},
757
802
  rap: {value:true},
@@ -787,6 +832,16 @@
787
832
  $("div.form-row-mqtt5").toggleClass("form-row-mqtt5-active",!!v5);
788
833
  $("div.form-row.form-row-mqtt-static").toggleClass("form-row-mqtt-static-disabled", !!dynamic)
789
834
  }
835
+
836
+ $("#node-input-datatype").on("change", function() {
837
+ if($(this).val() === "auto") {
838
+ $(".form-row.form-row-mqtt-datatype-tip").show();
839
+ } else {
840
+ $(".form-row.form-row-mqtt-datatype-tip").hide();
841
+ }
842
+ })
843
+ $("#node-input-datatype").trigger("change");
844
+
790
845
  $("#node-input-broker").on("change",function(d){
791
846
  updateVisibility();
792
847
  });
@@ -807,7 +862,7 @@
807
862
  $("#node-input-qos").val("2");
808
863
  }
809
864
  if (this.datatype === undefined) {
810
- $("#node-input-datatype").val("auto");
865
+ $("#node-input-datatype").val("auto-detect");
811
866
  }
812
867
  },
813
868
  oneditsave: function() {
@@ -821,7 +876,7 @@
821
876
  category: 'network',
822
877
  defaults: {
823
878
  name: {value:""},
824
- topic: {value:""},
879
+ topic: {value:"", validate:validateMQTTPublishTopic},
825
880
  qos: {value:""},
826
881
  retain: {value:""},
827
882
  respTopic: {value:""},
@@ -829,7 +884,8 @@
829
884
  userProps: {value:''},
830
885
  correl: {value:''},
831
886
  expiry: {value:''},
832
- broker: {type:"mqtt-broker", required:true}
887
+ broker: {type:"mqtt-broker", required:true,
888
+ label:RED._("node-red:mqtt.label.broker") }
833
889
  },
834
890
  color:"#d8bfd8",
835
891
  inputs:1,