@gregoriusrippenstein/node-red-contrib-introspection 0.4.4 → 0.5.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.
- package/README.md +49 -35
- package/examples/client-code.json +926 -0
- package/examples/drawsvg-flow.json +18 -14
- package/examples/get-flows.json +471 -31
- package/examples/orphans.json +220 -0
- package/examples/seeker-sink.json +349 -2465
- package/nodes/60-client-code.html +30 -0
- package/package.json +7 -8
- package/plugins/orphans.html +45 -0
- package/plugins/screenshot.html +74 -0
- package/examples/trigger-and-save-screenshot.json +0 -155
- package/nodes/15-screenshot.html +0 -576
- package/nodes/15-screenshot.js +0 -29
- package/nodes/20-orphans.html +0 -183
- package/nodes/20-orphans.js +0 -17
- package/nodes/25-ismobile.html +0 -49
- package/nodes/25-ismobile.js +0 -17
- package/nodes/30-navigator.html +0 -77
- package/nodes/30-navigator.js +0 -17
- package/nodes/40-drawsvg.html +0 -51
- package/nodes/40-drawsvg.js +0 -25
package/nodes/15-screenshot.html
DELETED
|
@@ -1,576 +0,0 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
function nr_intro_generate_svg_3_1( callbackWithSvgCode ) {
|
|
3
|
-
//****
|
|
4
|
-
// Node-RED 3.1.x has multiple SVGs all over the place, so we
|
|
5
|
-
// need to look for the one with 8000x8000.
|
|
6
|
-
// Tested this on Node-RED 3.1.0.beta.4 - dunno about other 3.1.x.beta.y
|
|
7
|
-
//****
|
|
8
|
-
|
|
9
|
-
return (callbackWithSvgCode) => {
|
|
10
|
-
try {
|
|
11
|
-
handleSvgObject( $($('svg[width=8000]')[0]), callbackWithSvgCode );
|
|
12
|
-
} catch ( e ) {
|
|
13
|
-
var msg = "Error Generating SVG: " + JSON.stringify(e);
|
|
14
|
-
|
|
15
|
-
red.notify(msg,{ type: "error" });
|
|
16
|
-
|
|
17
|
-
var svgData = '<?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">'+msg+'</text></svg>';
|
|
18
|
-
|
|
19
|
-
callbackWithSvgCode(svgData);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function nr_intro_generate_svg_3_0( red ) {
|
|
25
|
-
//****
|
|
26
|
-
// for Node-RED v3.0.x (well 3.0.2 tested, dunno about 3.0.1)
|
|
27
|
-
//****
|
|
28
|
-
|
|
29
|
-
return (callbackWithSvgCode) => {
|
|
30
|
-
try {
|
|
31
|
-
handleSvgObject( $($('svg')[0]), callbackWithSvgCode);
|
|
32
|
-
} catch ( e ) {
|
|
33
|
-
var msg = "Error Generating SVG: " + JSON.stringify(e);
|
|
34
|
-
|
|
35
|
-
red.notify(msg,{ type: "error" });
|
|
36
|
-
|
|
37
|
-
var svgData = '<?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">'+msg+'</text></svg>';
|
|
38
|
-
|
|
39
|
-
callbackWithSvgCode(svgData);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
function handleSvgObject( origSvg, callbackWithSvgCode ) {
|
|
46
|
-
// the DOMParser of Firefox does not like foreignObjects, so remove them.
|
|
47
|
-
// Correction: DOMParser doesn't mind foreignObjects as long as there is
|
|
48
|
-
// any HTML/<img>-tags in the foreignObjects.,,, of course, image tags
|
|
49
|
-
// rarely occur but nonetheless. foreighObjects are used to display divs
|
|
50
|
-
// within SVGs that contain html code to be displayed in the browser. So
|
|
51
|
-
// we assume that the foreignObject is not relevant for exporting as its
|
|
52
|
-
// content is specifically for the browser user.
|
|
53
|
-
var preParseSvg = origSvg.clone();
|
|
54
|
-
preParseSvg.find("foreignObject").remove();
|
|
55
|
-
|
|
56
|
-
// these are svgdraw inserts, this would be mirroring mirroring ...
|
|
57
|
-
preParseSvg.find("svg.__screenshot").remove();
|
|
58
|
-
|
|
59
|
-
var hwAttrs = (
|
|
60
|
-
'width="' + origSvg.attr('width') + '" height="' +
|
|
61
|
-
origSvg.attr('height') + '"'
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
// redefine the svgHeader because we need to include the xml namespaces
|
|
65
|
-
var svgHeader = (
|
|
66
|
-
'<?xml version="1.0" standalone="no"?>\r\n' +
|
|
67
|
-
'<svg ' + hwAttrs + ' pointer-events="all" style="cursor: crosshair; '+
|
|
68
|
-
'touch-action: none;" xmlns="http://www.w3.org/2000/svg" '+
|
|
69
|
-
'class="__screenshot" xmlns:xlink="http://www.w3.org/1999/xlink">\r\n'
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
var svgBody = preParseSvg.html();
|
|
73
|
-
|
|
74
|
-
var parser = new DOMParser();
|
|
75
|
-
|
|
76
|
-
var doc = parser.parseFromString(svgHeader + svgBody + '\r\n</svg>',
|
|
77
|
-
"image/svg+xml");
|
|
78
|
-
|
|
79
|
-
// SVG has very specific requirements for colour specification, baseline
|
|
80
|
-
// all colors to #rrggbb. This converts: 'rgb(rrr, ggg, bbb)' and '#rgb'.
|
|
81
|
-
// Although it could also just be Inkscape, SVG does have a broad range
|
|
82
|
-
// of color possibilities.
|
|
83
|
-
var rgb2hex = (rgb) => {
|
|
84
|
-
if ( !rgb || rgb === null || rgb == "none" ) { return "none" }
|
|
85
|
-
|
|
86
|
-
var rgb3 = rgb.match(/^#(.)(.)(.)$/);
|
|
87
|
-
if ( rgb3 ) {
|
|
88
|
-
return ("#" +rgb3[1]+rgb3[1]+rgb3[2]+rgb3[2]+rgb3[3]+rgb3[3]);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
rgb3 = rgb.match(/^#......$/);
|
|
92
|
-
if ( rgb3 ) { return rgb; }
|
|
93
|
-
|
|
94
|
-
rgb3 = rgb.match(/^rgb\(([0-9]+),\s+([0-9]+),\s+([0-9]+)/);
|
|
95
|
-
if ( rgb3 === null ) {
|
|
96
|
-
var rgb4 = rgb.match(/^rgba\(([0-9]+),\s+([0-9]+),\s+([0-9]+),\s+([0-9]+)/);
|
|
97
|
-
if ( rgb4 ) {
|
|
98
|
-
return {
|
|
99
|
-
clr: ("#" +
|
|
100
|
-
("0" + parseInt(rgb4[1],10).toString(16)).slice(-2) +
|
|
101
|
-
("0" + parseInt(rgb4[2],10).toString(16)).slice(-2) +
|
|
102
|
-
("0" + parseInt(rgb4[3],10).toString(16)).slice(-2) ),
|
|
103
|
-
opa: rgb4[4]
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
console.log( "Screenshot node: returned unknown color: " + rgb );
|
|
107
|
-
return rgb;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return "#" +
|
|
112
|
-
("0" + parseInt(rgb3[1],10).toString(16)).slice(-2) +
|
|
113
|
-
("0" + parseInt(rgb3[2],10).toString(16)).slice(-2) +
|
|
114
|
-
("0" + parseInt(rgb3[3],10).toString(16)).slice(-2);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Set everything that might have been set via CSS directly on the
|
|
118
|
-
// element. All styling values must be defined as attributes on the
|
|
119
|
-
// SVG element.
|
|
120
|
-
var convertCssToAttr = function( collection, origElems ) {
|
|
121
|
-
for ( var idx = 0; idx < collection.length; idx++ ) {
|
|
122
|
-
var elem = collection.item(idx);
|
|
123
|
-
var origElem = origElems[idx];
|
|
124
|
-
|
|
125
|
-
[
|
|
126
|
-
"stroke-width","fill-opacity","stroke-opacity","opacity",
|
|
127
|
-
"stroke-dasharray"
|
|
128
|
-
].forEach(function(attrname) {
|
|
129
|
-
elem.setAttribute(attrname,
|
|
130
|
-
$(origElem).attr(attrname) ||
|
|
131
|
-
$(origElem).css(attrname));
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
[
|
|
135
|
-
"fill", "stroke"
|
|
136
|
-
].forEach( function(attrname) {
|
|
137
|
-
var val = rgb2hex($(origElem).attr(attrname) ||
|
|
138
|
-
$(origElem).css(attrname) );
|
|
139
|
-
|
|
140
|
-
// Browsers/CSS has the color 'transparent', SVG is oblivious to
|
|
141
|
-
// such frills and whistles, instead opacity to the rescue.
|
|
142
|
-
if ( typeof val == "object" ) {
|
|
143
|
-
elem.setAttribute(attrname + "-opacity", val.opa);
|
|
144
|
-
elem.setAttribute(attrname, val.clr);
|
|
145
|
-
} else {
|
|
146
|
-
elem.setAttribute(attrname,val);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
if ( $(origElem).hasClass('hide') ) {
|
|
151
|
-
if ( elem.tagName == "g" ) {
|
|
152
|
-
// according to the SVG standard, visibility cannot be applied
|
|
153
|
-
// (or better said: has no effect) on 'g' (group) elements.
|
|
154
|
-
// Inkscape is rather pedantic about this and will show the
|
|
155
|
-
// group, so hack-it by using opacity. Browsers (firefox) doesn't
|
|
156
|
-
// seem to care and will apply visibility to 'g' elements.
|
|
157
|
-
elem.setAttribute("opacity", "0");
|
|
158
|
-
}
|
|
159
|
-
elem.setAttribute("visibility", "hidden");
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// include font details on the text elements.
|
|
165
|
-
var convertFontsToAttr = function( collection, origElems ) {
|
|
166
|
-
for ( var idx = 0; idx < collection.length; idx++ ) {
|
|
167
|
-
var elem = collection.item(idx);
|
|
168
|
-
var origElem = origElems[idx];
|
|
169
|
-
|
|
170
|
-
["font-family", "font-size", "font-size-adjust", "font-stretch",
|
|
171
|
-
"font-style", "font-variant", "font-weight", "text-anchor",
|
|
172
|
-
"dominant-baseline"
|
|
173
|
-
].forEach( function(attrname) {
|
|
174
|
-
elem.setAttribute(attrname,
|
|
175
|
-
$(origElem).attr(attrname) ||
|
|
176
|
-
$(origElem).css(attrname) );
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
var removeAllClassAndIdAttrs = (doc) => {
|
|
182
|
-
["g", "rect", "line", "path", "circle", "image", "text"].forEach((t)=>{
|
|
183
|
-
$(doc.getElementsByTagName(t)).each( (idx, elem ) => {
|
|
184
|
-
elem.setAttribute("class","");
|
|
185
|
-
elem.setAttribute("id","");
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
return doc;
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
// probably missed some elements ...
|
|
193
|
-
var tagnames = [ "g", "rect", "line", "path", "circle", "image" ];
|
|
194
|
-
tagnames.forEach( function(tagname) {
|
|
195
|
-
convertCssToAttr(doc.getElementsByTagName(tagname),
|
|
196
|
-
origSvg.find(tagname));
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
[ "text" ].forEach( function(tagname) {
|
|
200
|
-
convertCssToAttr(doc.getElementsByTagName(tagname),
|
|
201
|
-
origSvg.find(tagname));
|
|
202
|
-
|
|
203
|
-
convertFontsToAttr(doc.getElementsByTagName(tagname),
|
|
204
|
-
origSvg.find(tagname));
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// inline image data. Image types supported: Jpeg, Png and Svg.
|
|
208
|
-
var imageColl = doc.getElementsByTagName("image");
|
|
209
|
-
|
|
210
|
-
var imageCache = {};
|
|
211
|
-
|
|
212
|
-
var getDataAndCallbackWhenDone = (elem, cntr, cb) => {
|
|
213
|
-
var hrefSrc = elem.getAttribute("xlink:href");
|
|
214
|
-
|
|
215
|
-
var postfix = hrefSrc.substr(-4,4).toLowerCase();
|
|
216
|
-
var fileType = {
|
|
217
|
-
".jpg": "jpeg",
|
|
218
|
-
"jpeg": "jpeg",
|
|
219
|
-
".png": "png",
|
|
220
|
-
".svg": "svg+xml",
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
if ( imageCache[hrefSrc] ) {
|
|
224
|
-
elem.setAttribute(
|
|
225
|
-
"xlink:href",
|
|
226
|
-
"data:image/" + fileType[postfix] + ";base64," + imageCache[hrefSrc]
|
|
227
|
-
);
|
|
228
|
-
return cb(cntr-1);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
switch(postfix){
|
|
232
|
-
case ".jpg":
|
|
233
|
-
case "jpeg":
|
|
234
|
-
case ".png":
|
|
235
|
-
var oReq = new XMLHttpRequest();
|
|
236
|
-
|
|
237
|
-
oReq.open("GET", hrefSrc, true);
|
|
238
|
-
oReq.responseType = "arraybuffer";
|
|
239
|
-
|
|
240
|
-
var arrayBufferToBase64 = ( buffer ) => {
|
|
241
|
-
var binary = '';
|
|
242
|
-
var bytes = new Uint8Array( buffer );
|
|
243
|
-
var len = bytes.byteLength;
|
|
244
|
-
for (var i = 0; i < len; i++) {
|
|
245
|
-
binary += String.fromCharCode( bytes[ i ] );
|
|
246
|
-
}
|
|
247
|
-
return window.btoa( binary );
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
oReq.onload = function (oEvent) {
|
|
251
|
-
var arrayBuffer = oReq.response; // Note: not oReq.responseText
|
|
252
|
-
if (arrayBuffer) {
|
|
253
|
-
var b64Data = arrayBufferToBase64(arrayBuffer);
|
|
254
|
-
imageCache[hrefSrc] = b64Data;
|
|
255
|
-
elem.setAttribute(
|
|
256
|
-
"xlink:href", "data:image/"+fileType[postfix]+";base64,"+b64Data
|
|
257
|
-
);
|
|
258
|
-
cb(cntr-1)
|
|
259
|
-
} else {
|
|
260
|
-
cb(cntr-1)
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
oReq.send(null);
|
|
265
|
-
break;
|
|
266
|
-
|
|
267
|
-
case ".svg":
|
|
268
|
-
$.get( hrefSrc, function(data) {
|
|
269
|
-
const serializer = new XMLSerializer();
|
|
270
|
-
var b64Data = btoa(serializer.serializeToString(data));
|
|
271
|
-
imageCache[hrefSrc] = b64Data;
|
|
272
|
-
elem.setAttribute( "xlink:href",
|
|
273
|
-
"data:image/svg+xml;base64," + b64Data);
|
|
274
|
-
cb(cntr-1)
|
|
275
|
-
});
|
|
276
|
-
break;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
var cb = (cntr) => {
|
|
281
|
-
if ( cntr < 0 ) {
|
|
282
|
-
delete imageCache;
|
|
283
|
-
callbackWithSvgCode((new XMLSerializer()).serializeToString(
|
|
284
|
-
removeAllClassAndIdAttrs(doc)
|
|
285
|
-
));
|
|
286
|
-
} else {
|
|
287
|
-
getDataAndCallbackWhenDone( imageColl.item(cntr), cntr, cb );
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
if ( imageColl.length > 0 ) {
|
|
292
|
-
getDataAndCallbackWhenDone( imageColl.item(imageColl.length-1),
|
|
293
|
-
imageColl.length-1,
|
|
294
|
-
cb );
|
|
295
|
-
} else {
|
|
296
|
-
delete imageCache;
|
|
297
|
-
callbackWithSvgCode( (new XMLSerializer()).serializeToString(
|
|
298
|
-
removeAllClassAndIdAttrs(doc)
|
|
299
|
-
));
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
function generatorFunctionForVersion(red) {
|
|
304
|
-
var version = red.settings.version.split(".")
|
|
305
|
-
var major = version[0]; // 3.0.x or 3.1.x --> making assumptions that
|
|
306
|
-
var minor = version[1]; // between minor version nothing changed
|
|
307
|
-
|
|
308
|
-
var dummy = (red) => {
|
|
309
|
-
return (cb) => {
|
|
310
|
-
var msg = "Node-RED version (" + red.settings.version + ") not supported";
|
|
311
|
-
red.notify(msg,{ type: "error" });
|
|
312
|
-
|
|
313
|
-
if ( cb ) {
|
|
314
|
-
var svgData = '<?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">'+msg+'</text></svg>';
|
|
315
|
-
cb(svgData);
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
if ( major == "3" ) {
|
|
321
|
-
if ( minor == "0" ) { return nr_intro_generate_svg_3_0(red); }
|
|
322
|
-
if ( minor == "1" ) { return nr_intro_generate_svg_3_1(red); }
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return dummy(red);
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
/*
|
|
329
|
-
When the server side of this node is triggered, it posts a message on
|
|
330
|
-
the communication channel. The frontend node captures that message,
|
|
331
|
-
generates an SVG and posts that to the POST endpoint (that is assumed)
|
|
332
|
-
to be running. If not, there will be a console error.
|
|
333
|
-
*/
|
|
334
|
-
RED.comms.subscribe('introspect:screenshot-trigger-tripped', (event,data) => {
|
|
335
|
-
if ( data.msg == "timer-tripped" ) {
|
|
336
|
-
|
|
337
|
-
if ( data.notification != "off" ) {
|
|
338
|
-
RED.notify("Screenshot triggered", { type: "warning" });
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
var notification = data.notification;
|
|
342
|
-
|
|
343
|
-
generatorFunctionForVersion(RED)( (svgdata) => {
|
|
344
|
-
$.ajax({
|
|
345
|
-
type: "POST",
|
|
346
|
-
url: data.endpoint,
|
|
347
|
-
dataType: "application/json;charset=utf-8",
|
|
348
|
-
data: {
|
|
349
|
-
...data,
|
|
350
|
-
d: svgdata
|
|
351
|
-
},
|
|
352
|
-
complete: (obj) => {
|
|
353
|
-
switch( obj.status ) {
|
|
354
|
-
case 413:
|
|
355
|
-
// apiMaxLength in the settings.js is set to 5mb by default,
|
|
356
|
-
// if svg larger than that, need to increase the limit.
|
|
357
|
-
// Provide a hint to that setting in the error message.
|
|
358
|
-
RED.notify(
|
|
359
|
-
"Screenshot too large, increase apiMaxLength in settings.js.", {
|
|
360
|
-
type: "error"
|
|
361
|
-
}
|
|
362
|
-
);
|
|
363
|
-
break;
|
|
364
|
-
case 404:
|
|
365
|
-
// Http-in POST node is missing
|
|
366
|
-
RED.notify(
|
|
367
|
-
"Missing http-in node: method: POST, path: " + data.endpoint, {
|
|
368
|
-
type: "error"
|
|
369
|
-
}
|
|
370
|
-
);
|
|
371
|
-
break;
|
|
372
|
-
case 200:
|
|
373
|
-
if ( notification != "off" ) {
|
|
374
|
-
RED.notify("Screenshot successfully posted", {
|
|
375
|
-
type: "success"
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
break;
|
|
379
|
-
default:
|
|
380
|
-
RED.notify(
|
|
381
|
-
"Screenshot failed: " + obj.statusText + " " + obj.status, {
|
|
382
|
-
type: "error"
|
|
383
|
-
}
|
|
384
|
-
);
|
|
385
|
-
};
|
|
386
|
-
},
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
RED.nodes.registerType('Screenshot',{
|
|
393
|
-
color: '#e5e4ef',
|
|
394
|
-
icon: "font-awesome/fa-camera",
|
|
395
|
-
category: 'introspection',
|
|
396
|
-
paletteLabel: "Screenshot",
|
|
397
|
-
defaults: {
|
|
398
|
-
name: {
|
|
399
|
-
value: "",
|
|
400
|
-
},
|
|
401
|
-
screenshot: {
|
|
402
|
-
value: ""
|
|
403
|
-
},
|
|
404
|
-
endpoint: {
|
|
405
|
-
value: "/screenshot"
|
|
406
|
-
},
|
|
407
|
-
},
|
|
408
|
-
inputs:1,
|
|
409
|
-
outputs:0,
|
|
410
|
-
|
|
411
|
-
label: function() {
|
|
412
|
-
return (this.name || this._def.paletteLabel);
|
|
413
|
-
},
|
|
414
|
-
|
|
415
|
-
labelStyle: function() {
|
|
416
|
-
return this.name?"node_label_italic":"";
|
|
417
|
-
},
|
|
418
|
-
|
|
419
|
-
oneditprepare: function() {
|
|
420
|
-
const that = this;
|
|
421
|
-
const stateId = RED.editor.generateViewStateId("node", this, "");
|
|
422
|
-
|
|
423
|
-
if (!this.field) {
|
|
424
|
-
this.field = 'payload';
|
|
425
|
-
$("#node-input-field").val("payload");
|
|
426
|
-
}
|
|
427
|
-
if (!this.fieldType) {
|
|
428
|
-
this.fieldType = 'msg';
|
|
429
|
-
}
|
|
430
|
-
if (!this.syntax) {
|
|
431
|
-
this.syntax = 'mustache';
|
|
432
|
-
$("#node-input-syntax").val(this.syntax);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
$("#node-input-field").typedInput({
|
|
436
|
-
default: 'msg',
|
|
437
|
-
types: ['msg','flow','global'],
|
|
438
|
-
typeField: $("#node-input-fieldType")
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
this.editor = RED.editor.createEditor({
|
|
442
|
-
id: 'node-input-screenshot-editor',
|
|
443
|
-
mode: 'ace/mode/html',
|
|
444
|
-
stateId: stateId,
|
|
445
|
-
value: $("#node-input-screenshot").val()
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
this.editor.setValue( "Please wait, screenshot being prepared ..." );
|
|
449
|
-
|
|
450
|
-
generatorFunctionForVersion(RED)( (svgdata) => {
|
|
451
|
-
that.editor.setValue( svgdata );
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
// handle the download button under the editor window.
|
|
455
|
-
$('#node-screenshot-download-svg').on("click", function (e) {
|
|
456
|
-
e.preventDefault();
|
|
457
|
-
var svgBlob = new Blob([that.editor.getValue()], {type:"image/svg+xml;charset=utf-8"});
|
|
458
|
-
var svgUrl = URL.createObjectURL(svgBlob);
|
|
459
|
-
var downloadLink = document.createElement("a");
|
|
460
|
-
downloadLink.href = svgUrl;
|
|
461
|
-
downloadLink.download = "screenshot.svg";
|
|
462
|
-
document.body.appendChild(downloadLink);
|
|
463
|
-
downloadLink.click();
|
|
464
|
-
document.body.removeChild(downloadLink);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
$('#node-screenshot-copy-to-clipboard-svg').on("click", function (e) {
|
|
468
|
-
e.preventDefault();
|
|
469
|
-
if ( RED.clipboard.copyText(that.editor.getValue()) ) {
|
|
470
|
-
RED.notify("SVG copied to clipboard", { type: "success" });
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
$("#node-input-format").on("change", function() {
|
|
475
|
-
var mod = "ace/mode/"+$("#node-input-format").val();
|
|
476
|
-
that.editor.getSession().setMode({
|
|
477
|
-
path: mod,
|
|
478
|
-
v: Date.now()
|
|
479
|
-
});
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
RED.popover.tooltip($("#node-screenshot-expand-editor"), RED._("node-red:common.label.expand"));
|
|
483
|
-
$("#node-screenshot-expand-editor").on("click", function (e) {
|
|
484
|
-
e.preventDefault();
|
|
485
|
-
const value = that.editor.getValue();
|
|
486
|
-
that.editor.saveView();
|
|
487
|
-
RED.editor.editText({
|
|
488
|
-
mode: $("#node-input-format").val(),
|
|
489
|
-
value: value,
|
|
490
|
-
stateId: stateId,
|
|
491
|
-
width: "Infinity",
|
|
492
|
-
focus: true,
|
|
493
|
-
complete: function (v, cursor) {
|
|
494
|
-
that.editor.setValue(v, -1);
|
|
495
|
-
setTimeout(function () {
|
|
496
|
-
that.editor.restoreView();
|
|
497
|
-
that.editor.focus();
|
|
498
|
-
}, 250);
|
|
499
|
-
}
|
|
500
|
-
})
|
|
501
|
-
})
|
|
502
|
-
},
|
|
503
|
-
|
|
504
|
-
oneditsave: function() {
|
|
505
|
-
this.editor.destroy();
|
|
506
|
-
delete this.editor;
|
|
507
|
-
},
|
|
508
|
-
|
|
509
|
-
oneditcancel: function() {
|
|
510
|
-
this.editor.destroy();
|
|
511
|
-
delete this.editor;
|
|
512
|
-
},
|
|
513
|
-
|
|
514
|
-
oneditresize: function(size) {
|
|
515
|
-
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
|
516
|
-
var height = $("#dialog-form").height();
|
|
517
|
-
for (var i=0; i<rows.length; i++) {
|
|
518
|
-
height -= $(rows[i]).outerHeight(true);
|
|
519
|
-
}
|
|
520
|
-
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
|
521
|
-
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
|
522
|
-
$(".node-text-editor").css("height",height+"px");
|
|
523
|
-
this.editor.resize();
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
</script>
|
|
527
|
-
|
|
528
|
-
<script type="text/html" data-template-name="Screenshot">
|
|
529
|
-
<div class="form-row">
|
|
530
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name">Name</span></label>
|
|
531
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
|
532
|
-
</div>
|
|
533
|
-
|
|
534
|
-
<div class="form-row">
|
|
535
|
-
<label for="node-input-endpoint">
|
|
536
|
-
<i class="fa fa-send-o"></i>
|
|
537
|
-
<span>Post Endpoint</span>
|
|
538
|
-
</label>
|
|
539
|
-
<input type="text" id="node-input-endpoint" placeholder="/screenshot">
|
|
540
|
-
</div>
|
|
541
|
-
|
|
542
|
-
<div class="form-row" style="position: relative; margin-bottom: 0px;">
|
|
543
|
-
<label for="node-input-screenshot"><i class="fa fa-file-code-o"></i> <span data-i18n="screenshot.label.screenshot">Screenshot</span></label>
|
|
544
|
-
<input type="hidden" id="node-input-screenshot" autofocus="autofocus">
|
|
545
|
-
<div style="position: absolute; right:0;display:inline-block; text-align: right; font-size: 0.8em;">
|
|
546
|
-
<span data-i18n="screenshot.label.format">Syntax</span>:
|
|
547
|
-
<select id="node-input-format" style="width:110px; font-size: 10px !important; height: 24px; padding:0;">
|
|
548
|
-
<option value="handlebars">mustache</option>
|
|
549
|
-
<option value="html">HTML</option>
|
|
550
|
-
<option value="json">JSON</option>
|
|
551
|
-
<option value="javascript">JavaScript</option>
|
|
552
|
-
<option value="css">CSS</option>
|
|
553
|
-
<option value="markdown">Markdown</option>
|
|
554
|
-
<option value="php">PHP</option>
|
|
555
|
-
<option value="python">Python</option>
|
|
556
|
-
<option value="sql">SQL</option>
|
|
557
|
-
<option value="yaml">YAML</option>
|
|
558
|
-
<option value="text" data-i18n="screenshot.label.none"></option>
|
|
559
|
-
</select>
|
|
560
|
-
<button type="button" id="node-screenshot-expand-editor" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button>
|
|
561
|
-
</div>
|
|
562
|
-
</div>
|
|
563
|
-
|
|
564
|
-
<div class="form-row node-text-editor-row">
|
|
565
|
-
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-screenshot-editor" ></div>
|
|
566
|
-
</div>
|
|
567
|
-
|
|
568
|
-
<div class="form-row">
|
|
569
|
-
<button type="button" id="node-screenshot-download-svg" class="red-ui-button red-ui-button-large"><i class="fa fa-download"></i>Download</button>
|
|
570
|
-
<button type="button" id="node-screenshot-copy-to-clipboard-svg" class="red-ui-button red-ui-button-large"><i class="fa fa-clipboard"></i>Copy to Clipboard</button>
|
|
571
|
-
</div>
|
|
572
|
-
</script>
|
|
573
|
-
|
|
574
|
-
<script type="text/html" data-help-name="Screenshot">
|
|
575
|
-
<p>Create a SVG screenshot of the current tab.</p>
|
|
576
|
-
</script>
|
package/nodes/15-screenshot.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
module.exports = function(RED) {
|
|
2
|
-
function ScreenshotFunctionality(config) {
|
|
3
|
-
RED.nodes.createNode(this,config);
|
|
4
|
-
|
|
5
|
-
var node = this;
|
|
6
|
-
var cfg = config;
|
|
7
|
-
|
|
8
|
-
node.on('close', function() {
|
|
9
|
-
node.status({});
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
node.on("input", function(msg, send, done) {
|
|
13
|
-
RED.comms.publish("introspect:screenshot-trigger-tripped",
|
|
14
|
-
RED.util.encodeObject({
|
|
15
|
-
...msg,
|
|
16
|
-
msg: "timer-tripped",
|
|
17
|
-
endpoint: cfg.endpoint,
|
|
18
|
-
})
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
node.status({ fill: "green", shape: "dot", text: "Taking screenshot" });
|
|
22
|
-
setTimeout( () => { node.status({}) }, 1432 );
|
|
23
|
-
|
|
24
|
-
send(msg);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
RED.nodes.registerType("Screenshot", ScreenshotFunctionality);
|
|
29
|
-
}
|