@gregoriusrippenstein/node-red-contrib-introspection 0.11.5 → 0.12.1
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.
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "94afd585fb41a438",
|
|
4
|
+
"type": "tab",
|
|
5
|
+
"label": "client code loop",
|
|
6
|
+
"disabled": false,
|
|
7
|
+
"info": "Using the client code default values feature, create a loop counter.\n\nCreating a max loop counter for loop through data or whatever.",
|
|
8
|
+
"env": []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": "e0c808876e8685bd",
|
|
12
|
+
"type": "ClientCode",
|
|
13
|
+
"z": "94afd585fb41a438",
|
|
14
|
+
"name": "",
|
|
15
|
+
"clientcode": "if (msg.MAXLOOP > msg.loopcounter) {\n node.send(msg)\n}",
|
|
16
|
+
"format": "javascript",
|
|
17
|
+
"rules": [
|
|
18
|
+
{
|
|
19
|
+
"t": "default",
|
|
20
|
+
"p": "MAXLOOP",
|
|
21
|
+
"pt": "msg",
|
|
22
|
+
"to": "12",
|
|
23
|
+
"tot": "num"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"t": "fixed",
|
|
27
|
+
"p": "loopcounter",
|
|
28
|
+
"pt": "msg",
|
|
29
|
+
"to": "$filter([$$.loopcounter,0,0], function ($v) { $exists($v) })[0] + 1",
|
|
30
|
+
"tot": "jsonata"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"x": 691,
|
|
34
|
+
"y": 357,
|
|
35
|
+
"wires": [
|
|
36
|
+
[
|
|
37
|
+
"893c3ec0bf9d100a",
|
|
38
|
+
"0fc98024bdd207cb"
|
|
39
|
+
]
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "523c5f1c268546ed",
|
|
44
|
+
"type": "inject",
|
|
45
|
+
"z": "94afd585fb41a438",
|
|
46
|
+
"name": "",
|
|
47
|
+
"props": [
|
|
48
|
+
{
|
|
49
|
+
"p": "MAXLOOP",
|
|
50
|
+
"v": "24",
|
|
51
|
+
"vt": "num"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"p": "topic",
|
|
55
|
+
"vt": "str"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"repeat": "",
|
|
59
|
+
"crontab": "",
|
|
60
|
+
"once": false,
|
|
61
|
+
"onceDelay": 0.1,
|
|
62
|
+
"topic": "",
|
|
63
|
+
"x": 513,
|
|
64
|
+
"y": 481,
|
|
65
|
+
"wires": [
|
|
66
|
+
[
|
|
67
|
+
"e0c808876e8685bd"
|
|
68
|
+
]
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "893c3ec0bf9d100a",
|
|
73
|
+
"type": "debug",
|
|
74
|
+
"z": "94afd585fb41a438",
|
|
75
|
+
"name": "debug 1",
|
|
76
|
+
"active": true,
|
|
77
|
+
"tosidebar": true,
|
|
78
|
+
"console": false,
|
|
79
|
+
"tostatus": false,
|
|
80
|
+
"complete": "true",
|
|
81
|
+
"targetType": "full",
|
|
82
|
+
"statusVal": "",
|
|
83
|
+
"statusType": "auto",
|
|
84
|
+
"x": 917,
|
|
85
|
+
"y": 273,
|
|
86
|
+
"wires": []
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "0fc98024bdd207cb",
|
|
90
|
+
"type": "delay",
|
|
91
|
+
"z": "94afd585fb41a438",
|
|
92
|
+
"name": "",
|
|
93
|
+
"pauseType": "delay",
|
|
94
|
+
"timeout": "500",
|
|
95
|
+
"timeoutUnits": "milliseconds",
|
|
96
|
+
"rate": "1",
|
|
97
|
+
"nbRateUnits": "1",
|
|
98
|
+
"rateUnits": "second",
|
|
99
|
+
"randomFirst": "1",
|
|
100
|
+
"randomLast": "5",
|
|
101
|
+
"randomUnits": "seconds",
|
|
102
|
+
"drop": false,
|
|
103
|
+
"allowrate": false,
|
|
104
|
+
"outputs": 1,
|
|
105
|
+
"x": 915,
|
|
106
|
+
"y": 358,
|
|
107
|
+
"wires": [
|
|
108
|
+
[
|
|
109
|
+
"e0c808876e8685bd"
|
|
110
|
+
]
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
function handleMsgTracePacket(e,r){if(r.nodeid){let a=RED.nodes.node(r.nodeid);if(a){var s,r=$("#node-input-msgtracer-trace-treelist").treeList("data");let t=!1;r.forEach(e=>{e.id==a.id&&(t=!0,e.seenCounter+=1,e.sublabel=e.seenCounter+" @ "+e.workspaceLabel)}),t?$("#node-input-msgtracer-trace-treelist").treeList("data",r):(s={id:a.id,label:"",_label:RED.utils.getNodeLabel(a),seenCounter:1,workspaceLabel:(RED.nodes.workspace(a.z)||{label:a.z}).label,sublabel:"1 @ "+(RED.nodes.workspace(a.z)||{label:a.z}).label,selected:!1,checkbox:!1,node:a,icon:RED.utils.createNodeIcon(a,!0)},$("#node-input-msgtracer-trace-treelist").treeList("data",[s,...r]))}}}RED.comms.subscribe("msgtracer:node-received",(e,t)=>{try{handleMsgTracePacket(e,t)}catch(e){console.error(e)}});
|
|
4
4
|
|
|
5
|
-
function handleClientCodeFrontend(event,data){
|
|
5
|
+
function handleClientCodeFrontend(event,data){if("execfunc"==data.msg){let doSend=(e,n,t)=>{"object"==typeof e&&(e={...t,...e}),$.ajax({url:"ClientCode/"+n,type:"POST",contentType:"application/json; charset=utf-8",data:JSON.stringify(e),success:function(e){},error:function(e,t,o){RED.notify("ClientCode Communcation Failure: "+n+": "+t,{type:"error",id:n,timeout:3e3})}})},doStatus=(e,n,t)=>{$.ajax({url:"ClientCode/"+n+"/status",type:"POST",contentType:"application/json; charset=utf-8",data:JSON.stringify(e),success:function(e){},error:function(e,t,o){RED.notify("ClientCode Communcation Failure: "+n+": "+t,{type:"error",id:n,timeout:3e3})}})},doError=(e,t,o)=>{RED.notify("ClientCode Failed: "+t+": "+e,{type:"error",id:t,timeout:3e3}),console.log("ClientCode: Error with node: "+t+": "+e)},nodeid=data.nodeid,_msg=data._msg,msg=data._msg??{},cfg=data._cfg,node={id:data.nodeid,send:e=>{doSend(e,nodeid,_msg)},error:e=>{doError(e,nodeid,_msg)},status:e=>{doStatus(e,nodeid,_msg)}},payload=data.payload,topic=data.topic;eval(data.func)}}RED.comms.subscribe("introspect:client-code-perform",(e,t)=>{try{handleClientCodeFrontend(e,t)}catch(e){console.error(e)}});
|
|
6
6
|
|
|
7
7
|
RED.nodes.registerType('ClientCode',{
|
|
8
8
|
color: '#e5e4ef',
|
|
@@ -18,6 +18,9 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
|
|
|
18
18
|
},
|
|
19
19
|
format: {
|
|
20
20
|
value: "javascript"
|
|
21
|
+
},
|
|
22
|
+
rules: {
|
|
23
|
+
value: [{ t: "default", p: "payload", pt: "msg", to: "", tot: "str" }]
|
|
21
24
|
}
|
|
22
25
|
},
|
|
23
26
|
inputs:1,
|
|
@@ -35,6 +38,28 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
|
|
|
35
38
|
$('#node-input-clientcode').val(this.editor.getValue());
|
|
36
39
|
this.editor.destroy();
|
|
37
40
|
delete this.editor;
|
|
41
|
+
|
|
42
|
+
var rules = $("#node-inpclientcode-defaults-container").editableList('items');
|
|
43
|
+
|
|
44
|
+
var node = this;
|
|
45
|
+
node.rules = [];
|
|
46
|
+
|
|
47
|
+
rules.each(function (i) {
|
|
48
|
+
var rule = $(this);
|
|
49
|
+
var type = rule.find(".node-input-rule-type").val();
|
|
50
|
+
|
|
51
|
+
var r = {
|
|
52
|
+
t: type,
|
|
53
|
+
p: rule.find(".node-input-rule-property-name").typedInput('value'),
|
|
54
|
+
pt: rule.find(".node-input-rule-property-name").typedInput('type')
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
if (type !== "notset" && type !== "debug" && type !== "set") {
|
|
58
|
+
r.to = rule.find(".node-input-rule-property-value").typedInput('value');
|
|
59
|
+
r.tot = rule.find(".node-input-rule-property-value").typedInput('type');
|
|
60
|
+
}
|
|
61
|
+
node.rules.push(r);
|
|
62
|
+
});
|
|
38
63
|
},
|
|
39
64
|
|
|
40
65
|
oneditcancel: function() {
|
|
@@ -42,16 +67,170 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
|
|
|
42
67
|
delete this.editor;
|
|
43
68
|
},
|
|
44
69
|
|
|
70
|
+
//
|
|
71
|
+
// ***********************
|
|
72
|
+
// Prepare editor panel
|
|
73
|
+
// ***********************
|
|
74
|
+
//
|
|
45
75
|
oneditprepare: function() {
|
|
46
76
|
const that = this;
|
|
77
|
+
const node = this;
|
|
47
78
|
const stateId = RED.editor.generateViewStateId("node", this, "");
|
|
48
79
|
|
|
80
|
+
var to = this._("clientcode.action.to");
|
|
81
|
+
var toValueLabel = this._("clientcode.action.toValue", to);
|
|
82
|
+
var search = this._("clientcode.action.search");
|
|
83
|
+
var replace = this._("clientcode.action.replace");
|
|
84
|
+
var regex = this._("clientcode.label.regex");
|
|
85
|
+
|
|
86
|
+
function createPropertyValue(row2_1, row2_2, defaultType) {
|
|
87
|
+
var propValInput = $('<input/>', { class: "node-input-rule-property-value", type: "text" })
|
|
88
|
+
.appendTo(row2_1)
|
|
89
|
+
.typedInput({ default: defaultType || 'str', types: ['str', 'num', 'bool', 'json', 'bin', 'date', 'jsonata'] });
|
|
90
|
+
|
|
91
|
+
propValInput.on("change", function (evt, type, val) {
|
|
92
|
+
row2_2.toggle(type === "msg" || type === "flow" || type === "global" || type === "env");
|
|
93
|
+
})
|
|
94
|
+
return [propValInput, undefined];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
var tabs = RED.tabs.create({
|
|
98
|
+
id: "client-code-tabs",
|
|
99
|
+
onchange: function (tab) {
|
|
100
|
+
$("#client-code-tabs-content").children().hide();
|
|
101
|
+
$("#" + tab.id).show();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
tabs.addTab({
|
|
106
|
+
id: "client-code-tabs-default-values",
|
|
107
|
+
iconClass: "fa fa-cog",
|
|
108
|
+
label: "msg parameters"
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
tabs.addTab({
|
|
112
|
+
id: "client-code-tabs-code-editor",
|
|
113
|
+
iconClass: "fa fa-edit",
|
|
114
|
+
label: "editor"
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
tabs.activateTab("client-code-tabs-code-editor");
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
$('#node-inpclientcode-defaults-container').css('min-height', '150px').css('min-width', '450px').editableList({
|
|
121
|
+
addItem: function (container, i, opt) {
|
|
122
|
+
var rule = opt;
|
|
123
|
+
if (!rule.hasOwnProperty('t')) {
|
|
124
|
+
rule = { t: "default", p: "payload", to: "", tot: "str" };
|
|
125
|
+
}
|
|
126
|
+
container.css({
|
|
127
|
+
overflow: 'hidden',
|
|
128
|
+
whiteSpace: 'nowrap'
|
|
129
|
+
});
|
|
130
|
+
let fragment = document.createDocumentFragment();
|
|
131
|
+
var row1 = $('<div/>', { style: "display:flex; align-items: baseline" }).appendTo(fragment);
|
|
132
|
+
var row2 = $('<div/>', { style: "margin-top:8px;" }).appendTo(fragment);
|
|
133
|
+
var row3 = $('<div/>', { style: "margin-top:8px;" }).appendTo(fragment);
|
|
134
|
+
var row4 = $('<div/>', { style: "display:flex;margin-top:8px;align-items: baseline" }).appendTo(fragment);
|
|
135
|
+
|
|
136
|
+
var selectField = $('<select/>', { class: "node-input-rule-type", style: "width:110px; margin-right:10px;" }).appendTo(row1);
|
|
137
|
+
var selectOptions = [
|
|
138
|
+
{ v: "default" },
|
|
139
|
+
{ v: "overwrite" },
|
|
140
|
+
{ v: "fixed" },
|
|
141
|
+
];
|
|
142
|
+
for (var i = 0; i < selectOptions.length; i++) {
|
|
143
|
+
let label = node._("clientcode.action." + (selectOptions[i].l || selectOptions[i].v))
|
|
144
|
+
selectField.append($("<option></option>").val(selectOptions[i].v).text(label));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
var propertyName = $('<input/>', { class: "node-input-rule-property-name", type: "text" })
|
|
148
|
+
.appendTo(row1)
|
|
149
|
+
.typedInput({ types: ['msg'] });
|
|
150
|
+
|
|
151
|
+
var row2_1 = $('<div/>', { style: "display:flex;align-items: baseline" }).appendTo(row2);
|
|
152
|
+
$('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
|
|
153
|
+
.text(toValueLabel)
|
|
154
|
+
.appendTo(row2_1);
|
|
155
|
+
|
|
156
|
+
var row2_2 = $('<div/>', { style: "margin-top: 4px;" }).appendTo(row2);
|
|
157
|
+
|
|
158
|
+
var row3_1 = $('<div/>', { style: "display:flex;align-items: baseline" }).appendTo(row3);
|
|
159
|
+
$('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
|
|
160
|
+
.text(search)
|
|
161
|
+
.appendTo(row3_1);
|
|
162
|
+
|
|
163
|
+
var row3_2 = $('<div/>', { style: "display:flex;margin-top:8px;align-items: baseline" }).appendTo(row3);
|
|
164
|
+
$('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
|
|
165
|
+
.text(replace)
|
|
166
|
+
.appendTo(row3_2);
|
|
167
|
+
|
|
168
|
+
$('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
|
|
169
|
+
.text(to)
|
|
170
|
+
.appendTo(row4);
|
|
171
|
+
|
|
172
|
+
let propertyValue = null;
|
|
173
|
+
let fromValue = null;
|
|
174
|
+
let toValue = null;
|
|
175
|
+
let moveValue = null;
|
|
176
|
+
|
|
177
|
+
selectField.on("change", function () {
|
|
178
|
+
var type = $(this).val();
|
|
179
|
+
if (propertyValue) {
|
|
180
|
+
propertyValue.typedInput('hide');
|
|
181
|
+
}
|
|
182
|
+
if (fromValue) {
|
|
183
|
+
fromValue.typedInput('hide');
|
|
184
|
+
}
|
|
185
|
+
if (toValue) {
|
|
186
|
+
toValue.typedInput('hide');
|
|
187
|
+
}
|
|
188
|
+
if (moveValue) {
|
|
189
|
+
moveValue.typedInput('hide');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (type != "notset" && type != "debug" && type != "set") {
|
|
193
|
+
if (!propertyValue) {
|
|
194
|
+
var parts = createPropertyValue(row2_1, row2_2);
|
|
195
|
+
propertyValue = parts[0];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
propertyValue.typedInput('show');
|
|
199
|
+
propertyValue.typedInput('value', rule.to);
|
|
200
|
+
propertyValue.typedInput('type', rule.tot);
|
|
201
|
+
|
|
202
|
+
row2.show();
|
|
203
|
+
row3.hide();
|
|
204
|
+
row4.hide();
|
|
205
|
+
} else {
|
|
206
|
+
row2.hide();
|
|
207
|
+
row3.hide();
|
|
208
|
+
row4.hide();
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
selectField.val(rule.t);
|
|
213
|
+
propertyName.typedInput('value', rule.p);
|
|
214
|
+
propertyName.typedInput('type', rule.pt);
|
|
215
|
+
selectField.change();
|
|
216
|
+
container[0].appendChild(fragment);
|
|
217
|
+
},
|
|
218
|
+
removable: true,
|
|
219
|
+
sortable: true
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
this.rules = this.rules ?? [{t: "default", p: "payload", pt: "msg", to: "", tot: "str"}]
|
|
223
|
+
for (var i = 0; i < this.rules.length; i++) {
|
|
224
|
+
var rule = this.rules[i];
|
|
225
|
+
$("#node-inpclientcode-defaults-container").editableList('addItem', rule);
|
|
226
|
+
}
|
|
227
|
+
|
|
49
228
|
this.editor = RED.editor.createEditor({
|
|
50
229
|
id: 'node-input-clientcode-editor',
|
|
51
230
|
mode: 'ace/mode/nrjavascript',
|
|
52
231
|
stateId: stateId,
|
|
53
232
|
globals: {
|
|
54
|
-
msg:true,
|
|
233
|
+
msg:true,
|
|
55
234
|
RED: true,
|
|
56
235
|
node: true,
|
|
57
236
|
alert: true,
|
|
@@ -96,22 +275,53 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
|
|
|
96
275
|
|
|
97
276
|
},
|
|
98
277
|
|
|
278
|
+
//
|
|
279
|
+
// *******************
|
|
280
|
+
// Resize event
|
|
281
|
+
// *******************
|
|
282
|
+
//
|
|
99
283
|
oneditresize: function(size) {
|
|
100
|
-
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
|
284
|
+
var rows = $("#dialog-form #client-code-tabs-code-editor>div:not(.node-text-editor-row)");
|
|
101
285
|
var height = $("#dialog-form").height();
|
|
102
286
|
for (var i=0; i<rows.length; i++) {
|
|
103
287
|
height -= $(rows[i]).outerHeight(true);
|
|
104
288
|
}
|
|
105
|
-
|
|
289
|
+
|
|
290
|
+
var rows = $("#dialog-form>.client-code-node-name-row");
|
|
291
|
+
for (var i=0; i<rows.length; i++) {
|
|
292
|
+
height -= $(rows[i]).outerHeight(true);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// footer
|
|
296
|
+
height -= 40;
|
|
297
|
+
|
|
298
|
+
var editorRow = $("#dialog-form #client-code-tabs-code-editor>div.node-text-editor-row");
|
|
106
299
|
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
|
107
300
|
$(".node-text-editor").css("height",height+"px");
|
|
301
|
+
|
|
108
302
|
this.editor.resize();
|
|
303
|
+
|
|
304
|
+
//
|
|
305
|
+
//
|
|
306
|
+
//
|
|
307
|
+
if ($('#client-code-tabs-default-values').is(":visible")) {
|
|
308
|
+
var rows = $("#dialog-form #client-code-tabs-default-values>div:not(.node-inpclientcode-defaults-container-row)");
|
|
309
|
+
var height = size.height;
|
|
310
|
+
for (var i=0; i<rows.length; i++) {
|
|
311
|
+
height -= $(rows[i]).outerHeight(true);
|
|
312
|
+
}
|
|
313
|
+
var editorRow = $("#dialog-form #client-code-tabs-default-values>div.node-input-rule-container-row");
|
|
314
|
+
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
|
315
|
+
$("#node-inpclientcode-defaults-container").editableList('height', height-60);
|
|
316
|
+
} else {
|
|
317
|
+
$("#node-inpclientcode-defaults-container").editableList('height', height/3);
|
|
318
|
+
}
|
|
109
319
|
}
|
|
110
320
|
});
|
|
111
321
|
</script>
|
|
112
322
|
|
|
113
323
|
<script type="text/html" data-template-name="ClientCode">
|
|
114
|
-
<div class="form-row">
|
|
324
|
+
<div class="form-row client-code-node-name-row">
|
|
115
325
|
<label for="node-input-name">
|
|
116
326
|
<i class="fa fa-tag"></i>
|
|
117
327
|
<span data-i18n="common.label.name">Name</span>
|
|
@@ -119,40 +329,56 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
|
|
|
119
329
|
<input type="text" id="node-input-name" placeholder="Name">
|
|
120
330
|
</div>
|
|
121
331
|
|
|
122
|
-
<div class="form-row
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
332
|
+
<div class="form-row func-tabs-row">
|
|
333
|
+
<ul style="min-width: 400px; margin-bottom: 20px;" id="client-code-tabs"></ul>
|
|
334
|
+
</div>
|
|
335
|
+
|
|
336
|
+
<div id="client-code-tabs-content" style="min-height: calc(100% - 95px);">
|
|
126
337
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
<option value="handlebars">mustache</option>
|
|
131
|
-
<option value="html">HTML</option>
|
|
132
|
-
<option value="json">JSON</option>
|
|
133
|
-
<option value="javascript">JavaScript</option>
|
|
134
|
-
<option value="css">CSS</option>
|
|
135
|
-
<option value="markdown">Markdown</option>
|
|
136
|
-
<option value="php">PHP</option>
|
|
137
|
-
<option value="python">Python</option>
|
|
138
|
-
<option value="sql">SQL</option>
|
|
139
|
-
<option value="yaml">YAML</option>
|
|
140
|
-
<option value="text">None</option>
|
|
141
|
-
</select>
|
|
142
|
-
<button type="button" id="node-clientcode-expand-editor"
|
|
143
|
-
class="red-ui-button red-ui-button-small">
|
|
144
|
-
<i class="fa fa-expand"></i>
|
|
145
|
-
</button>
|
|
338
|
+
<div id="client-code-tabs-default-values" style="display:none;">
|
|
339
|
+
<div class="form-row node-input-rule-container-row node-inpclientcode-defaults-container-row">
|
|
340
|
+
<ol id="node-inpclientcode-defaults-container"></ol>
|
|
146
341
|
</div>
|
|
147
|
-
|
|
342
|
+
</div>
|
|
148
343
|
|
|
149
|
-
|
|
150
|
-
<div style="
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
344
|
+
<div id="client-code-tabs-code-editor">
|
|
345
|
+
<div class="form-row" style="position: relative; margin-bottom: 0px;">
|
|
346
|
+
<label for="node-input-clientcode">
|
|
347
|
+
<i class="fa fa-file-code-o"></i> Client Code
|
|
348
|
+
</label>
|
|
349
|
+
|
|
350
|
+
<div style="position: absolute; right:0;display:inline-block; text-align: right; font-size: 0.8em;">
|
|
351
|
+
Syntax:
|
|
352
|
+
<select id="node-input-format" style="width:110px; font-size: 10px !important; height: 24px; padding:0;">
|
|
353
|
+
<option value="handlebars">mustache</option>
|
|
354
|
+
<option value="html">HTML</option>
|
|
355
|
+
<option value="json">JSON</option>
|
|
356
|
+
<option value="javascript">JavaScript</option>
|
|
357
|
+
<option value="css">CSS</option>
|
|
358
|
+
<option value="markdown">Markdown</option>
|
|
359
|
+
<option value="php">PHP</option>
|
|
360
|
+
<option value="python">Python</option>
|
|
361
|
+
<option value="sql">SQL</option>
|
|
362
|
+
<option value="yaml">YAML</option>
|
|
363
|
+
<option value="text">None</option>
|
|
364
|
+
</select>
|
|
365
|
+
<button type="button" id="node-clientcode-expand-editor"
|
|
366
|
+
class="red-ui-button red-ui-button-small">
|
|
367
|
+
<i class="fa fa-expand"></i>
|
|
368
|
+
</button>
|
|
369
|
+
</div>
|
|
370
|
+
</div>
|
|
371
|
+
|
|
372
|
+
<div class="form-row node-text-editor-row">
|
|
373
|
+
<div style="height: 250px; min-height:150px;"
|
|
374
|
+
class="node-text-editor"
|
|
375
|
+
id="node-input-clientcode-editor" ></div>
|
|
376
|
+
</div>
|
|
154
377
|
|
|
155
|
-
|
|
378
|
+
<input type="hidden" id="node-input-clientcode" autofocus="autofocus">
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
</div>
|
|
156
382
|
</script>
|
|
157
383
|
|
|
158
384
|
<script type="text/html" data-help-name="ClientCode">
|
|
@@ -168,6 +394,7 @@ Variables:
|
|
|
168
394
|
node.id - id of this node, same as `nodeid` above
|
|
169
395
|
payload - a reference to msg.payload as it was received by this node
|
|
170
396
|
topic - a reference to the msg.topic as it was recieved by this node
|
|
397
|
+
cfg - an object that represents the default values defined in the msg parameters tab
|
|
171
398
|
|
|
172
399
|
Functionality:
|
|
173
400
|
node.send({..}) - send data to the output port of this node
|
|
@@ -191,4 +418,19 @@ Functionality:
|
|
|
191
418
|
The code to be executed by the client can also be passed in via the `msg` object using the
|
|
192
419
|
`clientcode` attribute on the `msg` object. If this attribute is set, it will take precendence
|
|
193
420
|
over the code defined in the node itself.
|
|
421
|
+
|
|
422
|
+
<p>
|
|
423
|
+
Handling of Default Values
|
|
424
|
+
<p>
|
|
425
|
+
Each default value can either be default, overwrite or fixed:
|
|
426
|
+
<li>
|
|
427
|
+
<ul><b>Default</b> - value is set on the message if value isn't set on the msg object already. Else the msg value is used.</ul>
|
|
428
|
+
<ul><b>Overwrite</b> - default value overwrites the existing value on the message. If the property does not exist on the message, then the default value is ignored. A default value will only overwrite if the value is already defined on the msg object.</ul>
|
|
429
|
+
<ul><b>Fixed</b> - the default value is always used, ignoring whether the value is already set or not on the msg object. This is useful for constants or JSONata expressions - see loop counter below.</ul>
|
|
430
|
+
</li>
|
|
431
|
+
<p>
|
|
432
|
+
Loop counters using jsonata
|
|
433
|
+
<p>
|
|
434
|
+
One usage of the default values is as an loop counter for messages going around and around. To define a loopcounter which is only defined on the msg object, define a default value <code>loopcounter</code> with the following JSONata code <code>$filter([$$.loopcounter,0,0], function ($v) { $exists($v) })[0] + 1</code> ($filter returns a single value if the array only contains one value else it returns an array).
|
|
435
|
+
|
|
194
436
|
</script>
|
package/nodes/60-client-code.js
CHANGED
|
@@ -58,6 +58,49 @@ module.exports = function (RED) {
|
|
|
58
58
|
var node = this;
|
|
59
59
|
var cfg = config;
|
|
60
60
|
|
|
61
|
+
function getToValue(msg, rule, done) {
|
|
62
|
+
var value = rule.to;
|
|
63
|
+
|
|
64
|
+
if (rule.tot === 'json') {
|
|
65
|
+
value = JSON.parse(rule.to);
|
|
66
|
+
} else if (rule.tot === 'bin') {
|
|
67
|
+
value = Buffer.from(JSON.parse(rule.to))
|
|
68
|
+
} else if (rule.tot === 'str') {
|
|
69
|
+
value = rule.to
|
|
70
|
+
} else if (rule.tot === "num") {
|
|
71
|
+
value = Number(rule.to)
|
|
72
|
+
} else if (rule.tot === "bool") {
|
|
73
|
+
value = /^true$/i.test(rule.to);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (rule.tot === "msg") {
|
|
77
|
+
value = RED.util.getMessageProperty(msg, rule.to);
|
|
78
|
+
} else if ((rule.tot === 'flow') || (rule.tot === 'global')) {
|
|
79
|
+
RED.util.evaluateNodeProperty(rule.to, rule.tot, node, msg, (err, value) => {
|
|
80
|
+
if (err) {
|
|
81
|
+
done(undefined, undefined);
|
|
82
|
+
} else {
|
|
83
|
+
done(undefined, value);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return
|
|
87
|
+
} else if (rule.tot === 'date') {
|
|
88
|
+
value = RED.util.evaluateNodeProperty(rule.to, rule.tot, node)
|
|
89
|
+
} else if (rule.tot === 'jsonata') {
|
|
90
|
+
let jsonExpr = RED.util.prepareJSONataExpression(rule.to, node);
|
|
91
|
+
|
|
92
|
+
RED.util.evaluateJSONataExpression(jsonExpr, msg, (err, value) => {
|
|
93
|
+
if (err) {
|
|
94
|
+
done(RED._("change.errors.invalid-expr", { error: err.message }))
|
|
95
|
+
} else {
|
|
96
|
+
done(undefined, value);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
done(undefined, value);
|
|
102
|
+
}
|
|
103
|
+
|
|
61
104
|
node.on('close', function () {
|
|
62
105
|
node.status({});
|
|
63
106
|
});
|
|
@@ -72,17 +115,48 @@ module.exports = function (RED) {
|
|
|
72
115
|
node.error(e)
|
|
73
116
|
}
|
|
74
117
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
let defaultValues = {}
|
|
119
|
+
|
|
120
|
+
let stupidLoop = (ruleIdx) => {
|
|
121
|
+
if ( ruleIdx >= (cfg.rules || []).length) {
|
|
122
|
+
RED.comms.publish(
|
|
123
|
+
"introspect:client-code-perform",
|
|
124
|
+
RED.util.encodeObject({
|
|
125
|
+
msg: "execfunc",
|
|
126
|
+
payload: msg.payload,
|
|
127
|
+
topic: msg.topic,
|
|
128
|
+
func: msg.clientcode || cfg.clientcode,
|
|
129
|
+
nodeid: node.id,
|
|
130
|
+
_msg: msg,
|
|
131
|
+
_cfg: defaultValues
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
done()
|
|
135
|
+
} else {
|
|
136
|
+
try {
|
|
137
|
+
let rule = cfg.rules[ruleIdx]
|
|
138
|
+
let name = rule.p
|
|
139
|
+
|
|
140
|
+
getToValue(msg, rule, (err, value) => {
|
|
141
|
+
defaultValues[name] = value
|
|
142
|
+
if ( rule.t == "fixed" ) {
|
|
143
|
+
msg[name] = value
|
|
144
|
+
} else if (rule.t == "default") {
|
|
145
|
+
msg[name] = msg[name] ?? value
|
|
146
|
+
} else if (rule.t == "overwrite" && msg.hasOwnProperty(name)) {
|
|
147
|
+
msg[name] = value ?? msg[name]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
stupidLoop(ruleIdx+1)
|
|
151
|
+
})
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.log(e)
|
|
154
|
+
stupidLoop(ruleIdx + 1)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
stupidLoop(0)
|
|
86
160
|
});
|
|
87
161
|
}
|
|
88
162
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"clientcode": {
|
|
3
|
+
"label": {
|
|
4
|
+
"statusset": "Status Set",
|
|
5
|
+
"rules": "Rules",
|
|
6
|
+
"rule": "rule",
|
|
7
|
+
|
|
8
|
+
"set": "set __property__",
|
|
9
|
+
"change": "change __property__",
|
|
10
|
+
"delete": "delete __property__",
|
|
11
|
+
"move": "move __property__",
|
|
12
|
+
|
|
13
|
+
"changeCount": "assert: __count__ values",
|
|
14
|
+
"regex": "Use regular expressions",
|
|
15
|
+
"deepCopy": "Deep copy value",
|
|
16
|
+
|
|
17
|
+
"notmth": "not match __property__",
|
|
18
|
+
"mth": "match __property__",
|
|
19
|
+
"eql": "equal __property__",
|
|
20
|
+
"noteql": "not equal __property__",
|
|
21
|
+
"notset": "not set __property__",
|
|
22
|
+
"debug": "debug __property__",
|
|
23
|
+
"unsupported": "supported rule __property__",
|
|
24
|
+
|
|
25
|
+
"ignore_failure_if_succeed": "Ignore failure if succeed once"
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
"action": {
|
|
29
|
+
"default": "Default",
|
|
30
|
+
"overwrite": "Overwrite",
|
|
31
|
+
"fixed": "Fixed",
|
|
32
|
+
"set": "Defined",
|
|
33
|
+
"change": "Change",
|
|
34
|
+
"delete": "Delete",
|
|
35
|
+
"move": "Move",
|
|
36
|
+
"toValue": "to the value",
|
|
37
|
+
"to": "to",
|
|
38
|
+
"search": "Search for",
|
|
39
|
+
"replace": "Replace with",
|
|
40
|
+
|
|
41
|
+
"notmth": "Not Match",
|
|
42
|
+
"mth": "Match",
|
|
43
|
+
"eql": "Equal",
|
|
44
|
+
"noteql": "Not Equal",
|
|
45
|
+
"notset": "Not Defined",
|
|
46
|
+
"debug": "Debug"
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
"errors": {
|
|
50
|
+
"invalid-from": "Invalid 'from' property: __error__",
|
|
51
|
+
"invalid-json": "Invalid 'to' JSON property",
|
|
52
|
+
"invalid-expr": "Invalid JSONata expression: __error__",
|
|
53
|
+
"no-override": "Cannot set property of non-object type: __property__",
|
|
54
|
+
"invalid-prop": "Invalid property expression: __property__",
|
|
55
|
+
"invalid-json-data": "Invalid JSON data: __error__"
|
|
56
|
+
},
|
|
57
|
+
"status": {
|
|
58
|
+
"waiting": "Waiting for Godot",
|
|
59
|
+
"timeout": "No more time to waiting"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|