@gregoriusrippenstein/node-red-contrib-introspection 0.9.20 → 0.10.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.
@@ -114,5 +114,8 @@
114
114
  </script>
115
115
 
116
116
  <script type="text/html" data-help-name="GetFlows">
117
- <p>Retrieves the current flow file from the server. This uses the Node-RED API and is therefore storage-method independent. Return value is a JSON.</p>
117
+ <p>Retrieves the current flow file from this server. This uses the Node-RED API and is therefore storage-method independent. Payload becomes a Json string.</p>
118
+
119
+ If the response is to sent to another host, then insert a JSON node to convert the response of this node to a Javascript array which can be passed as payload
120
+ to the SendFlow node.
118
121
  </script>
@@ -7,9 +7,15 @@
7
7
  name: {
8
8
  value:"",
9
9
  },
10
+
10
11
  hostUrl: {
11
- value: ""
12
+ value:"hostUrl",
13
+ required:true
14
+ },
15
+ hostUrlType: {
16
+ value:"str"
12
17
  },
18
+
13
19
  flowVersion: {
14
20
  value: "v1"
15
21
  },
@@ -29,6 +35,7 @@
29
35
  value: "env",
30
36
  },
31
37
  },
38
+
32
39
  inputs:1,
33
40
  outputs:1,
34
41
 
@@ -39,6 +46,7 @@
39
46
  labelStyle: function() {
40
47
  return this.name?"node_label_italic":"";
41
48
  },
49
+
42
50
  oneditprepare: function() {
43
51
  $("#node-input-apiUsername").typedInput({
44
52
  types:["env", "msg", "flow","global", "cred"],
@@ -46,10 +54,15 @@
46
54
  });
47
55
 
48
56
  $("#node-input-apiPassword").typedInput({
49
- types:["env", "msg", "flow","global", "env", "cred"],
57
+ types:["env", "msg", "flow","global", "cred"],
50
58
  typeField: "#node-input-apiPasswordType"
51
59
  });
52
60
 
61
+ $("#node-input-hostUrl").typedInput({
62
+ types:["str", "msg", "flow", "global", "env"],
63
+ typeField: "#node-input-hostUrlType"
64
+ });
65
+
53
66
  if ( $('#node-input-useAuthentication').is(":checked") ) {
54
67
  $('#useAuthentication-input-fields').show();
55
68
  } else {
@@ -75,7 +88,8 @@
75
88
 
76
89
  <div class="form-row">
77
90
  <label for="node-input-hostUrl"><i class="fa fa-tag"></i> Host</label>
78
- <input type="text" id="node-input-hostUrl" placeholder="Host URL">
91
+ <input type="text" id="node-input-hostUrl" placeholder="hostUrl">
92
+ <input type="hidden" id="node-input-hostUrlType" value="str">
79
93
  </div>
80
94
 
81
95
  <div class="form-row">
@@ -123,4 +137,6 @@
123
137
 
124
138
  <script type="text/html" data-help-name="SendFlow">
125
139
  <p>Send flow to another Node-RED instance.</p>
140
+
141
+ Payload is assumed to be a Javascript array containing flow data.
126
142
  </script>
@@ -11,29 +11,37 @@ module.exports = function(RED) {
11
11
 
12
12
  node.on("input", function(msg, send, done) {
13
13
  var sendFlow = (hdrs, got) => {
14
- got.post( (cfg.hostUrl || msg.hostUrl) + "/flows", {
15
- headers: {
16
- "Node-RED-API-Version": cfg.flowVersion,
17
- "Content-type": "application/json",
18
- "Node-RED-Deployment-Type": "full",
19
- ...hdrs
20
- },
21
- body: JSON.stringify(msg.payload)
22
- }).then( res => {
23
- send({
24
- ...msg,
25
- payload: res.body
26
- });
27
-
28
- node.status({fill:"green",shape:"dot",text:"Good"});
29
- setTimeout( function() {
30
- node.status({})
31
- }, 450);
32
-
33
- }).catch( err => {
34
- node.status({fill:"red",shape:"dot",text:"Failed"});
35
- node.error("error occurred", { ...msg, _err: err})
36
- });
14
+
15
+ RED.util.evaluateNodeProperty(cfg.hostUrl, cfg.hostUrlType, node, msg, (err, result) => {
16
+ if (err) {
17
+ node.status({ fill: "red", shape: "dot", text: "Failed" });
18
+ node.error("unable to obtain host url", { ...msg, _err: err })
19
+ } else {
20
+ got.post( result + "/flows", {
21
+ headers: {
22
+ "Node-RED-API-Version": cfg.flowVersion,
23
+ "Content-type": "application/json",
24
+ "Node-RED-Deployment-Type": "full",
25
+ ...hdrs
26
+ },
27
+ body: JSON.stringify(msg.payload)
28
+ }).then( res => {
29
+ send({
30
+ ...msg,
31
+ payload: res.body
32
+ });
33
+
34
+ node.status({fill:"green",shape:"dot",text:"Good"});
35
+ setTimeout( function() {
36
+ node.status({})
37
+ }, 450);
38
+
39
+ }).catch( err => {
40
+ node.status({fill:"red",shape:"dot",text:"Failed"});
41
+ node.error("posting data to host", { ...msg, _err: err})
42
+ });
43
+ }
44
+ })
37
45
  };
38
46
 
39
47
  /**
@@ -45,19 +53,17 @@ module.exports = function(RED) {
45
53
 
46
54
  node.status({fill:"blue",shape:"dot",text:"Requesting token"});
47
55
 
48
- RED.util.evaluateNodeProperty(cfg.apiUsername, cfg.apiUsernameType,
49
- node, msg, (err, result) => {
56
+ RED.util.evaluateNodeProperty(cfg.apiUsername, cfg.apiUsernameType, node, msg, (err, result) => {
50
57
  if (err) {
51
58
  node.status({fill:"red",shape:"dot",text:"Failed"});
52
- node.error("error occurred", { ...msg, _err: err})
59
+ node.error("unable to obtain api username", { ...msg, _err: err})
53
60
  } else {
54
61
  username = result;
55
62
 
56
- RED.util.evaluateNodeProperty(cfg.apiPassword, cfg.apiPasswordType,
57
- node, msg, (err, result) => {
63
+ RED.util.evaluateNodeProperty(cfg.apiPassword, cfg.apiPasswordType, node, msg, (err, result) => {
58
64
  if (err) {
59
65
  node.status({fill:"red",shape:"dot",text:"Failed"});
60
- node.error("error occurred", {...msg, _err: err})
66
+ node.error("unable to obtain api password", {...msg, _err: err})
61
67
  } else {
62
68
  password = result;
63
69
 
@@ -69,31 +75,39 @@ module.exports = function(RED) {
69
75
  "password": password
70
76
  }
71
77
 
72
- import('got').then( (module) => {
73
- module.got.post( (cfg.hostUrl || msg.hostUrl) + "/auth/token", {
74
- json: data
75
- }).then( res => {
76
- node.status({
77
- fill:"blue",
78
- shape:"dot",
79
- text:"Sending flow"
80
- });
78
+ RED.util.evaluateNodeProperty(cfg.hostUrl, cfg.hostUrlType, node, msg, (err, result) => {
79
+ if (err) {
80
+ node.status({ fill: "red", shape: "dot", text: "Failed" });
81
+ node.error("error occurred", { ...msg, _err: err })
82
+ } else {
83
+
84
+ import('got').then( (module) => {
85
+ module.got.post( result + "/auth/token", {
86
+ json: data
87
+ }).then( res => {
88
+ node.status({
89
+ fill:"blue",
90
+ shape:"dot",
91
+ text:"Sending flow"
92
+ });
81
93
 
82
- var access_token = JSON.parse(res.body).access_token;
94
+ var access_token = JSON.parse(res.body).access_token;
83
95
 
84
- sendFlow({
85
- "Authorization": "Bearer " + access_token
86
- }, module.got);
96
+ sendFlow({
97
+ "Authorization": "Bearer " + access_token
98
+ }, module.got);
87
99
 
88
- }).catch((err) => {
89
- node.status({fill:"red",shape:"dot",text:"Failed"});
90
- node.error( "error occurred", { ...msg, _err: err });
91
- });
92
- });
100
+ }).catch((err) => {
101
+ node.status({fill:"red",shape:"dot",text:"Failed"});
102
+ node.error( "unable to obtain api auth token", { ...msg, _err: err });
103
+ });
104
+ });
105
+ }
106
+ })
93
107
  }
94
108
  })
95
109
  }
96
- })
110
+ })
97
111
  } else {
98
112
  /*
99
113
  * Authentication free zone...
@@ -8,9 +8,15 @@
8
8
  name: {
9
9
  value:"",
10
10
  },
11
+
11
12
  hostUrl: {
12
- value: ""
13
+ value:"hostUrl",
14
+ required:true
15
+ },
16
+ hostUrlType: {
17
+ value:"str"
13
18
  },
19
+
14
20
  useAuthentication: {
15
21
  value:false
16
22
  },
@@ -30,6 +36,7 @@
30
36
  value: false
31
37
  }
32
38
  },
39
+
33
40
  inputs:1,
34
41
  outputs:1,
35
42
 
@@ -40,6 +47,7 @@
40
47
  labelStyle: function() {
41
48
  return this.name?"node_label_italic":"";
42
49
  },
50
+
43
51
  oneditprepare: function() {
44
52
  $("#node-input-apiUsername").typedInput({
45
53
  types:["env", "msg", "flow","global", "cred"],
@@ -51,6 +59,11 @@
51
59
  typeField: "#node-input-apiPasswordType"
52
60
  });
53
61
 
62
+ $("#node-input-hostUrl").typedInput({
63
+ types:["str", "msg", "flow", "global", "env"],
64
+ typeField: "#node-input-hostUrlType"
65
+ });
66
+
54
67
  if ( $('#node-input-useAuthentication').is(":checked") ) {
55
68
  $('#useAuthentication-input-fields').show();
56
69
  } else {
@@ -97,8 +110,9 @@
97
110
  -->
98
111
 
99
112
  <div class="form-row hostUrl-row">
100
- <label for="node-input-hostUrl"><i class="fa fa-tag"></i> Host</label>
101
- <input type="text" id="node-input-hostUrl" placeholder="Host URL">
113
+ <label for="node-input-hostUrl"><i class="fa fa-tag"></i> Host</label>
114
+ <input type="text" id="node-input-hostUrl" placeholder="hostUrl">
115
+ <input type="hidden" id="node-input-hostUrlType" value="str">
102
116
  </div>
103
117
 
104
118
  <div class="form-row">
@@ -134,4 +148,22 @@
134
148
 
135
149
  <script type="text/html" data-help-name="InstallPackage">
136
150
  <p>Install package on another Node-RED instance.</p>
151
+
152
+ <p>This takes two forms, it can either install a package by name and version (defaults to "latest") or it can
153
+ accept a buffer object containing a .tgz package file.</p>
154
+
155
+ <p></p>For the first case:
156
+ <pre>
157
+ msg.payload = {
158
+ module: "@gregoriusrippenstein/node-red-contrib-introspection",
159
+ version: "0.10.0"
160
+ }
161
+ </pre>
162
+
163
+ <p>To install a .tgz file, read it into a Buffer object and set the payload to:</p>
164
+ <pre>
165
+ msg.payload = {
166
+ data: new Buffer("ddd")
167
+ }
168
+ </pre>
137
169
  </script>
@@ -15,10 +15,17 @@ module.exports = function(RED) {
15
15
  return node.error("msg.payload missing or payload not hash", msg)
16
16
  }
17
17
 
18
+ /*
19
+ * This defines the helper function - installPackage - that is called either with
20
+ * an authentication token or without. That is determined below.
21
+ */
18
22
  var installPackage = (hdrs, got) => {
19
23
  let body = undefined
20
24
  let headers = {}
21
25
 
26
+ /*
27
+ * Check the Payload - either module name or .tgz buffer.
28
+ */
22
29
  if ( msg.payload.module ) {
23
30
  body = JSON.stringify({
24
31
  module: msg.payload.module,
@@ -40,27 +47,35 @@ module.exports = function(RED) {
40
47
  return node.error("msg.payload not well defined", msg)
41
48
  }
42
49
 
43
- got.post( (cfg.hostUrl || msg.hostUrl) + "/nodes", {
44
- headers: {
45
- ...headers,
46
- ...hdrs
47
- },
48
- body: body
49
- }).then( res => {
50
- send({
51
- ...msg,
52
- payload: JSON.parse(res.body)
53
- });
54
-
55
- node.status({fill:"green",shape:"dot",text:"Good"});
56
- setTimeout( function() {
57
- node.status({})
58
- }, 450);
59
-
60
- }).catch( err => {
61
- node.status({fill:"red",shape:"dot",text:"Failed"});
62
- node.error("error occurred", { ...msg, _err: err })
63
- });
50
+ /*
51
+ * Connect and send to host.
52
+ */
53
+ RED.util.evaluateNodeProperty(cfg.hostUrl, cfg.hostUrlType, node, msg, (err, result) => {
54
+ if (err) {
55
+ node.status({ fill: "red", shape: "dot", text: "Failed" });
56
+ node.error("unable to obtain host url", { ...msg, _err: err })
57
+ } else {
58
+ got.post( result + "/nodes", {
59
+ headers: {
60
+ ...headers,
61
+ ...hdrs
62
+ },
63
+ body: body
64
+ }).then( res => {
65
+ send({
66
+ ...msg,
67
+ payload: JSON.parse(res.body)
68
+ });
69
+
70
+ node.status({fill:"green",shape:"dot",text:"Good"});
71
+ setTimeout( function() { node.status({}) }, 450);
72
+
73
+ }).catch( err => {
74
+ node.status({fill:"red",shape:"dot",text:"Failed"});
75
+ node.error("unable to connect to host", { ...msg, _err: err })
76
+ });
77
+ }
78
+ })
64
79
  };
65
80
 
66
81
  /**
@@ -76,7 +91,7 @@ module.exports = function(RED) {
76
91
  node, msg, (err, result) => {
77
92
  if (err) {
78
93
  node.status({fill:"red",shape:"dot",text:"Failed"});
79
- node.error("error occurred", { ...msg, _err: err})
94
+ node.error("unable to obtain api username", { ...msg, _err: err})
80
95
  } else {
81
96
  username = result;
82
97
 
@@ -84,7 +99,7 @@ module.exports = function(RED) {
84
99
  node, msg, (err, result) => {
85
100
  if (err) {
86
101
  node.status({fill:"red",shape:"dot",text:"Failed"});
87
- node.error("error occurred", { ...msg, _err: err} )
102
+ node.error("unable to obtain api password", { ...msg, _err: err} )
88
103
  } else {
89
104
  password = result;
90
105
 
@@ -96,27 +111,34 @@ module.exports = function(RED) {
96
111
  "password": password
97
112
  }
98
113
 
99
- import('got').then( (module) => {
100
- module.got.post( (cfg.hostUrl || msg.hostUrl) + "/auth/token", {
101
- json: data
102
- }).then( res => {
103
- node.status({
104
- fill:"blue",
105
- shape:"dot",
106
- text:"Sending flow"
114
+ RED.util.evaluateNodeProperty(cfg.hostUrl, cfg.hostUrlType, node, msg, (err, result) => {
115
+ if (err) {
116
+ node.status({ fill: "red", shape: "dot", text: "Failed" });
117
+ node.error("unable to obtain api host url", { ...msg, _err: err })
118
+ } else {
119
+ import('got').then( (module) => {
120
+ module.got.post( result + "/auth/token", {
121
+ json: data
122
+ }).then( res => {
123
+ node.status({
124
+ fill:"blue",
125
+ shape:"dot",
126
+ text:"Installing packages"
127
+ });
128
+
129
+ var access_token = JSON.parse(res.body).access_token;
130
+
131
+ installPackage({
132
+ "Authorization": "Bearer " + access_token
133
+ }, module.got);
134
+
135
+ }).catch((err) => {
136
+ node.status({fill:"red",shape:"dot",text:"Failed"});
137
+ node.error( "error occured", { ...msg, _err: err } );
138
+ });
107
139
  });
108
-
109
- var access_token = JSON.parse(res.body).access_token;
110
-
111
- installPackage({
112
- "Authorization": "Bearer " + access_token
113
- }, module.got);
114
-
115
- }).catch((err) => {
116
- node.status({fill:"red",shape:"dot",text:"Failed"});
117
- node.error( "error occured", { ...msg, _err: err } );
118
- });
119
- });
140
+ }
141
+ })
120
142
  }
121
143
  })
122
144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gregoriusrippenstein/node-red-contrib-introspection",
3
- "version": "0.9.20",
3
+ "version": "0.10.0",
4
4
  "dependencies": {
5
5
  "got": "^13",
6
6
  "uglify-js": "^3.17.4",
@@ -6,7 +6,7 @@
6
6
 
7
7
  function setupTreelist(){var e=collectOrphans();if(0==e.length){RED.notify("No Orphans Found",{type:"success",timeout:2e3});try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){}}else{try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){$("#node-input-orphan-target-container-div").css({width:"100%",height:"calc(100%)"}).treeList({multi:!1}).on("treelistitemmouseover",function(e,t){}).on("treelistitemmouseout",function(e,t){}).on("treelistselect",function(e,t){t.node&&(RED.workspaces.show(t.node.z,!1,!1,!0),RED.view.reveal(t.node.id,!0),RED.view.redraw())}).on("treelistconfirm",function(e,t){var n;t.node&&(n=t.node.id,setTimeout(()=>{var e=RED.nodes.node(n);e&&(RED.view.reveal(e.id),RED.view.select(e.id),RED.editor.edit(e)),n==RED.workspaces.active()&&RED.workspaces.edit()},50))}),$("#node-input-orphan-target-filter").show();var n=$("#node-input-orphan-target-filter").searchBox({style:"compact",delay:300,change:function(){var e,t=$(this).val().trim().toLowerCase();""===t?($("#node-input-orphan-target-container-div").treeList("filter",null),n.searchBox("count","")):(e=$("#node-input-orphan-target-container-div").treeList("filter",function(e){return-1<e.label.toLowerCase().indexOf(t)||-1<e.node.type.toLowerCase().indexOf(t)}),n.searchBox("count",e+" / "+$("#node-input-orphan-target-container-div").treeList("data").length))}})}$("#node-input-orphan-target-container-div").treeList("data",e.sort((e,t)=>e.node.z>t.node.z))}}function collectOrphans(){let t=new Set;var n=[],i=(RED.nodes.eachLink(e=>{t.add(e.source),t.add(e.target)}),RED.nodes.eachNode(e=>{(!t.has(e)||"link out"==e.type&&"link"==e.mode&&0==e.links.reduce((e,t)=>e||!!RED.nodes.node(t),!1))&&n.push(e)}),[]),r={};return n.forEach(function(e){var t=RED.nodes.getType(e.type);if(t){var n=t.label,n=("function"==typeof n?n.call(e):n)||"",o=e.type;if(0===o.indexOf("subflow:"))return}t&&n||(n=e.type),r[e.id]={node:e,label:n,sublabel:o,selected:!1,checkbox:!1},i.push(r[e.id])}),i}
8
8
 
9
- function nr_intro_generate_svg_4_0(r,t){return e=>{try{handleSvgObject($($("#red-ui-workspace-chart").find("svg")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+n+"</text></svg>")}}}function nr_intro_generate_svg_3_1(r,t){return e=>{try{handleSvgObject($($("#red-ui-workspace-chart").find("svg")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+n+"</text></svg>")}}}function nr_intro_generate_svg_3_0(r,t){return e=>{try{handleSvgObject($($("svg")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+n+"</text></svg>")}}}function handleSvgObject(a,t,e){var n=a.clone(),r=(n.find("foreignObject").remove(),n.find("svg.__screenshot").remove(),'width="'+a.attr("width")+'" height="'+a.attr("height")+'"'),s=RED.settings.version.split("."),i=parseInt(s[0]),s=parseInt(s[1]);if(3<=i&&1<=s||4<=i){var o=$($($(a).children("g")[0]).children("g")[0]).children("g"),l={x:8e3,y:8e3,w:-1,h:-1};for(let t=1;t<o.length;t++){var g=o[t].getBBox();0==g.width&&0==g.height||(l.x=Math.min(g.x,l.x),l.y=Math.min(g.y,l.y),l.w=Math.max(g.width,l.w),l.h=Math.max(g.height,l.h))}r+=` viewBox='${l.x} ${l.y} ${l.w} ${l.h}'`}function c(t,e){for(var n=0;n<t.length;n++){var s=t.item(n),i=e[n];["stroke-width","fill-opacity","stroke-opacity","opacity","stroke-dasharray"].forEach(function(t){s.setAttribute(t,$(i).attr(t)||$(i).css(t))}),["fill","stroke"].forEach(function(t){var e,n,r=(e=$(i).attr(t)||$(i).css(t))&&null!==e&&"none"!=e?(n=e.match(/^#(.)(.)(.)$/))?"#"+n[1]+n[1]+n[2]+n[2]+n[3]+n[3]:(n=e.match(/^#......$/))?e:null===(n=e.match(/^rgb\(([0-9]+),\s+([0-9]+),\s+([0-9]+)/))?(r=e.match(/^rgba\(([0-9]+),\s+([0-9]+),\s+([0-9]+),\s+([0-9]+)/))?{clr:"#"+("0"+parseInt(r[1],10).toString(16)).slice(-2)+("0"+parseInt(r[2],10).toString(16)).slice(-2)+("0"+parseInt(r[3],10).toString(16)).slice(-2),opa:r[4]}:(console.log("Screenshot node: returned unknown color: "+e),e):"#"+("0"+parseInt(n[1],10).toString(16)).slice(-2)+("0"+parseInt(n[2],10).toString(16)).slice(-2)+("0"+parseInt(n[3],10).toString(16)).slice(-2):"none";"object"==typeof r?(s.setAttribute(t+"-opacity",r.opa),s.setAttribute(t,r.clr)):s.setAttribute(t,r)}),$(i).hasClass("hide")&&("g"==s.tagName&&s.setAttribute("opacity","0"),s.setAttribute("visibility","hidden"))}}var s='<?xml version="1.0" standalone="no"?>\r\n<svg '+r+' pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" class="__screenshot" xmlns:xlink="http://www.w3.org/1999/xlink">\r\n',i=n.html(),h=(new DOMParser).parseFromString(s+i+"\r\n</svg>","image/svg+xml"),v=t=>t,f=(e.rmidsandclasses&&(v=e=>(["g","rect","line","path","circle","image","text"].forEach(t=>{$(e.getElementsByTagName(t)).each((t,e)=>{e.setAttribute("class",""),e.setAttribute("id","")})}),e)),["g","rect","line","path","circle","image"].forEach(function(t){c(h.getElementsByTagName(t),a.find(t))}),["text"].forEach(function(t){c(h.getElementsByTagName(t),a.find(t));for(var e=h.getElementsByTagName(t),n=a.find(t),r=0;r<e.length;r++){var s=e.item(r),i=n[r];["font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","text-anchor","dominant-baseline"].forEach(function(t){s.setAttribute(t,$(i).attr(t)||$(i).css(t))})}}),h.getElementsByTagName("image")),w={},m=(n,r,s)=>{var i=n.getAttribute("xlink:href")||n.getAttribute("href"),a=i.substr(-4,4).toLowerCase(),o={".jpg":"jpeg",jpeg:"jpeg",".png":"png",".svg":"svg+xml"};if(w[i])return n.setAttribute("xlink:href","data:image/"+o[a]+";base64,"+w[i]),s(r-1);switch(a){case".jpg":case"jpeg":case".png":var l=new XMLHttpRequest;l.open("GET",i,!0),l.responseType="arraybuffer";l.onerror=function(t){s(r-1)},l.onload=function(t){var e=l.response;e&&(e=(t=>{for(var e="",n=new Uint8Array(t),r=n.byteLength,s=0;s<r;s++)e+=String.fromCharCode(n[s]);return window.btoa(e)})(e),w[i]=e,n.setAttribute("xlink:href","data:image/"+o[a]+";base64,"+e)),s(r-1)},l.send(null);break;case".svg":$.get(i,function(t){var e=new XMLSerializer,e=btoa(e.serializeToString(t));w[i]=e,n.setAttribute("xlink:href","data:image/svg+xml;base64,"+e),s(r-1)})}},d=e=>{if(e<0)t((new XMLSerializer).serializeToString(v(h)));else try{m(f.item(e),e,d)}catch(t){d(e-1)}};0<f.length?m(f.item(f.length-1),f.length-1,d):t((new XMLSerializer).serializeToString(v(h)))}function generatorFunctionForVersion(t,e){var n,r=t.settings.version.split("."),s=r[0],r=r[1];if("3"==s){if("0"==r)return nr_intro_generate_svg_3_0(t,e);if("1"==r)return nr_intro_generate_svg_3_1(t,e)}return"4"==s&&"0"==r?nr_intro_generate_svg_4_0(t,e):(n=t,t=>{var e="Node-RED version ("+n.settings.version+") not supported";n.notify(e,{type:"error"}),t&&t('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+e+"</text></svg>")})}function addPanZoom(){var t=d3.select("#node-input-screenshot-svgcontainer svg"),e=(t.html("<g>"+t.html()+"</g>"),setTimeout(()=>{var t=$("#node-input-screenshot-svgcontainer svg"),e=$(t).attr("viewBox").split(" ");t.animate({height:parseInt(e[3]),width:parseInt(e[2])},800,"swing")},100),t.select("g")),n=d3.behavior.zoom().scaleExtent([.1,200]).on("zoom",function(t){e.attr({transform:"translate("+n.translate()+") scale("+n.scale()+")"})});t.call(n)}
9
+ function nr_intro_generate_svg_4_0(r,t){return e=>{try{handleSvgObject($($("#red-ui-workspace-chart").find("svg")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+n+"</text></svg>")}}}function nr_intro_generate_svg_3_1(r,t){return e=>{try{handleSvgObject($($("#red-ui-workspace-chart").find("svg")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+n+"</text></svg>")}}}function nr_intro_generate_svg_3_0(r,t){return e=>{try{handleSvgObject($($("svg")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+n+"</text></svg>")}}}function handleSvgObject(a,t,e){var n=a.clone(),r=(n.find("foreignObject").remove(),n.find("svg.__screenshot").remove(),'width="'+a.attr("width")+'" height="'+a.attr("height")+'"'),s=RED.settings.version.split("."),i=parseInt(s[0]),s=parseInt(s[1]);if(3<=i&&1<=s||4<=i){var o=$($($(a).children("g")[0]).children("g")[0]).children("g"),l={x:8e3,y:8e3,w:-1,h:-1};for(let t=1;t<o.length;t++){var g=o[t].getBBox();0==g.width&&0==g.height||(l.x=Math.min(g.x,l.x),l.y=Math.min(g.y,l.y),l.w=Math.max(g.width,l.w),l.h=Math.max(g.height,l.h))}r+=` viewBox='${l.x} ${l.y} ${l.w} ${l.h}'`}function c(t,e){for(var n=0;n<t.length;n++){var s=t.item(n),i=e[n];["stroke-width","fill-opacity","stroke-opacity","opacity","stroke-dasharray"].forEach(function(t){s.setAttribute(t,$(i).attr(t)||$(i).css(t))}),["fill","stroke"].forEach(function(t){var e,n,r=(e=$(i).attr(t)||$(i).css(t))&&null!==e&&"none"!=e?(n=e.match(/^#(.)(.)(.)$/))?"#"+n[1]+n[1]+n[2]+n[2]+n[3]+n[3]:(n=e.match(/^#......$/))?e:null===(n=e.match(/^rgb\(([0-9]+),\s+([0-9]+),\s+([0-9]+)/))?(r=e.match(/^rgba\(([0-9]+),\s+([0-9]+),\s+([0-9]+),\s+([0-9]+)/))?{clr:"#"+("0"+parseInt(r[1],10).toString(16)).slice(-2)+("0"+parseInt(r[2],10).toString(16)).slice(-2)+("0"+parseInt(r[3],10).toString(16)).slice(-2),opa:r[4]}:(console.log("Screenshot node: returned unknown color: "+e),e):"#"+("0"+parseInt(n[1],10).toString(16)).slice(-2)+("0"+parseInt(n[2],10).toString(16)).slice(-2)+("0"+parseInt(n[3],10).toString(16)).slice(-2):"none";"object"==typeof r?(s.setAttribute(t+"-opacity",r.opa),s.setAttribute(t,r.clr)):s.setAttribute(t,r)}),$(i).hasClass("hide")&&("g"==s.tagName&&s.setAttribute("opacity","0"),s.setAttribute("visibility","hidden"))}}var s='<?xml version="1.0" standalone="no"?>\r\n<svg '+r+' pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" class="__screenshot" xmlns:xlink="http://www.w3.org/1999/xlink">\r\n',i=n.html(),h=(new DOMParser).parseFromString(s+i+"\r\n</svg>","image/svg+xml"),v=t=>t,f=(e.rmidsandclasses&&(v=e=>(["g","rect","line","path","circle","image","text"].forEach(t=>{$(e.getElementsByTagName(t)).each((t,e)=>{e.setAttribute("class",""),e.setAttribute("id","")})}),e)),["g","rect","line","path","circle","image"].forEach(function(t){c(h.getElementsByTagName(t),a.find(t))}),["text"].forEach(function(t){c(h.getElementsByTagName(t),a.find(t));for(var e=h.getElementsByTagName(t),n=a.find(t),r=0;r<e.length;r++){var s=e.item(r),i=n[r];["font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","text-anchor","dominant-baseline"].forEach(function(t){s.setAttribute(t,$(i).attr(t)||$(i).css(t))})}}),h.getElementsByTagName("image")),w={},m=(n,r,s)=>{var i=n.getAttribute("xlink:href")||n.getAttribute("href"),a=i.substr(-4,4).toLowerCase(),o={".jpg":"jpeg",jpeg:"jpeg",".png":"png",".svg":"svg+xml"};if(w[i])return n.setAttribute("xlink:href","data:image/"+o[a]+";base64,"+w[i]),s(r-1);switch(a){case".jpg":case"jpeg":case".png":var l=new XMLHttpRequest;l.open("GET",i,!0),l.responseType="arraybuffer";l.onerror=function(t){s(r-1)},l.onload=function(t){var e=l.response;e&&(e=(t=>{for(var e="",n=new Uint8Array(t),r=n.byteLength,s=0;s<r;s++)e+=String.fromCharCode(n[s]);return window.btoa(e)})(e),w[i]=e,n.setAttribute("xlink:href","data:image/"+o[a]+";base64,"+e)),s(r-1)},l.send(null);break;case".svg":$.get(i,function(t){var e=new XMLSerializer,e=btoa(e.serializeToString(t));w[i]=e,n.setAttribute("xlink:href","data:image/svg+xml;base64,"+e),s(r-1)});break;default:console.log("SVG Capture ignoring file prefix: "+a),s(r-1)}},d=e=>{if(e<0)t((new XMLSerializer).serializeToString(v(h)));else try{m(f.item(e),e,d)}catch(t){d(e-1)}};0<f.length?m(f.item(f.length-1),f.length-1,d):t((new XMLSerializer).serializeToString(v(h)))}function generatorFunctionForVersion(t,e){var n,r=t.settings.version.split("."),s=r[0],r=r[1];if("3"==s){if("0"==r)return nr_intro_generate_svg_3_0(t,e);if("1"==r)return nr_intro_generate_svg_3_1(t,e)}return"4"==s&&"0"==r?nr_intro_generate_svg_4_0(t,e):(n=t,t=>{var e="Node-RED version ("+n.settings.version+") not supported";n.notify(e,{type:"error"}),t&&t('<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+e+"</text></svg>")})}function addPanZoom(){var t=d3.select("#node-input-screenshot-svgcontainer svg"),e=(t.html("<g>"+t.html()+"</g>"),setTimeout(()=>{var t=$("#node-input-screenshot-svgcontainer svg"),e=$(t).attr("viewBox").split(" ");t.animate({height:parseInt(e[3]),width:parseInt(e[2])},800,"swing")},100),t.select("g")),n=d3.behavior.zoom().scaleExtent([.1,200]).on("zoom",function(t){e.attr({transform:"translate("+n.translate()+") scale("+n.scale()+")"})});t.call(n)}
10
10
 
11
11
  function setupTreelistInfoness(){var e=collectUndocumentedNodes();if(0==e.length){RED.notify("All nodes documented",{type:"success",timeout:2e3});try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){}}else{try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){$("#node-input-orphan-target-container-div").css({width:"100%",height:"calc(100%)"}).treeList({multi:!1}).on("treelistitemmouseover",function(e,t){}).on("treelistitemmouseout",function(e,t){}).on("treelistselect",function(e,t){t.node&&(RED.workspaces.show(t.node.z,!1,!1,!0),RED.view.reveal(t.node.id,!0),RED.view.redraw())}).on("treelistconfirm",function(e,t){var i;t.node&&(i=t.node.id,setTimeout(()=>{var e=RED.nodes.node(i);e&&(RED.view.reveal(e.id),RED.view.select(e.id),RED.editor.edit(e,"editor-tab-description")),i==RED.workspaces.active()&&RED.workspaces.edit()},50))}),$("#node-input-orphan-target-filter").show();var i=$("#node-input-orphan-target-filter").searchBox({style:"compact",delay:300,change:function(){var e,t=$(this).val().trim().toLowerCase();""===t?($("#node-input-orphan-target-container-div").treeList("filter",null),i.searchBox("count","")):(e=$("#node-input-orphan-target-container-div").treeList("filter",function(e){return-1<e.label.toLowerCase().indexOf(t)||-1<e.node.type.toLowerCase().indexOf(t)}),i.searchBox("count",e+" / "+$("#node-input-orphan-target-container-div").treeList("data").length))}})}$("#node-input-orphan-target-container-div").treeList("data",e.sort((e,t)=>e.node.z>t.node.z))}}function collectUndocumentedNodes(){let t=[];RED.nodes.eachNode(e=>{if($("#"+e.id).find(".red-ui-info-available-indicator").remove(),e.info&&e.info.trim()&&$("#"+e.id)[0]){var i=document.createElementNS("http://www.w3.org/2000/svg","g"),n=(i.setAttribute("class","red-ui-info-available-indicator"),i.setAttribute("transform","translate(20,10)"),i.setAttribute("id","infoclk-"+e.id),document.createElementNS("http://www.w3.org/2000/svg","g")),o=(n.setAttribute("class","tip"),n.setAttribute("fill","lightyellow"),document.createElementNS("http://www.w3.org/2000/svg","rect")),o=(o.setAttribute("width","30"),o.setAttribute("height","20"),o.setAttribute("x",$("#"+e.id)[0].getBBox().width-60),o.setAttribute("y","-15"),o.setAttribute("rx","2"),o.setAttribute("style","cursor: pointer;"),n.append(o),document.createElementNS("http://www.w3.org/2000/svg","text"));o.setAttribute("x",$("#"+e.id)[0].getBBox().width-55),o.setAttribute("y","-6"),o.appendChild(document.createTextNode("docs")),n.append(o),i.append(n),$(i).insertBefore($("#"+e.id).find(".red-ui-flow-node"));let t=e.id;$("#infoclk-"+e.id).on("click",e=>{e&&e.preventDefault();e=RED.nodes.node(t);RED.editor.edit(e,"editor-tab-description"),RED.sidebar.show("info")})}else e.z==RED.workspaces.active()&&["link in","link out","link call"].indexOf(e.type)<0&&t.push(e)});var o=[],r={};return t.forEach(function(e){var t=RED.nodes.getType(e.type);if(t){var i,n=t.label,n=("function"==typeof n?n.call(e):n)||"";if(0===(i=e.type).indexOf("subflow:"))return}t&&n||(n=e.type),r[e.id]={node:e,label:n,sublabel:i,selected:!1,checkbox:!1},o.push(r[e.id])}),o}
12
12