@gregoriusrippenstein/node-red-contrib-nodedev 0.1.2 → 0.1.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.
@@ -0,0 +1,113 @@
1
+ [
2
+ {
3
+ "id": "e68c8450d6e047e6",
4
+ "type": "NpmTarBall",
5
+ "z": "5644e181ee8af639",
6
+ "name": "",
7
+ "x": 905,
8
+ "y": 656,
9
+ "wires": [
10
+ [
11
+ "ddb9e4e7ca9e2797"
12
+ ]
13
+ ]
14
+ },
15
+ {
16
+ "id": "ddb9e4e7ca9e2797",
17
+ "type": "NodeRedInstall",
18
+ "z": "5644e181ee8af639",
19
+ "name": "",
20
+ "x": 983,
21
+ "y": 710,
22
+ "wires": [
23
+ []
24
+ ]
25
+ },
26
+ {
27
+ "id": "6f04b8605d139351",
28
+ "type": "group",
29
+ "z": "5644e181ee8af639",
30
+ "name": "Step 1: Generate the missing nodes",
31
+ "style": {
32
+ "label": true
33
+ },
34
+ "nodes": [
35
+ "4f2e91f3e9fa51b7"
36
+ ],
37
+ "x": 326,
38
+ "y": 562,
39
+ "w": 232,
40
+ "h": 82
41
+ },
42
+ {
43
+ "id": "4f2e91f3e9fa51b7",
44
+ "type": "NodeFactory",
45
+ "z": "5644e181ee8af639",
46
+ "g": "6f04b8605d139351",
47
+ "name": "",
48
+ "nodename": "Fubar",
49
+ "color": "#FFF0F0",
50
+ "hasbutton": true,
51
+ "hasinput": true,
52
+ "outputcount": 1,
53
+ "category": "snafu",
54
+ "summary": "Summary",
55
+ "description": "Description",
56
+ "icon": "font-awesome/fa-venus-double",
57
+ "frt2bakcomm": false,
58
+ "bak2frtcomm": false,
59
+ "createmanifest": true,
60
+ "isplugin": true,
61
+ "x": 422,
62
+ "y": 603,
63
+ "wires": [
64
+ []
65
+ ]
66
+ },
67
+ {
68
+ "id": "a599fd3ebf69cdb1",
69
+ "type": "group",
70
+ "z": "5644e181ee8af639",
71
+ "name": "Step 2: Connect and installing to Node-RED",
72
+ "style": {
73
+ "label": true
74
+ },
75
+ "nodes": [
76
+ "b45307819c625e63"
77
+ ],
78
+ "x": 326,
79
+ "y": 232,
80
+ "w": 284,
81
+ "h": 82
82
+ },
83
+ {
84
+ "id": "b45307819c625e63",
85
+ "type": "NodeDevOps",
86
+ "z": "5644e181ee8af639",
87
+ "g": "a599fd3ebf69cdb1",
88
+ "name": "",
89
+ "pname": "@johnsmith/fubar-node",
90
+ "pversion": "0.0.1",
91
+ "pauthorname": "Alfred E. Neumann",
92
+ "pauthoremail": "alfred@example.com",
93
+ "pdescription": "Fubar nods.",
94
+ "noderedinstall": true,
95
+ "randompackagename": true,
96
+ "gitcommit": false,
97
+ "gitcheckforchange": false,
98
+ "githubowner": "",
99
+ "githubrepo": "",
100
+ "githubbranch": "main",
101
+ "githubauthor": "",
102
+ "githubauthoremail": "",
103
+ "githubmessage": "",
104
+ "npmpublish": false,
105
+ "npmunpublish": false,
106
+ "npmotp": "",
107
+ "x": 442,
108
+ "y": 273,
109
+ "wires": [
110
+ []
111
+ ]
112
+ }
113
+ ]
@@ -47,20 +47,23 @@
47
47
  defaults: {
48
48
  name: { value:"" },
49
49
 
50
- pname: { value: "", required: true },
51
- pversion: { value: "", required: true },
50
+ pname: { value: "", required: true },
51
+ pversion: { value: "", required: true },
52
+ pauthorname: { value: "", required: true },
53
+ pauthoremail: { value: "", required: true },
54
+ pdescription: { value: "", required: true },
52
55
 
53
56
  noderedinstall: { value: false },
54
57
  randompackagename: { value: false },
55
58
 
56
- gitcommit: { value: false },
59
+ gitcommit: { value: false },
57
60
  gitcheckforchange: { value: false },
58
- githubowner: { value: ""},
59
- githubrepo: { value: ""},
60
- githubbranch: { value: "main"},
61
- githubauthor: { value: ""},
61
+ githubowner: { value: ""},
62
+ githubrepo: { value: ""},
63
+ githubbranch: { value: "main"},
64
+ githubauthor: { value: ""},
62
65
  githubauthoremail: { value: "" },
63
- githubmessage: { value: "" },
66
+ githubmessage: { value: "" },
64
67
 
65
68
  npmpublish: { value: false },
66
69
  npmunpublish: { value: false },
@@ -196,6 +199,21 @@
196
199
  <input type="text" id="node-input-pversion" placeholder="0.0.1"/>
197
200
  </div>
198
201
 
202
+ <div class="form-row">
203
+ <label for="node-input-pauthorname" style="min-width: 250px;"><i class="fa fa-address-book-o"></i> Package Author Name</label>
204
+ <input type="text" id="node-input-pauthorname" placeholder="Alfred E. Neumann"/>
205
+ </div>
206
+
207
+ <div class="form-row">
208
+ <label for="node-input-pauthoremail" style="min-width: 250px;"><i class="fa fa-envelope-o"></i> Package Author Email</label>
209
+ <input type="text" id="node-input-pauthoremail" placeholder="joe.blog@example.com"/>
210
+ </div>
211
+
212
+ <div class="form-row">
213
+ <label for="node-input-pdescription" style="min-width: 150px;"><i class="fa fa-book"></i> Package Description</label>
214
+ <input type="text" id="node-input-pdescription" placeholder="Package description"/>
215
+ </div>
216
+
199
217
  <hr/>
200
218
 
201
219
  <div class="form-row">
@@ -248,15 +266,15 @@
248
266
 
249
267
  <div id="github-options">
250
268
  <div class="form-row">
251
- <label for="node-input-githubowner" style="min-width: 150px;"><i class="fa fa-tag"></i> GitHub Username</label>
269
+ <label for="node-input-githubowner" style="min-width: 150px;"><i class="fa fa-user-o"></i> GitHub Username</label>
252
270
  <input type="text" id="node-input-githubowner" placeholder="username"/>
253
271
  </div>
254
272
  <div class="form-row">
255
- <label for="node-input-githubrepo" style="min-width: 150px;"><i class="fa fa-tag"></i> Repository</label>
273
+ <label for="node-input-githubrepo" style="min-width: 150px;"><i class="fa fa-paw"></i> Repository</label>
256
274
  <input type="text" id="node-input-githubrepo" placeholder=""/>
257
275
  </div>
258
276
  <div class="form-row">
259
- <label for="node-input-githubbranch" style="min-width: 150px;"><i class="fa fa-tag"></i> Branch</label>
277
+ <label for="node-input-githubbranch" style="min-width: 150px;"><i class="fa fa-tree"></i> Branch</label>
260
278
  <input type="text" id="node-input-githubbranch" placeholder="main"/>
261
279
  </div>
262
280
  </div>
@@ -267,11 +285,11 @@
267
285
  <input type="text" id="node-input-githubmessage" placeholder="Initial Commit"/>
268
286
  </div>
269
287
  <div class="form-row">
270
- <label for="node-input-githubauthor" style="min-width: 150px;"><i class="fa fa-tag"></i> Author Name</label>
288
+ <label for="node-input-githubauthor" style="min-width: 150px;"><i class="fa fa-address-book-o"></i> Author Name</label>
271
289
  <input type="text" id="node-input-githubauthor" placeholder="Joe Blog"/>
272
290
  </div>
273
291
  <div class="form-row">
274
- <label for="node-input-githubauthoremail" style="min-width: 150px;"><i class="fa fa-tag"></i> Author Email</label>
292
+ <label for="node-input-githubauthoremail" style="min-width: 150px;"><i class="fa fa-envelope-o"></i> Author Email</label>
275
293
  <input type="text" id="node-input-githubauthoremail" placeholder="joe@spreads-the.love"/>
276
294
  </div>
277
295
  </div>
@@ -47,7 +47,7 @@
47
47
  <div class="form-row">
48
48
  <label for="node-input-summary">
49
49
  <i class="fa fa-tag"></i>
50
- <span>Summary</span>
50
+ <span>Summary (REQUIRED)</span>
51
51
  </label>
52
52
  <div style="height: 150px; min-height:150px; max-height: 150px;" class="node-text-editor" id="node-input-summary">
53
53
  </div>
@@ -56,12 +56,19 @@
56
56
  <div class="form-row">
57
57
  <label for="node-input-description">
58
58
  <i class="fa fa-tag"></i>
59
- <span>Description</span>
59
+ <span>Description (REQUIRED)</span>
60
60
  </label>
61
61
  <div style="height: 350px; min-height:350px; max-height: 350px;" class="node-text-editor" id="node-input-description">
62
62
  </div>
63
63
  </div>
64
64
 
65
+ <div class="form-row">
66
+ <label for="node-input-isplugin" style="min-width: 250px;">
67
+ <span>Plugin: Sidebar + Config?</span>
68
+ </label>
69
+ <input type="checkbox" id="node-input-isplugin" style="display:inline-block; width:15px; vertical-align:baseline;">
70
+ </div>
71
+
65
72
  <div class="form-row">
66
73
  <label for="node-input-frt2bakcomm" style="min-width: 250px;">
67
74
  <span>Frontend to Backend communication?</span>
@@ -119,7 +126,9 @@
119
126
 
120
127
  data["color"] = $('#node-input-colour').val();
121
128
  data["icon"] = $('#red-ui-editor-node-icon').val();
129
+ data["iconclass"] = "fa " + data["icon"].split("/")[1]; /* Assume font-awesomeness */
122
130
  data["name"] = $('#node-input-nodename').val();
131
+ data["namelwr"] = data["name"].toLowerCase();
123
132
  data["outputcount"] = $('#node-input-outputcount').val();
124
133
  data["category"] = $('#node-input-category').val();
125
134
 
@@ -128,7 +137,8 @@
128
137
  data["bak2frtcomm"] = $('#node-input-bak2frtcomm').is(":checked");
129
138
  data["frt2bakcomm"] = $('#node-input-frt2bakcomm').is(":checked");
130
139
  data["createmanifest"] = $('#node-input-createmanifest').is(":checked");
131
-
140
+ data["isplugin"] = $('#node-input-isplugin').is(":checked");
141
+
132
142
  data["__task"] = "generate_from_templates";
133
143
 
134
144
  $.ajax({
@@ -177,19 +187,20 @@
177
187
  color: "#e5e4ef",
178
188
  category: 'nodedev',
179
189
  defaults: {
180
- name: { value: "" },
181
- nodename: { value: "" },
182
- color: { value: "#e5e4ef" },
183
- hasbutton: { value: false },
184
- hasinput: { value: true },
185
- outputcount: { value: 1 },
186
- category: { value: "" },
187
- summary: { value: ""},
188
- description: { value: ""},
189
- icon: { value: "font-awesome/fa-industry" },
190
- frt2bakcomm: { value: false },
191
- bak2frtcomm: { value: false },
192
- createmanifest: { value: false }
190
+ name: { value: "" },
191
+ nodename: { value: "", required: true },
192
+ color: { value: "#e5e4ef" },
193
+ hasbutton: { value: false },
194
+ hasinput: { value: true },
195
+ outputcount: { value: 1 },
196
+ category: { value: "" },
197
+ summary: { value: "", required: true },
198
+ description: { value: "", required: true },
199
+ icon: { value: "font-awesome/fa-industry" },
200
+ frt2bakcomm: { value: false },
201
+ bak2frtcomm: { value: false },
202
+ createmanifest: { value: false },
203
+ isplugin: { value: false },
193
204
  },
194
205
  inputs: 1,
195
206
  outputs: 1,
@@ -165,62 +165,137 @@ module.exports = function (RED) {
165
165
  });
166
166
  }
167
167
 
168
- function convertToPkgFileNodes(msg, jsCtnt, htmlCtnt) {
169
- var allNodes = [];
170
-
171
- var secondId = RED.util.generateId();
172
-
173
- allNodes.push({
174
- id: RED.util.generateId(),
175
- type: "PkgFile",
176
- name: msg.node.name + ".js",
177
- filename: "nodes/" + msg.node.name.toLowerCase() + ".js",
178
- template: jsCtnt,
179
- syntax: "mustache",
180
- format: "javascript",
181
- output: "str",
182
- x: 100,
183
- y: 50,
184
- wires: [[secondId]]
168
+ function createPluginNodeDefintions(msg, node) {
169
+ var sidebarHtmlPath = path.join(__dirname, 'templates', 'tmplsidebar.html');
170
+ var nodeJsPath = path.join(__dirname, 'templates', 'tmplsidebarnode.js');
171
+ var nodeHtmlPath = path.join(__dirname, 'templates', 'tmplsidebarnode.html');
172
+
173
+ var content = {};
174
+
175
+ var promises = [
176
+ handleTemplate(msg, node, fs.readFileSync(sidebarHtmlPath, 'utf8')).then((c) => { content["sbht"] = c }),
177
+ handleTemplate(msg, node, fs.readFileSync(nodeJsPath, 'utf8')).then((c) => { content["ndjs"] = c }),
178
+ handleTemplate(msg, node, fs.readFileSync(nodeHtmlPath, 'utf8')).then((c) => { content["ndht"] = c }),
179
+ ];
180
+
181
+ return Promise.all(promises).then(() => {
182
+ var secondId = RED.util.generateId();
183
+ var thirdId = RED.util.generateId();
184
+
185
+ return [{
186
+ id: RED.util.generateId(),
187
+ type: "PkgFile",
188
+ name: msg.node.name + "Cfg.js",
189
+ filename: "nodes/" + msg.node.namelwr + ".js",
190
+ template: content["ndjs"],
191
+ syntax: "mustache",
192
+ format: "javascript",
193
+ output: "str",
194
+ x: 100,
195
+ y: 50,
196
+ wires: [[secondId]]
197
+ },
198
+
199
+ {
200
+ id: secondId,
201
+ type: "PkgFile",
202
+ name: "Sidebar: " + msg.node.name + ".html",
203
+ filename: "plugins/" + msg.node.namelwr + ".html",
204
+ template: content["sbht"],
205
+ syntax: "mustache",
206
+ format: "html",
207
+ output: "str",
208
+ x: 100,
209
+ y: 100,
210
+ wires: [[thirdId]]
211
+ },
212
+
213
+ {
214
+ id: thirdId,
215
+ type: "PkgFile",
216
+ name: msg.node.name + "Cfg.html",
217
+ filename: "nodes/" + msg.node.namelwr + ".html",
218
+ template: content["ndht"],
219
+ syntax: "mustache",
220
+ format: "html",
221
+ output: "str",
222
+ x: 100,
223
+ y: 150,
224
+ wires: [[]]
225
+ }]
185
226
  })
227
+ }
228
+
229
+ function createSimpleNodeDefintions(msg,node) {
230
+ var htmlPath = path.join(__dirname, 'templates', 'tmpl.html');
231
+ var jsPath = path.join(__dirname, 'templates', 'tmpl.js');
232
+
233
+ var content = {};
186
234
 
187
- allNodes.push({
188
- id: secondId,
189
- type: "PkgFile",
190
- name: msg.node.name + ".html",
191
- filename: "nodes/" + msg.node.name.toLowerCase() + ".html",
192
- template: htmlCtnt,
193
- syntax: "mustache",
194
- format: "html",
195
- output: "str",
196
- x: 100,
197
- y: 100,
198
- wires: [[]]
235
+ var promises = [
236
+ handleTemplate(msg, node, fs.readFileSync(htmlPath, 'utf8')).then((c) => { content["html"] = c }),
237
+ handleTemplate(msg, node, fs.readFileSync(jsPath, 'utf8')).then((c) => { content["jasc"] = c }),
238
+ ];
239
+
240
+ return Promise.all(promises).then(() => {
241
+ var secondId = RED.util.generateId();
242
+
243
+ return [{
244
+ id: RED.util.generateId(),
245
+ type: "PkgFile",
246
+ name: msg.node.name + ".js",
247
+ filename: "nodes/" + msg.node.namelwr + ".js",
248
+ template: content["jasc"],
249
+ syntax: "mustache",
250
+ format: "javascript",
251
+ output: "str",
252
+ x: 100,
253
+ y: 50,
254
+ wires: [[secondId]]
255
+ },
256
+
257
+ {
258
+ id: secondId,
259
+ type: "PkgFile",
260
+ name: msg.node.name + ".html",
261
+ filename: "nodes/" + msg.node.namelwr + ".html",
262
+ template: content["html"],
263
+ syntax: "mustache",
264
+ format: "html",
265
+ output: "str",
266
+ x: 100,
267
+ y: 100,
268
+ wires: [[]]
269
+ }]
199
270
  })
271
+ }
200
272
 
201
- return allNodes;
273
+ function createNodeDefintions(msg, node) {
274
+ if ( msg.node.isplugin ) {
275
+ return createPluginNodeDefintions(msg, node)
276
+ } else {
277
+ return createSimpleNodeDefintions(msg, node)
278
+ }
202
279
  }
203
280
 
204
281
  function createManifestFiles(msg, node, nodeDefinitions) {
205
- /* ASSUMPTION: assume the .js file is defined first and
206
- then the .html file in the node definitions */
207
-
208
282
  var packageJsonPath = path.join(__dirname, 'templates', 'tmplpackage.json');
209
283
  var readmePath = path.join(__dirname, 'templates', 'tmplreadme.md');
210
284
  var licensePath = path.join(__dirname, 'templates', 'tmpllicense');
211
285
 
212
- var pkjsTmpl = fs.readFileSync(packageJsonPath, 'utf8');
213
- var rdmeTmpl = fs.readFileSync(readmePath, 'utf8');
214
- var lcnsTmpl = fs.readFileSync(licensePath, 'utf8');
215
-
216
- spcRepDict["nodestanza"] = " \"" + msg.node.name.toLowerCase() + "\": \"" + nodeDefinitions[0].filename + "\""
286
+ /* ASSUMPTION: assume the .js file is defined first and
287
+ then the .html file in the node definitions */
288
+ spcRepDict["nodestanza"] = " \"" + msg.node.namelwr + "\": \"" + nodeDefinitions[0].filename + "\""
289
+ if ( msg.node.isplugin ) {
290
+ spcRepDict["pluginstanza"] = " \"sidebar-plugin\": \"" + nodeDefinitions[1].filename + "\""
291
+ }
217
292
 
218
293
  var content = {};
219
294
 
220
295
  var promises = [
221
- handleTemplate(msg, node, pkjsTmpl).then((c) => { content["pkjs"] = c }),
222
- handleTemplate(msg, node, rdmeTmpl).then((c) => { content["rdme"] = c }),
223
- handleTemplate(msg, node, lcnsTmpl).then((c) => { content["lcns"] = c }),
296
+ handleTemplate(msg, node, fs.readFileSync(packageJsonPath, 'utf8')).then((c) => { content["pkjs"] = c }),
297
+ handleTemplate(msg, node, fs.readFileSync(readmePath, 'utf8')).then((c) => { content["rdme"] = c }),
298
+ handleTemplate(msg, node, fs.readFileSync(licensePath, 'utf8')).then((c) => { content["lcns"] = c }),
224
299
  ];
225
300
 
226
301
  return Promise.all(promises).then( () => {
@@ -284,43 +359,15 @@ module.exports = function (RED) {
284
359
  });
285
360
 
286
361
  node.on("input", function (msg, send, done) {
362
+ send({ payload: msg.node })
363
+
287
364
  if (msg.node && msg.node.__task == "generate_from_templates") {
288
365
  try {
289
- var htmlPath = path.join(__dirname, 'templates', 'tmpl.html');
290
- var jsPath = path.join(__dirname, 'templates', 'tmpl.js');
291
-
292
- var jsonTmpl = fs.readFileSync(jsPath, 'utf8');
293
- var htmlTmpl = fs.readFileSync(htmlPath, 'utf8');
294
-
295
- handleTemplate(msg, node, jsonTmpl).then(function (data) {
296
- var jsData = data;
297
-
298
- handleTemplate(msg, node, htmlTmpl).then(function (data) {
299
- var nodeDef = convertToPkgFileNodes(msg, jsData, data)
300
-
301
- if (msg.node.createmanifest ) {
302
- /* create the package.json, readme and license files */
303
- createManifestFiles(msg, node, nodeDef).then( (data) => {
304
- var nodeImpStr = JSON.stringify(data);
305
-
306
- send({ payload: nodeImpStr })
307
-
308
- RED.comms.publish(
309
- "nodedev:perform-autoimport-nodes",
310
- RED.util.encodeObject({
311
- msg: "autoimport",
312
- payload: nodeImpStr,
313
- topic: msg.topic,
314
- nodeid: node.id,
315
- _msg: msg
316
- })
317
- );
318
- }).catch( (err) => {
319
- msg.error = err
320
- done(err.message, msg)
321
- })
322
- } else {
323
- var nodeImpStr = JSON.stringify(nodeDef);
366
+ createNodeDefintions(msg,node).then( (nodeDef) => {
367
+ if (msg.node.createmanifest ) {
368
+ /* create the package.json, readme and license files */
369
+ createManifestFiles(msg, node, nodeDef).then( (data) => {
370
+ var nodeImpStr = JSON.stringify(data);
324
371
 
325
372
  send({ payload: nodeImpStr })
326
373
 
@@ -334,17 +381,31 @@ module.exports = function (RED) {
334
381
  _msg: msg
335
382
  })
336
383
  );
337
- }
338
- done()
339
- }).catch((err) => {
340
- msg.error = err
341
- done(err.message, msg)
342
- })
384
+ }).catch( (err) => {
385
+ msg.error = err
386
+ done(err.message, msg)
387
+ })
388
+ } else {
389
+ var nodeImpStr = JSON.stringify(nodeDef);
390
+
391
+ send({ payload: nodeImpStr })
392
+
393
+ RED.comms.publish(
394
+ "nodedev:perform-autoimport-nodes",
395
+ RED.util.encodeObject({
396
+ msg: "autoimport",
397
+ payload: nodeImpStr,
398
+ topic: msg.topic,
399
+ nodeid: node.id,
400
+ _msg: msg
401
+ })
402
+ );
403
+ }
404
+ done()
343
405
  }).catch((err) => {
344
406
  msg.error = err
345
407
  done(err.message, msg)
346
408
  })
347
- //send({ payload: jsonString })
348
409
  } catch (err) {
349
410
  msg.error = err
350
411
  done(err.message, msg)
@@ -1,5 +1,5 @@
1
1
  module.exports = function(RED) {
2
- function {{ node.name }}Functionality(config) {
2
+ function Core{{ node.name }}Functionality(config) {
3
3
  RED.nodes.createNode(this,config);
4
4
 
5
5
  var node = this;
@@ -24,7 +24,7 @@ module.exports = function(RED) {
24
24
  });
25
25
  }
26
26
 
27
- RED.nodes.registerType("{{ node.name }}", {{ node.name }}Functionality);
27
+ RED.nodes.registerType("{{ node.name }}", Core{{ node.name }}Functionality);
28
28
 
29
29
  {{ #node.frt2bakcomm }}
30
30
  RED.httpAdmin.post("/{{ node.name }}/:id",
@@ -1,28 +1,33 @@
1
1
  {
2
2
  "name" : "{{__.ocb3}} pname {{__.ccb3}}",
3
- "version": "{{__.ocb2}} pversion {{__.ccb2}}",
3
+ "version": "{{__.ocb3}} pversion {{__.ccb3}}",
4
4
  "dependencies": {
5
5
  },
6
6
 
7
+ "description": "{{__.ocb3}} pdescription {{__.ccb3}}",
7
8
  "keywords": [
8
9
  "node-red"
9
10
  ],
10
11
 
11
- "homepage": "https://github.com/{{__.ocb2}} githubowner {{__.ccb2}}/{{__.ocb2}} githubrepo {{__.ccb2}}#readme",
12
12
  "license": "Don't do evil.",
13
- "author": "Joe Blog <joe.blog@spreads-the.love>",
13
+ "homepage": "https://github.com/{{__.ocb2}} githubowner {{__.ccb2}}/{{__.ocb2}} githubrepo {{__.ccb2}}#readme",
14
+ "author": "{{__.ocb3}} pauthorname {{__.ccb3}} <{{__.ocb3}} pauthoremail {{__.ccb3}}>",
14
15
  "engines": {
15
16
  "node": ">=14"
16
17
  },
17
18
 
18
19
  "node-red" : {
19
20
  "version": ">=3.0.0",
21
+ {{#node.isplugin}}
22
+ "plugins": {
23
+ {{{__.pluginstanza}}}
24
+ },
25
+ {{/node.isplugin}}
20
26
  "nodes": {
21
27
  {{{__.nodestanza}}}
22
28
  }
23
29
  },
24
30
 
25
- "description": "Description of what these nodes do.",
26
31
  "repository": {
27
32
  "type": "github",
28
33
  "url": "git+https://github.com/{{__.ocb2}} githubowner {{__.ccb2}}/{{__.ocb2}} githubrepo {{__.ccb2}}.git"
@@ -0,0 +1,138 @@
1
+ <script type="text/javascript">
2
+ (function() {
3
+ var globalYourConfigNode = null;
4
+
5
+ function ensureYourConfigNodeExists() {
6
+ // This function makes sure there is 1 instance of your config node is available, and that the globalYourConfigNode variable refers to it.
7
+ // Explained in the next step of this tutorial... --> https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020
8
+
9
+ // If we had found it previously, check if it has been deleted by the user behind our back
10
+ if (globalYourConfigNode !== null) {
11
+ var configNode = RED.nodes.node(globalYourConfigNode.id);
12
+ if (configNode === null) { globalYourConfigNode = null; }
13
+ }
14
+
15
+ // If not found previously, let's go find it
16
+ if (globalYourConfigNode === null) {
17
+ var configNodes = [];
18
+ RED.nodes.eachConfig(function(configNode) {
19
+ if (configNode.type === '{{ node.name }}') {
20
+ configNodes.push(configNode);
21
+ }
22
+ });
23
+
24
+ // Make sure we only have 1 config node
25
+ while (configNodes.length > 1) {
26
+ var configNode = configNodes.pop();
27
+ RED.nodes.remove(configNode.id);
28
+ RED.nodes.dirty(true);
29
+ }
30
+
31
+ // When we found a config node, let's use that one
32
+ if (configNodes.length === 1) { globalYourConfigNode = configNodes[0]; }
33
+ }
34
+
35
+ // When it doesn't exist yet, create it if required
36
+ if (globalYourConfigNode === null) {
37
+ // Remark: since this config node is dynamically created (and only used in this sidebar which isn't another node), the config
38
+ // node is in fact "unused". But since we don't want it to appear "unused" in the "config nodes" panel, we need to set hasUsers
39
+ // to false (see https://github.com/node-red/node-red/blob/master/CHANGELOG.md#0161-maintenance-release).
40
+ // The hasUsers needs also to be specified in the RED.nodes.registerType statement!
41
+ globalYourConfigNode = {
42
+ id: RED.nodes.id(), // on the server side, this is called RED.util.generateId()
43
+ _def: RED.nodes.getType("{{ node.name }}Cfg"),
44
+ type: "{{ node.name }}Cfg",
45
+ hasUsers: false,
46
+ users: [],
47
+ name: "{{ node.name }}",
48
+ label: function() { return this.name || "{{ node.name }}"},
49
+ /* values and data defined by this config node */
50
+ data: "some default value", // Default data
51
+ }
52
+
53
+ // Add the new config node to the collection of Node-RED nodes
54
+ RED.nodes.add(globalYourConfigNode);
55
+
56
+ // Make sure the "Deploy" button becomes active
57
+ RED.nodes.dirty(true);
58
+ }
59
+ }
60
+
61
+ // Add your plugin as a new tabsheet in the right sidebar AFTER the flow editor is completely started
62
+ var initialiseConfigNodeOnce = () => {
63
+ RED.events.off('runtime-state', initialiseConfigNodeOnce);
64
+
65
+ // The html content of the sidebar has been specified below as a data-template, from where it can be loaded:
66
+ var content = $($('script[type="text/x-red"][data-template-name="{{ node.name }}"]').i18n().html());
67
+
68
+ // Add a "Your sidebar" tabsheet to the right sidebar panel, in which this sidebar panel can be displayed
69
+ // --> more details: https://nodered.org/docs/api/ui/sidebar/
70
+ RED.sidebar.addTab({
71
+ id: "{{ node.name }}",
72
+ label: "{{ node.namelwr }}", // short name for the tab
73
+ name: "{{ node.name }}", // long name for the menu
74
+ content: content,
75
+ closeable: true,
76
+ // disableOnEdit: true,
77
+ enableOnEdit: true,
78
+ iconClass: "{{{ node.iconclass }}}" // your fontawesome icon
79
+ });
80
+
81
+ ensureYourConfigNodeExists();
82
+
83
+ {{#node.hasbutton}}
84
+ var doSomething = (e) => {
85
+ if (e) { e.preventDefault(); }
86
+ RED.notify("Button pressed in the side or action "+
87
+ "triggered. Current value: <b>" + globalYourConfigNode.data + "</b>",
88
+ "success");
89
+ }
90
+
91
+ $('#node-input-button').on('click', (e) => {
92
+ doSomething(e);
93
+ })
94
+
95
+ /* name of action will become "My Sidebar Action", label is generated
96
+ from action name - see https://nodered.org/docs/api/ui/actions/ */
97
+ RED.actions.add("{{ node.namelwr }}:my-sidebar-action",function() {
98
+ doSomething();
99
+ });
100
+ {{/node.hasbutton}}
101
+
102
+ // At startup load your config node data into the plugin sidebar html elements
103
+ $("#node-input-data").val(globalYourConfigNode.data);
104
+
105
+ // When the user has entered new data in the sidebar, then store it into the config node
106
+ $("#node-input-data").on("change", function() {
107
+ ensureYourConfigNodeExists();
108
+
109
+ let data = $(this).val();
110
+
111
+ if (globalYourConfigNode.data != data) {
112
+ globalYourConfigNode.data = data;
113
+ // Since the config node has been updated, the 'Deploy' button should become active
114
+ RED.nodes.dirty(true);
115
+ }
116
+ })
117
+ };
118
+ RED.events.on('runtime-state', initialiseConfigNodeOnce);
119
+ })();
120
+ </script>
121
+
122
+ <!-- The html for the right sidebar plugin screen -->
123
+ <script type="text/x-red" data-template-name="{{ node.name }}">
124
+ <div class="form-row">
125
+ <div style="position: relative; height: 100%; margin: 15px;">
126
+ <label for="node-input-data" style="margin-top: 15px"><i class="fa fa-cog"></i> Data</label>
127
+ <input type="text" id="node-input-data" style="width: 100%; margin-top: 30px">
128
+ </div>
129
+ </div>
130
+
131
+ {{#node.hasbutton}}
132
+ <div class="form-row">
133
+ <div style="position: relative; height: 100%; margin: 15px;">
134
+ <button id="node-input-button" class="success" style="width: 100%; margin-top: 30px">Do something</button>
135
+ </div>
136
+ </div>
137
+ {{/node.hasbutton}}
138
+ </script>
@@ -0,0 +1,22 @@
1
+ <script type="text/javascript">
2
+ (function ($) {
3
+ RED.nodes.registerType('{{ node.name }}Cfg', {
4
+ category: 'config',
5
+ hasUsers: false,
6
+ defaults: {
7
+ name: { value: "" },
8
+ data: { value: "" }
9
+ },
10
+ paletteLabel: '{{ node.name }}Cfg',
11
+ label: function () {
12
+ return this.name;
13
+ }
14
+ });
15
+ })(jQuery);
16
+ </script>
17
+
18
+ <!-- The html for the config node info panel (in right sidebar) -->
19
+ <script type="text/x-red" data-template-name="{{ node.name }}Cfg">
20
+ <p>{{{ node.summary }}}</p>
21
+ {{{ node.description }}}
22
+ </script>
@@ -0,0 +1,6 @@
1
+ module.exports = function (RED) {
2
+ function Config{{ node.name }}Functionality(config) {
3
+ RED.nodes.createNode(this, config)
4
+ }
5
+ RED.nodes.registerType('{{ node.name }}Cfg', Config{{ node.name }}Functionality);
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name" : "@gregoriusrippenstein/node-red-contrib-nodedev",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "dependencies": {
5
5
  "pako": "latest",
6
6
  "tar-stream": "latest",