mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
1540 Commits
debugger
...
delete-unu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93d5db9752 | ||
|
|
d887ab126b | ||
|
|
fba339f666 | ||
|
|
09d41a9708 | ||
|
|
4630a162af | ||
|
|
80a15089b4 | ||
|
|
8edf399631 | ||
|
|
d5ffd1432f | ||
|
|
e73bf03615 | ||
|
|
665fe0e01e | ||
|
|
a866aa9c18 | ||
|
|
d9089b798c | ||
|
|
d34ebd4d1b | ||
|
|
2aae76c9bc | ||
|
|
5fc3ca0e23 | ||
|
|
5bb27109bf | ||
|
|
7406ab6017 | ||
|
|
08fccc4e77 | ||
|
|
c1d50e82e1 | ||
|
|
9777af7cb5 | ||
|
|
fd86035865 | ||
|
|
a8ec032553 | ||
|
|
66ee27c5fa | ||
|
|
17a737ca88 | ||
|
|
f30ff7a2fd | ||
|
|
75e7c0e50d | ||
|
|
62b2adab78 | ||
|
|
fc0cf1ff51 | ||
|
|
0f4d46671f | ||
|
|
048f9c0294 | ||
|
|
0529eed0c9 | ||
|
|
ca77842b5b | ||
|
|
8c169dc82b | ||
|
|
195342f7db | ||
|
|
cfaaef7860 | ||
|
|
e939d5e96e | ||
|
|
6fa8b7f5f1 | ||
|
|
a2d03c14ae | ||
|
|
c667a0e74c | ||
|
|
8123828113 | ||
|
|
72b8dbb45b | ||
|
|
9f4628cf0a | ||
|
|
ec4d24af91 | ||
|
|
7703875740 | ||
|
|
6442bb8a13 | ||
|
|
51373f59e2 | ||
|
|
6cc56879d3 | ||
|
|
f29d7c9252 | ||
|
|
2f7f53ed96 | ||
|
|
da89460830 | ||
|
|
9e006d42bb | ||
|
|
4c02bab4ee | ||
|
|
5800ed41f1 | ||
|
|
18b5b4901f | ||
|
|
368418cf56 | ||
|
|
94031a52a5 | ||
|
|
d67f91e7ed | ||
|
|
3e6cadf3d8 | ||
|
|
f37697c4fb | ||
|
|
0c5a76b391 | ||
|
|
69448c7329 | ||
|
|
8e9815fb91 | ||
|
|
bf1afcfe8a | ||
|
|
2980818f0d | ||
|
|
9da58dbaf0 | ||
|
|
4cdd7978cf | ||
|
|
40d81358f4 | ||
|
|
c7b62aed91 | ||
|
|
55d71659f8 | ||
|
|
c0e7d6d826 | ||
|
|
f809377de8 | ||
|
|
9767bd9697 | ||
|
|
3a55528552 | ||
|
|
56197ffe3a | ||
|
|
0f0d0c046c | ||
|
|
8d5b546763 | ||
|
|
19c9707d62 | ||
|
|
ecc4973645 | ||
|
|
79e004a040 | ||
|
|
3169f93cc2 | ||
|
|
c1a1a73599 | ||
|
|
48308db45b | ||
|
|
3f37e96f78 | ||
|
|
db1b0ccb79 | ||
|
|
df161ce672 | ||
|
|
4e21a5e557 | ||
|
|
72fe30892e | ||
|
|
19fa69811b | ||
|
|
0ddb4c625d | ||
|
|
d373105b32 | ||
|
|
36dc1d2f97 | ||
|
|
11fa2cb35d | ||
|
|
546f07156f | ||
|
|
7e7117632d | ||
|
|
954226da0d | ||
|
|
38a1291c5b | ||
|
|
998bf92ad4 | ||
|
|
974ba40f28 | ||
|
|
e57d8ba0ef | ||
|
|
6b79c6135f | ||
|
|
28b311b7ed | ||
|
|
dcda513901 | ||
|
|
72c400794c | ||
|
|
a747d8c2d5 | ||
|
|
a3aec6b939 | ||
|
|
042409f870 | ||
|
|
5b8f4f4069 | ||
|
|
d132d63c1d | ||
|
|
4374506981 | ||
|
|
ef8b936069 | ||
|
|
36e3bfffb4 | ||
|
|
91a38bdb60 | ||
|
|
f169a68319 | ||
|
|
ee886f98dd | ||
|
|
a3826cc6a7 | ||
|
|
ba33b832ba | ||
|
|
f6c017176b | ||
|
|
7a01b115bb | ||
|
|
1dc021e871 | ||
|
|
c9f916ebab | ||
|
|
ff627fd128 | ||
|
|
bba57f8d2b | ||
|
|
695873d35a | ||
|
|
15da19dcea | ||
|
|
4312a01707 | ||
|
|
ecd8f97d8b | ||
|
|
d5bdc1600b | ||
|
|
dfa077fd5f | ||
|
|
06abe63fb1 | ||
|
|
5155770213 | ||
|
|
9d507b09ca | ||
|
|
9c4a712dc7 | ||
|
|
f1d5bbb036 | ||
|
|
69ed0aebc3 | ||
|
|
549e56e220 | ||
|
|
450f4d9a5a | ||
|
|
6533a9793c | ||
|
|
2000cadb17 | ||
|
|
083c321efa | ||
|
|
f64c4a981f | ||
|
|
3ac8ce03bf | ||
|
|
66fca8710e | ||
|
|
1e245ece46 | ||
|
|
81efce03ba | ||
|
|
4e549dd426 | ||
|
|
52f74ff7e0 | ||
|
|
3c71b815f5 | ||
|
|
9efd48fe51 | ||
|
|
4609ee75b6 | ||
|
|
963ea4177e | ||
|
|
17e6940a42 | ||
|
|
315a9ceba3 | ||
|
|
a2bdeedb09 | ||
|
|
da5700d2d7 | ||
|
|
90e7f30247 | ||
|
|
3ccf6ba892 | ||
|
|
e50cd5b745 | ||
|
|
db77be5d72 | ||
|
|
c36870c23e | ||
|
|
e9be007040 | ||
|
|
9e400d9aa6 | ||
|
|
490c8dae75 | ||
|
|
3bcffe375d | ||
|
|
9f81a591e1 | ||
|
|
3db5306c70 | ||
|
|
45029dd084 | ||
|
|
b01cd30339 | ||
|
|
09329e1104 | ||
|
|
ab0fc2ecfa | ||
|
|
bf5d36d6bd | ||
|
|
a29527ec96 | ||
|
|
45e7ad8049 | ||
|
|
4d54663efd | ||
|
|
29d386cc51 | ||
|
|
ba1a67969b | ||
|
|
390ea5419e | ||
|
|
0fdeec7cc4 | ||
|
|
e34d883e50 | ||
|
|
507871687b | ||
|
|
ed58f62cd1 | ||
|
|
94bc4e7125 | ||
|
|
5832f7930d | ||
|
|
0066a20c22 | ||
|
|
774e4bfced | ||
|
|
054c7a76a4 | ||
|
|
c7f3b77aac | ||
|
|
a6a4620374 | ||
|
|
5148c62d1c | ||
|
|
6fc863a91e | ||
|
|
e066a154a1 | ||
|
|
d432edaed2 | ||
|
|
8f34f4e80b | ||
|
|
39b751acf5 | ||
|
|
bd5e8ba961 | ||
|
|
ed20327c41 | ||
|
|
991c68c394 | ||
|
|
2acc31a4e7 | ||
|
|
b9733e3dfa | ||
|
|
bb106bfce7 | ||
|
|
daf1388a6a | ||
|
|
8226f1fa75 | ||
|
|
e675512fa3 | ||
|
|
65e67b6c3e | ||
|
|
7612481570 | ||
|
|
f6c7cb5804 | ||
|
|
2201c9062f | ||
|
|
ca3da262da | ||
|
|
5847f92bef | ||
|
|
31ee1be81e | ||
|
|
6bccdd015f | ||
|
|
cecea318da | ||
|
|
8663ec6880 | ||
|
|
9b03f128aa | ||
|
|
8a51f97616 | ||
|
|
ee74ed9ce9 | ||
|
|
0f947c756e | ||
|
|
cae7949a48 | ||
|
|
be58b614e1 | ||
|
|
b0a01fa4b2 | ||
|
|
9734228001 | ||
|
|
9df1d44bc4 | ||
|
|
13d887028a | ||
|
|
83a8979309 | ||
|
|
75c29f1cb7 | ||
|
|
d9d15e41c7 | ||
|
|
d3598d5854 | ||
|
|
3a8aaee5d7 | ||
|
|
4fcf57d42c | ||
|
|
adb0891335 | ||
|
|
d21e719cc1 | ||
|
|
5807ab82c1 | ||
|
|
65cb04da63 | ||
|
|
312e3611b1 | ||
|
|
46acc62279 | ||
|
|
529b358c9b | ||
|
|
7fca04404e | ||
|
|
3a1cc6a2be | ||
|
|
5b76c91004 | ||
|
|
cf87837f7d | ||
|
|
5a0a7b907b | ||
|
|
6a2b1669b3 | ||
|
|
ca8264b3f4 | ||
|
|
b44ecd8819 | ||
|
|
987942959e | ||
|
|
91992b48c1 | ||
|
|
c9a335a6f9 | ||
|
|
b7ed159b50 | ||
|
|
c72961a52a | ||
|
|
afe6afca36 | ||
|
|
050acd239c | ||
|
|
24505ee4f5 | ||
|
|
63a249aba3 | ||
|
|
7bd94df2a0 | ||
|
|
761161a8e5 | ||
|
|
513579a7ee | ||
|
|
7165483d83 | ||
|
|
f8bcf219cb | ||
|
|
590506e306 | ||
|
|
9a5439c580 | ||
|
|
6b2f5fbb19 | ||
|
|
051c147b41 | ||
|
|
9111adf15f | ||
|
|
ba18b27371 | ||
|
|
2a287b2ae6 | ||
|
|
fc9040f715 | ||
|
|
0029022ef6 | ||
|
|
94f728d3fd | ||
|
|
d53ced7830 | ||
|
|
053d8c44c2 | ||
|
|
9f5767ea16 | ||
|
|
e8d76b0555 | ||
|
|
c2675600f6 | ||
|
|
6f087b4ec1 | ||
|
|
e94708606d | ||
|
|
c248f1a762 | ||
|
|
28402b0894 | ||
|
|
7dd98e99f9 | ||
|
|
dba195b396 | ||
|
|
88b153bc12 | ||
|
|
d4a47dc974 | ||
|
|
fe3ea6edfd | ||
|
|
6c8fc4846b | ||
|
|
54d9656f09 | ||
|
|
49da324c5d | ||
|
|
9bf87697fd | ||
|
|
f368f5a9c4 | ||
|
|
eea85485e6 | ||
|
|
1a544b3b82 | ||
|
|
8b38fe9fe0 | ||
|
|
1bf4addf63 | ||
|
|
407e16e900 | ||
|
|
6e9fe3248a | ||
|
|
d8cf86fd6f | ||
|
|
f8aa4a9588 | ||
|
|
c249907846 | ||
|
|
57c1524a9a | ||
|
|
d8d82e2ba3 | ||
|
|
807b512ef7 | ||
|
|
b2f06b6777 | ||
|
|
d7adff9a65 | ||
|
|
b0d7e11d48 | ||
|
|
fc9cdb61f2 | ||
|
|
9c00492dc2 | ||
|
|
1a6babd199 | ||
|
|
1b693eed37 | ||
|
|
afb566b6b4 | ||
|
|
f870e9ed3e | ||
|
|
4bcf13cb58 | ||
|
|
946a6d6041 | ||
|
|
372c213c2c | ||
|
|
a5a79d3ab7 | ||
|
|
e6c5cfb703 | ||
|
|
7843eccae8 | ||
|
|
7ca153abd0 | ||
|
|
33b4774c49 | ||
|
|
c243481432 | ||
|
|
80873e4ea9 | ||
|
|
4e4a1f11e6 | ||
|
|
9bbe405cd0 | ||
|
|
c440a4c730 | ||
|
|
a1251371d7 | ||
|
|
7d702e8332 | ||
|
|
43d7c8d48c | ||
|
|
7423583508 | ||
|
|
08b0838f9a | ||
|
|
038d821a7c | ||
|
|
6a218814d3 | ||
|
|
905f89b0f5 | ||
|
|
14882bda78 | ||
|
|
781fa4634b | ||
|
|
cdb173fd6e | ||
|
|
466cb4be89 | ||
|
|
c39e2ffd56 | ||
|
|
17bf09e276 | ||
|
|
bc01f9f8fd | ||
|
|
c0870c5694 | ||
|
|
3b5174a2ea | ||
|
|
af6885f3e8 | ||
|
|
e01996095f | ||
|
|
5d86f7b6ba | ||
|
|
8d6ac6406d | ||
|
|
40ff54f67e | ||
|
|
cce7ac09d0 | ||
|
|
73a18891c5 | ||
|
|
fe22cedc1d | ||
|
|
fa09c7c8b2 | ||
|
|
15e28e3cc0 | ||
|
|
2cb4f6b1fc | ||
|
|
b17a483b85 | ||
|
|
7c3e5443ab | ||
|
|
f95a2851c8 | ||
|
|
2b2eee352f | ||
|
|
11569d8056 | ||
|
|
bdf87452b6 | ||
|
|
0c6bf81c24 | ||
|
|
f2fa26fb07 | ||
|
|
f5e212ff1e | ||
|
|
461e6562ca | ||
|
|
fd67d08402 | ||
|
|
e6411d11b1 | ||
|
|
dd81d947fc | ||
|
|
23b887c30e | ||
|
|
c4eae3f130 | ||
|
|
41a04a2849 | ||
|
|
ed1d34e678 | ||
|
|
f44487338d | ||
|
|
7aced85a31 | ||
|
|
fbe0e2d6eb | ||
|
|
6e34f0697c | ||
|
|
a835f9f0cb | ||
|
|
16715673c3 | ||
|
|
c48c74f173 | ||
|
|
f262348497 | ||
|
|
7185bcd51f | ||
|
|
28d05e2449 | ||
|
|
7fafa21a1b | ||
|
|
84f598e143 | ||
|
|
e30f8628db | ||
|
|
0be9c88106 | ||
|
|
e046fc1ac5 | ||
|
|
3a476ac493 | ||
|
|
e33ec0cf50 | ||
|
|
b4b70a988e | ||
|
|
e66b381070 | ||
|
|
771b598c09 | ||
|
|
cd44f13171 | ||
|
|
aa6b72ac87 | ||
|
|
a467fe5ed7 | ||
|
|
467411c6c3 | ||
|
|
2648b7ca54 | ||
|
|
de35c7024a | ||
|
|
9d219c163d | ||
|
|
f7434b5ec8 | ||
|
|
5ed3360c0b | ||
|
|
6f5974f875 | ||
|
|
56db1da3cf | ||
|
|
fef71f29c4 | ||
|
|
d46b66878a | ||
|
|
6cad80c4ad | ||
|
|
68779caa2e | ||
|
|
2a122ed283 | ||
|
|
17c5fdf0d5 | ||
|
|
0835fdd0d1 | ||
|
|
f6274445a2 | ||
|
|
3b0300b834 | ||
|
|
4fbf1fe780 | ||
|
|
dcf44fed58 | ||
|
|
7136dc1c72 | ||
|
|
0e4cedbc5e | ||
|
|
dc139bcc30 | ||
|
|
b204b183de | ||
|
|
ab788bc1e3 | ||
|
|
95b4c8d515 | ||
|
|
b025644525 | ||
|
|
9e87a60597 | ||
|
|
5a70bea67a | ||
|
|
2a95af3928 | ||
|
|
0a0ca380d3 | ||
|
|
4cfbf7f71c | ||
|
|
de43148341 | ||
|
|
0a2aab7d68 | ||
|
|
745821c420 | ||
|
|
57c4c754d0 | ||
|
|
4b5c437533 | ||
|
|
8d63b6a1ed | ||
|
|
245a8adbf9 | ||
|
|
4f7d98aace | ||
|
|
b0c693cc3a | ||
|
|
b2cca10e8b | ||
|
|
a84b2ab5bb | ||
|
|
4565342b05 | ||
|
|
0ad54cc2d1 | ||
|
|
865853da19 | ||
|
|
392ed706fd | ||
|
|
0ff0f25aaf | ||
|
|
c157960846 | ||
|
|
a5c00b5c81 | ||
|
|
472bbdb59f | ||
|
|
7877093713 | ||
|
|
8cb2e51407 | ||
|
|
d5cee81fb6 | ||
|
|
bca020bc4d | ||
|
|
5069f2844c | ||
|
|
252df81f59 | ||
|
|
7f89a4a26f | ||
|
|
40f4167894 | ||
|
|
0ef16989cd | ||
|
|
3df3d6f516 | ||
|
|
10395ef254 | ||
|
|
83854c28db | ||
|
|
fcbea2629c | ||
|
|
522360dcb7 | ||
|
|
26bc142cc2 | ||
|
|
a4eb8e11c3 | ||
|
|
9fd5d1db56 | ||
|
|
1d05b4c981 | ||
|
|
61f6535be8 | ||
|
|
7dd329b5ee | ||
|
|
b761904424 | ||
|
|
36105412b1 | ||
|
|
184b1b018c | ||
|
|
f3e1b85d82 | ||
|
|
626d012775 | ||
|
|
9ad9c0ec6a | ||
|
|
e13fed9fc6 | ||
|
|
eb6d093e56 | ||
|
|
979713c4db | ||
|
|
af1ea610ea | ||
|
|
d4d9190919 | ||
|
|
4d3d1a02a8 | ||
|
|
30c2aa96d6 | ||
|
|
4edb1f80b0 | ||
|
|
0a82459233 | ||
|
|
db87b0dfa5 | ||
|
|
e41d5c249f | ||
|
|
f82a779817 | ||
|
|
cd42cf7583 | ||
|
|
2d5980ff2a | ||
|
|
df8a8ea204 | ||
|
|
8957d33e49 | ||
|
|
d49c7a3adb | ||
|
|
28fe1e4c8f | ||
|
|
0c7f4e2168 | ||
|
|
4fdd09a262 | ||
|
|
d6878512c4 | ||
|
|
8b1b8250ff | ||
|
|
9dccbf747e | ||
|
|
08727e1938 | ||
|
|
7584820987 | ||
|
|
d572356642 | ||
|
|
3b5a2815a9 | ||
|
|
f3cf01df25 | ||
|
|
63e6e64ad3 | ||
|
|
e8d7b48bff | ||
|
|
12944d1ebd | ||
|
|
fa1ff6e393 | ||
|
|
98546b6e6a | ||
|
|
2fef6fd1fa | ||
|
|
20cf91f1dc | ||
|
|
2efa78d590 | ||
|
|
880af0671a | ||
|
|
62471e4531 | ||
|
|
b15f8535f8 | ||
|
|
7a3a4493da | ||
|
|
11078235c4 | ||
|
|
f3e05cd08a | ||
|
|
0ca3cabbe8 | ||
|
|
44a75c1291 | ||
|
|
4a4513a746 | ||
|
|
60ff8660de | ||
|
|
6fa0d671c0 | ||
|
|
f478d7c9f0 | ||
|
|
53e3e08d70 | ||
|
|
c4d1ccb6f5 | ||
|
|
e3520309fc | ||
|
|
27bf72372e | ||
|
|
ae4b1b17a9 | ||
|
|
94cb03f4b5 | ||
|
|
e691351976 | ||
|
|
3190de873e | ||
|
|
b22956bd99 | ||
|
|
42516206d9 | ||
|
|
fc4edde6e6 | ||
|
|
54cc04fd96 | ||
|
|
80062b6a62 | ||
|
|
99af79fcf3 | ||
|
|
11d87205d7 | ||
|
|
5866d414ce | ||
|
|
9a972b0b8a | ||
|
|
e6aeeea8c1 | ||
|
|
5d064aa1d7 | ||
|
|
34832d5942 | ||
|
|
e3b1179a21 | ||
|
|
f94a36613c | ||
|
|
efc3cc24f4 | ||
|
|
b47f8aaf70 | ||
|
|
94ca4607bc | ||
|
|
2dab1d3e6e | ||
|
|
825b0fb22f | ||
|
|
1cdb039ea2 | ||
|
|
7409cb3abb | ||
|
|
e8e8f70c27 | ||
|
|
e8a637498d | ||
|
|
e1195ac00a | ||
|
|
6cd9ccc37c | ||
|
|
25345302e8 | ||
|
|
eccd5e9801 | ||
|
|
ff355af9f2 | ||
|
|
5967f4b0d4 | ||
|
|
ff18618032 | ||
|
|
20f03c356c | ||
|
|
27fdc9e56e | ||
|
|
52d9578a19 | ||
|
|
f4c2938b41 | ||
|
|
9f703de5ec | ||
|
|
a327fd85e2 | ||
|
|
9d22a86ec8 | ||
|
|
29e0b194dd | ||
|
|
ae9cf13fc2 | ||
|
|
64ae67586a | ||
|
|
838c7a5e89 | ||
|
|
89bfc90f40 | ||
|
|
acad9f57f9 | ||
|
|
0d08dc410e | ||
|
|
ebb3fb96cd | ||
|
|
f31f23ff07 | ||
|
|
d2aa3d1868 | ||
|
|
c9e2fce94d | ||
|
|
8b0e76dd55 | ||
|
|
884618adfe | ||
|
|
6e2e36e7a0 | ||
|
|
9994df9601 | ||
|
|
98f7271ac8 | ||
|
|
087cd121b8 | ||
|
|
2d52527fb4 | ||
|
|
fe289e62b5 | ||
|
|
2845475e3f | ||
|
|
b307492487 | ||
|
|
d48284f7ea | ||
|
|
7e416797e9 | ||
|
|
5d54ca7477 | ||
|
|
b979b4e61a | ||
|
|
2527f7984a | ||
|
|
d9350b2362 | ||
|
|
bd0b903f1a | ||
|
|
f243c0df19 | ||
|
|
7482978953 | ||
|
|
77966689d4 | ||
|
|
cf43939d65 | ||
|
|
391ac4b351 | ||
|
|
e1e48aadd9 | ||
|
|
0681f206c4 | ||
|
|
d257c6f3d3 | ||
|
|
fa45c82cdc | ||
|
|
e805b58da6 | ||
|
|
943976d207 | ||
|
|
3a2e5a6ccd | ||
|
|
35ef036246 | ||
|
|
e09c3bbdd3 | ||
|
|
3b12076d4b | ||
|
|
cfcf78ae28 | ||
|
|
341ff9bf5c | ||
|
|
10d8ca30b0 | ||
|
|
4ebb5d099e | ||
|
|
1e82b66bf0 | ||
|
|
06a5e4273b | ||
|
|
e123e7b0b0 | ||
|
|
aeadc40c65 | ||
|
|
7ef418ec52 | ||
|
|
2ed52820b6 | ||
|
|
e8fd7484b6 | ||
|
|
ce5242cfe8 | ||
|
|
af947879d8 | ||
|
|
3ed112cde6 | ||
|
|
99c6a9eccd | ||
|
|
2029f6ea0a | ||
|
|
e984e1f30f | ||
|
|
f21260370f | ||
|
|
fdae75c99b | ||
|
|
a0489f2a0d | ||
|
|
0123eacbdb | ||
|
|
53401b6aa7 | ||
|
|
9a5139f452 | ||
|
|
2ee0c8c228 | ||
|
|
c53562cc9c | ||
|
|
ec5d7c2e5c | ||
|
|
d6fc258485 | ||
|
|
f953612695 | ||
|
|
2ab93acca8 | ||
|
|
326c6c496e | ||
|
|
9f7f50664c | ||
|
|
f6f1436123 | ||
|
|
c3c519419d | ||
|
|
e569a80b72 | ||
|
|
284f437c1a | ||
|
|
1fd44a9958 | ||
|
|
cad34742f6 | ||
|
|
323359b3c8 | ||
|
|
35db8b45f0 | ||
|
|
50ae815ceb | ||
|
|
1a4389c90d | ||
|
|
fdaa5ce1da | ||
|
|
09d9936aed | ||
|
|
b3f6109b1c | ||
|
|
5fb3ffc240 | ||
|
|
360db252bb | ||
|
|
0b6e290271 | ||
|
|
7f0174e6db | ||
|
|
a25dad6c2e | ||
|
|
6191a49ed3 | ||
|
|
6252b075bc | ||
|
|
7face138fd | ||
|
|
382b83b093 | ||
|
|
691687d1bc | ||
|
|
5814b80a72 | ||
|
|
e147fbb1fa | ||
|
|
b9e256adfa | ||
|
|
3b7bf04e22 | ||
|
|
43408a724c | ||
|
|
5fbd5bf9e2 | ||
|
|
5e87828b29 | ||
|
|
9066cedc29 | ||
|
|
aa1cf0b228 | ||
|
|
06a6a4408f | ||
|
|
d5619d2b9d | ||
|
|
2f6ac42efe | ||
|
|
0bba3dd83d | ||
|
|
abe60b62e6 | ||
|
|
555b7df986 | ||
|
|
b3786700e6 | ||
|
|
ce9643d21b | ||
|
|
4a5cb7f2f5 | ||
|
|
42a7e902e6 | ||
|
|
aebe080e85 | ||
|
|
c316284924 | ||
|
|
8d98b228ab | ||
|
|
5b4c42ff05 | ||
|
|
a596a4551a | ||
|
|
0968f96982 | ||
|
|
5931e13b9c | ||
|
|
415c768ae4 | ||
|
|
b4c8bf21d5 | ||
|
|
5fe5db603d | ||
|
|
9f7dd7f5d4 | ||
|
|
e6d32aab7b | ||
|
|
08bd6d963c | ||
|
|
ff05fb14a6 | ||
|
|
22d942b705 | ||
|
|
0526372f28 | ||
|
|
f99051906a | ||
|
|
d1f7fd8bfd | ||
|
|
fc1436a96d | ||
|
|
d21568497b | ||
|
|
df4beef060 | ||
|
|
a52f195d41 | ||
|
|
419019a656 | ||
|
|
42b5635485 | ||
|
|
a8fc5b01f3 | ||
|
|
ead841d844 | ||
|
|
67d7930aef | ||
|
|
6f69995f4e | ||
|
|
05252fa239 | ||
|
|
1377439bb0 | ||
|
|
407123a280 | ||
|
|
750dd590c8 | ||
|
|
44112a9d18 | ||
|
|
b220bf0d99 | ||
|
|
d0d93d7070 | ||
|
|
4117961236 | ||
|
|
68a3d71ee6 | ||
|
|
bf5d741f0d | ||
|
|
55a33bc408 | ||
|
|
3ec35ed119 | ||
|
|
3d8d6953ec | ||
|
|
528db67c34 | ||
|
|
b847e962aa | ||
|
|
bbb9a3c63b | ||
|
|
322cebc48c | ||
|
|
1cceb3d880 | ||
|
|
effc64db9a | ||
|
|
7e5bd5f2c1 | ||
|
|
e32cc4d1af | ||
|
|
09a3cd850e | ||
|
|
b0c876019a | ||
|
|
6725f870d2 | ||
|
|
0e5adc1f0a | ||
|
|
57ebb93dc0 | ||
|
|
05dc0bfa1d | ||
|
|
2d0264116c | ||
|
|
3938550ea8 | ||
|
|
9f0c567794 | ||
|
|
8672fcd2bb | ||
|
|
3f2a92e801 | ||
|
|
771e43583a | ||
|
|
9353d5c1c4 | ||
|
|
5e462f0f02 | ||
|
|
a25f6fec9f | ||
|
|
519edce0ed | ||
|
|
0bc7702d95 | ||
|
|
18be0d6d26 | ||
|
|
1d4a435f20 | ||
|
|
34e46fc6d3 | ||
|
|
50956c51f7 | ||
|
|
dd7bb28b6a | ||
|
|
8516f41ba8 | ||
|
|
15c3cc60f6 | ||
|
|
716bca211b | ||
|
|
8179813fe1 | ||
|
|
d355de509b | ||
|
|
b04a2d4c08 | ||
|
|
6d3232a4f0 | ||
|
|
2753075180 | ||
|
|
d0166b25e4 | ||
|
|
73ee657d74 | ||
|
|
45913e5ee8 | ||
|
|
e6369820a9 | ||
|
|
22a5b339f7 | ||
|
|
2cea3b6435 | ||
|
|
5d2d06fb3e | ||
|
|
0dd7bc7fb9 | ||
|
|
0b0005337c | ||
|
|
d26fb02bb9 | ||
|
|
af683835d9 | ||
|
|
c43647ca86 | ||
|
|
6d02e70025 | ||
|
|
5498c6f87d | ||
|
|
11f59bc3ac | ||
|
|
94cb7de79f | ||
|
|
838f45775b | ||
|
|
1c1422e4b5 | ||
|
|
cd8ca6fc62 | ||
|
|
b7a0a9d7c2 | ||
|
|
7822ab113a | ||
|
|
e250a91f09 | ||
|
|
92a65dcda5 | ||
|
|
4b129d94e4 | ||
|
|
e7960d1d44 | ||
|
|
95589307cd | ||
|
|
20a0e4f3e0 | ||
|
|
6a9213da64 | ||
|
|
7a89e3cf33 | ||
|
|
64607df929 | ||
|
|
a62a1012fa | ||
|
|
14efd0b2f9 | ||
|
|
7ad2192df8 | ||
|
|
3cb5cbd8d5 | ||
|
|
cc9011cd68 | ||
|
|
dc3d89008d | ||
|
|
1893642187 | ||
|
|
a9ece5772d | ||
|
|
cf34716a57 | ||
|
|
1337831061 | ||
|
|
757e72100d | ||
|
|
a75b819858 | ||
|
|
da4a0f09ed | ||
|
|
87d847a074 | ||
|
|
84711beec0 | ||
|
|
f3cf58c8ff | ||
|
|
cf40497e6e | ||
|
|
dfebc4b78d | ||
|
|
15f41a2e7c | ||
|
|
ad6e55ca17 | ||
|
|
6b466d217a | ||
|
|
00dcb304c7 | ||
|
|
c6fb3d6f41 | ||
|
|
ac3143811f | ||
|
|
7e27dd7678 | ||
|
|
c2508296a5 | ||
|
|
a9b50ce6fc | ||
|
|
eac98a6d4d | ||
|
|
7e2b2a9a02 | ||
|
|
353de471eb | ||
|
|
85fc20b52d | ||
|
|
cc25a781f8 | ||
|
|
fc3012ba72 | ||
|
|
d93a92c1c8 | ||
|
|
f7f795f58a | ||
|
|
2700f8cdd2 | ||
|
|
6310de0d20 | ||
|
|
218794be77 | ||
|
|
af71ae649b | ||
|
|
9bc72c1a06 | ||
|
|
8d7c157751 | ||
|
|
558a66fbe5 | ||
|
|
f95b414d22 | ||
|
|
e793a1e1aa | ||
|
|
b76010cb5a | ||
|
|
52475df783 | ||
|
|
1f3f32d377 | ||
|
|
3f5ba10354 | ||
|
|
25f4a018d9 | ||
|
|
a11a279c00 | ||
|
|
fd4fdb31b5 | ||
|
|
1921796d6d | ||
|
|
543a2b9dc7 | ||
|
|
dd23e03342 | ||
|
|
5307c74f85 | ||
|
|
d701c406e2 | ||
|
|
3ba56a0a65 | ||
|
|
4adafb6d1e | ||
|
|
4453a51211 | ||
|
|
14429d2943 | ||
|
|
1a62a7831b | ||
|
|
242e35c212 | ||
|
|
ea763fdfd5 | ||
|
|
e762b7ff48 | ||
|
|
298068b2b9 | ||
|
|
cb4120ec4b | ||
|
|
5cfbb87bee | ||
|
|
9e472ed83c | ||
|
|
ebca753fc4 | ||
|
|
548f45cd56 | ||
|
|
8ffabf1813 | ||
|
|
1f40d4f941 | ||
|
|
41582045d0 | ||
|
|
fd9e3fc03a | ||
|
|
8c42b2bdb4 | ||
|
|
7b1787fdbb | ||
|
|
71fee0025d | ||
|
|
1204cf1ba0 | ||
|
|
7bd8d8c3ae | ||
|
|
2c4d5fa38d | ||
|
|
bedb2d943e | ||
|
|
a3640bd9bf | ||
|
|
7c0b9ffe06 | ||
|
|
161c7d30ca | ||
|
|
4ff6e792cd | ||
|
|
af5df890a5 | ||
|
|
9ba011003a | ||
|
|
bb168d35a8 | ||
|
|
3306d30094 | ||
|
|
6516e0dfd2 | ||
|
|
00a396014b | ||
|
|
13356047dc | ||
|
|
8a6488b067 | ||
|
|
1c2ea56f42 | ||
|
|
1d7ae300e2 | ||
|
|
6013e186ed | ||
|
|
207d3d3340 | ||
|
|
5a6cde1446 | ||
|
|
63f7d826bc | ||
|
|
ff8773f6bd | ||
|
|
a868cb97d9 | ||
|
|
915d73e6f2 | ||
|
|
5f4f6e37b5 | ||
|
|
9c350311e8 | ||
|
|
3c6ba72a2a | ||
|
|
816442f5f0 | ||
|
|
3b51d18ce7 | ||
|
|
6696b6661a | ||
|
|
8c87478636 | ||
|
|
d870b072d7 | ||
|
|
2ea2af7d2a | ||
|
|
f737ea96f3 | ||
|
|
05f90394db | ||
|
|
c24b0c6bb4 | ||
|
|
e07a4dc7ba | ||
|
|
fc6748a46b | ||
|
|
7697c46652 | ||
|
|
ed52e5afd1 | ||
|
|
33a5b84181 | ||
|
|
c09a407f4c | ||
|
|
d35784ec61 | ||
|
|
53e012f296 | ||
|
|
2a9d0a5e7d | ||
|
|
474f4572f2 | ||
|
|
bf57cb209f | ||
|
|
9bc41c1709 | ||
|
|
fe10b8650f | ||
|
|
3a311c9584 | ||
|
|
d1106f53e0 | ||
|
|
a3a1bba5ef | ||
|
|
028d66befc | ||
|
|
bb59cd5742 | ||
|
|
604e3068b2 | ||
|
|
27f1d3b704 | ||
|
|
d007623347 | ||
|
|
6a5cf7a1fa | ||
|
|
3adfe249b0 | ||
|
|
923893e160 | ||
|
|
256e5360d4 | ||
|
|
304c597a2f | ||
|
|
f86d3a69d2 | ||
|
|
d7c8adfd82 | ||
|
|
55cd069043 | ||
|
|
3ca0e9c420 | ||
|
|
1dd4323613 | ||
|
|
d78916f85f | ||
|
|
1840d15397 | ||
|
|
b98d1216b1 | ||
|
|
27db727321 | ||
|
|
3f6b1f6ccb | ||
|
|
6d633b372a | ||
|
|
91352e855a | ||
|
|
8bb9b594cf | ||
|
|
6d2fd2e641 | ||
|
|
422fbcb0b7 | ||
|
|
afce106186 | ||
|
|
f21c8154ed | ||
|
|
3988a648d6 | ||
|
|
1b632894d3 | ||
|
|
5e128f89f6 | ||
|
|
fff0b15ae5 | ||
|
|
a7e14f1093 | ||
|
|
94eeaeb8d3 | ||
|
|
64191e8303 | ||
|
|
21cfb71617 | ||
|
|
806457063f | ||
|
|
b9213b73bd | ||
|
|
d7f0102aa2 | ||
|
|
f09e61a59a | ||
|
|
d426aaa88a | ||
|
|
19e45389e1 | ||
|
|
6d2389945b | ||
|
|
14c48253f6 | ||
|
|
e5ff25b92d | ||
|
|
5c88888e02 | ||
|
|
10057de9b3 | ||
|
|
cc88ebd2b9 | ||
|
|
6baedf909d | ||
|
|
f39d9d6f1b | ||
|
|
ab61a95f83 | ||
|
|
10ceed30c6 | ||
|
|
2b9aa94f3a | ||
|
|
848fb975ed | ||
|
|
d7f59dac84 | ||
|
|
dd47e615ee | ||
|
|
8f2f7ea1a5 | ||
|
|
80a8efd8ce | ||
|
|
d9dce77ef4 | ||
|
|
ce7053a1fe | ||
|
|
0db1530171 | ||
|
|
3745504107 | ||
|
|
57533fd831 | ||
|
|
f57a0d4d6b | ||
|
|
22772ca33e | ||
|
|
dba6ff1d51 | ||
|
|
40146dedaf | ||
|
|
387b822f53 | ||
|
|
b9a3563e5b | ||
|
|
3d6468326a | ||
|
|
298e37ec53 | ||
|
|
5b137c457b | ||
|
|
5218a3fbac | ||
|
|
4569cb432d | ||
|
|
611e598756 | ||
|
|
937d79d28f | ||
|
|
23c2a771d3 | ||
|
|
58a890e836 | ||
|
|
6a869e120c | ||
|
|
ae7c298b1a | ||
|
|
53bfe12ac1 | ||
|
|
140ea683a6 | ||
|
|
0634a97598 | ||
|
|
3479c794de | ||
|
|
89cad116f7 | ||
|
|
19c84eb694 | ||
|
|
eae390acf5 | ||
|
|
10567afbb9 | ||
|
|
51bad3bf3c | ||
|
|
9134d8841d | ||
|
|
e9a026c131 | ||
|
|
9a2fd0e2b2 | ||
|
|
522f7e6844 | ||
|
|
cb4f46decc | ||
|
|
81256279a8 | ||
|
|
039bd1ddc0 | ||
|
|
0791d4797f | ||
|
|
6a06142e1e | ||
|
|
ef53dca062 | ||
|
|
6ce761edda | ||
|
|
d8fd218409 | ||
|
|
edc2310599 | ||
|
|
b1cd13d629 | ||
|
|
b81940351f | ||
|
|
a42e99c4aa | ||
|
|
ff40b521b7 | ||
|
|
85392496e7 | ||
|
|
29cae9975e | ||
|
|
170d6b28f8 | ||
|
|
9a8b404054 | ||
|
|
41af5187aa | ||
|
|
a844ca161f | ||
|
|
e09efba313 | ||
|
|
96a0dbea2d | ||
|
|
5b3b5271ad | ||
|
|
d7d13c12fe | ||
|
|
54220d0e71 | ||
|
|
4a2e3586f1 | ||
|
|
f808e85da9 | ||
|
|
1671d1f580 | ||
|
|
7de1bf9d95 | ||
|
|
7368b0cefb | ||
|
|
4af43d676a | ||
|
|
67dc848b2d | ||
|
|
7ec8f0d26b | ||
|
|
eaf08a9971 | ||
|
|
5bdb9e972e | ||
|
|
d4d87054c4 | ||
|
|
0f93929544 | ||
|
|
1c0e794f87 | ||
|
|
f9bce5a5f9 | ||
|
|
797ae096c8 | ||
|
|
6d76918424 | ||
|
|
2aced893c6 | ||
|
|
f0373cd789 | ||
|
|
2f88dc64fc | ||
|
|
781ca77794 | ||
|
|
c6e453fb00 | ||
|
|
a40b3dd377 | ||
|
|
096b3534d8 | ||
|
|
5324244c55 | ||
|
|
993f1dc853 | ||
|
|
d8a4e9e1ab | ||
|
|
b3ffd33507 | ||
|
|
c93870316c | ||
|
|
fc9906624e | ||
|
|
ba6209ba54 | ||
|
|
f9769a73fe | ||
|
|
3a2f56cb95 | ||
|
|
a4d33879dc | ||
|
|
e2a91d1ea9 | ||
|
|
f30f80d117 | ||
|
|
266274135e | ||
|
|
a10439b67c | ||
|
|
0fd8d0e2bf | ||
|
|
47e2707fd3 | ||
|
|
f7bb4a7d60 | ||
|
|
6102a31a31 | ||
|
|
1692c3b102 | ||
|
|
ac60725d2a | ||
|
|
1542f73fa5 | ||
|
|
70a22187f7 | ||
|
|
347e598715 | ||
|
|
a737810c50 | ||
|
|
92654a71fb | ||
|
|
18615640e0 | ||
|
|
b8c80a2310 | ||
|
|
c34c98386e | ||
|
|
d8a3d2793f | ||
|
|
360b0d9997 | ||
|
|
356f46aaf4 | ||
|
|
87ac0507d9 | ||
|
|
63657c18e2 | ||
|
|
817f92a50e | ||
|
|
304be96dd6 | ||
|
|
9639081e7e | ||
|
|
dca553048a | ||
|
|
6201ed4d55 | ||
|
|
6db2c04585 | ||
|
|
f3840512ba | ||
|
|
9a6cf58565 | ||
|
|
78076122ba | ||
|
|
7429f66d6b | ||
|
|
e59eff83b9 | ||
|
|
2083d85afa | ||
|
|
4c9f1369c8 | ||
|
|
adca1d7855 | ||
|
|
dfc4e99560 | ||
|
|
344076c943 | ||
|
|
710f1e2ca0 | ||
|
|
74ea85d19c | ||
|
|
dded98e30c | ||
|
|
160c27c15a | ||
|
|
a6a9025bab | ||
|
|
a780d4463c | ||
|
|
23539ee907 | ||
|
|
b515df611d | ||
|
|
0d896fef0b | ||
|
|
283d5c64cb | ||
|
|
3134bc432b | ||
|
|
fd93fef73e | ||
|
|
8939a9c786 | ||
|
|
52c0d360b2 | ||
|
|
d99432bff1 | ||
|
|
4dd2d3ac7d | ||
|
|
aa7fe3668c | ||
|
|
83ebcf1dae | ||
|
|
c9317659c5 | ||
|
|
6562c558de | ||
|
|
303f67c036 | ||
|
|
2482d122b8 | ||
|
|
1733c38b5c | ||
|
|
7a1e4e9e99 | ||
|
|
e590313297 | ||
|
|
b63d243e33 | ||
|
|
e9c1216d5c | ||
|
|
df9e50445e | ||
|
|
61339face6 | ||
|
|
9cd751e977 | ||
|
|
7aa08ff885 | ||
|
|
a824caf712 | ||
|
|
395210e4f0 | ||
|
|
e23354b2bb | ||
|
|
bc472eb0b3 | ||
|
|
256f8e7226 | ||
|
|
f41959537b | ||
|
|
c9e05cf9f6 | ||
|
|
82d9a02d92 | ||
|
|
dc9fa81346 | ||
|
|
b91c178200 | ||
|
|
adebdf36a5 | ||
|
|
4f34980c9f | ||
|
|
e70766a535 | ||
|
|
55110dfbac | ||
|
|
56405ac903 | ||
|
|
2b2136c468 | ||
|
|
f12031ee9e | ||
|
|
c26852da77 | ||
|
|
d9dc171c28 | ||
|
|
d407f31ae5 | ||
|
|
f688b8d299 | ||
|
|
d8e6a7b687 | ||
|
|
7c42b04eff | ||
|
|
f527841c29 | ||
|
|
48a8dc0989 | ||
|
|
7e35c9c754 | ||
|
|
7502a2b1ff | ||
|
|
6c2de40dba | ||
|
|
ef90f19eaa | ||
|
|
90ab34591a | ||
|
|
21d3a3dd1e | ||
|
|
b44e70115b | ||
|
|
ac31957707 | ||
|
|
65e27a268d | ||
|
|
6bd59b10c7 | ||
|
|
6a6a692891 | ||
|
|
479b18354d | ||
|
|
9c6452544b | ||
|
|
0a6ff900da | ||
|
|
f54f863611 | ||
|
|
9cc04da7b2 | ||
|
|
d7f5b0c9d7 | ||
|
|
9bd4598c6a | ||
|
|
e3b052bc38 | ||
|
|
f215970649 | ||
|
|
dfe1cd4f90 | ||
|
|
3d2e6aea7b | ||
|
|
749b0d7019 | ||
|
|
7978f85f7a | ||
|
|
bd14acb68a | ||
|
|
1e9ce550db | ||
|
|
6278dfa77e | ||
|
|
2a3e355437 | ||
|
|
f6b0459d27 | ||
|
|
790d6912fd | ||
|
|
e69e5b4f50 | ||
|
|
483306e73c | ||
|
|
1148a0b637 | ||
|
|
524021f0fa | ||
|
|
5b5f9aa01d | ||
|
|
f97f92c297 | ||
|
|
9d4139085b | ||
|
|
0ee7ffb5e5 | ||
|
|
8a7bb1be9f | ||
|
|
d4135e80a6 | ||
|
|
a5ade39d7c | ||
|
|
f39b4e7d22 | ||
|
|
080469cdf5 | ||
|
|
835ad29417 | ||
|
|
c09bea4710 | ||
|
|
879c0f4114 | ||
|
|
5feb07583b | ||
|
|
5388002f54 | ||
|
|
c80fa9914b | ||
|
|
b43d566968 | ||
|
|
6b4e15dd0f | ||
|
|
d9ef32d7e8 | ||
|
|
49389d6f06 | ||
|
|
c75dc3cc36 | ||
|
|
c0eabf0438 | ||
|
|
7730d0a4f8 | ||
|
|
e79da408a8 | ||
|
|
7381784d0f | ||
|
|
085fb283e5 | ||
|
|
61e0e50e7b | ||
|
|
00460d856b | ||
|
|
48958f392f | ||
|
|
a84efeb5d5 | ||
|
|
1c8c05ae04 | ||
|
|
401d386812 | ||
|
|
6b07f58e8e | ||
|
|
6e8c978d12 | ||
|
|
5b2296b056 | ||
|
|
dbf0486acb | ||
|
|
b030e935ce | ||
|
|
29bd43413a | ||
|
|
2249b9449c | ||
|
|
30920b1b78 | ||
|
|
8f92a3e875 | ||
|
|
ed1a55d9cd | ||
|
|
93ef84f495 | ||
|
|
ccfcbe8526 | ||
|
|
5938143002 | ||
|
|
8135da71bd | ||
|
|
a3c73a04c2 | ||
|
|
7f90d31846 | ||
|
|
45fbd22e28 | ||
|
|
4689d56955 | ||
|
|
aa1b2808e7 | ||
|
|
40ad4bdbd8 | ||
|
|
b6510d66e0 | ||
|
|
4ea33ea482 | ||
|
|
e13d410b4a | ||
|
|
72da7e6c54 | ||
|
|
fb05960d79 | ||
|
|
7bd0943412 | ||
|
|
bb2649d063 | ||
|
|
d743bdbf5a | ||
|
|
61890f19bc | ||
|
|
b756a8edef | ||
|
|
adcb2f1aa8 | ||
|
|
e574f4516f | ||
|
|
2ac9c11ec9 | ||
|
|
1c470ab9e3 | ||
|
|
08b8a8e3af | ||
|
|
11ee1a7dcb | ||
|
|
a281b8c74e | ||
|
|
5cb37148c6 | ||
|
|
05878d3176 | ||
|
|
d1c42262d6 | ||
|
|
8dcc114873 | ||
|
|
c54cf26848 | ||
|
|
bfb548636e | ||
|
|
36e1b2ba08 | ||
|
|
301ac279ff | ||
|
|
08d21ccba7 | ||
|
|
62876ca377 | ||
|
|
10f94148af | ||
|
|
31502c2ebc | ||
|
|
62b29ecb65 | ||
|
|
67337e013a | ||
|
|
f987fa13ea | ||
|
|
73dfe631ce | ||
|
|
83ca8147ca | ||
|
|
1c11e7f97b | ||
|
|
aefae79186 | ||
|
|
4b05a9bb6f | ||
|
|
2453719a87 | ||
|
|
ea929b00e3 | ||
|
|
ede940a398 | ||
|
|
67da853146 | ||
|
|
624befd704 | ||
|
|
203539841d | ||
|
|
262db23f7d | ||
|
|
28ea22f0e1 | ||
|
|
3f349c3531 | ||
|
|
9928e8562a | ||
|
|
b1e3fc5761 | ||
|
|
b2390f1caf | ||
|
|
8cc9aeba4a | ||
|
|
ba0823c38c | ||
|
|
b9379f2ddf | ||
|
|
38a950a6dc | ||
|
|
fb24dca019 | ||
|
|
07d131c945 | ||
|
|
0c1c710afe | ||
|
|
15cd93c30f | ||
|
|
a5d9e17a8c | ||
|
|
a82926dd0d | ||
|
|
12435b997a | ||
|
|
5945be95cf | ||
|
|
5c2e7ce407 | ||
|
|
834e894b1d | ||
|
|
d25dac69d2 | ||
|
|
3cc4173399 | ||
|
|
36ab16c1ed | ||
|
|
5356373681 | ||
|
|
f45a2643f2 | ||
|
|
e55933706d | ||
|
|
3b3d696e45 | ||
|
|
281351e6b3 | ||
|
|
34089aec70 | ||
|
|
3658d0e039 | ||
|
|
7a10636128 | ||
|
|
604ba7f4bc | ||
|
|
27b7fb54e8 | ||
|
|
d351aa842c | ||
|
|
59da705b8f | ||
|
|
99b8f16d88 | ||
|
|
06ffe722d4 | ||
|
|
6264104642 | ||
|
|
c97812c340 | ||
|
|
bd4c578230 | ||
|
|
6ec2949b6f | ||
|
|
1ff23ebfd9 | ||
|
|
7698990e37 | ||
|
|
17e092afb3 | ||
|
|
2db65b9d1f | ||
|
|
c6436f47eb | ||
|
|
e88b4a4412 | ||
|
|
01a177adfb | ||
|
|
052b5e0ea8 | ||
|
|
68cd447109 | ||
|
|
4a8a5ed8d4 | ||
|
|
84077505b0 | ||
|
|
c4554b71d3 | ||
|
|
63ce743571 | ||
|
|
6cf53c611b | ||
|
|
d8720ee325 | ||
|
|
73501f3ad3 | ||
|
|
54ee655472 | ||
|
|
571b9fb8e0 | ||
|
|
cdd6b243ff | ||
|
|
fca77a868f | ||
|
|
424e854778 | ||
|
|
0979d565bb | ||
|
|
f5e6ca3e10 | ||
|
|
2bde07561f | ||
|
|
16c92cc739 | ||
|
|
8b31a918a4 | ||
|
|
ee0bd49918 | ||
|
|
a625eeeac8 | ||
|
|
bfcd795687 | ||
|
|
e2a9be9cec | ||
|
|
37dd075309 | ||
|
|
89769fb0e5 | ||
|
|
b24fac3dd8 | ||
|
|
4794fe495c | ||
|
|
869fdbcc6a | ||
|
|
702e6d3b51 | ||
|
|
2913e13a30 | ||
|
|
5f1e37b7fa | ||
|
|
ec0209b175 | ||
|
|
a17dcbde0f | ||
|
|
fbd159a23a | ||
|
|
599a6bf050 | ||
|
|
185b16a858 | ||
|
|
e7e3ed4923 | ||
|
|
47df5476ba | ||
|
|
d7c516ab00 | ||
|
|
50838970ec | ||
|
|
1d15ee7034 | ||
|
|
7029541b4f | ||
|
|
ada8e447cc | ||
|
|
1841fc18fa | ||
|
|
94ee465682 | ||
|
|
3e021b3a75 | ||
|
|
0643f149b7 | ||
|
|
939768eec0 | ||
|
|
f2235dacdc | ||
|
|
50017c28da | ||
|
|
85b2a03a42 | ||
|
|
829087550d | ||
|
|
dd6f71fe85 | ||
|
|
92a928680c | ||
|
|
d008b1970c | ||
|
|
4affbb8c6b | ||
|
|
ddb2ea4b5f | ||
|
|
a69683183f | ||
|
|
8d34f87667 | ||
|
|
128c4fe222 | ||
|
|
b10141d71f | ||
|
|
68e0b35364 | ||
|
|
1324f5e59c | ||
|
|
7759aacb35 | ||
|
|
fd6f7cd881 | ||
|
|
3fdeb38bb7 | ||
|
|
e27f5d0460 | ||
|
|
0720128bd4 | ||
|
|
540472a093 | ||
|
|
daca78b6cd | ||
|
|
4195840b2c | ||
|
|
57c529758e | ||
|
|
5ba9a0eb3f | ||
|
|
b8888a5d46 | ||
|
|
0857f979ff | ||
|
|
11f4ae019c | ||
|
|
0ffeb0c5af | ||
|
|
d6f6b41145 | ||
|
|
64daaeb310 | ||
|
|
0646b0060e | ||
|
|
c794ca85fd | ||
|
|
5b4019dd3d | ||
|
|
a03ccd7b59 | ||
|
|
4b64aad5ce | ||
|
|
d146ff8794 | ||
|
|
5349bf7628 | ||
|
|
a79e4d1bb3 | ||
|
|
f462435dc2 | ||
|
|
48ad614441 | ||
|
|
f699516fdb | ||
|
|
ca5cbb640a | ||
|
|
0a96259ddf | ||
|
|
d99b9c04e4 | ||
|
|
64d261e053 | ||
|
|
eb027d98aa | ||
|
|
a95727b654 | ||
|
|
4e636d7eec | ||
|
|
3cd53f617a | ||
|
|
b1684e82d8 | ||
|
|
a55027b838 | ||
|
|
28678acf74 | ||
|
|
ce6594c8cc | ||
|
|
75855d5450 | ||
|
|
f248699a30 | ||
|
|
29594726ca | ||
|
|
0a41b07297 | ||
|
|
e45cb7fac1 | ||
|
|
489dbfc72a | ||
|
|
a89ae7d77a | ||
|
|
a1eeff4034 | ||
|
|
0e1013a570 | ||
|
|
4562b06a60 | ||
|
|
3c96218338 | ||
|
|
f0a4ea099c | ||
|
|
c8d6693fba | ||
|
|
81bbdfe413 | ||
|
|
0e362943bf | ||
|
|
1e37fed90b | ||
|
|
aafcfef387 | ||
|
|
4b83d8160f | ||
|
|
73a41707e5 | ||
|
|
c989c533e8 | ||
|
|
707dc8c65c | ||
|
|
4c6157a06e | ||
|
|
f973396821 | ||
|
|
e73216d4c1 | ||
|
|
e6de26736b | ||
|
|
d131addd63 | ||
|
|
0c7705beff | ||
|
|
08b11addec | ||
|
|
555f96cfaf | ||
|
|
59ffacb3df | ||
|
|
83acb66f00 | ||
|
|
1f9ae45875 | ||
|
|
ffa628be2d | ||
|
|
8916f6f829 | ||
|
|
215c8fd261 | ||
|
|
061cc908a7 | ||
|
|
18a519f9ed | ||
|
|
7970c9dbe5 | ||
|
|
5ca0c066e2 | ||
|
|
563728c7b8 | ||
|
|
31a72b6562 | ||
|
|
d3dfbc3034 | ||
|
|
f143a6ba08 | ||
|
|
28a65923b6 | ||
|
|
4ca3df77b3 | ||
|
|
4cbe264869 | ||
|
|
b6b65b6bf7 | ||
|
|
e7cc42a927 | ||
|
|
bba3ca8cc0 | ||
|
|
8423e2d245 | ||
|
|
fc263718a1 | ||
|
|
c3a99cf5a4 | ||
|
|
f6820ec615 | ||
|
|
226ad3fe22 | ||
|
|
a9b17e930c | ||
|
|
932ea7ba8f | ||
|
|
c720d78c39 | ||
|
|
8d21e441a0 | ||
|
|
16ecb1a9cb | ||
|
|
f68acca427 | ||
|
|
671d7e2beb | ||
|
|
52fc497412 | ||
|
|
2084ad318f | ||
|
|
b530c1a43d | ||
|
|
f2797a4153 | ||
|
|
659c326f89 | ||
|
|
534b07d120 | ||
|
|
de64fc8b8d | ||
|
|
1e234fcb73 | ||
|
|
fa9a7e725b | ||
|
|
95b2675f03 | ||
|
|
564902b886 | ||
|
|
071a04595a | ||
|
|
eaa4b76ede | ||
|
|
74a1713e99 | ||
|
|
5f5aa0b2f7 | ||
|
|
eef59fd40e | ||
|
|
361ff315e9 | ||
|
|
eeea8e530e | ||
|
|
8d5286703f | ||
|
|
74f2180fa4 | ||
|
|
d042169f2e | ||
|
|
eeaff6b553 | ||
|
|
6efd048fd6 | ||
|
|
6e9e694f66 | ||
|
|
44a0f1b505 | ||
|
|
9790211891 | ||
|
|
8caee09ea4 | ||
|
|
26f5305593 | ||
|
|
d33029027f | ||
|
|
339aaaec57 | ||
|
|
db2425c473 | ||
|
|
18731f6055 | ||
|
|
34f1f7a31d | ||
|
|
7ef153756b | ||
|
|
bf90509526 | ||
|
|
d853eca489 | ||
|
|
869ae01da9 | ||
|
|
9cc1b03c56 | ||
|
|
96820418b5 | ||
|
|
385d9f16e9 | ||
|
|
d56fce37dd | ||
|
|
aef2c9e5cf | ||
|
|
0a5a42b32a | ||
|
|
9a4ff5cb43 | ||
|
|
f66c91e18e |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/packages/node_modules/** linguist-generated=false
|
||||
34
.github/ISSUE_TEMPLATE.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<!--
|
||||
## Before you hit that Submit button....
|
||||
|
||||
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
|
||||
|
||||
If your issue is:
|
||||
- a general 'how-to' type question,
|
||||
- a feature request or suggestion for a change,
|
||||
- or problems with 3rd party (`node-red-contrib-`) nodes
|
||||
|
||||
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
|
||||
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
||||
|
||||
## So you have a real issue to raise...
|
||||
|
||||
To help us understand the issue, please fill-in as much of the following information as you can:
|
||||
-->
|
||||
|
||||
### What are the steps to reproduce?
|
||||
|
||||
### What happens?
|
||||
|
||||
### What do you expect to happen?
|
||||
|
||||
### Please tell us about your environment:
|
||||
|
||||
- [ ] Node-RED version:
|
||||
- [ ] node.js version:
|
||||
- [ ] npm version:
|
||||
- [ ] Platform/OS:
|
||||
- [ ] Browser:
|
||||
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<!--
|
||||
## Before you hit that Submit button....
|
||||
|
||||
Please read our [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
|
||||
before submitting a pull-request.
|
||||
|
||||
## Types of changes
|
||||
|
||||
What types of changes does your code introduce?
|
||||
Put an `x` in the boxes that apply
|
||||
-->
|
||||
|
||||
- [ ] Bugfix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
|
||||
<!--
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it **may well get rejected** if it hasn't been discussed on
|
||||
the [forum](https://discourse.nodered.org) or
|
||||
[slack team](https://nodered.org/slack) first.
|
||||
|
||||
-->
|
||||
|
||||
## Proposed changes
|
||||
|
||||
<!-- Describe the nature of this change. What problem does it address? -->
|
||||
|
||||
## Checklist
|
||||
<!-- Put an `x` in the boxes that apply -->
|
||||
|
||||
- [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
|
||||
- [ ] For non-bugfix PRs, I have discussed this change on the mailing list/slack team.
|
||||
- [ ] I have run `grunt` to verify the unit tests pass
|
||||
- [ ] I have added suitable unit tests to cover the new/changed functionality
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -17,3 +17,7 @@ node_modules
|
||||
public
|
||||
locales/zz-ZZ
|
||||
nodes/core/locales/zz-ZZ
|
||||
!packages/node_modules
|
||||
packages/node_modules/@node-red/editor-client/public
|
||||
!test/**/node_modules
|
||||
docs
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
"asi": true, // allow missing semicolons
|
||||
"curly": true, // require braces
|
||||
"eqnull": true, // ignore ==null
|
||||
//"eqeqeq": true, // enforce ===
|
||||
"freeze": true, // don't allow override
|
||||
"indent": 4, // default indent of 4
|
||||
"forin": true, // require property filtering in "for in" loops
|
||||
"immed": true, // require immediate functions to be wrapped in ( )
|
||||
"nonbsp": true, // warn on unexpected whitespace breaking chars
|
||||
@@ -9,6 +12,8 @@
|
||||
//"unused": true, // Check for unused functions and variables
|
||||
"loopfunc": true, // allow functions to be defined in loops
|
||||
//"expr": true, // allow ternery operator syntax...
|
||||
"shadow": true, // allow variable shadowing (re-use of names...)
|
||||
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
||||
"proto": true // allow setting of __proto__ in node < v0.12
|
||||
"proto": true, // allow setting of __proto__ in node < v0.12,
|
||||
"esversion": 6 // allow es6
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.settings
|
||||
.jshintignore
|
||||
.jshintrc
|
||||
.project
|
||||
.tern-project
|
||||
.travis.yml
|
||||
.git
|
||||
28
.travis.yml
28
.travis.yml
@@ -1,24 +1,10 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
env:
|
||||
- CXX="g++-4.8"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- gcc-4.8
|
||||
matrix:
|
||||
allow_failures:
|
||||
- node_js: "7"
|
||||
node_js:
|
||||
- "7"
|
||||
- "6"
|
||||
- "4"
|
||||
- "0.10"
|
||||
script:
|
||||
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
|
||||
before_script:
|
||||
- npm install -g istanbul
|
||||
- npm install coveralls
|
||||
include:
|
||||
- node_js: "10"
|
||||
script:
|
||||
- ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
|
||||
before_script:
|
||||
- npm install -g istanbul coveralls
|
||||
- node_js: "8"
|
||||
|
||||
854
CHANGELOG.md
854
CHANGELOG.md
@@ -1,3 +1,821 @@
|
||||
#### 0.19.4: Maintenance Release
|
||||
|
||||
- Fix race condition in non-cache lfs context Fixes #1888
|
||||
- LocalFileSystem Context: Remove extra flush code
|
||||
- Prevent race condition in caching mode of lfs context (#1889)
|
||||
- Allow context store name to be provided in the key
|
||||
- Switch node: only use promises when absolutely necessary
|
||||
- Fix dbl-click handling on webkit-based browsers
|
||||
- Ensure context.flow/global cannot be deleted or enumerated
|
||||
- Handle context.get with multiple levels of unknown key Fixes #1883
|
||||
- Fix global.get("foo.bar") for functionGlobalContext set values
|
||||
- Fix node color bug (#1877)
|
||||
- Merge pull request #1857 from cclauss/patch-1
|
||||
- Define raw_input() in Python 3 & fix time.sleep()
|
||||
|
||||
#### 0.19.3: Maintenance Release
|
||||
|
||||
- Split node - fix complete to send msg for k/v object
|
||||
- Remove unused Join node merged object key typed input
|
||||
- Set the JavaScript editor to full-screen
|
||||
- Filter global modules installed locally
|
||||
- Add svg to permitted icon extension list
|
||||
- Debug node - indicate status all the time if selected to do so
|
||||
- pi nodes - increase test coverage slightly
|
||||
- TCP-request node - only write payload
|
||||
- JSON schema: perform validation when obj -> obj or str -> str
|
||||
- JSON schema: add draft-06 support (via $schema keyword)
|
||||
- Mqtt proxy configuration for websocket connection, #1651.
|
||||
- Allows MQTT Shared Subscriptions for MQTT-In core node
|
||||
- Fix use of HTML tag or CSS class specification as icon of typedInput
|
||||
|
||||
#### 0.19.2: Maintenance Release
|
||||
|
||||
- Ensure node default colour is used if palette.theme has no match
|
||||
- fix lost messages / properties in TCPRequest Node; closes #1863 (#1864)
|
||||
- Fix typo in template.html
|
||||
- Improve error reporting from context plugin loading
|
||||
- Prevent no-op edit of node marking as changed due to icon
|
||||
- Change node must handle empty rule set
|
||||
|
||||
#### 0.19.1: Maintenance Release
|
||||
|
||||
- Pull in latest twitter node
|
||||
- Handle windows paths for context storage
|
||||
- Handle persisting objects with circular refs in context
|
||||
- Ensure js editor can expand to fill available space
|
||||
- Add example localfilesystem contextStorage to settings
|
||||
- Fix template node handling of nested context tags
|
||||
|
||||
#### 0.19: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add editorTheme.palette.theme to allow overriding colours
|
||||
- Index all node properties when searching Fixes #1446
|
||||
- Handle NaN and Infinity properly in debug sidebar Fixes #1778 #1779
|
||||
- Prevent horizontal scroll when palette name cannot wrap
|
||||
- Ignore middle-click on node/ports to enable panning
|
||||
- Better wire layout when looping back
|
||||
- fix appearence of retry button of remote branch management dialog
|
||||
- Handle releasing ctrl when using quick-add node dialog
|
||||
- Add $env function to JSONata expressions
|
||||
- Widen support for env var to use ${} or $() syntax
|
||||
- Add env-var support to TypedInput
|
||||
- Show unknown node properties in info tab
|
||||
- Add node icon picker widget
|
||||
- Only edit nodes on dbl click on primary button with no modifiers
|
||||
- Allow subflows to be put in any palette category
|
||||
- Add flow navigator widget
|
||||
- Cache flow library result to improve response time Fixes #1753
|
||||
- Add middle-button-drag to pan the workspace
|
||||
- allow multi-line category name in editor
|
||||
- Redesign sidebar tabs
|
||||
- Do not disable the export-clipboard menu option with empty selection
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Ensure runtime errors in Change node can be caught Fixes #1769
|
||||
- File: Add output to File Out node
|
||||
- Function: add expandable JavaScript editor pane
|
||||
- Function: allow id and name reference in function node code (#1731)
|
||||
- HTTP Request: Move to request module
|
||||
- HTTP: Ensure apiMaxLength applies to HTTP Nodes Fixes #1278
|
||||
- Join: accumulate top level properties
|
||||
- Join: allow environment variable as reduce init value
|
||||
- JSON: add JSON schema validation via msg.schema
|
||||
- Pi: Let nrgpio code work with python 3
|
||||
- Pi: let Pi nodes be visible/editable on all platforms
|
||||
- Switch: add isEmpty rule
|
||||
- TCP: queue messages while connecting; closes #1414
|
||||
- TLS: Add servername option to TLS config node for SNI Fixes #1805
|
||||
- UDP: Don't accidentally re-use udp port when set to not do so
|
||||
|
||||
Persistent Context
|
||||
|
||||
- Add Context data sidebar
|
||||
- Add persistable context option
|
||||
- Add default memory store
|
||||
- Add file-based context store
|
||||
- Add async mode to evaluateJSONataExpression
|
||||
- Update RED.util.evaluateNodeProperty to support context stores
|
||||
|
||||
Runtime
|
||||
|
||||
- Support flow.disabled and .info in /flow API
|
||||
- Node errors should be Strings not Errors Fixes #1781
|
||||
- Add detection of connection timeout in git communication Fixes #1770
|
||||
- Handle loading empty nodesDir
|
||||
- Add 'private' property to userDir generated package.json
|
||||
- Add RED.require to allow nodes to access other modules
|
||||
- Ensure add/remove modules are run sequentially
|
||||
|
||||
#### 0.18.7: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Do not trim wires if node declares outputs in defaults but misses value Fixes #1737
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Relax twitter node version ready for major version bump
|
||||
- Pass Date into the Function node sandbox to fix instanceof tests
|
||||
- let TCP in node report remote ip and port when in single packet mode
|
||||
- typo fix in node help (#1735)
|
||||
|
||||
Other Fixes
|
||||
- Tidy up default grunt task and fixup test break due to reorder Fixes #1738
|
||||
- Bump jsonata version
|
||||
|
||||
#### 0.18.6: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Handle a node having wires in the editor on ports it no longer has Fixes #1724
|
||||
- Add missing ACE snippet files
|
||||
- Fix wireClippedNodes is not defined Fixes #1726
|
||||
- Split node html to isolate bad nodes when loading
|
||||
- Avoid unnecessary use of .html() where .text() will do
|
||||
|
||||
- Add editorTheme.projects.enabled to default settings.js"
|
||||
|
||||
#### 0.18.5: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Add clone project to welcome screen
|
||||
- Handle cloning a project without package.json
|
||||
- Keep remote branch state in sync between editor and runtime
|
||||
|
||||
New Features
|
||||
|
||||
- Add type checks to switch node options (#1714)
|
||||
- add output property select to HTML parse node (#1701)
|
||||
- Add Prevent Following Redirect to HTTP Request node (#615) (#1684)
|
||||
- Add debug and trace functions to function node (#1654)
|
||||
- Enable user defined icon for subflow
|
||||
- Add MQTT disconnect message and rework broker node UI (#1719)
|
||||
- Japanese message catalogue updates (#1723)
|
||||
- Show node load errors in the Palette Manager view
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Highlight subflow node when log msg comes from inside Fixes #1698
|
||||
- Ensure node wires array is not longer than outputs value Fixes #1678
|
||||
- Allow importing an unknown config node to be undone Fixes #1681
|
||||
- Ensure keyboard shortcuts get saved in runtime settings Fixes #1696
|
||||
- Don't mark a subflow changed when actually modified nothing (#1665)
|
||||
|
||||
Node Fixes
|
||||
|
||||
- bind to correct port when doing udp broadcast/multicast (#1686)
|
||||
- Provide full error stack in Function node log message (#1700)
|
||||
- Fix http request doc type Fixes #1690
|
||||
- Make debug slightly larger to pass WCAG AA rating
|
||||
- Make core nodes labels more consistent, to close #1673
|
||||
- Allow template node to be updated more than once Fixes #1671
|
||||
- Fix the problem that output labels of switch node sometimes disappear (#1664)
|
||||
- Chinese translations for core nodes (#1607)
|
||||
|
||||
Runtime Fixes
|
||||
|
||||
- Handle and display for invalid flow credentials when project is disabled #1689 (#1694)
|
||||
- node-red-pi: fix behavior with old bash version (#1713)
|
||||
- Fix ENOENT error on first start when no user dir (#1711)
|
||||
- Handle null error object in Flow.handleError Fixes #1721
|
||||
- update settings comments to describe how to setup for ipv6 (#1675)
|
||||
- Remove credential props after diffing flow to prevent future false positives Fixes #1359
|
||||
- Log error if settings unavailable when saving user settings Fixes #1645
|
||||
- Keep backup of .config.json
|
||||
- Add warning if using \_credentialSecret from .config.json
|
||||
- Filter req.user in /settings to prevent potentially leaking info
|
||||
|
||||
#### 0.18.4: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Ensure sshkey file path is properly escaped on Windows
|
||||
- Normalize ssh key paths for Windows file names
|
||||
- Ensure userDir is an absolute path when used with sshkeygen
|
||||
- Detect if there are no existing flows to migrate into a project
|
||||
- Use relative urls when retriving flow history
|
||||
- Add credentialSecret to clone pane
|
||||
- Delay clearing inflight when changing credentials key
|
||||
- Mark deploy inflight when reverting a file change
|
||||
- Handle missing_flow_file error on clone properly
|
||||
- Remote project from cached list on delete so it can be reused
|
||||
- Fix tests for existing file flag in settings
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Fix merging a remote diff
|
||||
- Fixed the problems when using a node without defaults
|
||||
- Disable user defined icon for subflow
|
||||
- getDefaultNodeIcon should handle subflow instance nodes Fixes #1635
|
||||
- Add Japanese info text for core nodes
|
||||
- Fix message lookup for core nodes in case of i18 locales directory exists
|
||||
- Prevent the last tab from being deleted
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Ensure trigger gets reset when 2nd output is null
|
||||
|
||||
|
||||
#### 0.18.3: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Fix permissions on git/ssh scripts
|
||||
- Add support for GIT_SSH on older levels of git
|
||||
- Handle host key verification as auth error
|
||||
- Ensure commit list has a refs object even if empty
|
||||
- Make git error detection case-insensitive
|
||||
- Fix up merge conflict handling
|
||||
- Use flow-diff when looking at flow file changes
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Ensure debug tools show for 'complete msg object'
|
||||
- Fix msg.parts handling in concat mode of Batch node
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Fix offset calculation when dragging node from palette
|
||||
- Allow a library entry to use non-default node-input- prefixes
|
||||
- Change remote-diff shortcut and add it to keymap Fixes #1628
|
||||
|
||||
#### 0.18.2: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Filter out %D from git log command for older git versions
|
||||
- Ensure projects are created as logged in user
|
||||
- Better error handling/reporting in project creation
|
||||
- Add Project Settings menu option
|
||||
- Refresh vc sidebar on remote add/remove
|
||||
- Fix auth prompt for ssh repos
|
||||
- Prevent http git urls from including username/pword
|
||||
- Fix fetch auth handling on non-default remote
|
||||
- Avoid exception if git not installed
|
||||
- Check version of git client on startup
|
||||
- Fix pull/push when no tracked branch
|
||||
- Add git_pull_unrelated_history handling
|
||||
- Handle delete of last remote in project settings
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Fix and Add some Chinese translations
|
||||
- Update sort/batch docs
|
||||
- Don't assume node has defaults when exporting icon property
|
||||
- Ensure send is last thing trigger does
|
||||
- Ensure trigger doesn't set two simultaneous timeouts
|
||||
- Add missing property select var to HTML node
|
||||
- Add a default keepalive to tcp client mode
|
||||
- Move node.send in exec and httprequest nodes
|
||||
|
||||
|
||||
#### 0.18.1: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Handle more repo clone error cases
|
||||
- Relax validation of git urls
|
||||
- Revalidate project name on return to project-details view
|
||||
- Avoid unnecessary project refresh on branch-switch Fixes #1597
|
||||
- Add support for file:// git urls
|
||||
- Handle project first-run without existing flow file
|
||||
- Handle delete of last remote in project settings
|
||||
- Add git_pull_unrelated_history handling
|
||||
- Fix pull/push when no tracked branch
|
||||
- Remember to disable projects in editor when git not found
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Trigger node migration - ensure bytopic not blank
|
||||
- Add HEAD to list of methods with no body in http req node #1598
|
||||
- Do not include payload in GET requests Fixes #1598
|
||||
- Update sort/batch docs Fixes #1601
|
||||
- Don't assume node has defaults when exporting icon property
|
||||
|
||||
|
||||
#### 0.18: Milestone Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Beta: Projects - must be enabled in settings file
|
||||
- Allow port zero for Express (#1363)
|
||||
- Better error reporting when module provides duplicate type
|
||||
- Update jsonata to 1.5.0
|
||||
- add express-session memorystore without leaks (#1435)
|
||||
- Allow adminAuth.user to be a Function Fixes #1461
|
||||
- Ensure RED.server is set even if admin api disabled
|
||||
- Ensure strategy login button uses relative URL Fixes #1481
|
||||
- ignore `_msgid` when merging full objects
|
||||
- Move node install to spawn to allow for big stdout Fixes #1488
|
||||
- SIGINT handler should wait for stop to complete before exit
|
||||
|
||||
Editor
|
||||
|
||||
- allow a node's icon to be set dynamically (#1490)
|
||||
- Batch messages sent over comms to increase throughput
|
||||
- Migrate deploy confirmations to notifications
|
||||
- `oneditdelete` should be available to all node types Closes #1346
|
||||
- Sort typeSearch results based on position of match
|
||||
- Update ACE to test and add python highlighter (#1373)
|
||||
- Clear mouse state when typeSearch cancelled Fixes #1517
|
||||
- Handle scoped modules via palette editor
|
||||
- TypedInput: handle user defined value/labels options Fixes #1549
|
||||
|
||||
Nodes
|
||||
|
||||
- add msg. select to range and yaml nodes
|
||||
- add property choice to xml, sentiment nodes
|
||||
- mqtt: Add 'name' to mqtt-broker node, and label it by this if it is set. (#1364)
|
||||
- Add option to JSON node to ensure particular encoding
|
||||
- add parts support for HTML node (#1495)
|
||||
- Add passphrase to TLS node
|
||||
- Add rc property to exec node outputs 1 and 2 (#1401)
|
||||
- Add skip first n lines capability to csv node (#1535)
|
||||
- Add support for rejectUnauthorized msg property
|
||||
- Add TLS options to WebSocket client
|
||||
- Added parsed YAML support for template node (#1443)
|
||||
- Allow delay node in rate-limit mode to be reset Fixes #1360
|
||||
- Allow setTimeout in Function node to be promisified in node 8
|
||||
- Debug to status option (#1499)
|
||||
- enable template config via msg.template for stored or generated templates (#1503)
|
||||
- HTTP REQUEST: Adding PROPPATCH and PROPFIND http methods (#1531)
|
||||
- Initial support of merge & reduce mode for JOIN node (#1546)
|
||||
- Initial support of new BATCH node (#1548)
|
||||
- Initial support of sequence rules for SWITCH node (#1545)
|
||||
- initial support of SORT node (#1500)
|
||||
- Inject node - let once delay be editable (#1541)
|
||||
- Introduce `nodeMaxMessageBufferLength` setting for msg sequence nodes
|
||||
- Let CSV correct parts if we remove header row.
|
||||
- let default apply if msg.delay not set in override mode. (#1397)
|
||||
- let trigger node be reset by boolean message (#1554)
|
||||
- Let trigger node support per topic mode (#1398)
|
||||
- let HTML node return empty array for no matching input (#1582)
|
||||
- MQTT node - if Server/URL config contains '//' use it as a complete url; enabled ws:// and wss://
|
||||
- clone messages before delayed send (#1474)
|
||||
- Decrement connected client count rather than show disconnected
|
||||
- Don't end mqtt client on first error Fixes #1566
|
||||
- File out - create dirs synchronously to ensure they exist Fixes #1489
|
||||
- Fix debug message format for Buffer (#1444)
|
||||
- Fix global.keys() bug in function node (#1417)
|
||||
- Handle escape characters in template node which uses Mustache format and JSON output mode (#1377)
|
||||
- Move all node.send to end of timer functions in trigger node (issue #1527) (#1539)
|
||||
- Publish null/undefined to mqtt as blank not toString Fixes #1521
|
||||
- remove inject node at specific time spinner
|
||||
- restrict inject interval to less that 2^31 millisecs
|
||||
- tag UDP ports in use properly so they get closed correctly (#1508)
|
||||
|
||||
#### 0.17.5: Maintenance Release
|
||||
|
||||
- Add express-session missing dependency for oauth
|
||||
- Fix improper type tests is core test cases
|
||||
- File node: recreate write stream when file deleted Fixes #1351
|
||||
- Add flow stopping trace messages
|
||||
- Fix userDir test case when .config.json exists (#1350)
|
||||
- Do not try to send msg after http request error handled Fixes #1344
|
||||
- Fix boundary problem in range node (#1338)
|
||||
- Modify messages in node properties to refer messages.json (#1339)
|
||||
- Fix settings.js replacing webSocketVerifyClient by webSocketNodeVerifyClient (#1343)
|
||||
|
||||
|
||||
#### 0.17.4: Maintenance Release
|
||||
|
||||
- Add request node test case for POSTing 0
|
||||
- Allow false and 0 in payload for httprequest (#1334)
|
||||
- Add file extension into flow name of library automatically (#1331)
|
||||
- Fix accessing global context from jsonata expressions Fixes #1335
|
||||
- Disable editor whilst a deploy is inflight Fixes #1332
|
||||
- Replace Unknown nodes with their real versions when node loaded
|
||||
- Retry auto-install of modules that fail
|
||||
- Fix column name in link nodes to refer language file (#1330)
|
||||
- Use namespaces with link node title attributes i18n name Fixes #1329
|
||||
- Tidy up GPIO pin table presentation Fixes #1328
|
||||
- Join: count of 0 should not send on every msg
|
||||
- Handle importing only one end of a link node pair
|
||||
- Make sending to Debug synchronous again Fixes #1323
|
||||
- Make send-error behaviour optional in file node
|
||||
- Restore File In node behaviour of sending msg on error
|
||||
- Expose context.keys within Function node
|
||||
- JSON parser default should be not formatting output
|
||||
|
||||
|
||||
#### 0.17.3: Maintenance Release
|
||||
|
||||
- Fix flow library in menu to support period characters as flow name (#1320)
|
||||
- editorTheme not setting custom css/scripts properly
|
||||
- Fix missing icons for some nodes (#1321)
|
||||
- Add reformat button to JSONata test data editor
|
||||
- Update delay node status without spawning unnecessary intervals
|
||||
- Avoid stringify ServerResponse and Socket in Debug node Fixes #1311
|
||||
- Fix creating userDir other than system drive on Windows (#1317)
|
||||
- Trigger node not handling a duration of 0 as block mode Fixes #1316
|
||||
- Unable to config GPIO Pin 13 Fixes #1314
|
||||
|
||||
#### 0.17.2: Maintenance Release
|
||||
|
||||
- Fix GPIO node labels
|
||||
|
||||
#### 0.17.1: Maintenance Release
|
||||
|
||||
- Fix PI gpio to use BCM
|
||||
- Prevent event thread contention when sending to Debug node Closes #1311
|
||||
- Fix Bug: Can not display node icon when npm package has scope (#1305) (#1309)
|
||||
- Clear moved flag when nodes are deployed
|
||||
|
||||
#### 0.17: Milestone Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Return flow rev on reload api when api v2 enabled Closes #1273
|
||||
- Provide single endpoint to load all node message catalogs
|
||||
- Add .trace and .debug to Node prototype
|
||||
- Rename oauth auth scheme to strategy as it works for openid
|
||||
- Allow oauth schemes provide a custom verify function
|
||||
- Add support for oauth adminAuth configs
|
||||
- Cache auth details to save needlessly recalculating hashes
|
||||
- Add context.keys function to list top-level keys
|
||||
- Strip BOM character from JSON files if present Fixes #1239
|
||||
- Version check no meta (#1243)
|
||||
- Ensure all nodes have access to global context Fixes #1230
|
||||
- Don't process subscription for unauthenticated comms link Fixes #851
|
||||
- Clone credentials when passing to node Fixes #1198
|
||||
- Resolve dir argument of getLocalNodeFiles function (#1216)
|
||||
- Add wait for writing a library entry into a file. (#1186)
|
||||
- Use correct Buffer.from method rather than constructor
|
||||
- update core nodes to use newer Buffer syntax
|
||||
- Treat missing msg properties as undefined rather than throw error Fixes #1167
|
||||
- Allows flows to be enabled/disabled in the runtime
|
||||
- add off option to logging settings comment
|
||||
- Log error stack traces if verbose flag is set
|
||||
- Extract line number if available from node load errors
|
||||
- Add node 8 to travis (with allow failure)
|
||||
- Shuffle promises for creating default package.json
|
||||
- Create a package.json file in userDir if one doesn't exist
|
||||
- autoInstallModules option must honour version/pending_version
|
||||
- Refuse to update a non-local node module
|
||||
- Finalise nodeSettings and update tlsConfigDisableLocalFiles
|
||||
- Allow a node to declare what settings should be made available to the editor. (#1185)
|
||||
- Add node whitelist function (#1184)
|
||||
- Allow a node to declare settings that should be exported
|
||||
- Add test coverage for deleting a flow
|
||||
- Update tests for oauth -> strategy rename
|
||||
- Fix the test cases which sometimes fails due to timing. (#1228)
|
||||
- Extend timeout for the test case of installing non-existant path. (#1191)
|
||||
- Fix loader test to expect line numbers in load errors
|
||||
- Update ui_spec for icon module path
|
||||
- let node installer try to save with ~ version prefix to allow minor updates
|
||||
- Log error when non-msg-object is returned from a Function
|
||||
- Timeout a node that fails to close - default 15s timeout
|
||||
- Pass a 'removed' parameter to node close handler
|
||||
- Remove event passing for icons/examples from the api layer
|
||||
- Update general dependencies
|
||||
|
||||
Nodes
|
||||
|
||||
- Do not log node errors if handled by a Catch node
|
||||
- Fix wrong number of double quotes in CSV parsing
|
||||
- let csv node handle ip addresses without trying to parse
|
||||
- Update debug node to register the settings it uses
|
||||
- Handle IncomingMessage/ServerResponse object types in debug Fixes #1202
|
||||
- Toggling debug node enabled/disabled state should set state dirty Fixes #1203
|
||||
- redo delay node status messages to be interval based
|
||||
- Update delay node ui
|
||||
- Add new msg.delay option to delay node
|
||||
- stop delay node spamming web socket (when in fast rate limit mode)
|
||||
- Delay/Range node help tidy up
|
||||
- Bug fix in exec node. White spaces in arguments now works (#1285)
|
||||
- Make exec node explicitly call SIGTERM for default
|
||||
- Fix exec node error tests on Windows (#1234)
|
||||
- update messages for updated exec node
|
||||
- Make exec node spawn and exec outputs more consistent
|
||||
- Exec node for windows environment (#1200)
|
||||
- remove requirement for cmd in exec node config + new style info
|
||||
- retry exec node tests
|
||||
- let exec node take msg.kill SIG... param and pid param
|
||||
- Third output from Exec node must be consistent for success/failure conditions
|
||||
- exec node returns 0 on the third output if command ended without error. (#1160)
|
||||
- exec node can be killed on demand
|
||||
- add "split/stream" ability to file in node
|
||||
- add port label to file node and update info
|
||||
- Allow nodes to have translations not in core (#1183)
|
||||
- fix tcp node new Buffer alloc size 0
|
||||
- change pin selection table for pi gpis nodes
|
||||
- stop using sudo for Pi gpio access
|
||||
- adding frequency configuration to pwm output (#1206)
|
||||
- Fix Pi GPIO debounce
|
||||
- let Hypriot on Pi detect gpio correctly
|
||||
- More core node info help tidy up
|
||||
- Tidy up more core node help text
|
||||
- Tidy up parser node edit dialogs and help text
|
||||
- yet more core node info updates
|
||||
- more core node info updates to newer style
|
||||
- Update some core nodes info
|
||||
- First pass of new node-info style
|
||||
- MQTT new style info
|
||||
- Fix empty extra node help content issue
|
||||
- Handle HTTP In url that is missing its leading / Fixes #1218
|
||||
- Add file upload support to HTTP In node
|
||||
- HTTP Request node: add info on how to do form encoding
|
||||
- Prevent unmodified msg.headers from breaking HTTP Request flows Closed #1015
|
||||
- Add cookie handling to HTTP Request node
|
||||
- Add guard against the http-request buffer fix being reverted
|
||||
- Multipart streaming
|
||||
- Add http-request node unit tests
|
||||
- http request node add transport validity check and warn.
|
||||
- Update follow_redirects to fix http_proxy handling Fixes #1172
|
||||
- Allow statusCode/headers to be set directly within HTTP Response node
|
||||
- let inject "between time" also fire at start - Plus new info
|
||||
- remove repeat symbol from inject if repeat is 0
|
||||
- Add port labels to inject node (to show types)
|
||||
- Add buffer joiner mode to Join node
|
||||
- Let join node auto re-assemble buffers
|
||||
- let join also accumulate strings (and not fail)
|
||||
- Add Pretty print option to JSON node and
|
||||
- Fix selection of link nodes
|
||||
- Add link label value as portLabels
|
||||
- Add sentence about clearing retained topic on mqtt
|
||||
- make sure MQTT client closes if redeploy during reconnect
|
||||
- make sure MQTT client closes if redeploy during reconnect
|
||||
- slight filed size adjust for mqtt broker port field - allow 5 digits
|
||||
- Add help info for split node
|
||||
- split node - in object mode allow msg.complete on its own
|
||||
- let split of objects use key to set another property (e.g. topic)
|
||||
- adding streaming modes into split node
|
||||
- let split node reassemble based on a final packet. (as well as the first)
|
||||
- Add buffer support to split node
|
||||
- updated split/join node (split still needs work before release)
|
||||
- Added a name icon and a description label on edit subflow window.
|
||||
- Don't display port labels for subflow pseudo-port nodes
|
||||
- Added a name icon and a description label on edit subflow window.
|
||||
- tcp request - remove confusing timeout wording from info
|
||||
- Final TCP node nits - let 0 do it's thing as per every other timeout
|
||||
- fix tcp port not waiting as per info/previous behaviour
|
||||
- TCP In: Fix error in timout callback (#1249)
|
||||
- Make tcp send msg more consistent
|
||||
- Update 31-tcpin.js (#1235)
|
||||
- really close tcp node connection right away (if told to)
|
||||
- clone message before send in stay connected mode
|
||||
- Better template node help example
|
||||
- Add option to parse Template result as JSON before sending
|
||||
- nail trigger test for windows AND linux
|
||||
- give up on SIGQUIT for widows test
|
||||
- better tests for windows nodes
|
||||
- comment out 2nd exec node kill tests
|
||||
- fixes for grunt files tests on Windows
|
||||
- Add events to test helper
|
||||
- Change default value of tlsConfigDisableLocalFiles to false
|
||||
- Add the node setting tlsConfigDisableLocalFiles for tls node. (#1190)
|
||||
- UI to upload certificates and keys for TLS node
|
||||
- Update trigger help
|
||||
- let trigger node set repeated outputs
|
||||
- Move udp sock error listener to only be instantiated once.
|
||||
- Let watch node recurse into subdirectories
|
||||
- Misconfigured WebSocket nodes should not register msg handlers
|
||||
- Add websocketVerifyClient option to enable custom websocket auth Fixes #1127
|
||||
|
||||
Editor
|
||||
|
||||
- Bump ACE editor to v1.2.7
|
||||
- Add RED.utils.getNodeLabel utility function
|
||||
- Include module name in requests for node icons
|
||||
- Change debug message menu icon
|
||||
- Handle empty array/objects in debug view
|
||||
- Add per-node filter option to Debug pane
|
||||
- Ensure debug node marked changed when button pressed
|
||||
- Fix pop-out debug window for all the recent updates
|
||||
- Add debug message menu
|
||||
- Don't include msg. in debug message copied paths
|
||||
- Format Buffer numbers as hex by default
|
||||
- Remember formatting choices for dbg msg elements
|
||||
- Allow debug msg elements to be pinned
|
||||
- Only show debug tools under the debug tab
|
||||
- Fix test for valid js identifiers in debug path construction
|
||||
- Remove unused modified flag on debug messages
|
||||
- Add copy path/value buttons to debug messages
|
||||
- dont match only part of the node type (#1242)
|
||||
- Add editorTheme.logout.redirect to allow redirect on logout Closes #1213
|
||||
- Handle logging out and already logged-out editor Fixes #1288
|
||||
- Fix bug: Export Subflows (#1282)
|
||||
- destroy editor to ensure fully removed on close (function, template, comment)
|
||||
- Don't try to nls status text starting with '.' Fixes #1258
|
||||
- Add note of removed flows in diffConfig (#1253)
|
||||
- Add description to flow same as subflow
|
||||
- Allow tabs to be enabled/disabled in the editor
|
||||
- Make H3 sections in node help collapsible
|
||||
- Add JSON Expression editor
|
||||
- Expression editor - clear legacy flag for blank expressions
|
||||
- Ensure node labels are reordered properly to match outputs
|
||||
- Add 'none' placeholder for empty port label form
|
||||
- Don't mark a node changed when going from none to blank labels
|
||||
- Leave a node to nls its own port labels
|
||||
- Allow a node to override default labels
|
||||
- Add placeholder text on label inputs and clear buttons
|
||||
- Add port labels to Subflow nodes
|
||||
- Keep port label form in sync with output reordering
|
||||
- Basic node label editor
|
||||
- Port label editor starting point
|
||||
- Allow port labels be i18n identifiers
|
||||
- Add inputLabels and outputLabels to node defn + Update Change node
|
||||
- Resize port labels based on content
|
||||
- Initial port label behaviour
|
||||
- Allow a node to decide for itself if its button should be enabled or not
|
||||
- Provide feedback when enable/disable node fails
|
||||
- Add node module update api and expose in palette editor
|
||||
- Reset palette-manager tabs when settings dialog reopened
|
||||
- Move palette editor to settings panel
|
||||
- Move palette editor to userSettings dialog
|
||||
- Move view and keyboard into user settings dialog
|
||||
- Add basic user settings panel
|
||||
- Node status should be on by default
|
||||
- Make theme able to load custom javascript (#1211)
|
||||
- Allow tips to be hidden and cycled through
|
||||
- Add info tips back to the sidebar
|
||||
- Add buffer mode to typedInput
|
||||
- Add typedInput binary mode icon
|
||||
- Ensure all ace editors are destroyed in the expression editors
|
||||
- Refresh sidebar info when tab is changed
|
||||
- better spacing for library widget
|
||||
- Fix gridSize for node width calculation to avoid odd resizing
|
||||
- Redraw grid properly if gridSize changes
|
||||
- Scroll sidebar info tab to top when changing content
|
||||
- Ensure info tab sections are collapsible when set from palette
|
||||
- Only show tab info if there is an active tab
|
||||
- Only check for reordered outputs if outputMap defiend
|
||||
- Avoid circular references when stingifying node objects
|
||||
- Fix padding of config node edit dialog
|
||||
- Add force-deploy option when conflict detected
|
||||
- Hide tip box on startup if disabled
|
||||
- Track node moves separately to node config changes
|
||||
- Ensure ace editor instances are freed if edit cancelled
|
||||
- Clip overly long notification messages
|
||||
- Use queryCommandSupported not queryCommandEnabled to check for copy support
|
||||
- Add tip to tab description editor
|
||||
- Make tab info edit box resizable
|
||||
- Shrink config node appearance in info table
|
||||
- Display config nodes in Info sidebar table
|
||||
- Ensure flow info box updates after editing flow
|
||||
- Hide Node info section when displaying changelog
|
||||
- Restructure info tab
|
||||
- Provide notification when new flows deployed in the background
|
||||
- Stop some ui elements from clearing url anchor when clicked
|
||||
- clipboard export text stay highlighted even when button deselected
|
||||
- ensure export clipboard keeps text selected and formatted
|
||||
- Defer resizing tray components until they have finished building
|
||||
- Use pre-calculated values for connection path
|
||||
- Use textContent to avoid manual escaping
|
||||
- Add RED.stack as a common ui component
|
||||
- Numeric validator that accepts blank should accept undefined
|
||||
- Add visual cue as to whether the workspace is focused
|
||||
- Allow RED.validators.number to allow blank values as valid
|
||||
- Support dropping json files into the editor
|
||||
- NLS Expression/JSON editor and fix their height calculation
|
||||
- Update JSONata to 1.2.4 Closes #1275
|
||||
- Remember test expression data on a per-node basis
|
||||
- NLS jsonata test messages
|
||||
- Add JSONata expr tester and improved feedback
|
||||
- Add $context/$flow/$global functions to jsonata
|
||||
- Update jsonata
|
||||
|
||||
Other
|
||||
|
||||
- add allow es6 to .jshintrc
|
||||
- travis - don't allow node 8 fails, (and re-add 7)
|
||||
- ask istanbul for more reports as default
|
||||
- Add istanbul to Gruntfile.js (#1189)
|
||||
|
||||
|
||||
#### 0.16.2: Maintenance Release
|
||||
|
||||
- Ensure custom mustache context parent set in Template node fixes #1126
|
||||
- Display debug node name in debug panel if its known
|
||||
- Ensure auth-tokens are removed when no user is specified in settings
|
||||
- Ensure all a tags have blank target in info sidebar
|
||||
- Ensure links do not span tabs in the editor
|
||||
- Avoid creating multiple reconnect timers in websocket node
|
||||
- Fix inner reference in install fail message catalog entry Fixes #1120
|
||||
- Display buffer data properly for truncated buffers under Object property
|
||||
|
||||
#### 0.16.1: Maintenance Release
|
||||
|
||||
- Add colour swatches to debug when hex colour matched
|
||||
- Nodes with hasUsers set to false should not appear unused
|
||||
- Change hard error to verbose warning if using old node.js level
|
||||
- Don't filter debug properties starting with _ Fixes #1117
|
||||
- Node logged errors not displayed properly in debug pane Fixes #1116
|
||||
- Do not look for existing nodes when checking for wires on paste Fixes #1114
|
||||
- -v option not enabling verbose mode properly
|
||||
- Add node.js version check on startup
|
||||
|
||||
#### 0.16.0: Milestone Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Drop support for node 0.10 and 0.12
|
||||
|
||||
Nodes
|
||||
|
||||
- Add option to colourise debug console output Closes #1103
|
||||
- Add property validation to nodes using typedInput
|
||||
- Add common validator for typedInput fields Closes #1104
|
||||
- Update debug node console logging indicator icon Closes #1094
|
||||
- Let exec node (spawn) handle commands with spaces in path
|
||||
- Add symbol to debug node to indicate debugging also to console.log
|
||||
- Change file node to use node 4 syntax (drops support for 0.8)
|
||||
- add info for httprequest responseUrl property
|
||||
- Add res.responseUrl to httprequest node response
|
||||
- Add support for flow and global context in Template node (#1048)
|
||||
- Added YAML parser node (#1034)
|
||||
- node-red-node-serialport removed as a default node
|
||||
|
||||
Editor
|
||||
|
||||
- Add install/remove dialog to increase friction Closes #1109
|
||||
- Report node catalogue load errors Closes #1009
|
||||
- Properly report module remove errors in palette editor Fixes #1043
|
||||
- Update rather than hide install button after success install
|
||||
- Tweak search box styling
|
||||
- Display info tips slightly longer
|
||||
- Allow tips to be enabled/disabled via menu option
|
||||
- Info-tips update
|
||||
- Make typedInput keyboard navigable
|
||||
- update Font Awesome to 4.7.0
|
||||
- Add expression editor for jsonata
|
||||
- Overhaul keyboard handling and introduce editor actions
|
||||
- Add Japanese translation file(editor.json) (#1084)
|
||||
- Add quick-add node mode with cmd/ctrl-click
|
||||
- Add cmd/ctrl-click to quick add wires
|
||||
- Use json-stringify-safe to detect circular references in debug msgs
|
||||
- debug - format if time if correct length/range
|
||||
- Make Debug object explorable
|
||||
- Initial debug pop-out window
|
||||
- Add proper three-way diff view
|
||||
- Focus tray body when edit dialog opened
|
||||
- Hit enter to edit first node in selection
|
||||
- Add node delete button to edit dialog
|
||||
- Add notification when runtime stopped due to missing types Part of #832
|
||||
|
||||
Fixes
|
||||
|
||||
- Do not tie debug src loading to needsPermission Fixes #1111
|
||||
- Initialise nodeApp regardless of httpAdmin setting Closes #1096 #1095
|
||||
- Speed up reveal of search dialogs
|
||||
- Ensure flows exist before delegating status/error events Fixes #1069
|
||||
- Update package dependencies
|
||||
- Update MQTT to latest 2.2.1
|
||||
- Node status not being refreshed properly in the editor
|
||||
- Try to prevent auto-fill of password fields in node edit tray Fixes #1081
|
||||
- Fix whitespace in localfilesystem
|
||||
- fix bug where savesettings did not honor local settings variables (#1073)
|
||||
- Tidy up unused/duplicate editor messages Closes #922
|
||||
- Property expressions must not be blank
|
||||
- Tidy up merge commit of validatePropertyExpression
|
||||
- add port if wires array > number of ports declared.
|
||||
- Allow quoted property expressions Fixes #1101
|
||||
- Index all node properties for node search
|
||||
- Remove node 0.10 from travis config
|
||||
- update welcome message to use logger so it can be turned off/on if required (#1083)
|
||||
- Fix dynamically loading multiple node-sets from palette editor
|
||||
- Allow a node to reorder its outputs and maintain links Fixes #1031
|
||||
|
||||
#### 0.15.3: Maintenance Release
|
||||
|
||||
- Tcpgetfix: Another small check (#1070)
|
||||
- TCPGet: Ensure done() is called only once (#1068)
|
||||
- Allow $ and _ at start of property identifiers Fixes #1063
|
||||
- TCPGet: Separated the node.connected property for each instance (#1062)
|
||||
- Corrected 'overide' typo in XML node help (#1061)
|
||||
- TCPGet: Last property check (hopefully) (#1059)
|
||||
- Add additional safety checks to avoid acting on non-existent objects (#1057)
|
||||
- add --title for process name to command line options
|
||||
- add indicator for fire once on inject node
|
||||
- reimplement $(env var) replace to share common code.
|
||||
- Fix error message for missing node html file, and add test.
|
||||
- Let credentials also use $(...) substitutions from ENV
|
||||
- Rename insecureRedirect to requireHttps
|
||||
- Add setting to cause insecure redirect (#1054)
|
||||
- Palette editor fixes (#1033)
|
||||
- Close comms on stopServer in test helper (#1020)
|
||||
- Tcpgetfix (#1050)
|
||||
- TCPget: Store incoming messages alongside the client object to keep reference
|
||||
- Merge remote-tracking branch 'upstream/master' into tcpgetfix
|
||||
- TCPget can now handle concurrent sessions (#1042)
|
||||
- Better scope handling
|
||||
- Add security checks
|
||||
- small change to udp httpadmin
|
||||
- Fix comparison to "" in tcpin
|
||||
- Change scope of clients object
|
||||
- Works when connection is left open
|
||||
- First release of multi connection tcpget
|
||||
- Fix node.error() not printing when passed false (#1037)
|
||||
- fix test for CSV array input
|
||||
- different test for Pi (rather than use serial port name)
|
||||
- Fix missing 0 handling for css node with array input
|
||||
|
||||
|
||||
#### 0.15.2: Maintenance Release
|
||||
|
||||
- Revert bidi changes to nodes and hide menu option until fixed Fixes #1024
|
||||
@@ -442,7 +1260,7 @@ Fixes
|
||||
#### 0.10.10: Maintenance Release
|
||||
|
||||
- Fix permissions issue with packaged nrgpio script
|
||||
- Add better help message if deprecated node missing
|
||||
- Add better help message if deprecated node missing
|
||||
|
||||
|
||||
|
||||
@@ -454,16 +1272,16 @@ Fix packaging of bin scripts
|
||||
|
||||
#### 0.10.8: Maintenance Release
|
||||
|
||||
- Nodes moved out of core
|
||||
- still included as a dependency: twitter, serial, email, feedparser
|
||||
- Nodes moved out of core
|
||||
- still included as a dependency: twitter, serial, email, feedparser
|
||||
- no longer included: mongo, arduino, irc, redis
|
||||
- node icon defn can be a function
|
||||
- http_proxy support
|
||||
- httpNodeMiddleware setting
|
||||
- Trigger node ui refresh
|
||||
- editorTheme setting
|
||||
- Warn on deploy of unused config nodes
|
||||
- catch node prevents error loops
|
||||
- node icon defn can be a function
|
||||
- http_proxy support
|
||||
- httpNodeMiddleware setting
|
||||
- Trigger node ui refresh
|
||||
- editorTheme setting
|
||||
- Warn on deploy of unused config nodes
|
||||
- catch node prevents error loops
|
||||
|
||||
|
||||
|
||||
@@ -486,14 +1304,14 @@ Changes:
|
||||
|
||||
Changes:
|
||||
|
||||
- http request node passes on request url as msg.url
|
||||
- handle config nodes appearing out of order in flow file - don't assume they are always at the start
|
||||
- move subflow palette category to the top, to make it more obvious
|
||||
- fix labelling of Raspberry Pi pins
|
||||
- allow email node to mark mail as read
|
||||
- fix saving library content
|
||||
- add node-red and node-red-pi start scripts
|
||||
- use $HOME/.node-red for user data unless specified otherwise (or existing data is found in install dir)
|
||||
- http request node passes on request url as msg.url
|
||||
- handle config nodes appearing out of order in flow file - don't assume they are always at the start
|
||||
- move subflow palette category to the top, to make it more obvious
|
||||
- fix labelling of Raspberry Pi pins
|
||||
- allow email node to mark mail as read
|
||||
- fix saving library content
|
||||
- add node-red and node-red-pi start scripts
|
||||
- use $HOME/.node-red for user data unless specified otherwise (or existing data is found in install dir)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ We welcome contributions, but request you follow these guidelines.
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable
|
||||
behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
|
||||
behavior to the project's core team at team@nodered.org.
|
||||
|
||||
## Raising issues
|
||||
|
||||
@@ -30,29 +30,21 @@ At a minimum, please include:
|
||||
|
||||
## Feature requests
|
||||
|
||||
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
For feature requests, please raise them on the [forum](https://discourse.nodered.org).
|
||||
|
||||
## Pull-Requests
|
||||
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it may well get rejected if you haven't discussed it on
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
|
||||
the [forum](https://discourse.nodered.org) first.
|
||||
|
||||
### Contributor License Agreement
|
||||
All contributors need to sign the JS Foundation's Contributor License Agreement.
|
||||
It is an online process and quick to do. You can read the details of the agreement
|
||||
here: https://cla.js.foundation/node-red/node-red.
|
||||
|
||||
In order for us to accept pull-requests, the contributor must first complete
|
||||
a Contributor License Agreement (CLA). This clarifies the intellectual
|
||||
property license granted with any contribution. It is for your protection as a
|
||||
Contributor as well as the protection of IBM and its customers; it does not
|
||||
change your rights to use your own Contributions for any other purpose.
|
||||
If you raise a pull-request without having signed the CLA, you will be prompted
|
||||
to do so automatically.
|
||||
|
||||
You can download the CLAs here:
|
||||
|
||||
- [individual](http://nodered.org/cla/node-red-cla-individual.pdf)
|
||||
- [corporate](http://nodered.org/cla/node-red-cla-corporate.pdf)
|
||||
|
||||
If you are an IBMer, please contact us directly as the contribution process is
|
||||
slightly different.
|
||||
|
||||
### Coding standards
|
||||
|
||||
|
||||
340
Gruntfile.js
340
Gruntfile.js
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,10 @@ module.exports = function(grunt) {
|
||||
nodemonArgs.push(flowFile);
|
||||
}
|
||||
|
||||
var nonHeadless = grunt.option('non-headless');
|
||||
if (nonHeadless) {
|
||||
process.env.NODE_RED_NON_HEADLESS = 'true';
|
||||
}
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
paths: {
|
||||
@@ -38,7 +42,25 @@ module.exports = function(grunt) {
|
||||
reporter: 'spec'
|
||||
},
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
webdriver: {
|
||||
all: {
|
||||
configFile: 'test/editor/wdio.conf.js'
|
||||
}
|
||||
},
|
||||
mocha_istanbul: {
|
||||
options: {
|
||||
globals: ['expect'],
|
||||
timeout: 3000,
|
||||
ignoreLeaks: false,
|
||||
ui: 'bdd',
|
||||
reportFormats: ['lcov','html'],
|
||||
print: 'both'
|
||||
},
|
||||
all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
jshint: {
|
||||
@@ -58,16 +80,14 @@ module.exports = function(grunt) {
|
||||
all: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js',
|
||||
'nodes/core/*/*.js',
|
||||
'editor/js/**/*.js'
|
||||
'packages/**/*.js'
|
||||
],
|
||||
core: {
|
||||
files: {
|
||||
src: [
|
||||
'Gruntfile.js',
|
||||
'red.js',
|
||||
'red/**/*.js'
|
||||
'packages/**/*.js',
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -98,61 +118,81 @@ module.exports = function(grunt) {
|
||||
src: [
|
||||
// Ensure editor source files are concatenated in
|
||||
// the right order
|
||||
"editor/js/red.js",
|
||||
"editor/js/events.js",
|
||||
"editor/js/i18n.js",
|
||||
"editor/js/settings.js",
|
||||
"editor/js/user.js",
|
||||
"editor/js/comms.js",
|
||||
"editor/js/text/bidi.js",
|
||||
"editor/js/text/format.js",
|
||||
"editor/js/ui/state.js",
|
||||
"editor/js/nodes.js",
|
||||
"editor/js/history.js",
|
||||
"editor/js/validators.js",
|
||||
"editor/js/debugger.js",
|
||||
"editor/js/ui/common/editableList.js",
|
||||
"editor/js/ui/common/menu.js",
|
||||
"editor/js/ui/common/popover.js",
|
||||
"editor/js/ui/common/searchBox.js",
|
||||
"editor/js/ui/common/tabs.js",
|
||||
"editor/js/ui/common/typedInput.js",
|
||||
"editor/js/ui/utils.js",
|
||||
"editor/js/ui/deploy.js",
|
||||
"editor/js/ui/keyboard.js",
|
||||
"editor/js/ui/workspaces.js",
|
||||
"editor/js/ui/view.js",
|
||||
"editor/js/ui/sidebar.js",
|
||||
"editor/js/ui/palette.js",
|
||||
"editor/js/ui/tab-info.js",
|
||||
"editor/js/ui/tab-config.js",
|
||||
"editor/js/ui/palette-editor.js",
|
||||
"editor/js/ui/editor.js",
|
||||
"editor/js/ui/tray.js",
|
||||
"editor/js/ui/clipboard.js",
|
||||
"editor/js/ui/library.js",
|
||||
"editor/js/ui/notifications.js",
|
||||
"editor/js/ui/search.js",
|
||||
"editor/js/ui/typeSearch.js",
|
||||
"editor/js/ui/subflow.js",
|
||||
"editor/js/ui/touch/radialMenu.js"
|
||||
"packages/node_modules/@node-red/editor-client/src/js/red.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/events.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/i18n.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/settings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/user.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/comms.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/text/bidi.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/text/format.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/state.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/nodes.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/history.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tray.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/library.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/search.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js"
|
||||
],
|
||||
dest: "public/red/red.js"
|
||||
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
|
||||
},
|
||||
vendor: {
|
||||
files: {
|
||||
"public/vendor/vendor.js": [
|
||||
"editor/vendor/jquery/js/jquery-1.11.3.min.js",
|
||||
"editor/vendor/bootstrap/js/bootstrap.min.js",
|
||||
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||
"editor/vendor/marked/marked.min.js",
|
||||
"editor/vendor/d3/d3.v3.min.js",
|
||||
"editor/vendor/i18next/i18next.min.js"
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-1.11.3.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/js/bootstrap.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js"
|
||||
],
|
||||
"public/vendor/vendor.css": [
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [
|
||||
// TODO: resolve relative resource paths in
|
||||
// bootstrap/FA/jquery
|
||||
],
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/jsonata/jsonata.min.js": [
|
||||
"node_modules/jsonata/jsonata-es5.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js"
|
||||
],
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [
|
||||
"node_modules/jsonata/jsonata-es5.min.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -160,8 +200,10 @@ module.exports = function(grunt) {
|
||||
uglify: {
|
||||
build: {
|
||||
files: {
|
||||
'public/red/red.min.js': 'public/red/red.js',
|
||||
'public/red/main.min.js': 'public/red/main.js'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js': 'packages/node_modules/@node-red/editor-client/public/red/main.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/mode-jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/mode-jsonata.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/vendor/ace/snippets/jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/snippets-jsonata.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -171,45 +213,50 @@ module.exports = function(grunt) {
|
||||
outputStyle: 'compressed'
|
||||
},
|
||||
files: [{
|
||||
dest: 'public/red/style.min.css',
|
||||
src: 'editor/sass/style.scss'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css',
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss'
|
||||
},
|
||||
{
|
||||
dest: 'public/vendor/bootstrap/css/bootstrap.min.css',
|
||||
src: 'editor/vendor/bootstrap/css/bootstrap.css'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/bootstrap/css/bootstrap.min.css',
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/css/bootstrap.css'
|
||||
}]
|
||||
}
|
||||
},
|
||||
jsonlint: {
|
||||
messages: {
|
||||
src: [
|
||||
'nodes/core/locales/en-US/messages.json',
|
||||
'red/api/locales/en-US/editor.json',
|
||||
'red/runtime/locales/en-US/runtime.json'
|
||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/editor-api/lib/editor/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
||||
]
|
||||
},
|
||||
keymaps: {
|
||||
src: [
|
||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
||||
]
|
||||
}
|
||||
},
|
||||
attachCopyright: {
|
||||
js: {
|
||||
src: [
|
||||
'public/red/red.min.js',
|
||||
'public/red/main.min.js'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/red.min.js',
|
||||
'packages/node_modules/@node-red/editor-client/public/red/main.min.js'
|
||||
]
|
||||
},
|
||||
css: {
|
||||
src: [
|
||||
'public/red/style.min.css'
|
||||
'packages/node_modules/@node-red/editor-client/public/red/style.min.css'
|
||||
]
|
||||
}
|
||||
},
|
||||
clean: {
|
||||
build: {
|
||||
src: [
|
||||
"public/red",
|
||||
"public/index.html",
|
||||
"public/favicon.ico",
|
||||
"public/icons",
|
||||
"public/vendor"
|
||||
"packages/node_modules/@node-red/editor-client/public/red",
|
||||
"packages/node_modules/@node-red/editor-client/public/index.html",
|
||||
"packages/node_modules/@node-red/editor-client/public/favicon.ico",
|
||||
"packages/node_modules/@node-red/editor-client/public/icons",
|
||||
"packages/node_modules/@node-red/editor-client/public/vendor"
|
||||
]
|
||||
},
|
||||
release: {
|
||||
@@ -221,24 +268,30 @@ module.exports = function(grunt) {
|
||||
watch: {
|
||||
js: {
|
||||
files: [
|
||||
'editor/js/**/*.js'
|
||||
'packages/node_modules/@node-red/editor-client/src/js/**/*.js'
|
||||
],
|
||||
tasks: ['concat','uglify','attachCopyright:js']
|
||||
tasks: ['copy:build','concat','uglify','attachCopyright:js']
|
||||
},
|
||||
sass: {
|
||||
files: [
|
||||
'editor/sass/**/*.scss'
|
||||
'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss'
|
||||
],
|
||||
tasks: ['sass','attachCopyright:css']
|
||||
},
|
||||
json: {
|
||||
files: [
|
||||
'nodes/core/locales/en-US/messages.json',
|
||||
'red/api/locales/en-US/editor.json',
|
||||
'red/runtime/locales/en-US/runtime.json'
|
||||
'packages/node_modules/@node-red/nodes/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/editor-api/lib/editor/locales/**/*.json',
|
||||
'packages/node_modules/@node-red/runtime/locales/**/*.json'
|
||||
],
|
||||
tasks: ['jsonlint:messages']
|
||||
},
|
||||
keymaps: {
|
||||
files: [
|
||||
'packages/node_modules/@node-red/editor-client/src/js/keymap.json'
|
||||
],
|
||||
tasks: ['jsonlint:keymaps','copy:build']
|
||||
},
|
||||
misc: {
|
||||
files: [
|
||||
'CHANGELOG.md'
|
||||
@@ -250,12 +303,13 @@ module.exports = function(grunt) {
|
||||
nodemon: {
|
||||
/* uses .nodemonignore */
|
||||
dev: {
|
||||
script: 'red.js',
|
||||
script: 'packages/node_modules/node-red/red.js',
|
||||
options: {
|
||||
args: nodemonArgs,
|
||||
ext: 'js,html,json',
|
||||
watch: [
|
||||
'red','nodes'
|
||||
'packages/node_modules',
|
||||
'!packages/node_modules/@node-red/editor-client'
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -274,17 +328,21 @@ module.exports = function(grunt) {
|
||||
build: {
|
||||
files:[
|
||||
{
|
||||
src: 'editor/js/main.js',
|
||||
dest: 'public/red/main.js'
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/js/main.js',
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/images',
|
||||
src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json',
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json'
|
||||
},
|
||||
{
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/images',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/red/images/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/images/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/vendor',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/vendor',
|
||||
src: [
|
||||
'ace/**',
|
||||
//'bootstrap/css/**',
|
||||
@@ -293,46 +351,25 @@ module.exports = function(grunt) {
|
||||
'font-awesome/**'
|
||||
],
|
||||
expand: true,
|
||||
dest: 'public/vendor/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/'
|
||||
},
|
||||
{
|
||||
cwd: 'editor/icons',
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/icons',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'public/icons/'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/icons/'
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
src: ['editor/index.html','editor/favicon.ico'],
|
||||
dest: 'public/',
|
||||
src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'],
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/',
|
||||
flatten: true
|
||||
},
|
||||
{
|
||||
src: 'CHANGELOG.md',
|
||||
dest: 'public/red/about'
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/about'
|
||||
}
|
||||
]
|
||||
},
|
||||
release: {
|
||||
files: [{
|
||||
mode: true,
|
||||
expand: true,
|
||||
src: [
|
||||
'*.md',
|
||||
'LICENSE',
|
||||
'package.json',
|
||||
'settings.js',
|
||||
'red.js',
|
||||
'lib/.gitignore',
|
||||
'nodes/*.demo',
|
||||
'nodes/core/**',
|
||||
'red/**',
|
||||
'public/**',
|
||||
'editor/templates/**',
|
||||
'bin/**'
|
||||
],
|
||||
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
|
||||
}]
|
||||
}
|
||||
},
|
||||
chmod: {
|
||||
@@ -340,9 +377,9 @@ module.exports = function(grunt) {
|
||||
mode: '755'
|
||||
},
|
||||
release: {
|
||||
// Target-specific file/dir lists and/or options go here.
|
||||
src: [
|
||||
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*')
|
||||
"packages/node_modules/@node-red/nodes/core/hardware/nrgpio",
|
||||
"packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -352,8 +389,43 @@ module.exports = function(grunt) {
|
||||
archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip'
|
||||
},
|
||||
expand: true,
|
||||
cwd: '<%= paths.dist %>/',
|
||||
src: ['node-red-<%= pkg.version %>/**']
|
||||
cwd: 'packages/node_modules/',
|
||||
src: [
|
||||
'**',
|
||||
'!@node-red/editor-client/src/**'
|
||||
]
|
||||
}
|
||||
},
|
||||
jsdoc : {
|
||||
runtimeAPI: {
|
||||
src: 'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
options: {
|
||||
destination: 'docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
},
|
||||
nodeREDUtil: {
|
||||
src: 'packages/node_modules/@node-red/util/**/*.js',
|
||||
options: {
|
||||
destination: 'packages/node_modules/@node-red/util/docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
}
|
||||
},
|
||||
jsdoc2md: {
|
||||
runtimeAPI: {
|
||||
options: {
|
||||
separators: true
|
||||
},
|
||||
src: 'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
dest: 'docs/runtime-api.md'
|
||||
},
|
||||
nodeREDUtil: {
|
||||
options: {
|
||||
separators: true
|
||||
},
|
||||
src: 'packages/node_modules/@node-red/util/**/*.js',
|
||||
dest: 'packages/node_modules/@node-red/util/docs/api.md'
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -371,11 +443,15 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-chmod');
|
||||
grunt.loadNpmTasks('grunt-jsonlint');
|
||||
grunt.loadNpmTasks('grunt-mocha-istanbul');
|
||||
grunt.loadNpmTasks('grunt-webdriver');
|
||||
grunt.loadNpmTasks('grunt-jsdoc');
|
||||
grunt.loadNpmTasks('grunt-jsdoc-to-markdown');
|
||||
|
||||
grunt.registerMultiTask('attachCopyright', function() {
|
||||
var files = this.data.src;
|
||||
var copyright = "/**\n"+
|
||||
" * Copyright 2013, 2015 IBM Corp.\n"+
|
||||
" * Copyright JS Foundation and other contributors, http://js.foundation\n"+
|
||||
" *\n"+
|
||||
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
|
||||
" * you may not use this file except in compliance with the License.\n"+
|
||||
@@ -391,7 +467,7 @@ module.exports = function(grunt) {
|
||||
" **/\n";
|
||||
|
||||
if (files) {
|
||||
for (var i=0;i<files.length;i++) {
|
||||
for (var i=0; i<files.length; i++) {
|
||||
var file = files[i];
|
||||
if (!grunt.file.exists(file)) {
|
||||
grunt.log.warn('File '+ file + ' not found');
|
||||
@@ -412,6 +488,15 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('verifyPackageDependencies', function() {
|
||||
var verifyDependencies = require("./scripts/verify-package-dependencies.js");
|
||||
var failures = verifyDependencies();
|
||||
if (failures.length > 0) {
|
||||
failures.forEach(f => grunt.log.error(f));
|
||||
grunt.fail.fatal("Failed to verify package dependencies");
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('setDevEnv',
|
||||
'Sets NODE_ENV=development so non-minified assets are used',
|
||||
function () {
|
||||
@@ -420,23 +505,27 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('default',
|
||||
'Builds editor content then runs code style checks and unit tests on all components',
|
||||
['build','test-core','test-editor','test-nodes']);
|
||||
['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']);
|
||||
|
||||
grunt.registerTask('test-core',
|
||||
'Runs code style check and unit tests on core runtime code',
|
||||
['jshint:core','simplemocha:core']);
|
||||
['build','mocha_istanbul:core']);
|
||||
|
||||
grunt.registerTask('test-editor',
|
||||
'Runs code style check on editor code',
|
||||
['jshint:editor']);
|
||||
|
||||
grunt.registerTask('test-ui',
|
||||
'Builds editor content then runs unit tests on editor ui',
|
||||
['build','jshint:editor','webdriver:all']);
|
||||
|
||||
grunt.registerTask('test-nodes',
|
||||
'Runs unit tests on core nodes',
|
||||
['simplemocha:nodes']);
|
||||
['build','mocha_istanbul:nodes']);
|
||||
|
||||
grunt.registerTask('build',
|
||||
'Builds editor content',
|
||||
['clean:build','concat:build','concat:vendor','copy:build','uglify:build','sass:build','jsonlint:messages','attachCopyright']);
|
||||
['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']);
|
||||
|
||||
grunt.registerTask('dev',
|
||||
'Developer mode: run node-red, watch for source changes and build/restart',
|
||||
@@ -444,6 +533,13 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('release',
|
||||
'Create distribution zip file',
|
||||
['build','clean:release','copy:release','chmod:release','compress:release']);
|
||||
['build','verifyPackageDependencies','clean:release','chmod:release','compress:release']);
|
||||
|
||||
grunt.registerTask('coverage',
|
||||
'Run Istanbul code test coverage task',
|
||||
['build','mocha_istanbul:all']);
|
||||
|
||||
grunt.registerTask('docs',
|
||||
'Generates API documentation',
|
||||
['jsdoc','jsdoc2md']);
|
||||
};
|
||||
|
||||
1
LICENSE
1
LICENSE
@@ -1,3 +1,4 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
|
||||
18
README.md
18
README.md
@@ -14,7 +14,7 @@ A visual tool for wiring the Internet of Things.
|
||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
started.
|
||||
|
||||
1. `sudo npm install -g node-red`
|
||||
1. `sudo npm install -g --unsafe-perm node-red`
|
||||
2. `node-red`
|
||||
3. Open <http://localhost:1880>
|
||||
|
||||
@@ -22,8 +22,7 @@ started.
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the
|
||||
[mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
## Developers
|
||||
|
||||
@@ -45,9 +44,6 @@ If you want to run the latest code from git, here's how to get started:
|
||||
4. Run
|
||||
|
||||
npm start
|
||||
or
|
||||
|
||||
node red.js
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -56,17 +52,19 @@ Before raising a pull-request, please read our
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable
|
||||
behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
|
||||
behavior to any of the project's core team at team@nodered.org.
|
||||
|
||||
## Authors
|
||||
|
||||
Node-RED is a creation of [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
|
||||
Node-RED is a project of the [JS Foundation](http://js.foundation).
|
||||
|
||||
It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
|
||||
|
||||
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
|
||||
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
|
||||
|
||||
For more open-source projects from IBM, head over [here](http://ibm.github.io).
|
||||
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Copyright 2013, 2016 IBM Corp. under [the Apache 2.0 license](LICENSE).
|
||||
Copyright JS Foundation and other contributors, http://js.foundation under [the Apache 2.0 license](LICENSE).
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
RED.debugger = (function() {
|
||||
|
||||
|
||||
})();
|
||||
@@ -1,306 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.history = (function() {
|
||||
var undo_history = [];
|
||||
|
||||
return {
|
||||
//TODO: this function is a placeholder until there is a 'save' event that can be listened to
|
||||
markAllDirty: function() {
|
||||
for (var i=0;i<undo_history.length;i++) {
|
||||
undo_history[i].dirty = true;
|
||||
}
|
||||
},
|
||||
list: function() {
|
||||
return undo_history
|
||||
},
|
||||
depth: function() {
|
||||
return undo_history.length;
|
||||
},
|
||||
push: function(ev) {
|
||||
undo_history.push(ev);
|
||||
},
|
||||
pop: function() {
|
||||
var ev = undo_history.pop();
|
||||
var i;
|
||||
var node;
|
||||
var subflow;
|
||||
var modifiedTabs = {};
|
||||
if (ev) {
|
||||
if (ev.t == 'add') {
|
||||
if (ev.nodes) {
|
||||
for (i=0;i<ev.nodes.length;i++) {
|
||||
node = RED.nodes.node(ev.nodes[i]);
|
||||
if (node.z) {
|
||||
modifiedTabs[node.z] = true;
|
||||
}
|
||||
RED.nodes.remove(ev.nodes[i]);
|
||||
}
|
||||
}
|
||||
if (ev.links) {
|
||||
for (i=0;i<ev.links.length;i++) {
|
||||
RED.nodes.removeLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
if (ev.workspaces) {
|
||||
for (i=0;i<ev.workspaces.length;i++) {
|
||||
RED.nodes.removeWorkspace(ev.workspaces[i].id);
|
||||
RED.workspaces.remove(ev.workspaces[i]);
|
||||
}
|
||||
}
|
||||
if (ev.subflows) {
|
||||
for (i=0;i<ev.subflows.length;i++) {
|
||||
RED.nodes.removeSubflow(ev.subflows[i]);
|
||||
RED.workspaces.remove(ev.subflows[i]);
|
||||
}
|
||||
}
|
||||
if (ev.subflow) {
|
||||
if (ev.subflow.instances) {
|
||||
ev.subflow.instances.forEach(function(n) {
|
||||
var node = RED.nodes.node(n.id);
|
||||
if (node) {
|
||||
node.changed = n.changed;
|
||||
node.dirty = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (ev.subflow.hasOwnProperty('changed')) {
|
||||
subflow = RED.nodes.subflow(ev.subflow.id);
|
||||
if (subflow) {
|
||||
subflow.changed = ev.subflow.changed;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ev.removedLinks) {
|
||||
for (i=0;i<ev.removedLinks.length;i++) {
|
||||
RED.nodes.addLink(ev.removedLinks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ev.t == "delete") {
|
||||
if (ev.workspaces) {
|
||||
for (i=0;i<ev.workspaces.length;i++) {
|
||||
RED.nodes.addWorkspace(ev.workspaces[i]);
|
||||
RED.workspaces.add(ev.workspaces[i]);
|
||||
}
|
||||
}
|
||||
if (ev.subflow && ev.subflow.subflow) {
|
||||
RED.nodes.addSubflow(ev.subflow.subflow);
|
||||
}
|
||||
if (ev.subflowInputs && ev.subflowInputs.length > 0) {
|
||||
subflow = RED.nodes.subflow(ev.subflowInputs[0].z);
|
||||
subflow.in.push(ev.subflowInputs[0]);
|
||||
subflow.in[0].dirty = true;
|
||||
}
|
||||
if (ev.subflowOutputs && ev.subflowOutputs.length > 0) {
|
||||
subflow = RED.nodes.subflow(ev.subflowOutputs[0].z);
|
||||
ev.subflowOutputs.sort(function(a,b) { return a.i-b.i});
|
||||
for (i=0;i<ev.subflowOutputs.length;i++) {
|
||||
var output = ev.subflowOutputs[i];
|
||||
subflow.out.splice(output.i,0,output);
|
||||
for (var j=output.i+1;j<subflow.out.length;j++) {
|
||||
subflow.out[j].i++;
|
||||
subflow.out[j].dirty = true;
|
||||
}
|
||||
RED.nodes.eachLink(function(l) {
|
||||
if (l.source.type == "subflow:"+subflow.id) {
|
||||
if (l.sourcePort >= output.i) {
|
||||
l.sourcePort++;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (ev.subflow && ev.subflow.hasOwnProperty('instances')) {
|
||||
ev.subflow.instances.forEach(function(n) {
|
||||
var node = RED.nodes.node(n.id);
|
||||
if (node) {
|
||||
node.changed = n.changed;
|
||||
node.dirty = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (subflow) {
|
||||
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
|
||||
n.inputs = subflow.in.length;
|
||||
n.outputs = subflow.out.length;
|
||||
while (n.outputs > n.ports.length) {
|
||||
n.ports.push(n.ports.length);
|
||||
}
|
||||
n.resize = true;
|
||||
n.dirty = true;
|
||||
});
|
||||
}
|
||||
if (ev.nodes) {
|
||||
for (i=0;i<ev.nodes.length;i++) {
|
||||
RED.nodes.add(ev.nodes[i]);
|
||||
modifiedTabs[ev.nodes[i].z] = true;
|
||||
}
|
||||
}
|
||||
if (ev.links) {
|
||||
for (i=0;i<ev.links.length;i++) {
|
||||
RED.nodes.addLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
if (ev.changes) {
|
||||
for (i in ev.changes) {
|
||||
if (ev.changes.hasOwnProperty(i)) {
|
||||
node = RED.nodes.node(i);
|
||||
if (node) {
|
||||
for (var d in ev.changes[i]) {
|
||||
if (ev.changes[i].hasOwnProperty(d)) {
|
||||
node[d] = ev.changes[i][d];
|
||||
}
|
||||
}
|
||||
node.dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if (ev.t == "move") {
|
||||
for (i=0;i<ev.nodes.length;i++) {
|
||||
var n = ev.nodes[i];
|
||||
n.n.x = n.ox;
|
||||
n.n.y = n.oy;
|
||||
n.n.dirty = true;
|
||||
n.n.changed = n.changed;
|
||||
}
|
||||
// A move could have caused a link splice
|
||||
if (ev.links) {
|
||||
for (i=0;i<ev.links.length;i++) {
|
||||
RED.nodes.removeLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
if (ev.removedLinks) {
|
||||
for (i=0;i<ev.removedLinks.length;i++) {
|
||||
RED.nodes.addLink(ev.removedLinks[i]);
|
||||
}
|
||||
}
|
||||
} else if (ev.t == "edit") {
|
||||
for (i in ev.changes) {
|
||||
if (ev.changes.hasOwnProperty(i)) {
|
||||
if (ev.node._def.defaults[i].type) {
|
||||
// This is a config node property
|
||||
var currentConfigNode = RED.nodes.node(ev.node[i]);
|
||||
if (currentConfigNode) {
|
||||
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
|
||||
}
|
||||
var newConfigNode = RED.nodes.node(ev.changes[i]);
|
||||
if (newConfigNode) {
|
||||
newConfigNode.users.push(ev.node);
|
||||
}
|
||||
}
|
||||
ev.node[i] = ev.changes[i];
|
||||
}
|
||||
}
|
||||
if (ev.subflow) {
|
||||
if (ev.subflow.hasOwnProperty('inputCount')) {
|
||||
if (ev.node.in.length > ev.subflow.inputCount) {
|
||||
ev.node.in.splice(ev.subflow.inputCount);
|
||||
} else if (ev.subflow.inputs.length > 0) {
|
||||
ev.node.in = ev.node.in.concat(ev.subflow.inputs);
|
||||
}
|
||||
}
|
||||
if (ev.subflow.hasOwnProperty('outputCount')) {
|
||||
if (ev.node.out.length > ev.subflow.outputCount) {
|
||||
ev.node.out.splice(ev.subflow.outputCount);
|
||||
} else if (ev.subflow.outputs.length > 0) {
|
||||
ev.node.out = ev.node.out.concat(ev.subflow.outputs);
|
||||
}
|
||||
}
|
||||
if (ev.subflow.hasOwnProperty('instances')) {
|
||||
ev.subflow.instances.forEach(function(n) {
|
||||
var node = RED.nodes.node(n.id);
|
||||
if (node) {
|
||||
node.changed = n.changed;
|
||||
node.dirty = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
||||
n.inputs = ev.node.in.length;
|
||||
n.outputs = ev.node.out.length;
|
||||
RED.editor.updateNodeProperties(n);
|
||||
});
|
||||
} else {
|
||||
var outputMap;
|
||||
if (ev.outputMap) {
|
||||
outputMap = {};
|
||||
for (var port in ev.outputMap) {
|
||||
if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== -1) {
|
||||
outputMap[ev.outputMap[port]] = port;
|
||||
}
|
||||
}
|
||||
}
|
||||
RED.editor.updateNodeProperties(ev.node,outputMap);
|
||||
RED.editor.validateNode(ev.node);
|
||||
}
|
||||
if (ev.links) {
|
||||
for (i=0;i<ev.links.length;i++) {
|
||||
RED.nodes.addLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
ev.node.dirty = true;
|
||||
ev.node.changed = ev.changed;
|
||||
} else if (ev.t == "createSubflow") {
|
||||
if (ev.nodes) {
|
||||
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
|
||||
n.z = ev.activeWorkspace;
|
||||
n.dirty = true;
|
||||
});
|
||||
for (i=0;i<ev.nodes.length;i++) {
|
||||
RED.nodes.remove(ev.nodes[i]);
|
||||
}
|
||||
}
|
||||
if (ev.links) {
|
||||
for (i=0;i<ev.links.length;i++) {
|
||||
RED.nodes.removeLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.removeSubflow(ev.subflow.subflow);
|
||||
RED.workspaces.remove(ev.subflow.subflow);
|
||||
|
||||
if (ev.removedLinks) {
|
||||
for (i=0;i<ev.removedLinks.length;i++) {
|
||||
RED.nodes.addLink(ev.removedLinks[i]);
|
||||
}
|
||||
}
|
||||
} else if (ev.t == "reorder") {
|
||||
if (ev.order) {
|
||||
RED.workspaces.order(ev.order);
|
||||
}
|
||||
}
|
||||
Object.keys(modifiedTabs).forEach(function(id) {
|
||||
var subflow = RED.nodes.subflow(id);
|
||||
if (subflow) {
|
||||
RED.editor.validateNode(subflow);
|
||||
}
|
||||
});
|
||||
|
||||
RED.nodes.dirty(ev.dirty);
|
||||
RED.view.redraw(true);
|
||||
RED.palette.refresh();
|
||||
RED.workspaces.refresh();
|
||||
RED.sidebar.config.refresh();
|
||||
}
|
||||
},
|
||||
peek: function() {
|
||||
return undo_history[undo_history.length-1];
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
RED.i18n = (function() {
|
||||
|
||||
return {
|
||||
init: function(done) {
|
||||
i18n.init({
|
||||
resGetPath: 'locales/__ns__',
|
||||
dynamicLoad: false,
|
||||
load:'current',
|
||||
ns: {
|
||||
namespaces: ["editor","node-red"],
|
||||
defaultNs: "editor"
|
||||
},
|
||||
fallbackLng: ['en-US'],
|
||||
useCookie: false
|
||||
},function() {
|
||||
done();
|
||||
});
|
||||
RED["_"] = function() {
|
||||
return i18n.t.apply(null,arguments);
|
||||
}
|
||||
|
||||
},
|
||||
loadCatalog: function(namespace,done) {
|
||||
i18n.loadNamespace(namespace,done);
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -1,264 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
(function() {
|
||||
|
||||
|
||||
function loadNodeList() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"application/json"
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
RED.nodes.setNodeList(data);
|
||||
|
||||
var nsCount = 0;
|
||||
for (var i=0;i<data.length;i++) {
|
||||
var ns = data[i];
|
||||
if (ns.module != "node-red") {
|
||||
nsCount++;
|
||||
RED.i18n.loadCatalog(ns.id, function() {
|
||||
nsCount--;
|
||||
if (nsCount === 0) {
|
||||
loadNodes();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (nsCount === 0) {
|
||||
loadNodes();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadNodes() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html"
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
$("body").append(data);
|
||||
$("body").i18n();
|
||||
$("#palette > .palette-spinner").hide();
|
||||
$(".palette-scroll").removeClass("hide");
|
||||
$("#palette-search").removeClass("hide");
|
||||
loadFlows();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadFlows() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"application/json",
|
||||
},
|
||||
cache: false,
|
||||
url: 'flows',
|
||||
success: function(nodes) {
|
||||
var currentHash = window.location.hash;
|
||||
RED.nodes.version(nodes.rev);
|
||||
RED.nodes.import(nodes.flows);
|
||||
RED.nodes.dirty(false);
|
||||
RED.view.redraw(true);
|
||||
if (/^#flow\/.+$/.test(currentHash)) {
|
||||
RED.workspaces.show(currentHash.substring(6));
|
||||
}
|
||||
RED.comms.subscribe("status/#",function(topic,msg) {
|
||||
var parts = topic.split("/");
|
||||
var node = RED.nodes.node(parts[1]);
|
||||
if (node) {
|
||||
if (msg.hasOwnProperty("text")) {
|
||||
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
|
||||
}
|
||||
node.status = msg;
|
||||
if (statusEnabled) {
|
||||
node.dirty = true;
|
||||
RED.view.redraw();
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.comms.subscribe("node/#",function(topic,msg) {
|
||||
var i,m;
|
||||
var typeList;
|
||||
var info;
|
||||
|
||||
if (topic == "node/added") {
|
||||
var addedTypes = [];
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadCatalog(id, function() {
|
||||
$.get('nodes/'+id, function(data) {
|
||||
$("body").append(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||
}
|
||||
} else if (topic == "node/removed") {
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
info = RED.nodes.removeNodeSet(m.id);
|
||||
if (info.added) {
|
||||
typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success");
|
||||
}
|
||||
}
|
||||
} else if (topic == "node/enabled") {
|
||||
if (msg.types) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
$.get('nodes/'+msg.id, function(data) {
|
||||
$("body").append(data);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (topic == "node/disabled") {
|
||||
if (msg.types) {
|
||||
RED.nodes.disableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success");
|
||||
}
|
||||
}
|
||||
// Refresh flow library to ensure any examples are updated
|
||||
RED.library.loadFlowLibrary();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showAbout() {
|
||||
$.get('red/about', function(data) {
|
||||
var aboutHeader = '<div style="text-align:center;">'+
|
||||
'<img width="50px" src="red/images/node-red-icon.svg" />'+
|
||||
'</div>';
|
||||
|
||||
RED.sidebar.info.set(aboutHeader+marked(data));
|
||||
RED.sidebar.info.show();
|
||||
});
|
||||
}
|
||||
|
||||
var statusEnabled = false;
|
||||
function toggleStatus(state) {
|
||||
statusEnabled = state;
|
||||
RED.view.status(statusEnabled);
|
||||
}
|
||||
|
||||
function loadEditor() {
|
||||
|
||||
var menuOptions = [];
|
||||
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
|
||||
{id:"menu-item-view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:RED.view.toggleShowGrid},
|
||||
{id:"menu-item-view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:RED.view.toggleSnapGrid},
|
||||
{id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:toggleStatus, selected: true},
|
||||
null,
|
||||
// {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[
|
||||
// {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}},
|
||||
// {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}},
|
||||
// {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}},
|
||||
// {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}}
|
||||
// ]},
|
||||
// null,
|
||||
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true}
|
||||
]});
|
||||
menuOptions.push(null);
|
||||
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[
|
||||
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:RED.clipboard.import},
|
||||
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
|
||||
]});
|
||||
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
|
||||
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:RED.clipboard.export},
|
||||
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:RED.library.export}
|
||||
]});
|
||||
menuOptions.push(null);
|
||||
menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:RED.search.show});
|
||||
menuOptions.push(null);
|
||||
menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:function() {}});
|
||||
menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
|
||||
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:RED.workspaces.add},
|
||||
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:RED.workspaces.edit},
|
||||
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:RED.workspaces.remove}
|
||||
]});
|
||||
menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
|
||||
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:RED.subflow.createSubflow},
|
||||
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:RED.subflow.convertToSubflow},
|
||||
]});
|
||||
menuOptions.push(null);
|
||||
if (RED.settings.theme('palette.editable') !== false) {
|
||||
RED.palette.editor.init();
|
||||
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:RED.palette.editor.show});
|
||||
menuOptions.push(null);
|
||||
}
|
||||
|
||||
menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:RED.keyboard.showHelp});
|
||||
menuOptions.push({id:"menu-item-help",
|
||||
label: RED.settings.theme("menu.menu-item-help.label","Node-RED website"),
|
||||
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
||||
});
|
||||
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: showAbout });
|
||||
|
||||
RED.menu.init({id:"btn-sidemenu",options: menuOptions});
|
||||
|
||||
RED.user.init();
|
||||
|
||||
RED.library.init();
|
||||
RED.palette.init();
|
||||
RED.sidebar.init();
|
||||
RED.subflow.init();
|
||||
RED.workspaces.init();
|
||||
RED.clipboard.init();
|
||||
RED.search.init();
|
||||
RED.view.init();
|
||||
RED.editor.init();
|
||||
|
||||
RED.deploy.init(RED.settings.theme("deployButton",null));
|
||||
|
||||
RED.keyboard.add("workspace", /* ? */ 191,{shift:true},function() {RED.keyboard.showHelp();d3.event.preventDefault();});
|
||||
RED.comms.connect();
|
||||
|
||||
$("#main-container").show();
|
||||
$(".header-toolbar").show();
|
||||
|
||||
loadNodeList();
|
||||
}
|
||||
|
||||
$(function() {
|
||||
|
||||
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
|
||||
document.title = document.title+" : "+window.location.hostname;
|
||||
}
|
||||
|
||||
ace.require("ace/ext/language_tools");
|
||||
|
||||
RED.i18n.init(function() {
|
||||
RED.settings.init(loadEditor);
|
||||
})
|
||||
});
|
||||
})();
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
RED.popover = (function() {
|
||||
|
||||
|
||||
function createPopover(options) {
|
||||
var target = options.target;
|
||||
|
||||
var content = options.content;
|
||||
var delay = options.delay;
|
||||
var timer = null;
|
||||
var active;
|
||||
var div;
|
||||
|
||||
var openPopup = function() {
|
||||
if (active) {
|
||||
div = $('<div class="red-ui-popover"></div>').html(content).appendTo("body");
|
||||
var targetPos = target.offset();
|
||||
var targetWidth = target.width();
|
||||
var targetHeight = target.height();
|
||||
|
||||
var divHeight = div.height();
|
||||
div.css({top: targetPos.top+targetHeight/2-divHeight/2-10,left:targetPos.left+targetWidth+17});
|
||||
|
||||
div.fadeIn("fast");
|
||||
}
|
||||
}
|
||||
var closePopup = function() {
|
||||
if (!active) {
|
||||
if (div) {
|
||||
div.fadeOut("fast",function() {
|
||||
$(this).remove();
|
||||
});
|
||||
div = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target.on('mouseenter',function(e) {
|
||||
clearTimeout(timer);
|
||||
active = true;
|
||||
timer = setTimeout(openPopup,delay.show);
|
||||
});
|
||||
target.on('mouseleave', function(e) {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
active = false;
|
||||
setTimeout(closePopup,delay.hide);
|
||||
});
|
||||
var res = {
|
||||
setContent: function(_content) {
|
||||
content = _content;
|
||||
}
|
||||
}
|
||||
target.data('popover',res);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
create: createPopover
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -1,472 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
(function($) {
|
||||
function validateExpression(str) {
|
||||
var length = str.length;
|
||||
var start = 0;
|
||||
var inString = false;
|
||||
var inBox = false;
|
||||
var quoteChar;
|
||||
var v;
|
||||
for (var i=0;i<length;i++) {
|
||||
var c = str[i];
|
||||
if (!inString) {
|
||||
if (c === "'" || c === '"') {
|
||||
if (!inBox) {
|
||||
return false;
|
||||
}
|
||||
inString = true;
|
||||
quoteChar = c;
|
||||
start = i+1;
|
||||
} else if (c === '.') {
|
||||
if (i===0 || i===length-1) {
|
||||
return false;
|
||||
}
|
||||
// Next char is a-z
|
||||
if (!/[a-z0-9]/i.test(str[i+1])) {
|
||||
return false;
|
||||
}
|
||||
start = i+1;
|
||||
} else if (c === '[') {
|
||||
if (i === 0) {
|
||||
return false;
|
||||
}
|
||||
if (i===length-1) {
|
||||
return false;
|
||||
}
|
||||
// Next char is either a quote or a number
|
||||
if (!/["'\d]/.test(str[i+1])) {
|
||||
return false;
|
||||
}
|
||||
start = i+1;
|
||||
inBox = true;
|
||||
} else if (c === ']') {
|
||||
if (!inBox) {
|
||||
return false;
|
||||
}
|
||||
if (start != i) {
|
||||
v = str.substring(start,i);
|
||||
if (!/^\d+$/.test(v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
start = i+1;
|
||||
inBox = false;
|
||||
} else if (c === ' ') {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (c === quoteChar) {
|
||||
// Next char must be a ]
|
||||
if (!/\]/.test(str[i+1])) {
|
||||
return false;
|
||||
}
|
||||
start = i+1;
|
||||
inString = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (inBox || inString) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
var allOptions = {
|
||||
msg: {value:"msg",label:"msg.",validate:validateExpression},
|
||||
flow: {value:"flow",label:"flow.",validate:validateExpression},
|
||||
global: {value:"global",label:"global.",validate:validateExpression},
|
||||
str: {value:"str",label:"string",icon:"red/images/typedInput/az.png"},
|
||||
num: {value:"num",label:"number",icon:"red/images/typedInput/09.png",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/},
|
||||
bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.png",options:["true","false"]},
|
||||
json: {value:"json",label:"JSON",icon:"red/images/typedInput/json.png", validate: function(v) { try{JSON.parse(v);return true;}catch(e){return false;}}},
|
||||
re: {value:"re",label:"regular expression",icon:"red/images/typedInput/re.png"},
|
||||
date: {value:"date",label:"timestamp",hasValue:false}
|
||||
};
|
||||
var nlsd = false;
|
||||
|
||||
$.widget( "nodered.typedInput", {
|
||||
_create: function() {
|
||||
if (!nlsd && RED && RED._) {
|
||||
for (var i in allOptions) {
|
||||
if (allOptions.hasOwnProperty(i)) {
|
||||
allOptions[i].label = RED._("typedInput.type."+i,{defaultValue:allOptions[i].label});
|
||||
}
|
||||
}
|
||||
}
|
||||
nlsd = true;
|
||||
var that = this;
|
||||
|
||||
this.disarmClick = false;
|
||||
this.element.addClass('red-ui-typedInput');
|
||||
this.uiWidth = this.element.outerWidth();
|
||||
this.elementDiv = this.element.wrap("<div>").parent().addClass('red-ui-typedInput-input');
|
||||
this.uiSelect = this.elementDiv.wrap( "<div>" ).parent();
|
||||
var attrStyle = this.element.attr('style');
|
||||
var m;
|
||||
if ((m = /width\s*:\s*(\d+(%|px))/i.exec(attrStyle)) !== null) {
|
||||
this.element.css('width','100%');
|
||||
this.uiSelect.width(m[1]);
|
||||
this.uiWidth = null;
|
||||
} else {
|
||||
this.uiSelect.width(this.uiWidth);
|
||||
}
|
||||
["Right","Left"].forEach(function(d) {
|
||||
var m = that.element.css("margin"+d);
|
||||
that.uiSelect.css("margin"+d,m);
|
||||
that.element.css("margin"+d,0);
|
||||
});
|
||||
this.uiSelect.addClass("red-ui-typedInput-container");
|
||||
|
||||
this.options.types = this.options.types||Object.keys(allOptions);
|
||||
|
||||
this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect);
|
||||
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
|
||||
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
|
||||
|
||||
this.types(this.options.types);
|
||||
|
||||
if (this.options.typeField) {
|
||||
this.typeField = $(this.options.typeField).hide();
|
||||
var t = this.typeField.val();
|
||||
if (t && this.typeMap[t]) {
|
||||
this.options.default = t;
|
||||
}
|
||||
} else {
|
||||
this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect);
|
||||
}
|
||||
|
||||
this.element.on('focus', function() {
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
});
|
||||
this.element.on('blur', function() {
|
||||
that.uiSelect.removeClass('red-ui-typedInput-focus');
|
||||
});
|
||||
this.element.on('change', function() {
|
||||
that.validate();
|
||||
})
|
||||
this.selectTrigger.click(function(event) {
|
||||
event.preventDefault();
|
||||
that._showTypeMenu();
|
||||
});
|
||||
this.selectTrigger.on('keydown',function(evt) {
|
||||
if (evt.keyCode === 40) {
|
||||
// Down
|
||||
that._showTypeMenu();
|
||||
}
|
||||
}).on('focus', function() {
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
})
|
||||
|
||||
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
|
||||
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect);
|
||||
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
|
||||
this.optionSelectTrigger.click(function(event) {
|
||||
event.preventDefault();
|
||||
that._showOptionSelectMenu();
|
||||
}).on('keydown', function(evt) {
|
||||
if (evt.keyCode === 40) {
|
||||
// Down
|
||||
that._showOptionSelectMenu();
|
||||
}
|
||||
}).on('blur', function() {
|
||||
that.uiSelect.removeClass('red-ui-typedInput-focus');
|
||||
}).on('focus', function() {
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
this.type(this.options.default||this.typeList[0].value);
|
||||
},
|
||||
_showTypeMenu: function() {
|
||||
if (this.typeList.length > 1) {
|
||||
this._showMenu(this.menu,this.selectTrigger);
|
||||
this.menu.find("[value='"+this.propertyType+"']").focus();
|
||||
} else {
|
||||
this.element.focus();
|
||||
}
|
||||
},
|
||||
_showOptionSelectMenu: function() {
|
||||
if (this.optionMenu) {
|
||||
this.optionMenu.css({
|
||||
minWidth:this.optionSelectLabel.width()
|
||||
});
|
||||
|
||||
this._showMenu(this.optionMenu,this.optionSelectLabel);
|
||||
var selectedOption = this.optionMenu.find("[value='"+this.value()+"']");
|
||||
if (selectedOption.length === 0) {
|
||||
selectedOption = this.optionMenu.children(":first");
|
||||
}
|
||||
selectedOption.focus();
|
||||
|
||||
}
|
||||
},
|
||||
_hideMenu: function(menu) {
|
||||
$(document).off("mousedown.close-property-select");
|
||||
menu.hide();
|
||||
if (this.elementDiv.is(":visible")) {
|
||||
this.element.focus();
|
||||
} else if (this.optionSelectTrigger.is(":visible")){
|
||||
this.optionSelectTrigger.focus();
|
||||
} else {
|
||||
this.selectTrigger.focus();
|
||||
}
|
||||
},
|
||||
_createMenu: function(opts,callback) {
|
||||
var that = this;
|
||||
var menu = $("<div>").addClass("red-ui-typedInput-options");
|
||||
opts.forEach(function(opt) {
|
||||
if (typeof opt === 'string') {
|
||||
opt = {value:opt,label:opt};
|
||||
}
|
||||
var op = $('<a href="#"></a>').attr("value",opt.value).appendTo(menu);
|
||||
if (opt.label) {
|
||||
op.text(opt.label);
|
||||
}
|
||||
if (opt.icon) {
|
||||
$('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op);
|
||||
} else {
|
||||
op.css({paddingLeft: "18px"});
|
||||
}
|
||||
|
||||
op.click(function(event) {
|
||||
event.preventDefault();
|
||||
callback(opt.value);
|
||||
that._hideMenu(menu);
|
||||
});
|
||||
});
|
||||
menu.css({
|
||||
display: "none",
|
||||
});
|
||||
menu.appendTo(document.body);
|
||||
|
||||
menu.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 40) {
|
||||
// DOWN
|
||||
$(this).children(":focus").next().focus();
|
||||
} else if (evt.keyCode === 38) {
|
||||
// UP
|
||||
$(this).children(":focus").prev().focus();
|
||||
} else if (evt.keyCode === 27) {
|
||||
that._hideMenu(menu);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
return menu;
|
||||
|
||||
},
|
||||
_showMenu: function(menu,relativeTo) {
|
||||
if (this.disarmClick) {
|
||||
this.disarmClick = false;
|
||||
return
|
||||
}
|
||||
var that = this;
|
||||
var pos = relativeTo.offset();
|
||||
var height = relativeTo.height();
|
||||
var menuHeight = menu.height();
|
||||
var top = (height+pos.top-3);
|
||||
if (top+menuHeight > $(window).height()) {
|
||||
top -= (top+menuHeight)-$(window).height()+5;
|
||||
}
|
||||
menu.css({
|
||||
top: top+"px",
|
||||
left: (2+pos.left)+"px",
|
||||
});
|
||||
menu.slideDown(100);
|
||||
this._delay(function() {
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
$(document).on("mousedown.close-property-select", function(event) {
|
||||
if(!$(event.target).closest(menu).length) {
|
||||
that._hideMenu(menu);
|
||||
}
|
||||
if ($(event.target).closest(relativeTo).length) {
|
||||
that.disarmClick = true;
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
_getLabelWidth: function(label) {
|
||||
var labelWidth = label.outerWidth();
|
||||
if (labelWidth === 0) {
|
||||
var container = $('<div class="red-ui-typedInput-container"></div>').css({
|
||||
position:"absolute",
|
||||
top:0,
|
||||
left:-1000
|
||||
}).appendTo(document.body);
|
||||
var newTrigger = label.clone().appendTo(container);
|
||||
labelWidth = newTrigger.outerWidth();
|
||||
container.remove();
|
||||
}
|
||||
return labelWidth;
|
||||
},
|
||||
_resize: function() {
|
||||
if (this.uiWidth !== null) {
|
||||
this.uiSelect.width(this.uiWidth);
|
||||
}
|
||||
if (this.typeMap[this.propertyType] && this.typeMap[this.propertyType].hasValue === false) {
|
||||
this.selectTrigger.css('width',"100%");
|
||||
} else {
|
||||
this.selectTrigger.width('auto');
|
||||
var labelWidth = this._getLabelWidth(this.selectTrigger);
|
||||
this.elementDiv.css('left',labelWidth+"px");
|
||||
if (this.optionSelectTrigger) {
|
||||
this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'});
|
||||
}
|
||||
}
|
||||
},
|
||||
_destroy: function() {
|
||||
this.menu.remove();
|
||||
},
|
||||
types: function(types) {
|
||||
var that = this;
|
||||
var currentType = this.type();
|
||||
this.typeMap = {};
|
||||
this.typeList = types.map(function(opt) {
|
||||
var result;
|
||||
if (typeof opt === 'string') {
|
||||
result = allOptions[opt];
|
||||
} else {
|
||||
result = opt;
|
||||
}
|
||||
that.typeMap[result.value] = result;
|
||||
return result;
|
||||
});
|
||||
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
|
||||
if (this.menu) {
|
||||
this.menu.remove();
|
||||
}
|
||||
this.menu = this._createMenu(this.typeList, function(v) { that.type(v) });
|
||||
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
|
||||
this.type(this.typeList[0].value);
|
||||
}
|
||||
},
|
||||
width: function(desiredWidth) {
|
||||
this.uiWidth = desiredWidth;
|
||||
this._resize();
|
||||
},
|
||||
value: function(value) {
|
||||
if (!arguments.length) {
|
||||
return this.element.val();
|
||||
} else {
|
||||
if (this.typeMap[this.propertyType].options) {
|
||||
if (this.typeMap[this.propertyType].options.indexOf(value) === -1) {
|
||||
value = "";
|
||||
}
|
||||
this.optionSelectLabel.text(value);
|
||||
}
|
||||
this.element.val(value);
|
||||
this.element.trigger('change',this.type(),value);
|
||||
}
|
||||
},
|
||||
type: function(type) {
|
||||
if (!arguments.length) {
|
||||
return this.propertyType;
|
||||
} else {
|
||||
var that = this;
|
||||
var opt = this.typeMap[type];
|
||||
if (opt && this.propertyType !== type) {
|
||||
this.propertyType = type;
|
||||
this.typeField.val(type);
|
||||
this.selectLabel.empty();
|
||||
var image;
|
||||
if (opt.icon) {
|
||||
image = new Image();
|
||||
image.name = opt.icon;
|
||||
image.src = opt.icon;
|
||||
$('<img>',{src:opt.icon,style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
|
||||
} else {
|
||||
this.selectLabel.text(opt.label);
|
||||
}
|
||||
if (opt.options) {
|
||||
if (this.optionSelectTrigger) {
|
||||
this.optionSelectTrigger.show();
|
||||
this.elementDiv.hide();
|
||||
this.optionMenu = this._createMenu(opt.options,function(v){
|
||||
that.optionSelectLabel.text(v);
|
||||
that.value(v);
|
||||
});
|
||||
var currentVal = this.element.val();
|
||||
if (opt.options.indexOf(currentVal) !== -1) {
|
||||
this.optionSelectLabel.text(currentVal);
|
||||
} else {
|
||||
this.value(opt.options[0]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.optionMenu) {
|
||||
this.optionMenu.remove();
|
||||
this.optionMenu = null;
|
||||
}
|
||||
if (this.optionSelectTrigger) {
|
||||
this.optionSelectTrigger.hide();
|
||||
}
|
||||
if (opt.hasValue === false) {
|
||||
this.oldValue = this.element.val();
|
||||
this.element.val("");
|
||||
this.elementDiv.hide();
|
||||
} else {
|
||||
if (this.oldValue !== undefined) {
|
||||
this.element.val(this.oldValue);
|
||||
delete this.oldValue;
|
||||
}
|
||||
this.elementDiv.show();
|
||||
}
|
||||
this.element.trigger('change',this.propertyType,this.value());
|
||||
}
|
||||
if (image) {
|
||||
image.onload = function() { that._resize(); }
|
||||
image.onerror = function() { that._resize(); }
|
||||
} else {
|
||||
this._resize();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
validate: function() {
|
||||
var result;
|
||||
var value = this.value();
|
||||
var type = this.type();
|
||||
if (this.typeMap[type] && this.typeMap[type].validate) {
|
||||
var val = this.typeMap[type].validate;
|
||||
if (typeof val === 'function') {
|
||||
result = val(value);
|
||||
} else {
|
||||
result = val.test(value);
|
||||
}
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
if (result) {
|
||||
this.uiSelect.removeClass('input-error');
|
||||
} else {
|
||||
this.uiSelect.addClass('input-error');
|
||||
}
|
||||
return result;
|
||||
},
|
||||
show: function() {
|
||||
this.uiSelect.show();
|
||||
this._resize();
|
||||
},
|
||||
hide: function() {
|
||||
this.uiSelect.hide();
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
@@ -1,669 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
RED.deploy = (function() {
|
||||
|
||||
var deploymentTypes = {
|
||||
"full":{img:"red/images/deploy-full-o.png"},
|
||||
"nodes":{img:"red/images/deploy-nodes-o.png"},
|
||||
"flows":{img:"red/images/deploy-flows-o.png"}
|
||||
}
|
||||
|
||||
var ignoreDeployWarnings = {
|
||||
unknown: false,
|
||||
unusedConfig: false,
|
||||
invalid: false
|
||||
}
|
||||
|
||||
var deploymentType = "full";
|
||||
|
||||
function changeDeploymentType(type) {
|
||||
deploymentType = type;
|
||||
$("#btn-deploy-icon").attr("src",deploymentTypes[type].img);
|
||||
}
|
||||
|
||||
var currentDiff = null;
|
||||
|
||||
/**
|
||||
* options:
|
||||
* type: "default" - Button with drop-down options - no further customisation available
|
||||
* type: "simple" - Button without dropdown. Customisations:
|
||||
* label: the text to display - default: "Deploy"
|
||||
* icon : the icon to use. Null removes the icon. default: "red/images/deploy-full-o.png"
|
||||
*/
|
||||
function init(options) {
|
||||
options = options || {};
|
||||
var type = options.type || "default";
|
||||
|
||||
if (type == "default") {
|
||||
$('<li><span class="deploy-button-group button-group">'+
|
||||
'<a id="btn-deploy" class="deploy-button disabled" href="#">'+
|
||||
'<span class="deploy-button-content">'+
|
||||
'<img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> '+
|
||||
'<span>'+RED._("deploy.deploy")+'</span>'+
|
||||
'</span>'+
|
||||
'<span class="deploy-button-spinner hide">'+
|
||||
'<img src="red/images/spin.svg"/>'+
|
||||
'</span>'+
|
||||
'</a>'+
|
||||
'<a id="btn-deploy-options" data-toggle="dropdown" class="deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+
|
||||
'</span></li>').prependTo(".header-toolbar");
|
||||
RED.menu.init({id:"btn-deploy-options",
|
||||
options: [
|
||||
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.png",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
|
||||
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.png",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
|
||||
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.png",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
|
||||
]
|
||||
});
|
||||
} else if (type == "simple") {
|
||||
var label = options.label || RED._("deploy.deploy");
|
||||
var icon = 'red/images/deploy-full-o.png';
|
||||
if (options.hasOwnProperty('icon')) {
|
||||
icon = options.icon;
|
||||
}
|
||||
|
||||
$('<li><span class="deploy-button-group button-group">'+
|
||||
'<a id="btn-deploy" class="deploy-button disabled" href="#">'+
|
||||
'<span class="deploy-button-content">'+
|
||||
(icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+
|
||||
'<span>'+label+'</span>'+
|
||||
'</span>'+
|
||||
'<span class="deploy-button-spinner hide">'+
|
||||
'<img src="red/images/spin.svg"/>'+
|
||||
'</span>'+
|
||||
'</a>'+
|
||||
'</span></li>').prependTo(".header-toolbar");
|
||||
}
|
||||
|
||||
$('#btn-deploy').click(function() { save(); });
|
||||
|
||||
$( "#node-dialog-confirm-deploy" ).dialog({
|
||||
title: RED._('deploy.confirm.button.confirm'),
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 550,
|
||||
height: "auto",
|
||||
buttons: [
|
||||
{
|
||||
text: RED._("deploy.confirm.button.cancel"),
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
},
|
||||
// {
|
||||
// id: "node-dialog-confirm-deploy-review",
|
||||
// text: RED._("deploy.confirm.button.review"),
|
||||
// class: "primary",
|
||||
// click: function() {
|
||||
// showDiff();
|
||||
// $( this ).dialog( "close" );
|
||||
// }
|
||||
// },
|
||||
{
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
|
||||
var ignoreChecked = $( "#node-dialog-confirm-deploy-hide" ).prop("checked");
|
||||
if (ignoreChecked) {
|
||||
ignoreDeployWarnings[$( "#node-dialog-confirm-deploy-type" ).val()] = true;
|
||||
}
|
||||
save(true,$( "#node-dialog-confirm-deploy-type" ).val() === "conflict");
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
],
|
||||
create: function() {
|
||||
$("#node-dialog-confirm-deploy").parent().find("div.ui-dialog-buttonpane")
|
||||
.prepend('<div style="height:0; vertical-align: middle; display:inline-block; margin-top: 13px; float:left;">'+
|
||||
'<input style="vertical-align:top;" type="checkbox" id="node-dialog-confirm-deploy-hide">'+
|
||||
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+
|
||||
'<input type="hidden" id="node-dialog-confirm-deploy-type">'+
|
||||
'</div>');
|
||||
},
|
||||
open: function() {
|
||||
if ($( "#node-dialog-confirm-deploy-type" ).val() === "conflict") {
|
||||
// $("#node-dialog-confirm-deploy-review").show();
|
||||
$("#node-dialog-confirm-deploy-hide").parent().hide();
|
||||
} else {
|
||||
// $("#node-dialog-confirm-deploy-review").hide();
|
||||
$("#node-dialog-confirm-deploy-hide").parent().show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
RED.events.on('nodes:change',function(state) {
|
||||
if (state.dirty) {
|
||||
window.onbeforeunload = function() {
|
||||
return RED._("deploy.confirm.undeployedChanges");
|
||||
}
|
||||
$("#btn-deploy").removeClass("disabled");
|
||||
} else {
|
||||
window.onbeforeunload = null;
|
||||
$("#btn-deploy").addClass("disabled");
|
||||
}
|
||||
});
|
||||
|
||||
// $("#node-dialog-view-diff").dialog({
|
||||
// title: RED._('deploy.confirm.button.review'),
|
||||
// modal: true,
|
||||
// autoOpen: false,
|
||||
// buttons: [
|
||||
// {
|
||||
// text: RED._("deploy.confirm.button.cancel"),
|
||||
// click: function() {
|
||||
// $( this ).dialog( "close" );
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// text: RED._("deploy.confirm.button.merge"),
|
||||
// class: "primary",
|
||||
// click: function() {
|
||||
// $( this ).dialog( "close" );
|
||||
// }
|
||||
// }
|
||||
// ],
|
||||
// open: function() {
|
||||
// $(this).dialog({width:Math.min($(window).width(),900),height:Math.min($(window).height(),600)});
|
||||
// }
|
||||
// });
|
||||
|
||||
// $("#node-dialog-view-diff-diff").editableList({
|
||||
// addButton: false,
|
||||
// scrollOnAdd: false,
|
||||
// addItem: function(container,i,object) {
|
||||
// var tab = object.tab.n;
|
||||
// var tabDiv = $('<div>',{class:"node-diff-tab collapsed"}).appendTo(container);
|
||||
//
|
||||
// var titleRow = $('<div>',{class:"node-diff-tab-title"}).appendTo(tabDiv);
|
||||
// titleRow.click(function(evt) {
|
||||
// evt.preventDefault();
|
||||
// titleRow.parent().toggleClass('collapsed');
|
||||
// })
|
||||
// var chevron = $('<i class="fa fa-angle-down node-diff-chevron ">').appendTo(titleRow);
|
||||
// var title = $('<span>').html(tab.label||tab.id).appendTo(titleRow);
|
||||
//
|
||||
// var stats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(titleRow);
|
||||
//
|
||||
// var addedCount = 0;
|
||||
// var deletedCount = 0;
|
||||
// var changedCount = 0;
|
||||
// var conflictedCount = 0;
|
||||
//
|
||||
// object.tab.nodes.forEach(function(node) {
|
||||
// var realNode = RED.nodes.node(node.id);
|
||||
// var hasChanges = false;
|
||||
// if (currentDiff.added[node.id]) {
|
||||
// addedCount++;
|
||||
// hasChanges = true;
|
||||
// }
|
||||
// if (currentDiff.deleted[node.id]) {
|
||||
// deletedCount++;
|
||||
// hasChanges = true;
|
||||
// }
|
||||
// if (currentDiff.changed[node.id]) {
|
||||
// changedCount++;
|
||||
// hasChanges = true;
|
||||
// }
|
||||
// if (currentDiff.conflicted[node.id]) {
|
||||
// conflictedCount++;
|
||||
// hasChanges = true;
|
||||
// }
|
||||
//
|
||||
// if (hasChanges) {
|
||||
// var def = RED.nodes.getType(node.type)||{};
|
||||
// var div = $("<div>",{class:"node-diff-node-entry collapsed"}).appendTo(tabDiv);
|
||||
// var nodeTitleDiv = $("<div>",{class:"node-diff-node-entry-title"}).appendTo(div);
|
||||
// nodeTitleDiv.click(function(evt) {
|
||||
// evt.preventDefault();
|
||||
// $(this).parent().toggleClass('collapsed');
|
||||
// })
|
||||
// var newNode = currentDiff.newConfig.all[node.id];
|
||||
// var nodePropertiesDiv = $("<div>",{class:"node-diff-node-entry-properties"}).appendTo(div);
|
||||
//
|
||||
// var nodePropertiesTable = $("<table>").appendTo(nodePropertiesDiv);
|
||||
//
|
||||
// if (node.hasOwnProperty('x')) {
|
||||
// if (newNode.x !== node.x || newNode.y !== node.y) {
|
||||
// var currentPosition = node.x+", "+node.y
|
||||
// var newPosition = newNode.x+", "+newNode.y;
|
||||
// $("<tr><td>position</td><td>"+currentPosition+"</td><td>"+newPosition+"</td></tr>").appendTo(nodePropertiesTable);
|
||||
// }
|
||||
// }
|
||||
// var properties = Object.keys(node).filter(function(p) { return p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
|
||||
// if (def.defaults) {
|
||||
// properties = properties.concat(Object.keys(def.defaults));
|
||||
// }
|
||||
// properties.forEach(function(d) {
|
||||
// var localValue = JSON.stringify(node[d]);
|
||||
// var remoteValue = JSON.stringify(newNode[d]);
|
||||
// var originalValue = realNode._config[d];
|
||||
//
|
||||
// if (remoteValue !== originalValue) {
|
||||
// var formattedProperty = formatNodeProperty(node[d]);
|
||||
// var newFormattedProperty = formatNodeProperty(newNode[d]);
|
||||
// if (localValue === originalValue) {
|
||||
// // no conflict change
|
||||
// } else {
|
||||
// // conflicting change
|
||||
// }
|
||||
// $("<tr><td>"+d+'</td><td class="">'+formattedProperty+'</td><td class="node-diff-property-changed">'+newFormattedProperty+"</td></tr>").appendTo(nodePropertiesTable);
|
||||
// }
|
||||
//
|
||||
// })
|
||||
// var nodeChevron = $('<i class="fa fa-angle-down node-diff-chevron">').appendTo(nodeTitleDiv);
|
||||
//
|
||||
//
|
||||
// // var leftColumn = $('<div>',{class:"node-diff-column"}).appendTo(div);
|
||||
// // var rightColumn = $('<div>',{class:"node-diff-column"}).appendTo(div);
|
||||
// // rightColumn.html(" ");
|
||||
//
|
||||
//
|
||||
//
|
||||
// var nodeDiv = $("<div>",{class:"node-diff-node-entry-node"}).appendTo(nodeTitleDiv);
|
||||
// var colour = def.color;
|
||||
// var icon_url = "arrow-in.png";
|
||||
// if (node.type === 'tab') {
|
||||
// colour = "#C0DEED";
|
||||
// icon_url = "subflow.png";
|
||||
// } else if (def.category === 'config') {
|
||||
// icon_url = "cog.png";
|
||||
// } else if (node.type === 'unknown') {
|
||||
// icon_url = "alert.png";
|
||||
// } else {
|
||||
// icon_url = def.icon;
|
||||
// }
|
||||
// nodeDiv.css('backgroundColor',colour);
|
||||
//
|
||||
// var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
|
||||
// $('<div/>',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer);
|
||||
//
|
||||
//
|
||||
//
|
||||
// var contentDiv = $('<div>',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
|
||||
//
|
||||
// $('<span>',{class:"node-diff-node-label"}).html(node.label || node.name || node.id).appendTo(contentDiv);
|
||||
// //$('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
|
||||
// //$('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
|
||||
// }
|
||||
//
|
||||
// });
|
||||
//
|
||||
// var statsInfo = '<span class="node-diff-count">'+object.tab.nodes.length+" nodes"+
|
||||
// (addedCount+deletedCount+changedCount+conflictedCount > 0 ? " : ":"")+
|
||||
// "</span> "+
|
||||
// ((addedCount > 0)?'<span class="node-diff-added">'+addedCount+' added</span> ':'')+
|
||||
// ((deletedCount > 0)?'<span class="node-diff-deleted">'+deletedCount+' deleted</span> ':'')+
|
||||
// ((changedCount > 0)?'<span class="node-diff-changed">'+changedCount+' changed</span> ':'')+
|
||||
// ((conflictedCount > 0)?'<span class="node-diff-conflicted">'+conflictedCount+' conflicts</span>':'');
|
||||
// stats.html(statsInfo);
|
||||
//
|
||||
//
|
||||
//
|
||||
// //
|
||||
// //
|
||||
// //
|
||||
// // var node = object.node;
|
||||
// // var realNode = RED.nodes.node(node.id);
|
||||
// // var def = RED.nodes.getType(object.node.type)||{};
|
||||
// // var l = "";
|
||||
// // if (def && def.label && realNode) {
|
||||
// // l = def.label;
|
||||
// // try {
|
||||
// // l = (typeof l === "function" ? l.call(realNode) : l);
|
||||
// // } catch(err) {
|
||||
// // console.log("Definition error: "+node.type+".label",err);
|
||||
// // }
|
||||
// // }
|
||||
// // l = l||node.label||node.name||node.id||"";
|
||||
// // console.log(node);
|
||||
// // var div = $('<div>').appendTo(container);
|
||||
// // div.html(l);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
function formatNodeProperty(prop) {
|
||||
var formattedProperty = prop;
|
||||
if (formattedProperty === null) {
|
||||
formattedProperty = 'null';
|
||||
} else if (formattedProperty === undefined) {
|
||||
formattedProperty = 'undefined';
|
||||
} else if (typeof formattedProperty === 'object') {
|
||||
formattedProperty = JSON.stringify(formattedProperty);
|
||||
}
|
||||
if (/\n/.test(formattedProperty)) {
|
||||
formattedProperty = "<pre>"+formattedProperty+"</pre>"
|
||||
}
|
||||
return formattedProperty;
|
||||
}
|
||||
|
||||
function getNodeInfo(node) {
|
||||
var tabLabel = "";
|
||||
if (node.z) {
|
||||
var tab = RED.nodes.workspace(node.z);
|
||||
if (!tab) {
|
||||
tab = RED.nodes.subflow(node.z);
|
||||
tabLabel = tab.name;
|
||||
} else {
|
||||
tabLabel = tab.label;
|
||||
}
|
||||
}
|
||||
var label = RED.utils.getNodeLabel(node,node.id);
|
||||
return {tab:tabLabel,type:node.type,label:label};
|
||||
}
|
||||
function sortNodeInfo(A,B) {
|
||||
if (A.tab < B.tab) { return -1;}
|
||||
if (A.tab > B.tab) { return 1;}
|
||||
if (A.type < B.type) { return -1;}
|
||||
if (A.type > B.type) { return 1;}
|
||||
if (A.name < B.name) { return -1;}
|
||||
if (A.name > B.name) { return 1;}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function resolveConflict(currentNodes) {
|
||||
$( "#node-dialog-confirm-deploy-config" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-unknown" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-unused" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-conflict" ).show();
|
||||
$( "#node-dialog-confirm-deploy-type" ).val("conflict");
|
||||
$( "#node-dialog-confirm-deploy" ).dialog( "open" );
|
||||
|
||||
// $("#node-dialog-confirm-deploy-review").append($('<img src="red/images/spin.svg" style="background: rgba(255,255,255,0.8); margin-top: -16px; margin-left: -8px; height:16px; position: absolute; "/>'));
|
||||
// $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",0.4);
|
||||
// $("#node-dialog-confirm-deploy-review").attr("disabled",true).addClass("disabled");
|
||||
// $.ajax({
|
||||
// headers: {
|
||||
// "Accept":"application/json",
|
||||
// },
|
||||
// cache: false,
|
||||
// url: 'flows',
|
||||
// success: function(nodes) {
|
||||
// var newNodes = nodes.flows;
|
||||
// var newRevision = nodes.rev;
|
||||
// generateDiff(currentNodes,newNodes);
|
||||
// $("#node-dialog-confirm-deploy-review").attr("disabled",false).removeClass("disabled");
|
||||
// $("#node-dialog-confirm-deploy-review img").remove();
|
||||
// $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",1);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
// function parseNodes(nodeList) {
|
||||
// var tabOrder = [];
|
||||
// var tabs = {};
|
||||
// var subflows = {};
|
||||
// var globals = [];
|
||||
// var all = {};
|
||||
//
|
||||
// nodeList.forEach(function(node) {
|
||||
// all[node.id] = node;
|
||||
// if (node.type === 'tab') {
|
||||
// tabOrder.push(node.id);
|
||||
// tabs[node.id] = {n:node,nodes:[]};
|
||||
// } else if (node.type === 'subflow') {
|
||||
// subflows[node.id] = {n:node,nodes:[]};
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// nodeList.forEach(function(node) {
|
||||
// if (node.type !== 'tab' && node.type !== 'subflow') {
|
||||
// if (tabs[node.z]) {
|
||||
// tabs[node.z].nodes.push(node);
|
||||
// } else if (subflows[node.z]) {
|
||||
// subflows[node.z].nodes.push(node);
|
||||
// } else {
|
||||
// globals.push(node);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// return {
|
||||
// all: all,
|
||||
// tabOrder: tabOrder,
|
||||
// tabs: tabs,
|
||||
// subflows: subflows,
|
||||
// globals: globals
|
||||
// }
|
||||
// }
|
||||
|
||||
// function generateDiff(currentNodes,newNodes) {
|
||||
// var currentConfig = parseNodes(currentNodes);
|
||||
// var newConfig = parseNodes(newNodes);
|
||||
// var pending = RED.nodes.pending();
|
||||
// var added = {};
|
||||
// var deleted = {};
|
||||
// var changed = {};
|
||||
// var conflicted = {};
|
||||
//
|
||||
//
|
||||
// Object.keys(currentConfig.all).forEach(function(id) {
|
||||
// var node = RED.nodes.workspace(id)||RED.nodes.subflow(id)||RED.nodes.node(id);
|
||||
// if (!newConfig.all.hasOwnProperty(id)) {
|
||||
// if (!pending.added.hasOwnProperty(id)) {
|
||||
// deleted[id] = true;
|
||||
// conflicted[id] = node.changed;
|
||||
// }
|
||||
// } else if (JSON.stringify(currentConfig.all[id]) !== JSON.stringify(newConfig.all[id])) {
|
||||
// changed[id] = true;
|
||||
// conflicted[id] = node.changed;
|
||||
// }
|
||||
// });
|
||||
// Object.keys(newConfig.all).forEach(function(id) {
|
||||
// if (!currentConfig.all.hasOwnProperty(id) && !pending.deleted.hasOwnProperty(id)) {
|
||||
// added[id] = true;
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // console.log("Added",added);
|
||||
// // console.log("Deleted",deleted);
|
||||
// // console.log("Changed",changed);
|
||||
// // console.log("Conflicted",conflicted);
|
||||
//
|
||||
// var formatString = function(id) {
|
||||
// return conflicted[id]?"!":(added[id]?"+":(deleted[id]?"-":(changed[id]?"~":" ")));
|
||||
// }
|
||||
// newConfig.tabOrder.forEach(function(tabId) {
|
||||
// var tab = newConfig.tabs[tabId];
|
||||
// console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
|
||||
// tab.nodes.forEach(function(node) {
|
||||
// console.log(" ",formatString(node.id),node.type,node.name || node.id);
|
||||
// })
|
||||
// if (currentConfig.tabs[tabId]) {
|
||||
// currentConfig.tabs[tabId].nodes.forEach(function(node) {
|
||||
// if (deleted[node.id]) {
|
||||
// console.log(" ",formatString(node.id),node.type,node.name || node.id);
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// });
|
||||
// currentConfig.tabOrder.forEach(function(tabId) {
|
||||
// if (deleted[tabId]) {
|
||||
// console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// currentDiff = {
|
||||
// currentConfig: currentConfig,
|
||||
// newConfig: newConfig,
|
||||
// added: added,
|
||||
// deleted: deleted,
|
||||
// changed: changed,
|
||||
// conflicted: conflicted
|
||||
// }
|
||||
// }
|
||||
|
||||
// function showDiff() {
|
||||
// if (currentDiff) {
|
||||
// var list = $("#node-dialog-view-diff-diff");
|
||||
// list.editableList('empty');
|
||||
// var currentConfig = currentDiff.currentConfig;
|
||||
// currentConfig.tabOrder.forEach(function(tabId) {
|
||||
// var tab = currentConfig.tabs[tabId];
|
||||
// list.editableList('addItem',{tab:tab})
|
||||
// });
|
||||
// }
|
||||
// $("#node-dialog-view-diff").dialog("open");
|
||||
// }
|
||||
|
||||
|
||||
function save(skipValidation,force) {
|
||||
if (!$("#btn-deploy").hasClass("disabled")) {
|
||||
if (!skipValidation) {
|
||||
var hasUnknown = false;
|
||||
var hasInvalid = false;
|
||||
var hasUnusedConfig = false;
|
||||
|
||||
var unknownNodes = [];
|
||||
var invalidNodes = [];
|
||||
|
||||
RED.nodes.eachNode(function(node) {
|
||||
hasInvalid = hasInvalid || !node.valid;
|
||||
if (!node.valid) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
|
||||
var unusedConfigNodes = [];
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if (node.users.length === 0 && (node._def.hasUsers !== false)) {
|
||||
unusedConfigNodes.push(getNodeInfo(node));
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
$( "#node-dialog-confirm-deploy-config" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-unknown" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-unused" ).hide();
|
||||
$( "#node-dialog-confirm-deploy-conflict" ).hide();
|
||||
|
||||
var showWarning = false;
|
||||
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
$( "#node-dialog-confirm-deploy-type" ).val("unknown");
|
||||
$( "#node-dialog-confirm-deploy-unknown" ).show();
|
||||
$( "#node-dialog-confirm-deploy-unknown-list" )
|
||||
.html("<li>"+unknownNodes.join("</li><li>")+"</li>");
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
$( "#node-dialog-confirm-deploy-type" ).val("invalid");
|
||||
$( "#node-dialog-confirm-deploy-config" ).show();
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
$( "#node-dialog-confirm-deploy-invalid-list" )
|
||||
.html("<li>"+invalidNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"}).join("</li><li>")+"</li>");
|
||||
|
||||
} else if (hasUnusedConfig && !ignoreDeployWarnings.unusedConfig) {
|
||||
// showWarning = true;
|
||||
// $( "#node-dialog-confirm-deploy-type" ).val("unusedConfig");
|
||||
// $( "#node-dialog-confirm-deploy-unused" ).show();
|
||||
//
|
||||
// unusedConfigNodes.sort(sortNodeInfo);
|
||||
// $( "#node-dialog-confirm-deploy-unused-list" )
|
||||
// .html("<li>"+unusedConfigNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"}).join("</li><li>")+"</li>");
|
||||
}
|
||||
if (showWarning) {
|
||||
$( "#node-dialog-confirm-deploy-hide" ).prop("checked",false);
|
||||
$( "#node-dialog-confirm-deploy" ).dialog( "open" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
|
||||
var startTime = Date.now();
|
||||
$(".deploy-button-content").css('opacity',0);
|
||||
$(".deploy-button-spinner").show();
|
||||
$("#btn-deploy").addClass("disabled");
|
||||
|
||||
var data = {flows:nns};
|
||||
|
||||
if (!force) {
|
||||
data.rev = RED.nodes.version();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url:"flows",
|
||||
type: "POST",
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
headers: {
|
||||
"Node-RED-Deployment-Type":deploymentType
|
||||
}
|
||||
}).done(function(data,textStatus,xhr) {
|
||||
RED.nodes.dirty(false);
|
||||
RED.nodes.version(data.rev);
|
||||
if (hasUnusedConfig) {
|
||||
RED.notify(
|
||||
'<p>'+RED._("deploy.successfulDeploy")+'</p>'+
|
||||
'<p>'+RED._("deploy.unusedConfigNodes")+' <a href="#" onclick="RED.sidebar.config.show(true); return false;">'+RED._("deploy.unusedConfigNodesLink")+'</a></p>',"success",false,6000);
|
||||
} else {
|
||||
RED.notify(RED._("deploy.successfulDeploy"),"success");
|
||||
}
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if(node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
ws.changed = false;
|
||||
})
|
||||
// Once deployed, cannot undo back to a clean state
|
||||
RED.history.markAllDirty();
|
||||
RED.view.redraw();
|
||||
RED.events.emit("deploy");
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
RED.nodes.dirty(true);
|
||||
$("#btn-deploy").removeClass("disabled");
|
||||
if (xhr.status === 401) {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
|
||||
} else if (xhr.status === 409) {
|
||||
resolveConflict(nns);
|
||||
} else if (xhr.responseText) {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
|
||||
} else {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
|
||||
}
|
||||
}).always(function() {
|
||||
var delta = Math.max(0,300-(Date.now()-startTime));
|
||||
setTimeout(function() {
|
||||
$(".deploy-button-content").css('opacity',1);
|
||||
$(".deploy-button-spinner").hide();
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
}
|
||||
return {
|
||||
init: init
|
||||
}
|
||||
})();
|
||||
@@ -1,156 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.keyboard = (function() {
|
||||
|
||||
var handlers = {};
|
||||
|
||||
function resolveKeyEvent(evt) {
|
||||
var slot = handlers;
|
||||
if (evt.ctrlKey || evt.metaKey) {
|
||||
slot = slot.ctrl;
|
||||
}
|
||||
if (slot && evt.shiftKey) {
|
||||
slot = slot.shift;
|
||||
}
|
||||
if (slot && evt.altKey) {
|
||||
slot = slot.alt;
|
||||
}
|
||||
if (slot && slot[evt.keyCode]) {
|
||||
var handler = slot[evt.keyCode];
|
||||
if (handler.scope && handler.scope !== "*") {
|
||||
var target = evt.target;
|
||||
while (target.nodeName !== 'BODY' && target.id !== handler.scope) {
|
||||
target = target.parentElement;
|
||||
}
|
||||
if (target.nodeName === 'BODY') {
|
||||
handler = null;
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
d3.select(window).on("keydown",function() {
|
||||
var handler = resolveKeyEvent(d3.event);
|
||||
if (handler && handler.ondown) {
|
||||
handler.ondown();
|
||||
}
|
||||
});
|
||||
d3.select(window).on("keyup",function() {
|
||||
var handler = resolveKeyEvent(d3.event);
|
||||
if (handler && handler.onup) {
|
||||
handler.onup();
|
||||
}
|
||||
});
|
||||
|
||||
function addHandler(scope,key,modifiers,ondown,onup) {
|
||||
var mod = modifiers;
|
||||
var cbdown = ondown;
|
||||
var cbup = onup;
|
||||
if (typeof modifiers == "function") {
|
||||
mod = {};
|
||||
cbdown = modifiers;
|
||||
cbup = ondown;
|
||||
}
|
||||
var slot = handlers;
|
||||
if (mod.ctrl) {
|
||||
slot.ctrl = slot.ctrl||{};
|
||||
slot = slot.ctrl;
|
||||
}
|
||||
if (mod.shift) {
|
||||
slot.shift = slot.shift||{};
|
||||
slot = slot.shift;
|
||||
}
|
||||
if (mod.alt) {
|
||||
slot.alt = slot.alt||{};
|
||||
slot = slot.alt;
|
||||
}
|
||||
slot[key] = {scope: scope, ondown:cbdown, onup:cbup};
|
||||
}
|
||||
|
||||
function removeHandler(key,modifiers) {
|
||||
var mod = modifiers || {};
|
||||
var slot = handlers;
|
||||
if (mod.ctrl) {
|
||||
slot = slot.ctrl;
|
||||
}
|
||||
if (slot && mod.shift) {
|
||||
slot = slot.shift;
|
||||
}
|
||||
if (slot && mod.alt) {
|
||||
slot = slot.alt;
|
||||
}
|
||||
if (slot) {
|
||||
delete slot[key];
|
||||
}
|
||||
}
|
||||
|
||||
var dialog = null;
|
||||
|
||||
function showKeyboardHelp() {
|
||||
if (!RED.settings.theme("menu.menu-item-keyboard-shortcuts",true)) {
|
||||
return;
|
||||
}
|
||||
if (!dialog) {
|
||||
dialog = $('<div id="keyboard-help-dialog" class="hide">'+
|
||||
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
|
||||
'<table class="keyboard-shortcuts">'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">a</span></td><td>'+RED._("keyboard.selectAll")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Shift</span> + <span class="help-key">Click</span></td><td>'+RED._("keyboard.selectAllConnected")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Click</span></td><td>'+RED._("keyboard.addRemoveNode")+'</td></tr>'+
|
||||
'<tr><td> </td><td></td></tr>'+
|
||||
'<tr><td><span class="help-key">Enter</span></td><td>'+RED._("keyboard.editSelected")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Delete</span> / <span class="help-key">Backspace</span></td><td>'+RED._("keyboard.deleteSelected")+'</td></tr>'+
|
||||
'<tr><td> </td><td></td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">i</span></td><td>'+RED._("keyboard.importNode")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">e</span></td><td>'+RED._("keyboard.exportNode")+'</td></tr>'+
|
||||
'</table>'+
|
||||
'</div>'+
|
||||
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
|
||||
'<table class="keyboard-shortcuts">'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Space</span></td><td>'+RED._("keyboard.toggleSidebar")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">.</span></td><td>'+RED._("keyboard.searchBox")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Shift</span> + <span class="help-key">p</span></td><td>'+RED._("keyboard.managePalette")+'</td></tr>'+
|
||||
'<tr><td> </td><td></td></tr>'+
|
||||
'<tr><td><span class="help-key">←</span> <span class="help-key">↑</span> <span class="help-key">→</span> <span class="help-key">↓</span></td><td>'+RED._("keyboard.nudgeNode")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Shift</span> + <span class="help-key">←</span> <span class="help-key">↑</span> <span class="help-key">→</span> <span class="help-key">↓</span></td><td>'+RED._("keyboard.moveNode")+'</td></tr>'+
|
||||
'<tr><td> </td><td></td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">c</span></td><td>'+RED._("keyboard.copyNode")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">x</span></td><td>'+RED._("keyboard.cutNode")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">v</span></td><td>'+RED._("keyboard.pasteNode")+'</td></tr>'+
|
||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">z</span></td><td>'+RED._("keyboard.undoChange")+'</td></tr>'+
|
||||
'</table>'+
|
||||
'</div>'+
|
||||
'</div>')
|
||||
.appendTo("body")
|
||||
.dialog({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: "800",
|
||||
title:"Keyboard shortcuts",
|
||||
resizable: false
|
||||
});
|
||||
}
|
||||
|
||||
dialog.dialog("open");
|
||||
}
|
||||
|
||||
return {
|
||||
add: addHandler,
|
||||
remove: removeHandler,
|
||||
showHelp: showKeyboardHelp
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.notify = (function() {
|
||||
var currentNotifications = [];
|
||||
var c = 0;
|
||||
return function(msg,type,fixed,timeout) {
|
||||
if (currentNotifications.length > 4) {
|
||||
var ll = currentNotifications.length;
|
||||
for (var i = 0;ll > 4 && i<currentNotifications.length;i+=1) {
|
||||
var notifiction = currentNotifications[i];
|
||||
if (!notifiction.fixed) {
|
||||
window.clearTimeout(notifiction.timeoutid);
|
||||
notifiction.close();
|
||||
ll -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
var n = document.createElement("div");
|
||||
n.id="red-notification-"+c;
|
||||
n.className = "notification";
|
||||
n.fixed = fixed;
|
||||
if (type) {
|
||||
n.className = "notification notification-"+type;
|
||||
}
|
||||
n.style.display = "none";
|
||||
n.innerHTML = msg;
|
||||
$("#notifications").append(n);
|
||||
$(n).slideDown(300);
|
||||
n.close = (function() {
|
||||
var nn = n;
|
||||
return function() {
|
||||
currentNotifications.splice(currentNotifications.indexOf(nn),1);
|
||||
$(nn).slideUp(300, function() {
|
||||
nn.parentNode.removeChild(nn);
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
n.update = (function() {
|
||||
var nn = n;
|
||||
return function(msg) {
|
||||
nn.innerHTML = msg;
|
||||
}
|
||||
})();
|
||||
|
||||
if (!fixed) {
|
||||
$(n).click((function() {
|
||||
var nn = n;
|
||||
return function() {
|
||||
nn.close();
|
||||
window.clearTimeout(nn.timeoutid);
|
||||
};
|
||||
})());
|
||||
n.timeoutid = window.setTimeout(n.close,timeout||3000);
|
||||
}
|
||||
currentNotifications.push(n);
|
||||
c+=1;
|
||||
return n;
|
||||
}
|
||||
})();
|
||||
@@ -1,184 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.sidebar.info = (function() {
|
||||
|
||||
marked.setOptions({
|
||||
renderer: new marked.Renderer(),
|
||||
gfm: true,
|
||||
tables: true,
|
||||
breaks: false,
|
||||
pedantic: false,
|
||||
sanitize: true,
|
||||
smartLists: true,
|
||||
smartypants: false
|
||||
});
|
||||
|
||||
var content = document.createElement("div");
|
||||
content.style.paddingTop = "4px";
|
||||
content.style.paddingLeft = "4px";
|
||||
content.style.paddingRight = "4px";
|
||||
content.className = "sidebar-node-info"
|
||||
|
||||
var propertiesExpanded = false;
|
||||
|
||||
function init() {
|
||||
RED.sidebar.addTab({
|
||||
id: "info",
|
||||
label: RED._("sidebar.info.label"),
|
||||
name: RED._("sidebar.info.name"),
|
||||
content: content,
|
||||
enableOnEdit: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function show() {
|
||||
RED.sidebar.show("info");
|
||||
}
|
||||
|
||||
function jsonFilter(key,value) {
|
||||
if (key === "") {
|
||||
return value;
|
||||
}
|
||||
var t = typeof value;
|
||||
if ($.isArray(value)) {
|
||||
return "[array:"+value.length+"]";
|
||||
} else if (t === "object") {
|
||||
return "[object]"
|
||||
} else if (t === "string") {
|
||||
if (value.length > 30) {
|
||||
return value.substring(0,30)+" ...";
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function refresh(node) {
|
||||
$(content).empty();
|
||||
var table = $('<table class="node-info"></table>');
|
||||
var tableBody = $('<tbody>').appendTo(table);
|
||||
$('<tr class="blank"><td colspan="2">'+RED._("sidebar.info.node")+'</td></tr>').appendTo(tableBody);
|
||||
if (node.type != "subflow" && node.name) {
|
||||
$('<tr><td>'+RED._("common.label.name")+'</td><td> <span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody);
|
||||
}
|
||||
$("<tr><td>"+RED._("sidebar.info.type")+"</td><td> "+node.type+"</td></tr>").appendTo(tableBody);
|
||||
$("<tr><td>"+RED._("sidebar.info.id")+"</td><td> "+node.id+"</td></tr>").appendTo(tableBody);
|
||||
|
||||
var m = /^subflow(:(.+))?$/.exec(node.type);
|
||||
var subflowNode;
|
||||
if (m) {
|
||||
if (m[2]) {
|
||||
subflowNode = RED.nodes.subflow(m[2]);
|
||||
} else {
|
||||
subflowNode = node;
|
||||
}
|
||||
|
||||
$('<tr class="blank"><td colspan="2">'+RED._("sidebar.info.subflow")+'</td></tr>').appendTo(tableBody);
|
||||
|
||||
var userCount = 0;
|
||||
var subflowType = "subflow:"+subflowNode.id;
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.type === subflowType) {
|
||||
userCount++;
|
||||
}
|
||||
});
|
||||
$('<tr><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+subflowNode.name+'</span></td></tr>').appendTo(tableBody);
|
||||
$("<tr><td>"+RED._("sidebar.info.instances")+"</td><td>"+userCount+"</td></tr>").appendTo(tableBody);
|
||||
}
|
||||
|
||||
if (!m && node.type != "subflow" && node.type != "comment") {
|
||||
$('<tr class="blank"><td colspan="2"><a href="#" class="node-info-property-header"><i style="width: 10px; text-align: center;" class="fa fa-caret-'+(propertiesExpanded?"down":"right")+'"></i> '+RED._("sidebar.info.properties")+'</a></td></tr>').appendTo(tableBody);
|
||||
if (node._def) {
|
||||
for (var n in node._def.defaults) {
|
||||
if (n != "name" && node._def.defaults.hasOwnProperty(n)) {
|
||||
var val = node[n];
|
||||
var type = typeof val;
|
||||
var propRow = $('<tr class="node-info-property-row'+(propertiesExpanded?"":" hide")+'"><td>'+n+"</td><td></td></tr>").appendTo(tableBody);
|
||||
RED.utils.createObjectElement(val).appendTo(propRow.children()[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$(table).appendTo(content);
|
||||
$("<hr/>").appendTo(content);
|
||||
if (!subflowNode && node.type != "comment") {
|
||||
var helpText = $("script[data-help-name$='"+node.type+"']").html()||"";
|
||||
$('<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(helpText)+'">'+helpText+'</span></div>').appendTo(content);
|
||||
}
|
||||
if (subflowNode) {
|
||||
$('<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.info||"")+'">'+marked(subflowNode.info||"")+'</span></div>').appendTo(content);
|
||||
} else if (node._def && node._def.info) {
|
||||
var info = node._def.info;
|
||||
var textInfo = (typeof info === "function" ? info.call(node) : info);
|
||||
$('<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(textInfo)+'">'+marked(textInfo)+'</span></div>').appendTo(content);
|
||||
//$('<div class="node-help">'+(typeof info === "function" ? info.call(node) : info)+'</div>';
|
||||
}
|
||||
|
||||
|
||||
$(".node-info-property-header").click(function(e) {
|
||||
var icon = $(this).find("i");
|
||||
if (icon.hasClass("fa-caret-right")) {
|
||||
icon.removeClass("fa-caret-right");
|
||||
icon.addClass("fa-caret-down");
|
||||
$(".node-info-property-row").show();
|
||||
propertiesExpanded = true;
|
||||
} else {
|
||||
icon.addClass("fa-caret-right");
|
||||
icon.removeClass("fa-caret-down");
|
||||
$(".node-info-property-row").hide();
|
||||
propertiesExpanded = false;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
$(content).html("");
|
||||
}
|
||||
|
||||
function set(html) {
|
||||
$(content).html(html);
|
||||
}
|
||||
|
||||
RED.events.on("view:selection-changed",function(selection) {
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length == 1) {
|
||||
var node = selection.nodes[0];
|
||||
if (node.type === "subflow" && node.direction) {
|
||||
refresh(RED.nodes.subflow(node.z));
|
||||
} else {
|
||||
refresh(node);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
if (subflow) {
|
||||
refresh(subflow);
|
||||
} else {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
init: init,
|
||||
show: show,
|
||||
refresh:refresh,
|
||||
clear: clear,
|
||||
set: set
|
||||
}
|
||||
})();
|
||||
@@ -1,286 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
RED.utils = (function() {
|
||||
|
||||
function formatString(str) {
|
||||
return str.replace(/\r?\n/g,"↵").replace(/\t/g,"→");
|
||||
}
|
||||
|
||||
function buildMessageSummaryValue(value) {
|
||||
var result;
|
||||
if (Array.isArray(value)) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
|
||||
} else if (value === null) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-null">null</span>');
|
||||
} else if (typeof value === 'object') {
|
||||
if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.data.length+']');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
|
||||
} else {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta">object</span>');
|
||||
}
|
||||
} else if (typeof value === 'string') {
|
||||
subvalue = value;
|
||||
if (subvalue.length > 30) {
|
||||
subvalue = subvalue.substring(0,30)+"…";
|
||||
}
|
||||
result = $('<span class="debug-message-object-value debug-message-type-string"></span>').html('"'+formatString(subvalue)+'"');
|
||||
} else {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-other"></span>').text(""+value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function makeExpandable(el,onexpand) {
|
||||
el.addClass("debug-message-expandable");
|
||||
el.click(function(e) {
|
||||
var parent = $(this).parent();
|
||||
if (parent.hasClass('collapsed')) {
|
||||
if (onexpand && !parent.hasClass('built')) {
|
||||
onexpand();
|
||||
parent.addClass('built');
|
||||
}
|
||||
parent.removeClass('collapsed');
|
||||
} else {
|
||||
parent.addClass('collapsed');
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
function buildMessageElement(obj,key,typeHint,hideKey) {
|
||||
var i;
|
||||
var e;
|
||||
var entryObj;
|
||||
var header;
|
||||
var headerHead;
|
||||
var value,subvalue;
|
||||
var element = $('<span class="debug-message-element"></span>');
|
||||
if (!key) {
|
||||
element.addClass("debug-message-top-level");
|
||||
}
|
||||
|
||||
header = $('<span></span>').appendTo(element);
|
||||
|
||||
if (key && !hideKey) {
|
||||
$('<span class="debug-message-object-key"></span>').text(key).appendTo(header);
|
||||
$('<span>: </span>').appendTo(header);
|
||||
}
|
||||
entryObj = $('<span class="debug-message-object-value"></span>').appendTo(header);
|
||||
|
||||
var isArray = Array.isArray(obj);
|
||||
var isArrayObject = false;
|
||||
if (obj && typeof obj === 'object' && obj.hasOwnProperty('type') && obj.hasOwnProperty('data')) {
|
||||
isArray = true;
|
||||
isArrayObject = true;
|
||||
}
|
||||
|
||||
if (obj === null || obj === undefined) {
|
||||
$('<span class="debug-message-type-null">'+obj+'</span>').appendTo(entryObj);
|
||||
} else if (typeof obj === 'string') {
|
||||
if (/[\t\n\r]/.test(obj)) {
|
||||
element.addClass('collapsed');
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
|
||||
makeExpandable(header, function() {
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header);
|
||||
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
|
||||
$('<pre class="debug-message-type-string"></pre>').html(obj).appendTo(row);
|
||||
});
|
||||
}
|
||||
$('<span class="debug-message-type-string debug-message-object-header"></span>').html('"'+formatString(obj)+'"').appendTo(entryObj);
|
||||
|
||||
|
||||
} else if (typeof obj === 'number') {
|
||||
e = $('<span class="debug-message-type-number"></span>').text(""+obj).appendTo(entryObj);
|
||||
e.click(function(evt) {
|
||||
var format = $(this).data('format');
|
||||
if (format === 'hex') {
|
||||
$(this).text(""+obj).data('format','dec');
|
||||
} else {
|
||||
$(this).text("0x"+(obj).toString(16)).data('format','hex');
|
||||
}
|
||||
evt.preventDefault();
|
||||
});
|
||||
} else if (isArray) {
|
||||
element.addClass('collapsed');
|
||||
|
||||
var originalLength = obj.length;
|
||||
if (typeHint) {
|
||||
var m = /\[(\d+)\]/.exec(typeHint);
|
||||
if (m) {
|
||||
originalLength = parseInt(m[1]);
|
||||
}
|
||||
}
|
||||
var data = obj;
|
||||
var type = 'array';
|
||||
if (isArrayObject) {
|
||||
data = obj.data;
|
||||
if (originalLength === undefined) {
|
||||
originalLength = data.length;
|
||||
}
|
||||
type = obj.type.toLowerCase();
|
||||
} else if (/buffer/.test(typeHint)) {
|
||||
type = 'buffer';
|
||||
}
|
||||
var fullLength = data.length;
|
||||
|
||||
if (originalLength > 0) {
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
|
||||
var arrayRows = $('<div class="debug-message-array-rows"></div>').appendTo(element);
|
||||
element.addClass('debug-message-buffer-raw');
|
||||
makeExpandable(header,function() {
|
||||
if (!key) {
|
||||
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(header);
|
||||
}
|
||||
if (type === 'buffer') {
|
||||
var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element);
|
||||
var sr = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(stringRow);
|
||||
var stringEncoding = "";
|
||||
try {
|
||||
stringEncoding = String.fromCharCode.apply(null, new Uint16Array(data))
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
$('<pre class="debug-message-type-string"></pre>').html(stringEncoding).appendTo(sr);
|
||||
var bufferOpts = $('<span class="debug-message-buffer-opts"></span>').appendTo(headerHead);
|
||||
$('<a href="#"></a>').addClass('selected').html('raw').appendTo(bufferOpts).click(function(e) {
|
||||
if ($(this).text() === 'raw') {
|
||||
$(this).text('string');
|
||||
element.addClass('debug-message-buffer-string').removeClass('debug-message-buffer-raw');
|
||||
} else {
|
||||
$(this).text('raw');
|
||||
element.removeClass('debug-message-buffer-string').addClass('debug-message-buffer-raw');
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
})
|
||||
}
|
||||
var row;
|
||||
if (fullLength <= 10) {
|
||||
for (i=0;i<fullLength;i++) {
|
||||
row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows);
|
||||
buildMessageElement(data[i],""+i,false).appendTo(row);
|
||||
}
|
||||
} else {
|
||||
for (i=0;i<fullLength;i+=10) {
|
||||
var minRange = i;
|
||||
row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows);
|
||||
header = $('<span></span>').appendTo(row);
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').appendTo(header);
|
||||
makeExpandable(header, (function() {
|
||||
var min = minRange;
|
||||
var max = Math.min(fullLength-1,(minRange+9));
|
||||
var parent = row;
|
||||
return function() {
|
||||
for (var i=min;i<=max;i++) {
|
||||
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(parent);
|
||||
buildMessageElement(data[i],""+i,false).appendTo(row);
|
||||
}
|
||||
}
|
||||
})());
|
||||
$('<span class="debug-message-object-key"></span>').html("["+minRange+" … "+Math.min(fullLength-1,(minRange+9))+"]").appendTo(header);
|
||||
}
|
||||
if (fullLength < originalLength) {
|
||||
$('<div class="debug-message-object-entry collapsed"><span class="debug-message-object-key">['+fullLength+' … '+originalLength+']</span></div>').appendTo(arrayRows);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (key) {
|
||||
headerHead = $('<span class="debug-message-type-meta f"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
|
||||
} else {
|
||||
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
|
||||
$('<span>[ </span>').appendTo(headerHead);
|
||||
var arrayLength = Math.min(originalLength,10);
|
||||
for (i=0;i<arrayLength;i++) {
|
||||
buildMessageSummaryValue(data[i]).appendTo(headerHead);
|
||||
if (i < arrayLength-1) {
|
||||
$('<span>, </span>').appendTo(headerHead);
|
||||
}
|
||||
}
|
||||
if (originalLength > arrayLength) {
|
||||
$('<span> …</span>').appendTo(headerHead);
|
||||
}
|
||||
if (arrayLength === 0) {
|
||||
$('<span class="debug-message-type-meta">empty</span>').appendTo(headerHead);
|
||||
}
|
||||
$('<span> ]</span>').appendTo(headerHead);
|
||||
}
|
||||
|
||||
} else if (typeof obj === 'object') {
|
||||
element.addClass('collapsed');
|
||||
var keys = Object.keys(obj);
|
||||
if (key || keys.length > 0) {
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
|
||||
makeExpandable(header, function() {
|
||||
if (!key) {
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html('object').appendTo(header);
|
||||
}
|
||||
for (i=0;i<keys.length;i++) {
|
||||
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
|
||||
buildMessageElement(obj[keys[i]],keys[i],false).appendTo(row);
|
||||
}
|
||||
if (keys.length === 0) {
|
||||
$('<div class="debug-message-object-entry debug-message-type-meta collapsed"></div>').text("empty").appendTo(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (key) {
|
||||
$('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj);
|
||||
} else {
|
||||
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
|
||||
$('<span>{ </span>').appendTo(headerHead);
|
||||
var keysLength = Math.min(keys.length,5);
|
||||
for (i=0;i<keysLength;i++) {
|
||||
$('<span class="debug-message-object-key"></span>').text(keys[i]).appendTo(headerHead);
|
||||
$('<span>: </span>').appendTo(headerHead);
|
||||
buildMessageSummaryValue(obj[keys[i]]).appendTo(headerHead);
|
||||
if (i < keysLength-1) {
|
||||
$('<span>, </span>').appendTo(headerHead);
|
||||
}
|
||||
}
|
||||
if (keys.length > keysLength) {
|
||||
$('<span> …</span>').appendTo(headerHead);
|
||||
}
|
||||
if (keysLength === 0) {
|
||||
$('<span class="debug-message-type-meta">empty</span>').appendTo(headerHead);
|
||||
}
|
||||
$('<span> }</span>').appendTo(headerHead);
|
||||
}
|
||||
} else {
|
||||
$('<span class="debug-message-type-other"></span>').text(""+obj).appendTo(entryObj);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
function getNodeLabel(node,defaultLabel) {
|
||||
defaultLabel = defaultLabel||"";
|
||||
var l = node._def.label;
|
||||
try {
|
||||
l = (typeof l === "function" ? l.call(node) : l)||defaultLabel;
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+node.type+".label",err);
|
||||
l = defaultLabel;
|
||||
}
|
||||
return RED.text.bidi.enforceTextDirectionWithUCC(l);
|
||||
}
|
||||
|
||||
return {
|
||||
createObjectElement: buildMessageElement,
|
||||
getNodeLabel: getNodeLabel
|
||||
}
|
||||
})();
|
||||
@@ -1,165 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
#node-dialog-view-diff {
|
||||
height: 600px;
|
||||
|
||||
.red-ui-editableList-container {
|
||||
border-radius:1px;
|
||||
padding:0;
|
||||
}
|
||||
ol {
|
||||
position: absolute;
|
||||
top:10px;
|
||||
bottom:10px;
|
||||
left:10px;
|
||||
right:10px;
|
||||
li {
|
||||
padding: 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
}
|
||||
.red-ui-editableList-item-content {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
.node-diff-tab {
|
||||
border: 1px solid $secondary-border-color;
|
||||
border-radius: 3px;
|
||||
|
||||
&.collapsed {
|
||||
.node-diff-tab-title > .node-diff-chevron {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.node-diff-node-entry {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.node-diff-tab-stats {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.node-diff-chevron {
|
||||
width: 15px;
|
||||
text-align: center;
|
||||
margin: 3px 5px 3px 5px;
|
||||
transition: transform 0.1s ease-in-out;
|
||||
|
||||
}
|
||||
.node-diff-node-entry {
|
||||
padding: 0 0 0 5px;
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $secondary-border-color;
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
.node-diff-chevron {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.node-diff-node-entry-properties {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
table-layout:fixed;
|
||||
}
|
||||
td, th {
|
||||
border: 1px solid $secondary-border-color;
|
||||
padding: 3px 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td:nth-child(1) {
|
||||
width: 150px;
|
||||
}
|
||||
td:not(:first-child) {
|
||||
width: calc(50% - 150px);
|
||||
}
|
||||
}
|
||||
.node-diff-column {
|
||||
display:inline-block;
|
||||
height:100%;
|
||||
width:50%;
|
||||
box-sizing: border-box;
|
||||
white-space:nowrap;
|
||||
overflow: hidden;
|
||||
&:first-child {
|
||||
border-right: 1px solid $secondary-border-color
|
||||
}
|
||||
}
|
||||
.node-diff-tab-title {
|
||||
padding: 3px 3px 3px 0;
|
||||
background: #f6f6f6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.node-diff-node-entry-node {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
width: 24px;
|
||||
height: 20px;
|
||||
background: #ddd;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #999;
|
||||
background-position: 5% 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
position: relative;
|
||||
|
||||
.palette-icon {
|
||||
width: 16px;
|
||||
}
|
||||
.palette_icon_container {
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
.node-diff-node-entry-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
.node-diff-node-entry-properties {
|
||||
margin-left: 30px;
|
||||
margin-right: 8px;
|
||||
margin-bottom:8px;
|
||||
color: #666;
|
||||
}
|
||||
.node-diff-node-description {
|
||||
color: $form-text-color;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
padding-top: 5px;
|
||||
display: inline-block;
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.node-diff-count { color: #999}
|
||||
.node-diff-added { color: #009900}
|
||||
.node-diff-deleted { color: #f80000}
|
||||
.node-diff-changed { color: #f89406}
|
||||
.node-diff-conflicted { color: purple}
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
.red-ui-popover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
padding: 10px;
|
||||
height: auto;
|
||||
background: #fff;
|
||||
|
||||
z-index: 1000;
|
||||
font-size: 14px;
|
||||
line-height: 1.4em;
|
||||
@include component-shadow;
|
||||
}
|
||||
.red-ui-popover:after, .red-ui-popover:before {
|
||||
right: 100%;
|
||||
top: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.red-ui-popover:after {
|
||||
border-color: rgba(136, 183, 213, 0);
|
||||
border-right-color: #fff;
|
||||
border-width: 10px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.red-ui-popover:before {
|
||||
border-color: rgba(194, 225, 245, 0);
|
||||
border-right-color: $primary-border-color;
|
||||
border-width: 11px;
|
||||
margin-top: -11px;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
.sidebar-node-info hr {
|
||||
margin: 10px 0;
|
||||
}
|
||||
table.node-info {
|
||||
font-size: 14px;
|
||||
margin: 0px;
|
||||
width: 97%;
|
||||
}
|
||||
table.node-info tr {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
table.node-info tr.blank {
|
||||
border: none;
|
||||
}
|
||||
table.node-info tr.blank td {
|
||||
padding-top: 8px;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
padding-left: 0px;
|
||||
}
|
||||
table.node-info td:first-child{
|
||||
color: #666;
|
||||
vertical-align: top;
|
||||
width: 90px;
|
||||
padding: 3px;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
table.node-info td:last-child{
|
||||
padding-left: 5px;
|
||||
color: #666;
|
||||
}
|
||||
div.node-info {
|
||||
margin: 5px;
|
||||
}
|
||||
.node-info-property-header {
|
||||
color: #666;
|
||||
}
|
||||
.node-info-property-header:hover,
|
||||
.node-info-property-header:focus {
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
}
|
||||
.node-help {
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
font-size: 23px;
|
||||
margin: 8px auto;
|
||||
}
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
font-size: 18px;
|
||||
margin: 8px auto;
|
||||
}
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
margin: 8px auto;
|
||||
}
|
||||
h4,
|
||||
h5 {
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
margin: 8px auto;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
.red-ui-editableList-container {
|
||||
border: 1px solid $form-input-border-color;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
|
||||
.red-ui-editableList-list {
|
||||
list-style-type:none;
|
||||
margin: 0;
|
||||
}
|
||||
.red-ui-editabelList-item-placeholder {
|
||||
border: 2px dashed $secondary-border-color !important;
|
||||
}
|
||||
li {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
margin:0;
|
||||
padding:8px 0px;
|
||||
border-bottom: 1px solid $secondary-border-color;
|
||||
min-height: 20px;
|
||||
.red-ui-editableList-item-handle {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 2px;
|
||||
margin-top: -7px;
|
||||
color: #eee;
|
||||
cursor: move;
|
||||
}
|
||||
.red-ui-editableList-item-remove {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0px;
|
||||
margin-top: -9px;
|
||||
}
|
||||
&.ui-sortable-helper {
|
||||
border-top: 1px solid $secondary-border-color;
|
||||
}
|
||||
//.red-ui-editableList-item-content { outline: 1px solid red}
|
||||
|
||||
&.red-ui-editableList-item-sortable .red-ui-editableList-item-content {
|
||||
margin-left: 22px;
|
||||
}
|
||||
&.red-ui-editableList-item-removable .red-ui-editableList-item-content {
|
||||
margin-right: 28px;
|
||||
}
|
||||
&.red-ui-editableList-item-deleting {
|
||||
background: #fee;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<!--
|
||||
Copyright 2013, 2016 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<head>
|
||||
<title>{{ page.title }}</title>
|
||||
<link rel="icon" type="image/png" href="{{ page.favicon }}">
|
||||
<link rel="mask-icon" href="{{ page.tabicon }}" color="#8f0000">
|
||||
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<link href="vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="vendor/vendor.css">
|
||||
<link rel="stylesheet" href="red/style.min.css">
|
||||
{{#page.css}}
|
||||
<link rel="stylesheet" href="{{.}}">
|
||||
{{/page.css}}
|
||||
|
||||
</head>
|
||||
<body spellcheck="false">
|
||||
<div id="header">
|
||||
<span class="logo">{{#header.url}}<a href="{{.}}">{{/header.url}}{{#header.image}}<img src="{{.}}" title="{{version}}">{{/header.image}} <span>{{ header.title }}</span>{{#header.url}}</a>{{/header.url}}</span>
|
||||
<ul class="header-toolbar hide">
|
||||
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
|
||||
</ul>
|
||||
<div id="header-shade" class="hide"></div>
|
||||
</div>
|
||||
<div id="main-container" class="sidebar-closed hide">
|
||||
<div id="workspace">
|
||||
<ul id="workspace-tabs"></ul>
|
||||
<div id="chart" tabindex="1"></div>
|
||||
<div id="workspace-toolbar"></div>
|
||||
<div id="workspace-footer">
|
||||
<a class="workspace-footer-button" id="btn-zoom-out" href="#"><i class="fa fa-minus"></i></a>
|
||||
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
|
||||
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
||||
</div>
|
||||
<div id="editor-shade" class="hide"></div>
|
||||
</div>
|
||||
<div id="editor-stack"></div>
|
||||
<div id="palette">
|
||||
<img src="red/images/spin.svg" class="palette-spinner hide"/>
|
||||
<div id="palette-search" class="palette-search hide">
|
||||
<input type="text" data-i18n="[placeholder]palette.filter"></input>
|
||||
</div>
|
||||
<div id="palette-editor">
|
||||
<div class="editor-tray-header"><div class="editor-tray-titlebar"><ul class="editor-tray-breadcrumbs"><li data-i18n="palette.editor.title"></li></ul></div><div class="editor-tray-toolbar"><button id="palette-editor-close" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only primary" role="button" aria-disabled="false" data-i18n="common.label.done"></button></div></div>
|
||||
<ul id="palette-editor-tabs"></ul>
|
||||
</div>
|
||||
<div id="palette-container" class="palette-scroll hide"></div>
|
||||
<div id="palette-footer">
|
||||
<a class="palette-button" id="palette-collapse-all" href="#"><i class="fa fa-angle-double-up"></i></a>
|
||||
<a class="palette-button" id="palette-expand-all" href="#"><i class="fa fa-angle-double-down"></i></a>
|
||||
</div>
|
||||
<div id="palette-shade" class="hide"></div>
|
||||
</div><!-- /palette -->
|
||||
<div id="sidebar">
|
||||
<ul id="sidebar-tabs"></ul>
|
||||
<div id="sidebar-content"></div>
|
||||
<div id="sidebar-footer"></div>
|
||||
<div id="sidebar-shade" class="hide"></div>
|
||||
</div>
|
||||
|
||||
<div id="sidebar-separator"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="notifications"></div>
|
||||
<div id="dropTarget"><div data-i18n="[append]workspace.dropFlowHere"><br/><i class="fa fa-download"></i></div></div>
|
||||
|
||||
<div id="node-dialog-confirm-deploy" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div id="node-dialog-confirm-deploy-config" style="text-align: left; padding-top: 30px;" data-i18n="[prepend]deploy.confirm.improperlyConfigured;[append]deploy.confirm.confirm">
|
||||
<ul style="font-size: 0.9em; width: 400px; margin: 10px auto; text-align: left;" id="node-dialog-confirm-deploy-invalid-list"></ul>
|
||||
</div>
|
||||
<div id="node-dialog-confirm-deploy-unknown" style="text-align: left; padding-top: 10px;" data-i18n="[prepend]deploy.confirm.unknown;[append]deploy.confirm.confirm">
|
||||
<ul style="font-size: 0.9em; width: 400px; margin: 10px auto; text-align: left;" id="node-dialog-confirm-deploy-unknown-list"></ul>
|
||||
</div>
|
||||
<div id="node-dialog-confirm-deploy-conflict" style="text-align: left; padding-top: 10px;" data-i18n="[prepend]deploy.confirm.conflict;[append]deploy.confirm.confirm">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="node-dialog-view-diff" class="hide">
|
||||
<ol id="node-dialog-view-diff-diff"></ol>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-save-confirm" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div style="text-align: center; padding-top: 30px;" id="node-dialog-library-save-content">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-save" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<label for="node-dialog-library-save-folder" data-i18n="[append]library.folder"><i class="fa fa-folder-open"></i> </label>
|
||||
<input type="text" id="node-dialog-library-save-folder" data-i18n="[placeholder]library.folderPlaceholder">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-dialog-library-save-filename" data-i18n="[append]library.filename"><i class="fa fa-file"></i> </label>
|
||||
<input type="text" id="node-dialog-library-save-filename" data-i18n="[placeholder]library.filenamePlaceholder">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="node-dialog-library-lookup" class="hide">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-row">
|
||||
<ul id="node-dialog-library-breadcrumbs" class="breadcrumb">
|
||||
<li class="active"><a href="#" data-i18n="[append]library.breadcrumb"></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;">
|
||||
<div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div>
|
||||
</div>
|
||||
<div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;">
|
||||
<div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script type="text/x-red" data-template-name="subflow">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="subflow-template">
|
||||
<div class="form-row">
|
||||
<label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name">
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom: 0px;">
|
||||
<label for="subflow-input-info" data-i18n="subflow.info"></label>
|
||||
<a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div style="height: 250px;" class="node-text-editor" id="subflow-input-info-editor"></div>
|
||||
</div>
|
||||
<div class="form-row form-tips" id="subflow-dialog-user-count"></div>
|
||||
</script>
|
||||
|
||||
<script src="vendor/vendor.js"></script>
|
||||
<script src="vendor/ace/ace.js"></script>
|
||||
<script src="vendor/ace/ext-language_tools.js"></script>
|
||||
<script src="{{ asset.red }}"></script>
|
||||
<script src="{{ asset.main }}"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
15
editor/vendor/ace/ace.js
vendored
15
editor/vendor/ace/ace.js
vendored
File diff suppressed because one or more lines are too long
5
editor/vendor/ace/ext-language_tools.js
vendored
5
editor/vendor/ace/ext-language_tools.js
vendored
File diff suppressed because one or more lines are too long
5
editor/vendor/ace/ext-searchbox.js
vendored
5
editor/vendor/ace/ext-searchbox.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-css.js
vendored
1
editor/vendor/ace/mode-css.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-handlebars.js
vendored
1
editor/vendor/ace/mode-handlebars.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-html.js
vendored
1
editor/vendor/ace/mode-html.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-javascript.js
vendored
1
editor/vendor/ace/mode-javascript.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-json.js
vendored
1
editor/vendor/ace/mode-json.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-markdown.js
vendored
1
editor/vendor/ace/mode-markdown.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-properties.js
vendored
1
editor/vendor/ace/mode-properties.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/mode/properties_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e=/\\u[0-9a-fA-F]{4}|\\/;this.$rules={start:[{token:"comment",regex:/[!#].*$/},{token:"keyword",regex:/[=:]$/},{token:"keyword",regex:/[=:]/,next:"value"},{token:"constant.language.escape",regex:e},{defaultToken:"variable"}],value:[{regex:/\\$/,token:"string",next:"value"},{regex:/$/,token:"string",next:"start"},{token:"constant.language.escape",regex:e},{defaultToken:"string"}]}};r.inherits(s,i),t.PropertiesHighlightRules=s}),define("ace/mode/properties",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/properties_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./properties_highlight_rules").PropertiesHighlightRules,o=function(){this.HighlightRules=s};r.inherits(o,i),function(){this.$id="ace/mode/properties"}.call(o.prototype),t.Mode=o})
|
||||
1
editor/vendor/ace/mode-sql.js
vendored
1
editor/vendor/ace/mode-sql.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/mode/sql_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|when|else|end|type|left|right|join|on|outer|desc|asc|union|create|table|primary|key|if|foreign|not|references|default|null|inner|cross|natural|database|drop|grant",t="true|false",n="avg|count|first|last|max|min|sum|ucase|lcase|mid|len|round|rank|now|format|coalesce|ifnull|isnull|nvl",r="int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|money|real|number|integer",i=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t,"storage.type":r},"identifier",!0);this.$rules={start:[{token:"comment",regex:"--.*$"},{token:"comment",start:"/\\*",end:"\\*/"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:i,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]},this.normalizeRules()};r.inherits(s,i),t.SqlHighlightRules=s}),define("ace/mode/sql",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/sql_highlight_rules","ace/range"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./sql_highlight_rules").SqlHighlightRules,o=e("../range").Range,u=function(){this.HighlightRules=s};r.inherits(u,i),function(){this.lineCommentStart="--",this.$id="ace/mode/sql"}.call(u.prototype),t.Mode=u})
|
||||
1
editor/vendor/ace/mode-swift.js
vendored
1
editor/vendor/ace/mode-swift.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/mode-yaml.js
vendored
1
editor/vendor/ace/mode-yaml.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/mode/yaml_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"list.markup",regex:/^(?:-{3}|\.{3})\s*(?=#|$)/},{token:"list.markup",regex:/^\s*[\-?](?:$|\s)/},{token:"constant",regex:"!![\\w//]+"},{token:"constant.language",regex:"[&\\*][a-zA-Z0-9-_]+"},{token:["meta.tag","keyword"],regex:/^(\s*\w.*?)(:(?:\s+|$))/},{token:["meta.tag","keyword"],regex:/(\w+?)(\s*:(?:\s+|$))/},{token:"keyword.operator",regex:"<<\\w*:\\w*"},{token:"keyword.operator",regex:"-\\s*(?=[{])"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",regex:"[|>][-+\\d\\s]*$",next:"qqstring"},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"constant.numeric",regex:/(\b|[+\-\.])[\d_]+(?:(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)/},{token:"constant.numeric",regex:/[+\-]?\.inf\b|NaN\b|0x[\dA-Fa-f_]+|0b[10_]+/},{token:"constant.language.boolean",regex:"(?:true|false|TRUE|FALSE|True|False|yes|no)\\b"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"}],qqstring:[{token:"string",regex:"(?=(?:(?:\\\\.)|(?:[^:]))*?:)",next:"start"},{token:"string",regex:".+"}]}};r.inherits(s,i),t.YamlHighlightRules=s}),define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++n<f){o=e.getLine(n);var h=o.search(i);if(h==-1)continue;if(o[h]!="#")break;c=n}if(c>l){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<a?"start":"","";if(u==-1){if(i==a&&r[i]=="#"&&s[i]=="#")return e.foldWidgets[n-1]="",e.foldWidgets[n+1]="","start"}else if(u==i&&r[i]=="#"&&o[i]=="#"&&e.getLine(n-2).search(/\S/)==-1)return e.foldWidgets[n-1]="start",e.foldWidgets[n+1]="","";return u!=-1&&u<i?e.foldWidgets[n-1]="start":e.foldWidgets[n-1]="",i<a?"start":""}}.call(o.prototype)}),define("ace/mode/yaml",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/yaml_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./yaml_highlight_rules").YamlHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./folding/coffee").FoldMode,a=function(){this.HighlightRules=s,this.$outdent=new o,this.foldingRules=new u};r.inherits(a,i),function(){this.lineCommentStart="#",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(e=="start"){var i=t.match(/^.*[\{\(\[]\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/yaml"}.call(a.prototype),t.Mode=a})
|
||||
1
editor/vendor/ace/snippets/css.js
vendored
1
editor/vendor/ace/snippets/css.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/snippets/handlebars.js
vendored
1
editor/vendor/ace/snippets/handlebars.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/snippets/handlebars",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="handlebars"})
|
||||
1
editor/vendor/ace/snippets/html.js
vendored
1
editor/vendor/ace/snippets/html.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/snippets/javascript.js
vendored
1
editor/vendor/ace/snippets/javascript.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/snippets/javascript",["require","exports","module"],function(e,t,n){"use strict";t.snippetText='# Prototype\nsnippet proto\n ${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n ${4:// body...}\n };\n# Function\nsnippet fun\n function ${1?:function_name}(${2:argument}) {\n ${3:// body...}\n }\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n function${M1?: ${1:functionName}}($2) {\n ${0:$TM_SELECTED_TEXT}\n }${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n (function(${1}) {\n ${0:${TM_SELECTED_TEXT:/* code */}}\n }(${1}));\n# if\nsnippet if\n if (${1:true}) {\n ${0}\n }\n# if ... else\nsnippet ife\n if (${1:true}) {\n ${2}\n } else {\n ${0}\n }\n# tertiary conditional\nsnippet ter\n ${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n switch (${1:expression}) {\n case \'${3:case}\':\n ${4:// code}\n break;\n ${5}\n default:\n ${2:// code}\n }\n# case\nsnippet case\n case \'${1:case}\':\n ${2:// code}\n break;\n ${3}\n\n# while (...) {...}\nsnippet wh\n while (${1:/* condition */}) {\n ${0:/* code */}\n }\n# try\nsnippet try\n try {\n ${0:/* code */}\n } catch (e) {}\n# do...while\nsnippet do\n do {\n ${2:/* code */}\n } while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n ${1:method_name}: function(${2:attribute}) {\n ${0}\n }${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# Get Elements\nsnippet gett\n getElementsBy${1:TagName}(\'${2}\')${3}\n# Get Element\nsnippet get\n getElementBy${1:Id}(\'${2}\')${3}\n# console.log (Firebug)\nsnippet cl\n console.log(${1});\n# return\nsnippet ret\n return ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n for (var ${1:prop} in ${2:Things}) {\n ${0:$2[$1]}\n }\n# hasOwnProperty\nsnippet has\n hasOwnProperty(${1})\n# docstring\nsnippet /**\n /**\n * ${1:description}\n *\n */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n @param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n @return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n JSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n JSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n var ${1:function_name} = function(${2:argument}) {\n ${3:// initial code ...}\n\n $1 = function($2) {\n ${4:// main code}\n };\n }\n# singleton\nsnippet sing\n function ${1:Singleton} (${2:argument}) {\n // the cached instance\n var instance;\n\n // rewrite the constructor\n $1 = function $1($2) {\n return instance;\n };\n \n // carry over the prototype properties\n $1.prototype = this;\n\n // the instance\n instance = new $1();\n\n // reset the constructor pointer\n instance.constructor = $1;\n\n ${3:// code ...}\n\n return instance;\n }\n# class\nsnippet class\nregex /^\\s*/clas{0,2}/\n var ${1:class} = function(${20}) {\n $40$0\n };\n \n (function() {\n ${60:this.prop = ""}\n }).call(${1:class}.prototype);\n \n exports.${1:class} = ${1:class};\n# \nsnippet for-\n for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n ${0:${2:Things}[${1:i}];}\n }\n# for (...) {...}\nsnippet for\n for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n ${3:$2[$1]}$0\n }\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n ${3:$2[$1]}$0\n }\n\n\n#modules\nsnippet def\n define(function(require, exports, module) {\n "use strict";\n var ${1/.*\\///} = require("${1}");\n \n $TM_SELECTED_TEXT\n });\nsnippet req\nguard ^\\s*\n var ${1/.*\\///} = require("${1}");\n $0\nsnippet requ\nguard ^\\s*\n var ${1/.*\\/(.)/\\u$1/} = require("${1}").${1/.*\\/(.)/\\u$1/};\n $0\n',t.scope="javascript"})
|
||||
1
editor/vendor/ace/snippets/markdown.js
vendored
1
editor/vendor/ace/snippets/markdown.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/snippets/markdown",["require","exports","module"],function(e,t,n){"use strict";t.snippetText='# Markdown\n\n# Includes octopress (http://octopress.org/) snippets\n\nsnippet [\n [${1:text}](http://${2:address} "${3:title}")\nsnippet [*\n [${1:link}](${2:`@*`} "${3:title}")${4}\n\nsnippet [:\n [${1:id}]: http://${2:url} "${3:title}"\nsnippet [:*\n [${1:id}]: ${2:`@*`} "${3:title}"\n\nsnippet \nsnippet ${4}\n\nsnippet ![:\n ![${1:id}]: ${2:url} "${3:title}"\nsnippet ![:*\n ![${1:id}]: ${2:`@*`} "${3:title}"\n\nsnippet ===\nregex /^/=+/=*//\n ${PREV_LINE/./=/g}\n \n ${0}\nsnippet ---\nregex /^/-+/-*//\n ${PREV_LINE/./-/g}\n \n ${0}\nsnippet blockquote\n {% blockquote %}\n ${1:quote}\n {% endblockquote %}\n\nsnippet blockquote-author\n {% blockquote ${1:author}, ${2:title} %}\n ${3:quote}\n {% endblockquote %}\n\nsnippet blockquote-link\n {% blockquote ${1:author} ${2:URL} ${3:link_text} %}\n ${4:quote}\n {% endblockquote %}\n\nsnippet bt-codeblock-short\n ```\n ${1:code_snippet}\n ```\n\nsnippet bt-codeblock-full\n ``` ${1:language} ${2:title} ${3:URL} ${4:link_text}\n ${5:code_snippet}\n ```\n\nsnippet codeblock-short\n {% codeblock %}\n ${1:code_snippet}\n {% endcodeblock %}\n\nsnippet codeblock-full\n {% codeblock ${1:title} lang:${2:language} ${3:URL} ${4:link_text} %}\n ${5:code_snippet}\n {% endcodeblock %}\n\nsnippet gist-full\n {% gist ${1:gist_id} ${2:filename} %}\n\nsnippet gist-short\n {% gist ${1:gist_id} %}\n\nsnippet img\n {% img ${1:class} ${2:URL} ${3:width} ${4:height} ${5:title_text} ${6:alt_text} %}\n\nsnippet youtube\n {% youtube ${1:video_id} %}\n\n# The quote should appear only once in the text. It is inherently part of it.\n# See http://octopress.org/docs/plugins/pullquote/ for more info.\n\nsnippet pullquote\n {% pullquote %}\n ${1:text} {" ${2:quote} "} ${3:text}\n {% endpullquote %}\n',t.scope="markdown"})
|
||||
1
editor/vendor/ace/snippets/properties.js
vendored
1
editor/vendor/ace/snippets/properties.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/snippets/properties",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="properties"})
|
||||
1
editor/vendor/ace/snippets/text.js
vendored
1
editor/vendor/ace/snippets/text.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/snippets/text",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="text"})
|
||||
1
editor/vendor/ace/snippets/yaml.js
vendored
1
editor/vendor/ace/snippets/yaml.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/snippets/yaml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="yaml"})
|
||||
1
editor/vendor/ace/theme-chrome.js
vendored
1
editor/vendor/ace/theme-chrome.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/theme/chrome",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-chrome",t.cssText='.ace-chrome .ace_gutter {background: #ebebeb;color: #333;overflow : hidden;}.ace-chrome .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-chrome {background-color: #FFFFFF;color: black;}.ace-chrome .ace_cursor {color: black;}.ace-chrome .ace_invisible {color: rgb(191, 191, 191);}.ace-chrome .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-chrome .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-chrome .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-chrome .ace_invalid {background-color: rgb(153, 0, 0);color: white;}.ace-chrome .ace_fold {}.ace-chrome .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-chrome .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-chrome .ace_support.ace_type,.ace-chrome .ace_support.ace_class.ace-chrome .ace_support.ace_other {color: rgb(109, 121, 222);}.ace-chrome .ace_variable.ace_parameter {font-style:italic;color:#FD971F;}.ace-chrome .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-chrome .ace_comment {color: #236e24;}.ace-chrome .ace_comment.ace_doc {color: #236e24;}.ace-chrome .ace_comment.ace_doc.ace_tag {color: #236e24;}.ace-chrome .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-chrome .ace_variable {color: rgb(49, 132, 149);}.ace-chrome .ace_xml-pe {color: rgb(104, 104, 91);}.ace-chrome .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-chrome .ace_heading {color: rgb(12, 7, 255);}.ace-chrome .ace_list {color:rgb(185, 6, 144);}.ace-chrome .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-chrome .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-chrome .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-chrome .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-chrome .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-chrome .ace_gutter-active-line {background-color : #dcdcdc;}.ace-chrome .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-chrome .ace_storage,.ace-chrome .ace_keyword,.ace-chrome .ace_meta.ace_tag {color: rgb(147, 15, 128);}.ace-chrome .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-chrome .ace_string {color: #1A1AA6;}.ace-chrome .ace_entity.ace_other.ace_attribute-name {color: #994409;}.ace-chrome .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})
|
||||
1
editor/vendor/ace/theme-tomorrow.js
vendored
1
editor/vendor/ace/theme-tomorrow.js
vendored
@@ -1 +0,0 @@
|
||||
define("ace/theme/tomorrow",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-tomorrow",t.cssText=".ace-tomorrow .ace_gutter {background: #f6f6f6;color: #4D4D4C}.ace-tomorrow .ace_print-margin {width: 1px;background: #f6f6f6}.ace-tomorrow {background-color: #FFFFFF;color: #4D4D4C}.ace-tomorrow .ace_cursor {color: #AEAFAD}.ace-tomorrow .ace_marker-layer .ace_selection {background: #D6D6D6}.ace-tomorrow.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #FFFFFF;}.ace-tomorrow .ace_marker-layer .ace_step {background: rgb(255, 255, 0)}.ace-tomorrow .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #D1D1D1}.ace-tomorrow .ace_marker-layer .ace_active-line {background: #EFEFEF}.ace-tomorrow .ace_gutter-active-line {background-color : #dcdcdc}.ace-tomorrow .ace_marker-layer .ace_selected-word {border: 1px solid #D6D6D6}.ace-tomorrow .ace_invisible {color: #D1D1D1}.ace-tomorrow .ace_keyword,.ace-tomorrow .ace_meta,.ace-tomorrow .ace_storage,.ace-tomorrow .ace_storage.ace_type,.ace-tomorrow .ace_support.ace_type {color: #8959A8}.ace-tomorrow .ace_keyword.ace_operator {color: #3E999F}.ace-tomorrow .ace_constant.ace_character,.ace-tomorrow .ace_constant.ace_language,.ace-tomorrow .ace_constant.ace_numeric,.ace-tomorrow .ace_keyword.ace_other.ace_unit,.ace-tomorrow .ace_support.ace_constant,.ace-tomorrow .ace_variable.ace_parameter {color: #F5871F}.ace-tomorrow .ace_constant.ace_other {color: #666969}.ace-tomorrow .ace_invalid {color: #FFFFFF;background-color: #C82829}.ace-tomorrow .ace_invalid.ace_deprecated {color: #FFFFFF;background-color: #8959A8}.ace-tomorrow .ace_fold {background-color: #4271AE;border-color: #4D4D4C}.ace-tomorrow .ace_entity.ace_name.ace_function,.ace-tomorrow .ace_support.ace_function,.ace-tomorrow .ace_variable {color: #4271AE}.ace-tomorrow .ace_support.ace_class,.ace-tomorrow .ace_support.ace_type {color: #C99E00}.ace-tomorrow .ace_heading,.ace-tomorrow .ace_markup.ace_heading,.ace-tomorrow .ace_string {color: #718C00}.ace-tomorrow .ace_entity.ace_name.ace_tag,.ace-tomorrow .ace_entity.ace_other.ace_attribute-name,.ace-tomorrow .ace_meta.ace_tag,.ace-tomorrow .ace_string.ace_regexp,.ace-tomorrow .ace_variable {color: #C82829}.ace-tomorrow .ace_comment {color: #8E908C}.ace-tomorrow .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bdu3f/BwAlfgctduB85QAAAABJRU5ErkJggg==) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})
|
||||
1
editor/vendor/ace/worker-html.js
vendored
1
editor/vendor/ace/worker-html.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/worker-javascript.js
vendored
1
editor/vendor/ace/worker-javascript.js
vendored
File diff suppressed because one or more lines are too long
1
editor/vendor/ace/worker-json.js
vendored
1
editor/vendor/ace/worker-json.js
vendored
File diff suppressed because one or more lines are too long
26
jsdoc.json
Normal file
26
jsdoc.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"opts": {
|
||||
"template": "./node_modules/jsdoc-nr-template",
|
||||
"destination": "./docs",
|
||||
"recurse": true
|
||||
},
|
||||
"tags": {
|
||||
"allowUnknownTags": false,
|
||||
"dictionaries": ["jsdoc"]
|
||||
},
|
||||
"source": {
|
||||
"_include": [
|
||||
"./packages/node_modules/@node-red/runtime/lib/api"
|
||||
]
|
||||
},
|
||||
"templates": {
|
||||
"systemName": "Node-RED Runtime API",
|
||||
"theme":"yeti",
|
||||
"footer": "",
|
||||
"copyright": "Released under the Apache License v2.0",
|
||||
"default": {
|
||||
"outputSourceFiles": false
|
||||
}
|
||||
},
|
||||
"plugins": ["plugins/markdown"]
|
||||
}
|
||||
1
lib/.gitignore
vendored
1
lib/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
*
|
||||
@@ -1,50 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="sentiment">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>Analyses the <code>msg.payload</code> and adds a <code>msg.sentiment</code> object
|
||||
that contains the resulting AFINN-111 sentiment score as <code>msg.sentiment.score</code>.</p>
|
||||
<p>A score greater than zero is positive and less than zero is negative.</p>
|
||||
<p>The score typically ranges from -5 to +5, but can go higher and lower.</p>
|
||||
<p>An object of word score overrides can be supplied as <code>msg.overrides</code>.</p>
|
||||
<p>See <a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('sentiment',{
|
||||
category: 'analysis-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "arrow-in.png",
|
||||
label: function() {
|
||||
return this.name||"sentiment";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var sentiment = require('sentiment');
|
||||
|
||||
function SentimentNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
if (msg.hasOwnProperty("payload")) {
|
||||
sentiment(msg.payload, msg.overrides || null, function (err, result) {
|
||||
msg.sentiment = result;
|
||||
node.send(msg);
|
||||
});
|
||||
}
|
||||
else { node.send(msg); } // If no payload - just pass it on.
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("sentiment",SentimentNode);
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var cron = require("cron");
|
||||
|
||||
function InjectNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.topic = n.topic;
|
||||
this.payload = n.payload;
|
||||
this.payloadType = n.payloadType;
|
||||
this.repeat = n.repeat;
|
||||
this.crontab = n.crontab;
|
||||
this.once = n.once;
|
||||
var node = this;
|
||||
this.interval_id = null;
|
||||
this.cronjob = null;
|
||||
|
||||
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
|
||||
this.repeat = this.repeat * 1000;
|
||||
if (RED.settings.verbose) { this.log(RED._("inject.repeat",this)); }
|
||||
this.interval_id = setInterval( function() {
|
||||
node.emit("input",{});
|
||||
}, this.repeat );
|
||||
} else if (this.crontab) {
|
||||
if (RED.settings.verbose) { this.log(RED._("inject.crontab",this)); }
|
||||
this.cronjob = new cron.CronJob(this.crontab,
|
||||
function() {
|
||||
node.emit("input",{});
|
||||
},
|
||||
null,true);
|
||||
}
|
||||
|
||||
if (this.once) {
|
||||
setTimeout( function() { node.emit("input",{}); }, 100 );
|
||||
}
|
||||
|
||||
this.on("input",function(msg) {
|
||||
try {
|
||||
msg.topic = this.topic;
|
||||
if ( (this.payloadType == null && this.payload === "") || this.payloadType === "date") {
|
||||
msg.payload = Date.now();
|
||||
} else if (this.payloadType == null) {
|
||||
msg.payload = this.payload;
|
||||
} else if (this.payloadType == 'none') {
|
||||
msg.payload = "";
|
||||
} else {
|
||||
msg.payload = RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg);
|
||||
}
|
||||
this.send(msg);
|
||||
msg = null;
|
||||
} catch(err) {
|
||||
this.error(err,msg);
|
||||
}
|
||||
});
|
||||
this.on('close', function() {
|
||||
if (node.interval_id != null) {
|
||||
clearInterval(node.interval_id);
|
||||
if (RED.settings.verbose) { node.log(RED._("inject.stopped")); }
|
||||
} else if (node.cronjob != null) {
|
||||
node.cronjob.stop();
|
||||
if (RED.settings.verbose) { node.log(RED._("inject.stopped")); }
|
||||
delete node.cronjob;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("inject",InjectNode);
|
||||
|
||||
RED.httpAdmin.post("/inject/:id", RED.auth.needsPermission("inject.write"), function(req,res) {
|
||||
var node = RED.nodes.getNode(req.params.id);
|
||||
if (node != null) {
|
||||
try {
|
||||
node.receive();
|
||||
res.sendStatus(200);
|
||||
} catch(err) {
|
||||
res.sendStatus(500);
|
||||
node.error(RED._("inject.failed",{error:err.toString()}));
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var util = require("util");
|
||||
var events = require("events");
|
||||
var path = require("path");
|
||||
var debuglength = RED.settings.debugMaxLength||1000;
|
||||
var useColors = false;
|
||||
// util.inspect.styles.boolean = "red";
|
||||
|
||||
function DebugNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.name = n.name;
|
||||
this.complete = (n.complete||"payload").toString();
|
||||
|
||||
if (this.complete === "false") {
|
||||
this.complete = "payload";
|
||||
}
|
||||
|
||||
this.console = n.console;
|
||||
this.active = (n.active === null || typeof n.active === "undefined") || n.active;
|
||||
var node = this;
|
||||
|
||||
this.on("input",function(msg) {
|
||||
if (this.complete === "true") {
|
||||
// debug complete msg object
|
||||
if (this.console === "true") {
|
||||
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
|
||||
}
|
||||
if (this.active) {
|
||||
sendDebug({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path});
|
||||
}
|
||||
} else {
|
||||
// debug user defined msg property
|
||||
var property = "payload";
|
||||
var output = msg[property];
|
||||
if (this.complete !== "false" && typeof this.complete !== "undefined") {
|
||||
property = this.complete;
|
||||
try {
|
||||
output = RED.util.getMessageProperty(msg,this.complete);
|
||||
} catch(err) {
|
||||
output = undefined;
|
||||
}
|
||||
}
|
||||
if (this.console === "true") {
|
||||
if (typeof output === "string") {
|
||||
node.log((output.indexOf("\n") !== -1 ? "\n" : "") + output);
|
||||
} else if (typeof output === "object") {
|
||||
node.log("\n"+util.inspect(output, {colors:useColors, depth:10}));
|
||||
} else {
|
||||
node.log(util.inspect(output, {colors:useColors}));
|
||||
}
|
||||
}
|
||||
if (this.active) {
|
||||
sendDebug({id:this.id,z:this.z,name:this.name,topic:msg.topic,property:property,msg:output,_path:msg._path});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("debug",DebugNode);
|
||||
|
||||
function sendDebug(msg) {
|
||||
if (msg.msg instanceof Error) {
|
||||
msg.format = "error";
|
||||
msg.msg = msg.msg.toString();
|
||||
} else if (msg.msg instanceof Buffer) {
|
||||
msg.format = "buffer["+msg.msg.length+"]";
|
||||
msg.msg = msg.msg.toString('hex');
|
||||
if (msg.msg.length > debuglength) {
|
||||
msg.msg = msg.msg.substring(0,debuglength);
|
||||
}
|
||||
} else if (msg.msg && typeof msg.msg === 'object') {
|
||||
var seen = [];
|
||||
try {
|
||||
msg.format = msg.msg.constructor.name || "Object";
|
||||
} catch(err) {
|
||||
msg.format = "Object";
|
||||
}
|
||||
if (/error/i.test(msg.format)) {
|
||||
msg.msg = JSON.stringify({
|
||||
name: msg.msg.name,
|
||||
message: msg.msg.message
|
||||
});
|
||||
} else {
|
||||
var isArray = util.isArray(msg.msg);
|
||||
if (isArray) {
|
||||
msg.format = "array["+msg.msg.length+"]";
|
||||
if (msg.msg.length > debuglength) {
|
||||
msg.msg = msg.msg.slice(0,debuglength);
|
||||
}
|
||||
}
|
||||
if (isArray || (msg.format === "Object")) {
|
||||
msg.msg = JSON.stringify(msg.msg, function(key, value) {
|
||||
if (key[0] === '_' && key !== "_msgid") {
|
||||
return undefined;
|
||||
}
|
||||
if (key === '_req' || key === '_res') {
|
||||
return "[internal]"
|
||||
}
|
||||
if (value instanceof Error) {
|
||||
return value.toString()
|
||||
}
|
||||
if (util.isArray(value) && value.length > debuglength) {
|
||||
value = {
|
||||
type: "array",
|
||||
data: value.slice(0,debuglength),
|
||||
length: value.length
|
||||
}
|
||||
}
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (seen.indexOf(value) !== -1) { return "[circular]"; }
|
||||
seen.push(value);
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
if (value.length > debuglength) {
|
||||
return value.substring(0,debuglength)+"...";
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}," ");
|
||||
} else {
|
||||
try { msg.msg = msg.msg.toString(); }
|
||||
catch(e) { msg.msg = "[Type not printable]"; }
|
||||
}
|
||||
}
|
||||
seen = null;
|
||||
} else if (typeof msg.msg === "boolean") {
|
||||
msg.format = "boolean";
|
||||
msg.msg = msg.msg.toString();
|
||||
} else if (typeof msg.msg === "number") {
|
||||
msg.format = "number";
|
||||
msg.msg = msg.msg.toString();
|
||||
} else if (msg.msg === 0) {
|
||||
msg.format = "number";
|
||||
msg.msg = "0";
|
||||
} else if (msg.msg === null || typeof msg.msg === "undefined") {
|
||||
msg.format = (msg.msg === null)?"null":"undefined";
|
||||
msg.msg = "(undefined)";
|
||||
} else {
|
||||
msg.format = "string["+msg.msg.length+"]";
|
||||
if (msg.msg.length > debuglength) {
|
||||
msg.msg = msg.msg.substring(0,debuglength)+"...";
|
||||
}
|
||||
}
|
||||
// if (msg.msg.length > debuglength) {
|
||||
// msg.msg = msg.msg.substr(0,debuglength) +" ....";
|
||||
// }
|
||||
RED.comms.publish("debug",msg);
|
||||
}
|
||||
|
||||
DebugNode.logHandler = new events.EventEmitter();
|
||||
DebugNode.logHandler.on("log",function(msg) {
|
||||
if (msg.level === RED.log.WARN || msg.level === RED.log.ERROR) {
|
||||
sendDebug(msg);
|
||||
}
|
||||
});
|
||||
RED.log.addHandler(DebugNode.logHandler);
|
||||
|
||||
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
|
||||
var node = RED.nodes.getNode(req.params.id);
|
||||
var state = req.params.state;
|
||||
if (node !== null && typeof node !== "undefined" ) {
|
||||
if (state === "enable") {
|
||||
node.active = true;
|
||||
res.sendStatus(200);
|
||||
} else if (state === "disable") {
|
||||
node.active = false;
|
||||
res.sendStatus(201);
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
RED.httpAdmin.get("/debug/view/*",RED.auth.needsPermission("debug.read"),function(req,res) {
|
||||
var options = {
|
||||
root: __dirname + '/lib/debug/',
|
||||
dotfiles: 'deny'
|
||||
};
|
||||
res.sendFile(req.params[0], options);
|
||||
});
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013,2015 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="exec">
|
||||
<div class="form-row">
|
||||
<label for="node-input-command"><i class="fa fa-file"></i> <span data-i18n="exec.label.command"></span></label>
|
||||
<input type="text" id="node-input-command" data-i18n="[placeholder]exec.label.command">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-plus"></i> <span data-i18n="exec.label.append"></span></label>
|
||||
<input type="checkbox" id="node-input-addpay" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
msg.payload
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-append"> </label>
|
||||
<input type="text" id="node-input-append" data-i18n="[placeholder]exec.placeholder.extraparams">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-useSpawn" placeholder="spawn" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-useSpawn" style="width:70%;"><span data-i18n="exec.spawn"></span></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-timer"><i class="fa fa-clock-o"></i> <span data-i18n="exec.label.timeout"></span></label>
|
||||
<input type="text" id="node-input-timer" style="width:65px;" data-i18n="[placeholder]exec.label.timeoutplace"> seconds
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="exec">
|
||||
<p>Calls out to a system command.<br/></p>
|
||||
<p>Provides 3 outputs: stdout, stderr, and return code.</p>
|
||||
<p>By default uses the <code>exec</code> system call which calls the command, then gets a callback
|
||||
on completion, returning the complete result in one message, along with any errors.</p>
|
||||
<p>Optionally can use <code>spawn</code> instead, which returns the output from stdout and stderr
|
||||
as the command runs (usually one line at a time). On completion it then returns a return code
|
||||
(on the 3rd output).</p>
|
||||
<p>The optional append gets added to the command after <code>msg.payload</code> - so you can do
|
||||
things like pipe the result to another command.</p>
|
||||
<p>Parameters with spaces should be enclosed in quotes - <i>"This is a single parameter"</i></p>
|
||||
<p>If stdout is binary a <i>buffer</i> is returned - otherwise returns a <i>string</i>.</p>
|
||||
<p>The blue status icon will be visible while the node is active.</p>
|
||||
<p>If running a Python app you may need to use the <code>-u</code> parameter to stop the output being buffered.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('exec',{
|
||||
category: 'advanced-function',
|
||||
color:"darksalmon",
|
||||
defaults: {
|
||||
command: {value:"",required:true},
|
||||
addpay: {value:true},
|
||||
append: {value:""},
|
||||
useSpawn: {value:""},
|
||||
timer: {value:""},
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:3,
|
||||
icon: "arrow-in.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.command;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013,2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var spawn = require('child_process').spawn;
|
||||
var exec = require('child_process').exec;
|
||||
var isUtf8 = require('is-utf8');
|
||||
|
||||
function ExecNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.cmd = (n.command || "").trim();
|
||||
if (n.addpay === undefined) { n.addpay = true; }
|
||||
this.addpay = n.addpay;
|
||||
this.append = (n.append || "").trim();
|
||||
this.useSpawn = n.useSpawn;
|
||||
this.timer = Number(n.timer || 0)*1000;
|
||||
this.activeProcesses = {};
|
||||
var node = this;
|
||||
|
||||
var cleanup = function(p) {
|
||||
node.activeProcesses[p].kill();
|
||||
node.status({fill:"red",shape:"dot",text:"timeout"});
|
||||
node.error("Exec node timeout");
|
||||
}
|
||||
|
||||
this.on("input", function(msg) {
|
||||
var child;
|
||||
node.status({fill:"blue",shape:"dot",text:" "});
|
||||
if (this.useSpawn === true) {
|
||||
// make the extra args into an array
|
||||
// then prepend with the msg.payload
|
||||
var arg = node.cmd;
|
||||
if ((node.addpay === true) && msg.hasOwnProperty("payload")) { arg += " "+msg.payload; }
|
||||
if (node.append.trim() !== "") { arg += " "+node.append; }
|
||||
// slice whole line by spaces (trying to honour quotes);
|
||||
arg = arg.match(/(?:[^\s"]+|"[^"]*")+/g);
|
||||
var cmd = arg.shift();
|
||||
/* istanbul ignore else */
|
||||
if (RED.settings.verbose) { node.log(cmd+" ["+arg+"]"); }
|
||||
child = spawn(cmd,arg);
|
||||
var unknownCommand = (child.pid === undefined);
|
||||
if (node.timer !== 0) {
|
||||
child.tout = setTimeout(function() { cleanup(child.pid); }, node.timer);
|
||||
}
|
||||
node.activeProcesses[child.pid] = child;
|
||||
child.stdout.on('data', function (data) {
|
||||
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
|
||||
// console.log('[exec] stdout: ' + data,child.pid);
|
||||
if (isUtf8(data)) { msg.payload = data.toString(); }
|
||||
else { msg.payload = data; }
|
||||
node.send([RED.util.cloneMessage(msg),null,null]);
|
||||
}
|
||||
});
|
||||
child.stderr.on('data', function (data) {
|
||||
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
|
||||
if (isUtf8(data)) { msg.payload = data.toString(); }
|
||||
else { msg.payload = new Buffer(data); }
|
||||
node.send([null,RED.util.cloneMessage(msg),null]);
|
||||
}
|
||||
});
|
||||
child.on('close', function (code) {
|
||||
if (unknownCommand || (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null)) {
|
||||
delete node.activeProcesses[child.pid];
|
||||
if (child.tout) { clearTimeout(child.tout); }
|
||||
msg.payload = code;
|
||||
if (code === 0) { node.status({}); }
|
||||
if (code === null) { node.status({fill:"red",shape:"dot",text:"timeout"}); }
|
||||
else if (code < 0) { node.status({fill:"red",shape:"dot",text:"rc: "+code}); }
|
||||
else { node.status({fill:"yellow",shape:"dot",text:"rc: "+code}); }
|
||||
node.send([null,null,RED.util.cloneMessage(msg)]);
|
||||
}
|
||||
});
|
||||
child.on('error', function (code) {
|
||||
if (child.tout) { clearTimeout(child.tout); }
|
||||
delete node.activeProcesses[child.pid];
|
||||
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
|
||||
node.error(code,RED.util.cloneMessage(msg));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
var cl = node.cmd;
|
||||
if ((node.addpay === true) && msg.hasOwnProperty("payload")) { cl += " "+msg.payload; }
|
||||
if (node.append.trim() !== "") { cl += " "+node.append; }
|
||||
/* istanbul ignore else */
|
||||
if (RED.settings.verbose) { node.log(cl); }
|
||||
child = exec(cl, {encoding: 'binary', maxBuffer:10000000}, function (error, stdout, stderr) {
|
||||
msg.payload = new Buffer(stdout,"binary");
|
||||
if (isUtf8(msg.payload)) { msg.payload = msg.payload.toString(); }
|
||||
var msg2 = {payload:stderr};
|
||||
var msg3 = null;
|
||||
//console.log('[exec] stdout: ' + stdout);
|
||||
//console.log('[exec] stderr: ' + stderr);
|
||||
if (error !== null) {
|
||||
msg3 = {payload:error};
|
||||
//console.log('[exec] error: ' + error);
|
||||
}
|
||||
node.status({});
|
||||
node.send([msg,msg2,msg3]);
|
||||
if (child.tout) { clearTimeout(child.tout); }
|
||||
delete node.activeProcesses[child.pid];
|
||||
});
|
||||
child.on('error',function() {});
|
||||
if (node.timer !== 0) {
|
||||
child.tout = setTimeout(function() { cleanup(child.pid); }, node.timer);
|
||||
}
|
||||
node.activeProcesses[child.pid] = child;
|
||||
}
|
||||
});
|
||||
this.on('close',function() {
|
||||
for (var pid in node.activeProcesses) {
|
||||
/* istanbul ignore else */
|
||||
if (node.activeProcesses.hasOwnProperty(pid)) {
|
||||
if (node.activeProcesses[pid].tout) { clearTimeout(node.activeProcesses[pid].tout); }
|
||||
// console.log("KILLLING",pid);
|
||||
var process = node.activeProcesses[pid];
|
||||
node.activeProcesses[pid] = null;
|
||||
process.kill();
|
||||
}
|
||||
}
|
||||
node.activeProcesses = {};
|
||||
node.status({});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("exec",ExecNode);
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
|
||||
/**
|
||||
* Custom Mustache Context capable to resolve message property and node
|
||||
* flow and global context
|
||||
*/
|
||||
function NodeContext(msg, nodeContext) {
|
||||
this.msgContext = new mustache.Context(msg);
|
||||
this.nodeContext = nodeContext;
|
||||
}
|
||||
|
||||
NodeContext.prototype = new mustache.Context();
|
||||
|
||||
NodeContext.prototype.lookup = function (name) {
|
||||
// try message first:
|
||||
var value = this.msgContext.lookup(name);
|
||||
if (value !== undefined) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// try node context:
|
||||
var dot = name.indexOf(".");
|
||||
if (dot > 0) {
|
||||
var contextName = name.substr(0, dot);
|
||||
var variableName = name.substr(dot + 1);
|
||||
|
||||
if (contextName === "flow" && this.nodeContext.flow) {
|
||||
return this.nodeContext.flow.get(variableName);
|
||||
}
|
||||
else if (contextName === "global" && this.nodeContext.global) {
|
||||
return this.nodeContext.global.get(variableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function TemplateNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.name = n.name;
|
||||
this.field = n.field || "payload";
|
||||
this.template = n.template;
|
||||
this.syntax = n.syntax || "mustache";
|
||||
this.fieldType = n.fieldType || "msg";
|
||||
|
||||
var node = this;
|
||||
node.on("input", function(msg) {
|
||||
try {
|
||||
var value;
|
||||
if (node.syntax === "mustache") {
|
||||
value = mustache.render(node.template, new NodeContext(msg, node.context()));
|
||||
} else {
|
||||
value = node.template;
|
||||
}
|
||||
if (node.fieldType === 'msg') {
|
||||
RED.util.setMessageProperty(msg,node.field,value);
|
||||
} else if (node.fieldType === 'flow') {
|
||||
node.context().flow.set(node.field,value);
|
||||
} else if (node.fieldType === 'global') {
|
||||
node.context().global.set(node.field,value);
|
||||
}
|
||||
node.send(msg);
|
||||
} catch(err) {
|
||||
node.error(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("template",TemplateNode);
|
||||
RED.library.register("templates");
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="delay">
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-pauseType"><i class="fa fa-tasks"></i> <span data-i18n="delay.action"></span></label>
|
||||
<select id="node-input-pauseType" style="width:270px !important">
|
||||
<option value="delay" data-i18n="delay.delaymsg"></option>
|
||||
<option value="random" data-i18n="delay.randomdelay"></option>
|
||||
<option value="rate" data-i18n="delay.limitrate"></option>
|
||||
<option value="queue" data-i18n="delay.fairqueue"></option>
|
||||
<option value="timed" data-i18n="delay.timedqueue"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="delay-details" class="form-row">
|
||||
<label for="node-input-timeout"><i class="fa fa-clock-o"></i> <span data-i18n="delay.for"></span></label>
|
||||
<input type="text" id="node-input-timeout" placeholder="Time" style="text-align:end; width:50px !important">
|
||||
<select id="node-input-timeoutUnits" style="width:200px !important">
|
||||
<option value="milliseconds" data-i18n="delay.milisecs"></option>
|
||||
<option value="seconds" data-i18n="delay.secs"></option>
|
||||
<option value="minutes" data-i18n="delay.mins"></option>
|
||||
<option value="hours" data-i18n="delay.hours"></option>
|
||||
<option value="days" data-i18n="delay.days"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="rate-details" class="form-row">
|
||||
<label for="node-input-rate"><i class="fa fa-clock-o"></i> <span data-i18n="delay.rate"></span></label>
|
||||
<input type="text" id="node-input-rate" placeholder="1" style="text-align:end; width:30px !important">
|
||||
<label for="node-input-rateUnits"><span data-i18n="delay.msgper"></span></label>
|
||||
<input type="text" id="node-input-nbRateUnits" placeholder="1" style="text-align:end; width:30px !important">
|
||||
<select id="node-input-rateUnits" style="width:110px !important">
|
||||
<option value="second" data-i18n="delay.label.units.second.singular"></option>
|
||||
<option value="minute" data-i18n="delay.label.units.minute.singular"></option>
|
||||
<option value="hour" data-i18n="delay.label.units.hour.singular"></option>
|
||||
<option value="day" data-i18n="delay.label.units.day.singular"></option>
|
||||
</select>
|
||||
<br/>
|
||||
<div id="node-input-dr"><input style="margin: 20px 0 20px 100px; width: 30px;" type="checkbox" id="node-input-drop"><label style="width: 250px;" for="node-input-drop"><span data-i18n="delay.dropmsg"></span></label></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="random-details" class="form-row">
|
||||
<label for="node-input-randomFirst"><i class="fa fa-clock-o"></i> <span data-i18n="delay.between"></span></label>
|
||||
<input type="text" id="node-input-randomFirst" placeholder="" style="text-align:end; width:30px !important">
|
||||
&
|
||||
<input type="text" id="node-input-randomLast" placeholder="" style="text-align:end; width:30px !important">
|
||||
<select id="node-input-randomUnits" style="width:140px !important">
|
||||
<option value="milliseconds" data-i18n="delay.milisecs"></option>
|
||||
<option value="seconds" data-i18n="delay.secs"></option>
|
||||
<option value="minutes" data-i18n="delay.mins"></option>
|
||||
<option value="hours" data-i18n="delay.hours"></option>
|
||||
<option value="days" data-i18n="delay.days"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="delay">
|
||||
<p>Introduces a delay into a flow or rate limits messages.</p>
|
||||
<p>The default delay is 5 seconds and rate limit of 1 msg/second, but both can be configured.</p>
|
||||
<p>When set to rate limit messages, they are spread across the configured time period. It can
|
||||
also be set to discard any intermediate messages that arrive.</p>
|
||||
<p>The "topic based fair queue" adds messages to a release queue tagged by their <code>msg.topic</code> property.
|
||||
At each "tick", derived from the rate, the next "topic" is released.
|
||||
Any messages arriving on the same topic before release replace those in that position in the queue.
|
||||
So each "topic" gets a turn - but the most recent value is always the one sent.</p>
|
||||
<p>The "timed release queue" adds messages to an array based on their <code>msg.topic</code> property.
|
||||
At each "tick", all the latest messages are released. Any new messages arriving before release will
|
||||
replace those of the same topic.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('delay',{
|
||||
category: 'function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
pauseType: {value:"delay", required:true},
|
||||
timeout: {value:"5", required:true, validate:RED.validators.number()},
|
||||
timeoutUnits: {value:"seconds"},
|
||||
rate: {value:"1", required:true, validate:RED.validators.number()},
|
||||
nbRateUnits: {value:"1", required:false, validate:RED.validators.regex(/\d+|/)},
|
||||
rateUnits: {value: "second"},
|
||||
randomFirst: {value:"1", required:true, validate:RED.validators.number()},
|
||||
randomLast: {value:"5", required:true, validate:RED.validators.number()},
|
||||
randomUnits: {value: "seconds"},
|
||||
drop: {value:false}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "timer.png",
|
||||
label: function() {
|
||||
if (this.pauseType == "delay") {
|
||||
var units = this.timeoutUnits ? this.timeoutUnits.charAt(0) : "s";
|
||||
if (this.timeoutUnits == "milliseconds") { units = "ms"; }
|
||||
return this.name||this._("delay.label.delay")+" "+this.timeout+" "+units;
|
||||
} else if (this.pauseType == "rate") {
|
||||
var units = this.rateUnits ? (this.nbRateUnits > 1 ? this.nbRateUnits : '') + this.rateUnits.charAt(0) : "s";
|
||||
return this.name||this._("delay.label.limit")+" "+this.rate+" msg/"+units;
|
||||
} else if (this.pauseType == "random") {
|
||||
return this.name || this._("delay.label.random");
|
||||
}
|
||||
else if (this.pauseType == "timed") {
|
||||
var units = '';
|
||||
if (this.nbRateUnits > 1) {
|
||||
units = this.nbRateUnits + ' ' + this._("delay.label.units." + this.rateUnits + ".plural");
|
||||
} else {
|
||||
units = this._("delay.label.units." + this.rateUnits + ".singular");
|
||||
}
|
||||
return this.name || this.rate + " " + this._("delay.label.timed") + ' ' + units;
|
||||
}
|
||||
else {
|
||||
var units = this.rateUnits ? (this.nbRateUnits > 1 ? this.nbRateUnits : '') + this.rateUnits.charAt(0) : "s";
|
||||
return this.name || this._("delay.label.queue")+" "+this.rate+" msg/"+units;
|
||||
}
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var node = this;
|
||||
$( "#node-input-timeout" ).spinner({min:1});
|
||||
$( "#node-input-rate" ).spinner({min:1});
|
||||
$( "#node-input-nbRateUnits" ).spinner({min:1});
|
||||
|
||||
$( "#node-input-randomFirst" ).spinner({min:0});
|
||||
$( "#node-input-randomLast" ).spinner({min:1});
|
||||
|
||||
$('.ui-spinner-button').click(function() {
|
||||
$(this).siblings('input').change();
|
||||
});
|
||||
|
||||
$( "#node-input-nbRateUnits" ).on('change keyup', function() {
|
||||
var $this = $(this);
|
||||
var val = parseInt($this.val());
|
||||
var type = "singular";
|
||||
if(val > 1) {
|
||||
type = "plural";
|
||||
}
|
||||
if($this.attr("data-type") == type) {
|
||||
return;
|
||||
}
|
||||
$this.attr("data-type", type);
|
||||
$("#node-input-rateUnits option").each(function () {
|
||||
var $option = $(this);
|
||||
var key = "delay.label.units." + $option.val() + "." + type;
|
||||
$option.attr('data-i18n', 'node-red:' + key);
|
||||
$option.html(node._(key));
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (this.pauseType == "delay") {
|
||||
$("#delay-details").show();
|
||||
$("#rate-details").hide();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").hide();
|
||||
} else if (this.pauseType == "rate") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").show();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").show();
|
||||
} else if (this.pauseType == "random") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").hide();
|
||||
$("#random-details").show();
|
||||
$("#node-input-dr").hide();
|
||||
} else if (this.pauseType == "queue") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").show();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").hide();
|
||||
} else if (this.pauseType == "timed") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").show();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").hide();
|
||||
}
|
||||
|
||||
if (!this.timeoutUnits) {
|
||||
$("#node-input-timeoutUnits option").filter(function() {
|
||||
return $(this).val() == 'seconds';
|
||||
}).attr('selected', true);
|
||||
}
|
||||
|
||||
if (!this.randomUnits) {
|
||||
$("#node-input-randomUnits option").filter(function() {
|
||||
return $(this).val() == 'seconds';
|
||||
}).attr('selected', true);
|
||||
}
|
||||
|
||||
$("#node-input-pauseType").on("change",function() {
|
||||
if (this.value == "delay") {
|
||||
$("#delay-details").show();
|
||||
$("#rate-details").hide();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").hide();
|
||||
} else if (this.value == "rate") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").show();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").show();
|
||||
} else if (this.value == "random") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").hide();
|
||||
$("#random-details").show();
|
||||
$("#node-input-dr").hide();
|
||||
} else if (this.value == "queue") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").show();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").hide();
|
||||
} else if (this.value == "timed") {
|
||||
$("#delay-details").hide();
|
||||
$("#rate-details").show();
|
||||
$("#random-details").hide();
|
||||
$("#node-input-dr").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var mustache = require("mustache");
|
||||
function TriggerNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.op1 = n.op1 || "1";
|
||||
this.op2 = n.op2 || "0";
|
||||
this.op1type = n.op1type || "str";
|
||||
this.op2type = n.op2type || "str";
|
||||
|
||||
if (this.op1type === 'val') {
|
||||
if (this.op1 === 'true' || this.op1 === 'false') {
|
||||
this.op1type = 'bool'
|
||||
} else if (this.op1 === 'null') {
|
||||
this.op1type = 'null';
|
||||
this.op1 = null;
|
||||
} else {
|
||||
this.op1type = 'str';
|
||||
}
|
||||
}
|
||||
if (this.op2type === 'val') {
|
||||
if (this.op2 === 'true' || this.op2 === 'false') {
|
||||
this.op2type = 'bool'
|
||||
} else if (this.op2 === 'null') {
|
||||
this.op2type = 'null';
|
||||
this.op2 = null;
|
||||
} else {
|
||||
this.op2type = 'str';
|
||||
}
|
||||
}
|
||||
this.extend = n.extend || "false";
|
||||
this.units = n.units || "ms";
|
||||
this.reset = n.reset || '';
|
||||
this.duration = n.duration || 250;
|
||||
if (this.duration <= 0) { this.duration = 0; }
|
||||
else {
|
||||
if (this.units == "s") { this.duration = this.duration * 1000; }
|
||||
if (this.units == "min") { this.duration = this.duration * 1000 * 60; }
|
||||
if (this.units == "hr") { this.duration = this.duration * 1000 *60 * 60; }
|
||||
}
|
||||
this.op1Templated = (this.op1type === 'str' && this.op1.indexOf("{{") != -1);
|
||||
this.op2Templated = (this.op2type === 'str' && this.op2.indexOf("{{") != -1);
|
||||
if ((this.op1type === "num") && (!isNaN(this.op1))) { this.op1 = Number(this.op1); }
|
||||
if ((this.op2type === "num") && (!isNaN(this.op2))) { this.op2 = Number(this.op2); }
|
||||
if (this.op1 == "null") { this.op1 = null; }
|
||||
if (this.op2 == "null") { this.op2 = null; }
|
||||
//try { this.op1 = JSON.parse(this.op1); }
|
||||
//catch(e) { this.op1 = this.op1; }
|
||||
//try { this.op2 = JSON.parse(this.op2); }
|
||||
//catch(e) { this.op2 = this.op2; }
|
||||
|
||||
var node = this;
|
||||
var tout = null;
|
||||
var m2;
|
||||
this.on("input", function(msg) {
|
||||
if (msg.hasOwnProperty("reset") || ((node.reset !== '')&&(msg.payload == node.reset)) ) {
|
||||
clearTimeout(tout);
|
||||
tout = null;
|
||||
node.status({});
|
||||
}
|
||||
else {
|
||||
if ((!tout) && (tout !== 0)) {
|
||||
if (node.op2type === "pay" || node.op2type === "payl") { m2 = msg.payload; }
|
||||
else if (node.op2Templated) { m2 = mustache.render(node.op2,msg); }
|
||||
else if (node.op2type !== "nul") {
|
||||
m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
|
||||
if (node.op1type === "pay") { }
|
||||
else if (node.op1Templated) { msg.payload = mustache.render(node.op1,msg); }
|
||||
else if (node.op1type !== "nul") {
|
||||
msg.payload = RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg);
|
||||
}
|
||||
|
||||
if (node.op1type !== "nul") { node.send(msg); }
|
||||
|
||||
if (node.duration === 0) { tout = 0; }
|
||||
else {
|
||||
tout = setTimeout(function() {
|
||||
if (node.op2type !== "nul") {
|
||||
var msg2 = RED.util.cloneMessage(msg);
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
msg2.payload = m2;
|
||||
node.send(msg2);
|
||||
}
|
||||
tout = null;
|
||||
node.status({});
|
||||
},node.duration);
|
||||
}
|
||||
node.status({fill:"blue",shape:"dot",text:" "});
|
||||
}
|
||||
else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) {
|
||||
clearTimeout(tout);
|
||||
if (node.op2type === "payl") { m2 = msg.payload; }
|
||||
tout = setTimeout(function() {
|
||||
if (node.op2type !== "nul") {
|
||||
var msg2 = RED.util.cloneMessage(msg);
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
msg2.payload = m2;
|
||||
node.send(msg2);
|
||||
}
|
||||
tout = null;
|
||||
node.status({});
|
||||
},node.duration);
|
||||
} else {
|
||||
if (node.op2type === "payl") { m2 = msg.payload; }
|
||||
}
|
||||
}
|
||||
});
|
||||
this.on("close", function() {
|
||||
if (tout) {
|
||||
clearTimeout(tout);
|
||||
}
|
||||
node.status({});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("trigger",TriggerNode);
|
||||
}
|
||||
@@ -1,544 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
if (!RED) {
|
||||
var RED = {}
|
||||
}
|
||||
RED.debug = (function() {
|
||||
var config;
|
||||
var messageList;
|
||||
var messageTable;
|
||||
var debuggerView;
|
||||
var filter = false;
|
||||
var view = 'list';
|
||||
var messages = [];
|
||||
var messagesByNode = {};
|
||||
var sbc;
|
||||
var activeWorkspace;
|
||||
var breakpointList;
|
||||
|
||||
var debuggerEnabled = false;
|
||||
|
||||
function init(_config) {
|
||||
config = _config;
|
||||
var content = $("<div>").css({"position":"relative","height":"100%"});
|
||||
var toolbar = $('<div class="sidebar-header">'+
|
||||
'<span class="button-group" style="float: left"><button id="debug-tab-view-console" class="sidebar-header-button-toggle selected">console</button><button id="debug-tab-view-debugger" class="sidebar-header-button-toggle">debugger</button></span>'+
|
||||
'<span class="debug-tab-view-console-buttons">'+
|
||||
'<span class="button-group"><button id="debug-tab-filter" class="sidebar-header-button"><i class="fa fa-filter"></i></button></span>'+
|
||||
'<span class="button-group"><button id="debug-tab-clear" title="clear log" class="sidebar-header-button"><i class="fa fa-trash"></i></button></span>'+
|
||||
'</span>'+
|
||||
'<span class="debug-tab-view-dbgr-buttons hide">'+
|
||||
'<span class="button-group"><button id="debug-tab-dbgr-toggle" class="sidebar-header-button"><i class="fa fa-toggle-off"></i></button></span>'+
|
||||
'</span>'+
|
||||
'</div>').appendTo(content);
|
||||
|
||||
var footerToolbar = $('<div>'+
|
||||
// '<span class="button-group">'+
|
||||
// '<a class="sidebar-footer-button-toggle text-button selected" id="debug-tab-view-list" href="#"><span data-i18n="">list</span></a>'+
|
||||
// '<a class="sidebar-footer-button-toggle text-button" id="debug-tab-view-table" href="#"><span data-i18n="">table</span></a> '+
|
||||
// '</span>'+
|
||||
'<span class="button-group"><button id="debug-tab-open" title="open in new window" class="sidebar-footer-button"><i class="fa fa-desktop"></i></button></span> ' +
|
||||
'</div>');
|
||||
|
||||
messageList = $('<div class="debug-content debug-content-list"/>').appendTo(content);
|
||||
sbc = messageList[0];
|
||||
messageTable = $('<div class="debug-content debug-content-table hide"/>').appendTo(content);
|
||||
|
||||
var filterDialog = $('<div class="debug-filter-box hide">'+
|
||||
'<div class="debug-filter-row">'+
|
||||
'<span class="button-group">'+
|
||||
'<button class="sidebar-header-button-toggle selected" id="debug-tab-filter-all"><span data-i18n="node-red:debug.sidebar.filterAll">all flows</span></button>'+
|
||||
'<button class="sidebar-header-button-toggle" id="debug-tab-filter-current"><span data-i18n="node-red:debug.sidebar.filterCurrent">current flow</span></button> '+
|
||||
'</span>'+
|
||||
'</div>'+
|
||||
'</div>').appendTo(content);
|
||||
|
||||
|
||||
|
||||
debuggerView = $('<div class="debug-content hide"/>').appendTo(content);
|
||||
|
||||
var dbgrDisabled = $('<div class="debug-content debug-dbgr-content debug-dbgr-content-disabled">Debugger is disabled</div>').appendTo(debuggerView);
|
||||
var dbgrPanel = $('<div class="debug-content debug-dbgr-content"></div>').hide().appendTo(debuggerView);
|
||||
|
||||
var dbgrToolbar = $('<div class="sidebar-header" style="text-align:left">'+
|
||||
'<span>'+
|
||||
'<button id="" class="sidebar-header-button"><i class="fa fa-pause"></i></button>'+
|
||||
'<button id="" class="sidebar-header-button"><i class="fa fa-play"></i></button>'+
|
||||
'<button id="" class="sidebar-header-button"><i class="fa fa-step-forward"></i></button>'+
|
||||
'</span>'+
|
||||
'</div>').appendTo(dbgrPanel);
|
||||
|
||||
/************ Breakpoints ************/
|
||||
|
||||
var breakpointPanel = $('<div class="palette-category">'+
|
||||
'<div class="palette-header">'+
|
||||
'<i class="fa fa-angle-down expanded"></i>'+
|
||||
'<span>Breakpoints</span>'+
|
||||
'<span id="debug-dbgr-breakpoint-count" class="config-node-filter-info"></span>'+
|
||||
'</div>'+
|
||||
'</div>').appendTo(dbgrPanel);
|
||||
|
||||
|
||||
|
||||
var breakPointContent = $('<div>',{class:"palette-content debug-dbgr-breakpoints"}).appendTo(breakpointPanel);
|
||||
|
||||
// var buttonGroup = $('<div>').css({position:"absolute", right: 0,top:0}).appendTo(breakPointContent);
|
||||
// $('<button class="editor-button editor-button-small"><i class="fa fa-plus"></i> breakpoint</button>')
|
||||
// .click(function(evt) {
|
||||
// breakpointList.editableList('addItem',{});
|
||||
// })
|
||||
// .appendTo(buttonGroup);
|
||||
|
||||
var emptyItem = {};
|
||||
|
||||
breakpointList = $("<ol>").css({height: "200px"}).appendTo(breakPointContent).editableList({
|
||||
addButton: false,
|
||||
addItem: function(container,i,breakpoint) {
|
||||
if (breakpoint === emptyItem) {
|
||||
$('<div>',{class:"red-ui-search-empty"}).html('Double click on a port to add a breakpoint').appendTo(container);
|
||||
return;
|
||||
}
|
||||
var currentCount = breakpointList.find('.debug-dbgr-breakpoint').length;
|
||||
if (currentCount === 0) {
|
||||
console.log("out with the old")
|
||||
breakpointList.editableList('removeItem',emptyItem);
|
||||
}
|
||||
var id = "breakpoint_"+breakpoint.key;
|
||||
var label = $('<label>',{for:id}).appendTo(container);
|
||||
var cb = $('<input class="debug-dbgr-breakpoint" id="'+id+'" type="checkbox" checked></input>').appendTo(label);
|
||||
|
||||
|
||||
$('<span>').html(RED.utils.getNodeLabel(breakpoint.node,breakpoint.node.id)).appendTo(label);
|
||||
|
||||
var workspace = RED.nodes.workspace(breakpoint.node.z);
|
||||
if (!workspace) {
|
||||
workspace = RED.nodes.subflow(breakpoint.node.z);
|
||||
workspace = "subflow:"+workspace.name;
|
||||
} else {
|
||||
workspace = "flow:"+workspace.label;
|
||||
}
|
||||
var flowMeta = $('<div>',{class:"red-ui-search-result-node-flow"}).appendTo(label);
|
||||
|
||||
$('<div>').html(workspace).appendTo(flowMeta);
|
||||
$('<div>').html((breakpoint.portType === 0?"output":"input")+" "+(breakpoint.portIndex+1)).appendTo(flowMeta);
|
||||
|
||||
|
||||
$('<div>',{class:"red-ui-search-result-node-type"}).html(breakpoint.node.type).appendTo(label);
|
||||
|
||||
//+" : "+breakpoint.portType+" : "+breakpoint.portIndex).appendTo(label);
|
||||
cb.on('change',function(evt) {
|
||||
if ($(this).is(":checked")) {
|
||||
delete breakpoint.disabled;
|
||||
} else {
|
||||
breakpoint.disabled = true;
|
||||
}
|
||||
breakpoint.node.dirty = true;
|
||||
RED.view.redraw();
|
||||
refreshBreakpointCount();
|
||||
});
|
||||
label.on('mouseenter',function() {
|
||||
config.messageMouseEnter(breakpoint.node.id);
|
||||
});
|
||||
label.on('mouseleave',function() {
|
||||
config.messageMouseLeave(breakpoint.node.id);
|
||||
});
|
||||
refreshBreakpointCount();
|
||||
console.log(breakpointList.editableList('length'));
|
||||
},
|
||||
removeItem: function(breakpoint) {
|
||||
refreshBreakpointCount();
|
||||
if (breakpoint !== emptyItem) {
|
||||
var currentCount = breakpointList.find('.debug-dbgr-breakpoint').length;
|
||||
if (currentCount === 0) {
|
||||
breakpointList.editableList('addItem',emptyItem);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
breakpointList.editableList('addItem',emptyItem);
|
||||
|
||||
|
||||
|
||||
/************ Something else ************/
|
||||
|
||||
$('<div class="palette-category">'+
|
||||
'<div class="palette-header">'+
|
||||
'<i class="fa fa-angle-down expanded"></i>'+
|
||||
'<span>Messages</span>'+
|
||||
'</div>'+
|
||||
'<div class="palette-content"></div>'+
|
||||
'</div>').appendTo(dbgrPanel);
|
||||
|
||||
/************ Something else ************/
|
||||
|
||||
$('<div class="palette-category">'+
|
||||
'<div class="palette-header">'+
|
||||
'<i class="fa fa-angle-down expanded"></i>'+
|
||||
'<span>Context</span>'+
|
||||
'</div>'+
|
||||
'<div class="palette-content"></div>'+
|
||||
'</div>').appendTo(dbgrPanel);
|
||||
|
||||
|
||||
/****************************************/
|
||||
|
||||
|
||||
try {
|
||||
content.i18n();
|
||||
} catch(err) {
|
||||
console.log("TODO: i18n library support");
|
||||
}
|
||||
|
||||
dbgrPanel.find(".palette-header").on('click', function(e) {
|
||||
var icon = $(this).find("i");
|
||||
var content = $(this).next();
|
||||
if (icon.hasClass("expanded")) {
|
||||
icon.removeClass("expanded");
|
||||
content.slideUp();
|
||||
} else {
|
||||
icon.addClass("expanded");
|
||||
content.slideDown();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
toolbar.find('#debug-tab-filter-all').on("click",function(e) {
|
||||
e.preventDefault();
|
||||
if (filter) {
|
||||
$(this).addClass('selected');
|
||||
$('#debug-tab-filter-current').removeClass('selected');
|
||||
filter = !filter;
|
||||
refreshMessageList();
|
||||
}
|
||||
});
|
||||
toolbar.find('#debug-tab-filter-current').on("click",function(e) {
|
||||
e.preventDefault();
|
||||
if (!filter) {
|
||||
$(this).addClass('selected');
|
||||
$('#debug-tab-filter-all').removeClass('selected');
|
||||
filter = !filter;
|
||||
refreshMessageList();
|
||||
}
|
||||
});
|
||||
// $('#debug-tab-view-list').on("click",function(e) {
|
||||
// e.preventDefault();
|
||||
// if (!$(this).hasClass('selected')) {
|
||||
// $(this).addClass('selected');
|
||||
// $('#debug-tab-view-table').removeClass('selected');
|
||||
// showMessageList();
|
||||
// }
|
||||
// });
|
||||
// $('#debug-tab-view-table').on("click",function(e) {
|
||||
// e.preventDefault();
|
||||
// if (!$(this).hasClass('selected')) {
|
||||
// $(this).addClass('selected');
|
||||
// $('#debug-tab-view-list').removeClass('selected');
|
||||
// showMessageTable();
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
toolbar.find('#debug-tab-filter').on("click",function(e) {
|
||||
e.preventDefault();
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected');
|
||||
filterDialog.slideUp(200);
|
||||
} else {
|
||||
$(this).addClass('selected');
|
||||
filterDialog.slideDown(200);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
toolbar.find('#debug-tab-view-debugger').on("click",function(e) {
|
||||
if ($(messageList).is(":visible")) {
|
||||
messageList.hide();
|
||||
debuggerView.show();
|
||||
toolbar.find(".debug-tab-view-console-buttons").hide();
|
||||
toolbar.find(".debug-tab-view-dbgr-buttons").show();
|
||||
$(this).siblings().removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
|
||||
}
|
||||
});
|
||||
toolbar.find('#debug-tab-view-console').on("click",function(e) {
|
||||
if ($(debuggerView).is(":visible")) {
|
||||
messageList.show();
|
||||
debuggerView.hide();
|
||||
toolbar.find(".debug-tab-view-console-buttons").show();
|
||||
toolbar.find(".debug-tab-view-dbgr-buttons").hide();
|
||||
$(this).siblings().removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
toolbar.find('#debug-tab-dbgr-toggle').on("click",function(e) {
|
||||
var i = $(this).find("i");
|
||||
if (i.hasClass('fa-toggle-off')) {
|
||||
i.addClass('fa-toggle-on');
|
||||
i.removeClass('fa-toggle-off');
|
||||
dbgrPanel.show();
|
||||
dbgrDisabled.hide();
|
||||
debuggerEnabled = true;
|
||||
} else {
|
||||
i.addClass('fa-toggle-off');
|
||||
i.removeClass('fa-toggle-on');
|
||||
dbgrPanel.hide();
|
||||
dbgrDisabled.show();
|
||||
debuggerEnabled = false;
|
||||
}
|
||||
RED.view.redraw(true);
|
||||
})
|
||||
|
||||
|
||||
toolbar.find("#debug-tab-clear").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(".debug-message").remove();
|
||||
messageCount = 0;
|
||||
config.clear();
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
content: content,
|
||||
footer: footerToolbar
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getTimestamp() {
|
||||
var d = new Date();
|
||||
return d.toLocaleString();
|
||||
}
|
||||
|
||||
function sanitize(m) {
|
||||
return m.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
|
||||
}
|
||||
|
||||
function refreshMessageList(_activeWorkspace) {
|
||||
if (_activeWorkspace) {
|
||||
activeWorkspace = _activeWorkspace;
|
||||
}
|
||||
$(".debug-message").each(function() {
|
||||
$(this).toggleClass('hide',filter&&!$(this).hasClass('debug-message-flow-'+activeWorkspace));
|
||||
});
|
||||
}
|
||||
function refreshMessageTable() {
|
||||
|
||||
}
|
||||
|
||||
function showMessageList() {
|
||||
view = 'list';
|
||||
messageTable.hide();
|
||||
messageTable.empty();
|
||||
|
||||
messages.forEach(function(m) {
|
||||
messageList.append(m.el);
|
||||
})
|
||||
messageList.show();
|
||||
}
|
||||
function showMessageTable() {
|
||||
view = 'table';
|
||||
messageList.hide();
|
||||
messageList.empty();
|
||||
|
||||
Object.keys(messagesByNode).forEach(function(id) {
|
||||
var m = messagesByNode[id];
|
||||
var msg = m.el;
|
||||
var sourceNode = m.source;
|
||||
if (sourceNode) {
|
||||
var wrapper = $("<div>",{id:"debug-message-source-"+sourceNode.id.replace(/\./g,"_")}).appendTo(messageTable);
|
||||
wrapper.append(msg);
|
||||
}
|
||||
});
|
||||
messageTable.show();
|
||||
}
|
||||
function formatString(str) {
|
||||
return str.replace(/\n/g,"↵").replace(/\t/g,"→");
|
||||
}
|
||||
|
||||
function handleDebugMessage(o) {
|
||||
var msg = document.createElement("div");
|
||||
|
||||
var sourceNode = o._source;
|
||||
|
||||
msg.onmouseenter = function() {
|
||||
msg.style.borderRightColor = "#999";
|
||||
if (o._source) {
|
||||
config.messageMouseEnter(o._source.id);
|
||||
}
|
||||
};
|
||||
msg.onmouseleave = function() {
|
||||
msg.style.borderRightColor = "";
|
||||
if (o._source) {
|
||||
config.messageMouseLeave(o._source.id);
|
||||
}
|
||||
};
|
||||
var name = sanitize(((o.name?o.name:o.id)||"").toString());
|
||||
var topic = sanitize((o.topic||"").toString());
|
||||
var property = sanitize(o.property?o.property:'');
|
||||
var payload = sanitize((o.msg||"").toString());
|
||||
var format = sanitize((o.format||"").toString());
|
||||
msg.className = 'debug-message'+(o.level?(' debug-message-level-'+o.level):'') +
|
||||
((sourceNode&&sourceNode.z)?((" debug-message-flow-"+sourceNode.z+((filter&&(activeWorkspace!==sourceNode.z))?" hide":""))):"");
|
||||
var metaRow = $('<div class="debug-message-meta"></div>').appendTo(msg);
|
||||
$('<span class="debug-message-date">'+ getTimestamp()+'</span>').appendTo(metaRow);
|
||||
if (sourceNode) {
|
||||
$('<a>',{href:"#",class:"debug-message-name"}).html('node: '+sourceNode.id)
|
||||
.appendTo(metaRow)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
config.messageSourceClick(sourceNode.id);
|
||||
});
|
||||
} else if (name) {
|
||||
$('<span class="debug-message-name">'+name+'</span>').appendTo(metaRow);
|
||||
}
|
||||
// NOTE: relying on function error to have a "type" that all other msgs don't
|
||||
if (o.hasOwnProperty("type") && (o.type === "function")) {
|
||||
var errorLvlType = 'error';
|
||||
var errorLvl = 20;
|
||||
if (o.hasOwnProperty("level") && o.level === 30) {
|
||||
errorLvl = 30;
|
||||
errorLvlType = 'warn';
|
||||
}
|
||||
$(msg).addClass('debug-message-level-' + errorLvl);
|
||||
$('<span class="debug-message-topic">function : (' + errorLvlType + ')</span>').appendTo(metaRow);
|
||||
} else {
|
||||
$('<span class="debug-message-topic">'+
|
||||
(o.topic?topic+' : ':'')+
|
||||
(o.property?'msg.'+property:'msg')+" : "+format+
|
||||
'</span>').appendTo(metaRow);
|
||||
}
|
||||
if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number'||/error/i.test(format) ) {
|
||||
payload = JSON.parse(payload);
|
||||
} else if (format === 'null') {
|
||||
payload = null;
|
||||
} else if (format === 'undefined') {
|
||||
payload = undefined;
|
||||
} else if (/^buffer/.test(format)) {
|
||||
var buffer = payload;
|
||||
payload = [];
|
||||
for (var c = 0; c < buffer.length; c += 2) {
|
||||
payload.push(parseInt(buffer.substr(c, 2), 16));
|
||||
}
|
||||
}
|
||||
var el = $('<span class="debug-message-payload"></span>').appendTo(msg);
|
||||
RED.utils.createObjectElement(payload,/*true*/null,format).appendTo(el);
|
||||
var atBottom = (sbc.scrollHeight-messageList.height()-sbc.scrollTop) < 5;
|
||||
var m = {
|
||||
el: msg
|
||||
};
|
||||
messages.push(m);
|
||||
if (sourceNode) {
|
||||
m.source = sourceNode;
|
||||
messagesByNode[sourceNode.id] = m;
|
||||
}
|
||||
if (view == "list") {
|
||||
messageList.append(msg);
|
||||
} else {
|
||||
if (sourceNode) {
|
||||
var wrapper = $("#debug-message-source-"+sourceNode.id.replace(/\./g,"_"));
|
||||
if (wrapper.length === 0 ) {
|
||||
wrapper = $("<div>",{id:"debug-message-source-"+sourceNode.id.replace(/\./g,"_")}).appendTo(messageTable);
|
||||
}
|
||||
wrapper.empty();
|
||||
wrapper.append(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (messages.length === 100) {
|
||||
m = messages.shift();
|
||||
if (view === "list") {
|
||||
m.el.remove();
|
||||
}
|
||||
}
|
||||
if (atBottom) {
|
||||
messageList.scrollTop(sbc.scrollHeight);
|
||||
}
|
||||
}
|
||||
|
||||
var breakpoints = {};
|
||||
|
||||
function getBreakpointKey(node,portType,portIndex) {
|
||||
return (node.id+"_"+portType+"_"+portIndex).replace(/\./,"_");
|
||||
}
|
||||
function toggleBreakpoint(node,portType,portIndex) {
|
||||
if (!debuggerEnabled) {
|
||||
return false;
|
||||
}
|
||||
var key = getBreakpointKey(node,portType,portIndex);
|
||||
if (breakpoints.hasOwnProperty(key)) {
|
||||
node.dirty = true;
|
||||
if (breakpoints[key].disabled) {
|
||||
delete breakpoints[key].disabled;
|
||||
$("#breakpoint_"+key).prop('checked',true);
|
||||
refreshBreakpointCount();
|
||||
return true;
|
||||
} else {
|
||||
breakpointList.editableList('removeItem',breakpoints[key]);
|
||||
delete breakpoints[key];
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
breakpoints[key] = {
|
||||
key: key,
|
||||
node: node,
|
||||
portType: portType,
|
||||
portIndex: portIndex
|
||||
}
|
||||
breakpointList.editableList('addItem',breakpoints[key]);
|
||||
node.dirty = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function checkBreakpoint(node,portType,portIndex) {
|
||||
var key = getBreakpointKey(node,portType,portIndex);
|
||||
return debuggerEnabled && breakpoints.hasOwnProperty(key) && !breakpoints[key].disabled;
|
||||
}
|
||||
function refreshBreakpointCount() {
|
||||
var total = 0;
|
||||
var checked = 0;
|
||||
breakpointList.find('.debug-dbgr-breakpoint').each(function() {
|
||||
total++;
|
||||
if ($(this).is(":checked")) {
|
||||
checked++;
|
||||
}
|
||||
});
|
||||
var label = "";
|
||||
if (total > 0) {
|
||||
if (total === checked) {
|
||||
label = total;
|
||||
} else {
|
||||
label = checked+"/"+total;
|
||||
}
|
||||
}
|
||||
$("#debug-dbgr-breakpoint-count").html(label);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
init: init,
|
||||
refreshMessageList:refreshMessageList,
|
||||
handleDebugMessage: handleDebugMessage,
|
||||
toggleBreakpoint: toggleBreakpoint,
|
||||
checkBreakpoint: checkBreakpoint
|
||||
}
|
||||
})();
|
||||
@@ -1,28 +0,0 @@
|
||||
$(function() {
|
||||
var options = {
|
||||
messageMouseEnter: function(sourceId) {
|
||||
window.opener.postMessage({event:"mouseEnter",id:sourceId},'*');
|
||||
},
|
||||
messageMouseLeave: function(sourceId) {
|
||||
window.opener.postMessage({event:"mouseLeave",id:sourceId},'*');
|
||||
},
|
||||
messageSourceClick: function(sourceId) {
|
||||
window.opener.postMessage({event:"mouseClick",id:sourceId},'*');
|
||||
},
|
||||
clear: function() {
|
||||
window.opener.postMessage({event:"clear"},'*');
|
||||
}
|
||||
}
|
||||
|
||||
var uiComponents = RED.debug.init(options);
|
||||
|
||||
$(".debug-window").append(uiComponents.content);
|
||||
|
||||
window.addEventListener('message',function(evt) {
|
||||
if (evt.data.event === "message") {
|
||||
RED.debug.handleDebugMessage(evt.data.msg);
|
||||
} else if (evt.data.event === "workspaceChange") {
|
||||
RED.debug.refreshMessageList(evt.data.activeWorkspace);
|
||||
}
|
||||
},false);
|
||||
});
|
||||
@@ -1,408 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013,2014 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-gpio in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.label.gpiopin"></span></label>
|
||||
<select type="text" id="node-input-pin" style="width: 250px;">
|
||||
<option value='' disabled selected style='display:none;'><span data-i18n="rpi-gpio.label.selectpin"></span></option>
|
||||
<!-- <option value="3">Pin 3 - SDA1 - BCM2</option> -->
|
||||
<!-- <option value="5">Pin 5 - SCL1 - BCM3</option> -->
|
||||
<option value="7">Pin 7 - GPIO4</option>
|
||||
<!-- <option value="8">Pin 8 - TxD - BCM14</option> -->
|
||||
<!-- <option value="10">Pin 10 - RxD - BCM15</option> -->
|
||||
<option value="11">Pin 11 - GPIO17</option>
|
||||
<option value="12">Pin 12 - GPIO18</option>
|
||||
<option value="13">Pin 13 - GPIO27</option>
|
||||
<option value="15">Pin 15 - GPIO22</option>
|
||||
<option value="16">Pin 16 - GPIO23</option>
|
||||
<option value="18">Pin 18 - GPIO24</option>
|
||||
<!-- <option value="19">Pin 19 - MOSI - BCM10</option> -->
|
||||
<!-- <option value="21">Pin 21 - MISO - BCM9</option> -->
|
||||
<option value="22">Pin 22 - GPIO25</option>
|
||||
<!-- <option value="23">Pin 23 - SCLK - BCM11</option> -->
|
||||
<!-- <option value="24">Pin 24 - CE0 - BCM8</option> -->
|
||||
<!-- <option value="26">Pin 26 - CE1 - BCM7</option> -->
|
||||
</select>
|
||||
<span id="pitype"></span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-intype"><i class="fa fa-level-up"></i> <span data-i18n="rpi-gpio.label.resistor"></span></label>
|
||||
<select type="text" id="node-input-intype" style="width:100px;">
|
||||
<option value="tri" data-i18n="rpi-gpio.resistor.none"></option>
|
||||
<option value="up" data-i18n="rpi-gpio.resistor.pullup"></option>
|
||||
<option value="down" data-i18n="rpi-gpio.resistor.pulldown"></option>
|
||||
</select>
|
||||
<span data-i18n="rpi-gpio.label.debounce"></span>
|
||||
<input type="text" id="node-input-debounce" style="width:47px; text-align:right"/> mS
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-read" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-read" style="width:70%;"><span data-i18n="rpi-gpio.label.readinitial"></span></label>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-tips" id="pin-tip"><span data-i18n="[html]rpi-gpio.tip.pin"></span></div>
|
||||
<div class="form-tips"><span data-i18n="[html]rpi-gpio.tip.in"></span></div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="rpi-gpio in">
|
||||
<p>Raspberry Pi input node. Generates a <code>msg.payload</code> with either a
|
||||
0 or 1 depending on the state of the input pin.</p>
|
||||
<p>You may also enable the input pullup resistor or the pulldown resistor.</p>
|
||||
<p>The <code>msg.topic</code> is set to <i>pi/{the pin number}</i></p>
|
||||
<p>Requires the RPi.GPIO python library version 0.5.10 (or better) in order to work.</p>
|
||||
<p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var pinsInUse = {};
|
||||
RED.nodes.registerType('rpi-gpio in',{
|
||||
category: 'Raspberry Pi',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:"" },
|
||||
pin: { value:"tri",required:true,validate:RED.validators.number() },
|
||||
intype: { value:"in" },
|
||||
debounce: { value:"25" },
|
||||
read: { value:false }
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "rpi.png",
|
||||
info: function() {
|
||||
if ( Object.keys(pinsInUse).length !== 0 ) {
|
||||
return "**Pins in use** : "+Object.keys(pinsInUse);
|
||||
}
|
||||
else { return ""; }
|
||||
},
|
||||
label: function() {
|
||||
return this.name || "Pin: "+this.pin ;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var pinnow = this.pin;
|
||||
var pintip = this._("rpi-gpio.tip.pin");
|
||||
var pinname = this._("rpi-gpio.pinname");
|
||||
var alreadyuse = this._("rpi-gpio.alreadyuse");
|
||||
var alreadyset = this._("rpi-gpio.alreadyset");
|
||||
$.getJSON('rpi-gpio/'+this.id,function(data) {
|
||||
$('#pitype').text(data.type);
|
||||
if ((data.type !== "Model B") && (data.type !== "Model A")) {
|
||||
//$('#node-input-pin').append($("<option></option>").attr("value",27).text("Pin 27 - SDA0 - BCM0"));
|
||||
//$('#node-input-pin').append($("<option></option>").attr("value",28).text("Pin 28 - SCL0 - BCM1"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",29).text("Pin 29 - GPIO5"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",31).text("Pin 31 - GPIO6"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",32).text("Pin 32 - GPIO12"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",33).text("Pin 33 - GPIO13"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",35).text("Pin 35 - GPIO19"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",36).text("Pin 36 - GPIO16"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",37).text("Pin 37 - GPIO26"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",38).text("Pin 38 - GPIO20"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",40).text("Pin 40 - GPIO21"));
|
||||
$('#node-input-pin').val(pinnow);
|
||||
}
|
||||
});
|
||||
|
||||
$.getJSON('rpi-pins/'+this.id,function(data) {
|
||||
pinsInUse = data || {};
|
||||
$('#pin-tip').html(pintip + Object.keys(data));
|
||||
});
|
||||
|
||||
$("#node-input-pin").change(function() {
|
||||
var pinnew = $("#node-input-pin").val();
|
||||
if ((pinnew) && (pinnew !== pinnow)) {
|
||||
if (pinsInUse.hasOwnProperty(pinnew)) {
|
||||
RED.notify(pinname+" "+pinnew+" "+alreadyuse,"warn");
|
||||
}
|
||||
pinnow = pinnew;
|
||||
}
|
||||
});
|
||||
|
||||
$("#node-input-intype").change(function() {
|
||||
var newtype = $("#node-input-intype").val();
|
||||
if ((pinsInUse.hasOwnProperty(pinnow)) && (pinsInUse[pinnow] !== newtype)) {
|
||||
RED.notify(pinname+" "+pinnow+" "+alreadyset+" "+pinsInUse[pinnow],"error");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-gpio out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.label.gpiopin"></span></label>
|
||||
<select type="text" id="node-input-pin" style="width: 250px;">
|
||||
<option value='' disabled selected style='display:none;'><span data-i18n="rpi-gpio.label.selectpin"></span></option>
|
||||
<!-- <option value="3">Pin 3 - SDA1 - BCM2</option> -->
|
||||
<!-- <option value="5">Pin 5 - SCL1 - BCM3</option> -->
|
||||
<option value="7">Pin 7 - GPIO4</option>
|
||||
<!-- <option value="8">Pin 8 - TxD - BCM14</option> -->
|
||||
<!-- <option value="10">Pin 10 - RxD - BCM15</option> -->
|
||||
<option value="11">Pin 11 - GPIO17</option>
|
||||
<option value="12">Pin 12 - GPIO18</option>
|
||||
<option value="13">Pin 13 - GPIO27</option>
|
||||
<option value="15">Pin 15 - GPIO22</option>
|
||||
<option value="16">Pin 16 - GPIO23</option>
|
||||
<option value="18">Pin 18 - GPIO24</option>
|
||||
<!-- <option value="19">Pin 19 - MOSI - BCM10</option> -->
|
||||
<!-- <option value="21">Pin 21 - MISO - BCM9</option> -->
|
||||
<option value="22">Pin 22 - GPIO25</option>
|
||||
<!-- <option value="23">Pin 23 - SCLK - BCM11</option> -->
|
||||
<!-- <option value="24">Pin 24 - CE0 - BCM8</option> -->
|
||||
<!-- <option value="26">Pin 26 - CE1 - BCM7</option> -->
|
||||
</select>
|
||||
<span id="pitype"></span>
|
||||
</div>
|
||||
<div class="form-row" id="node-set-pwm">
|
||||
<label> <span data-i18n="rpi-gpio.label.type"></span></label>
|
||||
<select id="node-input-out" style="width: 250px;">
|
||||
<option value="out" data-i18n="rpi-gpio.digout"></option>
|
||||
<option value="pwm" data-i18n="rpi-gpio.pwmout"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" id="node-set-tick">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-set" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-set" style="width: 70%;"><span data-i18n="rpi-gpio.label.initpin"></span></label>
|
||||
</div>
|
||||
<div class="form-row" id="node-set-state">
|
||||
<label for="node-input-level"> </label>
|
||||
<select id="node-input-level" style="width: 250px;">
|
||||
<option value="0" data-i18n="rpi-gpio.initpin0"></option>
|
||||
<option value="1" data-i18n="rpi-gpio.initpin1"></option>
|
||||
</select>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-tips" id="pin-tip"><span data-i18n="[html]rpi-gpio.tip.pin"></span></div>
|
||||
<div class="form-tips" id="dig-tip"><span data-i18n="[html]rpi-gpio.tip.dig"></span></div>
|
||||
<div class="form-tips" id="pwm-tip"><span data-i18n="[html]rpi-gpio.tip.pwm"></span></div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="rpi-gpio out">
|
||||
<p>Raspberry Pi output node. Can be used in Digital, PWM or Servo modes.
|
||||
<p>Digital mode expects a <code>msg.payload</code> with either a 0 or 1 (or true or false),
|
||||
and will set the selected physical pin high or low depending on the value passed in.</p>
|
||||
<p>The initial value of the pin at deploy time can also be set to 0 or 1.</p>
|
||||
<p>When using PWM mode - expects an input value of a number 0 - 100. It can be floating point.</p>
|
||||
<p>PWM mode can be used to drive a servo using input values between 10 and 20 only.
|
||||
The GPIO2 pin is best for this as it uses hardware to do the PWM.</p>
|
||||
<p>Requires the RPi.GPIO python library version 0.5.10 (or better) in order to work.</p>
|
||||
<p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var pinsInUse = {};
|
||||
RED.nodes.registerType('rpi-gpio out',{
|
||||
category: 'Raspberry Pi',
|
||||
label: 'Raspberry Pi',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:"" },
|
||||
pin: { value:"",required:true,validate:RED.validators.number() },
|
||||
set: { value:"" },
|
||||
level: { value:"0" },
|
||||
out: { value:"out" }
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "rpi.png",
|
||||
info: function() {
|
||||
if ( Object.keys(pinsInUse).length !== 0 ) {
|
||||
return "**Pins in use** : "+Object.keys(pinsInUse);
|
||||
}
|
||||
else { return ""; }
|
||||
},
|
||||
align: "right",
|
||||
label: function() {
|
||||
if (this.out === "pwm") { return this.name || "PWM: "+this.pin; }
|
||||
else { return this.name||"Pin: "+this.pin ; }
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var pinnow = this.pin;
|
||||
var pintip = this._("rpi-gpio.tip.pin");
|
||||
var pinname = this._("rpi-gpio.pinname");
|
||||
var alreadyuse = this._("rpi-gpio.alreadyuse");
|
||||
var alreadyset = this._("rpi-gpio.alreadyset");
|
||||
if (!$("#node-input-out").val()) { $("#node-input-out").val("out"); }
|
||||
$.getJSON('rpi-gpio/'+this.id,function(data) {
|
||||
$('#pitype').text(data.type);
|
||||
if ((data.type !== "Model B") && (data.type !== "Model A")) {
|
||||
//$('#node-input-pin').append($("<option></option>").attr("value",27).text("Pin 27 - SDA0 - BCM0"));
|
||||
//$('#node-input-pin').append($("<option></option>").attr("value",28).text("Pin 28 - SCL0 - BCM1"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",29).text("Pin 29 - GPIO5"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",31).text("Pin 31 - GPIO6"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",32).text("Pin 32 - GPIO12"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",33).text("Pin 33 - GPIO13"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",35).text("Pin 35 - GPIO19"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",36).text("Pin 36 - GPIO16"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",37).text("Pin 37 - GPIO26"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",38).text("Pin 38 - GPIO20"));
|
||||
$('#node-input-pin').append($("<option></option>").attr("value",40).text("Pin 40 - GPIO21"));
|
||||
$('#node-input-pin').val(pinnow);
|
||||
}
|
||||
});
|
||||
|
||||
$.getJSON('rpi-pins/'+this.id,function(data) {
|
||||
pinsInUse = data || {};
|
||||
$('#pin-tip').html(pintip + Object.keys(data));
|
||||
});
|
||||
|
||||
$("#node-input-pin").change(function() {
|
||||
var pinnew = $("#node-input-pin").val();
|
||||
if ((pinnew) && (pinnew !== pinnow)) {
|
||||
if (pinsInUse.hasOwnProperty(pinnew)) {
|
||||
RED.notify(pinname+" "+pinnew+" "+alreadyuse,"warn");
|
||||
}
|
||||
pinnow = pinnew;
|
||||
}
|
||||
});
|
||||
|
||||
$("#node-input-out").change(function() {
|
||||
var newtype = $("#node-input-out").val();
|
||||
if ((pinsInUse.hasOwnProperty(pinnow)) && (pinsInUse[pinnow] !== newtype)) {
|
||||
RED.notify(pinname+" "+pinnow+" "+alreadyset+" "+pinsInUse[pinnow],"error");
|
||||
}
|
||||
});
|
||||
|
||||
var hidestate = function () {
|
||||
if ($("#node-input-out").val() === "pwm") {
|
||||
$('#node-set-tick').hide();
|
||||
$('#node-set-state').hide();
|
||||
$('#node-input-set').prop('checked', false);
|
||||
$("#dig-tip").hide();
|
||||
$("#pwm-tip").show();
|
||||
}
|
||||
else {
|
||||
$('#node-set-tick').show();
|
||||
$("#dig-tip").show();
|
||||
$("#pwm-tip").hide();
|
||||
}
|
||||
};
|
||||
$("#node-input-out").change(function () { hidestate(); });
|
||||
hidestate();
|
||||
|
||||
var setstate = function () {
|
||||
if ($('#node-input-set').is(":checked")) {
|
||||
$("#node-set-state").show();
|
||||
} else {
|
||||
$("#node-set-state").hide();
|
||||
}
|
||||
};
|
||||
$("#node-input-set").change(function () { setstate(); });
|
||||
setstate();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-mouse">
|
||||
<div class="form-row">
|
||||
<label for="node-input-butt"><i class="fa fa-circle"></i> <span data-i18n="rpi-gpio.label.button"></span></label>
|
||||
<select type="text" id="node-input-butt" style="width: 250px;">
|
||||
<option value="1" data-i18n="rpi-gpio.left"></option>
|
||||
<option value="2" data-i18n="rpi-gpio.right"></option>
|
||||
<option value="4" data-i18n="rpi-gpio.middle"></option>
|
||||
<option value="7" data-i18n="rpi-gpio.any"></option>
|
||||
</select>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="rpi-mouse">
|
||||
<p>Raspberry Pi mouse button node. Requires a USB mouse.</p>
|
||||
<p>Generates a <code>msg.payload</code> with
|
||||
either a 1 or 0 when the selected mouse button is pressed and released</p>
|
||||
<p>Also sets <code>msg.button</code> to the code value
|
||||
<ul><li>1 = left</li><li>2 = right</li><li>4 = middle</li></ul>
|
||||
so you can work out which button or combination was pressed.</p>
|
||||
<p>And sets <code>msg.topic</code> to <i>pi/mouse</i>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('rpi-mouse',{
|
||||
category: 'Raspberry Pi',
|
||||
label: 'Raspberry Pi',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:"" },
|
||||
butt: { value:"1",required:true }
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "rpi.png",
|
||||
label: function() {
|
||||
var na = this._("rpi-gpio.label.pimouse");
|
||||
if (this.butt === "1") { na += " "+this._("rpi-gpio.label.left"); }
|
||||
if (this.butt === "2") { na += " "+this._("rpi-gpio.label.right"); }
|
||||
if (this.butt === "4") { na += " "+this._("rpi-gpio.label.middle"); }
|
||||
return this.name||na;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-keyboard">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="rpi-keyboard">
|
||||
<p>Raspberry Pi keyboard handling node. Requires a USB keyboard.</p>
|
||||
<p>Generates a <code>msg.payload</code> with a keycode, and <code>msg.action</code> set to
|
||||
<i>up, down</i> or <i>repeat</i> whenever a key is pressed or released.</p>
|
||||
<p>It also sets <code>msg.topic</code> to <i>pi/key</i>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('rpi-keyboard',{
|
||||
category: 'Raspberry Pi',
|
||||
label: 'Raspberry Pi',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:"" }
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "rpi.png",
|
||||
label: function() {
|
||||
return this.name || this._("rpi-gpio.label.pikeyboard");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,340 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013,2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var exec = require('child_process').exec;
|
||||
var spawn = require('child_process').spawn;
|
||||
var fs = require('fs');
|
||||
|
||||
var gpioCommand = __dirname+'/nrgpio';
|
||||
|
||||
try {
|
||||
fs.statSync("/dev/ttyAMA0"); // unlikely if not on a Pi
|
||||
} catch(err) {
|
||||
//RED.log.info(RED._("rpi-gpio.errors.ignorenode"));
|
||||
throw "Info : "+RED._("rpi-gpio.errors.ignorenode");
|
||||
}
|
||||
|
||||
try {
|
||||
fs.statSync("/usr/share/doc/python-rpi.gpio"); // test on Raspbian
|
||||
// /usr/lib/python2.7/dist-packages/RPi/GPIO
|
||||
} catch(err) {
|
||||
try {
|
||||
fs.statSync("/usr/lib/python2.7/site-packages/RPi/GPIO"); // test on Arch
|
||||
}
|
||||
catch(err) {
|
||||
RED.log.warn(RED._("rpi-gpio.errors.libnotfound"));
|
||||
throw "Warning : "+RED._("rpi-gpio.errors.libnotfound");
|
||||
}
|
||||
}
|
||||
|
||||
if ( !(1 & parseInt((fs.statSync(gpioCommand).mode & parseInt("777", 8)).toString(8)[0]) )) {
|
||||
RED.log.error(RED._("rpi-gpio.errors.needtobeexecutable",{command:gpioCommand}));
|
||||
throw "Error : "+RED._("rpi-gpio.errors.mustbeexecutable");
|
||||
}
|
||||
|
||||
// the magic to make python print stuff immediately
|
||||
process.env.PYTHONUNBUFFERED = 1;
|
||||
|
||||
var pinsInUse = {};
|
||||
var pinTypes = {"out":RED._("rpi-gpio.types.digout"), "tri":RED._("rpi-gpio.types.input"), "up":RED._("rpi-gpio.types.pullup"), "down":RED._("rpi-gpio.types.pulldown"), "pwm":RED._("rpi-gpio.types.pwmout")};
|
||||
|
||||
function GPIOInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.buttonState = -1;
|
||||
this.pin = n.pin;
|
||||
this.intype = n.intype;
|
||||
this.read = n.read || false;
|
||||
this.debounce = Number(n.debounce || 25);
|
||||
if (this.read) { this.buttonState = -2; }
|
||||
var node = this;
|
||||
if (!pinsInUse.hasOwnProperty(this.pin)) {
|
||||
pinsInUse[this.pin] = this.intype;
|
||||
}
|
||||
else {
|
||||
if ((pinsInUse[this.pin] !== this.intype)||(pinsInUse[this.pin] === "pwm")) {
|
||||
node.warn(RED._("rpi-gpio.errors.alreadyset",{pin:this.pin,type:pinTypes[pinsInUse[this.pin]]}));
|
||||
}
|
||||
}
|
||||
|
||||
if (node.pin !== undefined) {
|
||||
node.child = spawn(gpioCommand, ["in",node.pin,node.intype,node.debounce]);
|
||||
node.running = true;
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var d = data.toString().trim().split("\n");
|
||||
for (var i = 0; i < d.length; i++) {
|
||||
if (node.running && node.buttonState !== -1 && !isNaN(Number(d[i]))) {
|
||||
node.send({ topic:"pi/"+node.pin, payload:Number(d[i]) });
|
||||
}
|
||||
node.buttonState = d[i];
|
||||
node.status({fill:"green",shape:"dot",text:d[i]});
|
||||
if (RED.settings.verbose) { node.log("out: "+d[i]+" :"); }
|
||||
}
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error",{error:err.errno})) }
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
delete pinsInUse[node.pin];
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.stdin.write("close "+node.pin);
|
||||
node.child.kill('SIGKILL');
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("rpi-gpio in",GPIOInNode);
|
||||
|
||||
function GPIOOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.pin = n.pin;
|
||||
this.set = n.set || false;
|
||||
this.level = n.level || 0;
|
||||
this.out = n.out || "out";
|
||||
var node = this;
|
||||
if (!pinsInUse.hasOwnProperty(this.pin)) {
|
||||
pinsInUse[this.pin] = this.out;
|
||||
}
|
||||
else {
|
||||
if ((pinsInUse[this.pin] !== this.out)||(pinsInUse[this.pin] === "pwm")) {
|
||||
node.warn(RED._("rpi-gpio.errors.alreadyset",{pin:this.pin,type:pinTypes[pinsInUse[this.pin]]}));
|
||||
}
|
||||
}
|
||||
|
||||
function inputlistener(msg) {
|
||||
if (msg.payload === "true") { msg.payload = true; }
|
||||
if (msg.payload === "false") { msg.payload = false; }
|
||||
var out = Number(msg.payload);
|
||||
var limit = 1;
|
||||
if (node.out === "pwm") { limit = 100; }
|
||||
if ((out >= 0) && (out <= limit)) {
|
||||
if (RED.settings.verbose) { node.log("out: "+msg.payload); }
|
||||
if (node.child !== null) {
|
||||
node.child.stdin.write(msg.payload+"\n");
|
||||
node.status({fill:"green",shape:"dot",text:msg.payload.toString()});
|
||||
}
|
||||
else {
|
||||
node.error(RED._("rpi-gpio.errors.pythoncommandnotfound"),msg);
|
||||
node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.not-running"});
|
||||
}
|
||||
}
|
||||
else { node.warn(RED._("rpi-gpio.errors.invalidinput")+": "+out); }
|
||||
}
|
||||
|
||||
if (node.pin !== undefined) {
|
||||
if (node.set && (node.out === "out")) {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin,node.level]);
|
||||
node.status({fill:"green",shape:"dot",text:node.level});
|
||||
} else {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
}
|
||||
node.running = true;
|
||||
|
||||
node.on("input", inputlistener);
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("out: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.child = null;
|
||||
node.running = false;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
delete pinsInUse[node.pin];
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.stdin.write("close "+node.pin);
|
||||
node.child.kill('SIGKILL');
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
|
||||
}
|
||||
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
|
||||
|
||||
function PiMouseNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.butt = n.butt || 7;
|
||||
var node = this;
|
||||
|
||||
node.child = spawn(gpioCommand+".py", ["mouse",node.butt]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
data = Number(data);
|
||||
if (data === 1) { node.send({ topic:"pi/mouse", button:data, payload:1 }); }
|
||||
else { node.send({ topic:"pi/mouse", button:data, payload:0 }); }
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.child = null;
|
||||
node.running = false;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.kill('SIGINT');
|
||||
node.child = null;
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("rpi-mouse",PiMouseNode);
|
||||
|
||||
function PiKeyboardNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
|
||||
node.child = spawn(gpioCommand+".py", ["kbd","0"]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var b = data.toString().trim().split(",");
|
||||
var act = "up";
|
||||
if (b[1] === "1") { act = "down"; }
|
||||
if (b[1] === "2") { act = "repeat"; }
|
||||
node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({});
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.kill('SIGINT');
|
||||
node.child = null;
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("rpi-keyboard",PiKeyboardNode);
|
||||
|
||||
var pitype = { type:"" };
|
||||
exec(gpioCommand+" info", function(err,stdout,stderr) {
|
||||
if (err) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.version"));
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var info = JSON.parse( stdout.trim().replace(/\'/g,"\"") );
|
||||
pitype.type = info["TYPE"];
|
||||
}
|
||||
catch(e) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.sawpitype"),stdout.trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
RED.httpAdmin.get('/rpi-gpio/:id', RED.auth.needsPermission('rpi-gpio.read'), function(req,res) {
|
||||
res.json(pitype);
|
||||
});
|
||||
|
||||
RED.httpAdmin.get('/rpi-pins/:id', RED.auth.needsPermission('rpi-gpio.read'), function(req,res) {
|
||||
res.json(pinsInUse);
|
||||
});
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
<!--
|
||||
Copyright 2016 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="tls-config">
|
||||
<div class="form-row">
|
||||
<label style="width: 120px;" for="node-config-input-cert"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.cert"></span></label>
|
||||
<input style="width: 60%;" type="text" id="node-config-input-cert" data-i18n="[placeholder]tls.placeholder.cert">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 120px;" for="node-config-input-key"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.key"></span></label>
|
||||
<input style="width: 60%;" type="text" id="node-config-input-key" data-i18n="[placeholder]tls.placeholder.key">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 120px;" for="node-config-input-ca"><i class="fa fa-file-text-o"></i> <span data-i18n="tls.label.ca"></span></label>
|
||||
<input style="width: 60%;" type="text" id="node-config-input-ca" data-i18n="[placeholder]tls.placeholder.ca">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-config-input-verifyservercert" style="width: 70%;" data-i18n="tls.label.verify-server-cert"></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 120px;" for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input style="width: 60%;" type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tls-config">
|
||||
<p>Configuration options for TLS connections.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tls-config',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
cert: {value:"", validate: function(v) {
|
||||
var currentKey = $("#node-config-input-key").val();
|
||||
if (currentKey === undefined) {
|
||||
currentKey = this.key;
|
||||
}
|
||||
return currentKey === '' || v != '';
|
||||
}},
|
||||
key: {value:"", validate: function(v) {
|
||||
var currentCert = $("#node-config-input-cert").val();
|
||||
if (currentCert === undefined) {
|
||||
currentCert = this.cert;
|
||||
}
|
||||
return currentCert === '' || v != '';
|
||||
}},
|
||||
ca: {value:""},
|
||||
verifyservercert: {value: true}
|
||||
},
|
||||
label: function() {
|
||||
return this.name || this._("tls.tls");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var fs = require('fs');
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
function TLSConfig(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.valid = true;
|
||||
var certPath = n.cert.trim();
|
||||
var keyPath = n.key.trim();
|
||||
var caPath = n.ca.trim();
|
||||
|
||||
if ( (certPath.length > 0) !== (keyPath.length > 0)) {
|
||||
this.valid = false;
|
||||
this.error(RED._("tls.error.missing-file"));
|
||||
return;
|
||||
}
|
||||
this.verifyservercert = n.verifyservercert;
|
||||
|
||||
try {
|
||||
if (certPath) {
|
||||
this.cert = fs.readFileSync(certPath);
|
||||
}
|
||||
if (keyPath) {
|
||||
this.key = fs.readFileSync(keyPath);
|
||||
}
|
||||
if (caPath) {
|
||||
this.ca = fs.readFileSync(caPath);
|
||||
}
|
||||
} catch(err) {
|
||||
this.valid = false;
|
||||
this.error(err.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("tls-config",TLSConfig);
|
||||
|
||||
TLSConfig.prototype.addTLSOptions = function(opts) {
|
||||
if (this.valid) {
|
||||
if (this.key) {
|
||||
opts.key = this.key;
|
||||
}
|
||||
if (this.cert) {
|
||||
opts.cert = this.cert;
|
||||
}
|
||||
if (this.ca) {
|
||||
opts.ca = this.ca;
|
||||
}
|
||||
opts.rejectUnauthorized = this.verifyservercert;
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,359 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013, 2016 IBM Corp.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
|
||||
<input type="text" id="node-input-broker">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-qos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-input-qos" style="width:125px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt in">
|
||||
<p>Connects to a broker and subscribes to the specified topic.</p>
|
||||
<p>Outputs a message with the properties:</p>
|
||||
<ul>
|
||||
<li><code>msg.topic</code></li>
|
||||
<li><code>msg.payload</code></li>
|
||||
<li><code>msg.qos</code></li>
|
||||
<li><code>msg.retain</code></li>
|
||||
</ul>
|
||||
<p><code>msg.payload</code> will be a String, unless it is detected as a binary buffer.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt in',{
|
||||
category: 'input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
topic: {value:"",required:true,validate: RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)},
|
||||
qos: {value: "2"},
|
||||
broker: {type:"mqtt-broker", required:true}
|
||||
},
|
||||
color:"#d8bfd8",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge.png",
|
||||
label: function() {
|
||||
return this.name||this.topic||"mqtt";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
if (this.qos === undefined) {
|
||||
$("#node-input-qos").val("2");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
|
||||
<input type="text" id="node-input-broker">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-qos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-input-qos" style="width:125px !important">
|
||||
<option value=""></option>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
<i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span> <select id="node-input-retain" style="width:125px !important">
|
||||
<option value=""></option>
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-tips"><span data-i18n="mqtt.tip"></span></div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt out">
|
||||
<p>Connects to a MQTT broker and publishes messages.</p>
|
||||
<p><code>msg.payload</code> is used as the payload of the published message.
|
||||
If it contains an Object it will be converted to JSON before being sent.
|
||||
</p>
|
||||
<p>The topic used can be configured in the node or, if left blank, can be set
|
||||
by <code>msg.topic</code>.</p>
|
||||
<p>Likewise the QoS and retain values can be configured in the node or, if left
|
||||
blank, set by <code>msg.qos</code> and <code>msg.retain</code> respectively.
|
||||
By default, messages are published at QoS 0 with the retain flag set to false.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt out',{
|
||||
category: 'output',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
topic: {value:""},
|
||||
qos: {value:""},
|
||||
retain: {value:""},
|
||||
broker: {type:"mqtt-broker", required:true}
|
||||
},
|
||||
color:"#d8bfd8",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.topic||"mqtt";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt-broker">
|
||||
<div class="form-row">
|
||||
<ul style="background: #fff; min-width: 600px; margin-bottom: 20px;" id="node-config-mqtt-broker-tabs"></ul>
|
||||
</div>
|
||||
<div id="node-config-mqtt-broker-tabs-content" style="min-height: 170px;">
|
||||
<div id="mqtt-broker-tab-connection" style="display:none">
|
||||
<div class="form-row node-input-broker">
|
||||
<label for="node-config-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
|
||||
<input class="input-append-left" type="text" id="node-config-input-broker" placeholder="e.g. localhost" style="width: 40%;" >
|
||||
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="mqtt.label.port"></span></label>
|
||||
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:45px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-config-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-config-input-usetls" style="width: auto" data-i18n="mqtt.label.use-tls"></label>
|
||||
<div id="node-config-row-tls" class="hide">
|
||||
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-config-input-tls"><span data-i18n="mqtt.label.tls-config"></span></label><input style="width: 300px;" type="text" id="node-config-input-tls">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
|
||||
<input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.placeholder.clientid">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-keepalive" style="width: auto"><i class="fa fa-clock-o"></i> <span data-i18n="mqtt.label.keepalive"></span></label>
|
||||
<input type="text" id="node-config-input-keepalive" style="width: 50px">
|
||||
<input type="checkbox" id="node-config-input-cleansession" style="margin-left: 30px; height: 1em;display: inline-block; width: auto; vertical-align: middle;">
|
||||
<label for="node-config-input-cleansession" style="width: auto;" data-i18n="mqtt.label.cleansession"></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-config-input-compatmode" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-config-input-compatmode" style="width: auto;" data-i18n="mqtt.label.compatmode"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-security" style="display:none">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
|
||||
<input type="text" id="node-config-input-user">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
|
||||
<input type="password" id="node-config-input-password">
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-birth" style="display:none">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-birthQos" style="width:125px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
<i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span> <select id="node-config-input-birthRetain" style="width:125px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input type="text" id="node-config-input-birthPayload" data-i18n="[placeholder]common.label.payload">
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-will" style="display:none">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-config-input-willTopic" data-i18n="[placeholder]mqtt.placeholder.will-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-willQos" style="width:125px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
<i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span> <select id="node-config-input-willRetain" style="width:125px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input type="text" id="node-config-input-willPayload" data-i18n="[placeholder]common.label.payload">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt-broker">
|
||||
<p>A minimum MQTT broker connection requires only a broker server address to be added to the default configuration.</p>
|
||||
<p>To secure the connection with SSL/TLS, a TLS Configuration must also be configured and selected.</p>
|
||||
<p>If you create a Client ID it must be unique to the broker you are connecting to.</p>
|
||||
<p>For more information about MQTT see the <a href="http://www.eclipse.org/paho/" target="_blank">Eclipse Paho</a> site.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt-broker',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
broker: {value:"",required:true},
|
||||
port: {value:1883,required:true,validate:RED.validators.number()},
|
||||
tls: {type:"tls-config",required: false},
|
||||
clientid: {value:"", validate: function(v) {
|
||||
if ($("#node-config-input-clientid").length) {
|
||||
// Currently editing the node
|
||||
return $("#node-config-input-cleansession").is(":checked") || (v||"").length > 0;
|
||||
} else {
|
||||
return (this.cleansession===undefined || this.cleansession) || (v||"").length > 0;
|
||||
}
|
||||
}},
|
||||
usetls: {value: false},
|
||||
verifyservercert: { value: false},
|
||||
compatmode: { value: true},
|
||||
keepalive: {value:60,validate:RED.validators.number()},
|
||||
cleansession: {value: true},
|
||||
willTopic: {value:""},
|
||||
willQos: {value:"0"},
|
||||
willRetain: {value:false},
|
||||
willPayload: {value:""},
|
||||
birthTopic: {value:""},
|
||||
birthQos: {value:"0"},
|
||||
birthRetain: {value:false},
|
||||
birthPayload: {value:""}
|
||||
},
|
||||
credentials: {
|
||||
user: {type:"text"},
|
||||
password: {type: "password"}
|
||||
},
|
||||
label: function() {
|
||||
var b = this.broker;
|
||||
if (b === "") { b = "undefined"; }
|
||||
return (this.clientid?this.clientid+"@":"")+b+":"+this.port;
|
||||
},
|
||||
oneditprepare: function () {
|
||||
var tabs = RED.tabs.create({
|
||||
id: "node-config-mqtt-broker-tabs",
|
||||
onchange: function(tab) {
|
||||
$("#node-config-mqtt-broker-tabs-content").children().hide();
|
||||
$("#" + tab.id).show();
|
||||
}
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-connection",
|
||||
label: this._("mqtt.tabs-label.connection")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-security",
|
||||
label: this._("mqtt.tabs-label.security")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-birth",
|
||||
label: this._("mqtt.tabs-label.birth")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-will",
|
||||
label: this._("mqtt.tabs-label.will")
|
||||
});
|
||||
setTimeout(function() { tabs.resize()},0);
|
||||
if (typeof this.cleansession === 'undefined') {
|
||||
this.cleansession = true;
|
||||
$("#node-config-input-cleansession").prop("checked",true);
|
||||
}
|
||||
if (typeof this.usetls === 'undefined') {
|
||||
this.usetls = false;
|
||||
$("#node-config-input-usetls").prop("checked",false);
|
||||
}
|
||||
if (typeof this.compatmode === 'undefined') {
|
||||
this.compatmode = true;
|
||||
$("#node-config-input-compatmode").prop('checked', true);
|
||||
}
|
||||
if (typeof this.keepalive === 'undefined') {
|
||||
this.keepalive = 15;
|
||||
$("#node-config-input-keepalive").val(this.keepalive);
|
||||
}
|
||||
if (typeof this.willQos === 'undefined') {
|
||||
this.willQos = "0";
|
||||
$("#node-config-input-willQos").val("0");
|
||||
}
|
||||
if (typeof this.birthQos === 'undefined') {
|
||||
this.birthQos = "0";
|
||||
$("#node-config-input-birthQos").val("0");
|
||||
}
|
||||
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-config-input-usetls").is(':checked')) {
|
||||
$("#node-config-row-tls").show();
|
||||
} else {
|
||||
$("#node-config-row-tls").hide();
|
||||
}
|
||||
}
|
||||
updateTLSOptions();
|
||||
$("#node-config-input-usetls").on("click",function() {
|
||||
updateTLSOptions();
|
||||
});
|
||||
var node = this;
|
||||
function updateClientId() {
|
||||
if ($("#node-config-input-cleansession").is(":checked")) {
|
||||
$("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid"));
|
||||
} else {
|
||||
$("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid-nonclean"));
|
||||
}
|
||||
$("#node-config-input-clientid").change();
|
||||
}
|
||||
setTimeout(updateClientId,0);
|
||||
$("#node-config-input-cleansession").on("click",function() {
|
||||
updateClientId();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-config-input-usetls").is(':checked')) {
|
||||
$("#node-config-input-tls").val("");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,183 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013, 2016 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="http in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
|
||||
<select type="text" id="node-input-method" style="width:70%;">
|
||||
<option value="get">GET</option>
|
||||
<option value="post">POST</option>
|
||||
<option value="put">PUT</option>
|
||||
<option value="delete">DELETE</option>
|
||||
<option value="patch">PATCH</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
||||
<input id="node-input-url" type="text" placeholder="/url">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-row row-swagger-doc">
|
||||
<label for="node-input-swaggerDoc"><i class="fa fa-file-text-o"></i> <span data-i18n="httpin.label.doc"></span></label>
|
||||
<input type="text" id="node-input-swaggerDoc">
|
||||
</div>
|
||||
<div id="node-input-tip" class="form-tips"><span data-i18n="httpin.tip.in"></span><code><span id="node-input-path"></span></code>.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="http in">
|
||||
<p>Provides an input node for http requests, allowing the creation of simple web services.</p>
|
||||
<p>The resulting message has the following properties:
|
||||
<ul>
|
||||
<li>msg.req : <a href="http://expressjs.com/api.html#req">http request</a></li>
|
||||
<li>msg.res : <a href="http://expressjs.com/api.html#res">http response</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>For POST/PUT requests, the body is available under <code>msg.req.body</code>. This
|
||||
uses the <a href="http://expressjs.com/api.html#bodyParser">Express bodyParser middleware</a> to parse the content to a JSON object.
|
||||
</p>
|
||||
<p>
|
||||
By default, this expects the body of the request to be url encoded:
|
||||
<pre>foo=bar&this=that</pre>
|
||||
</p>
|
||||
<p>
|
||||
To send JSON encoded data to the node, the content-type header of the request must be set to
|
||||
<code>application/json</code>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Note: </b>This node does not send any response to the http request.
|
||||
This should be done with a subsequent HTTP Response node.
|
||||
</p>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="http response">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-tips"><span data-i18n="[html]httpin.tip.res"></span></div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="http response">
|
||||
<p>Sends responses back to http requests received from an HTTP Input node.</p>
|
||||
<p>The response can be customised using the following message properties:</p>
|
||||
<ul>
|
||||
<li><code>payload</code> is sent as the body of the response</li>
|
||||
<li><code>statusCode</code>, if set, is used as the response status code (default: 200)</li>
|
||||
<li><code>headers</code>, if set, should be an object containing field/value
|
||||
pairs to be added as response headers.</li>
|
||||
<li><code>cookies</code>, if set, can be used to set or delete cookies.
|
||||
</ul>
|
||||
<h3>Cookie handling</h3>
|
||||
<p>The <code>cookies</code> property must be an object of name/value pairs.
|
||||
The value can be either a string to set the value of the cookie with default
|
||||
options, or it can be an object of options.<p>
|
||||
<p>The following example sets two cookies - one called <code>name</code> with
|
||||
a value of <code>nick</code>, the other called <code>session</code> with a
|
||||
value of <code>1234</code> and an expiry set to 15 minutes.</p>
|
||||
<pre>
|
||||
msg.cookies = {
|
||||
name: 'nick',
|
||||
session: {
|
||||
value: '1234',
|
||||
maxAge: 900000
|
||||
}
|
||||
}</pre>
|
||||
<p>The valid options include:</p>
|
||||
<ul>
|
||||
<li><code>domain</code> - (String) domain name for the cookie</li>
|
||||
<li><code>expires</code> - (Date) expiry date in GMT. If not specified or set to 0, creates a session cookie</li>
|
||||
<li><code>maxAge</code> - (String) expiry date as relative to the current time in milliseconds</li>
|
||||
<li><code>path</code> - (String) path for the cookie. Defaults to /</li>
|
||||
<li><code>value</code> - (String) the value to use for the cookie</li>
|
||||
</ul>
|
||||
<p>To delete a cookie, set its <code>value</code> to <code>null</code>.</p>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('http in',{
|
||||
category: 'input',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
url: {value:"",required:true},
|
||||
method: {value:"get",required:true},
|
||||
swaggerDoc: {type:"swagger-doc", required:false}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
if (this.name) {
|
||||
return this.name;
|
||||
} else if (this.url) {
|
||||
var root = RED.settings.httpNodeRoot;
|
||||
if (root.slice(-1) != "/") {
|
||||
root = root+"/";
|
||||
}
|
||||
if (this.url.charAt(0) == "/") {
|
||||
root += this.url.slice(1);
|
||||
} else {
|
||||
root += this.url;
|
||||
}
|
||||
return "["+this.method+"] "+root;
|
||||
} else {
|
||||
return "http";
|
||||
}
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var root = RED.settings.httpNodeRoot;
|
||||
if (root.slice(-1) == "/") {
|
||||
root = root.slice(0,-1);
|
||||
}
|
||||
if (root == "") {
|
||||
$("#node-input-tip").hide();
|
||||
} else {
|
||||
$("#node-input-path").html(root);
|
||||
$("#node-input-tip").show();
|
||||
}
|
||||
if(!RED.nodes.getType("swagger-doc")){
|
||||
$('.row-swagger-doc').hide();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
RED.nodes.registerType('http response',{
|
||||
category: 'output',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
align: "right",
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||"http";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,220 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var http = require("follow-redirects").http;
|
||||
var https = require("follow-redirects").https;
|
||||
var urllib = require("url");
|
||||
var mustache = require("mustache");
|
||||
var querystring = require("querystring");
|
||||
|
||||
function HTTPRequest(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
var nodeUrl = n.url;
|
||||
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
|
||||
var nodeMethod = n.method || "GET";
|
||||
if (n.tls) {
|
||||
var tlsNode = RED.nodes.getNode(n.tls);
|
||||
}
|
||||
this.ret = n.ret || "txt";
|
||||
if (RED.settings.httpRequestTimeout) { this.reqTimeout = parseInt(RED.settings.httpRequestTimeout) || 120000; }
|
||||
else { this.reqTimeout = 120000; }
|
||||
|
||||
var prox, noprox;
|
||||
if (process.env.http_proxy != null) { prox = process.env.http_proxy; }
|
||||
if (process.env.HTTP_PROXY != null) { prox = process.env.HTTP_PROXY; }
|
||||
if (process.env.no_proxy != null) { noprox = process.env.no_proxy.split(","); }
|
||||
if (process.env.NO_PROXY != null) { noprox = process.env.NO_PROXY.split(","); }
|
||||
|
||||
this.on("input",function(msg) {
|
||||
var preRequestTimestamp = process.hrtime();
|
||||
node.status({fill:"blue",shape:"dot",text:"httpin.status.requesting"});
|
||||
var url = nodeUrl || msg.url;
|
||||
if (msg.url && nodeUrl && (nodeUrl !== msg.url)) { // revert change below when warning is finally removed
|
||||
node.warn(RED._("common.errors.nooverride"));
|
||||
}
|
||||
if (isTemplatedUrl) {
|
||||
url = mustache.render(nodeUrl,msg);
|
||||
}
|
||||
if (!url) {
|
||||
node.error(RED._("httpin.errors.no-url"),msg);
|
||||
return;
|
||||
}
|
||||
// url must start http:// or https:// so assume http:// if not set
|
||||
if (!((url.indexOf("http://") === 0) || (url.indexOf("https://") === 0))) {
|
||||
if (tlsNode) {
|
||||
url = "https://"+url;
|
||||
} else {
|
||||
url = "http://"+url;
|
||||
}
|
||||
}
|
||||
|
||||
var method = nodeMethod.toUpperCase() || "GET";
|
||||
if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set
|
||||
node.warn(RED._("common.errors.nooverride"));
|
||||
}
|
||||
if (msg.method && n.method && (n.method === "use")) {
|
||||
method = msg.method.toUpperCase(); // use the msg parameter
|
||||
}
|
||||
var opts = urllib.parse(url);
|
||||
opts.method = method;
|
||||
opts.headers = {};
|
||||
var ctSet = "Content-Type"; // set default camel case
|
||||
var clSet = "Content-Length";
|
||||
if (msg.headers) {
|
||||
for (var v in msg.headers) {
|
||||
if (msg.headers.hasOwnProperty(v)) {
|
||||
var name = v.toLowerCase();
|
||||
if (name !== "content-type" && name !== "content-length") {
|
||||
// only normalise the known headers used later in this
|
||||
// function. Otherwise leave them alone.
|
||||
name = v;
|
||||
}
|
||||
else if (name === 'content-type') { ctSet = v; }
|
||||
else { clSet = v; }
|
||||
opts.headers[name] = msg.headers[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.credentials && this.credentials.user) {
|
||||
opts.auth = this.credentials.user+":"+(this.credentials.password||"");
|
||||
}
|
||||
var payload = null;
|
||||
|
||||
if (msg.payload && (method == "POST" || method == "PUT" || method == "PATCH" ) ) {
|
||||
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
|
||||
payload = msg.payload;
|
||||
} else if (typeof msg.payload == "number") {
|
||||
payload = msg.payload+"";
|
||||
} else {
|
||||
if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') {
|
||||
payload = querystring.stringify(msg.payload);
|
||||
} else {
|
||||
payload = JSON.stringify(msg.payload);
|
||||
if (opts.headers['content-type'] == null) {
|
||||
opts.headers[ctSet] = "application/json";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts.headers['content-length'] == null) {
|
||||
if (Buffer.isBuffer(payload)) {
|
||||
opts.headers[clSet] = payload.length;
|
||||
} else {
|
||||
opts.headers[clSet] = Buffer.byteLength(payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
// revert to user supplied Capitalisation if needed.
|
||||
if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) {
|
||||
opts.headers[ctSet] = opts.headers['content-type'];
|
||||
delete opts.headers['content-type'];
|
||||
}
|
||||
if (opts.headers.hasOwnProperty('content-length') && (clSet !== 'content-length')) {
|
||||
opts.headers[clSet] = opts.headers['content-length'];
|
||||
delete opts.headers['content-length'];
|
||||
}
|
||||
var urltotest = url;
|
||||
var noproxy;
|
||||
if (noprox) {
|
||||
for (var i in noprox) {
|
||||
if (url.indexOf(noprox[i]) !== -1) { noproxy=true; }
|
||||
}
|
||||
}
|
||||
if (prox && !noproxy) {
|
||||
var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i);
|
||||
if (match) {
|
||||
//opts.protocol = "http:";
|
||||
//opts.host = opts.hostname = match[2];
|
||||
//opts.port = (match[3] != null ? match[3] : 80);
|
||||
opts.headers['Host'] = opts.host;
|
||||
var heads = opts.headers;
|
||||
var path = opts.pathname = opts.href;
|
||||
opts = urllib.parse(prox);
|
||||
opts.path = opts.pathname = path;
|
||||
opts.headers = heads;
|
||||
opts.method = method;
|
||||
urltotest = match[0];
|
||||
}
|
||||
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
|
||||
}
|
||||
if (tlsNode) {
|
||||
tlsNode.addTLSOptions(opts);
|
||||
}
|
||||
var req = ((/^https/.test(urltotest))?https:http).request(opts,function(res) {
|
||||
(node.ret === "bin") ? res.setEncoding('binary') : res.setEncoding('utf8');
|
||||
msg.statusCode = res.statusCode;
|
||||
msg.headers = res.headers;
|
||||
msg.payload = "";
|
||||
// msg.url = url; // revert when warning above finally removed
|
||||
res.on('data',function(chunk) {
|
||||
msg.payload += chunk;
|
||||
});
|
||||
res.on('end',function() {
|
||||
if (node.metric()) {
|
||||
// Calculate request time
|
||||
var diff = process.hrtime(preRequestTimestamp);
|
||||
var ms = diff[0] * 1e3 + diff[1] * 1e-6;
|
||||
var metricRequestDurationMillis = ms.toFixed(3);
|
||||
node.metric("duration.millis", msg, metricRequestDurationMillis);
|
||||
if (res.client && res.client.bytesRead) {
|
||||
node.metric("size.bytes", msg, res.client.bytesRead);
|
||||
}
|
||||
}
|
||||
if (node.ret === "bin") {
|
||||
msg.payload = new Buffer(msg.payload,"binary");
|
||||
}
|
||||
else if (node.ret === "obj") {
|
||||
try { msg.payload = JSON.parse(msg.payload); }
|
||||
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
|
||||
}
|
||||
node.send(msg);
|
||||
node.status({});
|
||||
});
|
||||
});
|
||||
req.setTimeout(node.reqTimeout, function() {
|
||||
node.error(RED._("common.notification.errors.no-response"),msg);
|
||||
setTimeout(function() {
|
||||
node.status({fill:"red",shape:"ring",text:"common.notification.errors.no-response"});
|
||||
},10);
|
||||
req.abort();
|
||||
});
|
||||
req.on('error',function(err) {
|
||||
node.error(err,msg);
|
||||
msg.payload = err.toString() + " : " + url;
|
||||
msg.statusCode = err.code;
|
||||
node.send(msg);
|
||||
node.status({fill:"red",shape:"ring",text:err.code});
|
||||
});
|
||||
if (payload) {
|
||||
req.write(payload);
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
|
||||
this.on("close",function() {
|
||||
node.status({});
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("http request",HTTPRequest,{
|
||||
credentials: {
|
||||
user: {type:"text"},
|
||||
password: {type: "password"}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
var util = require("util");
|
||||
var mqtt = require("./mqtt");
|
||||
var settings = require(process.env.NODE_RED_HOME+"/red/red").settings;
|
||||
|
||||
util.log("[warn] nodes/core/io/lib/mqttConnectionPool.js is deprecated and will be removed in a future release of Node-RED. Please report this usage to the Node-RED mailing list.");
|
||||
|
||||
var connections = {};
|
||||
|
||||
function matchTopic(ts,t) {
|
||||
if (ts == "#") {
|
||||
return true;
|
||||
}
|
||||
var re = new RegExp("^"+ts.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
|
||||
return re.test(t);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: function(broker,port,clientid,username,password,will) {
|
||||
var id = "["+(username||"")+":"+(password||"")+"]["+(clientid||"")+"]@"+broker+":"+port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = function() {
|
||||
var uid = (1+Math.random()*4294967295).toString(16);
|
||||
var client = mqtt.createClient(port,broker);
|
||||
client.uid = uid;
|
||||
client.setMaxListeners(0);
|
||||
var options = {keepalive:15};
|
||||
options.clientId = clientid || 'mqtt_' + (1+Math.random()*4294967295).toString(16);
|
||||
options.username = username;
|
||||
options.password = password;
|
||||
options.will = will;
|
||||
var queue = [];
|
||||
var subscriptions = {};
|
||||
var connecting = false;
|
||||
var obj = {
|
||||
_instances: 0,
|
||||
publish: function(msg) {
|
||||
if (client.isConnected()) {
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
} else {
|
||||
if (!connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
queue.push(msg);
|
||||
}
|
||||
},
|
||||
subscribe: function(topic,qos,callback,ref) {
|
||||
ref = ref||0;
|
||||
subscriptions[topic] = subscriptions[topic]||{};
|
||||
|
||||
var sub = {
|
||||
topic:topic,
|
||||
qos:qos,
|
||||
handler:function(mtopic,mpayload,mqos,mretain) {
|
||||
if (matchTopic(topic,mtopic)) {
|
||||
callback(mtopic,mpayload,mqos,mretain);
|
||||
}
|
||||
},
|
||||
ref: ref
|
||||
};
|
||||
subscriptions[topic][ref] = sub;
|
||||
client.on('message',sub.handler);
|
||||
if (client.isConnected()) {
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
},
|
||||
unsubscribe: function(topic,ref) {
|
||||
ref = ref||0;
|
||||
var sub = subscriptions[topic];
|
||||
if (sub) {
|
||||
if (sub[ref]) {
|
||||
client.removeListener('message',sub[ref].handler);
|
||||
delete sub[ref];
|
||||
}
|
||||
if (Object.keys(sub).length == 0) {
|
||||
delete subscriptions[topic];
|
||||
client.unsubscribe(topic);
|
||||
}
|
||||
}
|
||||
},
|
||||
on: function(a,b){
|
||||
client.on(a,b);
|
||||
},
|
||||
once: function(a,b){
|
||||
client.once(a,b);
|
||||
},
|
||||
connect: function() {
|
||||
if (client && !client.isConnected() && !connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
},
|
||||
disconnect: function(ref) {
|
||||
|
||||
this._instances -= 1;
|
||||
if (this._instances == 0) {
|
||||
client.disconnect();
|
||||
client = null;
|
||||
delete connections[id];
|
||||
}
|
||||
},
|
||||
isConnected: function() {
|
||||
return client.isConnected();
|
||||
}
|
||||
};
|
||||
client.on('connect',function() {
|
||||
if (client) {
|
||||
util.log('[mqtt] ['+uid+'] connected to broker tcp://'+broker+':'+port);
|
||||
connecting = false;
|
||||
for (var s in subscriptions) {
|
||||
var topic = s;
|
||||
var qos = 0;
|
||||
for (var r in subscriptions[s]) {
|
||||
qos = Math.max(qos,subscriptions[s][r].qos);
|
||||
}
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
//console.log("connected - publishing",queue.length,"messages");
|
||||
while(queue.length) {
|
||||
var msg = queue.shift();
|
||||
//console.log(msg);
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
}
|
||||
}
|
||||
});
|
||||
client.on('connectionlost', function(err) {
|
||||
util.log('[mqtt] ['+uid+'] connection lost to broker tcp://'+broker+':'+port);
|
||||
connecting = false;
|
||||
setTimeout(function() {
|
||||
obj.connect();
|
||||
}, settings.mqttReconnectTime||5000);
|
||||
});
|
||||
client.on('disconnect', function() {
|
||||
connecting = false;
|
||||
util.log('[mqtt] ['+uid+'] disconnected from broker tcp://'+broker+':'+port);
|
||||
});
|
||||
|
||||
return obj
|
||||
}();
|
||||
}
|
||||
connections[id]._instances += 1;
|
||||
return connections[id];
|
||||
}
|
||||
};
|
||||
@@ -1,257 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013, 2016 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="switch">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label data-i18n="switch.label.property"></label>
|
||||
<input type="text" id="node-input-property" style="width: 70%"/>
|
||||
</div>
|
||||
<div class="form-row node-input-rule-container-row">
|
||||
<ol id="node-input-rule-container"></ol>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<select id="node-input-checkall" style="width:100%; margin-right:5px;">
|
||||
<option value="true" data-i18n="switch.checkall"></option>
|
||||
<option value="false" data-i18n="switch.stopfirst"></option>
|
||||
</select>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="switch">
|
||||
<p>A node to route messages based on property values.</p>
|
||||
<p>When a message arrives, the selected property is evaluated against each
|
||||
of the defined rules. The message is then sent to the output of <i>all</i>
|
||||
rules that pass.</p>
|
||||
<p><b>Note</b>: the <i>otherwise</i> rule applies as a "not any of" the rules preceding it.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('switch', {
|
||||
color: "#E2D96E",
|
||||
category: 'function',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload", required:true},
|
||||
propertyType: { value:"msg" },
|
||||
rules: {value:[{t:"eq", v:""}]},
|
||||
checkall: {value:"true", required:true},
|
||||
outputs: {value:1}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "switch.png",
|
||||
label: function() {
|
||||
return this.name||"switch";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var node = this;
|
||||
var previousValueType = {value:"prev",label:this._("inject.previous"),hasValue:false};
|
||||
|
||||
$("#node-input-property").typedInput({default:this.propertyType||'msg',types:['msg','flow','global']});
|
||||
var operators = [
|
||||
{v:"eq",t:"=="},
|
||||
{v:"neq",t:"!="},
|
||||
{v:"lt",t:"<"},
|
||||
{v:"lte",t:"<="},
|
||||
{v:"gt",t:">"},
|
||||
{v:"gte",t:">="},
|
||||
{v:"btwn",t:this._("switch.rules.btwn")},
|
||||
{v:"cont",t:this._("switch.rules.cont")},
|
||||
{v:"regex",t:this._("switch.rules.regex")},
|
||||
{v:"true",t:this._("switch.rules.true")},
|
||||
{v:"false",t:this._("switch.rules.false")},
|
||||
{v:"null",t:this._("switch.rules.null")},
|
||||
{v:"nnull",t:this._("switch.rules.nnull")},
|
||||
{v:"else",t:this._("switch.rules.else")}
|
||||
];
|
||||
|
||||
var andLabel = this._("switch.and");
|
||||
var caseLabel = this._("switch.ignorecase");
|
||||
|
||||
function resizeRule(rule) {
|
||||
var newWidth = rule.width();
|
||||
var selectField = rule.find("select");
|
||||
var type = selectField.val()||"";
|
||||
var valueField = rule.find(".node-input-rule-value");
|
||||
var btwnField1 = rule.find(".node-input-rule-btwn-value");
|
||||
var btwnField2 = rule.find(".node-input-rule-btwn-value2");
|
||||
var selectWidth;
|
||||
if (type.length < 4) {
|
||||
selectWidth = 60;
|
||||
} else if (type === "regex") {
|
||||
selectWidth = 147;
|
||||
} else {
|
||||
selectWidth = 120;
|
||||
}
|
||||
selectField.width(selectWidth);
|
||||
if (type === "btwn") {
|
||||
btwnField1.typedInput("width",(newWidth-selectWidth-70));
|
||||
btwnField2.typedInput("width",(newWidth-selectWidth-70));
|
||||
} else {
|
||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
||||
// valueField.hide();
|
||||
} else {
|
||||
valueField.typedInput("width",(newWidth-selectWidth-70));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$("#node-input-rule-container").css('min-height','250px').css('min-width','450px').editableList({
|
||||
addItem: function(container,i,opt) {
|
||||
if (!opt.hasOwnProperty('r')) {
|
||||
opt.r = {};
|
||||
}
|
||||
var rule = opt.r;
|
||||
if (!rule.hasOwnProperty('t')) {
|
||||
rule.t = 'eq';
|
||||
}
|
||||
var row = $('<div/>').appendTo(container);
|
||||
var row2 = $('<div/>',{style:"padding-top: 5px; padding-left: 175px;"}).appendTo(container);
|
||||
var row3 = $('<div/>',{style:"padding-top: 5px; padding-left: 102px;"}).appendTo(container);
|
||||
var selectField = $('<select/>',{style:"width:120px; margin-left: 5px; text-align: center;"}).appendTo(row);
|
||||
for (var d in operators) {
|
||||
selectField.append($("<option></option>").val(operators[d].v).text(operators[d].t));
|
||||
}
|
||||
var valueField = $('<input/>',{class:"node-input-rule-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'str',types:['msg','flow','global','str','num',previousValueType]});
|
||||
var btwnValueField = $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'num',types:['msg','flow','global','str','num',previousValueType]});
|
||||
var btwnAndLabel = $('<span/>',{class:"node-input-rule-btwn-label"}).text(" "+andLabel+" ").appendTo(row3);
|
||||
var btwnValue2Field = $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"margin-left:2px;"}).appendTo(row3).typedInput({default:'num',types:['msg','flow','global','str','num',previousValueType]});
|
||||
var finalspan = $('<span/>',{style:"float: right;margin-top: 6px;"}).appendTo(row);
|
||||
finalspan.append(' → <span class="node-input-rule-index">'+(i+1)+'</span> ');
|
||||
var caseSensitive = $('<input/>',{id:"node-input-rule-case-"+i,class:"node-input-rule-case",type:"checkbox",style:"width:auto;vertical-align:top"}).appendTo(row2);
|
||||
$('<label/>',{for:"node-input-rule-case-"+i,style:"margin-left: 3px;"}).text(caseLabel).appendTo(row2);
|
||||
selectField.change(function() {
|
||||
resizeRule(container);
|
||||
var type = selectField.val();
|
||||
if (type === "btwn") {
|
||||
valueField.typedInput('hide');
|
||||
btwnValueField.typedInput('show');
|
||||
} else {
|
||||
btwnValueField.typedInput('hide');
|
||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
||||
valueField.typedInput('hide');
|
||||
} else {
|
||||
valueField.typedInput('show');
|
||||
}
|
||||
}
|
||||
if (type === "regex") {
|
||||
row2.show();
|
||||
row3.hide();
|
||||
} else if (type === "btwn"){
|
||||
row2.hide();
|
||||
row3.show();
|
||||
} else {
|
||||
row2.hide();
|
||||
row3.hide();
|
||||
}
|
||||
});
|
||||
selectField.val(rule.t);
|
||||
if (rule.t == "btwn") {
|
||||
btwnValueField.typedInput('value',rule.v);
|
||||
btwnValueField.typedInput('type',rule.vt||'num');
|
||||
btwnValue2Field.typedInput('value',rule.v2);
|
||||
btwnValue2Field.typedInput('type',rule.v2t||'num');
|
||||
} else if (typeof rule.v != "undefined") {
|
||||
valueField.typedInput('value',rule.v);
|
||||
valueField.typedInput('type',rule.vt||'str');
|
||||
}
|
||||
if (rule.case) {
|
||||
caseSensitive.prop('checked',true);
|
||||
} else {
|
||||
caseSensitive.prop('checked',false);
|
||||
}
|
||||
selectField.change();
|
||||
},
|
||||
removeItem: function(opt) {
|
||||
if (opt.hasOwnProperty('i')) {
|
||||
var removedList = $("#node-input-rule-container").data('removedList')||[];
|
||||
removedList.push(opt.i);
|
||||
$("#node-input-rule-container").data('removedList',removedList);
|
||||
}
|
||||
|
||||
var rules = $("#node-input-rule-container").editableList('items');
|
||||
rules.each(function(i) { $(this).find(".node-input-rule-index").html(i+1); });
|
||||
},
|
||||
resizeItem: resizeRule,
|
||||
sortItems: function(rules) {
|
||||
var rules = $("#node-input-rule-container").editableList('items');
|
||||
rules.each(function(i) { $(this).find(".node-input-rule-index").html(i+1); });
|
||||
},
|
||||
sortable: true,
|
||||
removable: true
|
||||
});
|
||||
|
||||
for (var i=0;i<this.rules.length;i++) {
|
||||
var rule = this.rules[i];
|
||||
$("#node-input-rule-container").editableList('addItem',{r:rule,i:i});
|
||||
}
|
||||
},
|
||||
oneditsave: function() {
|
||||
var rules = $("#node-input-rule-container").editableList('items');
|
||||
var ruleset;
|
||||
var node = this;
|
||||
node.rules = [];
|
||||
var changedOutputs = {};
|
||||
var removedList = $("#node-input-rule-container").data('removedList')||[];
|
||||
removedList.forEach(function(i) {
|
||||
changedOutputs[i] = -1;
|
||||
});
|
||||
rules.each(function(i) {
|
||||
var ruleData = $(this).data('data');
|
||||
var rule = $(this);
|
||||
var type = rule.find("select").val();
|
||||
var r = {t:type};
|
||||
if (!(type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else")) {
|
||||
if (type === "btwn") {
|
||||
r.v = rule.find(".node-input-rule-btwn-value").typedInput('value');
|
||||
r.vt = rule.find(".node-input-rule-btwn-value").typedInput('type');
|
||||
r.v2 = rule.find(".node-input-rule-btwn-value2").typedInput('value');
|
||||
r.v2t = rule.find(".node-input-rule-btwn-value2").typedInput('type');
|
||||
} else {
|
||||
r.v = rule.find(".node-input-rule-value").typedInput('value');
|
||||
r.vt = rule.find(".node-input-rule-value").typedInput('type');
|
||||
}
|
||||
if (type === "regex") {
|
||||
r.case = rule.find(".node-input-rule-case").prop("checked");
|
||||
}
|
||||
}
|
||||
if (ruleData.hasOwnProperty('i')) {
|
||||
if (ruleData.i !== i) {
|
||||
changedOutputs[ruleData.i] = i;
|
||||
}
|
||||
}
|
||||
node.rules.push(r);
|
||||
});
|
||||
this._outputs = changedOutputs;
|
||||
this.outputs = node.rules.length;
|
||||
this.propertyType = $("#node-input-property").typedInput('type');
|
||||
},
|
||||
oneditresize: function(size) {
|
||||
var rows = $("#dialog-form>div:not(.node-input-rule-container-row)");
|
||||
var height = size.height;
|
||||
for (var i=0;i<rows.size();i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
var editorRow = $("#dialog-form>div.node-input-rule-container-row");
|
||||
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-rule-container").editableList('height',height);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,109 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var operators = {
|
||||
'eq': function(a, b) { return a == b; },
|
||||
'neq': function(a, b) { return a != b; },
|
||||
'lt': function(a, b) { return a < b; },
|
||||
'lte': function(a, b) { return a <= b; },
|
||||
'gt': function(a, b) { return a > b; },
|
||||
'gte': function(a, b) { return a >= b; },
|
||||
'btwn': function(a, b, c) { return a >= b && a <= c; },
|
||||
'cont': function(a, b) { return (a + "").indexOf(b) != -1; },
|
||||
'regex': function(a, b, c, d) { return (a + "").match(new RegExp(b,d?'i':'')); },
|
||||
'true': function(a) { return a === true; },
|
||||
'false': function(a) { return a === false; },
|
||||
'null': function(a) { return (typeof a == "undefined" || a === null); },
|
||||
'nnull': function(a) { return (typeof a != "undefined" && a !== null); },
|
||||
'else': function(a) { return a === true; }
|
||||
};
|
||||
|
||||
function SwitchNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
this.rules = n.rules || [];
|
||||
this.property = n.property;
|
||||
this.propertyType = n.propertyType || "msg";
|
||||
this.checkall = n.checkall || "true";
|
||||
this.previousValue = null;
|
||||
var node = this;
|
||||
for (var i=0; i<this.rules.length; i+=1) {
|
||||
var rule = this.rules[i];
|
||||
if (!rule.vt) {
|
||||
if (!isNaN(Number(rule.v))) {
|
||||
rule.vt = 'num';
|
||||
} else {
|
||||
rule.vt = 'str';
|
||||
}
|
||||
}
|
||||
if (rule.vt === 'num') {
|
||||
if (!isNaN(Number(rule.v))) {
|
||||
rule.v = Number(rule.v);
|
||||
}
|
||||
}
|
||||
if (typeof rule.v2 !== 'undefined') {
|
||||
if (!rule.v2t) {
|
||||
if (!isNaN(Number(rule.v2))) {
|
||||
rule.v2t = 'num';
|
||||
} else {
|
||||
rule.v2t = 'str';
|
||||
}
|
||||
}
|
||||
if (rule.v2t === 'num') {
|
||||
rule.v2 = Number(rule.v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.on('input', function (msg) {
|
||||
var onward = [];
|
||||
try {
|
||||
var prop = RED.util.evaluateNodeProperty(node.property,node.propertyType,node,msg);
|
||||
var elseflag = true;
|
||||
for (var i=0; i<node.rules.length; i+=1) {
|
||||
var rule = node.rules[i];
|
||||
var test = prop;
|
||||
var v1,v2;
|
||||
if (rule.vt === 'prev') {
|
||||
v1 = node.previousValue;
|
||||
} else {
|
||||
v1 = RED.util.evaluateNodeProperty(rule.v,rule.vt,node,msg);
|
||||
}
|
||||
v2 = rule.v2;
|
||||
if (rule.v2t === 'prev') {
|
||||
v2 = node.previousValue;
|
||||
} else if (typeof v2 !== 'undefined') {
|
||||
v2 = RED.util.evaluateNodeProperty(rule.v2,rule.v2t,node,msg);
|
||||
}
|
||||
if (rule.t == "else") { test = elseflag; elseflag = true; }
|
||||
if (operators[rule.t](test,v1,v2,rule.case)) {
|
||||
onward.push(msg);
|
||||
elseflag = false;
|
||||
if (node.checkall == "false") { break; }
|
||||
} else {
|
||||
onward.push(null);
|
||||
}
|
||||
}
|
||||
node.previousValue = prop;
|
||||
this.send(onward);
|
||||
} catch(err) {
|
||||
node.warn(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("switch", SwitchNode);
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
function ChangeNode(n) {
|
||||
RED.nodes.createNode(this, n);
|
||||
|
||||
this.rules = n.rules;
|
||||
var rule;
|
||||
if (!this.rules) {
|
||||
rule = {
|
||||
t:(n.action=="replace"?"set":n.action),
|
||||
p:n.property||""
|
||||
}
|
||||
|
||||
if ((rule.t === "set")||(rule.t === "move")) {
|
||||
rule.to = n.to||"";
|
||||
} else if (rule.t === "change") {
|
||||
rule.from = n.from||"";
|
||||
rule.to = n.to||"";
|
||||
rule.re = (n.reg===null||n.reg);
|
||||
}
|
||||
this.rules = [rule];
|
||||
}
|
||||
|
||||
var valid = true;
|
||||
for (var i=0;i<this.rules.length;i++) {
|
||||
rule = this.rules[i];
|
||||
// Migrate to type-aware rules
|
||||
if (!rule.pt) {
|
||||
rule.pt = "msg";
|
||||
}
|
||||
if (rule.t === "change" && rule.re) {
|
||||
rule.fromt = 're';
|
||||
delete rule.re;
|
||||
}
|
||||
if (rule.t === "set" && !rule.tot) {
|
||||
if (rule.to.indexOf("msg.") === 0 && !rule.tot) {
|
||||
rule.to = rule.to.substring(4);
|
||||
rule.tot = "msg";
|
||||
}
|
||||
}
|
||||
if (!rule.tot) {
|
||||
rule.tot = "str";
|
||||
}
|
||||
if (!rule.fromt) {
|
||||
rule.fromt = "str";
|
||||
}
|
||||
if (rule.t === "change" && rule.fromt !== 'msg' && rule.fromt !== 'flow' && rule.fromt !== 'global') {
|
||||
rule.fromRE = rule.from;
|
||||
if (rule.fromt !== 're') {
|
||||
rule.fromRE = rule.fromRE.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||
}
|
||||
try {
|
||||
rule.fromRE = new RegExp(rule.fromRE, "g");
|
||||
} catch (e) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-from",{error:e.message}));
|
||||
}
|
||||
}
|
||||
if (rule.tot === 'num') {
|
||||
rule.to = Number(rule.to);
|
||||
} else if (rule.tot === 'json') {
|
||||
try {
|
||||
// check this is parsable JSON
|
||||
JSON.parse(rule.to);
|
||||
} catch(e2) {
|
||||
valid = false;
|
||||
this.error(RED._("change.errors.invalid-json"));
|
||||
}
|
||||
} else if (rule.tot === 'bool') {
|
||||
rule.to = /^true$/i.test(rule.to);
|
||||
}
|
||||
}
|
||||
|
||||
function applyRule(msg,rule) {
|
||||
try {
|
||||
var property = rule.p;
|
||||
var value = rule.to;
|
||||
if (rule.tot === 'json') {
|
||||
value = JSON.parse(rule.to);
|
||||
}
|
||||
var current;
|
||||
var fromValue;
|
||||
var fromType;
|
||||
var fromRE;
|
||||
if (rule.tot === "msg") {
|
||||
value = RED.util.getMessageProperty(msg,rule.to);
|
||||
} else if (rule.tot === 'flow') {
|
||||
value = node.context().flow.get(rule.to);
|
||||
} else if (rule.tot === 'global') {
|
||||
value = node.context().global.get(rule.to);
|
||||
} else if (rule.tot === 'date') {
|
||||
value = Date.now();
|
||||
}
|
||||
if (rule.t === 'change') {
|
||||
if (rule.fromt === 'msg' || rule.fromt === 'flow' || rule.fromt === 'global') {
|
||||
if (rule.fromt === "msg") {
|
||||
fromValue = RED.util.getMessageProperty(msg,rule.from);
|
||||
} else if (rule.tot === 'flow') {
|
||||
fromValue = node.context().flow.get(rule.from);
|
||||
} else if (rule.tot === 'global') {
|
||||
fromValue = node.context().global.get(rule.from);
|
||||
}
|
||||
if (typeof fromValue === 'number' || fromValue instanceof Number) {
|
||||
fromType = 'num';
|
||||
} else if (typeof fromValue === 'boolean') {
|
||||
fromType = 'bool'
|
||||
} else if (fromValue instanceof RegExp) {
|
||||
fromType = 're';
|
||||
fromRE = fromValue;
|
||||
} else if (typeof fromValue === 'string') {
|
||||
fromType = 'str';
|
||||
fromRE = fromValue.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
||||
try {
|
||||
fromRE = new RegExp(fromRE, "g");
|
||||
} catch (e) {
|
||||
valid = false;
|
||||
node.error(RED._("change.errors.invalid-from",{error:e.message}));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
node.error(RED._("change.errors.invalid-from",{error:"unsupported type: "+(typeof fromValue)}));
|
||||
return
|
||||
}
|
||||
} else {
|
||||
fromType = rule.fromt;
|
||||
fromValue = rule.from;
|
||||
fromRE = rule.fromRE;
|
||||
}
|
||||
}
|
||||
if (rule.pt === 'msg') {
|
||||
if (rule.t === 'delete') {
|
||||
RED.util.setMessageProperty(msg,property,undefined);
|
||||
} else if (rule.t === 'set') {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
} else if (rule.t === 'change') {
|
||||
current = RED.util.getMessageProperty(msg,property);
|
||||
if (typeof current === 'string') {
|
||||
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
|
||||
// str representation of exact from number/boolean
|
||||
// only replace if they match exactly
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
} else {
|
||||
current = current.replace(fromRE,value);
|
||||
RED.util.setMessageProperty(msg,property,current);
|
||||
}
|
||||
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
|
||||
if (current == Number(fromValue)) {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
}
|
||||
} else if (typeof current === 'boolean' && fromType === 'bool') {
|
||||
if (current.toString() === fromValue) {
|
||||
RED.util.setMessageProperty(msg,property,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var target;
|
||||
if (rule.pt === 'flow') {
|
||||
target = node.context().flow;
|
||||
} else if (rule.pt === 'global') {
|
||||
target = node.context().global;
|
||||
}
|
||||
if (target) {
|
||||
if (rule.t === 'delete') {
|
||||
target.set(property,undefined);
|
||||
} else if (rule.t === 'set') {
|
||||
target.set(property,value);
|
||||
} else if (rule.t === 'change') {
|
||||
current = target.get(msg,property);
|
||||
if (typeof current === 'string') {
|
||||
if ((fromType === 'num' || fromType === 'bool' || fromType === 'str') && current === fromValue) {
|
||||
// str representation of exact from number/boolean
|
||||
// only replace if they match exactly
|
||||
target.set(property,value);
|
||||
} else {
|
||||
current = current.replace(fromRE,value);
|
||||
target.set(property,current);
|
||||
}
|
||||
} else if ((typeof current === 'number' || current instanceof Number) && fromType === 'num') {
|
||||
if (current == Number(fromValue)) {
|
||||
target.set(property,value);
|
||||
}
|
||||
} else if (typeof current === 'boolean' && fromType === 'bool') {
|
||||
if (current.toString() === fromValue) {
|
||||
target.set(property,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {/*console.log(err.stack)*/}
|
||||
return msg;
|
||||
}
|
||||
if (valid) {
|
||||
var node = this;
|
||||
this.on('input', function(msg) {
|
||||
for (var i=0; i<this.rules.length; i++) {
|
||||
if (this.rules[i].t === "move") {
|
||||
var r = this.rules[i];
|
||||
if ((r.tot !== r.pt) || (r.p.indexOf(r.to) !== -1)) {
|
||||
msg = applyRule(msg,{t:"set", p:r.to, pt:r.tot, to:r.p, tot:r.pt});
|
||||
applyRule(msg,{t:"delete", p:r.p, pt:r.pt});
|
||||
}
|
||||
else { // 2 step move if we are moving from a child
|
||||
msg = applyRule(msg,{t:"set", p:"_temp_move", pt:r.tot, to:r.p, tot:r.pt});
|
||||
applyRule(msg,{t:"delete", p:r.p, pt:r.pt});
|
||||
msg = applyRule(msg,{t:"set", p:r.to, pt:r.tot, to:"_temp_move", tot:r.pt});
|
||||
applyRule(msg,{t:"delete", p:"_temp_move", pt:r.pt});
|
||||
}
|
||||
} else {
|
||||
msg = applyRule(msg,this.rules[i]);
|
||||
}
|
||||
if (msg === null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
node.send(msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("change", ChangeNode);
|
||||
};
|
||||
@@ -1,212 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2016 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="split">
|
||||
<div class="form-row">
|
||||
<label for="node-input-splt"><i class="fa fa-scissors"></i> Split</label>
|
||||
<input type="text" id="node-input-splt" placeholder="character to split strings on : e.g. \n">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="split">
|
||||
<p>A function that splits <code>msg.payload</code> into multiple messages.</p>
|
||||
<p>The behaviour is determined by the type of <code>msg.payload</code>:</p>
|
||||
<ul>
|
||||
<li><b>string</b> - a message is sent for each part of the string after it is split using the specified character, by default a newline (<code>\n</code>).
|
||||
<li><b>array</b> - a message is sent for each element of the array</li>
|
||||
<li><b>object</b> - a message is sent for each key/value pair of the object. <code>msg.parts.key</code> is set to the key of the property.</li>
|
||||
</ul>
|
||||
<p>Each message is sent with the <code>msg.parts</code> property set. This is
|
||||
an object that provides any subsequent <i>join</i> node the necessary information
|
||||
for it to reassemble the messages back into a single one. The object has the following
|
||||
properties:</p>
|
||||
<ul>
|
||||
<li><b>id</b> - an identifier for the group of messages</li>
|
||||
<li><b>index</b> - the position within the group</li>
|
||||
<li><b>count</b> - the total number of messages in the group</li>
|
||||
<li><b>type</b> - the type of message - string/array/object</li>
|
||||
<li><b>ch</b> - for a string, the character used to split</li>
|
||||
<li><b>key</b> - for an object, the key of the property this message was created from</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('split',{
|
||||
category: 'function',
|
||||
color:"#E2D96E",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
splt: {value:"\\n"}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "split.png",
|
||||
label: function() {
|
||||
return this.name||"split";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="join">
|
||||
<div class="form-row">
|
||||
<label>Mode</label>
|
||||
<select id="node-input-mode" style="width:200px;">
|
||||
<option value="auto">automatic</option>
|
||||
<option value="custom">manual</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="node-row-custom">
|
||||
<div class="form-row node-row-property">
|
||||
<label>Combine each </label>
|
||||
<input type="text" id="node-input-property" style="width:70%;">
|
||||
<input type="hidden" id="node-input-propertyType">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>to create </label>
|
||||
<select id="node-input-build" style="width:200px;">
|
||||
<option id="node-input-build-string" value="string">a String</option>
|
||||
<option value="array">an Array</option>
|
||||
<option value="object">a key/value Object</option>
|
||||
<option value="merged">a merged Object</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-row-key">
|
||||
<label style="vertical-align: top; margin-top: 7px;">using</label>
|
||||
<div style="display:inline-block">
|
||||
<input type="text" id="node-input-key" style="width:300px;">
|
||||
<div style="margin-top: 7px;">as the property key</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row node-row-joiner">
|
||||
<label for="node-input-joiner">joined using</label>
|
||||
<input type="text" id="node-input-joiner" style="width: 40px">
|
||||
</div>
|
||||
|
||||
<div class="form-row node-row-trigger">
|
||||
<label style="width: auto;">Send the message:</label>
|
||||
<ul>
|
||||
<li style="height: 40px;">
|
||||
<label style="width: 280px;" for="node-input-count">After a fixed number of messages:</label> <input id="node-input-count" placeholder="count" type="text" style="width: 75px;">
|
||||
</li>
|
||||
<li style="height: 40px;">
|
||||
<label style="width: 280px;" for="node-input-timeout">After a timeout following the first message:</label> <input id="node-input-timeout" placeholder="seconds" type="text" style="width: 75px;">
|
||||
</li>
|
||||
<li style="height: 40px;">
|
||||
<label style="width: auto; padding-top: 6px;">After a message with the <code>msg.complete</code> property set</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-tips form-tips-auto hide">This mode assumes this node is either
|
||||
paired with a <i>split</i> node or the received messages will have a properly
|
||||
configured <code>msg.parts</code> property.</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="join">
|
||||
<p>A function that joins a sequence of messages into a single message.</p>
|
||||
<p>When paired with the <b>split</b> node, it will automatically join the messages
|
||||
to reverse the split that was performed.</p>
|
||||
<p>The node can join either a specific property of each received message or,
|
||||
if the output type is not string, the entire message.</p>
|
||||
<p>The type of the resulting message property can be:</p>
|
||||
<ul>
|
||||
<li>a <b>string</b> - created by joining the property of each message with the specified join character.</li>
|
||||
<li>an <b>array</b>.</li>
|
||||
<li>a <b>key/value object</b> - created by using a property of each message to determine the key under which
|
||||
the required value is stored.</li>
|
||||
<li>a <b>merged object</b> - created by merging the property of each message under a single object.</li>
|
||||
</ul>
|
||||
The other properties of the output message are taken from the last message received before the result is sent.</p>
|
||||
<p>A <i>count</i> can be set for how many messages should be received before generating the output message</p>
|
||||
<p>A <i>timeout</i> can be set to trigger sending the new message using whatever has been received so far.</p>
|
||||
<p>If a message is received with the <b>msg.complete</b> property set, the output message is sent.</p>
|
||||
<p>The automatic behaviour relies on the received messages to have <b>msg.parts</b> set. The split node generates
|
||||
this property, but can be manually created. It has the following properties:</p>
|
||||
<ul>
|
||||
<li><b>id</b> - an identifier for the group of messages</li>
|
||||
<li><b>index</b> - the position within the group</li>
|
||||
<li><b>count</b> - the total number of messages in the group</li>
|
||||
<li><b>type</b> - the type of message - string/array/object</li>
|
||||
<li><b>ch</b> - for a string, the character used to split</li>
|
||||
<li><b>key</b> - for an object, the key of the property this message was created from</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('join',{
|
||||
category: 'function',
|
||||
color:"#E2D96E",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
mode: {value:"auto"},
|
||||
build: { value:"string"},
|
||||
property: { value: "payload"},
|
||||
propertyType: { value:"msg"},
|
||||
key: {value:"topic"},
|
||||
joiner: { value:"\\n"},
|
||||
timeout: {value:""},
|
||||
count: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "join.png",
|
||||
label: function() {
|
||||
return this.name||"join";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-input-mode").change(function(e) {
|
||||
var val = $(this).val();
|
||||
$(".node-row-custom").toggle(val==='custom');
|
||||
$(".form-tips-auto").toggle(val==='auto');
|
||||
});
|
||||
|
||||
$("#node-input-build").change(function(e) {
|
||||
var val = $(this).val();
|
||||
$(".node-row-key").toggle(val==='object');
|
||||
$(".node-row-joiner").toggle(val==='string');
|
||||
$(".node-row-trigger").toggle(val!=='auto');
|
||||
if (val === 'string') {
|
||||
$("#node-input-property").typedInput('types',['msg']);
|
||||
} else {
|
||||
$("#node-input-property").typedInput('types',['msg', {value:"full",label:"complete message",hasValue:false}]);
|
||||
}
|
||||
})
|
||||
|
||||
$("#node-input-property").typedInput({
|
||||
typeField: $("#node-input-propertyType"),
|
||||
types:['msg', {value:"full",label:"complete message",hasValue:false}]
|
||||
})
|
||||
$("#node-input-key").typedInput({
|
||||
types:['msg', {value:"merge",label:"",hasValue: false}]
|
||||
})
|
||||
|
||||
$("#node-input-build").change();
|
||||
$("#node-input-mode").change();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,228 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
function SplitNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.splt = (n.splt || "\\n").replace(/\\n/,"\n").replace(/\\r/,"\r").replace(/\\t/,"\t").replace(/\\e/,"\e").replace(/\\f/,"\f").replace(/\\0/,"\0");
|
||||
var node = this;
|
||||
this.on("input", function(msg) {
|
||||
if (msg.hasOwnProperty("payload")) {
|
||||
var a = msg.payload;
|
||||
if (msg.hasOwnProperty("parts")) { msg.parts = { parts:msg.parts }; } // push existing parts to a stack
|
||||
else { msg.parts = {}; }
|
||||
msg.parts.id = msg._msgid; // use the existing _msgid by default.
|
||||
if (typeof msg.payload === "string") { // Split String into array
|
||||
a = msg.payload.split(node.splt);
|
||||
msg.parts.ch = node.splt; // pass the split char to other end for rejoin
|
||||
msg.parts.type = "string";
|
||||
}
|
||||
if (Array.isArray(a)) { // then split array into messages
|
||||
msg.parts.type = msg.parts.type || "array"; // if it wasn't a string in the first place
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
msg.payload = a[i];
|
||||
msg.parts.index = i;
|
||||
msg.parts.count = a.length;
|
||||
node.send(RED.util.cloneMessage(msg));
|
||||
}
|
||||
}
|
||||
else if ((typeof msg.payload === "object") && !Buffer.isBuffer(msg.payload)) {
|
||||
var j = 0;
|
||||
var l = Object.keys(msg.payload).length;
|
||||
var pay = msg.payload;
|
||||
msg.parts.type = "object";
|
||||
for (var p in pay) {
|
||||
if (pay.hasOwnProperty(p)) {
|
||||
msg.payload = pay[p];
|
||||
msg.parts.key = p;
|
||||
msg.parts.index = j;
|
||||
msg.parts.count = l;
|
||||
node.send(RED.util.cloneMessage(msg));
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO not handling Buffers at present...
|
||||
//else { } // otherwise drop the message.
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("split",SplitNode);
|
||||
|
||||
|
||||
function JoinNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.mode = n.mode||"auto";
|
||||
this.property = n.property||"payload";
|
||||
this.propertyType = n.propertyType||"msg";
|
||||
if (this.propertyType === 'full') {
|
||||
this.property = "payload";
|
||||
}
|
||||
this.key = n.key||"topic";
|
||||
this.timer = (this.mode === "auto") ? 0 : Number(n.timeout || 0)*1000;
|
||||
this.timerr = n.timerr || "send";
|
||||
this.count = Number(n.count || 0);
|
||||
this.joiner = (n.joiner||"").replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t").replace(/\\e/g,"\e").replace(/\\f/g,"\f").replace(/\\0/g,"\0");
|
||||
this.build = n.build || "array";
|
||||
var node = this;
|
||||
var inflight = {};
|
||||
|
||||
var completeSend = function(partId) {
|
||||
var group = inflight[partId];
|
||||
clearTimeout(group.timeout);
|
||||
delete inflight[partId];
|
||||
|
||||
if (group.type === 'string') {
|
||||
RED.util.setMessageProperty(group.msg,node.property,group.payload.join(group.joinChar));
|
||||
} else {
|
||||
RED.util.setMessageProperty(group.msg,node.property,group.payload);
|
||||
}
|
||||
if (group.msg.hasOwnProperty('parts') && group.msg.parts.hasOwnProperty('parts')) {
|
||||
group.msg.parts = group.msg.parts.parts;
|
||||
} else {
|
||||
delete group.msg.parts;
|
||||
}
|
||||
node.send(group.msg);
|
||||
}
|
||||
|
||||
this.on("input", function(msg) {
|
||||
try {
|
||||
var property;
|
||||
if (node.mode === 'auto' && (!msg.hasOwnProperty("parts")||!msg.parts.hasOwnProperty("id"))) {
|
||||
node.warn("Message missing msg.parts property - cannot join in 'auto' mode")
|
||||
return;
|
||||
}
|
||||
if (node.propertyType == "full") {
|
||||
property = msg;
|
||||
} else {
|
||||
try {
|
||||
property = RED.util.getMessageProperty(msg,node.property);
|
||||
} catch(err) {
|
||||
node.warn("Message property "+node.property+" not found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var partId;
|
||||
var payloadType;
|
||||
var propertyKey;
|
||||
var targetCount;
|
||||
var joinChar;
|
||||
var propertyIndex;
|
||||
if (node.mode === "auto") {
|
||||
// Use msg.parts to identify all of the group information
|
||||
partId = msg.parts.id;
|
||||
payloadType = msg.parts.type;
|
||||
targetCount = msg.parts.count;
|
||||
joinChar = msg.parts.ch;
|
||||
propertyKey = msg.parts.key;
|
||||
propertyIndex = msg.parts.index;
|
||||
} else {
|
||||
// Use the node configuration to identify all of the group information
|
||||
partId = "_";
|
||||
payloadType = node.build;
|
||||
targetCount = node.count;
|
||||
joinChar = node.joiner;
|
||||
if (targetCount === 0 && msg.hasOwnProperty('parts')) {
|
||||
targetCount = msg.parts.count || 0;
|
||||
}
|
||||
if (node.build === 'object') {
|
||||
propertyKey = RED.util.getMessageProperty(msg,node.key);
|
||||
}
|
||||
}
|
||||
if (payloadType === 'object' && (propertyKey === null || propertyKey === undefined || propertyKey === "")) {
|
||||
if (node.mode === "auto") {
|
||||
node.warn("Message missing 'msg.parts.key' property - cannot add to object");
|
||||
} else {
|
||||
node.warn("Message missing key property 'msg."+node.key+"' '- cannot add to object")
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!inflight.hasOwnProperty(partId)) {
|
||||
if (payloadType === 'object' || payloadType === 'merged') {
|
||||
inflight[partId] = {
|
||||
currentCount:0,
|
||||
payload:{},
|
||||
targetCount:targetCount,
|
||||
type:"object",
|
||||
msg:msg
|
||||
};
|
||||
} else {
|
||||
inflight[partId] = {
|
||||
currentCount:0,
|
||||
payload:[],
|
||||
targetCount:targetCount,
|
||||
type:payloadType,
|
||||
joinChar: joinChar,
|
||||
msg:msg
|
||||
};
|
||||
if (payloadType === 'string') {
|
||||
inflight[partId].joinChar = joinChar;
|
||||
}
|
||||
}
|
||||
if (node.timer > 0) {
|
||||
inflight[partId].timeout = setTimeout(function() {
|
||||
completeSend(partId)
|
||||
}, node.timer)
|
||||
}
|
||||
}
|
||||
|
||||
var group = inflight[partId];
|
||||
if (payloadType === 'object') {
|
||||
group.payload[propertyKey] = property;
|
||||
group.currentCount = Object.keys(group.payload).length;
|
||||
} else if (payloadType === 'merged') {
|
||||
if (Array.isArray(property) || typeof property !== 'object') {
|
||||
node.warn("Cannot merge non-object types");
|
||||
} else {
|
||||
for (propertyKey in property) {
|
||||
if (property.hasOwnProperty(propertyKey)) {
|
||||
group.payload[propertyKey] = property[propertyKey];
|
||||
}
|
||||
}
|
||||
group.currentCount++;
|
||||
}
|
||||
} else {
|
||||
if (!isNaN(propertyIndex)) {
|
||||
group.payload[propertyIndex] = property;
|
||||
} else {
|
||||
group.payload.push(property);
|
||||
}
|
||||
group.currentCount++;
|
||||
}
|
||||
// TODO: currently reuse the last received - add option to pick first received
|
||||
group.msg = msg;
|
||||
if (group.currentCount === group.targetCount || msg.hasOwnProperty('complete')) {
|
||||
delete msg.complete;
|
||||
completeSend(partId);
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err.stack);
|
||||
}
|
||||
});
|
||||
|
||||
this.on("close", function() {
|
||||
for (var i in inflight) {
|
||||
if (inflight.hasOwnProperty(i)) {
|
||||
clearTimeout(inflight[i].timeout);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("join",JoinNode);
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
|
||||
<!--
|
||||
Copyright 2014,2015 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="csv">
|
||||
<div class="form-row">
|
||||
<label for="node-input-temp"><i class="fa fa-list"></i> <span data-i18n="csv.label.columns"></span></label>
|
||||
<input type="text" id="node-input-temp" data-i18n="[placeholder]csv.placeholder.columns">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-select-sep"><i class="fa fa-text-width"></i> <span data-i18n="csv.label.separator"></span></label>
|
||||
<select style="width: 150px" id="node-input-select-sep">
|
||||
<option value="," data-i18n="csv.separator.comma"></option>
|
||||
<option value="\t" data-i18n="csv.separator.tab"></option>
|
||||
<option value=" " data-i18n="csv.separator.space"></option>
|
||||
<option value=";" data-i18n="csv.separator.semicolon"></option>
|
||||
<option value=":" data-i18n="csv.separator.colon"></option>
|
||||
<option value="#" data-i18n="csv.separator.hashtag"></option>
|
||||
<option value="" data-i18n="csv.separator.other"></option>
|
||||
</select>
|
||||
<input style="width: 40px;" type="text" id="node-input-sep" pattern=".">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<hr align="middle"/>
|
||||
<div class="form-row">
|
||||
<label style="width: 100%;"><i class="fa fa-gears"></i> <span data-i18n="csv.label.c2o"></span></label>
|
||||
<label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-sign-in"></i> <span data-i18n="csv.label.input"></span></label>
|
||||
<input style="width: 30px" type="checkbox" id="node-input-hdrin"><label style="width: auto;" for="node-input-hdrin"><span data-i18n="csv.label.firstrow"></span></span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-sign-out"></i> <span data-i18n="csv.label.output"></span></label>
|
||||
<select type="text" id="node-input-multi" style="width: 250px;">
|
||||
<option value="one" data-i18n="csv.output.row"></option>
|
||||
<option value="mult" data-i18n="csv.output.array"></option>
|
||||
</select>
|
||||
</div>
|
||||
<hr align="middle"/>
|
||||
<div class="form-row">
|
||||
<label style="width: 100%;"><i class="fa fa-gears"></i> <span data-i18n="csv.label.o2c"></span></label>
|
||||
<label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-sign-in"></i> <span data-i18n="csv.label.output"></span></label>
|
||||
<input style="width: 30px" type="checkbox" id="node-input-hdrout"><label style="width: auto;" for="node-input-hdrout"><span data-i18n="csv.label.includerow"></span></span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="margin-left: 10px; margin-right: -10px;"><i class="fa fa-align-left"></i> <span data-i18n="csv.label.newline"></span></label>
|
||||
<select style="width: 150px" id="node-input-ret">
|
||||
<option value='\n' data-i18n="csv.newline.linux"></option>
|
||||
<option value='\r' data-i18n="csv.newline.mac"></option>
|
||||
<option value='\r\n' data-i18n="csv.newline.windows"></option>
|
||||
</select>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="csv">
|
||||
<p>A function that parses the <code>msg.payload</code> to convert CSV to/from a javascript object.
|
||||
Places the result in the payload.</p>
|
||||
<p>If the input is a string it tries to parse it as CSV and creates a javascript object.</p>
|
||||
<p>If the input is a javascript object it tries to build a CSV string.</p>
|
||||
<p>If the input is a simple array the output is just a CSV generated from that array.</p>
|
||||
<p>If the input is an array of arrays, or an array of objects, a multiple-line CSV is created.</p>
|
||||
<p>The columns template should contain an ordered list of column headers. For CSV input these become the property names.
|
||||
For CSV output these specify the properties to extract from the object and the order for the CSV.</p>
|
||||
<p>If the input is an array then the columns template does not matter, but can be used to generate a row of column titles.</p>
|
||||
<p><b>Note:</b> the columns should always be specified comma separated - even if another separator is chosen for the data.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('csv',{
|
||||
category: 'function',
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
sep: {value:',',required:true,validate:RED.validators.regex(/^.{1,2}$/)},
|
||||
//quo: {value:'"',required:true},
|
||||
hdrin: {value:""},
|
||||
hdrout: {value:""},
|
||||
multi: {value:"one",required:true},
|
||||
ret: {value:'\\n'},
|
||||
temp: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "parser-csv.png",
|
||||
label: function() {
|
||||
return this.name||"csv";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
if (this.sep == "," || this.sep == "\\t" || this.sep == ";" || this.sep == ":" || this.sep == " " || this.sep == "#") {
|
||||
$("#node-input-select-sep").val(this.sep);
|
||||
$("#node-input-sep").hide();
|
||||
} else {
|
||||
$("#node-input-select-sep").val("");
|
||||
$("#node-input-sep").val(this.sep);
|
||||
$("#node-input-sep").show();
|
||||
}
|
||||
$("#node-input-select-sep").change(function() {
|
||||
var v = $("#node-input-select-sep").val();
|
||||
$("#node-input-sep").val(v);
|
||||
if (v == "") {
|
||||
$("#node-input-sep").val("");
|
||||
$("#node-input-sep").show().focus();
|
||||
} else {
|
||||
$("#node-input-sep").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!--
|
||||
Copyright 2014 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="json">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="json">
|
||||
<p>A function that parses the <code>msg.payload</code> to convert a JSON string to/from a javascript object. Places the result back into the payload.</p>
|
||||
<p>If the input is a JSON string it tries to parse it to a javascript object.</p>
|
||||
<p>If the input is a javascript object it creates a JSON string.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('json',{
|
||||
category: 'function',
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "parser-json.png",
|
||||
label: function() {
|
||||
return this.name||"json";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
|
||||
function JSONNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
this.on("input", function(msg) {
|
||||
if (msg.hasOwnProperty("payload")) {
|
||||
if (typeof msg.payload === "string") {
|
||||
try {
|
||||
msg.payload = JSON.parse(msg.payload);
|
||||
node.send(msg);
|
||||
}
|
||||
catch(e) { node.error(e.message,msg); }
|
||||
}
|
||||
else if (typeof msg.payload === "object") {
|
||||
if (!Buffer.isBuffer(msg.payload)) {
|
||||
try {
|
||||
msg.payload = JSON.stringify(msg.payload);
|
||||
node.send(msg);
|
||||
}
|
||||
catch(e) { node.error(RED._("json.errors.dropped-error")); }
|
||||
}
|
||||
else { node.warn(RED._("json.errors.dropped-object")); }
|
||||
}
|
||||
else { node.warn(RED._("json.errors.dropped")); }
|
||||
}
|
||||
else { node.send(msg); } // If no payload - just pass it on.
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("json",JSONNode);
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
<!--
|
||||
Copyright 2014 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="xml">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-row" id="advanced">
|
||||
</div>
|
||||
<div id="advanced-options">
|
||||
<div class="form-row">
|
||||
<i class="fa fa-key"></i> <span data-i18n="xml.label.represent"></span> <input type="text" id="node-input-attr" style="text-align:center; width:40px" placeholder="$">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<i class="fa fa-key"></i> <span data-i18n="xml.label.prefix"></span> <input type="text" id="node-input-chr" style="text-align:center; width:40px" placeholder="_">
|
||||
</div>
|
||||
<div class="form-tips"><span data-i18n="xml.tip"></span></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xml">
|
||||
<p>A function that parses the <code>msg.payload</code> to convert xml to/from a javascript object. Places the result in the payload.</p>
|
||||
<p>If the input is a string it tries to parse it as XML and creates a javascript object.</p>
|
||||
<p>If the input is a javascript object it tries to build an XML string.</p>
|
||||
<p>You can also pass in a <code>msg.options</code> object to overide all the multitude of parameters. See
|
||||
<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a>
|
||||
for more information.</p>
|
||||
<p>If set, options in the edit dialogue override those passed in on the msg.options object.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('xml',{
|
||||
category: 'function',
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
attr: {value:""},
|
||||
chr: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "parser-xml.png",
|
||||
label: function() {
|
||||
return this.name||"xml";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var showadvanced = showadvanced || true;
|
||||
var advanced = this._("xml.label.advanced");
|
||||
var showall = function() {
|
||||
showadvanced = !showadvanced;
|
||||
if (showadvanced) {
|
||||
$("#advanced-options").show();
|
||||
$("#advanced").html('<label for="node-advanced" style="width:200px !important"><i class="fa fa-minus-square"></i> '+advanced+'</label>');
|
||||
}
|
||||
else {
|
||||
$("#advanced-options").hide();
|
||||
$("#advanced").html('<label for="node-advanced" style="width:200px !important"><i class="fa fa-plus-square"></i> '+advanced+' ...</label>');
|
||||
}
|
||||
};
|
||||
showall();
|
||||
$("#advanced").click( function() { showall(); });
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="yaml">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="yaml">
|
||||
<p>A function that parses the <code>msg.payload</code> to convert a YAML string to/from a javascript object. Places the result back into the payload.</p>
|
||||
<p>If the input is a YAML string it tries to parse it to a javascript object.</p>
|
||||
<p>If the input is a javascript object it creates a YAML string.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('yaml',{
|
||||
category: 'function',
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "parser-yaml.png",
|
||||
label: function() {
|
||||
return this.name||"yaml";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,133 +0,0 @@
|
||||
<!--
|
||||
Copyright 2013, 2014 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="file">
|
||||
<div class="form-row node-input-filename">
|
||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
||||
<input id="node-input-filename" type="text">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-overwriteFile"><i class="fa fa-random"></i> <span data-i18n="file.label.action"></span></label>
|
||||
<select type="text" id="node-input-overwriteFile" style="display: inline-block; width: 250px; vertical-align: top;">
|
||||
<option value="false" data-i18n="file.action.append"></option>
|
||||
<option value="true" data-i18n="file.action.overwrite"></option>
|
||||
<option value="delete" data-i18n="file.action.delete"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" id="node-appline">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-appendNewline" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-appendNewline" style="width: 70%;"><span data-i18n="file.label.addnewline"></span></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-createDir" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-createDir" style="width: 70%;"><span data-i18n="file.label.createdir"></span></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-tips"><span data-i18n="file.tip"></span></div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="file">
|
||||
<p>Writes <code>msg.payload</code> to the file specified, for example to create a log.</p>
|
||||
<p>The filename can be configured in the node. If left blank it should be
|
||||
set by <code>msg.filename</code> on the incoming message.</p>
|
||||
<p>A newline is added to every message. But this can be turned off if required, for example, to allow binary files to be written.</p>
|
||||
<p>The default behaviour is to append to the file. This can be changed to overwrite the file each time, for example if you want to output a "static" web page or report.</p>
|
||||
<p>This node can also be configured to delete a file if required.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="file in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
||||
<input id="node-input-filename" type="text" data-i18n="[placeholder]file.label.filename">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="file.label.outputas"></span></label>
|
||||
<select id="node-input-format">
|
||||
<option value="utf8" data-i18n="file.output.utf8"></option>
|
||||
<option value="" data-i18n="file.output.buffer"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="file in">
|
||||
<p>Reads the specified file and sends the content as <code>msg.payload</code>,
|
||||
and the filename as <code>msg.filename</code>.</p>
|
||||
<p>The filename can be configured in the node. If left blank it should be
|
||||
set by <code>msg.filename</code> on the incoming message.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('file',{
|
||||
category: 'storage-output',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filename: {value:""},
|
||||
appendNewline: {value:true},
|
||||
createDir: {value:false},
|
||||
overwriteFile: {value:"false"}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "file.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
if (this.overwriteFile === "delete") {
|
||||
return this.name||this._("file.label.deletelabel",{file:this.filename})
|
||||
} else {
|
||||
return this.name||this.filename||this._("file.label.filelabel");
|
||||
}
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-input-overwriteFile").on("change",function() {
|
||||
if (this.value === "delete") { $("#node-appline").hide(); }
|
||||
else { $("#node-appline").show(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
RED.nodes.registerType('file in',{
|
||||
category: 'storage-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filename: {value:""},
|
||||
format: {value:"utf8"},
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "file.png",
|
||||
label: function() {
|
||||
return this.name||this.filename||this._("file.label.filelabel");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013, 2015 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var fs = require("fs-extra");
|
||||
var os = require("os");
|
||||
|
||||
function FileNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.filename = n.filename;
|
||||
this.appendNewline = n.appendNewline;
|
||||
this.overwriteFile = n.overwriteFile.toString();
|
||||
this.createDir = n.createDir || false;
|
||||
var node = this;
|
||||
|
||||
this.on("input",function(msg) {
|
||||
var filename = node.filename || msg.filename || "";
|
||||
if (!node.filename) {
|
||||
node.status({fill:"grey",shape:"dot",text:filename});
|
||||
}
|
||||
if (filename === "") {
|
||||
node.warn(RED._("file.errors.nofilename"));
|
||||
} else if (msg.hasOwnProperty("payload") && (typeof msg.payload !== "undefined")) {
|
||||
var data = msg.payload;
|
||||
if ((typeof data === "object") && (!Buffer.isBuffer(data))) {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
if (typeof data === "boolean") { data = data.toString(); }
|
||||
if (typeof data === "number") { data = data.toString(); }
|
||||
if ((this.appendNewline) && (!Buffer.isBuffer(data))) { data += os.EOL; }
|
||||
data = new Buffer(data);
|
||||
if (this.overwriteFile === "true") {
|
||||
// using "binary" not {encoding:"binary"} to be 0.8 compatible for a while
|
||||
fs.writeFile(filename, data, "binary", function (err) {
|
||||
//fs.writeFile(filename, data, {encoding:"binary"}, function (err) {
|
||||
if (err) {
|
||||
if ((err.code === "ENOENT") && node.createDir) {
|
||||
fs.ensureFile(filename, function (err) {
|
||||
if (err) { node.error(RED._("file.errors.createfail",{error:err.toString()}),msg); }
|
||||
else {
|
||||
fs.writeFile(filename, data, "binary", function (err) {
|
||||
if (err) { node.error(RED._("file.errors.writefail",{error:err.toString()}),msg); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else { node.error(RED._("file.errors.writefail",{error:err.toString()}),msg); }
|
||||
}
|
||||
else if (RED.settings.verbose) { node.log(RED._("file.status.wrotefile",{file:filename})); }
|
||||
});
|
||||
}
|
||||
else if (this.overwriteFile === "delete") {
|
||||
fs.unlink(filename, function (err) {
|
||||
if (err) { node.error(RED._("file.errors.deletefail",{error:err.toString()}),msg); }
|
||||
else if (RED.settings.verbose) { node.log(RED._("file.status.deletedfile",{file:filename})); }
|
||||
});
|
||||
}
|
||||
else {
|
||||
// using "binary" not {encoding:"binary"} to be 0.8 compatible for a while longer
|
||||
fs.appendFile(filename, data, "binary", function (err) {
|
||||
//fs.appendFile(filename, data, {encoding:"binary"}, function (err) {
|
||||
if (err) {
|
||||
if ((err.code === "ENOENT") && node.createDir) {
|
||||
fs.ensureFile(filename, function (err) {
|
||||
if (err) { node.error(RED._("file.errors.createfail",{error:err.toString()}),msg); }
|
||||
else {
|
||||
fs.appendFile(filename, data, "binary", function (err) {
|
||||
if (err) { node.error(RED._("file.errors.appendfail",{error:err.toString()}),msg); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else { node.error(RED._("file.errors.appendfail",{error:err.toString()}),msg); }
|
||||
}
|
||||
else if (RED.settings.verbose) { node.log(RED._("file.status.appendedfile",{file:filename})); }
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
this.on('close', function() {
|
||||
node.status({});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("file",FileNode);
|
||||
|
||||
|
||||
function FileInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.filename = n.filename;
|
||||
this.format = n.format;
|
||||
var node = this;
|
||||
var options = {};
|
||||
if (this.format) {
|
||||
options['encoding'] = this.format;
|
||||
}
|
||||
this.on("input",function(msg) {
|
||||
var filename = node.filename || msg.filename || "";
|
||||
if (!node.filename) {
|
||||
node.status({fill:"grey",shape:"dot",text:filename});
|
||||
}
|
||||
if (filename === "") {
|
||||
node.warn(RED._("file.errors.nofilename"));
|
||||
} else {
|
||||
msg.filename = filename;
|
||||
fs.readFile(filename,options,function(err,data) {
|
||||
if (err) {
|
||||
node.error(err,msg);
|
||||
msg.error = err;
|
||||
delete msg.payload;
|
||||
} else {
|
||||
msg.payload = data;
|
||||
delete msg.error;
|
||||
}
|
||||
node.send(msg);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.on('close', function() {
|
||||
node.status({});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("file in",FileInNode);
|
||||
}
|
||||
175
package.json
175
package.json
@@ -1,93 +1,116 @@
|
||||
{
|
||||
"name" : "node-red",
|
||||
"version" : "0.15.2",
|
||||
"description" : "A visual tool for wiring the Internet of Things",
|
||||
"homepage" : "http://nodered.org",
|
||||
"license" : "Apache-2.0",
|
||||
"repository" : {
|
||||
"type":"git",
|
||||
"url":"https://github.com/node-red/node-red.git"
|
||||
"name": "node-red",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"main" : "red/red.js",
|
||||
"scripts" : {
|
||||
"start": "node red.js",
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"start": "node packages/node_modules/node-red/red.js",
|
||||
"test": "grunt",
|
||||
"build": "grunt build"
|
||||
},
|
||||
"bin" : {
|
||||
"node-red": "./red.js",
|
||||
"node-red-pi": "bin/node-red-pi"
|
||||
"build": "grunt build",
|
||||
"docs": "grunt docs"
|
||||
},
|
||||
"contributors": [
|
||||
{"name": "Nick O'Leary"},
|
||||
{"name": "Dave Conway-Jones"}
|
||||
],
|
||||
"keywords": [
|
||||
"editor", "messaging", "iot", "ibm", "flow"
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"basic-auth": "1.0.4",
|
||||
"bcryptjs": "2.3.0",
|
||||
"body-parser": "1.15.2",
|
||||
"cheerio":"0.22.0",
|
||||
"clone": "2.0.0",
|
||||
"ajv": "6.5.3",
|
||||
"basic-auth": "2.0.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
"cheerio": "0.22.0",
|
||||
"clone": "2.1.2",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cors":"2.8.1",
|
||||
"cron":"1.1.1",
|
||||
"express": "4.14.0",
|
||||
"follow-redirects":"0.2.0",
|
||||
"fs-extra": "0.30.0",
|
||||
"fs.notify":"0.0.4",
|
||||
"i18next":"1.10.6",
|
||||
"is-utf8":"0.2.1",
|
||||
"js-yaml": "3.6.1",
|
||||
"cors": "2.8.4",
|
||||
"cron": "1.4.1",
|
||||
"denque": "1.3.0",
|
||||
"express": "4.16.3",
|
||||
"express-session": "1.15.6",
|
||||
"fs-extra": "5.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"i18next": "11.6.0",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.5.4",
|
||||
"media-typer": "0.3.0",
|
||||
"mqtt": "1.14.1",
|
||||
"mustache": "2.2.1",
|
||||
"nopt": "3.0.6",
|
||||
"oauth2orize":"1.5.0",
|
||||
"on-headers":"1.0.1",
|
||||
"passport":"0.3.2",
|
||||
"passport-http-bearer":"1.0.1",
|
||||
"passport-oauth2-client-password":"0.1.2",
|
||||
"raw-body":"2.1.7",
|
||||
"semver": "5.3.0",
|
||||
"sentiment":"1.0.6",
|
||||
"uglify-js":"2.7.3",
|
||||
"when": "3.7.7",
|
||||
"ws": "0.8.1",
|
||||
"xml2js":"0.4.17",
|
||||
"node-red-node-feedparser":"0.1.*",
|
||||
"node-red-node-email":"0.1.*",
|
||||
"node-red-node-twitter":"0.1.*",
|
||||
"node-red-node-rbe":"0.1.*"
|
||||
"memorystore": "1.6.0",
|
||||
"mime": "1.4.1",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.3.1",
|
||||
"mustache": "2.3.2",
|
||||
"node-red-node-email": "0.1.*",
|
||||
"node-red-node-feedparser": "^0.1.12",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-twitter": "^1.1.0",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"on-headers": "1.0.1",
|
||||
"passport": "0.4.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.3.3",
|
||||
"request": "2.88.0",
|
||||
"semver": "5.5.1",
|
||||
"sentiment": "2.1.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"when": "3.7.8",
|
||||
"ws": "1.1.5",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"node-red-node-serialport":"0.4.*",
|
||||
"bcrypt":"0.8.7"
|
||||
"bcrypt": "~2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "1.0.1",
|
||||
"grunt-chmod": "1.1.1",
|
||||
"grunt-cli": "1.2.0",
|
||||
"grunt-concurrent":"2.3.1",
|
||||
"grunt-contrib-clean":"1.0.0",
|
||||
"grunt-contrib-compress": "1.3.0",
|
||||
"grunt-contrib-concat":"1.0.1",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-contrib-jshint": "1.0.0",
|
||||
"grunt-contrib-uglify": "2.0.0",
|
||||
"grunt-contrib-watch":"1.0.0",
|
||||
"grunt-jsonlint":"1.1.0",
|
||||
"grunt-nodemon":"0.4.2",
|
||||
"grunt-sass":"1.2.1",
|
||||
"grunt-simple-mocha": "0.4.1",
|
||||
"mocha": "3.1.1",
|
||||
"should": "8.4.0",
|
||||
"sinon": "1.17.6",
|
||||
"supertest": "2.0.0"
|
||||
"chromedriver": "^2.41.0",
|
||||
"grunt": "~1.0.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.3.1",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "~1.1.0",
|
||||
"grunt-contrib-uglify": "~3.4.0",
|
||||
"grunt-contrib-watch": "~1.1.0",
|
||||
"grunt-jsdoc": "^2.2.1",
|
||||
"grunt-jsdoc-to-markdown": "^4.0.0",
|
||||
"grunt-jsonlint": "~1.1.0",
|
||||
"grunt-mocha-istanbul": "5.0.2",
|
||||
"grunt-nodemon": "~0.4.2",
|
||||
"grunt-sass": "~2.0.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-webdriver": "^2.0.3",
|
||||
"http-proxy": "^1.16.2",
|
||||
"istanbul": "0.4.5",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "^5.2.0",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.0.6",
|
||||
"supertest": "3.1.0",
|
||||
"wdio-chromedriver-service": "^0.1.3",
|
||||
"wdio-mocha-framework": "^0.6.2",
|
||||
"wdio-spec-reporter": "^0.1.5",
|
||||
"webdriverio": "^4.13.1",
|
||||
"node-red-node-test-helper": "node-red/node-red-node-test-helper",
|
||||
"jsdoc-nr-template": "node-red/jsdoc-nr-template"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
"node": ">=8"
|
||||
}
|
||||
}
|
||||
|
||||
178
packages/node_modules/@node-red/editor-api/LICENSE
vendored
Normal file
178
packages/node_modules/@node-red/editor-api/LICENSE
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
12
packages/node_modules/@node-red/editor-api/README.md
vendored
Normal file
12
packages/node_modules/@node-red/editor-api/README.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
@node-red/editor-api
|
||||
====================
|
||||
|
||||
Node-RED editor api module.
|
||||
|
||||
This provides an Express application that can be used to serve the Node-RED
|
||||
editor.
|
||||
|
||||
|
||||
### Source
|
||||
|
||||
The main Node-RED modules are maintained as a monorepo on [GitHub](https://github.com/node-red/node-red).
|
||||
41
packages/node_modules/@node-red/editor-api/lib/admin/context.js
vendored
Normal file
41
packages/node_modules/@node-red/editor-api/lib/admin/context.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
|
||||
get: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
scope: req.params.scope,
|
||||
id: req.params.id,
|
||||
key: req.params[0],
|
||||
store: req.query['store']
|
||||
}
|
||||
runtimeAPI.context.getValue(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
||||
69
packages/node_modules/@node-red/editor-api/lib/admin/flow.js
vendored
Normal file
69
packages/node_modules/@node-red/editor-api/lib/admin/flow.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.getFlow(opts).then(function(result) {
|
||||
return res.json(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
post: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
flow: req.body
|
||||
}
|
||||
runtimeAPI.flows.addFlow(opts).then(function(id) {
|
||||
return res.json({id:id});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
put: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id,
|
||||
flow: req.body
|
||||
}
|
||||
runtimeAPI.flows.updateFlow(opts).then(function(id) {
|
||||
return res.json({id:id});
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params.id
|
||||
}
|
||||
runtimeAPI.flows.deleteFlow(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
||||
70
packages/node_modules/@node-red/editor-api/lib/admin/flows.js
vendored
Normal file
70
packages/node_modules/@node-red/editor-api/lib/admin/flows.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var runtimeAPI;
|
||||
var apiUtils = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
get: function(req,res) {
|
||||
var version = req.get("Node-RED-API-Version")||"v1";
|
||||
if (!/^v[12]$/.test(version)) {
|
||||
return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
|
||||
}
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.flows.getFlows(opts).then(function(result) {
|
||||
if (version === "v1") {
|
||||
res.json(result.flows);
|
||||
} else if (version === "v2") {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
post: function(req,res) {
|
||||
var version = req.get("Node-RED-API-Version")||"v1";
|
||||
if (!/^v[12]$/.test(version)) {
|
||||
return res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
deploymentType: req.get("Node-RED-Deployment-Type")||"full"
|
||||
}
|
||||
|
||||
if (opts.deploymentType !== 'reload') {
|
||||
if (version === "v1") {
|
||||
opts.flows = {flows: req.body}
|
||||
} else {
|
||||
opts.flows = req.body;
|
||||
}
|
||||
}
|
||||
|
||||
runtimeAPI.flows.setFlows(opts).then(function(result) {
|
||||
if (version === "v1") {
|
||||
res.status(204).end();
|
||||
} else {
|
||||
res.json(result);
|
||||
}
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
}
|
||||
67
packages/node_modules/@node-red/editor-api/lib/admin/index.js
vendored
Normal file
67
packages/node_modules/@node-red/editor-api/lib/admin/index.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var express = require("express");
|
||||
|
||||
var nodes = require("./nodes");
|
||||
var flows = require("./flows");
|
||||
var flow = require("./flow");
|
||||
var context = require("./context");
|
||||
var auth = require("../auth");
|
||||
|
||||
var apiUtil = require("../util");
|
||||
|
||||
module.exports = {
|
||||
init: function(runtimeAPI) {
|
||||
flows.init(runtimeAPI);
|
||||
flow.init(runtimeAPI);
|
||||
nodes.init(runtimeAPI);
|
||||
context.init(runtimeAPI);
|
||||
|
||||
var needsPermission = auth.needsPermission;
|
||||
|
||||
var adminApp = express();
|
||||
|
||||
// Flows
|
||||
adminApp.get("/flows",needsPermission("flows.read"),flows.get,apiUtil.errorHandler);
|
||||
adminApp.post("/flows",needsPermission("flows.write"),flows.post,apiUtil.errorHandler);
|
||||
|
||||
// Flow
|
||||
adminApp.get("/flow/:id",needsPermission("flows.read"),flow.get,apiUtil.errorHandler);
|
||||
adminApp.post("/flow",needsPermission("flows.write"),flow.post,apiUtil.errorHandler);
|
||||
adminApp.delete("/flow/:id",needsPermission("flows.write"),flow.delete,apiUtil.errorHandler);
|
||||
adminApp.put("/flow/:id",needsPermission("flows.write"),flow.put,apiUtil.errorHandler);
|
||||
|
||||
// Nodes
|
||||
adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,apiUtil.errorHandler);
|
||||
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalogs,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+\/[^\/]+)\/messages/,needsPermission("nodes.read"),nodes.getModuleCatalog,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.read"),nodes.getModule,apiUtil.errorHandler);
|
||||
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.putModule,apiUtil.errorHandler);
|
||||
adminApp.delete(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,needsPermission("nodes.write"),nodes.delete,apiUtil.errorHandler);
|
||||
adminApp.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.read"),nodes.getSet,apiUtil.errorHandler);
|
||||
adminApp.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,needsPermission("nodes.write"),nodes.putSet,apiUtil.errorHandler);
|
||||
|
||||
// Context
|
||||
adminApp.get("/context/:scope(global)",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
adminApp.get("/context/:scope(global)/*",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
adminApp.get("/context/:scope(node|flow)/:id",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
adminApp.get("/context/:scope(node|flow)/:id/*",needsPermission("context.read"),context.get,apiUtil.errorHandler);
|
||||
|
||||
return adminApp;
|
||||
}
|
||||
}
|
||||
173
packages/node_modules/@node-red/editor-api/lib/admin/nodes.js
vendored
Normal file
173
packages/node_modules/@node-red/editor-api/lib/admin/nodes.js
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var apiUtils = require("../util");
|
||||
|
||||
var runtimeAPI;
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
getAll: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
if (req.get("accept") == "application/json") {
|
||||
runtimeAPI.nodes.getNodeList(opts).then(function(list) {
|
||||
res.json(list);
|
||||
})
|
||||
} else {
|
||||
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
||||
runtimeAPI.nodes.getNodeConfigs(opts).then(function(configs) {
|
||||
res.send(configs);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
post: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.body.module,
|
||||
version: req.body.version
|
||||
}
|
||||
runtimeAPI.nodes.addModule(opts).then(function(info) {
|
||||
res.json(info);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
delete: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0]
|
||||
}
|
||||
runtimeAPI.nodes.removeModule(opts).then(function() {
|
||||
res.status(204).end();
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getSet: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params[0] + "/" + req.params[2]
|
||||
}
|
||||
if (req.get("accept") === "application/json") {
|
||||
runtimeAPI.nodes.getNodeInfo(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
} else {
|
||||
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
|
||||
runtimeAPI.nodes.getNodeConfig(opts).then(function(result) {
|
||||
return res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
getModule: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0]
|
||||
}
|
||||
runtimeAPI.nodes.getModuleInfo(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
putSet: function(req,res) {
|
||||
var body = req.body;
|
||||
if (!body.hasOwnProperty("enabled")) {
|
||||
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
|
||||
res.status(400).json({code:"invalid_request", message:"Invalid request"});
|
||||
return;
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
id: req.params[0] + "/" + req.params[2],
|
||||
enabled: body.enabled
|
||||
}
|
||||
runtimeAPI.nodes.setNodeSetState(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
putModule: function(req,res) {
|
||||
var body = req.body;
|
||||
if (!body.hasOwnProperty("enabled")) {
|
||||
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
|
||||
res.status(400).json({code:"invalid_request", message:"Invalid request"});
|
||||
return;
|
||||
}
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0],
|
||||
enabled: body.enabled
|
||||
}
|
||||
runtimeAPI.nodes.setModuleState(opts).then(function(result) {
|
||||
res.send(result);
|
||||
}).catch(function(err) {
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
getModuleCatalog: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
module: req.params[0],
|
||||
lang: req.query.lng
|
||||
}
|
||||
runtimeAPI.nodes.getModuleCatalog(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getModuleCatalogs: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user,
|
||||
lang: req.query.lng
|
||||
}
|
||||
runtimeAPI.nodes.getModuleCatalogs(opts).then(function(result) {
|
||||
res.json(result);
|
||||
}).catch(function(err) {
|
||||
console.log(err.stack);
|
||||
apiUtils.rejectHandler(req,res,err);
|
||||
})
|
||||
},
|
||||
|
||||
getIcons: function(req,res) {
|
||||
var opts = {
|
||||
user: req.user
|
||||
}
|
||||
runtimeAPI.nodes.getIconList(opts).then(function(list) {
|
||||
res.json(list);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,8 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var when = require("when");
|
||||
|
||||
var clients = [
|
||||
{id:"node-red-editor",secret:"not_available"},
|
||||
@@ -25,9 +23,9 @@ module.exports = {
|
||||
get: function(id) {
|
||||
for (var i=0;i<clients.length;i++) {
|
||||
if (clients[i].id == id) {
|
||||
return when.resolve(clients[i]);
|
||||
return Promise.resolve(clients[i]);
|
||||
}
|
||||
}
|
||||
return when.resolve(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
211
packages/node_modules/@node-red/editor-api/lib/auth/index.js
vendored
Normal file
211
packages/node_modules/@node-red/editor-api/lib/auth/index.js
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var passport = require("passport");
|
||||
var oauth2orize = require("oauth2orize");
|
||||
|
||||
var strategies = require("./strategies");
|
||||
var Tokens = require("./tokens");
|
||||
var Users = require("./users");
|
||||
var permissions = require("./permissions");
|
||||
|
||||
var theme = require("../editor/theme");
|
||||
|
||||
var settings = null;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
|
||||
|
||||
passport.use(strategies.bearerStrategy.BearerStrategy);
|
||||
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
|
||||
passport.use(strategies.anonymousStrategy);
|
||||
|
||||
var server = oauth2orize.createServer();
|
||||
|
||||
server.exchange(oauth2orize.exchange.password(strategies.passwordTokenExchange));
|
||||
|
||||
function init(_settings,storage) {
|
||||
settings = _settings;
|
||||
if (settings.adminAuth) {
|
||||
Users.init(settings.adminAuth);
|
||||
Tokens.init(settings.adminAuth,storage);
|
||||
}
|
||||
}
|
||||
|
||||
function needsPermission(permission) {
|
||||
return function(req,res,next) {
|
||||
if (settings && settings.adminAuth) {
|
||||
return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
|
||||
if (!req.user) {
|
||||
return next();
|
||||
}
|
||||
if (permissions.hasPermission(req.authInfo.scope,permission)) {
|
||||
return next();
|
||||
}
|
||||
log.audit({event: "permission.fail", permissions: permission},req);
|
||||
return res.status(401).end();
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ensureClientSecret(req,res,next) {
|
||||
if (!req.body.client_secret) {
|
||||
req.body.client_secret = 'not_available';
|
||||
}
|
||||
next();
|
||||
}
|
||||
function authenticateClient(req,res,next) {
|
||||
return passport.authenticate(['oauth2-client-password'], {session: false})(req,res,next);
|
||||
}
|
||||
function getToken(req,res,next) {
|
||||
return server.token()(req,res,next);
|
||||
}
|
||||
|
||||
function login(req,res) {
|
||||
var response = {};
|
||||
if (settings.adminAuth) {
|
||||
if (settings.adminAuth.type === "credentials") {
|
||||
response = {
|
||||
"type":"credentials",
|
||||
"prompts":[{id:"username",type:"text",label:"user.username"},{id:"password",type:"password",label:"user.password"}]
|
||||
}
|
||||
} else if (settings.adminAuth.type === "strategy") {
|
||||
|
||||
var urlPrefix = (settings.httpAdminRoot==='/')?"":settings.httpAdminRoot;
|
||||
response = {
|
||||
"type":"strategy",
|
||||
"prompts":[{type:"button",label:settings.adminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]
|
||||
}
|
||||
if (settings.adminAuth.strategy.icon) {
|
||||
response.prompts[0].icon = settings.adminAuth.strategy.icon;
|
||||
}
|
||||
if (settings.adminAuth.strategy.image) {
|
||||
response.prompts[0].image = theme.serveFile('/login/',settings.adminAuth.strategy.image);
|
||||
}
|
||||
}
|
||||
if (theme.context().login && theme.context().login.image) {
|
||||
response.image = theme.context().login.image;
|
||||
}
|
||||
}
|
||||
res.json(response);
|
||||
}
|
||||
|
||||
function revoke(req,res) {
|
||||
var token = req.body.token;
|
||||
// TODO: audit log
|
||||
Tokens.revoke(token).then(function() {
|
||||
log.audit({event: "auth.login.revoke"},req);
|
||||
if (settings.editorTheme && settings.editorTheme.logout && settings.editorTheme.logout.redirect) {
|
||||
res.json({redirect:settings.editorTheme.logout.redirect});
|
||||
} else {
|
||||
res.status(200).end();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function completeVerify(profile,done) {
|
||||
Users.authenticate(profile).then(function(user) {
|
||||
if (user) {
|
||||
Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) {
|
||||
log.audit({event: "auth.login",username:user.username,scope:user.permissions});
|
||||
user.tokens = tokens;
|
||||
done(null,user);
|
||||
});
|
||||
} else {
|
||||
log.audit({event: "auth.login.fail.oauth",username:typeof profile === "string"?profile:profile.username});
|
||||
done(null,false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function genericStrategy(adminApp,strategy) {
|
||||
var crypto = require("crypto")
|
||||
var session = require('express-session')
|
||||
var MemoryStore = require('memorystore')(session)
|
||||
|
||||
adminApp.use(session({
|
||||
// As the session is only used across the life-span of an auth
|
||||
// hand-shake, we can use a instance specific random string
|
||||
secret: crypto.randomBytes(20).toString('hex'),
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
store: new MemoryStore({
|
||||
checkPeriod: 86400000 // prune expired entries every 24h
|
||||
})
|
||||
}));
|
||||
//TODO: all passport references ought to be in ./auth
|
||||
adminApp.use(passport.initialize());
|
||||
adminApp.use(passport.session());
|
||||
|
||||
var options = strategy.options;
|
||||
|
||||
passport.use(new strategy.strategy(options,
|
||||
function() {
|
||||
var originalDone = arguments[arguments.length-1];
|
||||
if (options.verify) {
|
||||
var args = Array.from(arguments);
|
||||
args[args.length-1] = function(err,profile) {
|
||||
if (err) {
|
||||
return originalDone(err);
|
||||
} else {
|
||||
return completeVerify(profile,originalDone);
|
||||
}
|
||||
};
|
||||
options.verify.apply(null,args);
|
||||
} else {
|
||||
var profile = arguments[arguments.length - 2];
|
||||
return completeVerify(profile,originalDone);
|
||||
}
|
||||
|
||||
}
|
||||
));
|
||||
|
||||
adminApp.get('/auth/strategy',
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
);
|
||||
adminApp.get('/auth/strategy/callback',
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
);
|
||||
|
||||
}
|
||||
function completeGenerateStrategyAuth(req,res) {
|
||||
var tokens = req.user.tokens;
|
||||
delete req.user.tokens;
|
||||
// Successful authentication, redirect home.
|
||||
res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
needsPermission: needsPermission,
|
||||
ensureClientSecret: ensureClientSecret,
|
||||
authenticateClient: authenticateClient,
|
||||
getToken: getToken,
|
||||
errorHandler: function(err,req,res,next) {
|
||||
//TODO: audit log statment
|
||||
//console.log(err.stack);
|
||||
//log.log({level:"audit",type:"auth",msg:err.toString()});
|
||||
return server.errorHandler()(err,req,res,next);
|
||||
},
|
||||
login: login,
|
||||
revoke: revoke,
|
||||
genericStrategy: genericStrategy
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2015, 2016 IBM Corp.
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,7 @@ var Users = require("./users");
|
||||
var Clients = require("./clients");
|
||||
var permissions = require("./permissions");
|
||||
|
||||
var log;
|
||||
var log = require("@node-red/util").log; // TODO: separate module
|
||||
|
||||
var bearerStrategy = function (accessToken, done) {
|
||||
// is this a valid token?
|
||||
@@ -124,9 +124,6 @@ AnonymousStrategy.prototype.authenticate = function(req) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(runtime) {
|
||||
log = runtime.log;
|
||||
},
|
||||
bearerStrategy: bearerStrategy,
|
||||
clientPasswordStrategy: clientPasswordStrategy,
|
||||
passwordTokenExchange: passwordTokenExchange,
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2015 IBM Corp.
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var when = require("when");
|
||||
|
||||
function generateToken(length) {
|
||||
var c = "ABCDEFGHIJKLMNOPQRSTUZWXYZabcdefghijklmnopqrstuvwxyz1234567890";
|
||||
var token = [];
|
||||
@@ -49,7 +47,7 @@ function expireSessions() {
|
||||
if (modified) {
|
||||
return storage.saveSessions(sessions);
|
||||
} else {
|
||||
return when.resolve();
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
function loadSessions() {
|
||||
@@ -69,7 +67,7 @@ module.exports = {
|
||||
// At this point, storage will not have been initialised, so defer loading
|
||||
// the sessions until there's a request for them.
|
||||
loadedSessions = null;
|
||||
return when.resolve();
|
||||
return Promise.resolve();
|
||||
},
|
||||
get: function(token) {
|
||||
return loadSessions().then(function() {
|
||||
@@ -78,7 +76,7 @@ module.exports = {
|
||||
return expireSessions().then(function() { return null });
|
||||
}
|
||||
}
|
||||
return when.resolve(sessions[token]);
|
||||
return Promise.resolve(sessions[token]);
|
||||
});
|
||||
},
|
||||
create: function(user,client,scope) {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user