mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
980 Commits
2.0.1
...
fix-dynami
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9729c89f5d | ||
|
|
fc5a5f1b73 | ||
|
|
226ab406b2 | ||
|
|
9eaf5d82b6 | ||
|
|
e3d6d242ac | ||
|
|
53184715bc | ||
|
|
1844633ff1 | ||
|
|
7d7682b34e | ||
|
|
83655a749c | ||
|
|
b9444e8197 | ||
|
|
5ff70b2a36 | ||
|
|
4ed559af95 | ||
|
|
ce529a9b9f | ||
|
|
31e472145c | ||
|
|
1664428429 | ||
|
|
1780cb9b91 | ||
|
|
ad32677263 | ||
|
|
0eba4bdd61 | ||
|
|
28238eb5a7 | ||
|
|
cce4f6f7f7 | ||
|
|
6bea3dabbb | ||
|
|
ea46947054 | ||
|
|
22879f8c23 | ||
|
|
77c4423059 | ||
|
|
62a2a4a9f5 | ||
|
|
59690328e2 | ||
|
|
e50ecd613f | ||
|
|
d873a6138a | ||
|
|
8093ae8570 | ||
|
|
98ebb02763 | ||
|
|
ba22b07dce | ||
|
|
d1312703c5 | ||
|
|
8d99a42307 | ||
|
|
3ab93ecdd4 | ||
|
|
8762d0e164 | ||
|
|
2b91edeb74 | ||
|
|
6c49d1aa3f | ||
|
|
f07f086d62 | ||
|
|
c28862f8c7 | ||
|
|
9cfaf567be | ||
|
|
53f453bf34 | ||
|
|
a16032a8ed | ||
|
|
8cec0d8fcd | ||
|
|
6f6f67829b | ||
|
|
94471b6d07 | ||
|
|
7eed9c0584 | ||
|
|
3e717862a4 | ||
|
|
30d88bbe7e | ||
|
|
551e73adef | ||
|
|
99d32c4758 | ||
|
|
9e52c15829 | ||
|
|
71a272f0a6 | ||
|
|
64061c3440 | ||
|
|
3e34d0badb | ||
|
|
b2e8474df3 | ||
|
|
73ff7e2de4 | ||
|
|
b5d8d34718 | ||
|
|
ac44d22cee | ||
|
|
6e8fa12172 | ||
|
|
deb9c4ecc0 | ||
|
|
3046798ec5 | ||
|
|
c4332658ba | ||
|
|
50e3da0849 | ||
|
|
62cd3b2061 | ||
|
|
7e6dfa7b92 | ||
|
|
7fbebbf361 | ||
|
|
121372802f | ||
|
|
7924907384 | ||
|
|
51d429f9ae | ||
|
|
267aebb9cb | ||
|
|
3f9ebb588e | ||
|
|
f424f07e54 | ||
|
|
e5a21a3261 | ||
|
|
6f0de7c80e | ||
|
|
3ace7eeafd | ||
|
|
eb9f15e4e4 | ||
|
|
bc80569fe9 | ||
|
|
a147458120 | ||
|
|
6182e22d18 | ||
|
|
dda84c5cd5 | ||
|
|
6c15fb6978 | ||
|
|
b17b68c44b | ||
|
|
afdb15dc58 | ||
|
|
98b4b0dce0 | ||
|
|
70f26e0bea | ||
|
|
b6ad396a6c | ||
|
|
e44bb57b0e | ||
|
|
5c10b16b65 | ||
|
|
7ec1d42808 | ||
|
|
03e9e89558 | ||
|
|
3057035dec | ||
|
|
4af72cc7ba | ||
|
|
f6aee81651 | ||
|
|
a22f569ca0 | ||
|
|
8043f5d865 | ||
|
|
2ef50ab71f | ||
|
|
192a4f5e7f | ||
|
|
1af56a7f00 | ||
|
|
d2fab7fddd | ||
|
|
1818b0281d | ||
|
|
09973ba8cf | ||
|
|
dd3174c40f | ||
|
|
f0293b8f52 | ||
|
|
d549a9ad92 | ||
|
|
0385c72a8f | ||
|
|
e223b20cbd | ||
|
|
a0f7e92e40 | ||
|
|
c87ff3ca26 | ||
|
|
82672a825d | ||
|
|
98d524e82d | ||
|
|
3d3090a8f2 | ||
|
|
5561e89201 | ||
|
|
9ed96de237 | ||
|
|
0f2420576a | ||
|
|
d1b74675d9 | ||
|
|
abb81a0bac | ||
|
|
05eb055b8c | ||
|
|
e8ddd6d16d | ||
|
|
8706998c8c | ||
|
|
06e0869767 | ||
|
|
7841fc6d3e | ||
|
|
1f7311deeb | ||
|
|
07a9e69e7b | ||
|
|
9bc8adc715 | ||
|
|
7845ebffc5 | ||
|
|
b985de6df2 | ||
|
|
11f6491889 | ||
|
|
b2ec040a8d | ||
|
|
424a53da4e | ||
|
|
963c289af7 | ||
|
|
c5af71e0a2 | ||
|
|
329008bf6d | ||
|
|
531dbc5f83 | ||
|
|
851a925956 | ||
|
|
5d4e01eea6 | ||
|
|
7484dc5b4c | ||
|
|
e04f5cb277 | ||
|
|
c513cff843 | ||
|
|
a4603a4396 | ||
|
|
bc5eafce66 | ||
|
|
5fb811eb4c | ||
|
|
84a3884ffc | ||
|
|
50ae29a08c | ||
|
|
bf8bfa582a | ||
|
|
492d1ef30e | ||
|
|
bd19c203e1 | ||
|
|
1141f9de86 | ||
|
|
7955a17a17 | ||
|
|
58085e39d1 | ||
|
|
bbc32c4cd0 | ||
|
|
3841039728 | ||
|
|
f04d954882 | ||
|
|
39602ff5f2 | ||
|
|
55ecc7a92c | ||
|
|
1148960d43 | ||
|
|
415107fbf0 | ||
|
|
437cc20198 | ||
|
|
32f78a99fd | ||
|
|
65c7855afd | ||
|
|
7f68e341da | ||
|
|
a2f750ed1a | ||
|
|
b74a42cdf5 | ||
|
|
95b35be541 | ||
|
|
ea747a3d58 | ||
|
|
9b644e3c47 | ||
|
|
3f776397d1 | ||
|
|
1ec75035ba | ||
|
|
97b7b7b968 | ||
|
|
135427dcc8 | ||
|
|
a2de514c05 | ||
|
|
f1bada7fd8 | ||
|
|
ea5d25c794 | ||
|
|
193e420eb3 | ||
|
|
8a972ee543 | ||
|
|
b51eb7326f | ||
|
|
be3b5b7fe2 | ||
|
|
3a7a606f6a | ||
|
|
294fc6b62f | ||
|
|
662a44fccf | ||
|
|
b0a5d4fb6f | ||
|
|
4fb8292618 | ||
|
|
539e5899e3 | ||
|
|
bee9e20827 | ||
|
|
12f527a120 | ||
|
|
bd626899df | ||
|
|
54d036715f | ||
|
|
54c87f81a6 | ||
|
|
5de078dc61 | ||
|
|
ff57de0753 | ||
|
|
9565aee3c5 | ||
|
|
f63da0c58b | ||
|
|
205dbc1a25 | ||
|
|
12c309fd50 | ||
|
|
f04e3d5338 | ||
|
|
dc03d0b300 | ||
|
|
3e16cc4912 | ||
|
|
fcdf252f03 | ||
|
|
b23fea9cb5 | ||
|
|
e714ff35c4 | ||
|
|
4054d0eca7 | ||
|
|
367f9b6232 | ||
|
|
194eb4e266 | ||
|
|
f717eb7388 | ||
|
|
e8f20285af | ||
|
|
0fec9c7c55 | ||
|
|
f8d0ed7ca6 | ||
|
|
020eaef5ba | ||
|
|
973b31521e | ||
|
|
59e513f130 | ||
|
|
62e730b621 | ||
|
|
f4bb62adbc | ||
|
|
48a528a4b8 | ||
|
|
5aba66ea78 | ||
|
|
c5efdf5ae3 | ||
|
|
15958cd4a3 | ||
|
|
edcdc6c97c | ||
|
|
143b807e9b | ||
|
|
861379c227 | ||
|
|
2fb9f62d0b | ||
|
|
84e02fc144 | ||
|
|
57ac90f837 | ||
|
|
10a45ece76 | ||
|
|
c88a177cb2 | ||
|
|
a63dfc4650 | ||
|
|
8924ac2783 | ||
|
|
4fffa2d0ba | ||
|
|
856d2ab266 | ||
|
|
750d2c76f5 | ||
|
|
47157049c0 | ||
|
|
22000f10df | ||
|
|
d802ce1484 | ||
|
|
4b10b9ffc3 | ||
|
|
552408f488 | ||
|
|
4884938036 | ||
|
|
cdcc8cc59a | ||
|
|
f7bd600715 | ||
|
|
0014fec63f | ||
|
|
812efde342 | ||
|
|
889f0e1569 | ||
|
|
3a26c5cd65 | ||
|
|
12a25c37aa | ||
|
|
4706e20a1d | ||
|
|
14c23051ee | ||
|
|
330ddfa3ad | ||
|
|
a1e9a14ef3 | ||
|
|
958f57085f | ||
|
|
646a786b75 | ||
|
|
c8516bc5f4 | ||
|
|
58e87b3ddf | ||
|
|
ea0abb70a2 | ||
|
|
908f9562f6 | ||
|
|
8131d9a640 | ||
|
|
e092f41074 | ||
|
|
79a90dc476 | ||
|
|
25962dbf39 | ||
|
|
8df53e441d | ||
|
|
6f89efa40b | ||
|
|
d6a1b4e71f | ||
|
|
a2c0e53f87 | ||
|
|
013af7619e | ||
|
|
aa302ecc32 | ||
|
|
99b049fe2d | ||
|
|
dbdd1b8671 | ||
|
|
8ba6a7436e | ||
|
|
6e35a9f682 | ||
|
|
78f456911a | ||
|
|
8f5d3dc49c | ||
|
|
97678577fb | ||
|
|
ce67737cc9 | ||
|
|
b9919b0a9c | ||
|
|
226f45d8d5 | ||
|
|
accbf6ecfc | ||
|
|
0aa80d82d9 | ||
|
|
ace5f81a17 | ||
|
|
21a0b33645 | ||
|
|
8b991e11a2 | ||
|
|
8f013776df | ||
|
|
c30aedd309 | ||
|
|
39f303fcd6 | ||
|
|
76c0e140cf | ||
|
|
ccb3c991a6 | ||
|
|
a7932da207 | ||
|
|
5fda20c330 | ||
|
|
1be6e4565f | ||
|
|
e606d0b1de | ||
|
|
b4bcb7ace2 | ||
|
|
a63fee1223 | ||
|
|
ae76ff0aaf | ||
|
|
bba819ba84 | ||
|
|
d0d0da6cb7 | ||
|
|
475113838a | ||
|
|
b8435efc97 | ||
|
|
780e41d6a6 | ||
|
|
6d0b55f753 | ||
|
|
c9fa5c7284 | ||
|
|
e97f4c4054 | ||
|
|
96d15b7505 | ||
|
|
2f77596034 | ||
|
|
5619c105aa | ||
|
|
9a6ee023b3 | ||
|
|
77e2e44abc | ||
|
|
32bddfdd47 | ||
|
|
c9aa654ef0 | ||
|
|
5e501857aa | ||
|
|
6b00aba039 | ||
|
|
14fa9cfa4b | ||
|
|
5633c5224e | ||
|
|
03763a1423 | ||
|
|
cf6df1556c | ||
|
|
cdc8a42393 | ||
|
|
a2fd705153 | ||
|
|
3388f699a0 | ||
|
|
5e197713ff | ||
|
|
50718495da | ||
|
|
b7b604aed4 | ||
|
|
a1f5cabbba | ||
|
|
c2aae6ddf6 | ||
|
|
8a40622815 | ||
|
|
cb88409102 | ||
|
|
b918b75414 | ||
|
|
37f0e36c98 | ||
|
|
c8dc2327a3 | ||
|
|
f660973168 | ||
|
|
cf2e7744f3 | ||
|
|
855d799b21 | ||
|
|
97dd1d0f4f | ||
|
|
5b5553b9a3 | ||
|
|
702545e0b2 | ||
|
|
fa2787eb5d | ||
|
|
0f37b326a0 | ||
|
|
7f9f551cfe | ||
|
|
ecf1847dd2 | ||
|
|
40a9dce869 | ||
|
|
a6696733fa | ||
|
|
d9bd736159 | ||
|
|
4f5f5d31a3 | ||
|
|
fad1325427 | ||
|
|
8b6678a453 | ||
|
|
c7f48a83c0 | ||
|
|
af0f02d63e | ||
|
|
497d63e67e | ||
|
|
4d048af384 | ||
|
|
3649f10600 | ||
|
|
49e69a54bd | ||
|
|
a0acc89fcb | ||
|
|
64d1a82920 | ||
|
|
2396e28479 | ||
|
|
db1ad0df63 | ||
|
|
c5de18caae | ||
|
|
e57774e121 | ||
|
|
b7ee46d400 | ||
|
|
6007132640 | ||
|
|
31b3a4c342 | ||
|
|
73ff852648 | ||
|
|
6d50eb5737 | ||
|
|
3c0b74005b | ||
|
|
93ff667df1 | ||
|
|
a8579fa68a | ||
|
|
10f77fdf1a | ||
|
|
99d824a999 | ||
|
|
97d2b5df15 | ||
|
|
84a9cf7adf | ||
|
|
a49927f173 | ||
|
|
6a5c50ff77 | ||
|
|
c948573c2d | ||
|
|
5233bc501c | ||
|
|
ad96c6f838 | ||
|
|
0e92f68b4a | ||
|
|
ac97e8c613 | ||
|
|
95fe717ca7 | ||
|
|
10b18de3e0 | ||
|
|
08295eb807 | ||
|
|
fce4f0c116 | ||
|
|
cf1424976f | ||
|
|
94e8fce40a | ||
|
|
ea671bf395 | ||
|
|
fdb868516f | ||
|
|
c75bebfc90 | ||
|
|
3e102ef760 | ||
|
|
c07eddbd97 | ||
|
|
e85b925f40 | ||
|
|
27761ba6f2 | ||
|
|
b665698e78 | ||
|
|
97ebe33d68 | ||
|
|
249f7e45fb | ||
|
|
c0612e6193 | ||
|
|
79a789c557 | ||
|
|
450888f542 | ||
|
|
380a08242a | ||
|
|
e653a933f1 | ||
|
|
bda5dffa34 | ||
|
|
29df7e84a1 | ||
|
|
19cf43a10e | ||
|
|
0398ef3b90 | ||
|
|
8c19daf949 | ||
|
|
e4f0688a02 | ||
|
|
25f4fbf2bb | ||
|
|
0533c08438 | ||
|
|
5f0ea85f47 | ||
|
|
6c7c1202ed | ||
|
|
669aa769c2 | ||
|
|
fcf2994015 | ||
|
|
bee21ddc9e | ||
|
|
263e68e677 | ||
|
|
2b958f5724 | ||
|
|
95f7177ef4 | ||
|
|
006324b78e | ||
|
|
efd8c1229d | ||
|
|
0f1aea3e0d | ||
|
|
6a41cbebc9 | ||
|
|
fba95e6a42 | ||
|
|
bffb91f196 | ||
|
|
4573b65639 | ||
|
|
3d8505385a | ||
|
|
95d3a8cc22 | ||
|
|
99c053f86b | ||
|
|
f2dde705ef | ||
|
|
be11fda814 | ||
|
|
0261105c52 | ||
|
|
264047dc0c | ||
|
|
4d84926ed2 | ||
|
|
da3211fee6 | ||
|
|
1388b03cf2 | ||
|
|
9f98b4b082 | ||
|
|
b3f1401ab4 | ||
|
|
e5e3832809 | ||
|
|
2eff7da171 | ||
|
|
e9622bcfe8 | ||
|
|
63ebadc526 | ||
|
|
fe47b07229 | ||
|
|
dc73997be3 | ||
|
|
62315fd478 | ||
|
|
fb81121bd3 | ||
|
|
5293563a6a | ||
|
|
2e1e61dabe | ||
|
|
280d63fde7 | ||
|
|
c6104195f6 | ||
|
|
e55cbb3e3d | ||
|
|
56b85e4194 | ||
|
|
6431c43d0e | ||
|
|
a62107fbd1 | ||
|
|
7959d18248 | ||
|
|
2f66915a9f | ||
|
|
a508177e21 | ||
|
|
5a9d858604 | ||
|
|
514da83961 | ||
|
|
b7bae18849 | ||
|
|
fbde247c72 | ||
|
|
3a69af9034 | ||
|
|
5c87a6cb76 | ||
|
|
9c6bb434e8 | ||
|
|
d1bd303dfa | ||
|
|
3813c32454 | ||
|
|
3b00a692ee | ||
|
|
3304ebe9d3 | ||
|
|
513120cbfe | ||
|
|
b06049d5a3 | ||
|
|
0f50355deb | ||
|
|
bd6e35fea2 | ||
|
|
a4fd63cd44 | ||
|
|
fdc4219b68 | ||
|
|
5b428bb8e6 | ||
|
|
c948ff88a5 | ||
|
|
9b9a0d7060 | ||
|
|
16578e3677 | ||
|
|
be7f84bc67 | ||
|
|
033d26f2cb | ||
|
|
4c0826b1c4 | ||
|
|
c4cc204c94 | ||
|
|
3747db18b1 | ||
|
|
4173625fca | ||
|
|
0e7863a6fb | ||
|
|
207ba00ad2 | ||
|
|
87c89586a5 | ||
|
|
1cea1ced82 | ||
|
|
08732bac0f | ||
|
|
283e8d3c08 | ||
|
|
42a7165596 | ||
|
|
aa3f5001d5 | ||
|
|
56580c4005 | ||
|
|
ba304c9651 | ||
|
|
703c5adba7 | ||
|
|
8b85f6e0a6 | ||
|
|
c136d22382 | ||
|
|
42358419ad | ||
|
|
ab2ced5c37 | ||
|
|
faf31be0dc | ||
|
|
ff4c67d068 | ||
|
|
10b133db02 | ||
|
|
f0bf607b43 | ||
|
|
8948ca5323 | ||
|
|
9c3be51fe9 | ||
|
|
2da9161f29 | ||
|
|
983dad5b53 | ||
|
|
8b23d341b4 | ||
|
|
0ad60013aa | ||
|
|
289815e128 | ||
|
|
f7ee83f1b9 | ||
|
|
f67aafa8d3 | ||
|
|
4e5ddd57bf | ||
|
|
e0d4ecf835 | ||
|
|
81a461115b | ||
|
|
d679b02658 | ||
|
|
5effcdb024 | ||
|
|
211a5eb2bb | ||
|
|
c4465ba58d | ||
|
|
7903c53876 | ||
|
|
dbefe6a560 | ||
|
|
8b1f412255 | ||
|
|
a2e0074061 | ||
|
|
5fc920087b | ||
|
|
085233ab9b | ||
|
|
6657b2629f | ||
|
|
310a279aaf | ||
|
|
58f3a76da7 | ||
|
|
a2c9458b1b | ||
|
|
75bcd9e8d5 | ||
|
|
977e7ef395 | ||
|
|
eb1b8b577f | ||
|
|
28f91685ce | ||
|
|
81a4fe59d9 | ||
|
|
e7189ab81f | ||
|
|
346db89e66 | ||
|
|
f786c7f144 | ||
|
|
51f45293b8 | ||
|
|
943b103001 | ||
|
|
f055d42277 | ||
|
|
fb7a2a8d5d | ||
|
|
1e5ed2a2e3 | ||
|
|
e1467dfe23 | ||
|
|
c480f96d30 | ||
|
|
cf613aafb2 | ||
|
|
20dbf7c5f4 | ||
|
|
47c912c25b | ||
|
|
48fb1a8127 | ||
|
|
6c1b55db16 | ||
|
|
df70c8a800 | ||
|
|
82ae2e7118 | ||
|
|
0cf9b5f3df | ||
|
|
036a825892 | ||
|
|
8b43b31c64 | ||
|
|
3abef972a7 | ||
|
|
30b00741b5 | ||
|
|
f86e743cce | ||
|
|
cb96fb735e | ||
|
|
459a52d31d | ||
|
|
44ef9a13d6 | ||
|
|
0bb3652a63 | ||
|
|
6a82d683a9 | ||
|
|
fad708e8de | ||
|
|
c6a38b8355 | ||
|
|
ee84eb666b | ||
|
|
6d2793cac6 | ||
|
|
86d518fc2e | ||
|
|
25dba1a6d5 | ||
|
|
af949c62c2 | ||
|
|
ea20342d76 | ||
|
|
7732d52583 | ||
|
|
c801bc5e6b | ||
|
|
ea43729063 | ||
|
|
e26bae8027 | ||
|
|
555f155cad | ||
|
|
f8c47f59bc | ||
|
|
f3997128b9 | ||
|
|
154a4e23dd | ||
|
|
52e4e0e569 | ||
|
|
30f2b96c68 | ||
|
|
58c94b7773 | ||
|
|
83203d5f5d | ||
|
|
f77d161643 | ||
|
|
6580b139c0 | ||
|
|
2743c7c6ac | ||
|
|
062f76214e | ||
|
|
ce98ed98a2 | ||
|
|
dce9d93f6c | ||
|
|
f7e35a6cbe | ||
|
|
931335220f | ||
|
|
3ce35a8a4b | ||
|
|
9ac4e5cf6a | ||
|
|
bd77d7eec3 | ||
|
|
b5e48aa509 | ||
|
|
b14c42b6a4 | ||
|
|
ba794ba58c | ||
|
|
b00282590d | ||
|
|
44616c6872 | ||
|
|
aaa2b4c3db | ||
|
|
8974d8e4df | ||
|
|
699063cbb0 | ||
|
|
e76000b713 | ||
|
|
332b372e31 | ||
|
|
cb3fcb7bfa | ||
|
|
bef641609e | ||
|
|
24b52f09df | ||
|
|
942b17b807 | ||
|
|
cf19d7f3ad | ||
|
|
ebd62a4112 | ||
|
|
9af7357ca4 | ||
|
|
0dbc35c252 | ||
|
|
c9f03f1ac5 | ||
|
|
02bd292b8c | ||
|
|
e5f1029d0c | ||
|
|
cae247160f | ||
|
|
6692b1992c | ||
|
|
0937837b7f | ||
|
|
828888490a | ||
|
|
91cb6ba73b | ||
|
|
4ee4d32b2e | ||
|
|
8df630a2f5 | ||
|
|
2cad42870e | ||
|
|
43651135f3 | ||
|
|
6ae42eb787 | ||
|
|
ecaf866613 | ||
|
|
5ea3329b36 | ||
|
|
7bb7149f4c | ||
|
|
5856d043ca | ||
|
|
7cd3e49f04 | ||
|
|
173e75175e | ||
|
|
800006dd76 | ||
|
|
a824b6910a | ||
|
|
dcea382b38 | ||
|
|
d9f976baea | ||
|
|
1fa13efe19 | ||
|
|
33af5cd7c6 | ||
|
|
7cb8f97ef1 | ||
|
|
bf965a9cde | ||
|
|
17ffff685a | ||
|
|
ae76271cff | ||
|
|
8f3a96d615 | ||
|
|
30e750dfe5 | ||
|
|
682dff7c6f | ||
|
|
85415eb8a8 | ||
|
|
68a80b9244 | ||
|
|
c331da7323 | ||
|
|
04ffa06221 | ||
|
|
1f0690c6ec | ||
|
|
711467abcd | ||
|
|
9439cd0e3d | ||
|
|
314c19650d | ||
|
|
ed6afcd802 | ||
|
|
082d4fe8e1 | ||
|
|
cd23b44506 | ||
|
|
46b6b024b9 | ||
|
|
cb88cc35e5 | ||
|
|
75c0c44809 | ||
|
|
a091b82ba9 | ||
|
|
a3b8f022e6 | ||
|
|
279fcb7c51 | ||
|
|
49a9376073 | ||
|
|
96840ede56 | ||
|
|
7e7f481f99 | ||
|
|
3edbf52bc6 | ||
|
|
fba6e801fc | ||
|
|
720a163273 | ||
|
|
a9b12e5172 | ||
|
|
6ac0c0a367 | ||
|
|
300402d253 | ||
|
|
0d9bfae503 | ||
|
|
bfe0d3b8a3 | ||
|
|
5fdd9c0546 | ||
|
|
b6570a16b8 | ||
|
|
8e2d3ea16f | ||
|
|
bc2c81f058 | ||
|
|
3e0f080ea7 | ||
|
|
679e07189d | ||
|
|
a38ebef100 | ||
|
|
b8ad6475e1 | ||
|
|
0f0cb3ac6d | ||
|
|
d3efb9d7cc | ||
|
|
84a237d3f5 | ||
|
|
e6de52eede | ||
|
|
98aee964d7 | ||
|
|
570e5442e0 | ||
|
|
b77a2dc353 | ||
|
|
87af31de20 | ||
|
|
cfe201dbe1 | ||
|
|
6ccdab35e0 | ||
|
|
55b9f36b45 | ||
|
|
fbcb1130c9 | ||
|
|
d4f7a6d2bc | ||
|
|
8a19f71abe | ||
|
|
fb153757b5 | ||
|
|
4f175fc93e | ||
|
|
2d4ca7cec0 | ||
|
|
bf0ea89969 | ||
|
|
073f0c2a20 | ||
|
|
ba83be9062 | ||
|
|
2e7188ea4f | ||
|
|
5a012182d9 | ||
|
|
b855438af6 | ||
|
|
2ffea143e7 | ||
|
|
61d85b49e6 | ||
|
|
35f617e96c | ||
|
|
6b6ad47c35 | ||
|
|
e57183ed0e | ||
|
|
ecfd61a822 | ||
|
|
153f87704b | ||
|
|
836f7d2163 | ||
|
|
d4d6f71cf4 | ||
|
|
42a9da006e | ||
|
|
2bd5c4f527 | ||
|
|
6a49b5c106 | ||
|
|
23e14d1b72 | ||
|
|
f4f11c8884 | ||
|
|
2b220abdb7 | ||
|
|
c1d947ebe3 | ||
|
|
d695cf392e | ||
|
|
21304a695c | ||
|
|
fa51b06c46 | ||
|
|
7560bb8d7b | ||
|
|
fc9d65abcc | ||
|
|
a7413cccd0 | ||
|
|
7610353f07 | ||
|
|
d3f978c90c | ||
|
|
b55a8ef62a | ||
|
|
8d79deffb5 | ||
|
|
8158487c3e | ||
|
|
0cc061196d | ||
|
|
d0ec055222 | ||
|
|
ae12ddd32b | ||
|
|
31da3adaa9 | ||
|
|
9fd5213f13 | ||
|
|
de882f5849 | ||
|
|
fded1e0021 | ||
|
|
6cb06c146d | ||
|
|
b8f1386ad0 | ||
|
|
2b38b5ea50 | ||
|
|
2f707a6b16 | ||
|
|
d4c2fcd559 | ||
|
|
082970cdb7 | ||
|
|
fe97c78977 | ||
|
|
79394aa69f | ||
|
|
21fd6e3c21 | ||
|
|
de4944cd83 | ||
|
|
3fde5c27ed | ||
|
|
e1d492813e | ||
|
|
48d0ee3b6d | ||
|
|
eebb64901c | ||
|
|
60e0ed2af6 | ||
|
|
f030694ef4 | ||
|
|
e9ed13459a | ||
|
|
af1e38fdf7 | ||
|
|
b12900e680 | ||
|
|
44aa1f4a5e | ||
|
|
9425548a85 | ||
|
|
bfd4fc81fe | ||
|
|
439af2a325 | ||
|
|
3204b04455 | ||
|
|
bed1be14ba | ||
|
|
7cd92faf0d | ||
|
|
be7e28af5d | ||
|
|
8eaa762ec5 | ||
|
|
953a9f7cd4 | ||
|
|
36f099d68b | ||
|
|
c8fd5090bd | ||
|
|
155e1be494 | ||
|
|
cf5e125cb3 | ||
|
|
764fc8477d | ||
|
|
d35e62f8cf | ||
|
|
904babdd13 | ||
|
|
154d3842a8 | ||
|
|
edb8a120bd | ||
|
|
cdfeba0b82 | ||
|
|
8ce1465e9f | ||
|
|
a296b1c9c8 | ||
|
|
bb8d7058a4 | ||
|
|
816cfa1c7e | ||
|
|
53938200fc | ||
|
|
3885bb039d | ||
|
|
4adad6e424 | ||
|
|
5fb9531338 | ||
|
|
273d9c76a7 | ||
|
|
79a1d6c561 | ||
|
|
4b0eb8475d | ||
|
|
3dc874b517 | ||
|
|
8a3da1ce8d | ||
|
|
42d90542b5 | ||
|
|
690a93d82d | ||
|
|
8042fe4e2b | ||
|
|
a27ce375db | ||
|
|
db3688799d | ||
|
|
a88be35292 | ||
|
|
e2d7fcbfc2 | ||
|
|
421d155586 | ||
|
|
7f9e318214 | ||
|
|
57386edb7c | ||
|
|
94d5ba4550 | ||
|
|
2a0b4ea828 | ||
|
|
893ef227d4 | ||
|
|
1fe6e5a00d | ||
|
|
6c96cde73c | ||
|
|
2b12834d53 | ||
|
|
8a2e74b3b8 | ||
|
|
aa1721ab3d | ||
|
|
c0a256306b | ||
|
|
f0b03b4ada | ||
|
|
5503f53af2 | ||
|
|
a89d294b27 | ||
|
|
012e1cbcc5 | ||
|
|
3759e0f778 | ||
|
|
1c18641699 | ||
|
|
e50e2201b1 | ||
|
|
1419729458 | ||
|
|
c14177b0e8 | ||
|
|
126df969b3 | ||
|
|
f8ee92ba06 | ||
|
|
81a278dd8c | ||
|
|
a98013806c | ||
|
|
0171ffac6a | ||
|
|
7544241316 | ||
|
|
061afb3a94 | ||
|
|
8a5eda9c1f | ||
|
|
f62040f0ec | ||
|
|
f2e51779e4 | ||
|
|
da114fa3a5 | ||
|
|
3775a1657b | ||
|
|
2bd7c4bc81 | ||
|
|
253c489a33 | ||
|
|
ac84b6fe3f | ||
|
|
8761e61439 | ||
|
|
29e903e1c8 | ||
|
|
ec27e19e3f | ||
|
|
5df0dae11a | ||
|
|
7fffc1a36d | ||
|
|
f3d0179834 | ||
|
|
8bf69c598a | ||
|
|
aa5fad6628 | ||
|
|
b0f1fad4e2 | ||
|
|
3b6d0995b4 | ||
|
|
0cbf4ac37d | ||
|
|
9ccffee82c | ||
|
|
1b38e2eedf | ||
|
|
ce87abe96e | ||
|
|
becbda8483 | ||
|
|
da210e2ae4 | ||
|
|
d4fc6feeba | ||
|
|
f1cbca8d76 | ||
|
|
dfd9364061 | ||
|
|
1931395fdb | ||
|
|
b01fd24e15 | ||
|
|
c9d1329fc2 | ||
|
|
ab2d3bfd80 | ||
|
|
36bb172f29 | ||
|
|
01e64be39d | ||
|
|
4ebe160f6c | ||
|
|
b427eca21f | ||
|
|
3eb438c8d2 | ||
|
|
068f425833 | ||
|
|
b3c84242dc | ||
|
|
24672d91d8 | ||
|
|
4422af26ec | ||
|
|
5329e803e2 | ||
|
|
ad542b91fa | ||
|
|
e9e03c945b | ||
|
|
e20cfb3dae | ||
|
|
48baac916c | ||
|
|
adadf38b08 | ||
|
|
d4e1469450 | ||
|
|
2c456f044f | ||
|
|
228c15ace3 | ||
|
|
a0d15e6e7b | ||
|
|
2fe78cf971 | ||
|
|
5ec3544340 | ||
|
|
5443a17775 | ||
|
|
40d60e4eb3 | ||
|
|
f3312a6403 | ||
|
|
e638b55b30 | ||
|
|
5caa76a8b3 | ||
|
|
901a5ce9d2 | ||
|
|
6ab74951f4 | ||
|
|
c2625d696d | ||
|
|
77fb5ef2ab | ||
|
|
c20ca3399e | ||
|
|
5825da9c76 | ||
|
|
e3853ae402 | ||
|
|
bd142a9710 | ||
|
|
4f23847546 | ||
|
|
85820c571d | ||
|
|
d9bed03025 | ||
|
|
d6e05962c9 | ||
|
|
d32636ed6b | ||
|
|
bbf066f030 | ||
|
|
a3d2f6592e | ||
|
|
87b6327c5e | ||
|
|
abaebb329d | ||
|
|
8970fe412d | ||
|
|
9dc5ae21c4 | ||
|
|
4132fb79a6 | ||
|
|
9a4dc30604 | ||
|
|
192b542fe4 | ||
|
|
490547cd3d | ||
|
|
17f9829498 | ||
|
|
234e77fd06 | ||
|
|
87ac831c8a | ||
|
|
4e92492165 | ||
|
|
c3d0b1114f | ||
|
|
4463a7d4ba | ||
|
|
741fe3dd90 | ||
|
|
e910f3915d | ||
|
|
39aafc5007 | ||
|
|
9b83afae42 | ||
|
|
bdf54f6cff | ||
|
|
f2a9887a12 | ||
|
|
4f4d78bfab | ||
|
|
3b460fb8fa | ||
|
|
ee15e9acc5 | ||
|
|
48fce35fb3 | ||
|
|
78899378c2 | ||
|
|
67404a327d | ||
|
|
702dfa4b79 | ||
|
|
2144407e41 | ||
|
|
b36dd62c50 | ||
|
|
7026df7d96 | ||
|
|
ed8e7afdf6 | ||
|
|
d78e5932f9 | ||
|
|
26d83bb9ea | ||
|
|
8e89b1bdf2 | ||
|
|
c880cc0987 | ||
|
|
0874ba7a03 | ||
|
|
7962278475 | ||
|
|
c8949f5eeb | ||
|
|
8108b93c5f | ||
|
|
9dbe531bf7 | ||
|
|
46e2ff1001 | ||
|
|
d2cdc67ec7 | ||
|
|
56121203bf | ||
|
|
e13133fd2b | ||
|
|
f20565fd16 | ||
|
|
cf2d5841f5 | ||
|
|
630d2ca926 | ||
|
|
34cb93794c | ||
|
|
122b5ba468 | ||
|
|
401466d6c0 | ||
|
|
7f2627dbc8 | ||
|
|
6aecc3915c | ||
|
|
ef1b3aa7f5 | ||
|
|
1aaab2a814 | ||
|
|
e93734b209 | ||
|
|
9e5218f6b4 | ||
|
|
711ec39327 | ||
|
|
08049252f2 | ||
|
|
f1e7ec0c6b | ||
|
|
23765d9139 | ||
|
|
43febe269c | ||
|
|
40233c7702 | ||
|
|
27ed81614b | ||
|
|
889d23e9bd | ||
|
|
f8571023f6 | ||
|
|
6364e00202 | ||
|
|
a76c6f86c6 | ||
|
|
555e815402 | ||
|
|
8a1d81989b | ||
|
|
ee9234b2c6 | ||
|
|
735b9c5844 | ||
|
|
064f3eb3bc | ||
|
|
f1775d4fd1 | ||
|
|
a9bc111c4f | ||
|
|
c100612473 | ||
|
|
26087f8dc7 | ||
|
|
36e75cb728 | ||
|
|
d7a2fc2be4 | ||
|
|
142176f194 | ||
|
|
c5892fc17e | ||
|
|
6e69cfbca4 | ||
|
|
775181f761 | ||
|
|
36e83d628e | ||
|
|
5f6fcb2bc0 | ||
|
|
7b106e5650 | ||
|
|
79d9c83a2d | ||
|
|
269669ba28 | ||
|
|
4ef7240598 | ||
|
|
efdf689c31 | ||
|
|
f7606e92ca | ||
|
|
6750be3ec9 | ||
|
|
68fb5089f8 | ||
|
|
a8d093bacd | ||
|
|
233a1995b3 | ||
|
|
8ef3baaffb | ||
|
|
4d26b806dd | ||
|
|
a2b95dbb39 | ||
|
|
d820f55358 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
path: 'node-red.github.io'
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '12'
|
||||
node-version: '16'
|
||||
- run: node ./node-red/.github/scripts/update-node-red-docker.js
|
||||
- name: Create Docker Pull Request
|
||||
uses: peter-evans/create-pull-request@v2
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12, 14, 16]
|
||||
node-version: [14, 16]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
|
||||
3271
CHANGELOG.md
3271
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -38,12 +38,9 @@ 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 [forum](https://discourse.nodered.org) first.
|
||||
|
||||
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.
|
||||
|
||||
If you raise a pull-request without having signed the CLA, you will be prompted
|
||||
to do so automatically.
|
||||
All contributors need to sign the OpenJS Foundation's Contributor License Agreement.
|
||||
It is an online process and quick to do. If you raise a pull-request without
|
||||
having signed the CLA, you will be prompted to do so automatically.
|
||||
|
||||
|
||||
### Code Branches
|
||||
|
||||
22
Gruntfile.js
22
Gruntfile.js
@@ -162,9 +162,10 @@ module.exports = function(grunt) {
|
||||
"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/common/toggleButton.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.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/diagnostics.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",
|
||||
@@ -182,6 +183,7 @@ module.exports = function(grunt) {
|
||||
"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/panes/*.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/*.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
|
||||
@@ -190,6 +192,7 @@ module.exports = function(grunt) {
|
||||
"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/contextMenu.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actionList.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",
|
||||
@@ -199,7 +202,8 @@ module.exports = function(grunt) {
|
||||
"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"
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/tour/*.js"
|
||||
],
|
||||
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
|
||||
},
|
||||
@@ -326,6 +330,12 @@ module.exports = function(grunt) {
|
||||
],
|
||||
tasks: ['jsonlint:keymaps','copy:build']
|
||||
},
|
||||
tours: {
|
||||
files: [
|
||||
'packages/node_modules/@node-red/editor-client/src/tours/**/*.js'
|
||||
],
|
||||
tasks: ['copy:build']
|
||||
},
|
||||
misc: {
|
||||
files: [
|
||||
'CHANGELOG.md'
|
||||
@@ -423,6 +433,12 @@ module.exports = function(grunt) {
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
|
||||
},
|
||||
{
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/tours',
|
||||
src: '**',
|
||||
expand: true,
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/tours/'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -569,7 +585,7 @@ module.exports = function(grunt) {
|
||||
grunt.registerMultiTask('attachCopyright', function() {
|
||||
var files = this.data.src;
|
||||
var copyright = "/**\n"+
|
||||
" * Copyright JS Foundation and other contributors, http://js.foundation\n"+
|
||||
" * Copyright OpenJS Foundation and other contributors, https://openjsf.org/\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"+
|
||||
|
||||
10
README.md
10
README.md
@@ -56,13 +56,13 @@ This project adheres to the [Contributor Covenant 1.4](http://contributor-covena
|
||||
|
||||
## Authors
|
||||
|
||||
Node-RED is a project of the [OpenJS Foundation](https://openjsf.org).
|
||||
Node-RED is a project of the [OpenJS Foundation](http://openjsf.org).
|
||||
|
||||
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)
|
||||
It is maintained by:
|
||||
|
||||
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
|
||||
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
|
||||
* And many others...
|
||||
|
||||
|
||||
## Copyright and license
|
||||
|
||||
99
package.json
99
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0-beta.3",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -26,76 +26,77 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"acorn": "8.4.1",
|
||||
"acorn-walk": "8.1.1",
|
||||
"ajv": "8.6.0",
|
||||
"async-mutex": "0.3.1",
|
||||
"acorn": "8.7.1",
|
||||
"acorn-walk": "8.2.0",
|
||||
"ajv": "8.11.0",
|
||||
"async-mutex": "0.3.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
"body-parser": "1.20.0",
|
||||
"cheerio": "1.0.0-rc.10",
|
||||
"clone": "2.1.2",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.1",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cookie": "0.5.0",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
"denque": "1.5.0",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.2",
|
||||
"denque": "2.0.1",
|
||||
"express": "4.18.1",
|
||||
"express-session": "1.17.3",
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"got": "11.8.2",
|
||||
"fs-extra": "10.1.0",
|
||||
"got": "11.8.3",
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "^0.1.2",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"i18next": "20.3.2",
|
||||
"hpagent": "1.0.0",
|
||||
"https-proxy-agent": "5.0.1",
|
||||
"i18next": "21.8.10",
|
||||
"iconv-lite": "0.6.3",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.1",
|
||||
"js-yaml": "4.1.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.4",
|
||||
"jsonata": "1.8.6",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.6",
|
||||
"mime": "2.5.2",
|
||||
"moment-timezone": "0.5.33",
|
||||
"mqtt": "4.2.8",
|
||||
"multer": "1.4.2",
|
||||
"memorystore": "1.6.7",
|
||||
"mime": "3.0.0",
|
||||
"moment": "2.29.3",
|
||||
"moment-timezone": "0.5.34",
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^2.2.0",
|
||||
"node-red-admin": "^3.0.0",
|
||||
"node-watch": "0.7.3",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.4.1",
|
||||
"passport": "0.5.2",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.4.1",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.0",
|
||||
"raw-body": "2.5.1",
|
||||
"semver": "7.3.7",
|
||||
"tar": "6.1.11",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uglify-js": "3.13.10",
|
||||
"uglify-js": "3.16.0",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.1",
|
||||
"ws": "7.5.6",
|
||||
"xml2js": "0.4.23"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dompurify": "2.2.9",
|
||||
"grunt": "1.4.1",
|
||||
"dompurify": "2.3.8",
|
||||
"grunt": "1.5.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.4.3",
|
||||
"grunt-concurrent": "3.0.0",
|
||||
"grunt-contrib-clean": "~2.0.0",
|
||||
"grunt-contrib-clean": "2.0.1",
|
||||
"grunt-contrib-compress": "2.0.0",
|
||||
"grunt-contrib-concat": "~1.0.1",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-jshint": "3.0.0",
|
||||
"grunt-contrib-uglify": "5.0.1",
|
||||
"grunt-contrib-watch": "~1.1.0",
|
||||
"grunt-contrib-concat": "2.1.0",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-contrib-jshint": "3.2.0",
|
||||
"grunt-contrib-uglify": "5.2.1",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"grunt-jsdoc": "2.4.1",
|
||||
"grunt-jsdoc-to-markdown": "6.0.0",
|
||||
"grunt-jsonlint": "2.1.3",
|
||||
@@ -104,22 +105,22 @@
|
||||
"grunt-sass": "~3.1.0",
|
||||
"grunt-simple-mocha": "~0.4.1",
|
||||
"grunt-simple-nyc": "^3.0.1",
|
||||
"i18next-http-backend": "1.2.6",
|
||||
"i18next-http-backend": "1.4.1",
|
||||
"jquery-i18next": "1.2.1",
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "2.1.3",
|
||||
"marked": "4.0.17",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "9.0.1",
|
||||
"node-red-node-test-helper": "^0.2.7",
|
||||
"nodemon": "2.0.8",
|
||||
"mocha": "9.2.2",
|
||||
"node-red-node-test-helper": "^0.3.0",
|
||||
"nodemon": "2.0.16",
|
||||
"proxy": "^1.0.2",
|
||||
"sass": "1.35.1",
|
||||
"sass": "1.52.3",
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.1",
|
||||
"sinon": "11.1.2",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "6.1.3"
|
||||
"supertest": "6.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=14"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
|
||||
23
packages/node_modules/@node-red/editor-api/lib/admin/diagnostics.js
vendored
Normal file
23
packages/node_modules/@node-red/editor-api/lib/admin/diagnostics.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
let runtimeAPI;
|
||||
let settings;
|
||||
const apiUtil = require("../util");
|
||||
module.exports = {
|
||||
init: function(_settings, _runtimeAPI) {
|
||||
settings = _settings;
|
||||
runtimeAPI = _runtimeAPI;
|
||||
},
|
||||
getReport: function(req, res) {
|
||||
const diagnosticsOpts = settings.diagnostics || {};
|
||||
const opts = {
|
||||
user: req.user,
|
||||
scope: diagnosticsOpts.level || "basic"
|
||||
}
|
||||
if(diagnosticsOpts.enabled === false || diagnosticsOpts.enabled === "false") {
|
||||
apiUtil.rejectHandler(req, res, {message: "diagnostics are disabled", status: 403, code: "diagnostics.disabled" })
|
||||
} else {
|
||||
runtimeAPI.diagnostics.get(opts)
|
||||
.then(function(result) { res.json(result); })
|
||||
.catch(err => apiUtil.rejectHandler(req, res, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ var context = require("./context");
|
||||
var auth = require("../auth");
|
||||
var info = require("./settings");
|
||||
var plugins = require("./plugins");
|
||||
var diagnostics = require("./diagnostics");
|
||||
|
||||
var apiUtil = require("../util");
|
||||
|
||||
@@ -34,6 +35,7 @@ module.exports = {
|
||||
context.init(runtimeAPI);
|
||||
info.init(settings,runtimeAPI);
|
||||
plugins.init(runtimeAPI);
|
||||
diagnostics.init(settings, runtimeAPI);
|
||||
|
||||
var needsPermission = auth.needsPermission;
|
||||
|
||||
@@ -95,6 +97,8 @@ module.exports = {
|
||||
adminApp.get("/plugins", needsPermission("plugins.read"), plugins.getAll, apiUtil.errorHandler);
|
||||
adminApp.get("/plugins/messages", needsPermission("plugins.read"), plugins.getCatalogs, apiUtil.errorHandler);
|
||||
|
||||
adminApp.get("/diagnostics", needsPermission("diagnostics.read"), diagnostics.getReport, apiUtil.errorHandler);
|
||||
|
||||
return adminApp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,9 +106,15 @@ async function login(req,res) {
|
||||
urlPrefix += "/";
|
||||
}
|
||||
response = {
|
||||
"type":"strategy",
|
||||
"prompts":[{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}]
|
||||
"type":"strategy"
|
||||
}
|
||||
if (mergedAdminAuth.strategy.autoLogin) {
|
||||
response.autoLogin = true
|
||||
response.loginRedirect = urlPrefix + "auth/strategy"
|
||||
}
|
||||
response.prompts = [
|
||||
{type:"button",label:mergedAdminAuth.strategy.label, url: urlPrefix + "auth/strategy"}
|
||||
]
|
||||
if (mergedAdminAuth.strategy.icon) {
|
||||
response.prompts[0].icon = mergedAdminAuth.strategy.icon;
|
||||
}
|
||||
@@ -141,7 +147,7 @@ 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});
|
||||
log.audit({event: "auth.login",user,username:user.username,scope:user.permissions});
|
||||
user.tokens = tokens;
|
||||
done(null,user);
|
||||
});
|
||||
@@ -173,31 +179,38 @@ function genericStrategy(adminApp,strategy) {
|
||||
adminApp.use(passport.session());
|
||||
|
||||
var options = strategy.options;
|
||||
var verify = 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);
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
options.verify.apply(this,args);
|
||||
} else {
|
||||
var profile = arguments[arguments.length - 2];
|
||||
return completeVerify(profile,originalDone);
|
||||
}
|
||||
));
|
||||
};
|
||||
// Give our callback the same arity as the original one from options
|
||||
if (options.verify) {
|
||||
Object.defineProperty(verify, "length", { value: options.verify.length })
|
||||
}
|
||||
|
||||
passport.use(new strategy.strategy(options, verify));
|
||||
|
||||
adminApp.get('/auth/strategy',
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
passport.authenticate(strategy.name, {session:false,
|
||||
failureMessage: true,
|
||||
failureRedirect: settings.httpAdminRoot
|
||||
}),
|
||||
completeGenerateStrategyAuth,
|
||||
handleStrategyError
|
||||
);
|
||||
|
||||
var callbackMethodFunc = adminApp.get;
|
||||
@@ -205,8 +218,13 @@ function genericStrategy(adminApp,strategy) {
|
||||
callbackMethodFunc = adminApp.post;
|
||||
}
|
||||
callbackMethodFunc.call(adminApp,'/auth/strategy/callback',
|
||||
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
|
||||
completeGenerateStrategyAuth
|
||||
passport.authenticate(strategy.name, {
|
||||
session:false,
|
||||
failureMessage: true,
|
||||
failureRedirect: settings.httpAdminRoot
|
||||
}),
|
||||
completeGenerateStrategyAuth,
|
||||
handleStrategyError
|
||||
);
|
||||
|
||||
}
|
||||
@@ -216,6 +234,13 @@ function completeGenerateStrategyAuth(req,res) {
|
||||
// Successful authentication, redirect home.
|
||||
res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken);
|
||||
}
|
||||
function handleStrategyError(err, req, res, next) {
|
||||
if (res.headersSent) {
|
||||
return next(err)
|
||||
}
|
||||
log.audit({event: "auth.login.fail.oauth",error:err.toString()});
|
||||
res.redirect(settings.httpAdminRoot + '?session_message='+err.toString());
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
|
||||
@@ -92,10 +92,16 @@ var passwordTokenExchange = function(client, username, password, scope, done) {
|
||||
loginAttempts = loginAttempts.filter(function(logEntry) {
|
||||
return logEntry.user !== username;
|
||||
});
|
||||
Tokens.create(username,client.id,scope).then(function(tokens) {
|
||||
log.audit({event: "auth.login",username:username,client:client.id,scope:scope});
|
||||
done(null,tokens.accessToken,null,{expires_in:tokens.expires_in});
|
||||
});
|
||||
// Check if the user contains a user defined token and use it
|
||||
// instead of generating a new token
|
||||
if(user.token){
|
||||
done(null,user.token,null,null);
|
||||
} else {
|
||||
Tokens.create(username,client.id,scope).then(function(tokens) {
|
||||
log.audit({event: "auth.login",user,username:username,client:client.id,scope:scope});
|
||||
done(null,tokens.accessToken,null,{expires_in:tokens.expires_in});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
log.audit({event: "auth.login.fail.permissions",username:username,client:client.id,scope:scope});
|
||||
done(null,false);
|
||||
@@ -146,7 +152,7 @@ function authenticateUserToken(req) {
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}).catch(reject);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
@@ -163,6 +169,9 @@ TokensStrategy.prototype.authenticate = function(req) {
|
||||
authenticateUserToken(req).then(user => {
|
||||
this.success(user,{scope:user.permissions});
|
||||
}).catch(err => {
|
||||
if (err) {
|
||||
log.trace("token authentication failure: "+err.stack?err.stack:err)
|
||||
}
|
||||
this.fail(401);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,9 +48,10 @@ module.exports = {
|
||||
var prevLang = i18n.i.language;
|
||||
// Trigger a load from disk of the language if it is not the default
|
||||
i18n.i.changeLanguage(lang, function(){
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
i18n.i.changeLanguage(prevLang, function() {
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
});
|
||||
});
|
||||
i18n.i.changeLanguage(prevLang);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
if (req.body.active) {
|
||||
opts.clearContext = req.body.hasOwnProperty('clearContext')?req.body.clearContext:true
|
||||
runtimeAPI.projects.setActiveProject(opts).then(function() {
|
||||
listProjects(req,res);
|
||||
}).catch(function(err) {
|
||||
|
||||
@@ -18,14 +18,6 @@ var apiUtils = require("../util");
|
||||
var express = require("express");
|
||||
var runtimeAPI;
|
||||
|
||||
function getUsername(userObj) {
|
||||
var username = '__default';
|
||||
if ( userObj && userObj.name ) {
|
||||
username = userObj.name;
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
|
||||
@@ -24,15 +24,19 @@ var defaultContext = {
|
||||
page: {
|
||||
title: "Node-RED",
|
||||
favicon: "favicon.ico",
|
||||
tabicon: "red/images/node-red-icon-black.svg"
|
||||
tabicon: {
|
||||
icon: "red/images/node-red-icon-black.svg",
|
||||
colour: "#8f0000"
|
||||
},
|
||||
version: require(path.join(__dirname,"../../package.json")).version
|
||||
},
|
||||
header: {
|
||||
title: "Node-RED",
|
||||
image: "red/images/node-red.svg"
|
||||
},
|
||||
asset: {
|
||||
red: (process.env.NODE_ENV == "development")? "red/red.js":"red/red.min.js",
|
||||
main: (process.env.NODE_ENV == "development")? "red/main.js":"red/main.min.js",
|
||||
red: "red/red.min.js",
|
||||
main: "red/main.min.js",
|
||||
vendorMonaco: ""
|
||||
}
|
||||
};
|
||||
@@ -74,7 +78,7 @@ function serveFilesFromTheme(themeValue, themeApp, directory, baseDirectory) {
|
||||
let fullPath = array[i];
|
||||
if (baseDirectory) {
|
||||
fullPath = path.resolve(baseDirectory,array[i]);
|
||||
if (fullPath.indexOf(baseDirectory) !== 0) {
|
||||
if (fullPath.indexOf(path.resolve(baseDirectory)) !== 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -91,6 +95,10 @@ module.exports = {
|
||||
init: function(settings, _runtimeAPI) {
|
||||
runtimeAPI = _runtimeAPI;
|
||||
themeContext = clone(defaultContext);
|
||||
if (process.env.NODE_ENV == "development") {
|
||||
themeContext.asset.red = "red/red.js";
|
||||
themeContext.asset.main = "red/main.js";
|
||||
}
|
||||
themeSettings = null;
|
||||
theme = settings.editorTheme || {};
|
||||
themeContext.asset.vendorMonaco = ((theme.codeEditor || {}).lib === "monaco") ? "vendor/monaco/monaco-bootstrap.js" : "";
|
||||
@@ -123,9 +131,13 @@ module.exports = {
|
||||
}
|
||||
|
||||
if (theme.page.tabicon) {
|
||||
url = serveFile(themeApp,"/tabicon/",theme.page.tabicon)
|
||||
let icon = theme.page.tabicon.icon || theme.page.tabicon
|
||||
url = serveFile(themeApp,"/tabicon/", icon)
|
||||
if (url) {
|
||||
themeContext.page.tabicon = url;
|
||||
themeContext.page.tabicon.icon = url;
|
||||
}
|
||||
if (theme.page.tabicon.colour) {
|
||||
themeContext.page.tabicon.colour = theme.page.tabicon.colour
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +228,11 @@ module.exports = {
|
||||
if (theme.theme) {
|
||||
themeSettings.theme = theme.theme;
|
||||
}
|
||||
|
||||
if (theme.hasOwnProperty("tours")) {
|
||||
themeSettings.tours = theme.tours;
|
||||
}
|
||||
|
||||
return themeApp;
|
||||
},
|
||||
context: async function() {
|
||||
@@ -246,6 +263,9 @@ module.exports = {
|
||||
theme.page = theme.page || {_:{}}
|
||||
theme.page._.scripts = scriptFiles.concat(theme.page._.scripts || [])
|
||||
}
|
||||
if(theme.codeEditor) {
|
||||
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
|
||||
}
|
||||
}
|
||||
activeThemeInitialised = true;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,16 @@ module.exports = {
|
||||
},
|
||||
|
||||
editor: async function(req,res) {
|
||||
res.send(Mustache.render(editorTemplate,await theme.context()));
|
||||
|
||||
let sessionMessages;
|
||||
if (req.session && req.session.messages) {
|
||||
sessionMessages = JSON.stringify(req.session.messages);
|
||||
delete req.session.messages
|
||||
}
|
||||
res.send(Mustache.render(editorTemplate,{
|
||||
sessionMessages,
|
||||
...await theme.context()
|
||||
}));
|
||||
},
|
||||
editorResources: express.static(path.join(editorClientDir,'public'))
|
||||
};
|
||||
|
||||
@@ -90,6 +90,8 @@ function init(settings,_server,storage,runtimeAPI) {
|
||||
auth.getToken,
|
||||
auth.errorHandler
|
||||
);
|
||||
} else if (settings.adminAuth.tokens) {
|
||||
adminApp.use(passport.initialize());
|
||||
}
|
||||
adminApp.post("/auth/revoke",auth.needsPermission(""),auth.revoke,apiUtil.errorHandler);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0-beta.3",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,23 +16,23 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.0.1",
|
||||
"@node-red/editor-client": "2.0.1",
|
||||
"@node-red/util": "3.0.0-beta.3",
|
||||
"@node-red/editor-client": "3.0.0-beta.3",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
"body-parser": "1.20.0",
|
||||
"clone": "2.1.2",
|
||||
"cors": "2.8.5",
|
||||
"express-session": "1.17.2",
|
||||
"express": "4.17.1",
|
||||
"memorystore": "1.6.6",
|
||||
"mime": "2.5.2",
|
||||
"multer": "1.4.2",
|
||||
"express-session": "1.17.3",
|
||||
"express": "4.18.1",
|
||||
"memorystore": "1.6.7",
|
||||
"mime": "3.0.0",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.4.1",
|
||||
"ws": "7.5.1"
|
||||
"passport": "0.5.2",
|
||||
"ws": "7.5.6"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "5.0.1"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
|
||||
@@ -185,7 +185,8 @@
|
||||
"create-default-package": "Standardpaketdatei erstellen",
|
||||
"no-thanks": "Nein, Danke",
|
||||
"create-default-project": "Standardprojektdateien erstellen",
|
||||
"show-merge-conflicts": "Merge-Konflikte anzeigen"
|
||||
"show-merge-conflicts": "Merge-Konflikte anzeigen",
|
||||
"unknownNodesButton": "Finden Sie unbekannte nodes"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
@@ -269,7 +270,9 @@
|
||||
"successfulRestart": "Flows erfolgreich neugestartet",
|
||||
"deployFailed": "Übernahme (deploy) fehlgeschlagen: __message__",
|
||||
"unusedConfigNodes": "Einige Konfigurations-Nodes werden nicht verwendet.",
|
||||
"unusedConfigNodesLink": "Hier klicken, um sie anzuschauen.",
|
||||
"unusedConfigNodesButton":"Finden Sie ungenutzte konfig nodes",
|
||||
"unknownNodesButton":"Finden Sie unbekannte nodes",
|
||||
"invalidNodesButton":"Finden Sie ungültige nodes",
|
||||
"errors": {
|
||||
"noResponse": "Keine Antwort vom Server"
|
||||
},
|
||||
@@ -634,14 +637,7 @@
|
||||
"empty": "leer",
|
||||
"globalConfig": "Globale Konfigurations-Nodes",
|
||||
"triggerAction": "Auslösen",
|
||||
"find": "Suche im Arbeitsbereich",
|
||||
"search": {
|
||||
"configNodes": "Konfigurations-Nodes",
|
||||
"unusedConfigNodes": "Unbenutzte Konfigurations-Nodes",
|
||||
"invalidNodes": "Ungültige Nodes",
|
||||
"uknownNodes": "Unbekannte Nodes",
|
||||
"unusedSubflows": "Unbenutzte Subflows"
|
||||
}
|
||||
"find": "Suche im Arbeitsbereich"
|
||||
},
|
||||
"help": {
|
||||
"name": "Hilfe",
|
||||
@@ -863,7 +859,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "Keine Übereinstimmungen gefunden",
|
||||
"addNode": "Node hinzufügen ..."
|
||||
"addNode": "Node hinzufügen ...",
|
||||
"options": {
|
||||
"configNodes": "Konfigurations-Nodes",
|
||||
"unusedConfigNodes": "Unbenutzte Konfigurations-Nodes",
|
||||
"invalidNodes": "Ungültige Nodes",
|
||||
"uknownNodes": "Unbekannte Nodes",
|
||||
"unusedSubflows": "Unbenutzte Subflows"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "Funktionen",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"label": {
|
||||
"name": "Name",
|
||||
"ok": "Ok",
|
||||
"done":"Done",
|
||||
"done": "Done",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"close": "Close",
|
||||
@@ -53,11 +53,20 @@
|
||||
"confirmDelete": "Confirm delete",
|
||||
"delete": "Are you sure you want to delete '__label__'?",
|
||||
"dropFlowHere": "Drop the flow here",
|
||||
"addFlow": "Add Flow",
|
||||
"listFlows": "List Flows",
|
||||
"addFlow": "Add flow",
|
||||
"addFlowToRight": "Add flow to the right",
|
||||
"hideFlow": "Hide flow",
|
||||
"hideOtherFlows": "Hide other flows",
|
||||
"showAllFlows": "Show all flows",
|
||||
"hideAllFlows": "Hide all flows",
|
||||
"hiddenFlows": "List __count__ hidden flow",
|
||||
"hiddenFlows_plural": "List __count__ hidden flows",
|
||||
"showLastHiddenFlow": "Show last hidden flow",
|
||||
"listFlows": "List flows",
|
||||
"listSubflows": "List subflows",
|
||||
"status": "Status",
|
||||
"enabled": "Enabled",
|
||||
"disabled":"Disabled",
|
||||
"disabled": "Disabled",
|
||||
"info": "Description",
|
||||
"selectNodes": "Click nodes to select"
|
||||
},
|
||||
@@ -66,6 +75,8 @@
|
||||
"view": {
|
||||
"view": "View",
|
||||
"grid": "Grid",
|
||||
"storeZoom": "Restore zoom level on load",
|
||||
"storePosition": "Restore scroll position on load",
|
||||
"showGrid": "Show grid",
|
||||
"snapGrid": "Snap to grid",
|
||||
"gridSize": "Grid size",
|
||||
@@ -83,6 +94,7 @@
|
||||
"palette": {
|
||||
"show": "Show palette"
|
||||
},
|
||||
"edit": "Edit",
|
||||
"settings": "Settings",
|
||||
"userSettings": "User Settings",
|
||||
"nodes": "Nodes",
|
||||
@@ -102,9 +114,10 @@
|
||||
"keyboardShortcuts": "Keyboard shortcuts",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"editPalette":"Manage palette",
|
||||
"editPalette": "Manage palette",
|
||||
"other": "Other",
|
||||
"showTips": "Show tips",
|
||||
"showWelcomeTours": "Show guided tours for new versions",
|
||||
"help": "Node-RED website",
|
||||
"projects": "Projects",
|
||||
"projects-new": "New",
|
||||
@@ -116,14 +129,31 @@
|
||||
"groupSelection": "Group selection",
|
||||
"ungroupSelection": "Ungroup selection",
|
||||
"groupMergeSelection": "Merge selection",
|
||||
"groupRemoveSelection": "Remove from group"
|
||||
"groupRemoveSelection": "Remove from group",
|
||||
"arrange": "Arrange",
|
||||
"alignLeft": "Align to left",
|
||||
"alignCenter": "Align to center",
|
||||
"alignRight": "Align to right",
|
||||
"alignTop": "Align to top",
|
||||
"alignMiddle": "Align to middle",
|
||||
"alignBottom": "Align to bottom",
|
||||
"distributeHorizontally": "Distribute horizontally",
|
||||
"distributeVertically": "Distribute vertically",
|
||||
"moveToBack": "Move to back",
|
||||
"moveToFront": "Move to front",
|
||||
"moveBackwards": "Move backwards",
|
||||
"moveForwards": "Move forwards"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "Toggle navigator",
|
||||
"zoom-out": "Zoom out",
|
||||
"zoom-reset": "Reset zoom",
|
||||
"zoom-in": "Zoom in"
|
||||
"zoom-in": "Zoom in",
|
||||
"search-flows": "Search flows",
|
||||
"search-prev": "Previous",
|
||||
"search-next": "Next",
|
||||
"search-counter": "\"__term__\" __result__ of __count__"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "Logged in as __name__",
|
||||
@@ -146,10 +176,10 @@
|
||||
"nodeActionDisabledSubflow": "node actions disabled within subflow",
|
||||
"missing-types": "<p>Flows stopped due to missing node types.</p>",
|
||||
"missing-modules": "<p>Flows stopped due to missing modules.</p>",
|
||||
"safe-mode":"<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
|
||||
"safe-mode": "<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
|
||||
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
||||
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
|
||||
"credentials_load_failed_reset":"<p>Credentials could not be decrypted</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p><p>The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.</p>",
|
||||
"credentials_load_failed_reset": "<p>Credentials could not be decrypted</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p><p>The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.</p>",
|
||||
"missing_flow_file": "<p>Project flow file not found.</p><p>The project is not configured with a flow file.</p>",
|
||||
"missing_package_file": "<p>Project package file not found.</p><p>The project is missing a package.json file.</p>",
|
||||
"project_empty": "<p>The project is empty.</p><p>Do you want to create a default set of project files?<br/>Otherwise, you will have to manually add files to the project outside of the editor.</p>",
|
||||
@@ -187,7 +217,8 @@
|
||||
"create-default-package": "Create default package file",
|
||||
"no-thanks": "No thanks",
|
||||
"create-default-project": "Create default project files",
|
||||
"show-merge-conflicts": "Show merge conflicts"
|
||||
"show-merge-conflicts": "Show merge conflicts",
|
||||
"unknownNodesButton": "Search for unknown nodes"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
@@ -226,11 +257,11 @@
|
||||
"recoveredNodesInfo": "The nodes on this flow were missing a valid flow id when they were imported. They have been added to this flow so you can either restore or delete them.",
|
||||
"recoveredNodesNotification": "<p>Imported nodes without a valid flow id</p><p>They have been added to a new flow called '__flowName__'.</p>",
|
||||
"export": {
|
||||
"selected":"selected nodes",
|
||||
"current":"current flow",
|
||||
"all":"all flows",
|
||||
"compact":"compact",
|
||||
"formatted":"formatted",
|
||||
"selected": "selected nodes",
|
||||
"current": "current flow",
|
||||
"all": "all flows",
|
||||
"compact": "compact",
|
||||
"formatted": "formatted",
|
||||
"copy": "Copy to clipboard",
|
||||
"export": "Export to library",
|
||||
"exportAs": "Export as",
|
||||
@@ -270,8 +301,10 @@
|
||||
"successfulDeploy": "Successfully deployed",
|
||||
"successfulRestart": "Successfully restarted flows",
|
||||
"deployFailed": "Deploy failed: __message__",
|
||||
"unusedConfigNodes":"You have some unused configuration nodes.",
|
||||
"unusedConfigNodesLink":"Click here to see them",
|
||||
"unusedConfigNodes": "You have some unused configuration nodes.",
|
||||
"unusedConfigNodesButton": "Search unused config nodes",
|
||||
"unknownNodesButton": "Search for unknown nodes",
|
||||
"invalidNodesButton": "Search for invalid nodes",
|
||||
"errors": {
|
||||
"noResponse": "no response from server"
|
||||
},
|
||||
@@ -318,8 +351,8 @@
|
||||
},
|
||||
"nodeCount": "__count__ node",
|
||||
"nodeCount_plural": "__count__ nodes",
|
||||
"local":"Local changes",
|
||||
"remote":"Remote changes",
|
||||
"local": "Local changes",
|
||||
"remote": "Remote changes",
|
||||
"reviewChanges": "Review Changes",
|
||||
"noBinaryFileShowed": "Cannot show binary file contents",
|
||||
"viewCommitDiff": "View Commit Changes",
|
||||
@@ -403,7 +436,7 @@
|
||||
"inputType": "Input type",
|
||||
"selectType": "select types...",
|
||||
"loadCredentials": "Loading node credentials",
|
||||
"inputs" : {
|
||||
"inputs": {
|
||||
"input": "input",
|
||||
"select": "select",
|
||||
"checkbox": "checkbox",
|
||||
@@ -450,8 +483,9 @@
|
||||
"unassigned": "Unassigned",
|
||||
"global": "global",
|
||||
"workspace": "workspace",
|
||||
"selectAll": "Select all nodes",
|
||||
"selectAllConnected": "Select all connected nodes",
|
||||
"selectAll": "Select all",
|
||||
"selectNone": "Select none",
|
||||
"selectAllConnected": "Select connected",
|
||||
"addRemoveNode": "Add/remove node from selection",
|
||||
"editSelected": "Edit selected node",
|
||||
"deleteSelected": "Delete selected nodes or link",
|
||||
@@ -464,10 +498,14 @@
|
||||
"copyNode": "Copy selected nodes",
|
||||
"cutNode": "Cut selected nodes",
|
||||
"pasteNode": "Paste nodes",
|
||||
"undoChange": "Undo the last change performed",
|
||||
"copyGroupStyle": "Copy group style",
|
||||
"pasteGroupStyle": "Paste group style",
|
||||
"undoChange": "Undo",
|
||||
"redoChange": "Redo",
|
||||
"searchBox": "Open search box",
|
||||
"managePalette": "Manage palette",
|
||||
"actionList":"Action list"
|
||||
"actionList": "Action list",
|
||||
"splitWireWithLinks": "Split selection with Link nodes"
|
||||
},
|
||||
"library": {
|
||||
"library": "Library",
|
||||
@@ -519,7 +557,8 @@
|
||||
"nodeEnabled_plural": "Nodes enabled:",
|
||||
"nodeDisabled": "Node disabled:",
|
||||
"nodeDisabled_plural": "Nodes disabled:",
|
||||
"nodeUpgraded": "Node module __module__ upgraded to version __version__"
|
||||
"nodeUpgraded": "Node module __module__ upgraded to version __version__",
|
||||
"unknownNodeRegistered": "Error loading node: <ul><li>__type__<br>__error__</li></ul>"
|
||||
},
|
||||
"editor": {
|
||||
"title": "Manage palette",
|
||||
@@ -578,19 +617,19 @@
|
||||
},
|
||||
"confirm": {
|
||||
"install": {
|
||||
"body":"<p>Installing '__module__'</p><p>Before installing, please read the node's documentation. Some nodes have dependencies that cannot be automatically resolved and can require a restart of Node-RED.</p>",
|
||||
"body": "<p>Installing '__module__'</p><p>Before installing, please read the node's documentation. Some nodes have dependencies that cannot be automatically resolved and can require a restart of Node-RED.</p>",
|
||||
"title": "Install nodes"
|
||||
},
|
||||
"remove": {
|
||||
"body":"<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
|
||||
"body": "<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
|
||||
"title": "Remove nodes"
|
||||
},
|
||||
"update": {
|
||||
"body":"<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
|
||||
"body": "<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
|
||||
"title": "Update nodes"
|
||||
},
|
||||
"cannotUpdate": {
|
||||
"body":"An update for this node is available, but it is not installed in a location that the palette manager can update.<br/><br/>Please refer to the documentation for how to update this node."
|
||||
"body": "An update for this node is available, but it is not installed in a location that the palette manager can update.<br/><br/>Please refer to the documentation for how to update this node."
|
||||
},
|
||||
"button": {
|
||||
"review": "Open node information",
|
||||
@@ -624,26 +663,19 @@
|
||||
"showMore": "show more",
|
||||
"showLess": "show less",
|
||||
"flow": "Flow",
|
||||
"selection":"Selection",
|
||||
"nodes":"__count__ nodes",
|
||||
"selection": "Selection",
|
||||
"nodes": "__count__ nodes",
|
||||
"flowDesc": "Flow Description",
|
||||
"subflowDesc": "Subflow Description",
|
||||
"nodeHelp": "Node Help",
|
||||
"none":"None",
|
||||
"none": "None",
|
||||
"arrayItems": "__count__ items",
|
||||
"showTips":"You can open the tips from the settings panel",
|
||||
"showTips": "You can open the tips from the settings panel",
|
||||
"outline": "Outline",
|
||||
"empty": "empty",
|
||||
"globalConfig": "Global Configuration Nodes",
|
||||
"triggerAction": "Trigger action",
|
||||
"find": "Find in workspace",
|
||||
"search": {
|
||||
"configNodes": "Configuration nodes",
|
||||
"unusedConfigNodes": "Unused configuration nodes",
|
||||
"invalidNodes": "Invalid nodes",
|
||||
"uknownNodes": "Unknown nodes",
|
||||
"unusedSubflows": "Unused subflows"
|
||||
}
|
||||
"find": "Find in workspace"
|
||||
},
|
||||
"help": {
|
||||
"name": "Help",
|
||||
@@ -669,8 +701,8 @@
|
||||
"filtered": "__count__ hidden"
|
||||
},
|
||||
"context": {
|
||||
"name":"Context Data",
|
||||
"label":"context",
|
||||
"name": "Context Data",
|
||||
"label": "context",
|
||||
"none": "none selected",
|
||||
"refresh": "refresh to load",
|
||||
"empty": "empty",
|
||||
@@ -708,9 +740,9 @@
|
||||
"files": "Files",
|
||||
"flow": "Flow",
|
||||
"credentials": "Credentials",
|
||||
"package":"Package",
|
||||
"packageCreate":"File will be created when changes are saved",
|
||||
"fileNotExist":"File does not exist",
|
||||
"package": "Package",
|
||||
"packageCreate": "File will be created when changes are saved",
|
||||
"fileNotExist": "File does not exist",
|
||||
"selectFile": "Select File",
|
||||
"invalidEncryptionKey": "Invalid encryption key",
|
||||
"encryptionEnabled": "Encryption enabled",
|
||||
@@ -864,8 +896,20 @@
|
||||
"addTitle": "add an item"
|
||||
},
|
||||
"search": {
|
||||
"history": "Search history",
|
||||
"clear": "clear all",
|
||||
"empty": "No matches found",
|
||||
"addNode": "add a node..."
|
||||
"addNode": "add a node...",
|
||||
"options": {
|
||||
"configNodes": "Configuration nodes",
|
||||
"unusedConfigNodes": "Unused configuration nodes",
|
||||
"invalidNodes": "Invalid nodes",
|
||||
"uknownNodes": "Unknown nodes",
|
||||
"unusedSubflows": "Unused subflows",
|
||||
"hiddenFlows": "Hidden flows",
|
||||
"modifiedNodes": "Modified nodes and flows",
|
||||
"thisFlow": "Current flow"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "Functions",
|
||||
@@ -900,6 +944,8 @@
|
||||
"format": "format JSON",
|
||||
"rawMode": "Edit JSON",
|
||||
"uiMode": "Visual editor",
|
||||
"rawMode-readonly": "JSON",
|
||||
"uiMode-readonly": "Visual",
|
||||
"insertAbove": "Insert above",
|
||||
"insertBelow": "Insert below",
|
||||
"addItem": "Add item",
|
||||
@@ -932,7 +978,7 @@
|
||||
"title": "Buffer editor",
|
||||
"modeString": "Handle as UTF-8 String",
|
||||
"modeArray": "Handle as JSON array",
|
||||
"modeDesc":"<h3>Buffer editor</h3><p>The Buffer type is stored as a JSON array of byte values. The editor will attempt to parse the entered value as a JSON array. If it is not valid JSON, it will be treated as a UTF-8 String and converted to an array of the individual character code points.</p><p>For example, a value of <code>Hello World</code> will be converted to the JSON array:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
||||
"modeDesc": "<h3>Buffer editor</h3><p>The Buffer type is stored as a JSON array of byte values. The editor will attempt to parse the entered value as a JSON array. If it is not valid JSON, it will be treated as a UTF-8 String and converted to an array of the individual character code points.</p><p>For example, a value of <code>Hello World</code> will be converted to the JSON array:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
|
||||
},
|
||||
"projects": {
|
||||
"config-git": "Configure Git client",
|
||||
@@ -1061,7 +1107,8 @@
|
||||
"not-git": "Not a git repository",
|
||||
"no-resource": "Repository not found",
|
||||
"cant-get-ssh-key-path": "Error! Can't get selected SSH key path.",
|
||||
"unexpected_error": "unexpected_error"
|
||||
"unexpected_error": "unexpected_error",
|
||||
"clearContext": "Clear context when switching projects"
|
||||
},
|
||||
"delete": {
|
||||
"confirm": "Are you sure you want to delete this project?"
|
||||
@@ -1093,7 +1140,7 @@
|
||||
"no-empty": "Cannot create default file set on a non-empty project",
|
||||
"git-error": "git error"
|
||||
},
|
||||
"errors" : {
|
||||
"errors": {
|
||||
"no-username-email": "Your Git client is not configured with a username/email.",
|
||||
"unexpected": "An unexpected error occurred",
|
||||
"code": "code"
|
||||
@@ -1108,7 +1155,15 @@
|
||||
"preview": "UI Preview",
|
||||
"defaultValue": "Default value"
|
||||
},
|
||||
"languages" : {
|
||||
"tourGuide": {
|
||||
"takeATour": "Take a tour",
|
||||
"start": "Start",
|
||||
"next": "Next"
|
||||
},
|
||||
"diagnostics": {
|
||||
"title": "System Info"
|
||||
},
|
||||
"languages": {
|
||||
"de": "German",
|
||||
"en-US": "English",
|
||||
"ja": "Japanese",
|
||||
@@ -1116,5 +1171,21 @@
|
||||
"ru": "Russian",
|
||||
"zh-CN": "Chinese(Simplified)",
|
||||
"zh-TW": "Chinese(Traditional)"
|
||||
},
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "Invalid JSON data: __error__",
|
||||
"invalid-json-prop": "__prop__: invalid JSON data: __error__",
|
||||
"invalid-prop": "Invalid property expression",
|
||||
"invalid-prop-prop": "__prop__: invalid property expression",
|
||||
"invalid-num": "Invalid number",
|
||||
"invalid-num-prop": "__prop__: invalid number",
|
||||
"invalid-regexp": "Invalid input pattern",
|
||||
"invalid-regex-prop": "__prop__: invalid input pattern",
|
||||
"missing-required-prop": "__prop__: property value missing",
|
||||
"invalid-config": "__prop__: invalid configuration node",
|
||||
"missing-config": "__prop__: missing configuration node",
|
||||
"validation-error": "__prop__: validation error: __node__, __id__: __error__"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"info": {
|
||||
"tip0" : "You can remove the selected nodes or links with {{core:delete-selection}}",
|
||||
"tip1" : "Search for nodes using {{core:search}}",
|
||||
"tip2" : "{{core:toggle-sidebar}} will toggle the view of this sidebar",
|
||||
"tip3" : "You can manage your palette of nodes with {{core:manage-palette}}",
|
||||
"tip4" : "Your flow configuration nodes are listed in the sidebar panel. It can be accessed from the menu or with {{core:show-config-tab}}",
|
||||
"tip5" : "Enable or disable these tips from the option in the settings",
|
||||
"tip6" : "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further",
|
||||
"tip7" : "Dragging a node onto a wire will splice it into the link",
|
||||
"tip8" : "Export the selected nodes, or the current tab with {{core:show-export-dialog}}",
|
||||
"tip9" : "Import a flow by dragging its JSON into the editor, or with {{core:show-import-dialog}}",
|
||||
"tip10" : "[shift] [click] and drag on a node port to move all of the attached wires or just the selected one",
|
||||
"tip11" : "Show the Info tab with {{core:show-info-tab}} or the Debug tab with {{core:show-debug-tab}}",
|
||||
"tip12" : "[ctrl] [click] in the workspace to open the quick-add dialog",
|
||||
"tip13" : "Hold down [ctrl] when you [click] on a node port to enable quick-wiring",
|
||||
"tip14" : "Hold down [shift] when you [click] on a node to also select all of its connected nodes",
|
||||
"tip15" : "Hold down [ctrl] when you [click] on a node to add or remove it from the current selection",
|
||||
"tip16" : "Switch flow tabs with {{core:show-previous-tab}} and {{core:show-next-tab}}",
|
||||
"tip17" : "You can confirm your changes in the node edit tray with {{core:confirm-edit-tray}} or cancel them with {{core:cancel-edit-tray}}",
|
||||
"tip18" : "Pressing {{core:edit-selected-node}} will edit the first node in the current selection"
|
||||
"tip0": "You can remove the selected nodes or links with {{core:delete-selection}}",
|
||||
"tip1": "Search for nodes using {{core:search}}",
|
||||
"tip2": "{{core:toggle-sidebar}} will toggle the view of this sidebar",
|
||||
"tip3": "You can manage your palette of nodes with {{core:manage-palette}}",
|
||||
"tip4": "Your flow configuration nodes are listed in the sidebar panel. It can be accessed from the menu or with {{core:show-config-tab}}",
|
||||
"tip5": "Enable or disable these tips from the option in the settings",
|
||||
"tip6": "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further",
|
||||
"tip7": "Dragging a node onto a wire will splice it into the link",
|
||||
"tip8": "Export the selected nodes, or the current tab with {{core:show-export-dialog}}",
|
||||
"tip9": "Import a flow by dragging its JSON into the editor, or with {{core:show-import-dialog}}",
|
||||
"tip10": "[shift] [click] and drag on a node port to move all of the attached wires or just the selected one",
|
||||
"tip11": "Show the Info tab with {{core:show-info-tab}} or the Debug tab with {{core:show-debug-tab}}",
|
||||
"tip12": "[ctrl] [click] in the workspace to open the quick-add dialog",
|
||||
"tip13": "Hold down [ctrl] when you [click] on a node port to enable quick-wiring",
|
||||
"tip14": "Hold down [shift] when you [click] on a node to also select all of its connected nodes",
|
||||
"tip15": "Hold down [ctrl] when you [click] on a node to add or remove it from the current selection",
|
||||
"tip16": "Switch flow tabs with {{core:show-previous-tab}} and {{core:show-next-tab}}",
|
||||
"tip17": "You can confirm your changes in the node edit tray with {{core:confirm-edit-tray}} or cancel them with {{core:cancel-edit-tray}}",
|
||||
"tip18": "Pressing {{core:edit-selected-node}} will edit the first node in the current selection"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,52 +52,52 @@
|
||||
"desc": "Finds occurrences of `pattern` within `str` and replaces them with `replacement`.\n\nThe optional `limit` parameter is the maximum number of replacements."
|
||||
},
|
||||
"$now": {
|
||||
"args":"$[picture [, timezone]]",
|
||||
"desc":"Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional picture and timezone parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
||||
"args": "$[picture [, timezone]]",
|
||||
"desc": "Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional picture and timezone parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
||||
},
|
||||
"$base64encode": {
|
||||
"args":"string",
|
||||
"desc":"Converts an ASCII string to a base 64 representation. Each character in the string is treated as a byte of binary data. This requires that all characters in the string are in the 0x00 to 0xFF range, which includes all characters in URI encoded strings. Unicode characters outside of that range are not supported."
|
||||
"args": "string",
|
||||
"desc": "Converts an ASCII string to a base 64 representation. Each character in the string is treated as a byte of binary data. This requires that all characters in the string are in the 0x00 to 0xFF range, which includes all characters in URI encoded strings. Unicode characters outside of that range are not supported."
|
||||
},
|
||||
"$base64decode": {
|
||||
"args":"string",
|
||||
"desc":"Converts base 64 encoded bytes to a string, using a UTF-8 Unicode codepage."
|
||||
"args": "string",
|
||||
"desc": "Converts base 64 encoded bytes to a string, using a UTF-8 Unicode codepage."
|
||||
},
|
||||
"$number": {
|
||||
"args": "arg",
|
||||
"desc": "Casts the `arg` parameter to a number using the following casting rules:\n\n - Numbers are unchanged\n - Strings that contain a sequence of characters that represent a legal JSON number are converted to that number\n - All other values cause an error to be thrown."
|
||||
},
|
||||
"$abs": {
|
||||
"args":"number",
|
||||
"desc":"Returns the absolute value of the `number` parameter."
|
||||
"args": "number",
|
||||
"desc": "Returns the absolute value of the `number` parameter."
|
||||
},
|
||||
"$floor": {
|
||||
"args":"number",
|
||||
"desc":"Returns the value of `number` rounded down to the nearest integer that is smaller or equal to `number`."
|
||||
"args": "number",
|
||||
"desc": "Returns the value of `number` rounded down to the nearest integer that is smaller or equal to `number`."
|
||||
},
|
||||
"$ceil": {
|
||||
"args":"number",
|
||||
"desc":"Returns the value of `number` rounded up to the nearest integer that is greater than or equal to `number`."
|
||||
"args": "number",
|
||||
"desc": "Returns the value of `number` rounded up to the nearest integer that is greater than or equal to `number`."
|
||||
},
|
||||
"$round": {
|
||||
"args":"number [, precision]",
|
||||
"desc":"Returns the value of the `number` parameter rounded to the number of decimal places specified by the optional `precision` parameter."
|
||||
"args": "number [, precision]",
|
||||
"desc": "Returns the value of the `number` parameter rounded to the number of decimal places specified by the optional `precision` parameter."
|
||||
},
|
||||
"$power": {
|
||||
"args":"base, exponent",
|
||||
"desc":"Returns the value of `base` raised to the power of `exponent`."
|
||||
"args": "base, exponent",
|
||||
"desc": "Returns the value of `base` raised to the power of `exponent`."
|
||||
},
|
||||
"$sqrt": {
|
||||
"args":"number",
|
||||
"desc":"Returns the square root of the value of the `number` parameter."
|
||||
"args": "number",
|
||||
"desc": "Returns the square root of the value of the `number` parameter."
|
||||
},
|
||||
"$random": {
|
||||
"args":"",
|
||||
"desc":"Returns a pseudo random number greater than or equal to zero and less than one."
|
||||
"args": "",
|
||||
"desc": "Returns a pseudo random number greater than or equal to zero and less than one."
|
||||
},
|
||||
"$millis": {
|
||||
"args":"",
|
||||
"desc":"Returns the number of milliseconds since the Unix Epoch (1 January, 1970 UTC) as a number. All invocations of `$millis()` within an evaluation of an expression will all return the same value."
|
||||
"args": "",
|
||||
"desc": "Returns the number of milliseconds since the Unix Epoch (1 January, 1970 UTC) as a number. All invocations of `$millis()` within an evaluation of an expression will all return the same value."
|
||||
},
|
||||
"$sum": {
|
||||
"args": "array",
|
||||
@@ -136,20 +136,20 @@
|
||||
"desc": "Appends two arrays"
|
||||
},
|
||||
"$sort": {
|
||||
"args":"array [, function]",
|
||||
"desc":"Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values left and right. If the value of left should be placed after the value of right in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
||||
"args": "array [, function]",
|
||||
"desc": "Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values left and right. If the value of left should be placed after the value of right in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
||||
},
|
||||
"$reverse": {
|
||||
"args":"array",
|
||||
"desc":"Returns an array containing all the values from the `array` parameter, but in reverse order."
|
||||
"args": "array",
|
||||
"desc": "Returns an array containing all the values from the `array` parameter, but in reverse order."
|
||||
},
|
||||
"$shuffle": {
|
||||
"args":"array",
|
||||
"desc":"Returns an array containing all the values from the `array` parameter, but shuffled into random order."
|
||||
"args": "array",
|
||||
"desc": "Returns an array containing all the values from the `array` parameter, but shuffled into random order."
|
||||
},
|
||||
"$zip": {
|
||||
"args":"array, ...",
|
||||
"desc":"Returns a convolved (zipped) array containing grouped arrays of values from the `array1` … `arrayN` arguments from index 0, 1, 2...."
|
||||
"args": "array, ...",
|
||||
"desc": "Returns a convolved (zipped) array containing grouped arrays of values from the `array1` … `arrayN` arguments from index 0, 1, 2...."
|
||||
},
|
||||
"$keys": {
|
||||
"args": "object",
|
||||
@@ -168,24 +168,24 @@
|
||||
"desc": "Merges an array of `objects` into a single `object` containing all the key/value pairs from each of the objects in the input array. If any of the input objects contain the same key, then the returned `object` will contain the value of the last one in the array. It is an error if the input array contains an item that is not an object."
|
||||
},
|
||||
"$sift": {
|
||||
"args":"object, function",
|
||||
"desc":"Returns an object that contains only the key/value pairs from the `object` parameter that satisfy the predicate `function` passed in as the second parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, key [, object]])`"
|
||||
"args": "object, function",
|
||||
"desc": "Returns an object that contains only the key/value pairs from the `object` parameter that satisfy the predicate `function` passed in as the second parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, key [, object]])`"
|
||||
},
|
||||
"$each": {
|
||||
"args":"object, function",
|
||||
"desc":"Returns an array containing the values return by the `function` when applied to each key/value pair in the `object`."
|
||||
"args": "object, function",
|
||||
"desc": "Returns an array containing the values return by the `function` when applied to each key/value pair in the `object`."
|
||||
},
|
||||
"$map": {
|
||||
"args":"array, function",
|
||||
"desc":"Returns an array containing the results of applying the `function` parameter to each value in the `array` parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
||||
"args": "array, function",
|
||||
"desc": "Returns an array containing the results of applying the `function` parameter to each value in the `array` parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
||||
},
|
||||
"$filter": {
|
||||
"args":"array, function",
|
||||
"desc":"Returns an array containing only the values in the `array` parameter that satisfy the `function` predicate.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
||||
"args": "array, function",
|
||||
"desc": "Returns an array containing only the values in the `array` parameter that satisfy the `function` predicate.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, index [, array]])`"
|
||||
},
|
||||
"$reduce": {
|
||||
"args":"array, function [, init]",
|
||||
"desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`. The signature of `function` must be of the form: `myfunc($accumulator, $value[, $index[, $array]])`\n\nThe optional `init` parameter is used as the initial value in the aggregation."
|
||||
"args": "array, function [, init]",
|
||||
"desc": "Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`. The signature of `function` must be of the form: `myfunc($accumulator, $value[, $index[, $array]])`\n\nThe optional `init` parameter is used as the initial value in the aggregation."
|
||||
},
|
||||
"$flowContext": {
|
||||
"args": "string[, string]",
|
||||
|
||||
@@ -54,7 +54,16 @@
|
||||
"delete": "本当に '__label__' を削除しますか?",
|
||||
"dropFlowHere": "ここにフローをドロップしてください",
|
||||
"addFlow": "フローの追加",
|
||||
"addFlowToRight": "右側にフローを追加",
|
||||
"hideFlow": "フローを非表示",
|
||||
"hideOtherFlows": "他のフローを非表示",
|
||||
"showAllFlows": "全てのフローを表示",
|
||||
"hideAllFlows": "全てのフローを非表示",
|
||||
"hiddenFlows": "__count__ 個の非表示のフロー一覧",
|
||||
"hiddenFlows_plural": "__count__ 個の非表示のフロー一覧",
|
||||
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
|
||||
"listFlows": "フロー一覧",
|
||||
"listSubflows": "サブフロー一覧",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
@@ -66,6 +75,8 @@
|
||||
"view": {
|
||||
"view": "表示",
|
||||
"grid": "グリッド",
|
||||
"storeZoom": "読み込み時に拡大/縮小のレベルを復元",
|
||||
"storePosition": "読み込み時にスクロール位置を復元",
|
||||
"showGrid": "グリッドを表示",
|
||||
"snapGrid": "ノードの配置を補助",
|
||||
"gridSize": "グリッドの大きさ",
|
||||
@@ -83,6 +94,7 @@
|
||||
"palette": {
|
||||
"show": "パレットを表示"
|
||||
},
|
||||
"edit": "編集",
|
||||
"settings": "設定",
|
||||
"userSettings": "ユーザ設定",
|
||||
"nodes": "ノード",
|
||||
@@ -105,6 +117,7 @@
|
||||
"editPalette": "パレットの管理",
|
||||
"other": "その他",
|
||||
"showTips": "ヒントを表示",
|
||||
"showWelcomeTours": "新バージョンのガイドツアーを表示",
|
||||
"help": "Node-REDウェブサイト",
|
||||
"projects": "プロジェクト",
|
||||
"projects-new": "新規",
|
||||
@@ -116,14 +129,31 @@
|
||||
"groupSelection": "選択部分をグループ化",
|
||||
"ungroupSelection": "選択部分をグループ解除",
|
||||
"groupMergeSelection": "選択部分をマージ",
|
||||
"groupRemoveSelection": "グループから削除"
|
||||
"groupRemoveSelection": "グループから削除",
|
||||
"arrange": "配置",
|
||||
"alignLeft": "左揃え",
|
||||
"alignCenter": "左右中央揃え",
|
||||
"alignRight": "右揃え",
|
||||
"alignTop": "上揃え",
|
||||
"alignMiddle": "上下中央揃え",
|
||||
"alignBottom": "下揃え",
|
||||
"distributeHorizontally": "左右に整列",
|
||||
"distributeVertically": "上下に整列",
|
||||
"moveToBack": "最背面へ移動",
|
||||
"moveToFront": "最前面へ移動",
|
||||
"moveBackwards": "背面へ移動",
|
||||
"moveForwards": "前面へ移動"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "ナビゲータの表示/非表示を切替",
|
||||
"zoom-out": "縮小",
|
||||
"zoom-reset": "拡大/縮小を初期化",
|
||||
"zoom-in": "拡大"
|
||||
"zoom-in": "拡大",
|
||||
"search-flows": "フローを検索",
|
||||
"search-prev": "前へ",
|
||||
"search-next": "次へ",
|
||||
"search-counter": "\"__term__\" __count__ 件中の __result__ 件目"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "__name__ としてログインしました",
|
||||
@@ -187,7 +217,8 @@
|
||||
"create-default-package": "デフォルトパッケージファイルの作成",
|
||||
"no-thanks": "不要",
|
||||
"create-default-project": "デフォルトプロジェクトファイルの作成",
|
||||
"show-merge-conflicts": "マージ競合を表示"
|
||||
"show-merge-conflicts": "マージ競合を表示",
|
||||
"unknownNodesButton": "不明なノードを検索する"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
@@ -271,7 +302,9 @@
|
||||
"successfulRestart": "フローの再起動が成功しました",
|
||||
"deployFailed": "デプロイが失敗しました: __message__",
|
||||
"unusedConfigNodes": "使われていない設定ノードがあります。",
|
||||
"unusedConfigNodesLink": "設定を参照する",
|
||||
"unusedConfigNodesButton": "未使用の構成ノードを検索",
|
||||
"unknownNodesButton": "不明なノードを検索する",
|
||||
"invalidNodesButton": "無効なノードを検索する",
|
||||
"errors": {
|
||||
"noResponse": "サーバの応答がありません"
|
||||
},
|
||||
@@ -451,7 +484,8 @@
|
||||
"global": "グローバル",
|
||||
"workspace": "ワークスペース",
|
||||
"selectAll": "全てのノードを選択",
|
||||
"selectAllConnected": "接続された全てのノードを選択",
|
||||
"selectNone": "選択を外す",
|
||||
"selectAllConnected": "接続されたノードを選択",
|
||||
"addRemoveNode": "ノードの選択、選択解除",
|
||||
"editSelected": "選択したノードを編集",
|
||||
"deleteSelected": "選択したノードや接続を削除",
|
||||
@@ -461,13 +495,17 @@
|
||||
"moveNode": "選択したノードを移動(移動量大)",
|
||||
"toggleSidebar": "サイドバーの表示/非表示",
|
||||
"togglePalette": "パレットの表示/非表示",
|
||||
"copyNode": "選択したノードをコピー",
|
||||
"cutNode": "選択したノードを切り取り",
|
||||
"copyNode": "ノードをコピー",
|
||||
"cutNode": "ノードを切り取り",
|
||||
"pasteNode": "ノードを貼り付け",
|
||||
"copyGroupStyle": "グループ様式をコピー",
|
||||
"pasteGroupStyle": "グループ様式を貼り付け",
|
||||
"undoChange": "変更操作を戻す",
|
||||
"redoChange": "変更操作をやり直し",
|
||||
"searchBox": "ノードを検索",
|
||||
"managePalette": "パレットの管理",
|
||||
"actionList": "動作一覧"
|
||||
"actionList": "動作一覧",
|
||||
"splitWireWithLinks": "選択したワイヤーをlinkノードで分離"
|
||||
},
|
||||
"library": {
|
||||
"library": "ライブラリ",
|
||||
@@ -519,7 +557,8 @@
|
||||
"nodeEnabled_plural": "ノードを有効化しました:",
|
||||
"nodeDisabled": "ノードを無効化しました:",
|
||||
"nodeDisabled_plural": "ノードを無効化しました:",
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました",
|
||||
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
|
||||
},
|
||||
"editor": {
|
||||
"title": "パレットの管理",
|
||||
@@ -636,14 +675,7 @@
|
||||
"empty": "空",
|
||||
"globalConfig": "グローバル設定ノード",
|
||||
"triggerAction": "アクションを実行",
|
||||
"find": "ワークスペース内を検索",
|
||||
"search": {
|
||||
"configNodes": "設定ノード",
|
||||
"unusedConfigNodes": "未使用の設定ノード",
|
||||
"invalidNodes": "不正なノード",
|
||||
"uknownNodes": "未知のノード",
|
||||
"unusedSubflows": "未使用のサブフロー"
|
||||
}
|
||||
"find": "ワークスペース内を検索"
|
||||
},
|
||||
"help": {
|
||||
"name": "ヘルプ",
|
||||
@@ -864,8 +896,20 @@
|
||||
"addTitle": "要素を追加"
|
||||
},
|
||||
"search": {
|
||||
"history": "検索履歴",
|
||||
"clear": "全て削除",
|
||||
"empty": "一致したものが見つかりませんでした",
|
||||
"addNode": "ノードを追加..."
|
||||
"addNode": "ノードを追加...",
|
||||
"options": {
|
||||
"configNodes": "設定ノード",
|
||||
"unusedConfigNodes": "未使用の設定ノード",
|
||||
"invalidNodes": "不正なノード",
|
||||
"uknownNodes": "未知のノード",
|
||||
"unusedSubflows": "未使用のサブフロー",
|
||||
"hiddenFlows": "非表示のフロー",
|
||||
"modifiedNodes": "修正したノードやフロー",
|
||||
"thisFlow": "現在のフロー"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "関数",
|
||||
@@ -900,6 +944,8 @@
|
||||
"format": "JSONフォーマット",
|
||||
"rawMode": "JSONを編集",
|
||||
"uiMode": "ビジュアルエディタ",
|
||||
"rawMode-readonly": "JSON",
|
||||
"uiMode-readonly": "ビジュアル",
|
||||
"insertAbove": "上に挿入",
|
||||
"insertBelow": "下に挿入",
|
||||
"addItem": "要素を追加",
|
||||
@@ -1061,7 +1107,8 @@
|
||||
"not-git": "Gitリポジトリではありません",
|
||||
"no-resource": "リポジトリが見つかりません",
|
||||
"cant-get-ssh-key-path": "エラー! 選択したSSHキーのパスを取得できません。",
|
||||
"unexpected_error": "予期しないエラー"
|
||||
"unexpected_error": "予期しないエラー",
|
||||
"clearContext": "プロジェクトを切り替る際にコンテキストを初期化"
|
||||
},
|
||||
"delete": {
|
||||
"confirm": "プロジェクトを削除しても良いですか?"
|
||||
@@ -1108,6 +1155,14 @@
|
||||
"preview": "UIプレビュー",
|
||||
"defaultValue": "デフォルト値"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "ツアーを開始",
|
||||
"start": "開始",
|
||||
"next": "次へ"
|
||||
},
|
||||
"diagnostics": {
|
||||
"title": "システム情報"
|
||||
},
|
||||
"languages": {
|
||||
"de": "ドイツ語",
|
||||
"en-US": "英語",
|
||||
@@ -1116,5 +1171,159 @@
|
||||
"ru": "ロシア語",
|
||||
"zh-CN": "中国語(簡体)",
|
||||
"zh-TW": "中国語(繁体)"
|
||||
},
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "JSONデータが不正: __error__",
|
||||
"invalid-json-prop": "__prop__: JSONデータが不正: __error__",
|
||||
"invalid-prop": "プロパティ式が不正",
|
||||
"invalid-prop-prop": "__prop__: プロパティ式が不正",
|
||||
"invalid-num": "数値が不正",
|
||||
"invalid-num-prop": "__prop__: 数値が不正",
|
||||
"invalid-regexp": "入力パターンが不正",
|
||||
"invalid-regex-prop": "__prop__: 入力パターンが不正",
|
||||
"missing-required-prop": "__prop__: プロパティが未設定",
|
||||
"invalid-config": "__prop__: 設定ノードが不正",
|
||||
"missing-config": "__prop__: 設定ノードが存在しません",
|
||||
"validation-error": "__prop__: チェックエラー: __node__, __id__: __error__"
|
||||
}
|
||||
},
|
||||
"action-list": {
|
||||
"toggle-show-tips": "ヒント表示切替",
|
||||
"show-about": "Node-REDの説明を表示",
|
||||
"show-welcome-tour": "ウェルカムツアー表示",
|
||||
"show-next-tab": "次のタブを表示",
|
||||
"show-previous-tab": "前のタブを表示",
|
||||
"add-flow": "フローを追加",
|
||||
"add-flow-to-right": "フローを右に追加",
|
||||
"edit-flow": "フローを編集",
|
||||
"remove-flow": "フローを削除",
|
||||
"enable-flow": "フローを有効化",
|
||||
"disable-flow": "フローを無効化",
|
||||
"hide-flow": "フローを隠す",
|
||||
"hide-other-flows": "他のフローを非表示",
|
||||
"hide-all-flows": "全てのフローを非表示",
|
||||
"show-all-flows": "全てのフローを表示",
|
||||
"show-last-hidden-flow": "最後に非表示にしたフローを表示",
|
||||
"list-modified-nodes": "修正したフローを表示",
|
||||
"list-hidden-flows": "非表示フローを表示",
|
||||
"list-flows": "フロー一覧",
|
||||
"list-subflows": "サブフロー一覧",
|
||||
"go-to-previous-location": "前の位置に移動",
|
||||
"go-to-next-location": "次の位置に移動",
|
||||
"copy-selection-to-internal-clipboard": "選択をクリップボードにコピー",
|
||||
"cut-selection-to-internal-clipboard": "選択をクリップボードに切り取り",
|
||||
"paste-from-internal-clipboard": "クリップボードから貼り付け",
|
||||
"detach-selected-nodes": "選択ノードを接続から外す",
|
||||
"delete-selection": "選択を削除",
|
||||
"delete-selection-and-reconnect": "選択を削除し再接続",
|
||||
"edit-selected-node": "選択したノードを編集",
|
||||
"go-to-selection": "選択に移動",
|
||||
"undo": "変更操作を戻す",
|
||||
"redo": "変更操作をやり直し",
|
||||
"select-all-nodes": "全てのノードを選択",
|
||||
"select-none": "ノードを選択",
|
||||
"enable-selected-nodes": "選択ノードを有効化",
|
||||
"disable-selected-nodes": "選択ノードを無効化",
|
||||
"toggle-show-grid": "グリッド表示切替",
|
||||
"toggle-snap-grid": "ノードの配置補助切替",
|
||||
"toggle-status": "ステータス表示切替",
|
||||
"show-selected-node-labels": "選択したノードのラベルを表示",
|
||||
"hide-selected-node-labels": "選択したノードのラベルを非表示",
|
||||
"scroll-view-up": "上スクロール",
|
||||
"scroll-view-right": "右スクロール",
|
||||
"scroll-view-down": "下スクロール",
|
||||
"scroll-view-left": "左スクロール",
|
||||
"step-view-up": "一単位上スクロール",
|
||||
"step-view-right": "一単位右スクロール",
|
||||
"step-view-down": "一単位下スクロール",
|
||||
"step-view-left": "一単位左スクロール",
|
||||
"move-selection-up": "選択を上移動",
|
||||
"move-selection-right": "選択を右移動",
|
||||
"move-selection-down": "選択を下移動",
|
||||
"move-selection-left": "選択を左移動",
|
||||
"move-selection-forwards": "選択を前面に移動",
|
||||
"move-selection-backwards": "選択を背面に移動",
|
||||
"move-selection-to-front": "選択を最前面に移動",
|
||||
"move-selection-to-back": "選択を最背面に移動",
|
||||
"step-selection-up": "選択を一単位上移動",
|
||||
"step-selection-right": "選択を一単位右移動",
|
||||
"step-selection-down": "選択を一単位下移動",
|
||||
"step-selection-left": "選択を一単位左移動",
|
||||
"select-connected-nodes": "接続されたノードを選択",
|
||||
"select-downstream-nodes": "後方に接続されたノードを選択",
|
||||
"select-upstream-nodes": "前方に接続されたノードを選択",
|
||||
"go-to-next-node": "次のノードに移動",
|
||||
"go-to-previous-node": "前のノードに移動",
|
||||
"go-to-next-sibling": "次の兄弟ノードに移動",
|
||||
"go-to-previous-sibling": "前の兄弟ノードに移動",
|
||||
"go-to-nearest-node-on-left": "最も近い左側ノードに移動",
|
||||
"go-to-nearest-node-on-right": "最も近い右側ノードに移動",
|
||||
"go-to-nearest-node-above": "最も近い上側ノードに移動",
|
||||
"go-to-nearest-node-below": "最も近い下側ノードに移動",
|
||||
"align-selection-to-grid": "選択を整列",
|
||||
"align-selection-to-left": "選択を左揃え",
|
||||
"align-selection-to-right": "選択を右揃え",
|
||||
"align-selection-to-top": "選択を上揃え",
|
||||
"align-selection-to-bottom": "選択を下揃え",
|
||||
"align-selection-to-middle": "選択を上下中央揃え",
|
||||
"align-selection-to-center": "選択を左右中央揃え",
|
||||
"distribute-selection-horizontally": "選択を左右に整列",
|
||||
"distribute-selection-vertically": "選択を上下に整列",
|
||||
"wire-series-of-nodes": "ノードを一続きに接続",
|
||||
"wire-node-to-multiple": "ノードを複数に接続",
|
||||
"split-wire-with-link-nodes": "ワイヤーをlinkノードで分割",
|
||||
"generate-node-names": "ノード名を生成",
|
||||
"show-user-settings": "ユーザ設定を表示",
|
||||
"show-help": "ヘルプを表示",
|
||||
"toggle-palette": "パレットの表示切替",
|
||||
"show-event-log": "イベントログを表示",
|
||||
"manage-palette": "パレットの管理",
|
||||
"toggle-sidebar": "サイドバーの表示切替",
|
||||
"show-info-tab": "ノード情報タブの表示",
|
||||
"show-help-tab": "ノードヘルプタブの表示",
|
||||
"show-config-tab": "設定ノードタブの表示",
|
||||
"select-all-config-nodes": "全ての設定ノードを選択",
|
||||
"delete-config-selection": "選択した設定ノードを削除",
|
||||
"show-context-tab": "コンテキストデータタブを表示",
|
||||
"create-subflow": "サブフローを作成",
|
||||
"convert-to-subflow": "選択をサブフローに変換",
|
||||
"group-selection": "選択をグループ化",
|
||||
"ungroup-selection": "選択をグループ解除",
|
||||
"merge-selection-to-group": "選択をグループにマージ",
|
||||
"remove-selection-from-group": "選択をグループから削除",
|
||||
"copy-group-style": "グループのスタイルをコピー",
|
||||
"paste-group-style": "グループのスタイルを貼り付け",
|
||||
"show-export-dialog": "書き出しダイアログを表示",
|
||||
"show-import-dialog": "読み込みダイアログを表示",
|
||||
"show-library-export-dialog": "ライブラリ書き出しダイアログを表示",
|
||||
"show-library-import-dialog": "ライブラリ読み込みダイアログを表示",
|
||||
"show-examples-import-dialog": "サンプル読み込みダイアログを表示",
|
||||
"search": "検索",
|
||||
"search-previous": "前を検索",
|
||||
"search-next": "次を検索",
|
||||
"show-action-list": "アクション一覧を表示",
|
||||
"confirm-edit-tray": "編集を完了",
|
||||
"cancel-edit-tray": "編集をキャンセル",
|
||||
"show-remote-diff": "リモートとの変更差分を表示",
|
||||
"deploy-flows": "フローをデプロイ",
|
||||
"restart-flows": "フローを再起動",
|
||||
"set-deploy-type-to-full": "デプロイを「全て」に設定",
|
||||
"set-deploy-type-to-modified-flows": "デプロイを「変更したフロー」に設定",
|
||||
"set-deploy-type-to-modified-nodes": "デプロイを「変更したノード」に設定",
|
||||
"show-debug-tab": "デバッグタブを表示",
|
||||
"clear-debug-messages": "デバッグメッセージを削除",
|
||||
"clear-filtered-debug-messages": "フィルタしたデバッグメッセージを削除",
|
||||
"activate-selected-debug-nodes": "選択したデバッグノードを有効化",
|
||||
"activate-all-debug-nodes": "全てのデバッグノードを有効化",
|
||||
"activate-all-flow-debug-nodes": "フロー内の全デバッグノードを有効化",
|
||||
"deactivate-selected-debug-nodes": "選択したデバッグノードを無効化",
|
||||
"deactivate-all-debug-nodes": "全てのデバッグノードを無効化",
|
||||
"deactivate-all-flow-debug-nodes": "フロー内の全デバッグノードを無効化",
|
||||
"zoom-in": "ズームイン",
|
||||
"zoom-out": "ズームアウト",
|
||||
"zoom-reset": "ズームリセット",
|
||||
"toggle-navigator": "ナビゲータ表示切替",
|
||||
"show-system-info": "システムインフォメーション"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"tip14": "[shift] を押しながらノードを [click] すると、接続された全てのノードを選択できます。",
|
||||
"tip15": "[ctrl] を押しながらノードを [click] すると、選択/非選択を切り替えできます。",
|
||||
"tip16": "{{core:show-previous-tab}} や {{core:show-next-tab}} で、タブの切り替えができます。",
|
||||
"tip17": "ノードのプロバティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
|
||||
"tip17": "ノードのプロパティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
|
||||
"tip18": "ノードを選択し、 {{core:edit-selected-node}} を押すとプロパティ設定画面が表示されます。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"displayConfig": "설정노드 보기",
|
||||
"import": "가져오기",
|
||||
"export": "내보내기",
|
||||
"search": "플로우 겅색",
|
||||
"search": "플로우 검색",
|
||||
"searchInput": "플로우 검색",
|
||||
"subflows": "보조 플로우",
|
||||
"createSubflow": "보조 플로우 생성",
|
||||
@@ -141,7 +141,8 @@
|
||||
"create-default-package": "기본 패키지 파일 생성",
|
||||
"no-thanks": "괜찮습니다",
|
||||
"create-default-project": "기본 프로젝트 파일 생성",
|
||||
"show-merge-conflicts": "병합 충돌 보여주기"
|
||||
"show-merge-conflicts": "병합 충돌 보여주기",
|
||||
"unknownNodesButton": "알 수 없는 노드 검색"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
@@ -203,7 +204,9 @@
|
||||
"successfulRestart": "플로우 재시작을 성공했습니다",
|
||||
"deployFailed": "배포 실패 : __message__",
|
||||
"unusedConfigNodes": "사용되지 않는 설정노드가 있습니다",
|
||||
"unusedConfigNodesLink": "여기를 클릭하면 볼 수 있습니다",
|
||||
"unusedConfigNodesButton":"사용하지 않는 구성 노드 검색",
|
||||
"unknownNodesButton":"알 수 없는 노드 검색",
|
||||
"invalidNodesButton":"잘못된 노드 검색",
|
||||
"errors": {
|
||||
"noResponse": "서버의 응답이 없습니다"
|
||||
},
|
||||
|
||||
@@ -183,7 +183,8 @@
|
||||
"create-default-package": "Создать файл пакета по умолчанию",
|
||||
"no-thanks": "Нет, спасибо",
|
||||
"create-default-project": "Создать файлы проекта по умолчанию",
|
||||
"show-merge-conflicts": "Показать конфликты слияния"
|
||||
"show-merge-conflicts": "Показать конфликты слияния",
|
||||
"unknownNodesButton": "Поиск неизвестных узлов"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
@@ -277,7 +278,9 @@
|
||||
"successfulRestart": "Потоки успешно перезапущены",
|
||||
"deployFailed": "Развертывание не удалось: __message__",
|
||||
"unusedConfigNodes":"У вас есть неиспользуемых узлы конфигурации.",
|
||||
"unusedConfigNodesLink":"Нажмите здесь, чтобы их увидеть",
|
||||
"unusedConfigNodesButton":"Поиск неиспользуемых узлов конфигурации",
|
||||
"unknownNodesButton":"Поиск неизвестных узлов",
|
||||
"invalidNodesButton":"Поиск недопустимых узлов",
|
||||
"errors": {
|
||||
"noResponse": "нет ответа от сервера"
|
||||
},
|
||||
@@ -650,14 +653,7 @@
|
||||
"empty": "пусто",
|
||||
"globalConfig": "Глобальные конфиг узлы",
|
||||
"triggerAction": "Вызвать действие",
|
||||
"find": "Найти в рабочей области",
|
||||
"search": {
|
||||
"configNodes": "Узлы конфигурации",
|
||||
"unusedConfigNodes": "Неиспользуемые узлы конфигурации",
|
||||
"invalidNodes": "Недействительные узлы",
|
||||
"uknownNodes": "Неизвестные узлы",
|
||||
"unusedSubflows": "Неиспользуемые подпотоки"
|
||||
}
|
||||
"find": "Найти в рабочей области"
|
||||
},
|
||||
"help": {
|
||||
"name": "Справка",
|
||||
@@ -888,7 +884,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "Ничего не найдено",
|
||||
"addNode": "добавить узел..."
|
||||
"addNode": "добавить узел...",
|
||||
"options": {
|
||||
"configNodes": "Узлы конфигурации",
|
||||
"unusedConfigNodes": "Неиспользуемые узлы конфигурации",
|
||||
"invalidNodes": "Недействительные узлы",
|
||||
"uknownNodes": "Неизвестные узлы",
|
||||
"unusedSubflows": "Неиспользуемые подпотоки"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "Функции",
|
||||
|
||||
@@ -182,7 +182,8 @@
|
||||
"create-default-package": "创建默认的包文件",
|
||||
"no-thanks": "不了,谢谢",
|
||||
"create-default-project": "创建默认项目文件",
|
||||
"show-merge-conflicts": "显示合并冲突"
|
||||
"show-merge-conflicts": "显示合并冲突",
|
||||
"unknownNodesButton": "搜索未知节点"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
@@ -225,7 +226,7 @@
|
||||
"compact": "紧凑",
|
||||
"formatted": "已格式化",
|
||||
"copy": "导出到剪贴板",
|
||||
"export": "到处到库",
|
||||
"export": "导出到库",
|
||||
"exportAs": "导出为",
|
||||
"overwrite": "替换",
|
||||
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"
|
||||
@@ -264,7 +265,9 @@
|
||||
"successfulRestart": "成功重启流程",
|
||||
"deployFailed": "部署失败: __message__",
|
||||
"unusedConfigNodes": "您有一些未使用的配置节点",
|
||||
"unusedConfigNodesLink": "点击此处查看它们",
|
||||
"unusedConfigNodesButton":"搜索未使用的配置节点",
|
||||
"unknownNodesButton":"搜索未知节点",
|
||||
"invalidNodesButton":"搜索无效节点",
|
||||
"errors": {
|
||||
"noResponse": "服务器没有响应"
|
||||
},
|
||||
@@ -614,14 +617,7 @@
|
||||
"empty": "空的",
|
||||
"globalConfig": "全局配置节点",
|
||||
"triggerAction": "触发动作",
|
||||
"find": "在工作区中查找",
|
||||
"search": {
|
||||
"configNodes": "配置节点",
|
||||
"unusedConfigNodes": "未使用的配置节点",
|
||||
"invalidNodes": "无效的节点",
|
||||
"uknownNodes": "未知的节点",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
"find": "在工作区中查找"
|
||||
},
|
||||
"help": {
|
||||
"name": "帮助",
|
||||
@@ -842,7 +838,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "找不到匹配",
|
||||
"addNode": "添加一个节点..."
|
||||
"addNode": "添加一个节点...",
|
||||
"options": {
|
||||
"configNodes": "配置节点",
|
||||
"unusedConfigNodes": "未使用的配置节点",
|
||||
"invalidNodes": "无效的节点",
|
||||
"uknownNodes": "未知的节点",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "功能",
|
||||
|
||||
@@ -182,7 +182,8 @@
|
||||
"create-default-package": "創建默認的包文件",
|
||||
"no-thanks": "不了,謝謝",
|
||||
"create-default-project": "創建默認項目文件",
|
||||
"show-merge-conflicts": "顯示合併衝突"
|
||||
"show-merge-conflicts": "顯示合併衝突",
|
||||
"unknownNodesButton": "搜索未知節點"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
@@ -264,7 +265,9 @@
|
||||
"successfulRestart": "成功重啟流程",
|
||||
"deployFailed": "部署失敗: __message__",
|
||||
"unusedConfigNodes": "您有一些未使用的配置節點",
|
||||
"unusedConfigNodesLink": "點擊此處查看它們",
|
||||
"unusedConfigNodesButton":"搜索未使用的配置節點",
|
||||
"unknownNodesButton":"搜索未知節點",
|
||||
"invalidNodesButton":"搜索無效節點",
|
||||
"errors": {
|
||||
"noResponse": "伺服器沒有回應"
|
||||
},
|
||||
@@ -614,14 +617,7 @@
|
||||
"empty": "空的",
|
||||
"globalConfig": "全局配置節點",
|
||||
"triggerAction": "觸發動作",
|
||||
"find": "在工作區中查找",
|
||||
"search": {
|
||||
"configNodes": "配置節點",
|
||||
"unusedConfigNodes": "未使用的配置節點",
|
||||
"invalidNodes": "無效的節點",
|
||||
"uknownNodes": "未知的節點",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
"find": "在工作區中查找"
|
||||
},
|
||||
"help": {
|
||||
"name": "幫助",
|
||||
@@ -842,7 +838,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "找不到匹配",
|
||||
"addNode": "添加一個節點..."
|
||||
"addNode": "添加一個節點...",
|
||||
"options": {
|
||||
"configNodes": "配置節點",
|
||||
"unusedConfigNodes": "未使用的配置節點",
|
||||
"invalidNodes": "無效的節點",
|
||||
"uknownNodes": "未知的節點",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "功能",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0-beta.3",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,5 +14,5 @@
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"main": "./lib/index.js"
|
||||
"main": "./index.js"
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
|
||||
(function() {
|
||||
this.setOptions = function(options) {
|
||||
this.options = {
|
||||
o.options = {
|
||||
// undef: true,
|
||||
// unused: true,
|
||||
esversion: 9,
|
||||
@@ -98,7 +98,7 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
if (options) {
|
||||
for (var opt in options) {
|
||||
if (options.hasOwnProperty(opt)) {
|
||||
this.options[opt] = options.opt;
|
||||
o.options[opt] = options[opt];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 90 B |
1
packages/node_modules/@node-red/editor-client/src/images/grip-horizontal.svg
vendored
Normal file
1
packages/node_modules/@node-red/editor-client/src/images/grip-horizontal.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="50" height="5" viewBox="0, 0, 50, 5" xmlns="http://www.w3.org/2000/svg"><path d="M0 1H50V4H0Z" fill="#CCC"/></svg>
|
||||
|
After Width: | Height: | Size: 127 B |
Binary file not shown.
|
Before Width: | Height: | Size: 192 B |
1
packages/node_modules/@node-red/editor-client/src/images/grip.svg
vendored
Normal file
1
packages/node_modules/@node-red/editor-client/src/images/grip.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="5" height="50" viewBox="0, 0, 5, 50" xmlns="http://www.w3.org/2000/svg"><path d="M1 0H4V50H1Z" fill="#CCC"/></svg>
|
||||
|
After Width: | Height: | Size: 127 B |
1
packages/node_modules/@node-red/editor-client/src/images/node-red-256.svg
vendored
Normal file
1
packages/node_modules/@node-red/editor-client/src/images/node-red-256.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="512" width="512"><g transform="translate(0 -540.36)"><path fill="#8f0000" color="#000" d="M0 540.36h512v392H0z"/><rect ry="0" height="108.23" width="500.23" stroke="#fff" y="938.25" x="5.89" stroke-width="11.77" fill="#fff"/><path style="text-decoration-color:#000;isolation:auto;mix-blend-mode:normal;solid-color:#000;block-progression:tb;text-decoration-line:none;white-space:normal;text-indent:0;text-transform:none;text-decoration-style:solid" d="M122.88 305.82a4.46 4.46 0 0 0-4.38 4.42v.78c-2.23.1-4.04.54-5.33 1.43a10.5 10.5 0 0 0-3.18 3.87c-.71 1.3-1.3 2.41-2.15 3.2-.72.66-1.8 1.12-3.45 1.32a4.37 4.37 0 0 0-4.3-3.95H82.91a4.43 4.43 0 0 0-4.42 4.35v4.24a4.43 4.43 0 0 0 4.42 4.36h17.16a4.4 4.4 0 0 0 4.4-4.36v-1.6c9.72.14 12.46 2.6 15.59 5.33 3 2.62 6.66 5.38 15.43 5.5v.73a4.49 4.49 0 0 0 4.46 4.38h17.09c2.38 0 4.45-2 4.45-4.38v-4.24a4.49 4.49 0 0 0-4.45-4.38h-17.1c-2.38 0-4.45 2-4.45 4.38v.58c-8.1-.06-10.48-2.15-13.5-4.79-2.5-2.19-5.64-4.58-11.94-5.58 1.17-1.18 1.88-2.52 2.51-3.66.68-1.23 1.29-2.2 2.27-2.88.76-.52 1.98-.84 3.66-.94v.55c0 2.39 2 4.34 4.38 4.34h17.24a4.39 4.39 0 0 0 4.38-4.34v-4.24c0-2.38-2-4.42-4.38-4.42zm0 3h17.24c.8 0 1.38.62 1.38 1.42v4.24c0 .81-.57 1.34-1.38 1.34h-17.24c-.8 0-1.38-.53-1.38-1.34v-4.24c0-.8.57-1.42 1.38-1.42zm-39.96 11.02h17.16c.81 0 1.42.6 1.42 1.4v4.24c0 .81-.61 1.41-1.42 1.41H82.92c-.8 0-1.42-.6-1.42-1.4v-4.25c0-.8.61-1.4 1.42-1.4zm57.04 9.98h17.09c.8 0 1.45.57 1.45 1.38v4.17c0 .8-.65 1.45-1.45 1.45h-17.1c-.8 0-1.45-.65-1.45-1.45v-4.17c0-.8.65-1.38 1.46-1.38z" fill="#fff" color="#000" transform="matrix(4 0 0 4 -162 -450.91)"/><g fill="#8f0000"><path d="M91 954.34v8.45l-8 1.45v60.07H69.03l-28.53-47.1-.5.05v37.2l8 1.44v8.41H19v-8.4l7.45-1.45v-50.22L19 962.79v-8.46h21.48l28.37 47.1.15-.04v-37.15l-7-1.45v-8.45h29zM95 997.83q0-11.63 6.49-19.03 6.53-7.45 18.02-7.45 11.53 0 18.02 7.4 6.54 7.4 6.54 19.08v1q0 11.74-6.54 19.14-6.49 7.35-17.93 7.35-11.58 0-18.11-7.35-6.5-7.4-6.5-19.13v-1.01zm14.03 1q0 7.12 2.5 11.45 2.5 4.28 8.08 4.28 5.43 0 7.93-4.33 2.54-4.33 2.54-11.4v-1q0-6.92-2.54-11.3-2.55-4.37-8.03-4.37t-7.98 4.37-2.5 11.3v1zM184.48 1017.96a17.15 17.15 0 0 1-5.82 5.48 15.17 15.17 0 0 1-7.59 1.88c-6.4 0-11.4-2.35-14.95-7.03-3.52-4.67-5.13-10.86-5.13-18.55v-1c0-8.21 1.62-14.83 5.18-19.86 3.56-5.03 8.56-7.54 15-7.54 2.6 0 4.93.57 7.01 1.73a17.94 17.94 0 0 1 5.81 4.8v-18.64l-8-1.45v-8.46h22v65.13l6 1.44v8.43h-18.45l-1.06-6.36zm-19.49-18.22c0 4.55.63 8.14 2.14 10.77 1.54 2.6 4.04 3.9 7.5 3.9 2.05 0 3.83-.43 5.33-1.26 1.5-.83 3.07-2.03 4.03-3.6v-22.06a11.27 11.27 0 0 0-4.03-3.85 9.62 9.62 0 0 0-5.24-1.4c-3.43 0-5.92 1.53-7.5 4.57s-2.23 7.02-2.23 11.92v1.01zM233.7 1025.28c-7.5 0-13.5-2.4-17.98-7.21-4.48-4.81-6.73-10.91-6.73-18.32v-1.92c0-7.72 2.12-14.08 6.35-19.08 4.26-5 9.96-7.46 17.1-7.43 7.03 0 12.47 2.1 16.35 6.33a23.46 23.46 0 0 1 6.2 17.15v7.52h-31.43l-.1.41c.26 3.43 1.4 6.25 3.41 8.46 2.05 2.21 4.83 3.32 8.32 3.32 3.1 0 5.69-.3 7.74-.91 2.05-.64 4.29-1.64 6.73-2.98l3.8 8.65a27.59 27.59 0 0 1-8.37 4.28 35.28 35.28 0 0 1-11.4 1.73zm-1.25-43.16c-2.6 0-4.65.99-6.15 2.98s-2.44 4.6-2.8 7.83l.15.4H241v-1.41c0-2.98-.84-5.35-2.25-7.11-1.37-1.8-3.47-2.7-6.3-2.7zM291.99 1000.32h-27v-11h27zM331.88 954.34c7.95 0 14.18 1.82 18.7 5.47 4.52 3.63 6.4 8.64 6.4 15.05 0 3.52-.57 6.58-2.46 9.18-1.89 2.6-4.66 4.7-8.31 6.3 4.13 1.21 7.1 3.25 8.89 6.1a19.02 19.02 0 0 1 2.89 10.52v3.56c0 1.54.15 2.74.76 3.6.6.84 1.62 1.34 3.03 1.5l1.2.24v8.46h-6.73c-4.58 0-7.8-1.24-9.66-3.7s-2.6-5.66-2.6-9.57v-3.99c0-3.4-1.1-6.05-2.93-7.98-1.8-1.95-4.34-2.98-7.64-3.07H322v18.45l7 1.44v8.42h-29v-8.42l8-1.44v-50.22l-8-1.44v-8.46h31.89zm-9.95 30.85h9.71c3.91 0 6.84-.83 8.8-2.5s2.93-4.07 2.93-7.2c0-3.15-.98-5.65-2.93-7.5-1.92-1.9-4.78-2.84-8.56-2.84h-9.9v20.04zM412.99 993.32h-23v20h22.21l.63-8h10.2v18.99H368v-8.42l8-1.44v-50.22l-8-1.44v-8.47h54.95v19h-10.3l-.63-8H390v17h23v11zM462.48 954.36c8.55 0 15.6 2.71 21.14 8.19 5.55 5.45 8.36 12.42 8.36 20.98v11.58c0 8.59-2.81 15.63-8.36 21.08-5.54 5.41-12.59 8.12-21.14 8.12h-31.5v-8.41l7-1.52v-50.22l-7-1.37v-8.43l7.46-.08 24.04.08zm-10.5 10.76v48.4l9.77.02c5.03.02 8.98-1.7 11.83-5.1 2.85-3.39 4.4-7.8 4.4-13.28v-11.68c0-5.42-1.55-9.84-4.4-13.24-2.85-3.4-6.8-5.1-11.83-5.1l-9.77-.02z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -13,10 +13,23 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
/**
|
||||
* An API for undo / redo history buffer
|
||||
* @namespace RED.history
|
||||
*/
|
||||
RED.history = (function() {
|
||||
var undoHistory = [];
|
||||
var redoHistory = [];
|
||||
|
||||
function nodeOrJunction(id) {
|
||||
var node = RED.nodes.node(id);
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
return RED.nodes.junction(id);
|
||||
}
|
||||
|
||||
function undoEvent(ev) {
|
||||
var i;
|
||||
var len;
|
||||
@@ -101,6 +114,23 @@ RED.history = (function() {
|
||||
RED.nodes.removeLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
if (ev.junctions) {
|
||||
inverseEv.junctions = [];
|
||||
for (i=0;i<ev.junctions.length;i++) {
|
||||
inverseEv.junctions.push(ev.junctions[i]);
|
||||
RED.nodes.removeJunction(ev.junctions[i]);
|
||||
if (ev.junctions[i].g) {
|
||||
var group = RED.nodes.group(ev.junctions[i].g);
|
||||
var index = group.nodes.indexOf(ev.junctions[i]);
|
||||
if (index !== -1) {
|
||||
group.nodes.splice(index,1);
|
||||
RED.group.markDirty(group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if (ev.groups) {
|
||||
inverseEv.groups = [];
|
||||
for (i = ev.groups.length - 1;i>=0;i--) {
|
||||
@@ -267,6 +297,21 @@ RED.history = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ev.junctions) {
|
||||
inverseEv.junctions = [];
|
||||
for (i=0;i<ev.junctions.length;i++) {
|
||||
inverseEv.junctions.push(ev.junctions[i]);
|
||||
RED.nodes.addJunction(ev.junctions[i]);
|
||||
if (ev.junctions[i].g) {
|
||||
group = RED.nodes.group(ev.junctions[i].g);
|
||||
if (group.nodes.indexOf(ev.junctions[i]) === -1) {
|
||||
group.nodes.push(ev.junctions[i]);
|
||||
}
|
||||
RED.group.markDirty(group)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (ev.links) {
|
||||
inverseEv.links = [];
|
||||
for (i=0;i<ev.links.length;i++) {
|
||||
@@ -477,6 +522,7 @@ RED.history = (function() {
|
||||
var z = ev.activeWorkspace;
|
||||
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
|
||||
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
|
||||
fullNodeList = fullNodeList.concat(RED.nodes.junctions(ev.subflow.subflow.id))
|
||||
fullNodeList.forEach(function(n) {
|
||||
n.x += ev.subflow.offsetX;
|
||||
n.y += ev.subflow.offsetY;
|
||||
@@ -486,7 +532,7 @@ RED.history = (function() {
|
||||
});
|
||||
inverseEv.subflows = [];
|
||||
for (i=0;i<ev.nodes.length;i++) {
|
||||
inverseEv.subflows.push(RED.nodes.node(ev.nodes[i]));
|
||||
inverseEv.subflows.push(nodeOrJunction(ev.nodes[i]));
|
||||
RED.nodes.remove(ev.nodes[i]);
|
||||
}
|
||||
}
|
||||
@@ -558,11 +604,22 @@ RED.history = (function() {
|
||||
} else if (ev.t == "reorder") {
|
||||
inverseEv = {
|
||||
t: 'reorder',
|
||||
order: RED.nodes.getWorkspaceOrder(),
|
||||
dirty: RED.nodes.dirty()
|
||||
};
|
||||
if (ev.order) {
|
||||
RED.workspaces.order(ev.order);
|
||||
if (ev.workspaces) {
|
||||
inverseEv.workspaces = {
|
||||
from: ev.workspaces.to,
|
||||
to: ev.workspaces.from
|
||||
}
|
||||
RED.workspaces.order(ev.workspaces.from);
|
||||
}
|
||||
if (ev.nodes) {
|
||||
inverseEv.nodes = {
|
||||
z: ev.nodes.z,
|
||||
from: ev.nodes.to,
|
||||
to: ev.nodes.from
|
||||
}
|
||||
RED.nodes.setNodeOrder(ev.nodes.z,ev.nodes.from);
|
||||
}
|
||||
} else if (ev.t == "createGroup") {
|
||||
inverseEv = {
|
||||
@@ -658,6 +715,8 @@ RED.history = (function() {
|
||||
push: function(ev) {
|
||||
undoHistory.push(ev);
|
||||
redoHistory = [];
|
||||
RED.menu.setDisabled("menu-item-edit-undo", false);
|
||||
RED.menu.setDisabled("menu-item-edit-redo", true);
|
||||
},
|
||||
pop: function() {
|
||||
var ev = undoHistory.pop();
|
||||
@@ -665,13 +724,24 @@ RED.history = (function() {
|
||||
if (rev) {
|
||||
redoHistory.push(rev);
|
||||
}
|
||||
RED.menu.setDisabled("menu-item-edit-undo", undoHistory.length === 0);
|
||||
RED.menu.setDisabled("menu-item-edit-redo", redoHistory.length === 0);
|
||||
},
|
||||
peek: function() {
|
||||
return undoHistory[undoHistory.length-1];
|
||||
},
|
||||
replace: function(ev) {
|
||||
if (undoHistory.length === 0) {
|
||||
RED.history.push(ev);
|
||||
} else {
|
||||
undoHistory[undoHistory.length-1] = ev;
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
undoHistory = [];
|
||||
redoHistory = [];
|
||||
RED.menu.setDisabled("menu-item-edit-undo", true);
|
||||
RED.menu.setDisabled("menu-item-edit-redo", true);
|
||||
},
|
||||
redo: function() {
|
||||
var ev = redoHistory.pop();
|
||||
@@ -681,6 +751,8 @@ RED.history = (function() {
|
||||
undoHistory.push(uev);
|
||||
}
|
||||
}
|
||||
RED.menu.setDisabled("menu-item-edit-undo", undoHistory.length === 0);
|
||||
RED.menu.setDisabled("menu-item-edit-redo", redoHistory.length === 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ RED.i18n = (function() {
|
||||
apiRootUrl = options.apiRootUrl||"";
|
||||
var preferredLanguage = localStorage.getItem("editor-language") || detectLanguage();
|
||||
var opts = {
|
||||
compatibilityJSON: 'v3',
|
||||
backend: {
|
||||
loadPath: apiRootUrl+'locales/__ns__?lng=__lng__',
|
||||
},
|
||||
@@ -37,6 +38,8 @@ RED.i18n = (function() {
|
||||
defaultNS: "editor",
|
||||
fallbackLng: ['en-US'],
|
||||
returnObjects: true,
|
||||
keySeparator: ".",
|
||||
nsSeparator: ":",
|
||||
interpolation: {
|
||||
unescapeSuffix: 'HTML',
|
||||
escapeValue: false,
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
"ctrl-alt-o": "core:open-project",
|
||||
"ctrl-g v": "core:show-version-control-tab",
|
||||
"ctrl-shift-l": "core:show-event-log",
|
||||
"ctrl-shift-p":"core:show-action-list"
|
||||
"ctrl-shift-p":"core:show-action-list",
|
||||
"alt-w": "core:hide-flow",
|
||||
"alt-shift-w": "core:show-last-hidden-flow"
|
||||
},
|
||||
"red-ui-sidebar-node-config": {
|
||||
"backspace": "core:delete-config-selection",
|
||||
@@ -36,7 +38,9 @@
|
||||
},
|
||||
"red-ui-workspace": {
|
||||
"backspace": "core:delete-selection",
|
||||
"ctrl-backspace": "core:delete-selection-and-reconnect",
|
||||
"delete": "core:delete-selection",
|
||||
"ctrl-delete": "core:delete-selection-and-reconnect",
|
||||
"enter": "core:edit-selected-node",
|
||||
"ctrl-enter": "core:go-to-selection",
|
||||
"ctrl-c": "core:copy-selection-to-internal-clipboard",
|
||||
@@ -77,6 +81,19 @@
|
||||
"right": "core:go-to-nearest-node-on-right",
|
||||
"left": "core:go-to-nearest-node-on-left",
|
||||
"up": "core:go-to-nearest-node-above",
|
||||
"down": "core:go-to-nearest-node-below"
|
||||
"down": "core:go-to-nearest-node-below",
|
||||
"alt-a g": "core:align-selection-to-grid",
|
||||
"alt-a l": "core:align-selection-to-left",
|
||||
"alt-a r": "core:align-selection-to-right",
|
||||
"alt-a t": "core:align-selection-to-top",
|
||||
"alt-a b": "core:align-selection-to-bottom",
|
||||
"alt-a m": "core:align-selection-to-middle",
|
||||
"alt-a c": "core:align-selection-to-center",
|
||||
"alt-a h": "core:distribute-selection-horizontally",
|
||||
"alt-a v": "core:distribute-selection-vertically",
|
||||
"shift-f": "core:search-previous",
|
||||
"f": "core:search-next",
|
||||
"alt-l l": "core:split-wire-with-link-nodes"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -201,6 +201,7 @@ var RED = (function() {
|
||||
RED.projects.refresh(function(activeProject) {
|
||||
loadFlows(function() {
|
||||
RED.sidebar.info.refresh()
|
||||
var showProjectWelcome = false;
|
||||
if (!activeProject) {
|
||||
// Projects enabled but no active project
|
||||
RED.menu.setDisabled('menu-item-projects-open',true);
|
||||
@@ -208,10 +209,10 @@ var RED = (function() {
|
||||
if (activeProject === false) {
|
||||
// User previously decline the migration to projects.
|
||||
} else { // null/undefined
|
||||
RED.projects.showStartup();
|
||||
showProjectWelcome = true;
|
||||
}
|
||||
}
|
||||
completeLoad();
|
||||
completeLoad(showProjectWelcome);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -251,6 +252,22 @@ var RED = (function() {
|
||||
if (/^#flow\/.+$/.test(currentHash)) {
|
||||
RED.workspaces.show(currentHash.substring(6),true);
|
||||
}
|
||||
if (RED.workspaces.count() > 0) {
|
||||
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
const workspaces = RED.nodes.getWorkspaceOrder();
|
||||
if (RED.workspaces.active() === 0) {
|
||||
for (let index = 0; index < workspaces.length; index++) {
|
||||
const ws = workspaces[index];
|
||||
if (!hiddenTabs[ws]) {
|
||||
RED.workspaces.show(ws);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RED.workspaces.active() === 0) {
|
||||
RED.workspaces.show(workspaces[0]);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
console.warn(err);
|
||||
RED.notify(
|
||||
@@ -267,7 +284,7 @@ var RED = (function() {
|
||||
});
|
||||
}
|
||||
|
||||
function completeLoad() {
|
||||
function completeLoad(showProjectWelcome) {
|
||||
var persistentNotifications = {};
|
||||
RED.comms.subscribe("notification/#",function(topic,msg) {
|
||||
var parts = topic.split("/");
|
||||
@@ -341,6 +358,14 @@ var RED = (function() {
|
||||
} else {
|
||||
options.buttons = [
|
||||
{
|
||||
text: RED._("notification.label.unknownNodesButton"),
|
||||
class: "pull-left",
|
||||
click: function() {
|
||||
RED.actions.invoke("core:search", "type:unknown ");
|
||||
}
|
||||
},
|
||||
{
|
||||
class: "primary",
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
@@ -457,7 +482,7 @@ var RED = (function() {
|
||||
var parts = topic.split("/");
|
||||
var node = RED.nodes.node(parts[1]);
|
||||
if (node) {
|
||||
if (msg.hasOwnProperty("text") && msg.text !== null && /^[a-zA-Z]/.test(msg.text)) {
|
||||
if (msg.hasOwnProperty("text") && msg.text !== null && /^[@a-zA-Z]/.test(msg.text)) {
|
||||
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
|
||||
}
|
||||
node.status = msg;
|
||||
@@ -471,22 +496,33 @@ var RED = (function() {
|
||||
var typeList;
|
||||
var info;
|
||||
if (topic == "notification/node/added") {
|
||||
var addedTypes = [];
|
||||
msg.forEach(function(m) {
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadNodeCatalog(id, function() {
|
||||
$.get('nodes/'+id, function(data) {
|
||||
appendNodeConfig(data);
|
||||
RED.settings.refreshSettings(function(err, data) {
|
||||
var addedTypes = [];
|
||||
msg.forEach(function(m) {
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadNodeCatalog(id, function() {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||
}
|
||||
loadIconList();
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||
}
|
||||
loadIconList();
|
||||
})
|
||||
} else if (topic == "notification/node/removed") {
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
@@ -499,18 +535,29 @@ var RED = (function() {
|
||||
loadIconList();
|
||||
} else if (topic == "notification/node/enabled") {
|
||||
if (msg.types) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
$.get('nodes/'+msg.id, function(data) {
|
||||
appendNodeConfig(data);
|
||||
RED.settings.refreshSettings(function(err, data) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
});
|
||||
}
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+msg.id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (topic == "notification/node/disabled") {
|
||||
if (msg.types) {
|
||||
@@ -530,24 +577,28 @@ var RED = (function() {
|
||||
|
||||
$(".red-ui-header-toolbar").show();
|
||||
|
||||
|
||||
RED.sidebar.show(":first");
|
||||
RED.sidebar.show(":first", true);
|
||||
|
||||
setTimeout(function() {
|
||||
loader.end();
|
||||
checkFirstRun(function() {
|
||||
if (showProjectWelcome) {
|
||||
RED.projects.showStartup();
|
||||
}
|
||||
});
|
||||
},100);
|
||||
}
|
||||
|
||||
function showAbout() {
|
||||
$.get('red/about', function(data) {
|
||||
// data will be strictly markdown. Any HTML should be escaped.
|
||||
data = RED.utils.sanitize(data);
|
||||
var aboutHeader = '<div style="text-align:center;">'+
|
||||
'<img width="50px" src="red/images/node-red-icon.svg" />'+
|
||||
'</div>';
|
||||
|
||||
RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data));
|
||||
});
|
||||
function checkFirstRun(done) {
|
||||
if (RED.settings.theme("tours") === false) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
if (!RED.settings.get("editor.view.view-show-welcome-tours", true)) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
RED.actions.invoke("core:show-welcome-tour", RED.settings.get("editor.tours.welcome"), done);
|
||||
}
|
||||
|
||||
function buildMainMenu() {
|
||||
@@ -559,6 +610,25 @@ var RED = (function() {
|
||||
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
|
||||
]});
|
||||
}
|
||||
menuOptions.push({id:"menu-item-edit-menu", label:RED._("menu.label.edit"), options: [
|
||||
{id: "menu-item-edit-undo", label:RED._("keyboard.undoChange"), disabled: true, onselect: "core:undo"},
|
||||
{id: "menu-item-edit-redo", label:RED._("keyboard.redoChange"), disabled: true, onselect: "core:redo"},
|
||||
null,
|
||||
{id: "menu-item-edit-cut", label:RED._("keyboard.cutNode"), onselect: "core:cut-selection-to-internal-clipboard"},
|
||||
{id: "menu-item-edit-copy", label:RED._("keyboard.copyNode"), onselect: "core:copy-selection-to-internal-clipboard"},
|
||||
{id: "menu-item-edit-paste", label:RED._("keyboard.pasteNode"), disabled: true, onselect: "core:paste-from-internal-clipboard"},
|
||||
null,
|
||||
{id: "menu-item-edit-copy-group-style", label:RED._("keyboard.copyGroupStyle"), onselect: "core:copy-group-style"},
|
||||
{id: "menu-item-edit-paste-group-style", label:RED._("keyboard.pasteGroupStyle"), disabled: true, onselect: "core:paste-group-style"},
|
||||
null,
|
||||
{id: "menu-item-edit-select-all", label:RED._("keyboard.selectAll"), onselect: "core:select-all-nodes"},
|
||||
{id: "menu-item-edit-select-connected", label:RED._("keyboard.selectAllConnected"), onselect: "core:select-connected-nodes"},
|
||||
{id: "menu-item-edit-select-none", label:RED._("keyboard.selectNone"), onselect: "core:select-none"},
|
||||
null,
|
||||
{id: "menu-item-edit-split-wire-with-links", label:RED._("keyboard.splitWireWithLinks"), onselect: "core:split-wire-with-link-nodes"},
|
||||
|
||||
]});
|
||||
|
||||
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
|
||||
{id:"menu-item-palette",label:RED._("menu.label.palette.show"),toggle:true,onselect:"core:toggle-palette", selected: true},
|
||||
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true},
|
||||
@@ -566,6 +636,25 @@ var RED = (function() {
|
||||
{id:"menu-item-action-list",label:RED._("keyboard.actionList"),onselect:"core:show-action-list"},
|
||||
null
|
||||
]});
|
||||
|
||||
menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [
|
||||
{id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"},
|
||||
{id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"},
|
||||
{id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"},
|
||||
{id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"},
|
||||
null,
|
||||
{id: "menu-item-view-tools-align-left", label:RED._("menu.label.alignLeft"), disabled: true, onselect: "core:align-selection-to-left"},
|
||||
{id: "menu-item-view-tools-align-center", label:RED._("menu.label.alignCenter"), disabled: true, onselect: "core:align-selection-to-center"},
|
||||
{id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"},
|
||||
null,
|
||||
{id: "menu-item-view-tools-align-top", label:RED._("menu.label.alignTop"), disabled: true, onselect: "core:align-selection-to-top"},
|
||||
{id: "menu-item-view-tools-align-middle", label:RED._("menu.label.alignMiddle"), disabled: true, onselect: "core:align-selection-to-middle"},
|
||||
{id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"},
|
||||
null,
|
||||
{id: "menu-item-view-tools-distribute-horizontally", label:RED._("menu.label.distributeHorizontally"), disabled: true, onselect: "core:distribute-selection-horizontally"},
|
||||
{id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"}
|
||||
]});
|
||||
|
||||
menuOptions.push(null);
|
||||
if (RED.settings.theme("menu.menu-item-import-library", true)) {
|
||||
menuOptions.push({id: "menu-item-import", label: RED._("menu.label.import"), onselect: "core:show-import-dialog"});
|
||||
@@ -626,7 +715,6 @@ var RED = (function() {
|
||||
RED.user.init();
|
||||
RED.notifications.init();
|
||||
RED.library.init();
|
||||
RED.keyboard.init();
|
||||
RED.palette.init();
|
||||
RED.eventLog.init();
|
||||
|
||||
@@ -650,21 +738,19 @@ var RED = (function() {
|
||||
RED.search.init();
|
||||
RED.actionList.init();
|
||||
RED.editor.init();
|
||||
RED.diagnostics.init();
|
||||
RED.diff.init();
|
||||
|
||||
|
||||
RED.deploy.init(RED.settings.theme("deployButton",null));
|
||||
|
||||
buildMainMenu();
|
||||
RED.keyboard.init(buildMainMenu);
|
||||
|
||||
RED.nodes.init();
|
||||
RED.comms.connect();
|
||||
|
||||
$("#red-ui-main-container").show();
|
||||
|
||||
|
||||
RED.actions.add("core:show-about", showAbout);
|
||||
|
||||
loadPluginList();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ RED.settings = (function () {
|
||||
|
||||
var loadedSettings = {};
|
||||
var userSettings = {};
|
||||
var settingsDirty = false;
|
||||
var pendingSave;
|
||||
|
||||
var hasLocalStorage = function () {
|
||||
@@ -126,7 +125,7 @@ RED.settings = (function () {
|
||||
load(done);
|
||||
}
|
||||
|
||||
var load = function(done) {
|
||||
var refreshSettings = function(done) {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
@@ -136,6 +135,23 @@ RED.settings = (function () {
|
||||
url: 'settings',
|
||||
success: function (data) {
|
||||
setProperties(data);
|
||||
done(null, data);
|
||||
},
|
||||
error: function(jqXHR,textStatus,errorThrown) {
|
||||
if (jqXHR.status === 401) {
|
||||
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
|
||||
window.location.search = "";
|
||||
}
|
||||
RED.user.login(function() { refreshSettings(done); });
|
||||
} else {
|
||||
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
var load = function(done) {
|
||||
refreshSettings(function(err, data) {
|
||||
if (!err) {
|
||||
if (!RED.settings.user || RED.settings.user.anonymous) {
|
||||
RED.settings.remove("auth-tokens");
|
||||
}
|
||||
@@ -148,18 +164,8 @@ RED.settings = (function () {
|
||||
console.log("D3",d3.version);
|
||||
console.groupEnd();
|
||||
loadUserSettings(done);
|
||||
},
|
||||
error: function(jqXHR,textStatus,errorThrown) {
|
||||
if (jqXHR.status === 401) {
|
||||
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
|
||||
window.location.search = "";
|
||||
}
|
||||
RED.user.login(function() { load(done); });
|
||||
} else {
|
||||
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
function loadUserSettings(done) {
|
||||
@@ -220,14 +226,28 @@ RED.settings = (function () {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
function getLocal(key) {
|
||||
return localStorage.getItem(key)
|
||||
}
|
||||
function setLocal(key, value) {
|
||||
localStorage.setItem(key, value);
|
||||
}
|
||||
function removeLocal(key) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
init: init,
|
||||
load: load,
|
||||
loadUserSettings: loadUserSettings,
|
||||
refreshSettings: refreshSettings,
|
||||
set: set,
|
||||
get: get,
|
||||
remove: remove,
|
||||
theme: theme
|
||||
theme: theme,
|
||||
setLocal: setLocal,
|
||||
getLocal: getLocal,
|
||||
removeLocal: removeLocal
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -160,18 +160,19 @@ RED.actionList = (function() {
|
||||
createDialog();
|
||||
}
|
||||
dialog.slideDown(300);
|
||||
searchInput.searchBox('value',v)
|
||||
searchInput.searchBox('value',v);
|
||||
searchResults.editableList('empty');
|
||||
results = [];
|
||||
var actions = RED.actions.list();
|
||||
actions.sort(function(A,B) {
|
||||
return A.id.localeCompare(B.id);
|
||||
var Akey = A.label;
|
||||
var Bkey = B.label;
|
||||
return Akey.localeCompare(Bkey);
|
||||
});
|
||||
actions.forEach(function(action) {
|
||||
action.label = action.id.replace(/:/,": ").replace(/-/g," ").replace(/(^| )./g,function() { return arguments[0].toUpperCase()});
|
||||
action._label = action.label.toLowerCase();
|
||||
searchResults.editableList('addItem',action)
|
||||
})
|
||||
searchResults.editableList('addItem',action);
|
||||
});
|
||||
RED.events.emit("actionList:open");
|
||||
visible = true;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,67 @@
|
||||
RED.actions = (function() {
|
||||
var actions = {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function addAction(name,handler) {
|
||||
actions[name] = handler;
|
||||
function addAction(name,handler,options) {
|
||||
if (typeof handler !== 'function') {
|
||||
throw new Error("Action handler not a function");
|
||||
}
|
||||
if (actions[name]) {
|
||||
throw new Error("Cannot override existing action");
|
||||
}
|
||||
actions[name] = {
|
||||
handler: handler,
|
||||
options: options,
|
||||
};
|
||||
}
|
||||
function removeAction(name) {
|
||||
delete actions[name];
|
||||
}
|
||||
function getAction(name) {
|
||||
return actions[name];
|
||||
return actions[name].handler;
|
||||
}
|
||||
function invokeAction(name,args) {
|
||||
function getActionLabel(name) {
|
||||
let def = actions[name]
|
||||
if (!def) {
|
||||
return ''
|
||||
}
|
||||
if (!def.label) {
|
||||
var options = def.options;
|
||||
var key = options ? options.label : undefined;
|
||||
if (!key) {
|
||||
key = "action-list." +name.replace(/^.*:/,"");
|
||||
}
|
||||
var label = RED._(key);
|
||||
if (label === key) {
|
||||
// no translation. convert `name` to description
|
||||
label = name.replace(/(^.+:([a-z]))|(-([a-z]))/g, function() {
|
||||
if (arguments[5] === 0) {
|
||||
return arguments[2].toUpperCase();
|
||||
} else {
|
||||
return " "+arguments[4].toUpperCase();
|
||||
}
|
||||
});
|
||||
}
|
||||
def.label = label;
|
||||
}
|
||||
return def.label
|
||||
}
|
||||
|
||||
|
||||
function invokeAction() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var name = args.shift();
|
||||
if (actions.hasOwnProperty(name)) {
|
||||
actions[name](args);
|
||||
var handler = actions[name].handler;
|
||||
handler.apply(null, args);
|
||||
}
|
||||
}
|
||||
function listActions() {
|
||||
var result = [];
|
||||
|
||||
Object.keys(actions).forEach(function(action) {
|
||||
var def = actions[action];
|
||||
var shortcut = RED.keyboard.getShortcut(action);
|
||||
var isUser = false;
|
||||
if (shortcut) {
|
||||
@@ -27,19 +69,25 @@ RED.actions = (function() {
|
||||
} else {
|
||||
isUser = !!RED.keyboard.getUserShortcut(action);
|
||||
}
|
||||
if (!def.label) {
|
||||
def.label = getActionLabel(action)
|
||||
}
|
||||
result.push({
|
||||
id:action,
|
||||
scope:shortcut?shortcut.scope:undefined,
|
||||
key:shortcut?shortcut.key:undefined,
|
||||
user:isUser
|
||||
})
|
||||
})
|
||||
user:isUser,
|
||||
label: def.label,
|
||||
options: def.options,
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return {
|
||||
add: addAction,
|
||||
remove: removeAction,
|
||||
get: getAction,
|
||||
getLabel: getActionLabel,
|
||||
invoke: invokeAction,
|
||||
list: listActions
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ RED.clipboard = (function() {
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
},
|
||||
{ // red-ui-clipboard-dialog-download
|
||||
@@ -81,6 +82,7 @@ RED.clipboard = (function() {
|
||||
var data = $("#red-ui-clipboard-dialog-export-text").val();
|
||||
downloadData("flows.json", data);
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
},
|
||||
{ // red-ui-clipboard-dialog-export
|
||||
@@ -95,6 +97,7 @@ RED.clipboard = (function() {
|
||||
$( this ).dialog( "close" );
|
||||
copyText(flowData);
|
||||
RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"});
|
||||
RED.view.focus();
|
||||
} else {
|
||||
var flowToExport = $("#red-ui-clipboard-dialog-export-text").val();
|
||||
var selectedPath = activeLibraries[activeTab].getSelected();
|
||||
@@ -110,6 +113,7 @@ RED.clipboard = (function() {
|
||||
contentType: "application/json; charset=utf-8"
|
||||
}).done(function() {
|
||||
$(dialog).dialog( "close" );
|
||||
RED.view.focus();
|
||||
RED.notify(RED._("library.exportedToLibrary"),"success");
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
if (xhr.status === 401) {
|
||||
@@ -171,6 +175,7 @@ RED.clipboard = (function() {
|
||||
}
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
},
|
||||
{ // red-ui-clipboard-dialog-import-conflict
|
||||
@@ -203,6 +208,7 @@ RED.clipboard = (function() {
|
||||
// console.table(pendingImportConfig.importNodes.map(function(n) { return {id:n.id,type:n.type,result:importMap[n.id]}}))
|
||||
RED.view.importNodes(newNodes, pendingImportConfig.importOptions);
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -498,6 +504,13 @@ RED.clipboard = (function() {
|
||||
$("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport);
|
||||
$("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
|
||||
|
||||
if (RED.workspaces.active() === 0) {
|
||||
$("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected");
|
||||
$("#red-ui-clipboard-dialog-import-opt-new").addClass("selected");
|
||||
} else {
|
||||
$("#red-ui-clipboard-dialog-import-opt-current").removeClass('disabled').addClass("selected");
|
||||
$("#red-ui-clipboard-dialog-import-opt-new").removeClass("selected");
|
||||
}
|
||||
$("#red-ui-clipboard-dialog-import-opt > a").on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
|
||||
@@ -611,9 +624,6 @@ RED.clipboard = (function() {
|
||||
activeLibraries[tabId] = browser;
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
$("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename);
|
||||
$("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)});
|
||||
$("#red-ui-clipboard-dialog-export").button("enable");
|
||||
@@ -636,7 +646,6 @@ RED.clipboard = (function() {
|
||||
label: RED._("editor.types.json")
|
||||
});
|
||||
|
||||
|
||||
var previewList = $("#red-ui-clipboard-dialog-export-tab-clipboard-preview-list").css({position:"absolute",top:0,right:0,bottom:0,left:0}).treeList({
|
||||
data: []
|
||||
})
|
||||
@@ -700,6 +709,7 @@ RED.clipboard = (function() {
|
||||
} else if (type === 'flow') {
|
||||
var activeWorkspace = RED.workspaces.active();
|
||||
nodes = RED.nodes.groups(activeWorkspace);
|
||||
nodes = nodes.concat(RED.nodes.junctions(activeWorkspace));
|
||||
nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
|
||||
RED.nodes.eachConfig(function(n) {
|
||||
if (n.z === RED.workspaces.active() && n._def.hasUsers === false) {
|
||||
@@ -738,16 +748,22 @@ RED.clipboard = (function() {
|
||||
$("#red-ui-clipboard-dialog-export").hide();
|
||||
$("#red-ui-clipboard-dialog-import-conflict").hide();
|
||||
|
||||
var selection = RED.workspaces.selection();
|
||||
if (selection.length > 0) {
|
||||
$("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
|
||||
if (RED.workspaces.active() === 0) {
|
||||
$("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected');
|
||||
$("#red-ui-clipboard-dialog-export-rng-flow").addClass('disabled').removeClass('selected');
|
||||
$("#red-ui-clipboard-dialog-export-rng-full").trigger("click");
|
||||
} else {
|
||||
selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var selection = RED.workspaces.selection();
|
||||
if (selection.length > 0) {
|
||||
$("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
|
||||
} else {
|
||||
$("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected');
|
||||
$("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
|
||||
selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
$("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
|
||||
} else {
|
||||
$("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected');
|
||||
$("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
|
||||
@@ -931,7 +947,8 @@ RED.clipboard = (function() {
|
||||
if (truncated) {
|
||||
msg += "_truncated";
|
||||
}
|
||||
$("#red-ui-clipboard-hidden").val(value).focus().select();
|
||||
var clipboardHidden = $('<textarea type="text" id="red-ui-clipboard-hidden" tabIndex="-1">').appendTo(document.body);
|
||||
clipboardHidden.val(value).focus().select();
|
||||
var result = document.execCommand("copy");
|
||||
if (result && element) {
|
||||
var popover = RED.popover.create({
|
||||
@@ -945,14 +962,13 @@ RED.clipboard = (function() {
|
||||
},1000);
|
||||
popover.open();
|
||||
}
|
||||
$("#red-ui-clipboard-hidden").val("");
|
||||
clipboardHidden.remove();
|
||||
if (currentFocus) {
|
||||
$(currentFocus).focus();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function importNodes(nodesStr,addFlow) {
|
||||
var newNodes = nodesStr;
|
||||
if (typeof nodesStr === 'string') {
|
||||
@@ -972,6 +988,7 @@ RED.clipboard = (function() {
|
||||
try {
|
||||
RED.view.importNodes(newNodes, importOptions);
|
||||
} catch(error) {
|
||||
console.log(error.importConfig)
|
||||
// Thrown for import_conflict
|
||||
confirmImport(error.importConfig, newNodes, importOptions);
|
||||
}
|
||||
@@ -1227,8 +1244,6 @@ RED.clipboard = (function() {
|
||||
init: function() {
|
||||
setupDialogs();
|
||||
|
||||
$('<textarea type="text" id="red-ui-clipboard-hidden" tabIndex="-1">').appendTo("#red-ui-editor");
|
||||
|
||||
RED.actions.add("core:show-export-dialog",showExportNodes);
|
||||
RED.actions.add("core:show-import-dialog",showImportNodes);
|
||||
|
||||
|
||||
126
packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js
vendored
Normal file
126
packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
(function($) {
|
||||
|
||||
/**
|
||||
* Attach to an <input type="text"> to provide auto-complete
|
||||
*
|
||||
* $("#node-red-text").autoComplete({
|
||||
* search: function(value) { return ['a','b','c'] }
|
||||
* })
|
||||
*
|
||||
* options:
|
||||
*
|
||||
* search: function(value, [done])
|
||||
* A function that is passed the current contents of the input whenever
|
||||
* it changes.
|
||||
* The function must either return auto-complete options, or pass them
|
||||
* to the optional 'done' parameter.
|
||||
* If the function signature includes 'done', it must be used
|
||||
* minLength: number
|
||||
* If `minLength` is 0, pressing down arrow will show the list
|
||||
*
|
||||
* The auto-complete options should be an array of objects in the form:
|
||||
* {
|
||||
* value: String : the value to insert if selected
|
||||
* label: String|DOM Element : the label to display in the dropdown.
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
$.widget( "nodered.autoComplete", {
|
||||
_create: function() {
|
||||
const that = this;
|
||||
this.completionMenuShown = false;
|
||||
this.options.minLength = parseInteger(this.options.minLength, 1, 0);
|
||||
this.options.search = this.options.search || function() { return [] };
|
||||
this.element.addClass("red-ui-autoComplete");
|
||||
this.element.on("keydown.red-ui-autoComplete", function(evt) {
|
||||
if ((evt.keyCode === 13 || evt.keyCode === 9) && that.completionMenuShown) {
|
||||
var opts = that.menu.options();
|
||||
that.element.val(opts[0].value);
|
||||
that.menu.hide();
|
||||
evt.preventDefault();
|
||||
}
|
||||
})
|
||||
this.element.on("keyup.red-ui-autoComplete", function(evt) {
|
||||
if (evt.keyCode === 13 || evt.keyCode === 9 || evt.keyCode === 27) {
|
||||
// ENTER / TAB / ESCAPE
|
||||
return
|
||||
}
|
||||
if (evt.keyCode === 8 || evt.keyCode === 46) {
|
||||
// Delete/Backspace
|
||||
if (!that.completionMenuShown) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
that._updateCompletions(this.value);
|
||||
});
|
||||
},
|
||||
_showCompletionMenu: function(completions) {
|
||||
if (this.completionMenuShown) {
|
||||
return;
|
||||
}
|
||||
this.menu = RED.popover.menu({
|
||||
tabSelect: true,
|
||||
width: 300,
|
||||
maxHeight: 200,
|
||||
class: "red-ui-autoComplete-container",
|
||||
options: completions,
|
||||
onselect: (opt) => { this.element.val(opt.value); this.element.focus(); this.element.trigger("change") },
|
||||
onclose: () => { this.completionMenuShown = false; delete this.menu; this.element.focus()}
|
||||
});
|
||||
this.menu.show({
|
||||
target: this.element
|
||||
})
|
||||
this.completionMenuShown = true;
|
||||
},
|
||||
_updateCompletions: function(val) {
|
||||
const that = this;
|
||||
if (val.trim().length < this.options.minLength) {
|
||||
if (this.completionMenuShown) {
|
||||
this.menu.hide();
|
||||
}
|
||||
return;
|
||||
}
|
||||
function displayResults(completions,requestId) {
|
||||
if (requestId && requestId !== that.pendingRequest) {
|
||||
// This request has been superseded
|
||||
return
|
||||
}
|
||||
if (!completions || completions.length === 0) {
|
||||
if (that.completionMenuShown) {
|
||||
that.menu.hide();
|
||||
}
|
||||
return
|
||||
}
|
||||
if (that.completionMenuShown) {
|
||||
that.menu.options(completions);
|
||||
} else {
|
||||
that._showCompletionMenu(completions);
|
||||
}
|
||||
}
|
||||
if (this.options.search.length === 2) {
|
||||
const requestId = 1+Math.floor(Math.random()*10000);
|
||||
this.pendingRequest = requestId;
|
||||
this.options.search(val,function(completions) { displayResults(completions,requestId);})
|
||||
} else {
|
||||
displayResults(this.options.search(val))
|
||||
}
|
||||
},
|
||||
_destroy: function() {
|
||||
this.element.removeClass("red-ui-autoComplete")
|
||||
this.element.off("keydown.red-ui-autoComplete")
|
||||
this.element.off("keyup.red-ui-autoComplete")
|
||||
if (this.completionMenuShown) {
|
||||
this.menu.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
function parseInteger(input, def, min, max) {
|
||||
if(input == null) { return (def || 0); }
|
||||
min = min == null ? Number.NEGATIVE_INFINITY : min;
|
||||
max = max == null ? Number.POSITIVE_INFINITY : max;
|
||||
let n = parseInt(input);
|
||||
if(isNaN(n) || n < min || n > max) { n = def || 0; }
|
||||
return n;
|
||||
}
|
||||
})(jQuery);
|
||||
@@ -16,6 +16,7 @@
|
||||
RED.menu = (function() {
|
||||
|
||||
var menuItems = {};
|
||||
let menuItemCount = 0
|
||||
|
||||
function createMenuItem(opt) {
|
||||
var item;
|
||||
@@ -59,15 +60,16 @@ RED.menu = (function() {
|
||||
item = $('<li class="red-ui-menu-divider"></li>');
|
||||
} else {
|
||||
item = $('<li></li>');
|
||||
|
||||
if (!opt.id) {
|
||||
opt.id = 'red-ui-menu-item-'+(menuItemCount++)
|
||||
}
|
||||
if (opt.group) {
|
||||
item.addClass("red-ui-menu-group-"+opt.group);
|
||||
|
||||
}
|
||||
var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">';
|
||||
if (opt.toggle) {
|
||||
linkContent += '<i class="fa fa-square pull-left"></i>';
|
||||
linkContent += '<i class="fa fa-check-square pull-left"></i>';
|
||||
linkContent += '<i class="fa fa-square'+(opt.direction!=='right'?" pull-left":"")+'"></i>';
|
||||
linkContent += '<i class="fa fa-check-square'+(opt.direction!=='right'?" pull-left":"")+'"></i>';
|
||||
|
||||
}
|
||||
if (opt.icon !== undefined) {
|
||||
@@ -77,17 +79,27 @@ RED.menu = (function() {
|
||||
linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> ';
|
||||
}
|
||||
}
|
||||
|
||||
let label = opt.label
|
||||
if (!opt.label && typeof opt.onselect === 'string') {
|
||||
label = RED.actions.getLabel(opt.onselect)
|
||||
}
|
||||
if (opt.sublabel) {
|
||||
linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+opt.label+'</span>'+
|
||||
linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+label+'</span>'+
|
||||
'<span class="red-ui-menu-sublabel">'+opt.sublabel+'</span></span>'
|
||||
} else {
|
||||
linkContent += '<span class="red-ui-menu-label">'+opt.label+'</span>'
|
||||
linkContent += '<span class="red-ui-menu-label"><span>'+label+'</span></span>'
|
||||
}
|
||||
|
||||
linkContent += '</a>';
|
||||
|
||||
var link = $(linkContent).appendTo(item);
|
||||
opt.link = link;
|
||||
if (typeof opt.onselect === 'string') {
|
||||
var shortcut = RED.keyboard.getShortcut(opt.onselect);
|
||||
if (shortcut && shortcut.key) {
|
||||
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(link.find(".red-ui-menu-label"));
|
||||
}
|
||||
}
|
||||
|
||||
menuItems[opt.id] = opt;
|
||||
|
||||
@@ -119,15 +131,38 @@ RED.menu = (function() {
|
||||
});
|
||||
}
|
||||
if (opt.options) {
|
||||
item.addClass("red-ui-menu-dropdown-submenu pull-left");
|
||||
item.addClass("red-ui-menu-dropdown-submenu"+(opt.direction!=='right'?" pull-left":""));
|
||||
var submenu = $('<ul id="'+opt.id+'-submenu" class="red-ui-menu-dropdown"></ul>').appendTo(item);
|
||||
var hasIcons = false
|
||||
var hasSubmenus = false
|
||||
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
|
||||
if (opt.options[i]) {
|
||||
if (opt.onpreselect && opt.options[i].onpreselect === undefined) {
|
||||
opt.options[i].onpreselect = opt.onpreselect
|
||||
}
|
||||
if (opt.onpostselect && opt.options[i].onpostselect === undefined) {
|
||||
opt.options[i].onpostselect = opt.onpostselect
|
||||
}
|
||||
opt.options[i].direction = opt.direction
|
||||
hasIcons = hasIcons || (opt.options[i].icon);
|
||||
hasSubmenus = hasSubmenus || (opt.options[i].options);
|
||||
}
|
||||
|
||||
var li = createMenuItem(opt.options[i]);
|
||||
if (li) {
|
||||
li.appendTo(submenu);
|
||||
}
|
||||
}
|
||||
if (!hasIcons) {
|
||||
submenu.addClass("red-ui-menu-dropdown-noicons")
|
||||
}
|
||||
if (hasSubmenus) {
|
||||
submenu.addClass("red-ui-menu-dropdown-submenus")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (opt.disabled) {
|
||||
item.addClass("disabled");
|
||||
@@ -140,7 +175,9 @@ RED.menu = (function() {
|
||||
}
|
||||
function createMenu(options) {
|
||||
var topMenu = $("<ul/>",{class:"red-ui-menu red-ui-menu-dropdown pull-right"});
|
||||
|
||||
if (options.direction) {
|
||||
topMenu.addClass("red-ui-menu-dropdown-direction-"+options.direction)
|
||||
}
|
||||
if (options.id) {
|
||||
topMenu.attr({id:options.id+"-submenu"});
|
||||
var menuParent = $("#"+options.id);
|
||||
@@ -166,9 +203,22 @@ RED.menu = (function() {
|
||||
}
|
||||
|
||||
var lastAddedSeparator = false;
|
||||
var hasSubmenus = false;
|
||||
var hasIcons = false;
|
||||
for (var i=0;i<options.options.length;i++) {
|
||||
var opt = options.options[i];
|
||||
if (opt) {
|
||||
if (options.onpreselect && opt.onpreselect === undefined) {
|
||||
opt.onpreselect = options.onpreselect
|
||||
}
|
||||
if (options.onpostselect && opt.onpostselect === undefined) {
|
||||
opt.onpostselect = options.onpostselect
|
||||
}
|
||||
opt.direction = options.direction || 'left'
|
||||
}
|
||||
if (opt !== null || !lastAddedSeparator) {
|
||||
hasIcons = hasIcons || (opt && opt.icon);
|
||||
hasSubmenus = hasSubmenus || (opt && opt.options);
|
||||
var li = createMenuItem(opt);
|
||||
if (li) {
|
||||
li.appendTo(topMenu);
|
||||
@@ -176,13 +226,21 @@ RED.menu = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasIcons) {
|
||||
topMenu.addClass("red-ui-menu-dropdown-noicons")
|
||||
}
|
||||
if (hasSubmenus) {
|
||||
topMenu.addClass("red-ui-menu-dropdown-submenus")
|
||||
}
|
||||
return topMenu;
|
||||
}
|
||||
|
||||
function triggerAction(id, args) {
|
||||
var opt = menuItems[id];
|
||||
var callback = opt.onselect;
|
||||
if (opt.onpreselect) {
|
||||
opt.onpreselect.call(opt,args)
|
||||
}
|
||||
if (typeof opt.onselect === 'string') {
|
||||
callback = RED.actions.get(opt.onselect);
|
||||
}
|
||||
@@ -191,6 +249,9 @@ RED.menu = (function() {
|
||||
} else {
|
||||
console.log("No callback for",id,opt.onselect);
|
||||
}
|
||||
if (opt.onpostselect) {
|
||||
opt.onpostselect.call(opt,args)
|
||||
}
|
||||
}
|
||||
|
||||
function isSelected(id) {
|
||||
@@ -276,6 +337,22 @@ RED.menu = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function refreshShortcuts() {
|
||||
for (var id in menuItems) {
|
||||
if (menuItems.hasOwnProperty(id)) {
|
||||
var opt = menuItems[id];
|
||||
if (typeof opt.onselect === "string" && opt.shortcutSpan) {
|
||||
opt.shortcutSpan.remove();
|
||||
delete opt.shortcutSpan;
|
||||
var shortcut = RED.keyboard.getShortcut(opt.onselect);
|
||||
if (shortcut && shortcut.key) {
|
||||
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(opt.link.find(".red-ui-menu-label"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: createMenu,
|
||||
setSelected: setSelected,
|
||||
@@ -284,6 +361,7 @@ RED.menu = (function() {
|
||||
setDisabled: setDisabled,
|
||||
addItem: addItem,
|
||||
removeItem: removeItem,
|
||||
setAction: setAction
|
||||
setAction: setAction,
|
||||
refreshShortcuts: refreshShortcuts
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -13,24 +13,138 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
/*
|
||||
* RED.popover.create(options) - create a popover callout box
|
||||
* RED.popover.tooltip(target,content, action) - add a tooltip to an element
|
||||
* RED.popover.menu(options) - create a dropdown menu
|
||||
* RED.popover.panel(content) - create a dropdown container element
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* RED.popover.create(options)
|
||||
*
|
||||
* options
|
||||
* - target : DOM element - the element to target with the popover
|
||||
* - direction : string - position of the popover relative to target
|
||||
* 'top', 'right'(default), 'bottom', 'left', 'inset-[top,right,bottom,left]'
|
||||
* - trigger : string - what triggers the popover to be displayed
|
||||
* 'hover' - display when hovering the target
|
||||
* 'click' - display when target is clicked
|
||||
* 'modal' - hmm not sure, need to find where we use that mode
|
||||
* - content : string|function - contents of the popover. If a string, handled
|
||||
* as raw HTML, so take care.
|
||||
* If a function, can return a String to be added
|
||||
* as text (not HTML), or a DOM element to append
|
||||
* - delay : object - sets show/hide delays after mouseover/out events
|
||||
* { show: 750, hide: 50 }
|
||||
* - autoClose : number - delay before closing the popover in some cases
|
||||
* if trigger is click - delay after mouseout
|
||||
* else if trigger not hover/modal - delay after showing
|
||||
* - width : number - width of popover, default 'auto'
|
||||
* - maxWidth : number - max width of popover, default 'auto'
|
||||
* - size : string - scale of popover. 'default', 'small'
|
||||
* - offset : number - px offset from target
|
||||
* - tooltip : boolean - if true, clicking on popover closes it
|
||||
* - class : string - optional css class to apply to popover
|
||||
* - interactive : if trigger is 'hover' and this is set to true, allow the mouse
|
||||
* to move over the popover without hiding it.
|
||||
*
|
||||
* Returns the popover object with the following properties/functions:
|
||||
* properties:
|
||||
* - element : DOM element - the popover dom element
|
||||
* functions:
|
||||
* - setContent(content) - change the popover content. This only works if the
|
||||
* popover is not currently displayed. It does not
|
||||
* change the content of a visible popover.
|
||||
* - open(instant) - show the popover. If 'instant' is true, don't fade in
|
||||
* - close(instant) - hide the popover. If 'instant' is true, don't fade out
|
||||
* - move(options) - move the popover. The options parameter can take many
|
||||
* of the options detailed above including:
|
||||
* target,direction,content,width,offset
|
||||
* Other settings probably won't work because we haven't needed to change them
|
||||
*/
|
||||
|
||||
/*
|
||||
* RED.popover.tooltip(target,content, action)
|
||||
*
|
||||
* - target : DOM element - the element to apply the tooltip to
|
||||
* - content : string - the text of the tooltip
|
||||
* - action : string - *optional* the name of an Action this tooltip is tied to
|
||||
* For example, it 'target' is a button that triggers a particular action.
|
||||
* The tooltip will include the keyboard shortcut for the action
|
||||
* if one is defined
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* RED.popover.menu(options)
|
||||
*
|
||||
* options
|
||||
* - options : array - list of menu options - see below for format
|
||||
* - width : number - width of the menu. Default: 'auto'
|
||||
* - class : string - class to apply to the menu container
|
||||
* - maxHeight : number - maximum height of menu before scrolling items. Default: none
|
||||
* - onselect : function(item) - called when a menu item is selected, if that item doesn't
|
||||
* have its own onselect function
|
||||
* - onclose : function(cancelled) - called when the menu is closed
|
||||
* - disposeOnClose : boolean - by default, the menu is discarded when it closes
|
||||
* and mustbe rebuilt to redisplay. Setting this to 'false'
|
||||
* keeps the menu on the DOM so it can be shown again.
|
||||
*
|
||||
* Menu Options array:
|
||||
* [
|
||||
* label : string|DOM element - the label of the item. Can be custom DOM element
|
||||
* onselect : function - called when the item is selected
|
||||
* ]
|
||||
*
|
||||
* Returns the menu object with the following functions:
|
||||
*
|
||||
* - options([menuItems]) - if menuItems is undefined, returns the current items.
|
||||
* otherwise, sets the current menu items
|
||||
* - show(opts) - shows the menu. `opts` is an object of options. See RED.popover.panel.show(opts)
|
||||
* for the full list of options. In most scenarios, this just needs:
|
||||
* - target : DOM element - the element to display the menu below
|
||||
* - hide(cancelled) - hide the menu
|
||||
*/
|
||||
|
||||
/*
|
||||
* RED.popover.panel(content)
|
||||
* Create a UI panel that can be displayed relative to any target element.
|
||||
* Handles auto-closing when mouse clicks outside the panel
|
||||
*
|
||||
* - 'content' - DOM element to display in the panel
|
||||
*
|
||||
* Returns the panel object with the following functions:
|
||||
*
|
||||
* properties:
|
||||
* - container : DOM element - the panel element
|
||||
*
|
||||
* functions:
|
||||
* - show(opts) - show the panel.
|
||||
* opts:
|
||||
* - onclose : function - called when the panel closes
|
||||
* - closeButton : DOM element - if the panel is closeable by a click of a button,
|
||||
* by providing a reference to it here, we can
|
||||
* handle the events properly to hide the panel
|
||||
* - target : DOM element - the element to display the panel relative to
|
||||
* - align : string - should the panel align to the left or right edge of target
|
||||
* default: 'right'
|
||||
* - offset : Array - px offset to apply from the target. [width, height]
|
||||
* - dispose : boolean - whether the panel should be removed from DOM when hidden
|
||||
* default: true
|
||||
* - hide(dispose) - hide the panel.
|
||||
*/
|
||||
|
||||
RED.popover = (function() {
|
||||
var deltaSizes = {
|
||||
"default": {
|
||||
top: 10,
|
||||
topTop: 30,
|
||||
leftRight: 17,
|
||||
leftLeft: 25,
|
||||
leftBottom: 8,
|
||||
leftTop: 11
|
||||
x: 12,
|
||||
y: 12
|
||||
},
|
||||
"small": {
|
||||
top: 6,
|
||||
topTop: 20,
|
||||
leftRight: 8,
|
||||
leftLeft: 26,
|
||||
leftBottom: 8,
|
||||
leftTop: 9
|
||||
x:8,
|
||||
y:8
|
||||
}
|
||||
}
|
||||
function createPopover(options) {
|
||||
@@ -41,7 +155,9 @@ RED.popover = (function() {
|
||||
var delay = options.delay || { show: 750, hide: 50 };
|
||||
var autoClose = options.autoClose;
|
||||
var width = options.width||"auto";
|
||||
var maxWidth = options.maxWidth;
|
||||
var size = options.size||"default";
|
||||
var popupOffset = options.offset || 0;
|
||||
if (!deltaSizes[size]) {
|
||||
throw new Error("Invalid RED.popover size value:",size);
|
||||
}
|
||||
@@ -49,6 +165,8 @@ RED.popover = (function() {
|
||||
var timer = null;
|
||||
var active;
|
||||
var div;
|
||||
var contentDiv;
|
||||
var currentStyle;
|
||||
|
||||
var openPopup = function(instant) {
|
||||
if (active) {
|
||||
@@ -58,6 +176,10 @@ RED.popover = (function() {
|
||||
return;
|
||||
}
|
||||
div = $('<div class="red-ui-popover"></div>');
|
||||
if (options.class) {
|
||||
div.addClass(options.class);
|
||||
}
|
||||
contentDiv = $('<div class="red-ui-popover-content">').appendTo(div);
|
||||
if (size !== "default") {
|
||||
div.addClass("red-ui-popover-size-"+size);
|
||||
}
|
||||
@@ -67,71 +189,23 @@ RED.popover = (function() {
|
||||
return;
|
||||
}
|
||||
if (typeof result === 'string') {
|
||||
div.text(result);
|
||||
contentDiv.text(result);
|
||||
} else {
|
||||
div.append(result);
|
||||
contentDiv.append(result);
|
||||
}
|
||||
} else {
|
||||
div.html(content);
|
||||
}
|
||||
if (width !== "auto") {
|
||||
div.width(width);
|
||||
contentDiv.html(content);
|
||||
}
|
||||
div.appendTo("body");
|
||||
|
||||
var targetPos = target.offset();
|
||||
var targetWidth = target.outerWidth();
|
||||
var targetHeight = target.outerHeight();
|
||||
var divHeight = div.height();
|
||||
var divWidth = div.width();
|
||||
var paddingRight = 10;
|
||||
movePopup({target,direction,width,maxWidth});
|
||||
|
||||
var viewportTop = $(window).scrollTop();
|
||||
var viewportLeft = $(window).scrollLeft();
|
||||
var viewportBottom = viewportTop + $(window).height();
|
||||
var viewportRight = viewportLeft + $(window).width();
|
||||
var top = 0;
|
||||
var left = 0;
|
||||
var d = direction;
|
||||
if (d === 'right') {
|
||||
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
|
||||
left = targetPos.left+targetWidth+deltaSizes[size].leftRight;
|
||||
} else if (d === 'left') {
|
||||
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
|
||||
left = targetPos.left-deltaSizes[size].leftLeft-divWidth;
|
||||
} else if (d === 'bottom') {
|
||||
top = targetPos.top+targetHeight+deltaSizes[size].top;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom;
|
||||
if (left < 0) {
|
||||
d = "right";
|
||||
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
|
||||
left = targetPos.left+targetWidth+deltaSizes[size].leftRight;
|
||||
} else if (left+divWidth+paddingRight > viewportRight) {
|
||||
d = "left";
|
||||
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
|
||||
left = targetPos.left-deltaSizes[size].leftLeft-divWidth;
|
||||
if (top+divHeight+targetHeight/2 + 5 > viewportBottom) {
|
||||
top -= (top+divHeight+targetHeight/2 - viewportBottom + 5)
|
||||
}
|
||||
} else if (top+divHeight > viewportBottom) {
|
||||
d = 'top';
|
||||
top = targetPos.top-deltaSizes[size].topTop-divHeight;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftTop;
|
||||
}
|
||||
} else if (d === 'top') {
|
||||
top = targetPos.top-deltaSizes[size].topTop-divHeight;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftTop;
|
||||
if (top < 0) {
|
||||
d = 'bottom';
|
||||
top = targetPos.top+targetHeight+deltaSizes[size].top;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom;
|
||||
}
|
||||
}
|
||||
div.addClass('red-ui-popover-'+d).css({top: top, left: left});
|
||||
if (existingPopover) {
|
||||
existingPopover.close(true);
|
||||
}
|
||||
target.data("red-ui-popover",res)
|
||||
if (options.trigger !== 'manual') {
|
||||
target.data("red-ui-popover",res)
|
||||
}
|
||||
if (options.tooltip) {
|
||||
div.on("mousedown", function(evt) {
|
||||
closePopup(true);
|
||||
@@ -161,6 +235,104 @@ RED.popover = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
var movePopup = function(options) {
|
||||
target = options.target || target;
|
||||
direction = options.direction || direction || "right";
|
||||
popupOffset = options.offset || popupOffset;
|
||||
var transition = options.transition;
|
||||
|
||||
var width = options.width||"auto";
|
||||
div.width(width);
|
||||
if (options.maxWidth) {
|
||||
div.css("max-width",options.maxWidth)
|
||||
} else {
|
||||
div.css("max-width", 'auto');
|
||||
}
|
||||
|
||||
var targetPos = target[0].getBoundingClientRect();
|
||||
var targetHeight = targetPos.height;
|
||||
var targetWidth = targetPos.width;
|
||||
|
||||
var divHeight = div.outerHeight();
|
||||
var divWidth = div.outerWidth();
|
||||
var paddingRight = 10;
|
||||
|
||||
var viewportTop = $(window).scrollTop();
|
||||
var viewportLeft = $(window).scrollLeft();
|
||||
var viewportBottom = viewportTop + $(window).height();
|
||||
var viewportRight = viewportLeft + $(window).width();
|
||||
var top = 0;
|
||||
var left = 0;
|
||||
if (direction === 'right') {
|
||||
top = targetPos.top+targetHeight/2-divHeight/2;
|
||||
left = targetPos.left+targetWidth+deltaSizes[size].x+popupOffset;
|
||||
} else if (direction === 'left') {
|
||||
top = targetPos.top+targetHeight/2-divHeight/2;
|
||||
left = targetPos.left-deltaSizes[size].x-divWidth-popupOffset;
|
||||
} else if (direction === 'bottom') {
|
||||
top = targetPos.top+targetHeight+deltaSizes[size].y+popupOffset;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2;
|
||||
if (left < 0) {
|
||||
direction = "right";
|
||||
top = targetPos.top+targetHeight/2-divHeight/2;
|
||||
left = targetPos.left+targetWidth+deltaSizes[size].x+popupOffset;
|
||||
} else if (left+divWidth+paddingRight > viewportRight) {
|
||||
direction = "left";
|
||||
top = targetPos.top+targetHeight/2-divHeight/2;
|
||||
left = targetPos.left-deltaSizes[size].x-divWidth-popupOffset;
|
||||
if (top+divHeight+targetHeight/2 + 5 > viewportBottom) {
|
||||
top -= (top+divHeight+targetHeight/2 - viewportBottom + 5)
|
||||
}
|
||||
} else if (top+divHeight > viewportBottom) {
|
||||
direction = 'top';
|
||||
top = targetPos.top-deltaSizes[size].y-divHeight-popupOffset;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2;
|
||||
}
|
||||
} else if (direction === 'top') {
|
||||
top = targetPos.top-deltaSizes[size].y-divHeight-popupOffset;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2;
|
||||
if (top < 0) {
|
||||
direction = 'bottom';
|
||||
top = targetPos.top+targetHeight+deltaSizes[size].y+popupOffset;
|
||||
left = targetPos.left+targetWidth/2-divWidth/2;
|
||||
}
|
||||
} else if (/inset/.test(direction)) {
|
||||
top = targetPos.top + targetHeight/2 - divHeight/2;
|
||||
left = targetPos.left + targetWidth/2 - divWidth/2;
|
||||
|
||||
if (/bottom/.test(direction)) {
|
||||
top = targetPos.top + targetHeight - divHeight-popupOffset;
|
||||
}
|
||||
if (/top/.test(direction)) {
|
||||
top = targetPos.top+popupOffset;
|
||||
}
|
||||
if (/left/.test(direction)) {
|
||||
left = targetPos.left+popupOffset;
|
||||
}
|
||||
if (/right/.test(direction)) {
|
||||
left = targetPos.left + targetWidth - divWidth-popupOffset;
|
||||
}
|
||||
}
|
||||
if (currentStyle) {
|
||||
div.removeClass(currentStyle);
|
||||
}
|
||||
if (transition) {
|
||||
div.css({
|
||||
"transition": "0.6s ease",
|
||||
"transition-property": "top,left,right,bottom"
|
||||
})
|
||||
}
|
||||
currentStyle = 'red-ui-popover-'+direction;
|
||||
div.addClass(currentStyle).css({top: top, left: left});
|
||||
if (transition) {
|
||||
setTimeout(function() {
|
||||
div.css({
|
||||
"transition": "none"
|
||||
});
|
||||
},600);
|
||||
}
|
||||
|
||||
}
|
||||
var closePopup = function(instant) {
|
||||
$(document).off('mousedown.red-ui-popover');
|
||||
if (!active) {
|
||||
@@ -178,6 +350,16 @@ RED.popover = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
target.on("remove", function (ev) {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
if (active) {
|
||||
active = false;
|
||||
setTimeout(closePopup,delay.hide);
|
||||
}
|
||||
});
|
||||
|
||||
if (trigger === 'hover') {
|
||||
target.on('mouseenter',function(e) {
|
||||
clearTimeout(timer);
|
||||
@@ -236,8 +418,10 @@ RED.popover = (function() {
|
||||
},autoClose);
|
||||
}
|
||||
var res = {
|
||||
get element() { return div },
|
||||
setContent: function(_content) {
|
||||
content = _content;
|
||||
|
||||
return res;
|
||||
},
|
||||
open: function (instant) {
|
||||
@@ -249,6 +433,10 @@ RED.popover = (function() {
|
||||
active = false;
|
||||
closePopup(instant);
|
||||
return res;
|
||||
},
|
||||
move: function(options) {
|
||||
movePopup(options);
|
||||
return
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@@ -258,18 +446,17 @@ RED.popover = (function() {
|
||||
return {
|
||||
create: createPopover,
|
||||
tooltip: function(target,content, action) {
|
||||
var label = content;
|
||||
if (action) {
|
||||
label = function() {
|
||||
var label = content;
|
||||
var label = function() {
|
||||
var label = content;
|
||||
if (action) {
|
||||
var shortcut = RED.keyboard.getShortcut(action);
|
||||
if (shortcut && shortcut.key) {
|
||||
label = $('<span>'+content+' <span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span></span>');
|
||||
}
|
||||
return label;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
return RED.popover.create({
|
||||
var popover = RED.popover.create({
|
||||
tooltip: true,
|
||||
target:target,
|
||||
trigger: "hover",
|
||||
@@ -278,6 +465,19 @@ RED.popover = (function() {
|
||||
content: label,
|
||||
delay: { show: 750, hide: 50 }
|
||||
});
|
||||
popover.setContent = function(newContent) {
|
||||
content = newContent;
|
||||
}
|
||||
popover.setAction = function(newAction) {
|
||||
action = newAction;
|
||||
}
|
||||
popover.delete = function() {
|
||||
popover.close(true)
|
||||
target.off("mouseenter");
|
||||
target.off("mouseleave");
|
||||
};
|
||||
return popover;
|
||||
|
||||
},
|
||||
menu: function(options) {
|
||||
var list = $('<ul class="red-ui-menu"></ul>');
|
||||
@@ -286,20 +486,47 @@ RED.popover = (function() {
|
||||
}
|
||||
var menuOptions = options.options || [];
|
||||
var first;
|
||||
menuOptions.forEach(function(opt) {
|
||||
var item = $('<li>').appendTo(list);
|
||||
var link = $('<a href="#"></a>').text(opt.label).appendTo(item);
|
||||
link.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
if (opt.onselect) {
|
||||
opt.onselect();
|
||||
}
|
||||
menu.hide();
|
||||
})
|
||||
if (!first) { first = link}
|
||||
})
|
||||
|
||||
var container = RED.popover.panel(list);
|
||||
if (options.width) {
|
||||
container.container.width(options.width);
|
||||
}
|
||||
if (options.class) {
|
||||
container.container.addClass(options.class);
|
||||
}
|
||||
if (options.maxHeight) {
|
||||
container.container.css({
|
||||
"max-height": options.maxHeight,
|
||||
"overflow-y": 'auto'
|
||||
})
|
||||
}
|
||||
var menu = {
|
||||
options: function(opts) {
|
||||
if (opts === undefined) {
|
||||
return menuOptions
|
||||
}
|
||||
menuOptions = opts || [];
|
||||
list.empty();
|
||||
menuOptions.forEach(function(opt) {
|
||||
var item = $('<li>').appendTo(list);
|
||||
var link = $('<a href="#"></a>').appendTo(item);
|
||||
if (typeof opt.label == "string") {
|
||||
link.text(opt.label)
|
||||
} else if (opt.label){
|
||||
opt.label.appendTo(link);
|
||||
}
|
||||
link.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
if (opt.onselect) {
|
||||
opt.onselect();
|
||||
} else if (options.onselect) {
|
||||
options.onselect(opt);
|
||||
}
|
||||
menu.hide();
|
||||
})
|
||||
if (!first) { first = link}
|
||||
})
|
||||
},
|
||||
show: function(opts) {
|
||||
$(document).on("keydown.red-ui-menu", function(evt) {
|
||||
var currentItem = list.find(":focus").parent();
|
||||
@@ -333,6 +560,11 @@ RED.popover = (function() {
|
||||
// ESCAPE
|
||||
evt.preventDefault();
|
||||
menu.hide(true);
|
||||
} else if (evt.keyCode === 9 && options.tabSelect) {
|
||||
// TAB - with tabSelect enabled
|
||||
evt.preventDefault();
|
||||
currentItem.find("a").trigger("click");
|
||||
|
||||
}
|
||||
evt.stopPropagation();
|
||||
})
|
||||
@@ -352,6 +584,7 @@ RED.popover = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
menu.options(menuOptions);
|
||||
return menu;
|
||||
},
|
||||
panel: function(content) {
|
||||
@@ -377,15 +610,18 @@ RED.popover = (function() {
|
||||
var target = options.target;
|
||||
var align = options.align || "right";
|
||||
var offset = options.offset || [0,0];
|
||||
var xPos = options.x;
|
||||
var yPos = options.y;
|
||||
var isAbsolutePosition = (xPos !== undefined && yPos !== undefined)
|
||||
|
||||
var pos = target.offset();
|
||||
var targetWidth = target.width();
|
||||
var targetHeight = target.height();
|
||||
var pos = isAbsolutePosition?{left:xPos, top: yPos}:target.offset();
|
||||
var targetWidth = isAbsolutePosition?0:target.width();
|
||||
var targetHeight = isAbsolutePosition?0:target.outerHeight();
|
||||
var panelHeight = panel.height();
|
||||
var panelWidth = panel.width();
|
||||
|
||||
var top = (targetHeight+pos.top) + offset[1];
|
||||
if (top+panelHeight > $(window).height()) {
|
||||
if (top+panelHeight-$(document).scrollTop() > $(window).height()) {
|
||||
top -= (top+panelHeight)-$(window).height() + 5;
|
||||
}
|
||||
if (top < 0) {
|
||||
|
||||
@@ -105,8 +105,8 @@
|
||||
}
|
||||
});
|
||||
this.element.on("keydown",function(e) {
|
||||
if (!menuShown && e.keyCode === 40) {
|
||||
//DOWN
|
||||
if (!menuShown && e.keyCode === 40 && $(this).val() === '') {
|
||||
//DOWN (only show menu if search field is emty)
|
||||
showMenu();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -38,6 +38,7 @@ RED.tabs = (function() {
|
||||
if (options.vertical) {
|
||||
wrapper.addClass("red-ui-tabs-vertical");
|
||||
}
|
||||
|
||||
if (options.addButton) {
|
||||
wrapper.addClass("red-ui-tabs-add");
|
||||
var addButton = $('<div class="red-ui-tab-button red-ui-tabs-add"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
|
||||
@@ -75,6 +76,8 @@ RED.tabs = (function() {
|
||||
});
|
||||
}
|
||||
if (options.searchButton) {
|
||||
// This is soft-deprecated as we don't use this in the core anymore
|
||||
// We no use the `menu` option to provide a drop-down list of actions
|
||||
wrapper.addClass("red-ui-tabs-search");
|
||||
var searchButton = $('<div class="red-ui-tab-button red-ui-tabs-search"><a href="#"><i class="fa fa-list-ul"></i></a></div>').appendTo(wrapper);
|
||||
searchButton.find('a').on("click", function(evt) {
|
||||
@@ -94,6 +97,52 @@ RED.tabs = (function() {
|
||||
}
|
||||
|
||||
}
|
||||
if (options.menu) {
|
||||
wrapper.addClass("red-ui-tabs-menu");
|
||||
var menuButton = $('<div class="red-ui-tab-button red-ui-tabs-menu"><a href="#"><i class="fa fa-caret-down"></i></a></div>').appendTo(wrapper);
|
||||
var menuButtonLink = menuButton.find('a')
|
||||
var menuOpen = false;
|
||||
var menu;
|
||||
menuButtonLink.on("click", function(evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
if (menuOpen) {
|
||||
menu.remove();
|
||||
menuOpen = false;
|
||||
return;
|
||||
}
|
||||
menuOpen = true;
|
||||
var menuOptions = [];
|
||||
if (typeof options.searchButton === 'function') {
|
||||
menuOptions = options.menu()
|
||||
} else if (Array.isArray(options.menu)) {
|
||||
menuOptions = options.menu;
|
||||
} else if (typeof options.menu === 'function') {
|
||||
menuOptions = options.menu();
|
||||
}
|
||||
menu = RED.menu.init({options: menuOptions});
|
||||
menu.attr("id",options.id+"-menu");
|
||||
menu.css({
|
||||
position: "absolute"
|
||||
})
|
||||
menu.appendTo("body");
|
||||
var elementPos = menuButton.offset();
|
||||
menu.css({
|
||||
top: (elementPos.top+menuButton.height()-2)+"px",
|
||||
left: (elementPos.left - menu.width() + menuButton.width())+"px"
|
||||
})
|
||||
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
||||
$(document).on("click.red-ui-tabmenu", function(evt) {
|
||||
$(document).off("click.red-ui-tabmenu");
|
||||
menuOpen = false;
|
||||
menu.remove();
|
||||
});
|
||||
menu.show();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
var scrollLeft;
|
||||
var scrollRight;
|
||||
|
||||
@@ -117,9 +166,9 @@ RED.tabs = (function() {
|
||||
}
|
||||
})
|
||||
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
|
||||
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||
scrollLeft.on('mousedown',function(evt) {scrollEventHandler(evt, evt.shiftKey?('-='+scrollContainer.scrollLeft()):'-=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
|
||||
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,evt.shiftKey?('+='+(scrollContainer[0].scrollWidth - scrollContainer.width()-scrollContainer.scrollLeft())):'+=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||
}
|
||||
|
||||
if (options.collapsible) {
|
||||
@@ -337,6 +386,12 @@ RED.tabs = (function() {
|
||||
if (link.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (link.parent().hasClass("hide-tab")) {
|
||||
link.parent().removeClass("hide-tab").removeClass("hide");
|
||||
if (options.onshow) {
|
||||
options.onshow(tabs[link.attr('href').slice(1)])
|
||||
}
|
||||
}
|
||||
if (!link.parent().hasClass("active")) {
|
||||
ul.children().removeClass("active");
|
||||
ul.children().css({"transition": "width 100ms"});
|
||||
@@ -362,13 +417,13 @@ RED.tabs = (function() {
|
||||
}
|
||||
}
|
||||
function activatePreviousTab() {
|
||||
var previous = ul.find("li.active").prev();
|
||||
var previous = findPreviousVisibleTab();
|
||||
if (previous.length > 0) {
|
||||
activateTab(previous.find("a"));
|
||||
}
|
||||
}
|
||||
function activateNextTab() {
|
||||
var next = ul.find("li.active").next();
|
||||
var next = findNextVisibleTab();
|
||||
if (next.length > 0) {
|
||||
activateTab(next.find("a"));
|
||||
}
|
||||
@@ -378,7 +433,9 @@ RED.tabs = (function() {
|
||||
if (options.vertical) {
|
||||
return;
|
||||
}
|
||||
var tabs = ul.find("li.red-ui-tab");
|
||||
var allTabs = ul.find("li.red-ui-tab");
|
||||
var tabs = allTabs.filter(":not(.hide-tab)");
|
||||
var hiddenTabs = allTabs.filter(".hide-tab");
|
||||
var width = wrapper.width();
|
||||
var tabCount = tabs.length;
|
||||
var tabWidth;
|
||||
@@ -446,6 +503,7 @@ RED.tabs = (function() {
|
||||
// }
|
||||
|
||||
tabs.css({width:currentTabWidth});
|
||||
hiddenTabs.css({width:"0px"});
|
||||
if (tabWidth < 50) {
|
||||
// ul.find(".red-ui-tab-close").hide();
|
||||
ul.find(".red-ui-tab-icon").hide();
|
||||
@@ -486,12 +544,19 @@ RED.tabs = (function() {
|
||||
}
|
||||
var li = ul.find("a[href='#"+id+"']").parent();
|
||||
if (li.hasClass("active")) {
|
||||
var tab = li.prev();
|
||||
var tab = findPreviousVisibleTab(li);
|
||||
if (tab.length === 0) {
|
||||
tab = li.next();
|
||||
tab = findNextVisibleTab(li);
|
||||
}
|
||||
if (tab.length > 0) {
|
||||
activateTab(tab.find("a"));
|
||||
} else {
|
||||
if (options.onchange) {
|
||||
options.onchange(null);
|
||||
}
|
||||
}
|
||||
activateTab(tab.find("a"));
|
||||
}
|
||||
|
||||
li.remove();
|
||||
if (tabs[id].pinned) {
|
||||
pinnedTabsCount--;
|
||||
@@ -507,6 +572,75 @@ RED.tabs = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function findPreviousVisibleTab(li) {
|
||||
if (!li) {
|
||||
li = ul.find("li.active");
|
||||
}
|
||||
var previous = li.prev();
|
||||
while(previous.length > 0 && previous.hasClass("hide-tab")) {
|
||||
previous = previous.prev();
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
function findNextVisibleTab(li) {
|
||||
if (!li) {
|
||||
li = ul.find("li.active");
|
||||
}
|
||||
var next = li.next();
|
||||
while(next.length > 0 && next.hasClass("hide-tab")) {
|
||||
next = next.next();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
function showTab(id) {
|
||||
if (tabs[id]) {
|
||||
var li = ul.find("a[href='#"+id+"']").parent();
|
||||
if (li.hasClass("hide-tab")) {
|
||||
li.removeClass("hide-tab").removeClass("hide");
|
||||
if (ul.find("li.red-ui-tab:not(.hide-tab)").length === 1) {
|
||||
activateTab(li.find("a"))
|
||||
}
|
||||
updateTabWidths();
|
||||
if (options.onshow) {
|
||||
options.onshow(tabs[id])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function hideTab(id) {
|
||||
if (tabs[id]) {
|
||||
var li = ul.find("a[href='#"+id+"']").parent();
|
||||
if (!li.hasClass("hide-tab")) {
|
||||
if (li.hasClass("active")) {
|
||||
var tab = findPreviousVisibleTab(li);
|
||||
if (tab.length === 0) {
|
||||
tab = findNextVisibleTab(li);
|
||||
}
|
||||
if (tab.length > 0) {
|
||||
activateTab(tab.find("a"));
|
||||
} else {
|
||||
if (options.onchange) {
|
||||
options.onchange(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
li.removeClass("active");
|
||||
li.one("transitionend", function(evt) {
|
||||
li.addClass("hide");
|
||||
updateTabWidths();
|
||||
if (options.onhide) {
|
||||
options.onhide(tabs[id])
|
||||
}
|
||||
setTimeout(function() {
|
||||
updateScroll()
|
||||
},200)
|
||||
})
|
||||
li.addClass("hide-tab");
|
||||
li.css({width:0})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tabAPI = {
|
||||
addTab: function(tab,targetIndex) {
|
||||
if (options.onselect) {
|
||||
@@ -536,7 +670,7 @@ RED.tabs = (function() {
|
||||
}
|
||||
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
||||
if (tab.icon) {
|
||||
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
||||
$('<i>',{class:"red-ui-tab-icon", style:"mask-image: url("+tab.icon+"); -webkit-mask-image: url("+tab.icon+");"}).appendTo(link);
|
||||
} else if (tab.iconClass) {
|
||||
$('<i>',{class:"red-ui-tab-icon "+tab.iconClass}).appendTo(link);
|
||||
}
|
||||
@@ -663,6 +797,7 @@ RED.tabs = (function() {
|
||||
link.on("click", function(evt) { evt.preventDefault(); })
|
||||
link.on("dblclick", function(evt) { evt.stopPropagation(); evt.preventDefault(); })
|
||||
|
||||
$('<span class="red-ui-tabs-fade"></span>').appendTo(li);
|
||||
|
||||
if (tab.closeable) {
|
||||
li.addClass("red-ui-tabs-closeable")
|
||||
@@ -672,9 +807,19 @@ RED.tabs = (function() {
|
||||
event.preventDefault();
|
||||
removeTab(tab.id);
|
||||
});
|
||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||
}
|
||||
if (tab.hideable) {
|
||||
li.addClass("red-ui-tabs-closeable")
|
||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
|
||||
closeLink.append('<i class="fa fa-eye" />');
|
||||
closeLink.append('<i class="fa fa-eye-slash" />');
|
||||
closeLink.on("click",function(event) {
|
||||
event.preventDefault();
|
||||
hideTab(tab.id);
|
||||
});
|
||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||
}
|
||||
|
||||
$('<span class="red-ui-tabs-fade"></span>').appendTo(li);
|
||||
|
||||
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
|
||||
if (options.onselect) {
|
||||
@@ -682,11 +827,12 @@ RED.tabs = (function() {
|
||||
$('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges);
|
||||
}
|
||||
|
||||
// link.attr("title",tab.label);
|
||||
RED.popover.tooltip(link,function() { return RED.utils.sanitize(tab.label); });
|
||||
|
||||
if (options.onadd) {
|
||||
options.onadd(tab);
|
||||
}
|
||||
link.attr("title",tab.label);
|
||||
if (ul.find("li.red-ui-tab").length == 1) {
|
||||
activateTab(link);
|
||||
}
|
||||
@@ -787,7 +933,7 @@ RED.tabs = (function() {
|
||||
previousTab: activatePreviousTab,
|
||||
resize: updateTabWidths,
|
||||
count: function() {
|
||||
return ul.find("li.red-ui-tab").length;
|
||||
return ul.find("li.red-ui-tab:not(.hide)").length;
|
||||
},
|
||||
activeIndex: function() {
|
||||
return ul.find("li.active").index()
|
||||
@@ -795,14 +941,29 @@ RED.tabs = (function() {
|
||||
contains: function(id) {
|
||||
return ul.find("a[href='#"+id+"']").length > 0;
|
||||
},
|
||||
showTab: showTab,
|
||||
hideTab: hideTab,
|
||||
|
||||
renameTab: function(id,label) {
|
||||
tabs[id].label = label;
|
||||
var tab = ul.find("a[href='#"+id+"']");
|
||||
tab.attr("title",label);
|
||||
tab.find("span.red-ui-text-bidi-aware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label));
|
||||
updateTabWidths();
|
||||
},
|
||||
listTabs: function() {
|
||||
return $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
|
||||
},
|
||||
selection: getSelection,
|
||||
clearSelection: function() {
|
||||
if (options.onselect) {
|
||||
var selection = ul.find("li.red-ui-tab.selected");
|
||||
if (selection.length > 0) {
|
||||
selection.removeClass("selected");
|
||||
selectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
order: function(order) {
|
||||
preferredOrder = order;
|
||||
var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
|
||||
|
||||
@@ -21,9 +21,13 @@
|
||||
* - multi : boolean - if true, .selected will return an array of results
|
||||
* otherwise, returns the first selected item
|
||||
* - sortable: boolean/string - TODO: see editableList
|
||||
* - selectable: boolean - default true - whether individual items can be selected
|
||||
* - rootSortable: boolean - if 'sortable' is set, then setting this to
|
||||
* false, prevents items being sorted to the
|
||||
* top level of the tree
|
||||
* - autoSelect: boolean - default true - triggers item selection when navigating
|
||||
* list by keyboard. If the list has checkboxed items
|
||||
* you probably want to set this to false
|
||||
*
|
||||
* methods:
|
||||
* - data(items) - clears existing items and replaces with new data
|
||||
@@ -41,6 +45,7 @@
|
||||
* sublabel: 'Local', // a sub-label for the item
|
||||
* icon: 'fa fa-rocket', // (optional) icon for the item
|
||||
* checkbox: true/false, // (optional) if present, display checkbox accordingly
|
||||
* radio: 'group-name', // (optional) if present, display radio box - using group-name to set radio group
|
||||
* selected: true/false, // (optional) whether the item is selected or not
|
||||
* children: [] | function(done,item) // (optional) an array of child items, or a function
|
||||
* // that will call the `done` callback with an array
|
||||
@@ -49,6 +54,7 @@
|
||||
* deferBuild: true/false, // don't build any ui elements for the item's children
|
||||
* until it is expanded by the user.
|
||||
* element: // custom dom element to use for the item - ignored if `label` is set
|
||||
* collapsible: true/false, // prevent a parent item from being collapsed. default true.
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
@@ -89,77 +95,100 @@
|
||||
$.widget( "nodered.treeList", {
|
||||
_create: function() {
|
||||
var that = this;
|
||||
|
||||
var autoSelect = true;
|
||||
if (that.options.autoSelect === false) {
|
||||
autoSelect = false;
|
||||
}
|
||||
this.element.addClass('red-ui-treeList');
|
||||
this.element.attr("tabIndex",0);
|
||||
var wrapper = $('<div>',{class:'red-ui-treeList-container'}).appendTo(this.element);
|
||||
this.element.on('keydown', function(evt) {
|
||||
var selected = that._topList.find(".selected").parent().data('data');
|
||||
if (!selected && (evt.keyCode === 40 || evt.keyCode === 38)) {
|
||||
that.select(that._data[0]);
|
||||
var focussed = that._topList.find(".focus").parent().data('data');
|
||||
if (!focussed && (evt.keyCode === 40 || evt.keyCode === 38)) {
|
||||
if (that._data[0]) {
|
||||
if (autoSelect) {
|
||||
that.select(that._data[0]);
|
||||
} else {
|
||||
that._topList.find(".focus").removeClass("focus")
|
||||
}
|
||||
that._data[0].treeList.label.addClass('focus')
|
||||
}
|
||||
return;
|
||||
}
|
||||
var target;
|
||||
switch(evt.keyCode) {
|
||||
case 32: // SPACE
|
||||
case 13: // ENTER
|
||||
if (!that.options.selectable) { return }
|
||||
if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) {
|
||||
return
|
||||
}
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (selected.children) {
|
||||
if (selected.treeList.container.hasClass("expanded")) {
|
||||
selected.treeList.collapse()
|
||||
if (focussed.checkbox) {
|
||||
focussed.treeList.checkbox.trigger("click");
|
||||
} else if (focussed.radio) {
|
||||
focussed.treeList.radio.trigger("click");
|
||||
} else if (focussed.children) {
|
||||
if (focussed.treeList.container.hasClass("expanded")) {
|
||||
focussed.treeList.collapse()
|
||||
} else {
|
||||
selected.treeList.expand()
|
||||
focussed.treeList.expand()
|
||||
}
|
||||
} else {
|
||||
that._trigger("confirm",null,selected)
|
||||
that._trigger("confirm",null,focussed)
|
||||
}
|
||||
|
||||
break;
|
||||
case 37: // LEFT
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (selected.children&& selected.treeList.container.hasClass("expanded")) {
|
||||
selected.treeList.collapse()
|
||||
} else if (selected.parent) {
|
||||
target = selected.parent;
|
||||
if (focussed.children&& focussed.treeList.container.hasClass("expanded")) {
|
||||
focussed.treeList.collapse()
|
||||
} else if (focussed.parent) {
|
||||
target = focussed.parent;
|
||||
}
|
||||
break;
|
||||
case 38: // UP
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
target = that._getPreviousSibling(selected);
|
||||
target = that._getPreviousSibling(focussed);
|
||||
if (target) {
|
||||
target = that._getLastDescendant(target);
|
||||
}
|
||||
if (!target && selected.parent) {
|
||||
target = selected.parent;
|
||||
if (!target && focussed.parent) {
|
||||
target = focussed.parent;
|
||||
}
|
||||
break;
|
||||
case 39: // RIGHT
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (selected.children) {
|
||||
if (!selected.treeList.container.hasClass("expanded")) {
|
||||
selected.treeList.expand()
|
||||
if (focussed.children) {
|
||||
if (!focussed.treeList.container.hasClass("expanded")) {
|
||||
focussed.treeList.expand()
|
||||
}
|
||||
}
|
||||
break
|
||||
case 40: //DOWN
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) {
|
||||
target = selected.children[0];
|
||||
if (focussed.children && Array.isArray(focussed.children) && focussed.children.length > 0 && focussed.treeList.container.hasClass("expanded")) {
|
||||
target = focussed.children[0];
|
||||
} else {
|
||||
target = that._getNextSibling(selected);
|
||||
while (!target && selected.parent) {
|
||||
selected = selected.parent;
|
||||
target = that._getNextSibling(selected);
|
||||
target = that._getNextSibling(focussed);
|
||||
while (!target && focussed.parent) {
|
||||
focussed = focussed.parent;
|
||||
target = that._getNextSibling(focussed);
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
if (target) {
|
||||
that.select(target);
|
||||
if (autoSelect) {
|
||||
that.select(target);
|
||||
} else {
|
||||
that._topList.find(".focus").removeClass("focus")
|
||||
}
|
||||
target.treeList.label.addClass('focus')
|
||||
}
|
||||
});
|
||||
this._data = [];
|
||||
@@ -313,7 +342,7 @@
|
||||
if (child.depth !== parent.depth+1) {
|
||||
child.depth = parent.depth+1;
|
||||
// var labelPaddingWidth = ((child.gutter ? child.gutter[0].offsetWidth + 2 : 0) + (child.depth * 20));
|
||||
var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20));
|
||||
var labelPaddingWidth = (((child.gutter&&!child.gutter.hasClass("red-ui-treeList-gutter-float"))?child.gutter.width()+2:0)+(child.depth*20));
|
||||
child.treeList.labelPadding.width(labelPaddingWidth+'px');
|
||||
if (child.element) {
|
||||
$(child.element).css({
|
||||
@@ -462,6 +491,9 @@
|
||||
container.addClass("expanded");
|
||||
}
|
||||
item.treeList.collapse = function() {
|
||||
if (item.collapsible === false) {
|
||||
return
|
||||
}
|
||||
if (!item.children) {
|
||||
return;
|
||||
}
|
||||
@@ -532,10 +564,12 @@
|
||||
}).appendTo(label)
|
||||
|
||||
}
|
||||
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
|
||||
// var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (depth * 20)
|
||||
|
||||
var labelPaddingWidth = ((item.gutter&&!item.gutter.hasClass("red-ui-treeList-gutter-float"))?item.gutter.width()+2:0)+(depth*20);
|
||||
|
||||
item.treeList.labelPadding = $('<span>').css({
|
||||
display: "inline-block",
|
||||
"flex-shrink": 0,
|
||||
width: labelPaddingWidth+'px'
|
||||
}).appendTo(label);
|
||||
|
||||
@@ -581,7 +615,7 @@
|
||||
// Already a parent because we've got the angle-right icon
|
||||
return;
|
||||
}
|
||||
$('<i class="fa fa-angle-right" />').appendTo(treeListIcon);
|
||||
$('<i class="fa fa-angle-right" />').toggleClass("hide",item.collapsible === false).appendTo(treeListIcon);
|
||||
treeListIcon.on("click.red-ui-treeList-expand", function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
@@ -632,6 +666,46 @@
|
||||
label.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
cb.trigger("click");
|
||||
that._topList.find(".focus").removeClass("focus")
|
||||
label.addClass('focus')
|
||||
})
|
||||
}
|
||||
item.treeList.select = function(v) {
|
||||
if (v !== item.selected) {
|
||||
cb.trigger("click");
|
||||
}
|
||||
}
|
||||
item.treeList.checkbox = cb;
|
||||
selectWrapper.appendTo(label)
|
||||
} else if (item.radio) {
|
||||
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>');
|
||||
var cb = $('<input class="red-ui-treeList-radio" type="radio">').prop('name', item.radio).prop('checked',item.selected).appendTo(selectWrapper);
|
||||
cb.on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
cb.on('change', function(e) {
|
||||
item.selected = this.checked;
|
||||
that._selected.forEach(function(selectedItem) {
|
||||
if (selectedItem.radio === item.radio) {
|
||||
selectedItem.treeList.label.removeClass("selected");
|
||||
selectedItem.selected = false;
|
||||
that._selected.delete(selectedItem);
|
||||
}
|
||||
})
|
||||
if (item.selected) {
|
||||
that._selected.add(item);
|
||||
} else {
|
||||
that._selected.delete(item);
|
||||
}
|
||||
label.toggleClass("selected",this.checked);
|
||||
that._trigger("select",e,item);
|
||||
})
|
||||
if (!item.children) {
|
||||
label.on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
cb.trigger("click");
|
||||
that._topList.find(".focus").removeClass("focus")
|
||||
label.addClass('focus')
|
||||
})
|
||||
}
|
||||
item.treeList.select = function(v) {
|
||||
@@ -640,6 +714,7 @@
|
||||
}
|
||||
}
|
||||
selectWrapper.appendTo(label)
|
||||
item.treeList.radio = cb;
|
||||
} else {
|
||||
label.on("click", function(e) {
|
||||
if (!that.options.multi) {
|
||||
@@ -647,10 +722,14 @@
|
||||
}
|
||||
label.addClass("selected");
|
||||
that._selected.add(item);
|
||||
that._topList.find(".focus").removeClass("focus")
|
||||
label.addClass('focus')
|
||||
|
||||
that._trigger("select",e,item)
|
||||
})
|
||||
label.on("dblclick", function(e) {
|
||||
that._topList.find(".focus").removeClass("focus")
|
||||
label.addClass('focus')
|
||||
if (!item.children) {
|
||||
that._trigger("confirm",e,item);
|
||||
}
|
||||
@@ -798,6 +877,9 @@
|
||||
if (item.treeList.label) {
|
||||
item.treeList.label.addClass("selected");
|
||||
}
|
||||
|
||||
that._topList.find(".focus").removeClass("focus");
|
||||
|
||||
if (triggerEvent !== false) {
|
||||
this._trigger("select",null,item)
|
||||
}
|
||||
@@ -805,6 +887,9 @@
|
||||
clearSelection: function() {
|
||||
this._selected.forEach(function(item) {
|
||||
item.selected = false;
|
||||
if (item.treeList.checkbox) {
|
||||
item.treeList.checkbox.prop('checked',false)
|
||||
}
|
||||
if (item.treeList.label) {
|
||||
item.treeList.label.removeClass("selected")
|
||||
}
|
||||
|
||||
@@ -53,8 +53,120 @@
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
var autoComplete = function(options) {
|
||||
function getMatch(value, searchValue) {
|
||||
const idx = value.toLowerCase().indexOf(searchValue.toLowerCase());
|
||||
const len = idx > -1 ? searchValue.length : 0;
|
||||
return {
|
||||
index: idx,
|
||||
found: idx > -1,
|
||||
pre: value.substring(0,idx),
|
||||
match: value.substring(idx,idx+len),
|
||||
post: value.substring(idx+len),
|
||||
}
|
||||
}
|
||||
function generateSpans(match) {
|
||||
const els = [];
|
||||
if(match.pre) { els.push($('<span/>').text(match.pre)); }
|
||||
if(match.match) { els.push($('<span/>',{style:"font-weight: bold; color: var(--red-ui-text-color-link);"}).text(match.match)); }
|
||||
if(match.post) { els.push($('<span/>').text(match.post)); }
|
||||
return els;
|
||||
}
|
||||
return function(val) {
|
||||
var matches = [];
|
||||
options.forEach(opt => {
|
||||
const optVal = opt.value;
|
||||
const optSrc = (opt.source||[]).join(",");
|
||||
const valMatch = getMatch(optVal, val);
|
||||
const srcMatch = getMatch(optSrc, val);
|
||||
if (valMatch.found || srcMatch.found) {
|
||||
const element = $('<div>',{style: "display: flex"});
|
||||
const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
|
||||
valEl.append(generateSpans(valMatch));
|
||||
valEl.appendTo(element);
|
||||
if (optSrc) {
|
||||
const optEl = $('<div>').css({ "font-size": "0.8em" });
|
||||
optEl.append(generateSpans(srcMatch));
|
||||
optEl.appendTo(element);
|
||||
}
|
||||
matches.push({
|
||||
value: optVal,
|
||||
label: element,
|
||||
i: (valMatch.found ? valMatch.index : srcMatch.index)
|
||||
});
|
||||
}
|
||||
})
|
||||
matches.sort(function(A,B){return A.i-B.i})
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a hand-generated list of completions for the core nodes (based on the node help html).
|
||||
var msgCompletions = [
|
||||
{ value: "payload" },
|
||||
{ value: "topic", source: ["mqtt","inject","rbe"] },
|
||||
{ value: "action", source: ["mqtt"] },
|
||||
{ value: "complete", source: ["join"] },
|
||||
{ value: "contentType", source: ["mqtt"] },
|
||||
{ value: "cookies", source: ["http request","http response"] },
|
||||
{ value: "correlationData", source: ["mqtt"] },
|
||||
{ value: "delay", source: ["delay","trigger"] },
|
||||
{ value: "encoding", source: ["file"] },
|
||||
{ value: "error", source: ["catch"] },
|
||||
{ value: "error.message", source: ["catch"] },
|
||||
{ value: "error.source", source: ["catch"] },
|
||||
{ value: "error.source.id", source: ["catch"] },
|
||||
{ value: "error.source.type", source: ["catch"] },
|
||||
{ value: "error.source.name", source: ["catch"] },
|
||||
{ value: "filename", source: ["file","file in"] },
|
||||
{ value: "flush", source: ["delay"] },
|
||||
{ value: "followRedirects", source: ["http request"] },
|
||||
{ value: "headers", source: ["http response","http request"] },
|
||||
{ value: "host", source: ["tcp request","http request"] },
|
||||
{ value: "ip", source: ["udp out"] },
|
||||
{ value: "kill", source: ["exec"] },
|
||||
{ value: "messageExpiryInterval", source: ["mqtt"] },
|
||||
{ value: "method", source: ["http request"] },
|
||||
{ value: "options", source: ["xml"] },
|
||||
{ value: "parts", source: ["split","join","batch","sort"] },
|
||||
{ value: "pid", source: ["exec"] },
|
||||
{ value: "port", source: ["tcp request"," udp out"] },
|
||||
{ value: "qos", source: ["mqtt"] },
|
||||
{ value: "rate", source: ["delay"] },
|
||||
{ value: "rejectUnauthorized", source: ["http request"] },
|
||||
{ value: "req", source: ["http in"]},
|
||||
{ value: "req.body", source: ["http in"]},
|
||||
{ value: "req.headers", source: ["http in"]},
|
||||
{ value: "req.query", source: ["http in"]},
|
||||
{ value: "req.params", source: ["http in"]},
|
||||
{ value: "req.cookies", source: ["http in"]},
|
||||
{ value: "req.files", source: ["http in"]},
|
||||
{ value: "requestTimeout", source: ["http request"] },
|
||||
{ value: "reset", source: ["delay","trigger","join","rbe"] },
|
||||
{ value: "responseCookies", source: ["http request"] },
|
||||
{ value: "responseTopic", source: ["mqtt"] },
|
||||
{ value: "responseURL", source: ["http request"] },
|
||||
{ value: "restartTimeout", source: ["join"] },
|
||||
{ value: "retain", source: ["mqtt"] },
|
||||
{ value: "schema", source: ["json"] },
|
||||
{ value: "select", source: ["html"] },
|
||||
{ value: "statusCode", source: ["http response","http request"] },
|
||||
{ value: "status", source: ["status"] },
|
||||
{ value: "status.text", source: ["status"] },
|
||||
{ value: "status.source", source: ["status"] },
|
||||
{ value: "status.source.type", source: ["status"] },
|
||||
{ value: "status.source.id", source: ["status"] },
|
||||
{ value: "status.source.name", source: ["status"] },
|
||||
{ value: "target", source: ["link call"] },
|
||||
{ value: "template", source: ["template"] },
|
||||
{ value: "toFront", source: ["delay"] },
|
||||
{ value: "url", source: ["http request"] },
|
||||
{ value: "userProperties", source: ["mqtt"] },
|
||||
{ value: "_session", source: ["websocket out","tcp out"] },
|
||||
]
|
||||
var allOptions = {
|
||||
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression},
|
||||
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete: autoComplete(msgCompletions)},
|
||||
flow: {value:"flow",label:"flow.",hasValue:true,
|
||||
options:[],
|
||||
validate:RED.utils.validatePropertyExpression,
|
||||
@@ -86,6 +198,8 @@
|
||||
}
|
||||
RED.editor.editJSON({
|
||||
value: value,
|
||||
stateId: RED.editor.generateViewStateId("typedInput", that, "json"),
|
||||
focus: true,
|
||||
complete: function(v) {
|
||||
var value = v;
|
||||
try {
|
||||
@@ -108,6 +222,8 @@
|
||||
var that = this;
|
||||
RED.editor.editExpression({
|
||||
value: this.value().replace(/\t/g,"\n"),
|
||||
stateId: RED.editor.generateViewStateId("typedInput", that, "jsonata"),
|
||||
focus: true,
|
||||
complete: function(v) {
|
||||
that.value(v.replace(/\n/g,"\t"));
|
||||
}
|
||||
@@ -122,6 +238,8 @@
|
||||
var that = this;
|
||||
RED.editor.editBuffer({
|
||||
value: this.value(),
|
||||
stateId: RED.editor.generateViewStateId("typedInput", that, "bin"),
|
||||
focus: true,
|
||||
complete: function(v) {
|
||||
that.value(v);
|
||||
}
|
||||
@@ -265,6 +383,47 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For a type with options, check value is a valid selection
|
||||
// If !opt.multiple, returns the valid option object
|
||||
// if opt.multiple, returns an array of valid option objects
|
||||
// If not valid, returns null;
|
||||
|
||||
function isOptionValueValid(opt, currentVal) {
|
||||
if (!opt.multiple) {
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
op = opt.options[i];
|
||||
if (typeof op === "string" && op === currentVal) {
|
||||
return {value:currentVal}
|
||||
} else if (op.value === currentVal) {
|
||||
return op;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check to see if value is a valid csv of
|
||||
// options.
|
||||
var currentValues = {};
|
||||
var selected = [];
|
||||
currentVal.split(",").forEach(function(v) {
|
||||
if (v) {
|
||||
currentValues[v] = true;
|
||||
}
|
||||
});
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
op = opt.options[i];
|
||||
var val = typeof op === "string" ? op : op.value;
|
||||
if (currentValues.hasOwnProperty(val)) {
|
||||
delete currentValues[val];
|
||||
selected.push(typeof op === "string" ? {value:op} : op.value)
|
||||
}
|
||||
}
|
||||
if (!$.isEmptyObject(currentValues)) {
|
||||
return null;
|
||||
}
|
||||
return selected
|
||||
}
|
||||
}
|
||||
|
||||
var nlsd = false;
|
||||
|
||||
$.widget( "nodered.typedInput", {
|
||||
@@ -298,7 +457,8 @@
|
||||
}
|
||||
nlsd = true;
|
||||
var that = this;
|
||||
|
||||
this.identifier = this.element.attr('id') || "TypedInput-"+Math.floor(Math.random()*100);
|
||||
if (this.options.debug) { console.log(this.identifier,"Create",{defaultType:this.options.default, value:this.element.val()}) }
|
||||
this.disarmClick = false;
|
||||
this.input = $('<input class="red-ui-typedInput-input" type="text"></input>');
|
||||
this.input.insertAfter(this.element);
|
||||
@@ -328,6 +488,8 @@
|
||||
});
|
||||
|
||||
this.defaultInputType = this.input.attr('type');
|
||||
// Used to remember selections per-type to restore them when switching between types
|
||||
this.oldValues = {};
|
||||
|
||||
this.uiSelect.addClass("red-ui-typedInput-container");
|
||||
|
||||
@@ -380,6 +542,9 @@
|
||||
that.element.trigger('paste',evt);
|
||||
});
|
||||
this.input.on('keydown', function(evt) {
|
||||
if (that.typeMap[that.propertyType].autoComplete) {
|
||||
return
|
||||
}
|
||||
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
|
||||
evt.stopPropagation();
|
||||
}
|
||||
@@ -407,9 +572,9 @@
|
||||
// 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="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
|
||||
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
|
||||
RED.popover.tooltip(this.optionSelectLabel,function() {
|
||||
return that.optionValue;
|
||||
});
|
||||
// RED.popover.tooltip(this.optionSelectLabel,function() {
|
||||
// return that.optionValue;
|
||||
// });
|
||||
this.optionSelectTrigger.on("click", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@@ -428,7 +593,9 @@
|
||||
|
||||
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
|
||||
this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton);
|
||||
this.type(this.options.default||this.typeList[0].value);
|
||||
|
||||
this.type(this.typeField.val() || this.options.default||this.typeList[0].value);
|
||||
this.typeChanged = !!this.options.default;
|
||||
}catch(err) {
|
||||
console.log(err.stack);
|
||||
}
|
||||
@@ -508,7 +675,7 @@
|
||||
if (opt.icon.indexOf("<") === 0) {
|
||||
$(opt.icon).prependTo(op);
|
||||
} else if (opt.icon.indexOf("/") !== -1) {
|
||||
$('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px; height: 18px;"}).prependTo(op);
|
||||
$('<i>',{class:"red-ui-typedInput-icon", style:"mask-image: url("+opt.icon+"); -webkit-mask-image: url("+opt.icon+");"}).prependTo(op);
|
||||
} else {
|
||||
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(op);
|
||||
}
|
||||
@@ -579,7 +746,7 @@
|
||||
var height = relativeTo.height();
|
||||
var menuHeight = menu.height();
|
||||
var top = (height+pos.top);
|
||||
if (top+menuHeight > $(window).height()) {
|
||||
if (top+menuHeight-$(document).scrollTop() > $(window).height()) {
|
||||
top -= (top+menuHeight)-$(window).height()+5;
|
||||
}
|
||||
if (top < 0) {
|
||||
@@ -676,6 +843,7 @@
|
||||
var that = this;
|
||||
var currentType = this.type();
|
||||
this.typeMap = {};
|
||||
var firstCall = (this.typeList === undefined);
|
||||
this.typeList = types.map(function(opt) {
|
||||
var result;
|
||||
if (typeof opt === 'string') {
|
||||
@@ -688,8 +856,10 @@
|
||||
});
|
||||
if (this.typeList.length < 2) {
|
||||
this.selectTrigger.attr("tabindex", -1)
|
||||
this.selectTrigger.on("mousedown.red-ui-typedInput-focus-block", function(evt) { evt.preventDefault(); })
|
||||
} else {
|
||||
this.selectTrigger.attr("tabindex", 0)
|
||||
this.selectTrigger.off("mousedown.red-ui-typedInput-focus-block")
|
||||
}
|
||||
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
|
||||
this.selectTrigger.find(".fa-caret-down").toggle(this.typeList.length > 1)
|
||||
@@ -698,10 +868,19 @@
|
||||
}
|
||||
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
|
||||
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
|
||||
this.type(this.typeList[0].value);
|
||||
if (!firstCall) {
|
||||
this.type(this.typeList[0].value);
|
||||
}
|
||||
} else {
|
||||
this.propertyType = null;
|
||||
this.type(currentType);
|
||||
if (!firstCall) {
|
||||
this.type(currentType);
|
||||
}
|
||||
}
|
||||
if (this.typeList.length === 1 && !this.typeList[0].icon && (!this.typeList[0].label || this.typeList[0].showLabel === false)) {
|
||||
this.selectTrigger.hide()
|
||||
} else {
|
||||
this.selectTrigger.show()
|
||||
}
|
||||
},
|
||||
width: function(desiredWidth) {
|
||||
@@ -712,7 +891,10 @@
|
||||
},
|
||||
value: function(value) {
|
||||
var that = this;
|
||||
var opt = this.typeMap[this.propertyType];
|
||||
// If the default type has been set to an invalid type, then on first
|
||||
// creation, the current propertyType will not exist. Default to an
|
||||
// empty object on the assumption the corrent type will be set shortly
|
||||
var opt = this.typeMap[this.propertyType] || {};
|
||||
if (!arguments.length) {
|
||||
var v = this.input.val();
|
||||
if (opt.export) {
|
||||
@@ -720,27 +902,38 @@
|
||||
}
|
||||
return v;
|
||||
} else {
|
||||
if (this.options.debug) { console.log(this.identifier,"----- SET VALUE ------",value) }
|
||||
var selectedOption = [];
|
||||
var valueToCheck = value;
|
||||
if (opt.options) {
|
||||
var checkValues = [value];
|
||||
if (opt.hasValue && opt.parse) {
|
||||
var parts = opt.parse(value);
|
||||
if (this.options.debug) { console.log(this.identifier,"new parse",parts) }
|
||||
value = parts.value;
|
||||
valueToCheck = parts.option || parts.value;
|
||||
}
|
||||
|
||||
var checkValues = [valueToCheck];
|
||||
if (opt.multiple) {
|
||||
selectedOption = [];
|
||||
checkValues = value.split(",");
|
||||
checkValues = valueToCheck.split(",");
|
||||
}
|
||||
checkValues.forEach(function(value) {
|
||||
checkValues.forEach(function(valueToCheck) {
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
var op = opt.options[i];
|
||||
if (typeof op === "string") {
|
||||
if (op === value || op === ""+value) {
|
||||
if (op === valueToCheck || op === ""+valueToCheck) {
|
||||
selectedOption.push(that.activeOptions[op]);
|
||||
break;
|
||||
}
|
||||
} else if (op.value === value) {
|
||||
} else if (op.value === valueToCheck) {
|
||||
selectedOption.push(op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
if (this.options.debug) { console.log(this.identifier,"set value to",value) }
|
||||
|
||||
this.input.val(value);
|
||||
if (!opt.multiple) {
|
||||
if (selectedOption.length === 0) {
|
||||
@@ -765,9 +958,64 @@
|
||||
return this.propertyType;
|
||||
} else {
|
||||
var that = this;
|
||||
if (this.options.debug) { console.log(this.identifier,"----- SET TYPE -----",type) }
|
||||
var previousValue = null;
|
||||
var opt = this.typeMap[type];
|
||||
if (opt && this.propertyType !== type) {
|
||||
// If previousType is !null, then this is a change of the type, rather than the initialisation
|
||||
var previousType = this.typeMap[this.propertyType];
|
||||
previousValue = this.input.val();
|
||||
|
||||
if (previousType && this.typeChanged) {
|
||||
if (this.options.debug) { console.log(this.identifier,"typeChanged",{previousType,previousValue}) }
|
||||
if (previousType.options && opt.hasValue !== true) {
|
||||
this.oldValues[previousType.value] = previousValue;
|
||||
} else if (previousType.hasValue === false) {
|
||||
this.oldValues[previousType.value] = previousValue;
|
||||
} else {
|
||||
this.oldValues["_"] = previousValue;
|
||||
}
|
||||
if ((opt.options && opt.hasValue !== true) || opt.hasValue === false) {
|
||||
if (this.oldValues.hasOwnProperty(opt.value)) {
|
||||
if (this.options.debug) { console.log(this.identifier,"restored previous (1)",this.oldValues[opt.value]) }
|
||||
this.input.val(this.oldValues[opt.value]);
|
||||
} else if (opt.options) {
|
||||
// No old value for the option type.
|
||||
// It is possible code has called 'value' then 'type'
|
||||
// to set the selected option. This is what the Inject/Switch/Change
|
||||
// nodes did before 2.1.
|
||||
// So we need to be careful to not reset the value if it is a valid option.
|
||||
var validOptions = isOptionValueValid(opt,previousValue);
|
||||
if (this.options.debug) { console.log(this.identifier,{previousValue,opt,validOptions}) }
|
||||
if ((previousValue || previousValue === '') && validOptions) {
|
||||
if (this.options.debug) { console.log(this.identifier,"restored previous (2)") }
|
||||
this.input.val(previousValue);
|
||||
} else {
|
||||
if (typeof opt.default === "string") {
|
||||
if (this.options.debug) { console.log(this.identifier,"restored previous (3)",opt.default) }
|
||||
this.input.val(opt.default);
|
||||
} else if (Array.isArray(opt.default)) {
|
||||
if (this.options.debug) { console.log(this.identifier,"restored previous (4)",opt.default.join(",")) }
|
||||
this.input.val(opt.default.join(","))
|
||||
} else {
|
||||
if (this.options.debug) { console.log(this.identifier,"restored previous (5)") }
|
||||
this.input.val("");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.options.debug) { console.log(this.identifier,"restored default/blank",opt.default||"") }
|
||||
this.input.val(opt.default||"")
|
||||
}
|
||||
} else {
|
||||
if (this.options.debug) { console.log(this.identifier,"restored old/default/blank") }
|
||||
this.input.val(this.oldValues.hasOwnProperty("_")?this.oldValues["_"]:(opt.default||""))
|
||||
}
|
||||
if (previousType.autoComplete) {
|
||||
this.input.autoComplete("destroy");
|
||||
}
|
||||
}
|
||||
this.propertyType = type;
|
||||
this.typeChanged = true;
|
||||
if (this.typeField) {
|
||||
this.typeField.val(type);
|
||||
}
|
||||
@@ -778,10 +1026,7 @@
|
||||
$(opt.icon).prependTo(this.selectLabel);
|
||||
}
|
||||
else if (opt.icon.indexOf("/") !== -1) {
|
||||
image = new Image();
|
||||
image.name = opt.icon;
|
||||
image.src = mapDeprecatedIcon(opt.icon);
|
||||
$('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
|
||||
$('<i>',{class:"red-ui-typedInput-icon", style:"mask-image: url("+opt.icon+"); -webkit-mask-image: url("+opt.icon+"); margin-right: 4px;height: 18px;width:13px"}).prependTo(this.selectLabel);
|
||||
}
|
||||
else {
|
||||
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon,style:"min-width: 13px; margin-right: 4px;"}).prependTo(this.selectLabel);
|
||||
@@ -836,22 +1081,12 @@
|
||||
|
||||
var op;
|
||||
if (!opt.hasValue) {
|
||||
var validValue = false;
|
||||
var currentVal = this.input.val();
|
||||
// Check the value is valid for the available options
|
||||
var validValues = isOptionValueValid(opt,this.input.val());
|
||||
if (!opt.multiple) {
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
op = opt.options[i];
|
||||
if (typeof op === "string" && op === currentVal) {
|
||||
that._updateOptionSelectLabel({value:currentVal});
|
||||
validValue = true;
|
||||
break;
|
||||
} else if (op.value === currentVal) {
|
||||
that._updateOptionSelectLabel(op);
|
||||
validValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!validValue) {
|
||||
if (validValues) {
|
||||
that._updateOptionSelectLabel(validValues)
|
||||
} else {
|
||||
op = opt.options[0];
|
||||
if (typeof op === "string") {
|
||||
this.value(op);
|
||||
@@ -862,27 +1097,19 @@
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check to see if value is a valid csv of
|
||||
// options.
|
||||
var currentValues = {};
|
||||
currentVal.split(",").forEach(function(v) {
|
||||
if (v) {
|
||||
currentValues[v] = true;
|
||||
}
|
||||
});
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
op = opt.options[i];
|
||||
delete currentValues[op.value||op];
|
||||
}
|
||||
if (!$.isEmptyObject(currentValues)) {
|
||||
// Invalid, set to default/empty
|
||||
this.value((opt.default||[]).join(","));
|
||||
if (!validValues) {
|
||||
validValues = (opt.default || []).map(function(v) {
|
||||
return typeof v === "string"?v:v.value
|
||||
});
|
||||
this.value(validValues.join(","));
|
||||
}
|
||||
that._updateOptionSelectLabel(validValues);
|
||||
}
|
||||
} else {
|
||||
var selectedOption = this.optionValue||opt.options[0];
|
||||
if (opt.parse) {
|
||||
var parts = opt.parse(this.input.val(),selectedOption);
|
||||
var selectedOptionObj = typeof selectedOption === "string"?{value:selectedOption}:selectedOption
|
||||
var parts = opt.parse(this.input.val(),selectedOptionObj);
|
||||
if (parts.option) {
|
||||
selectedOption = parts.option;
|
||||
if (!this.activeOptions.hasOwnProperty(selectedOption)) {
|
||||
@@ -906,6 +1133,7 @@
|
||||
this._updateOptionSelectLabel(this.activeOptions[selectedOption]);
|
||||
}
|
||||
} else if (selectedOption) {
|
||||
if (this.options.debug) { console.log(this.identifier,"HERE",{optionValue:selectedOption.value}) }
|
||||
this.optionValue = selectedOption.value;
|
||||
this._updateOptionSelectLabel(selectedOption);
|
||||
} else {
|
||||
@@ -938,8 +1166,6 @@
|
||||
this.input.attr('type',this.defaultInputType)
|
||||
}
|
||||
if (opt.hasValue === false) {
|
||||
this.oldValue = this.input.val();
|
||||
this.input.val("");
|
||||
this.elementDiv.hide();
|
||||
this.valueLabelContainer.hide();
|
||||
} else if (opt.valueLabel) {
|
||||
@@ -952,12 +1178,14 @@
|
||||
this.elementDiv.hide();
|
||||
opt.valueLabel.call(this,this.valueLabelContainer,this.input.val());
|
||||
} else {
|
||||
if (this.oldValue !== undefined) {
|
||||
this.input.val(this.oldValue);
|
||||
delete this.oldValue;
|
||||
}
|
||||
this.valueLabelContainer.hide();
|
||||
this.elementDiv.show();
|
||||
if (opt.autoComplete) {
|
||||
this.input.autoComplete({
|
||||
search: opt.autoComplete,
|
||||
minLength: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
if (this.optionExpandButton) {
|
||||
if (opt.expand) {
|
||||
@@ -1042,6 +1270,9 @@
|
||||
},
|
||||
disabled: function() {
|
||||
return this.uiSelect.attr("disabled") === "disabled";
|
||||
},
|
||||
focus: function() {
|
||||
this.input.focus();
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
175
packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js
vendored
Normal file
175
packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
RED.contextMenu = (function() {
|
||||
|
||||
let menu;
|
||||
function createMenu() {
|
||||
// menu = RED.popover.menu({
|
||||
// options: [
|
||||
// {
|
||||
// label: 'delete selection',
|
||||
// onselect: function() {
|
||||
// RED.actions.invoke('core:delete-selection')
|
||||
// RED.view.focus()
|
||||
// }
|
||||
// },
|
||||
// { label: 'world' }
|
||||
// ],
|
||||
// width: 200,
|
||||
// })
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function disposeMenu() {
|
||||
$(document).off("mousedown.red-ui-workspace-context-menu");
|
||||
if (menu) {
|
||||
menu.remove();
|
||||
}
|
||||
menu = null;
|
||||
}
|
||||
function show(options) {
|
||||
if (menu) {
|
||||
menu.remove()
|
||||
}
|
||||
|
||||
const selection = RED.view.selection()
|
||||
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||
const hasLinks = selection.links && selection.links.length > 0;
|
||||
const isSingleLink = !hasSelection && hasLinks && selection.links.length === 1
|
||||
const isMultipleLinks = !hasSelection && hasLinks && selection.links.length > 1
|
||||
const canDelete = hasSelection || hasLinks
|
||||
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
|
||||
|
||||
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
|
||||
|
||||
|
||||
const menuItems = [
|
||||
{ onselect: 'core:show-action-list', onpostselect: function() {} },
|
||||
{
|
||||
label: 'Insert',
|
||||
options: [
|
||||
{
|
||||
label: 'Node',
|
||||
onselect: function() {
|
||||
RED.view.showQuickAddDialog({
|
||||
position: [ options.x - offset.left, options.y - offset.top ],
|
||||
touchTrigger: true,
|
||||
splice: isSingleLink?selection.links[0]:undefined,
|
||||
// spliceMultiple: isMultipleLinks
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Junction',
|
||||
onselect: 'core:split-wires-with-junctions',
|
||||
disabled: hasSelection || !hasLinks
|
||||
},
|
||||
{
|
||||
label: 'Link Nodes',
|
||||
onselect: 'core:split-wire-with-link-nodes',
|
||||
disabled: hasSelection || !hasLinks
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
}
|
||||
]
|
||||
// menuItems.push(
|
||||
// {
|
||||
// label: (isSingleLink || isMultipleLinks)?'Insert into wire...':'Add node...',
|
||||
// onselect: function() {
|
||||
// RED.view.showQuickAddDialog({
|
||||
// position: [ options.x - offset.left, options.y - offset.top ],
|
||||
// touchTrigger: true,
|
||||
// splice: isSingleLink?selection.links[0]:undefined,
|
||||
// spliceMultiple: isMultipleLinks
|
||||
// })
|
||||
// }
|
||||
// },
|
||||
// )
|
||||
// if (hasLinks && !hasSelection) {
|
||||
// menuItems.push({ onselect: 'core:split-wires-with-junctions', label: 'Insert junction'})
|
||||
// }
|
||||
menuItems.push(
|
||||
null,
|
||||
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
|
||||
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
|
||||
null,
|
||||
{ onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection},
|
||||
{ onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection },
|
||||
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() },
|
||||
{ onselect: 'core:delete-selection', disabled: !canDelete },
|
||||
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
|
||||
{ onselect: 'core:select-all-nodes' }
|
||||
)
|
||||
|
||||
if (hasSelection) {
|
||||
menuItems.push(
|
||||
null,
|
||||
isGroup ?
|
||||
{ onselect: 'core:ungroup-selection', disabled: !isGroup }
|
||||
: { onselect: 'core:group-selection', disabled: !hasSelection }
|
||||
)
|
||||
if (canRemoveFromGroup) {
|
||||
menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") })
|
||||
}
|
||||
|
||||
}
|
||||
const offset = $("#red-ui-workspace-chart").offset()
|
||||
menu = RED.menu.init({
|
||||
direction: 'right',
|
||||
onpreselect: function() {
|
||||
disposeMenu()
|
||||
},
|
||||
onpostselect: function() {
|
||||
RED.view.focus()
|
||||
},
|
||||
options: menuItems
|
||||
});
|
||||
|
||||
menu.attr("id","red-ui-workspace-context-menu");
|
||||
menu.css({
|
||||
position: "absolute"
|
||||
})
|
||||
menu.appendTo("body");
|
||||
|
||||
// TODO: prevent the menu from overflowing the window.
|
||||
|
||||
var top = options.y
|
||||
var left = options.x
|
||||
|
||||
if (top+menu.height()-$(document).scrollTop() > $(window).height()) {
|
||||
top -= (top+menu.height())-$(window).height() + 22;
|
||||
}
|
||||
if (left+menu.width()-$(document).scrollLeft() > $(window).width()) {
|
||||
left -= (left+menu.width())-$(window).width() + 18;
|
||||
}
|
||||
menu.css({
|
||||
top: top+"px",
|
||||
left: left+"px"
|
||||
})
|
||||
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
||||
$(document).on("mousedown.red-ui-workspace-context-menu", function(evt) {
|
||||
if (menu && menu[0].contains(evt.target)) {
|
||||
return
|
||||
}
|
||||
disposeMenu()
|
||||
});
|
||||
menu.show();
|
||||
|
||||
// menu.show({
|
||||
// target: $('#red-ui-main-container'),
|
||||
// x: options.x,
|
||||
// y: options.y
|
||||
// })
|
||||
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
show: show
|
||||
}
|
||||
})()
|
||||
@@ -319,192 +319,248 @@ RED.deploy = (function() {
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
function save(skipValidation,force) {
|
||||
if (!$("#red-ui-header-button-deploy").hasClass("disabled")) {
|
||||
if (!RED.user.hasPermission("flows.write")) {
|
||||
RED.notify(RED._("user.errors.deploy"),"error");
|
||||
function save(skipValidation, force) {
|
||||
if ($("#red-ui-header-button-deploy").hasClass("disabled")) {
|
||||
return; //deploy is disabled
|
||||
}
|
||||
if ($("#red-ui-header-shade").is(":visible")) {
|
||||
return; //deploy is shaded
|
||||
}
|
||||
if (!RED.user.hasPermission("flows.write")) {
|
||||
RED.notify(RED._("user.errors.deploy"), "error");
|
||||
return;
|
||||
}
|
||||
let hasUnusedConfig = false;
|
||||
if (!skipValidation) {
|
||||
let hasUnknown = false;
|
||||
let hasInvalid = false;
|
||||
const unknownNodes = [];
|
||||
const invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(function (node) {
|
||||
if (node.valid === undefined) {
|
||||
RED.editor.validateNode(node);
|
||||
}
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.nodes.eachNode(function (node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
hasInvalid = invalidNodes.length > 0;
|
||||
|
||||
const unusedConfigNodes = [];
|
||||
RED.nodes.eachConfig(function (node) {
|
||||
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
|
||||
unusedConfigNodes.push(getNodeInfo(node));
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
let showWarning = false;
|
||||
let notificationMessage;
|
||||
let notificationButtons = [];
|
||||
let notification;
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
notificationMessage = "<p>" + RED._('deploy.confirm.unknown') + "</p>" +
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(unknownNodes).map(function (n) { return sanitize(n) }).join("</li><li>") + "</li></ul><p>" +
|
||||
RED._('deploy.confirm.confirm') +
|
||||
"</p>";
|
||||
|
||||
notificationButtons = [
|
||||
{
|
||||
text: RED._("deploy.unknownNodesButton"),
|
||||
class: "pull-left",
|
||||
click: function() {
|
||||
notification.close();
|
||||
RED.actions.invoke("core:search","type:unknown ");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function () {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
|
||||
notificationMessage = "<p>" + RED._('deploy.confirm.improperlyConfigured') + "</p>" +
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(invalidNodes.map(function (A) { return sanitize((A.tab ? "[" + A.tab + "] " : "") + A.label + " (" + A.type + ")") })).join("</li><li>") + "</li></ul><p>" +
|
||||
RED._('deploy.confirm.confirm') +
|
||||
"</p>";
|
||||
notificationButtons = [
|
||||
{
|
||||
text: RED._("deploy.invalidNodesButton"),
|
||||
class: "pull-left",
|
||||
click: function() {
|
||||
notification.close();
|
||||
RED.actions.invoke("core:search","is:invalid ");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function () {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
if (showWarning) {
|
||||
notificationButtons.unshift(
|
||||
{
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function () {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
notification = RED.notify(notificationMessage, {
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons: notificationButtons
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!skipValidation) {
|
||||
var hasUnknown = false;
|
||||
var hasInvalid = false;
|
||||
var hasUnusedConfig = false;
|
||||
|
||||
var unknownNodes = [];
|
||||
var invalidNodes = [];
|
||||
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
hasInvalid = invalidNodes.length > 0;
|
||||
|
||||
var unusedConfigNodes = [];
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
|
||||
unusedConfigNodes.push(getNodeInfo(node));
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
var showWarning = false;
|
||||
var notificationMessage;
|
||||
var notificationButtons = [];
|
||||
var notification;
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.unknown')+"</p>"+
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(unknownNodes).map(function(n) { return sanitize(n) }).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
|
||||
notificationButtons= [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.improperlyConfigured')+"</p>"+
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(invalidNodes.map(function(A) { return sanitize( (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")")})).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
notificationButtons= [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
if (showWarning) {
|
||||
notificationButtons.unshift(
|
||||
{
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
notification = RED.notify(notificationMessage,{
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons:notificationButtons
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
|
||||
var startTime = Date.now();
|
||||
$(".red-ui-deploy-button-content").css('opacity',0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
|
||||
var data = {flows:nns};
|
||||
|
||||
if (!force) {
|
||||
data.rev = RED.nodes.version();
|
||||
}
|
||||
|
||||
deployInflight = true;
|
||||
$("#red-ui-header-shade").show();
|
||||
$("#red-ui-editor-shade").show();
|
||||
$("#red-ui-palette-shade").show();
|
||||
$("#red-ui-sidebar-shade").show();
|
||||
$.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);
|
||||
RED.nodes.originalFlow(nns);
|
||||
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('<p>'+RED._("deploy.successfulDeploy")+'</p>',"success");
|
||||
}
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if (node.moved) {
|
||||
node.dirty = true;
|
||||
node.moved = false;
|
||||
}
|
||||
if(node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachSubflow(function(subflow) {
|
||||
subflow.changed = false;
|
||||
});
|
||||
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);
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
if (xhr.status === 401) {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
|
||||
} else if (xhr.status === 409) {
|
||||
resolveConflict(nns, true);
|
||||
} 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() {
|
||||
deployInflight = false;
|
||||
var delta = Math.max(0,300-(Date.now()-startTime));
|
||||
setTimeout(function() {
|
||||
$(".red-ui-deploy-button-content").css('opacity',1);
|
||||
$(".red-ui-deploy-button-spinner").hide();
|
||||
$("#red-ui-header-shade").hide();
|
||||
$("#red-ui-editor-shade").hide();
|
||||
$("#red-ui-palette-shade").hide();
|
||||
$("#red-ui-sidebar-shade").hide();
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
|
||||
const nns = RED.nodes.createCompleteNodeSet();
|
||||
const startTime = Date.now();
|
||||
|
||||
$(".red-ui-deploy-button-content").css('opacity', 0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
|
||||
const data = { flows: nns };
|
||||
|
||||
if (!force) {
|
||||
data.rev = RED.nodes.version();
|
||||
}
|
||||
|
||||
deployInflight = true;
|
||||
$("#red-ui-header-shade").show();
|
||||
$("#red-ui-editor-shade").show();
|
||||
$("#red-ui-palette-shade").show();
|
||||
$("#red-ui-sidebar-shade").show();
|
||||
$.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);
|
||||
RED.nodes.originalFlow(nns);
|
||||
if (hasUnusedConfig) {
|
||||
let notification;
|
||||
const opts = {
|
||||
type: "success",
|
||||
fixed: false,
|
||||
timeout: 6000,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._("deploy.unusedConfigNodesButton"),
|
||||
class: "pull-left",
|
||||
click: function() {
|
||||
notification.close();
|
||||
RED.actions.invoke("core:search","is:config is:unused ");
|
||||
}
|
||||
},
|
||||
{
|
||||
text: RED._("common.label.close"),
|
||||
class: "primary",
|
||||
click: function () {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
notification = RED.notify(
|
||||
'<p>' + RED._("deploy.successfulDeploy") + '</p>' +
|
||||
'<p>' + RED._("deploy.unusedConfigNodes") + '</p>', opts);
|
||||
} else {
|
||||
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
|
||||
}
|
||||
RED.nodes.eachNode(function (node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if (node.moved) {
|
||||
node.dirty = true;
|
||||
node.moved = false;
|
||||
}
|
||||
if (node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachSubflow(function (subflow) {
|
||||
subflow.changed = false;
|
||||
});
|
||||
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);
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
if (xhr.status === 401) {
|
||||
RED.notify(RED._("deploy.deployFailed", { message: RED._("user.notAuthorized") }), "error");
|
||||
} else if (xhr.status === 409) {
|
||||
resolveConflict(nns, true);
|
||||
} 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 () {
|
||||
deployInflight = false;
|
||||
const delta = Math.max(0, 300 - (Date.now() - startTime));
|
||||
setTimeout(function () {
|
||||
$(".red-ui-deploy-button-content").css('opacity', 1);
|
||||
$(".red-ui-deploy-button-spinner").hide();
|
||||
$("#red-ui-header-shade").hide();
|
||||
$("#red-ui-editor-shade").hide();
|
||||
$("#red-ui-palette-shade").hide();
|
||||
$("#red-ui-sidebar-shade").hide();
|
||||
}, delta);
|
||||
});
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
|
||||
61
packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js
vendored
Normal file
61
packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
RED.diagnostics = (function () {
|
||||
|
||||
function init() {
|
||||
if (RED.settings.get('diagnostics.ui', true) === false) {
|
||||
return;
|
||||
}
|
||||
RED.actions.add("core:show-system-info", function () { show(); });
|
||||
}
|
||||
|
||||
function show() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
},
|
||||
cache: false,
|
||||
url: 'diagnostics',
|
||||
success: function (data) {
|
||||
var json = JSON.stringify(data || {}, "", 4);
|
||||
if (json === "{}") {
|
||||
json = "{\n\n}";
|
||||
}
|
||||
RED.editor.editJSON({
|
||||
title: RED._('diagnostics.title'),
|
||||
value: json,
|
||||
requireValid: true,
|
||||
readOnly: true,
|
||||
toolbarButtons: [
|
||||
{
|
||||
text: RED._('clipboard.export.copy'),
|
||||
icon: 'fa fa-copy',
|
||||
click: function () {
|
||||
RED.clipboard.copyText(json, $(this), RED._('clipboard.copyMessageValue'))
|
||||
}
|
||||
},
|
||||
{
|
||||
text: RED._('clipboard.download'),
|
||||
icon: 'fa fa-download',
|
||||
click: function () {
|
||||
var element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(json));
|
||||
element.setAttribute('download', "system-info.json");
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
},
|
||||
]
|
||||
});
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
console.log("Unexpected error loading system info:", jqXHR.status, textStatus, errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
};
|
||||
})();
|
||||
@@ -554,6 +554,8 @@ RED.diff = (function() {
|
||||
color: "#DDAA99",
|
||||
defaults:{name:{value:""}}
|
||||
}
|
||||
} else if (node.type === "group") {
|
||||
def = RED.group.def;
|
||||
} else {
|
||||
def = {};
|
||||
}
|
||||
@@ -763,16 +765,15 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (node.hasOwnProperty('x')) {
|
||||
if (localNode) {
|
||||
if (localNode.x !== node.x || localNode.y !== node.y) {
|
||||
if (localNode.x !== node.x || localNode.y !== node.y || localNode.w !== node.w || localNode.h !== node.h ) {
|
||||
localChanged = true;
|
||||
localChanges++;
|
||||
}
|
||||
}
|
||||
if (remoteNode) {
|
||||
if (remoteNode.x !== node.x || remoteNode.y !== node.y) {
|
||||
if (remoteNode.x !== node.x || remoteNode.y !== node.y|| remoteNode.w !== node.w || remoteNode.h !== node.h) {
|
||||
remoteChanged = true;
|
||||
remoteChanges++;
|
||||
}
|
||||
@@ -790,7 +791,12 @@ RED.diff = (function() {
|
||||
localCell.addClass("red-ui-diff-status-"+(localChanged?"changed":"unchanged"));
|
||||
$('<span class="red-ui-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
|
||||
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(localCell);
|
||||
propertyElements['local.position'] = RED.utils.createObjectElement({x:localNode.x,y:localNode.y},
|
||||
var localPosition = {x:localNode.x,y:localNode.y};
|
||||
if (localNode.hasOwnProperty('w')) {
|
||||
localPosition.w = localNode.w;
|
||||
localPosition.h = localNode.h;
|
||||
}
|
||||
propertyElements['local.position'] = RED.utils.createObjectElement(localPosition,
|
||||
{
|
||||
path: "position",
|
||||
exposeApi: true,
|
||||
@@ -811,7 +817,12 @@ RED.diff = (function() {
|
||||
if (remoteNode) {
|
||||
$('<span class="red-ui-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
|
||||
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(remoteCell);
|
||||
propertyElements['remote.position'] = RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y},
|
||||
var remotePosition = {x:remoteNode.x,y:remoteNode.y};
|
||||
if (remoteNode.hasOwnProperty('w')) {
|
||||
remotePosition.w = remoteNode.w;
|
||||
remotePosition.h = remoteNode.h;
|
||||
}
|
||||
propertyElements['remote.position'] = RED.utils.createObjectElement(remotePosition,
|
||||
{
|
||||
path: "position",
|
||||
exposeApi: true,
|
||||
@@ -883,11 +894,11 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
|
||||
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='w'&&p!=='h'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
|
||||
if (def.defaults) {
|
||||
properties = properties.concat(Object.keys(def.defaults));
|
||||
}
|
||||
if (node.type !== 'tab') {
|
||||
if (node.type !== 'tab' && node.type !== "group") {
|
||||
properties = properties.concat(['inputLabels','outputLabels']);
|
||||
}
|
||||
if ( ((localNode && localNode.hasOwnProperty('icon')) || (remoteNode && remoteNode.hasOwnProperty('icon'))) &&
|
||||
@@ -1376,6 +1387,7 @@ RED.diff = (function() {
|
||||
|
||||
function mergeDiff(diff) {
|
||||
//console.log(diff);
|
||||
var selectedTab = RED.workspaces.active();
|
||||
var appliedDiff = applyDiff(diff);
|
||||
|
||||
var newConfig = appliedDiff.config;
|
||||
@@ -1426,6 +1438,7 @@ RED.diff = (function() {
|
||||
RED.view.redraw(true);
|
||||
RED.palette.refresh();
|
||||
RED.workspaces.refresh();
|
||||
RED.workspaces.show(selectedTab, true);
|
||||
RED.sidebar.config.refresh();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,6 +47,7 @@
|
||||
var definition = {
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onCancel = options.cancel;
|
||||
var onComplete = options.complete;
|
||||
var type = "_buffer"
|
||||
if ($("script[data-template-name='"+type+"']").length === 0) {
|
||||
@@ -60,12 +61,14 @@
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
focusElement: options.focusElement,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
if (onCancel) { onCancel(); }
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
@@ -74,7 +77,8 @@
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(JSON.stringify(bufferBinValue));
|
||||
bufferStringEditor.saveView();
|
||||
if (onComplete) { onComplete(JSON.stringify(bufferBinValue),null,bufferStringEditor); }
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
@@ -86,19 +90,20 @@
|
||||
}
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.red-ui-tray-body'),'dialog-form',type,'editor');
|
||||
|
||||
bufferStringEditor = RED.editor.createEditor({
|
||||
id: 'red-ui-editor-type-buffer-str',
|
||||
value: "",
|
||||
value: value||"",
|
||||
stateId: RED.editor.generateViewStateId("buffer", options, ""),
|
||||
focus: true,
|
||||
mode:"ace/mode/text"
|
||||
});
|
||||
bufferStringEditor.getSession().setValue(value||"",-1);
|
||||
|
||||
bufferBinEditor = RED.editor.createEditor({
|
||||
id: 'red-ui-editor-type-buffer-bin',
|
||||
value: "",
|
||||
stateId: false,
|
||||
focus: false,
|
||||
mode:"ace/mode/text",
|
||||
readOnly: true
|
||||
});
|
||||
|
||||
@@ -80,6 +80,9 @@ RED.editor.codeEditor.ace = (function() {
|
||||
}
|
||||
},100);
|
||||
}
|
||||
if (!options.stateId && options.stateId !== false) {
|
||||
options.stateId = RED.editor.generateViewStateId("ace", options, (options.mode || options.title).split("/").pop());
|
||||
}
|
||||
if (options.mode === 'ace/mode/markdown') {
|
||||
$(el).addClass("red-ui-editor-text-container-toolbar");
|
||||
editor.toolbar = RED.editor.customEditTypes['_markdown'].buildToolbar(toolbarRow,editor);
|
||||
@@ -92,11 +95,15 @@ RED.editor.codeEditor.ace = (function() {
|
||||
RED.editor.editMarkdown({
|
||||
value: value,
|
||||
width: "Infinity",
|
||||
cursor: editor.getCursorPosition(),
|
||||
stateId: options.stateId,
|
||||
focus: true,
|
||||
cancel: function () {
|
||||
editor.focus();
|
||||
},
|
||||
complete: function(v,cursor) {
|
||||
editor.setValue(v, -1);
|
||||
editor.gotoLine(cursor.row+1,cursor.column,false);
|
||||
setTimeout(function() {
|
||||
editor.restoreView();
|
||||
editor.focus();
|
||||
},300);
|
||||
}
|
||||
@@ -117,11 +124,56 @@ RED.editor.codeEditor.ace = (function() {
|
||||
editor._destroy = editor.destroy;
|
||||
editor.destroy = function() {
|
||||
try {
|
||||
editor.saveView();
|
||||
editor._initState = null;
|
||||
this._destroy();
|
||||
} catch (e) { }
|
||||
$(el).remove();
|
||||
$(toolbarRow).remove();
|
||||
}
|
||||
editor.on("blur", function () {
|
||||
editor.focusMemory = false;
|
||||
editor.saveView();
|
||||
})
|
||||
editor.on("focus", function () {
|
||||
if (editor._initState) {
|
||||
editor.restoreView(editor._initState);
|
||||
editor._initState = null;
|
||||
}
|
||||
})
|
||||
editor.getView = function () {
|
||||
var session = editor.getSession();
|
||||
return {
|
||||
selection: session.selection.toJSON(),
|
||||
scrollTop: session.getScrollTop(),
|
||||
scrollLeft: session.getScrollLeft(),
|
||||
options: session.getOptions()
|
||||
}
|
||||
}
|
||||
editor.saveView = function () {
|
||||
if (!options.stateId) { return; } //only possible if created with a unique stateId
|
||||
window._editorStateAce = window._editorStateAce || {};
|
||||
var state = editor.getView();
|
||||
window._editorStateAce[options.stateId] = state;
|
||||
return state;
|
||||
}
|
||||
editor.restoreView = function (state) {
|
||||
if (!options.stateId) { return; } //only possible if created with a unique stateId
|
||||
window._editorStateAce = window._editorStateAce || {};
|
||||
var _state = state || window._editorStateAce[options.stateId];
|
||||
if (!_state) { return; } //no view state available
|
||||
try {
|
||||
var session = editor.getSession();
|
||||
session.setOptions(_state.options);
|
||||
session.selection.fromJSON(_state.selection);
|
||||
session.setScrollTop(_state.scrollTop);
|
||||
session.setScrollLeft(_state.scrollLeft);
|
||||
editor._initState = _state;
|
||||
} catch (error) {
|
||||
delete window._editorStateMonaco[options.stateId];
|
||||
}
|
||||
};
|
||||
editor.restoreView();
|
||||
editor.type = type;
|
||||
return editor;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
function setMode(mode, cb)
|
||||
function getRange();
|
||||
function replace(range, text)
|
||||
function selectAll
|
||||
function selectAll
|
||||
function clearSelection
|
||||
function getSelectedText()
|
||||
function destroy()
|
||||
@@ -54,6 +54,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
var initialised = false;
|
||||
const type = "monaco";
|
||||
const monacoThemes = ["vs","vs-dark","hc-black"]; //TODO: consider setting hc-black autmatically based on acessability?
|
||||
let userSelectedTheme;
|
||||
|
||||
//TODO: get from externalModules.js For now this is enough for feature parity with ACE (and then some).
|
||||
const knownModules = {
|
||||
@@ -153,9 +154,9 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
|
||||
function init(options) {
|
||||
|
||||
//Handles orphaned models
|
||||
//Handles orphaned models
|
||||
//ensure loaded models that are not explicitly destroyed by a call to .destroy() are disposed
|
||||
RED.events.on("editor:close",function() {
|
||||
RED.events.on("editor:close",function() {
|
||||
let models = window.monaco ? monaco.editor.getModels() : null;
|
||||
if(models && models.length) {
|
||||
console.warn("Cleaning up monaco models left behind. Any node that calls createEditor() should call .destroy().")
|
||||
@@ -170,7 +171,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
|
||||
options = options || {};
|
||||
window.MonacoEnvironment = window.MonacoEnvironment || {};
|
||||
window.MonacoEnvironment.getWorkerUrl = function (moduleId, label) {
|
||||
window.MonacoEnvironment.getWorkerUrl = window.MonacoEnvironment.getWorkerUrl || function (moduleId, label) {
|
||||
if (label === 'json') { return './vendor/monaco/dist/json.worker.js'; }
|
||||
if (label === 'css' || label === 'scss') { return './vendor/monaco/dist/css.worker.js'; }
|
||||
if (label === 'html' || label === 'handlebars') { return './vendor/monaco/dist/html.worker.js'; }
|
||||
@@ -181,19 +182,35 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
var editorSettings = RED.editor.codeEditor.settings || {};
|
||||
var editorOptions = editorSettings.options || {};
|
||||
|
||||
if (editorOptions.theme) {
|
||||
if (!monacoThemes.includes(editorOptions.theme)) {
|
||||
var customTheme = 'vendor/monaco/dist/theme/' + editorOptions.theme + '.json';
|
||||
$.get(customTheme, function (theme) {
|
||||
monacoThemes.push(editorOptions.theme);//add to list of loaded themes
|
||||
if ((theme.rules && Array.isArray(theme.rules)) || theme.colors) {
|
||||
monaco.editor.defineTheme(editorOptions.theme, theme);
|
||||
monaco.editor.setTheme(editorOptions.theme);
|
||||
//if editorOptions.theme is an object (set in theme.js context()), use the plugin theme name as the monaco theme name
|
||||
//if editorOptions.theme is a string, it should be the name of a pre-set theme, load that
|
||||
try {
|
||||
const addTheme = function (themeThemeName, theme) {
|
||||
if ((theme.rules && Array.isArray(theme.rules)) || theme.colors) {
|
||||
monacoThemes.push(themeThemeName); //add to list of loaded themes
|
||||
monaco.editor.defineTheme(themeThemeName, theme);
|
||||
monaco.editor.setTheme(themeThemeName);
|
||||
userSelectedTheme = themeThemeName;
|
||||
}
|
||||
};
|
||||
if (editorOptions.theme) {
|
||||
if (typeof editorOptions.theme == "object" && RED.settings.editorTheme.theme) {
|
||||
let themeThemeName = editorOptions.theme.name || RED.settings.editorTheme.theme;
|
||||
addTheme(themeThemeName, editorOptions.theme);
|
||||
} else if (typeof editorOptions.theme == "string") {
|
||||
let themeThemeName = editorOptions.theme;
|
||||
if (!monacoThemes.includes(themeThemeName)) {
|
||||
$.get('vendor/monaco/dist/theme/' + themeThemeName + '.json', function (theme) {
|
||||
addTheme(themeThemeName, theme);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
|
||||
|
||||
//Helper function to simplify snippet setup
|
||||
function createMonacoCompletionItem(label, insertText, documentation, range, kind) {
|
||||
if (Array.isArray(documentation)) { documentation = documentation.join("\n"); }
|
||||
@@ -560,7 +577,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
createMonacoCompletionItem("set (flow context)", 'flow.set("${1:name}", ${1:value});','Set a value in flow context',range),
|
||||
createMonacoCompletionItem("get (global context)", 'global.get("${1:name}");','Get a value from global context',range),
|
||||
createMonacoCompletionItem("set (global context)", 'global.set("${1:name}", ${1:value});','Set a value in global context',range),
|
||||
createMonacoCompletionItem("get (env)", 'env.get("${1:name}");','Get env variable value',range),
|
||||
createMonacoCompletionItem("get (env)", 'env.get("${1|NR_NODE_ID,NR_NODE_NAME,NR_NODE_PATH,NR_GROUP_ID,NR_GROUP_NAME,NR_FLOW_ID,NR_FLOW_NAME|}");','Get env variable value',range),
|
||||
createMonacoCompletionItem("cloneMessage (RED.util)", 'RED.util.cloneMessage(${1:msg});',
|
||||
["```typescript",
|
||||
"RED.util.cloneMessage<T extends registry.NodeMessage>(msg: T): T",
|
||||
@@ -653,6 +670,8 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
noSyntaxValidation: false,
|
||||
diagnosticCodesToIgnore: [
|
||||
1108, //return not inside function
|
||||
1375, //'await' expressions are only allowed at the top level of a file when that file is a module
|
||||
1378, //Top-level 'await' expressions are only allowed when the 'module' option is set to 'esnext' or 'system', and the 'target' option is set to 'es2017' or higher
|
||||
//2304, //Cannot find name - this one is heavy handed and prevents user seeing stupid errors. Would provide better ACE feature parity (i.e. no need for declaration of vars) but misses lots of errors. Lets be bold & leave it out!
|
||||
2307, //Cannot find module 'xxx' or its corresponding type declarations
|
||||
2322, //Type 'unknown' is not assignable to type 'string'
|
||||
@@ -728,13 +747,25 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
mode = "html";
|
||||
break;
|
||||
case "appcache":
|
||||
case "sh":
|
||||
case "bash":
|
||||
mode = "shell";
|
||||
break;
|
||||
case "batchfile":
|
||||
mode = "bat";
|
||||
break;
|
||||
case "protobuf":
|
||||
mode = "proto";
|
||||
break;
|
||||
//TODO: add other compatability types.
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
if(!options.stateId && options.stateId !== false) {
|
||||
options.stateId = RED.editor.generateViewStateId("monaco", options, (options.mode || options.title).split("/").pop());
|
||||
}
|
||||
var el = options.element || $("#"+options.id)[0];
|
||||
var toolbarRow = $("<div>").appendTo(el);
|
||||
el = $("<div>").appendTo(el).addClass("red-ui-editor-text-container")[0];
|
||||
@@ -742,12 +773,16 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
var editorOptions = $.extend({}, editorSettings.options, options);
|
||||
editorOptions.language = convertAceModeToMonacoLang(options.mode);
|
||||
|
||||
if(userSelectedTheme) {
|
||||
editorOptions.theme = userSelectedTheme;//use user selected theme for this session
|
||||
}
|
||||
|
||||
//by default, set javascript editors to text mode.
|
||||
//when element becomes visible, it will be (re) set to javascript mode
|
||||
//this is to ensure multiple editors sharing the model dont present its
|
||||
//this is to ensure multiple editors sharing the model dont present its
|
||||
//consts & lets to each other
|
||||
if(editorOptions.language == "javascript") {
|
||||
editorOptions._language = editorOptions.language;
|
||||
editorOptions._language = editorOptions.language;
|
||||
editorOptions.language = "text"
|
||||
}
|
||||
|
||||
@@ -921,6 +956,15 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
/*********** Create the monaco editor ***************/
|
||||
var ed = monaco.editor.create(el, editorOptions);
|
||||
|
||||
//Unbind ctrl-Enter (default action is to insert a newline in editor) This permits the shortcut to close the tray.
|
||||
try {
|
||||
ed._standaloneKeybindingService.addDynamicKeybinding(
|
||||
'-editor.action.insertLineAfter', // command ID prefixed by '-'
|
||||
null, // keybinding
|
||||
() => {} // need to pass an empty handler
|
||||
);
|
||||
} catch (error) { }
|
||||
|
||||
ed.nodered = {
|
||||
refreshModuleLibs: refreshModuleLibs //expose this for function node externalModules refresh
|
||||
}
|
||||
@@ -967,7 +1011,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
if (cb && typeof cb == "function") {
|
||||
cb();
|
||||
}
|
||||
if(resize) {
|
||||
if(resize) {
|
||||
this.resize(); //cause a call to layout()
|
||||
}
|
||||
}
|
||||
@@ -1066,6 +1110,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
try {
|
||||
var m = this.getModel();
|
||||
if(m && !m.isDisposed()) {
|
||||
ed._initState = null;
|
||||
m.dispose();
|
||||
}
|
||||
this.setModel(null);
|
||||
@@ -1119,7 +1164,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
try {
|
||||
var _model = ed.getModel();
|
||||
if (_model !== null) {
|
||||
var id = _model.getModeId(); // e.g. javascript
|
||||
var id = _model._languageId; // e.g. javascript
|
||||
var ra = _model._associatedResource.authority; //e.g. model
|
||||
var rp = _model._associatedResource.path; //e.g. /18
|
||||
var rs = _model._associatedResource.scheme; //e.g. inmemory
|
||||
@@ -1158,7 +1203,10 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
return { row: p.lineNumber-1, column: p.column-1 };
|
||||
}
|
||||
|
||||
ed.setTheme = monaco.editor.setTheme;
|
||||
ed.setTheme = function(theme) {
|
||||
monaco.editor.setTheme(theme);
|
||||
userSelectedTheme = theme;//remember users choice for this session
|
||||
}
|
||||
|
||||
ed.on = function (name, cb) {
|
||||
switch (name) {
|
||||
@@ -1208,17 +1256,10 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
//#endregion "ACE compatability"
|
||||
|
||||
//final setup
|
||||
if (options.cursor) {
|
||||
var row = options.cursor.row || options.cursor.lineNumber;
|
||||
var col = options.cursor.column || options.cursor.col;
|
||||
ed.gotoLine(row, col);
|
||||
}
|
||||
if (options.focus) {
|
||||
ed.focus();
|
||||
}
|
||||
ed.focusMemory = options.focus;
|
||||
ed._mode = editorOptions.language;
|
||||
|
||||
//as models are signleton, consts and let are avialable to other javascript instances
|
||||
//as models are signleton, consts and let are avialable to other javascript instances
|
||||
//so when not focused, set editor mode to text temporarily to avoid multiple defs
|
||||
|
||||
if(editorOptions._language) {
|
||||
@@ -1227,11 +1268,12 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
}
|
||||
|
||||
ed.onDidBlurEditorWidget(function() {
|
||||
ed.focusMemory = false;
|
||||
ed.saveView();
|
||||
if(isVisible(el) == false) {
|
||||
onVisibilityChange(false, 0, el);
|
||||
}
|
||||
});
|
||||
|
||||
ed.onDidFocusEditorWidget(function() {
|
||||
onVisibilityChange(true, 10, el);
|
||||
});
|
||||
@@ -1240,15 +1282,15 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
try {
|
||||
var options = {
|
||||
root: $(element).closest("div.red-ui-tray-content")[0] || document,
|
||||
attributes: true,
|
||||
childList: true,
|
||||
attributes: true,
|
||||
childList: true,
|
||||
};
|
||||
var observer = new IntersectionObserver(function(entries, observer) {
|
||||
entries.forEach(function(entry) {
|
||||
callback(entry.intersectionRatio > 0, 5, entry.target);
|
||||
});
|
||||
}, options);
|
||||
observer.observe(element);
|
||||
observer.observe(element);
|
||||
} catch (e1) {
|
||||
//browser not supporting IntersectionObserver? then fall back to polling!
|
||||
try {
|
||||
@@ -1265,19 +1307,35 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
}
|
||||
|
||||
function onVisibilityChange(visible, delay, element) {
|
||||
if(visible) {
|
||||
if(ed._mode == "javascript" && ed._tempMode == "text") {
|
||||
ed._tempMode = "";
|
||||
setTimeout(function() {
|
||||
if(element.parentElement) { //ensure el is still in DOM
|
||||
delay = delay || 50;
|
||||
if (visible) {
|
||||
if (ed.focusMemory) {
|
||||
setTimeout(function () {
|
||||
if (element.parentElement) { //ensure el is still in DOM
|
||||
ed.focus();
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
if (ed._initState) {
|
||||
setTimeout(function () {
|
||||
if (element.parentElement) { //ensure el is still in DOM
|
||||
ed.restoreViewState(ed._initState);
|
||||
ed._initState = null;
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
if (ed._mode == "javascript" && ed._tempMode == "text") {
|
||||
ed._tempMode = "";
|
||||
setTimeout(function () {
|
||||
if (element.parentElement) { //ensure el is still in DOM
|
||||
ed.setMode('javascript', undefined, false);
|
||||
}
|
||||
}, delay || 50);
|
||||
}, delay);
|
||||
}
|
||||
} else if(ed._mode == "javascript" && ed._tempMode != "text") {
|
||||
if(element.parentElement) { //ensure el is still in DOM
|
||||
} else if (ed._mode == "javascript" && ed._tempMode != "text") {
|
||||
if (element.parentElement) { //ensure el is still in DOM
|
||||
ed.setMode('text', undefined, false);
|
||||
ed._tempMode = "text";
|
||||
ed._tempMode = "text";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1294,15 +1352,19 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
expandButton.on("click", function (e) {
|
||||
e.preventDefault();
|
||||
var value = ed.getValue();
|
||||
ed.saveView();
|
||||
RED.editor.editMarkdown({
|
||||
value: value,
|
||||
width: "Infinity",
|
||||
cursor: ed.getCursorPosition(),
|
||||
stateId: options.stateId,
|
||||
cancel: function () {
|
||||
ed.focus();
|
||||
},
|
||||
complete: function (v, cursor) {
|
||||
ed.setValue(v, -1);
|
||||
ed.gotoLine(cursor.row + 1, cursor.column, false);
|
||||
setTimeout(function () {
|
||||
ed.focus();
|
||||
ed.restoreView();
|
||||
}, 300);
|
||||
}
|
||||
})
|
||||
@@ -1318,7 +1380,37 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
autoClose: 50
|
||||
});
|
||||
}
|
||||
|
||||
ed.getView = function () {
|
||||
return ed.saveViewState();
|
||||
}
|
||||
ed.saveView = function (debuginfo) {
|
||||
if (!options.stateId) { return; } //only possible if created with a unique stateId
|
||||
window._editorStateMonaco = window._editorStateMonaco || {};
|
||||
var state = ed.getView();
|
||||
window._editorStateMonaco[options.stateId] = state;
|
||||
return state;
|
||||
}
|
||||
ed.restoreView = function (state) {
|
||||
if (!options.stateId) { return; } //only possible if created with a unique stateId
|
||||
window._editorStateMonaco = window._editorStateMonaco || {};
|
||||
var _state = state || window._editorStateMonaco[options.stateId];
|
||||
if (!_state) { return; } //no view state available
|
||||
try {
|
||||
if (ed.type) { //is editor already initialised?
|
||||
ed.restoreViewState(_state);
|
||||
} else {
|
||||
ed._initState = _state;
|
||||
}
|
||||
} catch (error) {
|
||||
delete window._editorStateMonaco[options.stateId];
|
||||
}
|
||||
};
|
||||
ed.restoreView();
|
||||
if (options.cursor && !ed._initState) {
|
||||
var row = options.cursor.row || options.cursor.lineNumber;
|
||||
var col = options.cursor.column || options.cursor.col;
|
||||
ed.gotoLine(row, col);
|
||||
}
|
||||
ed.type = type;
|
||||
return ed;
|
||||
}
|
||||
@@ -1353,4 +1445,4 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
*/
|
||||
create: create
|
||||
}
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
RED.colorPicker = (function() {
|
||||
RED.editor.colorPicker = RED.colorPicker = (function() {
|
||||
|
||||
function create(options) {
|
||||
var color = options.value;
|
||||
616
packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js
vendored
Normal file
616
packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js
vendored
Normal file
@@ -0,0 +1,616 @@
|
||||
RED.editor.envVarList = (function() {
|
||||
|
||||
var currentLocale = 'en-US';
|
||||
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
||||
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
|
||||
|
||||
/**
|
||||
* Create env var edit interface
|
||||
* @param container - container
|
||||
* @param node - subflow node
|
||||
*/
|
||||
function buildPropertiesList(envContainer, node) {
|
||||
|
||||
var isTemplateNode = (node.type === "subflow");
|
||||
|
||||
envContainer
|
||||
.css({
|
||||
'min-height':'150px',
|
||||
'min-width':'450px'
|
||||
})
|
||||
.editableList({
|
||||
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
|
||||
addItem: function(container, i, opt) {
|
||||
// If this is an instance node, these are properties unique to
|
||||
// this instance - ie opt.parent will not be defined.
|
||||
|
||||
if (isTemplateNode) {
|
||||
container.addClass("red-ui-editor-subflow-env-editable")
|
||||
}
|
||||
|
||||
var envRow = $('<div/>').appendTo(container);
|
||||
var nameField = null;
|
||||
var valueField = null;
|
||||
|
||||
nameField = $('<input/>', {
|
||||
class: "node-input-env-name",
|
||||
type: "text",
|
||||
placeholder: RED._("common.label.name")
|
||||
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
|
||||
valueField = $('<input/>',{
|
||||
style: "width:100%",
|
||||
class: "node-input-env-value",
|
||||
type: "text",
|
||||
}).attr("autocomplete","disable").appendTo(envRow)
|
||||
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
|
||||
valueField.typedInput('type', opt.type);
|
||||
if (opt.type === "cred") {
|
||||
if (opt.value) {
|
||||
valueField.typedInput('value', opt.value);
|
||||
} else if (node.credentials && node.credentials[opt.name]) {
|
||||
valueField.typedInput('value', node.credentials[opt.name]);
|
||||
} else if (node.credentials && node.credentials['has_'+opt.name]) {
|
||||
valueField.typedInput('value', "__PWRD__");
|
||||
} else {
|
||||
valueField.typedInput('value', "");
|
||||
}
|
||||
} else {
|
||||
valueField.typedInput('value', opt.value);
|
||||
}
|
||||
|
||||
|
||||
opt.nameField = nameField;
|
||||
opt.valueField = valueField;
|
||||
|
||||
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
|
||||
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
|
||||
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
|
||||
actionButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
removeTip.close();
|
||||
container.parent().addClass("red-ui-editableList-item-deleting")
|
||||
container.fadeOut(300, function() {
|
||||
envContainer.editableList('removeItem',opt);
|
||||
});
|
||||
});
|
||||
|
||||
if (isTemplateNode) {
|
||||
// Add the UI customisation row
|
||||
// if `opt.ui` does not exist, then apply defaults. If these
|
||||
// defaults do not change then they will get stripped off
|
||||
// before saving.
|
||||
if (opt.type === 'cred') {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "cred"
|
||||
}
|
||||
opt.ui.type = "cred";
|
||||
} else {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "input",
|
||||
opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||
}
|
||||
}
|
||||
opt.ui.label = opt.ui.label || {};
|
||||
opt.ui.type = opt.ui.type || "input";
|
||||
|
||||
var uiRow = $('<div/>').appendTo(container).hide();
|
||||
// save current info for reverting on cancel
|
||||
// var copy = $.extend(true, {}, ui);
|
||||
|
||||
$('<a href="#"><i class="fa fa-angle-right"></a>').prependTo(envRow).on("click", function (evt) {
|
||||
evt.preventDefault();
|
||||
if ($(this).hasClass('expanded')) {
|
||||
uiRow.slideUp();
|
||||
$(this).removeClass('expanded');
|
||||
} else {
|
||||
uiRow.slideDown();
|
||||
$(this).addClass('expanded');
|
||||
}
|
||||
});
|
||||
|
||||
buildEnvEditRow(uiRow, opt.ui, nameField, valueField);
|
||||
nameField.trigger('change');
|
||||
}
|
||||
},
|
||||
sortable: ".red-ui-editableList-item-handle",
|
||||
removable: false
|
||||
});
|
||||
var parentEnv = {};
|
||||
var envList = [];
|
||||
if (/^subflow:/.test(node.type)) {
|
||||
var subflowDef = RED.nodes.subflow(node.type.substring(8));
|
||||
if (subflowDef.env) {
|
||||
subflowDef.env.forEach(function(env) {
|
||||
var item = {
|
||||
name:env.name,
|
||||
parent: {
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
}
|
||||
}
|
||||
envList.push(item);
|
||||
parentEnv[env.name] = item;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (node.env) {
|
||||
for (var i = 0; i < node.env.length; i++) {
|
||||
var env = node.env[i];
|
||||
if (parentEnv.hasOwnProperty(env.name)) {
|
||||
parentEnv[env.name].type = env.type;
|
||||
parentEnv[env.name].value = env.value;
|
||||
} else {
|
||||
envList.push({
|
||||
name: env.name,
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
envList.forEach(function(env) {
|
||||
if (env.parent && env.parent.ui && env.parent.ui.type === 'hide') {
|
||||
return;
|
||||
}
|
||||
if (!isTemplateNode && env.parent) {
|
||||
return;
|
||||
}
|
||||
envContainer.editableList('addItem', JSON.parse(JSON.stringify(env)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create UI edit interface for environment variable
|
||||
* @param container - container
|
||||
* @param env - env var definition
|
||||
* @param nameField - name field of env var
|
||||
* @param valueField - value field of env var
|
||||
*/
|
||||
function buildEnvEditRow(container, ui, nameField, valueField) {
|
||||
container.addClass("red-ui-editor-subflow-env-ui-row")
|
||||
var topRow = $('<div></div>').appendTo(container);
|
||||
$('<div></div>').appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.icon")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.label")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.inputType")).appendTo(topRow);
|
||||
|
||||
var row = $('<div></div>').appendTo(container);
|
||||
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
|
||||
var typeOptions = {
|
||||
'input': {types:DEFAULT_ENV_TYPE_LIST},
|
||||
'select': {opts:[]},
|
||||
'spinner': {},
|
||||
'cred': {}
|
||||
};
|
||||
if (ui.opts) {
|
||||
typeOptions[ui.type] = ui.opts;
|
||||
} else {
|
||||
// Pick up the default values if not otherwise provided
|
||||
ui.opts = typeOptions[ui.type];
|
||||
}
|
||||
var iconCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var iconButton = $('<a href="#"></a>').appendTo(iconCell);
|
||||
iconButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var icon = ui.icon || "";
|
||||
var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
|
||||
RED.editor.iconPicker.show(iconButton, null, iconPath, true, function (newIcon) {
|
||||
iconButton.empty();
|
||||
var path = newIcon || "";
|
||||
var newPath = RED.utils.separateIconPath(path);
|
||||
if (newPath) {
|
||||
$('<i class="fa"></i>').addClass(newPath.file).appendTo(iconButton);
|
||||
}
|
||||
ui.icon = path;
|
||||
});
|
||||
})
|
||||
|
||||
if (ui.icon) {
|
||||
var newPath = RED.utils.separateIconPath(ui.icon);
|
||||
$('<i class="fa '+newPath.file+'"></i>').appendTo(iconButton);
|
||||
}
|
||||
|
||||
var labelCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var label = ui.label && ui.label[currentLocale] || "";
|
||||
var labelInput = $('<input type="text">').val(label).appendTo(labelCell);
|
||||
ui.labelField = labelInput;
|
||||
labelInput.on('change', function(evt) {
|
||||
ui.label = ui.label || {};
|
||||
var val = $(this).val().trim();
|
||||
if (val === "") {
|
||||
delete ui.label[currentLocale];
|
||||
} else {
|
||||
ui.label[currentLocale] = val;
|
||||
}
|
||||
})
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelCell);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
var langs = Object.keys(ui.label);
|
||||
var content = $("<div>");
|
||||
if (langs.indexOf(currentLocale) === -1) {
|
||||
langs.push(currentLocale);
|
||||
langs.sort();
|
||||
}
|
||||
langs.forEach(function(l) {
|
||||
var row = $('<div>').appendTo(content);
|
||||
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
|
||||
$('<span>').text(ui.label[l]||"").appendTo(row);
|
||||
});
|
||||
return content;
|
||||
})
|
||||
|
||||
nameField.on('change',function(evt) {
|
||||
labelInput.attr("placeholder",$(this).val())
|
||||
});
|
||||
|
||||
var inputCell = $('<div></div>').appendTo(row);
|
||||
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
|
||||
if (ui.type === "input") {
|
||||
inputCellInput.val(ui.opts.types.join(","));
|
||||
}
|
||||
var checkbox;
|
||||
var selectBox;
|
||||
|
||||
inputCellInput.typedInput({
|
||||
types: [
|
||||
{
|
||||
value:"input",
|
||||
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
|
||||
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
|
||||
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
|
||||
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
|
||||
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
|
||||
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
|
||||
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"},
|
||||
{value: "cred",label: RED._("editor.types.cred"),icon: "fa fa-lock"}
|
||||
],
|
||||
default: DEFAULT_ENV_TYPE_LIST,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
|
||||
if (value.length) {
|
||||
value.forEach(function(v) {
|
||||
if (!/^fa /.test(v.icon)) {
|
||||
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
} else {
|
||||
var s = $('<span>',{style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
$("<i>",{class: v.icon}).appendTo(s);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
$('<span class="red-ui-editor-subflow-env-input-type-placeholder"></span>').text(RED._("editor.selectType")).appendTo(input);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value: "cred",
|
||||
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type">').css({
|
||||
"border-top-right-radius": "4px",
|
||||
"border-bottom-right-radius": "4px"
|
||||
}).appendTo(container);
|
||||
$('<div class="placeholder-input">').html("••••••••").appendTo(innerContainer);
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"select",
|
||||
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding","0");
|
||||
|
||||
selectBox = $('<select></select>').appendTo(container);
|
||||
if (ui.opts && Array.isArray(ui.opts.opts)) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
|
||||
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
|
||||
$('<option>').val(o.v).text(label).appendTo(selectBox);
|
||||
})
|
||||
}
|
||||
selectBox.on('change', function(evt) {
|
||||
var v = selectBox.val();
|
||||
// var parts = v.split(":");
|
||||
// var t = parts.shift();
|
||||
// v = parts.join(":");
|
||||
//
|
||||
// valueField.typedInput("type",'str')
|
||||
valueField.typedInput("value",v)
|
||||
});
|
||||
selectBox.val(valueField.typedInput("value"));
|
||||
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
minWidth: 400,
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
var optList = $('<ol>').appendTo(content).editableList({
|
||||
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
|
||||
addItem: function(row,index,itemData) {
|
||||
var labelDiv = $('<div>').appendTo(row);
|
||||
var label = lookupLabel(itemData.l, "", currentLocale);
|
||||
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
|
||||
itemData.label.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
itemData.input.focus();
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
return currentLocale;
|
||||
})
|
||||
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
|
||||
|
||||
// Problem using a TI here:
|
||||
// - this is in a popout panel
|
||||
// - clicking the expand button in the TI will close the parent edit tray
|
||||
// and open the type editor.
|
||||
// - but it leaves the popout panel over the top.
|
||||
// - there is no way to get back to the popout panel after closing the type editor
|
||||
//.typedInput({default:itemData.t||'str', types:DEFAULT_ENV_TYPE_LIST});
|
||||
itemData.input.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
// Enter or Tab
|
||||
var index = optList.editableList('indexOf',itemData);
|
||||
var length = optList.editableList('length');
|
||||
if (index + 1 === length) {
|
||||
var newItem = {};
|
||||
optList.editableList('addItem',newItem);
|
||||
setTimeout(function() {
|
||||
if (newItem.label) {
|
||||
newItem.label.focus();
|
||||
}
|
||||
},100)
|
||||
} else {
|
||||
var nextItem = optList.editableList('getItemAt',index+1);
|
||||
if (nextItem.label) {
|
||||
nextItem.label.focus()
|
||||
}
|
||||
}
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
},
|
||||
sortable: true,
|
||||
removable: true,
|
||||
height: 160
|
||||
})
|
||||
if (ui.opts.opts.length > 0) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
optList.editableList('addItem',$.extend(true,{},o))
|
||||
})
|
||||
} else {
|
||||
optList.editableList('addItem',{})
|
||||
}
|
||||
return {
|
||||
onclose: function() {
|
||||
var items = optList.editableList('items');
|
||||
var vals = [];
|
||||
items.each(function (i,el) {
|
||||
var data = el.data('data');
|
||||
var l = data.label.val().trim();
|
||||
var v = data.input.val();
|
||||
// var t = data.input.typedInput('type');
|
||||
// var v = data.input.typedInput('value');
|
||||
if (l.length > 0) {
|
||||
data.l = data.l || {};
|
||||
data.l[currentLocale] = l;
|
||||
}
|
||||
data.v = v;
|
||||
|
||||
if (l.length > 0 || v.length > 0) {
|
||||
var val = {l:data.l,v:data.v};
|
||||
// if (t !== 'str') {
|
||||
// val.t = t;
|
||||
// }
|
||||
vals.push(val);
|
||||
}
|
||||
});
|
||||
ui.opts.opts = vals;
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"checkbox",
|
||||
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
checkbox = $('<input type="checkbox">').appendTo(container);
|
||||
checkbox.on('change', function(evt) {
|
||||
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
|
||||
})
|
||||
checkbox.prop('checked',valueField.typedInput('value')==="true");
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"spinner",
|
||||
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
|
||||
|
||||
var min = ui.opts && ui.opts.min;
|
||||
var max = ui.opts && ui.opts.max;
|
||||
var label = "";
|
||||
if (min !== undefined && max !== undefined) {
|
||||
label = Math.min(min,max)+" - "+Math.max(min,max);
|
||||
} else if (min !== undefined) {
|
||||
label = "> "+min;
|
||||
} else if (max !== undefined) {
|
||||
label = "< "+max;
|
||||
}
|
||||
$('<span>').css("margin-left","15px").text(label).appendTo(input);
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
content.css("padding","8px 5px")
|
||||
var min = ui.opts.min;
|
||||
var max = ui.opts.max;
|
||||
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
minInput.val(min);
|
||||
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
maxInput.val(max);
|
||||
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
|
||||
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
|
||||
return {
|
||||
onclose: function() {
|
||||
var min = minInput.val().trim();
|
||||
var max = maxInput.val().trim();
|
||||
if (min !== "") {
|
||||
ui.opts.min = parseInt(min);
|
||||
} else {
|
||||
delete ui.opts.min;
|
||||
}
|
||||
if (max !== "") {
|
||||
ui.opts.max = parseInt(max);
|
||||
} else {
|
||||
delete ui.opts.max;
|
||||
}
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"none",
|
||||
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
|
||||
},
|
||||
{
|
||||
value:"hide",
|
||||
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
|
||||
}
|
||||
],
|
||||
default: 'none'
|
||||
}).on("typedinputtypechange", function(evt,type) {
|
||||
ui.type = $(this).typedInput("type");
|
||||
ui.opts = typeOptions[ui.type];
|
||||
if (ui.type === 'input') {
|
||||
// In the case of 'input' type, the typedInput uses the multiple-option
|
||||
// mode. Its value needs to be set to a comma-separately list of the
|
||||
// selected options.
|
||||
inputCellInput.typedInput('value',ui.opts.types.join(","))
|
||||
} else {
|
||||
// No other type cares about `value`, but doing this will
|
||||
// force a refresh of the label now that `ui.opts` has
|
||||
// been updated.
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
|
||||
switch (ui.type) {
|
||||
case 'input':
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
break;
|
||||
case 'select':
|
||||
valueField.typedInput('types',['str']);
|
||||
break;
|
||||
case 'checkbox':
|
||||
valueField.typedInput('types',['bool']);
|
||||
break;
|
||||
case 'spinner':
|
||||
valueField.typedInput('types',['num']);
|
||||
break;
|
||||
case 'cred':
|
||||
valueField.typedInput('types',['cred']);
|
||||
break;
|
||||
default:
|
||||
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
|
||||
}
|
||||
if (ui.type === 'checkbox') {
|
||||
valueField.typedInput('type','bool');
|
||||
} else if (ui.type === 'spinner') {
|
||||
valueField.typedInput('type','num');
|
||||
}
|
||||
if (ui.type !== 'checkbox') {
|
||||
checkbox = null;
|
||||
}
|
||||
|
||||
}).on("change", function(evt,type) {
|
||||
if (ui.type === 'input') {
|
||||
var types = inputCellInput.typedInput('value');
|
||||
ui.opts.types = (types === "") ? ["str"] : types.split(",");
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
}
|
||||
});
|
||||
valueField.on("change", function(evt) {
|
||||
if (checkbox) {
|
||||
checkbox.prop('checked',$(this).typedInput('value')==="true")
|
||||
}
|
||||
})
|
||||
// Set the input to the right type. This will trigger the 'typedinputtypechange'
|
||||
// event handler (just above ^^) to update the value if needed
|
||||
inputCellInput.typedInput('type',ui.type)
|
||||
}
|
||||
|
||||
function setLocale(l, list) {
|
||||
currentLocale = l;
|
||||
if (list) {
|
||||
var items = list.editableList("items");
|
||||
items.each(function (i, item) {
|
||||
var entry = $(this).data('data');
|
||||
var labelField = entry.ui.labelField;
|
||||
labelField.val(lookupLabel(entry.ui.label, "", currentLocale));
|
||||
if (labelField.timeout) {
|
||||
clearTimeout(labelField.timeout);
|
||||
delete labelField.timeout;
|
||||
}
|
||||
labelField.addClass("input-updated");
|
||||
labelField.timeout = setTimeout(function() {
|
||||
delete labelField.timeout
|
||||
labelField.removeClass("input-updated");
|
||||
},3000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup text for specific locale
|
||||
* @param labels - dict of labels
|
||||
* @param defaultLabel - fallback label if not found
|
||||
* @param locale - target locale
|
||||
* @returns {string} text for specified locale
|
||||
*/
|
||||
function lookupLabel(labels, defaultLabel, locale) {
|
||||
if (labels) {
|
||||
if (labels[locale]) {
|
||||
return labels[locale];
|
||||
}
|
||||
if (locale) {
|
||||
var lang = locale.substring(0, 2);
|
||||
if (labels[lang]) {
|
||||
return labels[lang];
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultLabel;
|
||||
}
|
||||
|
||||
return {
|
||||
create: buildPropertiesList,
|
||||
setLocale: setLocale,
|
||||
lookupLabel: lookupLabel,
|
||||
DEFAULT_ENV_TYPE_LIST: DEFAULT_ENV_TYPE_LIST,
|
||||
DEFAULT_ENV_TYPE_LIST_INC_CRED: DEFAULT_ENV_TYPE_LIST_INC_CRED
|
||||
}
|
||||
})();
|
||||
@@ -50,6 +50,7 @@
|
||||
show: function(options) {
|
||||
var expressionTestCacheId = options.parent||"_";
|
||||
var value = options.value;
|
||||
var onCancel = options.cancel;
|
||||
var onComplete = options.complete;
|
||||
var type = "_expression"
|
||||
if ($("script[data-template-name='"+type+"']").length === 0) {
|
||||
@@ -63,12 +64,14 @@
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
focusElement: options.focusElement,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
if(onCancel) { onCancel(); }
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
@@ -78,7 +81,8 @@
|
||||
class: "primary",
|
||||
click: function() {
|
||||
$("#red-ui-editor-type-expression-help").text("");
|
||||
onComplete(expressionEditor.getValue());
|
||||
expressionEditor.saveView();
|
||||
if (onComplete) { onComplete(expressionEditor.getValue(),expressionEditor.getCursorPosition(),expressionEditor); }
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
@@ -110,6 +114,8 @@
|
||||
id: 'red-ui-editor-type-expression',
|
||||
value: "",
|
||||
mode:"ace/mode/jsonata",
|
||||
stateId: options.stateId,
|
||||
focus: true,
|
||||
options: {
|
||||
enableBasicAutocompletion:true,
|
||||
enableSnippets:true,
|
||||
@@ -233,6 +239,8 @@
|
||||
testDataEditor = RED.editor.createEditor({
|
||||
id: 'red-ui-editor-type-expression-test-data',
|
||||
value: expressionTestCache[expressionTestCacheId] || '{\n "payload": "hello world"\n}',
|
||||
stateId: false,
|
||||
focus: false,
|
||||
mode:"ace/mode/json",
|
||||
lineNumbers: false
|
||||
});
|
||||
@@ -247,7 +255,7 @@
|
||||
var currentExpression = expressionEditor.getValue();
|
||||
var expr;
|
||||
var usesContext = false;
|
||||
var legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
|
||||
var legacyMode = /(^|[^a-zA-Z0-9_'".])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
|
||||
$(".red-ui-editor-type-expression-legacy").toggle(legacyMode);
|
||||
try {
|
||||
expr = jsonata(currentExpression);
|
||||
@@ -302,6 +310,8 @@
|
||||
testResultEditor = RED.editor.createEditor({
|
||||
id: 'red-ui-editor-type-expression-test-result',
|
||||
value: "",
|
||||
stateId: false,
|
||||
focus: false,
|
||||
mode:"ace/mode/json",
|
||||
lineNumbers: false,
|
||||
readOnly: true
|
||||
|
||||
99
packages/node_modules/@node-red/editor-client/src/js/ui/editors/iconPicker.js
vendored
Normal file
99
packages/node_modules/@node-red/editor-client/src/js/ui/editors/iconPicker.js
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
RED.editor.iconPicker = (function() {
|
||||
function showIconPicker(container, backgroundColor, iconPath, faOnly, done) {
|
||||
var picker = $('<div class="red-ui-icon-picker">');
|
||||
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(picker);
|
||||
searchInput = $('<input type="text">').attr("placeholder",RED._("editor.searchIcons")).appendTo(searchDiv).searchBox({
|
||||
delay: 50,
|
||||
change: function() {
|
||||
var searchTerm = $(this).val().trim();
|
||||
if (searchTerm === "") {
|
||||
iconList.find(".red-ui-icon-list-module").show();
|
||||
iconList.find(".red-ui-icon-list-icon").show();
|
||||
} else {
|
||||
iconList.find(".red-ui-icon-list-module").hide();
|
||||
iconList.find(".red-ui-icon-list-icon").each(function(i,n) {
|
||||
if ($(n).data('icon').indexOf(searchTerm) === -1) {
|
||||
$(n).hide();
|
||||
} else {
|
||||
$(n).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var row = $('<div>').appendTo(picker);
|
||||
var iconList = $('<div class="red-ui-icon-list">').appendTo(picker);
|
||||
var metaRow = $('<div class="red-ui-icon-meta"></div>').appendTo(picker);
|
||||
var summary = $('<span>').appendTo(metaRow);
|
||||
var resetButton = $('<button type="button" class="red-ui-button red-ui-button-small">'+RED._("editor.useDefault")+'</button>').appendTo(metaRow).on("click", function(e) {
|
||||
e.preventDefault();
|
||||
iconPanel.hide();
|
||||
done(null);
|
||||
});
|
||||
if (!backgroundColor && faOnly) {
|
||||
iconList.addClass("red-ui-icon-list-dark");
|
||||
}
|
||||
setTimeout(function() {
|
||||
var iconSets = RED.nodes.getIconSets();
|
||||
Object.keys(iconSets).forEach(function(moduleName) {
|
||||
if (faOnly && (moduleName !== "font-awesome")) {
|
||||
return;
|
||||
}
|
||||
var icons = iconSets[moduleName];
|
||||
if (icons.length > 0) {
|
||||
// selectIconModule.append($("<option></option>").val(moduleName).text(moduleName));
|
||||
var header = $('<div class="red-ui-icon-list-module"></div>').text(moduleName).appendTo(iconList);
|
||||
$('<i class="fa fa-cube"></i>').prependTo(header);
|
||||
icons.forEach(function(icon) {
|
||||
var iconDiv = $('<div>',{class:"red-ui-icon-list-icon"}).appendTo(iconList);
|
||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconDiv);
|
||||
var icon_url = RED.settings.apiRootUrl+"icons/"+moduleName+"/"+icon;
|
||||
iconDiv.data('icon',icon_url);
|
||||
if (backgroundColor) {
|
||||
nodeDiv.css({
|
||||
'backgroundColor': backgroundColor
|
||||
});
|
||||
var borderColor = RED.utils.getDarkerColor(backgroundColor);
|
||||
if (borderColor !== backgroundColor) {
|
||||
nodeDiv.css('border-color',borderColor)
|
||||
}
|
||||
|
||||
}
|
||||
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
||||
RED.utils.createIconElement(icon_url, iconContainer, true);
|
||||
|
||||
if (iconPath.module === moduleName && iconPath.file === icon) {
|
||||
iconDiv.addClass("selected");
|
||||
}
|
||||
iconDiv.on("mouseover", function() {
|
||||
summary.text(icon);
|
||||
})
|
||||
iconDiv.on("mouseout", function() {
|
||||
summary.html(" ");
|
||||
})
|
||||
iconDiv.on("click", function() {
|
||||
iconPanel.hide();
|
||||
done(moduleName+"/"+icon);
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
setTimeout(function() {
|
||||
spinner.remove();
|
||||
},50);
|
||||
},300);
|
||||
var spinner = RED.utils.addSpinnerOverlay(iconList,true);
|
||||
var iconPanel = RED.popover.panel(picker);
|
||||
iconPanel.show({
|
||||
target: container
|
||||
})
|
||||
|
||||
|
||||
picker.slideDown(100);
|
||||
searchInput.trigger("focus");
|
||||
}
|
||||
return {
|
||||
show: showIconPicker
|
||||
}
|
||||
})();
|
||||
@@ -21,6 +21,7 @@
|
||||
var definition = {
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onCancel = options.cancel;
|
||||
var onComplete = options.complete;
|
||||
var type = "_js"
|
||||
if ($("script[data-template-name='"+type+"']").length === 0) {
|
||||
@@ -28,16 +29,16 @@
|
||||
}
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
var changeTimer;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
focusElement: options.focusElement,
|
||||
width: options.width||"inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
if (onCancel) { onCancel(); }
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
@@ -46,7 +47,8 @@
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(expressionEditor.getValue(),expressionEditor.getCursorPosition());
|
||||
expressionEditor.saveView();
|
||||
if (onComplete) { onComplete(expressionEditor.getValue(), expressionEditor.getCursorPosition(), expressionEditor); }
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
@@ -62,11 +64,12 @@
|
||||
expressionEditor.resize();
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.red-ui-tray-body'),'dialog-form',type,'editor');
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-js',
|
||||
mode: options.mode || 'ace/mode/javascript',
|
||||
stateId: options.stateId,
|
||||
focus: true,
|
||||
value: value,
|
||||
globals: {
|
||||
msg:true,
|
||||
@@ -81,21 +84,19 @@
|
||||
clearTimeout: true,
|
||||
setInterval: true,
|
||||
clearInterval: true
|
||||
}
|
||||
},
|
||||
extraLibs: options.extraLibs
|
||||
});
|
||||
if (options.cursor) {
|
||||
if (options.cursor && !expressionEditor._initState) {
|
||||
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
||||
}
|
||||
dialogForm.i18n();
|
||||
setTimeout(function() {
|
||||
expressionEditor.focus();
|
||||
},300);
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
expressionEditor.destroy();
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
'<ul id="red-ui-editor-type-json-tabs"></ul>'+
|
||||
'<div id="red-ui-editor-type-json-tab-raw" class="red-ui-editor-type-json-tab-content hide">'+
|
||||
'<div class="form-row" style="margin-bottom: 3px; text-align: right;">'+
|
||||
'<button id="node-input-json-reformat" class="red-ui-button red-ui-button-small"><span data-i18n="jsonEditor.format"></span></button>'+
|
||||
'<span class="button-group">'+
|
||||
'<button id="node-input-json-reformat" class="red-ui-button red-ui-button-small"><span data-i18n="jsonEditor.format"></span></button>'+
|
||||
'<span class="button-group">'+
|
||||
'</div>'+
|
||||
'<div class="form-row node-text-editor-row">'+
|
||||
'<div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div>'+
|
||||
@@ -34,7 +36,7 @@
|
||||
|
||||
var activeTab;
|
||||
|
||||
function insertNewItem(parent,index,copyIndex) {
|
||||
function insertNewItem(parent,index,copyIndex,readOnly) {
|
||||
var newValue = "";
|
||||
|
||||
if (parent.children.length > 0) {
|
||||
@@ -60,26 +62,26 @@
|
||||
newKey = keyRoot+"-"+(keySuffix++);
|
||||
}
|
||||
}
|
||||
var newItem = handleItem(newKey,newValue,parent.depth+1,parent);
|
||||
var newItem = handleItem(newKey,newValue,parent.depth+1,parent,readOnly);
|
||||
parent.treeList.insertChildAt(newItem, index, true);
|
||||
parent.treeList.expand();
|
||||
}
|
||||
function showObjectMenu(button,item) {
|
||||
function showObjectMenu(button,item,readOnly) {
|
||||
var elementPos = button.offset();
|
||||
var options = [];
|
||||
if (item.parent) {
|
||||
options.push({id:"red-ui-editor-type-json-menu-insert-above", icon:"fa fa-toggle-up", label:RED._('jsonEditor.insertAbove'),onselect:function(){
|
||||
var index = item.parent.children.indexOf(item);
|
||||
insertNewItem(item.parent,index,index);
|
||||
insertNewItem(item.parent,index,index,readOnly);
|
||||
}});
|
||||
options.push({id:"red-ui-editor-type-json-menu-insert-below", icon:"fa fa-toggle-down", label:RED._('jsonEditor.insertBelow'),onselect:function(){
|
||||
var index = item.parent.children.indexOf(item)+1;
|
||||
insertNewItem(item.parent,index,index-1);
|
||||
insertNewItem(item.parent,index,index-1,readOnly);
|
||||
}});
|
||||
}
|
||||
if (item.type === 'array' || item.type === 'object') {
|
||||
options.push({id:"red-ui-editor-type-json-menu-add-child", icon:"fa fa-plus", label:RED._('jsonEditor.addItem'),onselect:function(){
|
||||
insertNewItem(item,item.children.length,item.children.length-1);
|
||||
insertNewItem(item,item.children.length,item.children.length-1,readOnly);
|
||||
}});
|
||||
}
|
||||
if (item.parent) {
|
||||
@@ -121,7 +123,7 @@
|
||||
newKey = keyRoot+"-"+(keySuffix++);
|
||||
}
|
||||
}
|
||||
var newItem = handleItem(newKey,convertToObject(item),item.parent.depth+1,item.parent);
|
||||
var newItem = handleItem(newKey,convertToObject(item),item.parent.depth+1,item.parent,readOnly);
|
||||
var index = item.parent.children.indexOf(item)+1;
|
||||
|
||||
item.parent.treeList.insertChildAt(newItem, index, true);
|
||||
@@ -171,24 +173,24 @@
|
||||
menuOptionMenu.show();
|
||||
}
|
||||
|
||||
function parseObject(obj,depth,parent) {
|
||||
function parseObject(obj,depth,parent,readOnly) {
|
||||
var result = [];
|
||||
for (var prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
result.push(handleItem(prop,obj[prop],depth,parent));
|
||||
result.push(handleItem(prop,obj[prop],depth,parent,readOnly));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function parseArray(obj,depth,parent) {
|
||||
function parseArray(obj,depth,parent,readOnly) {
|
||||
var result = [];
|
||||
var l = obj.length;
|
||||
for (var i=0;i<l;i++) {
|
||||
result.push(handleItem(i,obj[i],depth,parent));
|
||||
result.push(handleItem(i,obj[i],depth,parent,readOnly));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function handleItem(key,val,depth,parent) {
|
||||
function handleItem(key,val,depth,parent,readOnly) {
|
||||
var item = {depth:depth, type: typeof val};
|
||||
var container = $('<span class="red-ui-editor-type-json-editor-label">');
|
||||
if (key != null) {
|
||||
@@ -204,11 +206,14 @@
|
||||
if (parent && parent.type === "array") {
|
||||
keyLabel.addClass("red-ui-editor-type-json-editor-label-array-key")
|
||||
}
|
||||
|
||||
if(readOnly) {
|
||||
keyLabel.addClass("readonly")
|
||||
}
|
||||
keyLabel.on("click", function(evt) {
|
||||
if (item.parent.type === 'array') {
|
||||
return;
|
||||
}
|
||||
if (readOnly) { return; }
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
var w = Math.max(150,keyLabel.width());
|
||||
@@ -253,10 +258,10 @@
|
||||
item.expanded = depth < 2;
|
||||
item.type = "array";
|
||||
item.deferBuild = depth >= 2;
|
||||
item.children = parseArray(val,depth+1,item);
|
||||
item.children = parseArray(val,depth+1,item,readOnly);
|
||||
} else if (val !== null && item.type === "object") {
|
||||
item.expanded = depth < 2;
|
||||
item.children = parseObject(val,depth+1,item);
|
||||
item.children = parseObject(val,depth+1,item,readOnly);
|
||||
item.deferBuild = depth >= 2;
|
||||
} else {
|
||||
item.value = val;
|
||||
@@ -287,7 +292,11 @@
|
||||
//
|
||||
var orphanedChildren;
|
||||
var valueLabel = $('<span class="red-ui-editor-type-json-editor-label-value">').addClass(valClass).text(valValue).appendTo(container);
|
||||
if (readOnly) {
|
||||
valueLabel.addClass("readonly")
|
||||
}
|
||||
valueLabel.on("click", function(evt) {
|
||||
if (readOnly) { return; }
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (valType === 'str') {
|
||||
@@ -302,8 +311,8 @@
|
||||
types:[
|
||||
'str','num','bool',
|
||||
{value:"null",label:RED._("common.type.null"),hasValue:false},
|
||||
{value:"array",label:RED._("common.type.array"),hasValue:false,icon:"red/images/typedInput/json.png"},
|
||||
{value:"object",label:RED._("common.type.object"),hasValue:false,icon:"red/images/typedInput/json.png"}
|
||||
{value:"array",label:RED._("common.type.array"),hasValue:false,icon:"red/images/typedInput/json.svg"},
|
||||
{value:"object",label:RED._("common.type.object"),hasValue:false,icon:"red/images/typedInput/json.svg"}
|
||||
],
|
||||
default: valType
|
||||
});
|
||||
@@ -395,17 +404,19 @@
|
||||
valueLabel.hide();
|
||||
})
|
||||
item.gutter = $('<span class="red-ui-editor-type-json-editor-item-gutter"></span>');
|
||||
|
||||
if (parent) {//red-ui-editor-type-json-editor-item-handle
|
||||
$('<span class="red-ui-editor-type-json-editor-item-handle"><i class="fa fa-bars"></span>').appendTo(item.gutter);
|
||||
} else {
|
||||
$('<span></span>').appendTo(item.gutter);
|
||||
if(!readOnly) {
|
||||
if (parent) {
|
||||
$('<span class="red-ui-editor-type-json-editor-item-handle"><i class="fa fa-bars"></span>').appendTo(item.gutter);
|
||||
} else {
|
||||
$('<span></span>').appendTo(item.gutter);
|
||||
}
|
||||
$('<button type="button" class="editor-button editor-button-small"><i class="fa fa-caret-down"></button>').appendTo(item.gutter).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
showObjectMenu($(this), item, readOnly);
|
||||
});
|
||||
}
|
||||
$('<button type="button" class="editor-button editor-button-small"><i class="fa fa-caret-down"></button>').appendTo(item.gutter).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
showObjectMenu($(this), item);
|
||||
});
|
||||
|
||||
item.element = container;
|
||||
return item;
|
||||
}
|
||||
@@ -434,6 +445,7 @@
|
||||
var definition = {
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onCancel = options.cancel;
|
||||
var onComplete = options.complete;
|
||||
var type = "_json"
|
||||
if ($("script[data-template-name='"+type+"']").length === 0) {
|
||||
@@ -455,15 +467,16 @@
|
||||
}
|
||||
}
|
||||
var rootNode;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
focusElement: options.focusElement,
|
||||
width: options.width||700,
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
if (onCancel) { onCancel(); }
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
@@ -485,7 +498,8 @@
|
||||
} else if (activeTab === "json-raw") {
|
||||
result = expressionEditor.getValue();
|
||||
}
|
||||
if (onComplete) { onComplete(result) }
|
||||
expressionEditor.saveView();
|
||||
if (onComplete) { onComplete(result,null,expressionEditor) }
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
@@ -498,10 +512,29 @@
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.red-ui-tray-body'),'dialog-form',type,'editor');
|
||||
|
||||
var toolbarButtons = options.toolbarButtons || [];
|
||||
if (toolbarButtons.length) {
|
||||
toolbarButtons.forEach(function (button) {
|
||||
var element = $('<button type="button" class="red-ui-button red-ui-button-small"> </button>')
|
||||
.insertBefore("#node-input-json-reformat")
|
||||
.on("click", function (evt) {
|
||||
evt.preventDefault();
|
||||
if (button.click !== undefined) {
|
||||
button.click.call(element, evt);
|
||||
}
|
||||
});
|
||||
if (button.id) { element.attr("id", button.id); }
|
||||
if (button.title) { element.attr("title", button.title); }
|
||||
if (button.icon) { element.append($("<i></i>").attr("class", button.icon)); }
|
||||
if (button.label || button.text) {
|
||||
element.append($("<span></span>").text(" " + (button.label || button.text)));
|
||||
}
|
||||
});
|
||||
}
|
||||
var container = $("#red-ui-editor-type-json-tab-ui-container").css({"height":"100%"});
|
||||
var filterDepth = Infinity;
|
||||
var list = $('<div class="red-ui-debug-msg-payload red-ui-editor-type-json-editor">').appendTo(container).treeList({
|
||||
selectable: false,
|
||||
rootSortable: false,
|
||||
sortable: ".red-ui-editor-type-json-editor-item-handle",
|
||||
}).on("treelistchangeparent", function(event, evt) {
|
||||
@@ -528,13 +561,15 @@
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-json',
|
||||
value: "",
|
||||
mode:"ace/mode/json"
|
||||
value: value||"",
|
||||
mode:"ace/mode/json",
|
||||
readOnly: !!options.readOnly,
|
||||
stateId: options.stateId,
|
||||
focus: true
|
||||
});
|
||||
expressionEditor.getSession().setValue(value||"",-1);
|
||||
|
||||
if (options.requireValid) {
|
||||
expressionEditor.getSession().on('change', function() {
|
||||
clearTimeout(changeTimer);
|
||||
@@ -571,7 +606,7 @@
|
||||
var raw = expressionEditor.getValue().trim() ||"{}";
|
||||
try {
|
||||
var parsed = JSON.parse(raw);
|
||||
rootNode = handleItem(null,parsed,0,null);
|
||||
rootNode = handleItem(null,parsed,0,null,options.readOnly);
|
||||
rootNode.class = "red-ui-editor-type-json-root-node"
|
||||
list.treeList('data',[rootNode]);
|
||||
} catch(err) {
|
||||
@@ -589,17 +624,15 @@
|
||||
|
||||
tabs.addTab({
|
||||
id: 'json-raw',
|
||||
label: RED._('jsonEditor.rawMode'),
|
||||
label: options.readOnly ? RED._('jsonEditor.rawMode-readonly') : RED._('jsonEditor.rawMode'),
|
||||
content: $("#red-ui-editor-type-json-tab-raw")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: 'json-ui',
|
||||
label: RED._('jsonEditor.uiMode'),
|
||||
label: options.readOnly ? RED._('jsonEditor.uiMode-readonly') : RED._('jsonEditor.uiMode'),
|
||||
content: $("#red-ui-editor-type-json-tab-ui")
|
||||
});
|
||||
finishedBuild = true;
|
||||
|
||||
|
||||
},
|
||||
close: function() {
|
||||
if (options.onclose) {
|
||||
|
||||
@@ -54,24 +54,26 @@
|
||||
var definition = {
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onCancel = options.cancel;
|
||||
var onComplete = options.complete;
|
||||
var type = "_markdown"
|
||||
if ($("script[data-template-name='"+type+"']").length === 0) {
|
||||
$(template).appendTo("#red-ui-editor-node-configs");
|
||||
}
|
||||
|
||||
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
focusElement: options.focusElement,
|
||||
width: options.width||Infinity,
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
if (onCancel) { onCancel(); }
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
@@ -80,7 +82,8 @@
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(expressionEditor.getValue(),expressionEditor.getCursorPosition());
|
||||
expressionEditor.saveView();
|
||||
if (onComplete) { onComplete(expressionEditor.getValue(),expressionEditor.getCursorPosition(), expressionEditor); }
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
@@ -99,6 +102,8 @@
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'red-ui-editor-type-markdown',
|
||||
value: value,
|
||||
stateId: options.stateId,
|
||||
focus: true,
|
||||
mode:"ace/mode/markdown",
|
||||
expandable: false
|
||||
});
|
||||
@@ -143,17 +148,17 @@
|
||||
});
|
||||
RED.popover.tooltip($("#node-btn-markdown-preview"), RED._("markdownEditor.toggle-preview"));
|
||||
|
||||
if (options.cursor) {
|
||||
if (options.cursor && !expressionEditor._initState) {
|
||||
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
||||
}
|
||||
|
||||
dialogForm.i18n();
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
expressionEditor.destroy();
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
@@ -168,7 +173,7 @@
|
||||
'b': { before:"**", after: "**", tooltip: RED._("markdownEditor.bold")},
|
||||
'i': { before:"_", after: "_", tooltip: RED._("markdownEditor.italic")},
|
||||
'code': { before:"`", after: "`", tooltip: RED._("markdownEditor.code")},
|
||||
'ol': { before:" * ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
|
||||
'ol': { before:" 1. ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
|
||||
'ul': { before:" - ", newline: true, tooltip: RED._("markdownEditor.unordered-list")},
|
||||
'bq': { before:"> ", newline: true, tooltip: RED._("markdownEditor.quote")},
|
||||
'link': { before:"[", after: "]()", tooltip: RED._("markdownEditor.link")},
|
||||
|
||||
530
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/appearance.js
vendored
Normal file
530
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/appearance.js
vendored
Normal file
@@ -0,0 +1,530 @@
|
||||
;(function() {
|
||||
|
||||
RED.editor.registerEditPane("editor-tab-appearance", function(node) {
|
||||
return {
|
||||
label: RED._("editor-tab.appearance"),
|
||||
name: RED._("editor-tab.appearance"),
|
||||
iconClass: "fa fa-object-group",
|
||||
create: function(container) {
|
||||
this.content = container;
|
||||
buildAppearanceForm(this.content,node);
|
||||
|
||||
if (node.type === 'subflow') {
|
||||
this.defaultIcon = "node-red/subflow.svg";
|
||||
} else {
|
||||
var iconPath = RED.utils.getDefaultNodeIcon(node._def,node);
|
||||
this.defaultIcon = iconPath.module+"/"+iconPath.file;
|
||||
if (node.icon && node.icon !== this.defaultIcon) {
|
||||
this.isDefaultIcon = false;
|
||||
} else {
|
||||
this.isDefaultIcon = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
resize: function(size) {
|
||||
|
||||
},
|
||||
close: function() {
|
||||
|
||||
},
|
||||
show: function() {
|
||||
refreshLabelForm(this.content, node);
|
||||
},
|
||||
apply: function(editState) {
|
||||
if (updateLabels(node, editState.changes, editState.outputMap)) {
|
||||
editState.changed = true;
|
||||
}
|
||||
if (!node._def.defaults || !node._def.defaults.hasOwnProperty("icon")) {
|
||||
var icon = $("#red-ui-editor-node-icon").val()||"";
|
||||
if (!this.isDefaultIcon) {
|
||||
if ((icon !== node.icon) &&
|
||||
(icon !== "")) {
|
||||
editState.changes.icon = node.icon;
|
||||
node.icon = icon;
|
||||
editState.changed = true;
|
||||
}
|
||||
} else {
|
||||
if (icon !== "" && icon !== this.defaultIcon) {
|
||||
editState.changes.icon = node.icon;
|
||||
node.icon = icon;
|
||||
editState.changed = true;
|
||||
} else {
|
||||
var iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
|
||||
var currentDefaultIcon = iconPath.module+"/"+iconPath.file;
|
||||
if (this.defaultIcon !== currentDefaultIcon) {
|
||||
editState.changes.icon = node.icon;
|
||||
node.icon = currentDefaultIcon;
|
||||
editState.changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node.type === "subflow") {
|
||||
var newCategory = $("#subflow-appearance-input-category").val().trim();
|
||||
if (newCategory === "_custom_") {
|
||||
newCategory = $("#subflow-appearance-input-custom-category").val().trim();
|
||||
if (newCategory === "") {
|
||||
newCategory = node.category;
|
||||
}
|
||||
}
|
||||
if (newCategory === 'subflows') {
|
||||
newCategory = '';
|
||||
}
|
||||
if (newCategory != node.category) {
|
||||
editState.changes['category'] = node.category;
|
||||
node.category = newCategory;
|
||||
editState.changed = true;
|
||||
}
|
||||
|
||||
var oldColor = node.color;
|
||||
var newColor = $("#red-ui-editor-node-color").val();
|
||||
if (oldColor !== newColor) {
|
||||
editState.changes.color = node.color;
|
||||
node.color = newColor;
|
||||
editState.changed = true;
|
||||
RED.utils.clearNodeColorCache();
|
||||
if (node.type === "subflow") {
|
||||
var nodeDefinition = RED.nodes.getType(
|
||||
"subflow:" + node.id
|
||||
);
|
||||
nodeDefinition["color"] = newColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
var showLabel = node._def.hasOwnProperty("showLabel")?node._def.showLabel:true;
|
||||
|
||||
if (!$("#node-input-show-label").prop('checked')) {
|
||||
// Not checked - hide label
|
||||
|
||||
if (showLabel) {
|
||||
// Default to show label
|
||||
if (node.l !== false) {
|
||||
editState.changes.l = node.l;
|
||||
editState.changed = true;
|
||||
}
|
||||
node.l = false;
|
||||
} else {
|
||||
// Node has showLabel:false (eg link nodes)
|
||||
if (node.hasOwnProperty('l') && node.l) {
|
||||
editState.changes.l = node.l;
|
||||
editState.changed = true;
|
||||
}
|
||||
delete node.l;
|
||||
}
|
||||
} else {
|
||||
// Checked - show label
|
||||
if (showLabel) {
|
||||
// Default to show label
|
||||
if (node.hasOwnProperty('l') && !node.l) {
|
||||
editState.changes.l = node.l;
|
||||
editState.changed = true;
|
||||
}
|
||||
delete node.l;
|
||||
} else {
|
||||
if (!node.l) {
|
||||
editState.changes.l = node.l;
|
||||
editState.changed = true;
|
||||
}
|
||||
node.l = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function buildAppearanceForm(container,node) {
|
||||
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
|
||||
|
||||
var i,row;
|
||||
|
||||
if (node.type === "subflow") {
|
||||
var categoryRow = $("<div/>", {
|
||||
class: "form-row"
|
||||
}).appendTo(dialogForm);
|
||||
$("<label/>", {
|
||||
for: "subflow-appearance-input-category",
|
||||
"data-i18n": "editor:subflow.category"
|
||||
}).appendTo(categoryRow);
|
||||
var categorySelector = $("<select/>", {
|
||||
id: "subflow-appearance-input-category"
|
||||
}).css({
|
||||
width: "250px"
|
||||
}).appendTo(categoryRow);
|
||||
$("<input/>", {
|
||||
type: "text",
|
||||
id: "subflow-appearance-input-custom-category"
|
||||
}).css({
|
||||
display: "none",
|
||||
"margin-left": "10px",
|
||||
width: "calc(100% - 250px)"
|
||||
}).appendTo(categoryRow);
|
||||
|
||||
var categories = RED.palette.getCategories();
|
||||
categories.sort(function(A,B) {
|
||||
return A.label.localeCompare(B.label);
|
||||
});
|
||||
categories.forEach(function(cat) {
|
||||
categorySelector.append($("<option/>").val(cat.id).text(cat.label));
|
||||
});
|
||||
categorySelector.append($("<option/>").attr('disabled',true).text("---"));
|
||||
categorySelector.append($("<option/>").val("_custom_").text(RED._("palette.addCategory")));
|
||||
|
||||
$("#subflow-appearance-input-category").on("change", function() {
|
||||
var val = $(this).val();
|
||||
if (val === "_custom_") {
|
||||
$("#subflow-appearance-input-category").width(120);
|
||||
$("#subflow-appearance-input-custom-category").show();
|
||||
} else {
|
||||
$("#subflow-appearance-input-category").width(250);
|
||||
$("#subflow-appearance-input-custom-category").hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#subflow-appearance-input-category").val(node.category||"subflows");
|
||||
var userCount = 0;
|
||||
var subflowType = "subflow:"+node.id;
|
||||
|
||||
// RED.nodes.eachNode(function(n) {
|
||||
// if (n.type === subflowType) {
|
||||
// userCount++;
|
||||
// }
|
||||
// });
|
||||
$("#red-ui-editor-subflow-user-count")
|
||||
.text(RED._("subflow.subflowInstances", {count:node.instances.length})).show();
|
||||
}
|
||||
|
||||
$('<div class="form-row">'+
|
||||
'<label for="node-input-show-label-btn" data-i18n="editor.label"></label>'+
|
||||
'<span style="margin-right: 2px;"/>'+
|
||||
'<input type="checkbox" id="node-input-show-label"/>'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
|
||||
$("#node-input-show-label").toggleButton({
|
||||
enabledLabel: RED._("editor.show"),
|
||||
disabledLabel: RED._("editor.hide")
|
||||
});
|
||||
|
||||
if (!node.hasOwnProperty("l")) {
|
||||
// Show label unless def.showLabel set to false
|
||||
node.l = node._def.hasOwnProperty("showLabel")?node._def.showLabel:true;
|
||||
}
|
||||
$("#node-input-show-label").prop("checked",node.l).trigger("change");
|
||||
|
||||
if (node.type === "subflow") {
|
||||
// subflow template can select its color
|
||||
var color = node.color ? node.color : "#DDAA99";
|
||||
var colorRow = $("<div/>", {
|
||||
class: "form-row"
|
||||
}).appendTo(dialogForm);
|
||||
$("<label/>").text(RED._("editor.color")).appendTo(colorRow);
|
||||
|
||||
var recommendedColors = [
|
||||
"#DDAA99",
|
||||
"#3FADB5", "#87A980", "#A6BBCF",
|
||||
"#AAAA66", "#C0C0C0", "#C0DEED",
|
||||
"#C7E9C0", "#D7D7A0", "#D8BFD8",
|
||||
"#DAC4B4", "#DEB887", "#DEBD5C",
|
||||
"#E2D96E", "#E6E0F8", "#E7E7AE",
|
||||
"#E9967A", "#F3B567", "#FDD0A2",
|
||||
"#FDF0C2", "#FFAAAA", "#FFCC66",
|
||||
"#FFF0F0", "#FFFFFF"
|
||||
];
|
||||
|
||||
RED.editor.colorPicker.create({
|
||||
id: "red-ui-editor-node-color",
|
||||
value: color,
|
||||
palette: recommendedColors,
|
||||
sortPalette: function (a, b) {return a.l - b.l;}
|
||||
}).appendTo(colorRow);
|
||||
|
||||
$("#red-ui-editor-node-color").on('change', function(ev) {
|
||||
// Horribly out of scope...
|
||||
var colour = $(this).val();
|
||||
nodeDiv.css('backgroundColor',colour);
|
||||
var borderColor = RED.utils.getDarkerColor(colour);
|
||||
if (borderColor !== colour) {
|
||||
nodeDiv.css('border-color',borderColor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// If a node has icon property in defaults, the icon of the node cannot be modified. (e.g, ui_button node in dashboard)
|
||||
if ((!node._def.defaults || !node._def.defaults.hasOwnProperty("icon"))) {
|
||||
var iconRow = $('<div class="form-row"></div>').appendTo(dialogForm);
|
||||
$('<label data-i18n="editor.settingIcon">').appendTo(iconRow);
|
||||
|
||||
var iconButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(iconRow);
|
||||
$('<i class="fa fa-caret-down"></i>').appendTo(iconButton);
|
||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconButton);
|
||||
var colour = RED.utils.getNodeColor(node.type, node._def);
|
||||
var icon_url = RED.utils.getNodeIcon(node._def,node);
|
||||
nodeDiv.css('backgroundColor',colour);
|
||||
var borderColor = RED.utils.getDarkerColor(colour);
|
||||
if (borderColor !== colour) {
|
||||
nodeDiv.css('border-color',borderColor);
|
||||
}
|
||||
|
||||
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
||||
RED.utils.createIconElement(icon_url, iconContainer, true);
|
||||
|
||||
iconButton.on("click", function(e) {
|
||||
e.preventDefault();
|
||||
var iconPath;
|
||||
var icon = $("#red-ui-editor-node-icon").val()||"";
|
||||
if (icon) {
|
||||
iconPath = RED.utils.separateIconPath(icon);
|
||||
} else {
|
||||
iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
|
||||
}
|
||||
var backgroundColor = RED.utils.getNodeColor(node.type, node._def);
|
||||
if (node.type === "subflow") {
|
||||
backgroundColor = $("#red-ui-editor-node-color").val();
|
||||
}
|
||||
RED.editor.iconPicker.show(iconButton,backgroundColor,iconPath,false,function(newIcon) {
|
||||
$("#red-ui-editor-node-icon").val(newIcon||"");
|
||||
var icon_url = RED.utils.getNodeIcon(node._def,{type:node.type,icon:newIcon});
|
||||
RED.utils.createIconElement(icon_url, iconContainer, true);
|
||||
});
|
||||
});
|
||||
|
||||
RED.popover.tooltip(iconButton, function() {
|
||||
return $("#red-ui-editor-node-icon").val() || RED._("editor.default");
|
||||
});
|
||||
$('<input type="hidden" id="red-ui-editor-node-icon">').val(node.icon).appendTo(iconRow);
|
||||
}
|
||||
|
||||
|
||||
$('<div class="form-row"><span data-i18n="editor.portLabels"></span></div>').appendTo(dialogForm);
|
||||
|
||||
var inputCount = node.inputs || node._def.inputs || 0;
|
||||
var outputCount = node.outputs || node._def.outputs || 0;
|
||||
if (node.type === 'subflow') {
|
||||
inputCount = node.in.length;
|
||||
outputCount = node.out.length;
|
||||
}
|
||||
|
||||
var inputLabels = node.inputLabels || [];
|
||||
var outputLabels = node.outputLabels || [];
|
||||
|
||||
var inputPlaceholder = node._def.inputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
|
||||
var outputPlaceholder = node._def.outputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
|
||||
|
||||
$('<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelInputs"></span><div id="red-ui-editor-node-label-form-inputs"></div></div>').appendTo(dialogForm);
|
||||
var inputsDiv = $("#red-ui-editor-node-label-form-inputs");
|
||||
if (inputCount > 0) {
|
||||
for (i=0;i<inputCount;i++) {
|
||||
buildLabelRow("input",i,inputLabels[i],inputPlaceholder).appendTo(inputsDiv);
|
||||
}
|
||||
} else {
|
||||
buildLabelRow().appendTo(inputsDiv);
|
||||
}
|
||||
$('<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelOutputs"></span><div id="red-ui-editor-node-label-form-outputs"></div></div>').appendTo(dialogForm);
|
||||
var outputsDiv = $("#red-ui-editor-node-label-form-outputs");
|
||||
if (outputCount > 0) {
|
||||
for (i=0;i<outputCount;i++) {
|
||||
buildLabelRow("output",i,outputLabels[i],outputPlaceholder).appendTo(outputsDiv);
|
||||
}
|
||||
} else {
|
||||
buildLabelRow().appendTo(outputsDiv);
|
||||
}
|
||||
}
|
||||
|
||||
function refreshLabelForm(container,node) {
|
||||
|
||||
var inputPlaceholder = node._def.inputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
|
||||
var outputPlaceholder = node._def.outputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
|
||||
|
||||
var inputsDiv = $("#red-ui-editor-node-label-form-inputs");
|
||||
var outputsDiv = $("#red-ui-editor-node-label-form-outputs");
|
||||
|
||||
var inputCount;
|
||||
var formInputs = $("#node-input-inputs").val();
|
||||
if (formInputs === undefined) {
|
||||
if (node.type === 'subflow') {
|
||||
inputCount = node.in.length;
|
||||
} else {
|
||||
inputCount = node.inputs || node._def.inputs || 0;
|
||||
}
|
||||
} else {
|
||||
inputCount = Math.min(1,Math.max(0,parseInt(formInputs)));
|
||||
if (isNaN(inputCount)) {
|
||||
inputCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var children = inputsDiv.children();
|
||||
var childCount = children.length;
|
||||
if (childCount === 1 && $(children[0]).hasClass('red-ui-editor-node-label-form-none')) {
|
||||
childCount--;
|
||||
}
|
||||
|
||||
if (childCount < inputCount) {
|
||||
if (childCount === 0) {
|
||||
// remove the 'none' placeholder
|
||||
$(children[0]).remove();
|
||||
}
|
||||
for (i = childCount;i<inputCount;i++) {
|
||||
buildLabelRow("input",i,"",inputPlaceholder).appendTo(inputsDiv);
|
||||
}
|
||||
} else if (childCount > inputCount) {
|
||||
for (i=inputCount;i<childCount;i++) {
|
||||
$(children[i]).remove();
|
||||
}
|
||||
if (inputCount === 0) {
|
||||
buildLabelRow().appendTo(inputsDiv);
|
||||
}
|
||||
}
|
||||
|
||||
var outputCount;
|
||||
var i;
|
||||
var formOutputs = $("#node-input-outputs").val();
|
||||
|
||||
if (formOutputs === undefined) {
|
||||
if (node.type === 'subflow') {
|
||||
outputCount = node.out.length;
|
||||
} else {
|
||||
inputCount = node.outputs || node._def.outputs || 0;
|
||||
}
|
||||
} else if (isNaN(formOutputs)) {
|
||||
var outputMap = JSON.parse(formOutputs);
|
||||
var keys = Object.keys(outputMap);
|
||||
children = outputsDiv.children();
|
||||
childCount = children.length;
|
||||
if (childCount === 1 && $(children[0]).hasClass('red-ui-editor-node-label-form-none')) {
|
||||
childCount--;
|
||||
}
|
||||
|
||||
outputCount = 0;
|
||||
var rows = [];
|
||||
keys.forEach(function(p) {
|
||||
var row = $("#red-ui-editor-node-label-form-output-"+p).parent();
|
||||
if (row.length === 0 && outputMap[p] !== -1) {
|
||||
if (childCount === 0) {
|
||||
$(children[0]).remove();
|
||||
childCount = -1;
|
||||
}
|
||||
row = buildLabelRow("output",p,"",outputPlaceholder);
|
||||
} else {
|
||||
row.detach();
|
||||
}
|
||||
if (outputMap[p] !== -1) {
|
||||
outputCount++;
|
||||
rows.push({i:parseInt(outputMap[p]),r:row});
|
||||
}
|
||||
});
|
||||
rows.sort(function(A,B) {
|
||||
return A.i-B.i;
|
||||
});
|
||||
rows.forEach(function(r,i) {
|
||||
r.r.find("label").text((i+1)+".");
|
||||
r.r.appendTo(outputsDiv);
|
||||
});
|
||||
if (rows.length === 0) {
|
||||
buildLabelRow("output",i,"").appendTo(outputsDiv);
|
||||
} else {
|
||||
|
||||
}
|
||||
} else {
|
||||
outputCount = Math.max(0,parseInt(formOutputs));
|
||||
}
|
||||
children = outputsDiv.children();
|
||||
childCount = children.length;
|
||||
if (childCount === 1 && $(children[0]).hasClass('red-ui-editor-node-label-form-none')) {
|
||||
childCount--;
|
||||
}
|
||||
if (childCount < outputCount) {
|
||||
if (childCount === 0) {
|
||||
// remove the 'none' placeholder
|
||||
$(children[0]).remove();
|
||||
}
|
||||
for (i = childCount;i<outputCount;i++) {
|
||||
buildLabelRow("output",i,"").appendTo(outputsDiv);
|
||||
}
|
||||
} else if (childCount > outputCount) {
|
||||
for (i=outputCount;i<childCount;i++) {
|
||||
$(children[i]).remove();
|
||||
}
|
||||
if (outputCount === 0) {
|
||||
buildLabelRow().appendTo(outputsDiv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildLabelRow(type, index, value, placeHolder) {
|
||||
var result = $('<div>',{class:"red-ui-editor-node-label-form-row"});
|
||||
if (type === undefined) {
|
||||
$('<span>').text(RED._("editor.noDefaultLabel")).appendTo(result);
|
||||
result.addClass("red-ui-editor-node-label-form-none");
|
||||
} else {
|
||||
result.addClass("");
|
||||
var id = "red-ui-editor-node-label-form-"+type+"-"+index;
|
||||
$('<label>',{for:id}).text((index+1)+".").appendTo(result);
|
||||
var input = $('<input>',{type:"text",id:id, placeholder: placeHolder}).val(value).appendTo(result);
|
||||
var clear = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-times"></i></button>').appendTo(result);
|
||||
clear.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
input.val("");
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function updateLabels(node, changes, outputMap) {
|
||||
var inputLabels = $("#red-ui-editor-node-label-form-inputs").children().find("input");
|
||||
var outputLabels = $("#red-ui-editor-node-label-form-outputs").children().find("input");
|
||||
|
||||
var hasNonBlankLabel = false;
|
||||
var changed = false;
|
||||
var newValue = inputLabels.map(function() {
|
||||
var v = $(this).val();
|
||||
hasNonBlankLabel = hasNonBlankLabel || v!== "";
|
||||
return v;
|
||||
}).toArray().slice(0,node.inputs);
|
||||
if ((node.inputLabels === undefined && hasNonBlankLabel) ||
|
||||
(node.inputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(node.inputLabels))) {
|
||||
changes.inputLabels = node.inputLabels;
|
||||
node.inputLabels = newValue;
|
||||
changed = true;
|
||||
}
|
||||
hasNonBlankLabel = false;
|
||||
newValue = new Array(node.outputs);
|
||||
outputLabels.each(function() {
|
||||
var index = $(this).attr('id').substring("red-ui-editor-node-label-form-output-".length);
|
||||
if (outputMap && outputMap.hasOwnProperty(index)) {
|
||||
index = parseInt(outputMap[index]);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var v = $(this).val();
|
||||
hasNonBlankLabel = hasNonBlankLabel || v!== "";
|
||||
|
||||
// mark changed output port labels as dirty
|
||||
if (node.type === "subflow" && (!node.outputLabels || node.outputLabels[index] !== v)) {
|
||||
node.out[index].dirty = true;
|
||||
}
|
||||
|
||||
newValue[index] = v;
|
||||
});
|
||||
|
||||
if ((node.outputLabels === undefined && hasNonBlankLabel) ||
|
||||
(node.outputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(node.outputLabels))) {
|
||||
changes.outputLabels = node.outputLabels;
|
||||
node.outputLabels = newValue;
|
||||
changed = true;
|
||||
|
||||
// trigger redraw of dirty port labels
|
||||
if (node.type === "subflow") {
|
||||
RED.view.redraw();
|
||||
}
|
||||
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
67
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/description.js
vendored
Normal file
67
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/description.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
;(function() {
|
||||
|
||||
RED.editor.registerEditPane("editor-tab-description", function(node) {
|
||||
return {
|
||||
label: RED._("editor-tab.description"),
|
||||
name: RED._("editor-tab.description"),
|
||||
iconClass: "fa fa-file-text-o",
|
||||
|
||||
create: function(container) {
|
||||
this.editor = buildDescriptionForm(container,node);
|
||||
},
|
||||
resize: function(size) {
|
||||
this.editor.resize();
|
||||
},
|
||||
close: function() {
|
||||
this.editor.destroy();
|
||||
this.editor = null;
|
||||
},
|
||||
show: function() {
|
||||
this.editor.focus();
|
||||
},
|
||||
apply: function(editState) {
|
||||
var oldInfo = node.info;
|
||||
var newInfo = this.editor.getValue();
|
||||
if (!!oldInfo) {
|
||||
// Has existing info property
|
||||
if (newInfo.trim() === "") {
|
||||
// New value is blank - remove the property
|
||||
editState.changed = true;
|
||||
editState.changes.info = oldInfo;
|
||||
delete node.info;
|
||||
} else if (newInfo !== oldInfo) {
|
||||
// New value is different
|
||||
editState.changed = true;
|
||||
editState.changes.info = oldInfo;
|
||||
node.info = newInfo;
|
||||
}
|
||||
} else {
|
||||
// No existing info
|
||||
if (newInfo.trim() !== "") {
|
||||
// New value is not blank
|
||||
editState.changed = true;
|
||||
editState.changes.info = undefined;
|
||||
node.info = newInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function buildDescriptionForm(container,node) {
|
||||
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
|
||||
var toolbarRow = $('<div></div>').appendTo(dialogForm);
|
||||
var row = $('<div class="form-row node-text-editor-row" style="position:relative; padding-top: 4px; height: 100%"></div>').appendTo(dialogForm);
|
||||
var editorId = "node-info-input-info-editor-"+Math.floor(1000*Math.random());
|
||||
$('<div style="height: 100%" class="node-text-editor" id="'+editorId+'" ></div>').appendTo(row);
|
||||
var nodeInfoEditor = RED.editor.createEditor({
|
||||
id: editorId,
|
||||
mode: 'ace/mode/markdown',
|
||||
stateId: RED.editor.generateViewStateId("node", node, "nodeinfo"),
|
||||
value: node.info || ""
|
||||
});
|
||||
node.infoEditor = nodeInfoEditor;
|
||||
return nodeInfoEditor;
|
||||
}
|
||||
|
||||
})();
|
||||
75
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/envVarProperties.js
vendored
Normal file
75
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/envVarProperties.js
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
;(function() {
|
||||
|
||||
RED.editor.registerEditPane("editor-tab-envProperties", function(node) {
|
||||
return {
|
||||
label: RED._("editor-tab.envProperties"),
|
||||
name: RED._("editor-tab.envProperties"),
|
||||
iconClass: "fa fa-list",
|
||||
create: function(container) {
|
||||
var form = $('<form class="dialog-form form-horizontal"></form>').appendTo(container);
|
||||
var listContainer = $('<div class="form-row node-input-env-container-row"></div>').appendTo(form);
|
||||
this.list = $('<ol></ol>').appendTo(listContainer);
|
||||
RED.editor.envVarList.create(this.list, node);
|
||||
},
|
||||
resize: function(size) {
|
||||
this.list.editableList('height',size.height);
|
||||
},
|
||||
close: function() {
|
||||
|
||||
},
|
||||
apply: function(editState) {
|
||||
var old_env = node.env;
|
||||
var new_env = [];
|
||||
if (/^subflow:/.test(node.type)) {
|
||||
new_env = RED.subflow.exportSubflowInstanceEnv(node);
|
||||
}
|
||||
|
||||
// Get the values from the Properties table tab
|
||||
var items = this.list.editableList('items');
|
||||
items.each(function (i,el) {
|
||||
var data = el.data('data');
|
||||
var item;
|
||||
if (data.nameField && data.valueField) {
|
||||
item = {
|
||||
name: data.nameField.val(),
|
||||
value: data.valueField.typedInput("value"),
|
||||
type: data.valueField.typedInput("type")
|
||||
}
|
||||
if (item.name.trim() !== "") {
|
||||
new_env.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (new_env && new_env.length > 0) {
|
||||
new_env.forEach(function(prop) {
|
||||
if (prop.type === "cred") {
|
||||
node.credentials = node.credentials || {_:{}};
|
||||
node.credentials[prop.name] = prop.value;
|
||||
node.credentials['has_'+prop.name] = (prop.value !== "");
|
||||
if (prop.value !== '__PWRD__') {
|
||||
editState.changed = true;
|
||||
}
|
||||
delete prop.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!old_env && new_env.length === 0) {
|
||||
delete node.env;
|
||||
} else if (!isSameObj(old_env, new_env)) {
|
||||
editState.changes.env = node.env;
|
||||
if (new_env.length === 0) {
|
||||
delete node.env;
|
||||
} else {
|
||||
node.env = new_env;
|
||||
}
|
||||
editState.changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
function isSameObj(env0, env1) {
|
||||
return (JSON.stringify(env0) === JSON.stringify(env1));
|
||||
}
|
||||
})();
|
||||
60
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/flowProperties.js
vendored
Normal file
60
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/flowProperties.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
;(function() {
|
||||
|
||||
RED.editor.registerEditPane("editor-tab-flow-properties", function(node) {
|
||||
return {
|
||||
label: RED._("editor-tab.properties"),
|
||||
name: RED._("editor-tab.properties"),
|
||||
iconClass: "fa fa-cog",
|
||||
create: function(container) {
|
||||
var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(container);
|
||||
$('<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" data-i18n="[placeholder]common.label.name">'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
|
||||
var row = $('<div class="form-row node-text-editor-row">'+
|
||||
'<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+
|
||||
'<div style="min-height:150px;" class="node-text-editor" id="node-input-info"></div>'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
this.tabflowEditor = RED.editor.createEditor({
|
||||
id: 'node-input-info',
|
||||
mode: 'ace/mode/markdown',
|
||||
value: ""
|
||||
});
|
||||
|
||||
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
|
||||
dialogForm.on("submit", function(e) { e.preventDefault();});
|
||||
|
||||
$("#node-input-name").val(node.label);
|
||||
RED.text.bidi.prepareInput($("#node-input-name"));
|
||||
this.tabflowEditor.getSession().setValue(node.info || "", -1);
|
||||
},
|
||||
resize: function(size) {
|
||||
$("#node-input-info").css("height", (size.height-70)+"px");
|
||||
this.tabflowEditor.resize();
|
||||
},
|
||||
close: function() {
|
||||
this.tabflowEditor.destroy();
|
||||
},
|
||||
apply: function(editState) {
|
||||
var label = $( "#node-input-name" ).val();
|
||||
|
||||
if (node.label != label) {
|
||||
editState.changes.label = node.label;
|
||||
editState.changed = true;
|
||||
node.label = label;
|
||||
}
|
||||
|
||||
var info = this.tabflowEditor.getValue();
|
||||
if (node.info !== info) {
|
||||
editState.changes.info = node.info;
|
||||
editState.changed = true;
|
||||
node.info = info;
|
||||
}
|
||||
$("#red-ui-tab-"+(node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!node.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!node.disabled);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
198
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/properties.js
vendored
Normal file
198
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/properties.js
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
;(function() {
|
||||
|
||||
RED.editor.registerEditPane("editor-tab-properties", function(node) {
|
||||
return {
|
||||
label: RED._("editor-tab.properties"),
|
||||
name: RED._("editor-tab.properties"),
|
||||
iconClass: "fa fa-cog",
|
||||
create: function(container) {
|
||||
|
||||
var nodeType = node.type;
|
||||
if (node.type === "subflow") {
|
||||
nodeType = "subflow-template";
|
||||
} else if (node.type.substring(0,8) == "subflow:") {
|
||||
nodeType = "subflow";
|
||||
}
|
||||
|
||||
var i18nNamespace;
|
||||
if (node._def.set.module === "node-red") {
|
||||
i18nNamespace = "node-red";
|
||||
} else {
|
||||
i18nNamespace = node._def.set.id;
|
||||
}
|
||||
|
||||
var formStyle = "dialog-form";
|
||||
this.inputClass = "node-input";
|
||||
if (node._def.category === "config" && nodeType !== "group") {
|
||||
this.inputClass = "node-config-input";
|
||||
formStyle = "node-config-dialog-edit-form";
|
||||
}
|
||||
RED.editor.buildEditForm(container,formStyle,nodeType,i18nNamespace,node);
|
||||
},
|
||||
resize: function(size) {
|
||||
if (node && node._def.oneditresize) {
|
||||
try {
|
||||
node._def.oneditresize.call(node,size);
|
||||
} catch(err) {
|
||||
console.log("oneditresize",node.id,node.type,err.toString());
|
||||
}
|
||||
}
|
||||
},
|
||||
close: function() {
|
||||
|
||||
},
|
||||
apply: function(editState) {
|
||||
var newValue;
|
||||
var d;
|
||||
if (node._def.defaults) {
|
||||
for (d in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d)) {
|
||||
var input = $("#"+this.inputClass+"-"+d);
|
||||
if (input.attr('type') === "checkbox") {
|
||||
newValue = input.prop('checked');
|
||||
} else if (input.prop("nodeName") === "select" && input.attr("multiple") === "multiple") {
|
||||
// An empty select-multiple box returns null.
|
||||
// Need to treat that as an empty array.
|
||||
newValue = input.val();
|
||||
if (newValue == null) {
|
||||
newValue = [];
|
||||
}
|
||||
} else if ("format" in node._def.defaults[d] && node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") {
|
||||
newValue = input.text();
|
||||
} else {
|
||||
newValue = input.val();
|
||||
}
|
||||
if (newValue != null) {
|
||||
if (d === "outputs") {
|
||||
if (newValue.trim() === "") {
|
||||
continue;
|
||||
}
|
||||
if (isNaN(newValue)) {
|
||||
editState.outputMap = JSON.parse(newValue);
|
||||
var outputCount = 0;
|
||||
var outputsChanged = false;
|
||||
var keys = Object.keys(editState.outputMap);
|
||||
keys.forEach(function(p) {
|
||||
if (isNaN(p)) {
|
||||
// New output;
|
||||
outputCount ++;
|
||||
delete editState.outputMap[p];
|
||||
} else {
|
||||
editState.outputMap[p] = editState.outputMap[p]+"";
|
||||
if (editState.outputMap[p] !== "-1") {
|
||||
outputCount++;
|
||||
if (editState.outputMap[p] !== p) {
|
||||
// Output moved
|
||||
outputsChanged = true;
|
||||
} else {
|
||||
delete editState.outputMap[p];
|
||||
}
|
||||
} else {
|
||||
// Output removed
|
||||
outputsChanged = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
newValue = outputCount;
|
||||
if (outputsChanged) {
|
||||
editState.changed = true;
|
||||
}
|
||||
} else {
|
||||
newValue = parseInt(newValue);
|
||||
}
|
||||
}
|
||||
if (node._def.defaults[d].type) {
|
||||
if (newValue == "_ADD_") {
|
||||
newValue = "";
|
||||
}
|
||||
}
|
||||
if (!isEqual(node[d], newValue)) {
|
||||
if (node._def.defaults[d].type) {
|
||||
// Change to a related config node
|
||||
var configNode = RED.nodes.node(node[d]);
|
||||
if (configNode) {
|
||||
var users = configNode.users;
|
||||
users.splice(users.indexOf(node),1);
|
||||
RED.events.emit("nodes:change",configNode);
|
||||
}
|
||||
configNode = RED.nodes.node(newValue);
|
||||
if (configNode) {
|
||||
configNode.users.push(node);
|
||||
RED.events.emit("nodes:change",configNode);
|
||||
}
|
||||
}
|
||||
editState.changes[d] = node[d];
|
||||
node[d] = newValue;
|
||||
editState.changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node._def.credentials) {
|
||||
var credDefinition = node._def.credentials;
|
||||
var credsChanged = updateNodeCredentials(node,credDefinition,this.inputClass);
|
||||
editState.changed = editState.changed || credsChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Compares `newValue` with `originalValue` for equality.
|
||||
* @param {*} originalValue Original value
|
||||
* @param {*} newValue New value
|
||||
* @returns {boolean} true if originalValue equals newValue, otherwise false
|
||||
*/
|
||||
function isEqual(originalValue, newValue) {
|
||||
try {
|
||||
if(originalValue == newValue) {
|
||||
return true;
|
||||
}
|
||||
return JSON.stringify(originalValue) === JSON.stringify(newValue);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the node credentials from the edit form
|
||||
* @param node - the node containing the credentials
|
||||
* @param credDefinition - definition of the credentials
|
||||
* @param prefix - prefix of the input fields
|
||||
* @return {boolean} whether anything has changed
|
||||
*/
|
||||
function updateNodeCredentials(node, credDefinition, prefix) {
|
||||
var changed = false;
|
||||
if (!node.credentials) {
|
||||
node.credentials = {_:{}};
|
||||
} else if (!node.credentials._) {
|
||||
node.credentials._ = {};
|
||||
}
|
||||
|
||||
for (var cred in credDefinition) {
|
||||
if (credDefinition.hasOwnProperty(cred)) {
|
||||
var input = $("#" + prefix + '-' + cred);
|
||||
if (input.length > 0) {
|
||||
var value = input.val();
|
||||
if (credDefinition[cred].type == 'password') {
|
||||
node.credentials['has_' + cred] = (value !== "");
|
||||
if (value == '__PWRD__') {
|
||||
continue;
|
||||
}
|
||||
changed = true;
|
||||
|
||||
}
|
||||
node.credentials[cred] = value;
|
||||
if (value != node.credentials._[cred]) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
179
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/subflowModule.js
vendored
Normal file
179
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/subflowModule.js
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
(function() {
|
||||
var _subflowModulePaneTemplate = '<form class="dialog-form form-horizontal" autocomplete="off">'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-module" data-i18n="[append]editor:subflow.module"><i class="fa fa-cube"></i> </label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-module" data-i18n="[placeholder]common.label.name">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-type" data-i18n="[append]editor:subflow.type"> </label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-type">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-version" data-i18n="[append]editor:subflow.version"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-version" data-i18n="[placeholder]editor:subflow.versionPlaceholder">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-desc" data-i18n="[append]editor:subflow.desc"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-desc">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-license" data-i18n="[append]editor:subflow.license"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-license">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-author" data-i18n="[append]editor:subflow.author"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-author" data-i18n="[placeholder]editor:subflow.authorPlaceholder">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-keywords" data-i18n="[append]editor:subflow.keys"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-keywords" data-i18n="[placeholder]editor:subflow.keysPlaceholder">'+
|
||||
'</div>'+
|
||||
'</form>';
|
||||
|
||||
RED.editor.registerEditPane("editor-tab-subflow-module", function(node) {
|
||||
return {
|
||||
label: RED._("editor-tab.module"),
|
||||
name: RED._("editor-tab.module"),
|
||||
iconClass: "fa fa-cube",
|
||||
create: function(container) {
|
||||
buildModuleForm(container, node);
|
||||
},
|
||||
resize: function(size) {
|
||||
},
|
||||
close: function() {
|
||||
|
||||
},
|
||||
apply: function(editState) {
|
||||
var newMeta = exportSubflowModuleProperties(node);
|
||||
if (!isSameObj(node.meta,newMeta)) {
|
||||
editState.changes.meta = node.meta;
|
||||
node.meta = newMeta;
|
||||
editState.changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function isSameObj(env0, env1) {
|
||||
return (JSON.stringify(env0) === JSON.stringify(env1));
|
||||
}
|
||||
|
||||
function setupInputValidation(input,validator) {
|
||||
var errorTip;
|
||||
var validateTimeout;
|
||||
|
||||
var validateFunction = function() {
|
||||
if (validateTimeout) {
|
||||
return;
|
||||
}
|
||||
validateTimeout = setTimeout(function() {
|
||||
var error = validator(input.val());
|
||||
// if (!error && errorTip) {
|
||||
// errorTip.close();
|
||||
// errorTip = null;
|
||||
// } else if (error && !errorTip) {
|
||||
// errorTip = RED.popover.create({
|
||||
// tooltip: true,
|
||||
// target:input,
|
||||
// size: "small",
|
||||
// direction: "bottom",
|
||||
// content: error,
|
||||
// }).open();
|
||||
// }
|
||||
input.toggleClass("input-error",!!error);
|
||||
validateTimeout = null;
|
||||
})
|
||||
}
|
||||
input.on("change keyup paste", validateFunction);
|
||||
}
|
||||
|
||||
function buildModuleForm(container, node) {
|
||||
$(_subflowModulePaneTemplate).appendTo(container);
|
||||
var moduleProps = node.meta || {};
|
||||
[
|
||||
'module',
|
||||
'type',
|
||||
'version',
|
||||
'author',
|
||||
'desc',
|
||||
'keywords',
|
||||
'license'
|
||||
].forEach(function(property) {
|
||||
$("#subflow-input-module-"+property).val(moduleProps[property]||"")
|
||||
})
|
||||
$("#subflow-input-module-type").attr("placeholder",node.id);
|
||||
|
||||
setupInputValidation($("#subflow-input-module-module"), function(newValue) {
|
||||
newValue = newValue.trim();
|
||||
var isValid = newValue.length < 215;
|
||||
isValid = isValid && !/^[._]/.test(newValue);
|
||||
isValid = isValid && !/[A-Z]/.test(newValue);
|
||||
if (newValue !== encodeURIComponent(newValue)) {
|
||||
var m = /^@([^\/]+)\/([^\/]+)$/.exec(newValue);
|
||||
if (m) {
|
||||
isValid = isValid && (m[1] === encodeURIComponent(m[1]) && m[2] === encodeURIComponent(m[2]))
|
||||
} else {
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
return isValid?"":"Invalid module name"
|
||||
})
|
||||
setupInputValidation($("#subflow-input-module-version"), function(newValue) {
|
||||
newValue = newValue.trim();
|
||||
var isValid = newValue === "" ||
|
||||
/^(\d|[1-9]\d*)\.(\d|[1-9]\d*)\.(\d|[1-9]\d*)(-(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\.(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(newValue);
|
||||
return isValid?"":"Invalid version number"
|
||||
})
|
||||
|
||||
var licenses = ["none", "Apache-2.0", "BSD-3-Clause", "BSD-2-Clause", "GPL-2.0", "GPL-3.0", "MIT", "MPL-2.0", "CDDL-1.0", "EPL-2.0"];
|
||||
var typedLicenses = {
|
||||
types: licenses.map(function(l) {
|
||||
return {
|
||||
value: l,
|
||||
label: l === "none" ? RED._("editor:subflow.licenseNone") : l,
|
||||
hasValue: false
|
||||
};
|
||||
})
|
||||
}
|
||||
typedLicenses.types.push({
|
||||
value:"_custom_", label:RED._("editor:subflow.licenseOther"), icon:"red/images/typedInput/az.svg"
|
||||
})
|
||||
if (!moduleProps.license) {
|
||||
typedLicenses.default = "none";
|
||||
} else if (licenses.indexOf(moduleProps.license) > -1) {
|
||||
typedLicenses.default = moduleProps.license;
|
||||
} else {
|
||||
typedLicenses.default = "_custom_";
|
||||
}
|
||||
$("#subflow-input-module-license").typedInput(typedLicenses)
|
||||
}
|
||||
function exportSubflowModuleProperties(node) {
|
||||
var value;
|
||||
var moduleProps = {};
|
||||
[
|
||||
'module',
|
||||
'type',
|
||||
'version',
|
||||
'author',
|
||||
'desc',
|
||||
'keywords'
|
||||
].forEach(function(property) {
|
||||
value = $("#subflow-input-module-"+property).val().trim();
|
||||
if (value) {
|
||||
moduleProps[property] = value;
|
||||
}
|
||||
})
|
||||
var selectedLicenseType = $("#subflow-input-module-license").typedInput("type");
|
||||
|
||||
if (selectedLicenseType === '_custom_') {
|
||||
value = $("#subflow-input-module-license").val();
|
||||
if (value) {
|
||||
moduleProps.license = value;
|
||||
}
|
||||
} else if (selectedLicenseType !== "none") {
|
||||
moduleProps.license = selectedLicenseType;
|
||||
}
|
||||
return moduleProps;
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -21,6 +21,7 @@
|
||||
var definition = {
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onCancel = options.cancel;
|
||||
var onComplete = options.complete;
|
||||
var type = "_text"
|
||||
if ($("script[data-template-name='"+type+"']").length === 0) {
|
||||
@@ -28,16 +29,16 @@
|
||||
}
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
var changeTimer;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
focusElement: options.focusElement,
|
||||
width: options.width||"inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
if(onCancel) { onCancel(); }
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
@@ -46,7 +47,8 @@
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(expressionEditor.getValue(),expressionEditor.getCursorPosition());
|
||||
expressionEditor.saveView();
|
||||
if (onComplete) { onComplete(expressionEditor.getValue(),expressionEditor.getCursorPosition(),expressionEditor);}
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
@@ -55,31 +57,27 @@
|
||||
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
||||
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
||||
var height = $("#dialog-form").height();
|
||||
// for (var i=0;i<rows.size();i++) {
|
||||
// height -= $(rows[i]).outerHeight(true);
|
||||
// }
|
||||
// height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
expressionEditor.resize();
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.red-ui-tray-body'),'dialog-form',type,'editor');
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-text',
|
||||
value: "",
|
||||
mode:"ace/mode/"+(options.mode||"text")
|
||||
value: value||"",
|
||||
stateId: options.stateId,
|
||||
mode:"ace/mode/"+(options.mode||"text"),
|
||||
focus: true,
|
||||
});
|
||||
expressionEditor.getSession().setValue(value||"",-1);
|
||||
if (options.cursor) {
|
||||
if (options.cursor && !expressionEditor._initState) {
|
||||
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
||||
}
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
expressionEditor.destroy();
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
|
||||
@@ -87,16 +87,18 @@ RED.group = (function() {
|
||||
"label-position": "nw"
|
||||
};
|
||||
|
||||
|
||||
var groupDef = {
|
||||
defaults:{
|
||||
name:{value:""},
|
||||
style:{value:{label:true}},
|
||||
nodes:{value:[]}
|
||||
nodes:{value:[]},
|
||||
env: {value:[]},
|
||||
},
|
||||
category: "config",
|
||||
oneditprepare: function() {
|
||||
var style = this.style || {};
|
||||
RED.colorPicker.create({
|
||||
RED.editor.colorPicker.create({
|
||||
id:"node-input-style-stroke",
|
||||
value: style.stroke || defaultGroupStyle.stroke || "#a4a4a4",
|
||||
palette: colorPalette,
|
||||
@@ -107,7 +109,7 @@ RED.group = (function() {
|
||||
none: true,
|
||||
opacity: style.hasOwnProperty('stroke-opacity')?style['stroke-opacity']:(defaultGroupStyle.hasOwnProperty('stroke-opacity')?defaultGroupStyle['stroke-opacity']:1.0)
|
||||
}).appendTo("#node-input-row-style-stroke");
|
||||
RED.colorPicker.create({
|
||||
RED.editor.colorPicker.create({
|
||||
id:"node-input-style-fill",
|
||||
value: style.fill || defaultGroupStyle.fill ||"none",
|
||||
palette: colorPalette,
|
||||
@@ -124,7 +126,7 @@ RED.group = (function() {
|
||||
value:style["label-position"] || "nw"
|
||||
}).appendTo("#node-input-row-style-label-position");
|
||||
|
||||
RED.colorPicker.create({
|
||||
RED.editor.colorPicker.create({
|
||||
id:"node-input-style-color",
|
||||
value: style.color || defaultGroupStyle.color ||"#a4a4a4",
|
||||
palette: colorPalette,
|
||||
@@ -144,7 +146,6 @@ RED.group = (function() {
|
||||
})
|
||||
$("#node-input-style-label").prop("checked", this.style.label)
|
||||
$("#node-input-style-label").trigger("change");
|
||||
|
||||
},
|
||||
oneditresize: function(size) {
|
||||
},
|
||||
@@ -183,7 +184,9 @@ RED.group = (function() {
|
||||
var activateUngroup = false;
|
||||
var activateMerge = false;
|
||||
var activateRemove = false;
|
||||
var singleGroupSelected = false;
|
||||
if (activateGroup) {
|
||||
singleGroupSelected = selection.nodes.length === 1 && selection.nodes[0].type === 'group';
|
||||
selection.nodes.forEach(function (n) {
|
||||
if (n.type === "group") {
|
||||
activateUngroup = true;
|
||||
@@ -200,6 +203,8 @@ RED.group = (function() {
|
||||
RED.menu.setDisabled("menu-item-group-ungroup", !activateUngroup);
|
||||
RED.menu.setDisabled("menu-item-group-merge", !activateMerge);
|
||||
RED.menu.setDisabled("menu-item-group-remove", !activateRemove);
|
||||
RED.menu.setDisabled("menu-item-edit-copy-group-style", !singleGroupSelected);
|
||||
RED.menu.setDisabled("menu-item-edit-paste-group-style", !activateUngroup);
|
||||
});
|
||||
|
||||
RED.actions.add("core:group-selection", function() { groupSelection() })
|
||||
@@ -252,6 +257,7 @@ RED.group = (function() {
|
||||
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') {
|
||||
groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style));
|
||||
RED.notify(RED._("clipboard.groupStyleCopied"),{id:"clipboard"})
|
||||
RED.menu.setDisabled("menu-item-edit-paste-group-style", false)
|
||||
}
|
||||
}
|
||||
function pasteGroupStyle() {
|
||||
@@ -317,9 +323,6 @@ RED.group = (function() {
|
||||
groups: [ ],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
|
||||
groups.forEach(function(g) {
|
||||
newSelection = newSelection.concat(ungroup(g))
|
||||
historyEvent.groups.push(g);
|
||||
@@ -346,8 +349,10 @@ RED.group = (function() {
|
||||
}
|
||||
if (n.type === 'group') {
|
||||
RED.events.emit("groups:change",n)
|
||||
} else {
|
||||
} else if (n.type !== 'junction') {
|
||||
RED.events.emit("nodes:change",n)
|
||||
} else {
|
||||
RED.events.emit("junctions:change",n)
|
||||
}
|
||||
})
|
||||
RED.nodes.removeGroup(g);
|
||||
@@ -541,8 +546,10 @@ RED.group = (function() {
|
||||
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
|
||||
if (n.type === 'group') {
|
||||
RED.events.emit("groups:change",n)
|
||||
} else {
|
||||
} else if (n.type !== 'junction') {
|
||||
RED.events.emit("nodes:change",n)
|
||||
} else {
|
||||
RED.events.emit("junctions:change",n)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -577,19 +584,23 @@ RED.group = (function() {
|
||||
}
|
||||
if (n.type === 'group') {
|
||||
RED.events.emit("groups:change",n)
|
||||
} else {
|
||||
} else if (n.type !== 'junction') {
|
||||
RED.events.emit("nodes:change",n)
|
||||
} else {
|
||||
RED.events.emit("junctions:change",n)
|
||||
}
|
||||
}
|
||||
markDirty(group);
|
||||
}
|
||||
|
||||
function getNodes(group,recursive) {
|
||||
function getNodes(group,recursive,excludeGroup) {
|
||||
var nodes = [];
|
||||
group.nodes.forEach(function(n) {
|
||||
nodes.push(n);
|
||||
if (n.type !== 'group' || !excludeGroup) {
|
||||
nodes.push(n);
|
||||
}
|
||||
if (recursive && n.type === 'group') {
|
||||
nodes = nodes.concat(getNodes(n,recursive))
|
||||
nodes = nodes.concat(getNodes(n,recursive,excludeGroup))
|
||||
}
|
||||
})
|
||||
return nodes;
|
||||
|
||||
@@ -49,15 +49,15 @@ RED.keyboard = (function() {
|
||||
"]": 221,
|
||||
"{": 219,// <- QWERTY specific
|
||||
"}": 221 // <- QWERTY specific
|
||||
}
|
||||
};
|
||||
var metaKeyCodes = {
|
||||
16: true,
|
||||
17: true,
|
||||
18: true,
|
||||
91: true,
|
||||
93: true
|
||||
}
|
||||
var actionToKeyMap = {}
|
||||
};
|
||||
var actionToKeyMap = {};
|
||||
var defaultKeyMap = {};
|
||||
|
||||
// FF generates some different keycodes because reasons.
|
||||
@@ -65,7 +65,7 @@ RED.keyboard = (function() {
|
||||
59:186,
|
||||
61:187,
|
||||
173:189
|
||||
}
|
||||
};
|
||||
|
||||
function migrateOldKeymap() {
|
||||
// pre-0.18
|
||||
@@ -80,7 +80,7 @@ RED.keyboard = (function() {
|
||||
}
|
||||
|
||||
function getUserKey(action) {
|
||||
return RED.settings.get('editor.keymap',{})[action]
|
||||
return RED.settings.get('editor.keymap',{})[action];
|
||||
}
|
||||
|
||||
function mergeKeymaps(defaultKeymap, themeKeymap) {
|
||||
@@ -105,7 +105,7 @@ RED.keyboard = (function() {
|
||||
scope:scope,
|
||||
key:key,
|
||||
user:false
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,13 +115,13 @@ RED.keyboard = (function() {
|
||||
if (themeKeymap.hasOwnProperty(action)) {
|
||||
if (!themeKeymap[action].key) {
|
||||
// No key for this action - default is no keybinding
|
||||
delete mergedKeymap[action]
|
||||
delete mergedKeymap[action];
|
||||
} else {
|
||||
mergedKeymap[action] = [{
|
||||
scope: themeKeymap[action].scope || "*",
|
||||
key: themeKeymap[action].key,
|
||||
user: false
|
||||
}]
|
||||
}];
|
||||
if (mergedKeymap[action][0].scope === "workspace") {
|
||||
mergedKeymap[action][0].scope = "red-ui-workspace";
|
||||
}
|
||||
@@ -131,7 +131,7 @@ RED.keyboard = (function() {
|
||||
return mergedKeymap;
|
||||
}
|
||||
|
||||
function init() {
|
||||
function init(done) {
|
||||
// Migrate from pre-0.18
|
||||
migrateOldKeymap();
|
||||
|
||||
@@ -164,6 +164,7 @@ RED.keyboard = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
RED.userSettings.add({
|
||||
@@ -174,8 +175,11 @@ RED.keyboard = (function() {
|
||||
setTimeout(function() {
|
||||
$("#red-ui-settings-tab-keyboard-filter").trigger("focus");
|
||||
},200);
|
||||
},
|
||||
close: function() {
|
||||
RED.menu.refreshShortcuts();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function revertToDefault(action) {
|
||||
@@ -239,7 +243,13 @@ RED.keyboard = (function() {
|
||||
|
||||
function resolveKeyEvent(evt) {
|
||||
var slot = partialState||handlers;
|
||||
if (evt.ctrlKey || evt.metaKey) {
|
||||
// We cheat with MacOS CMD key and consider it the same as Ctrl.
|
||||
// That means we don't have to have separate keymaps for different OS.
|
||||
// It mostly works.
|
||||
// One exception is shortcuts that include both Cmd and Ctrl. We don't
|
||||
// support them - but we need to make sure we don't block browser-specific
|
||||
// shortcuts (such as Cmd-Ctrl-F for fullscreen).
|
||||
if ((evt.ctrlKey || evt.metaKey) && (evt.ctrlKey !== evt.metaKey)) {
|
||||
slot = slot.ctrl;
|
||||
}
|
||||
if (slot && evt.shiftKey) {
|
||||
@@ -317,7 +327,7 @@ RED.keyboard = (function() {
|
||||
scope:scope,
|
||||
key:key,
|
||||
user:false
|
||||
}
|
||||
};
|
||||
}
|
||||
if (!ondown) {
|
||||
var userAction = getUserKey(cbdown);
|
||||
@@ -340,7 +350,7 @@ RED.keyboard = (function() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
keys.push([key,mod])
|
||||
keys.push([key,mod]);
|
||||
}
|
||||
var slot = handlers;
|
||||
for (i=0;i<keys.length;i++) {
|
||||
@@ -363,7 +373,7 @@ RED.keyboard = (function() {
|
||||
//slot[key] = {scope: scope, ondown:cbdown};
|
||||
}
|
||||
slot.handlers = slot.handlers || [];
|
||||
slot.handlers.push({scope:scope,ondown:cbdown})
|
||||
slot.handlers.push({scope:scope,ondown:cbdown});
|
||||
slot.scope = scope;
|
||||
slot.ondown = cbdown;
|
||||
}
|
||||
@@ -380,12 +390,12 @@ RED.keyboard = (function() {
|
||||
if (parsedKey) {
|
||||
keys.push(parsedKey);
|
||||
} else {
|
||||
console.log("Unrecognised key specifier:",key)
|
||||
console.log("Unrecognised key specifier:",key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
keys.push([key,mod])
|
||||
keys.push([key,mod]);
|
||||
}
|
||||
var slot = handlers;
|
||||
for (i=0;i<keys.length;i++) {
|
||||
@@ -407,7 +417,7 @@ RED.keyboard = (function() {
|
||||
}
|
||||
if (typeof slot.ondown === "string") {
|
||||
if (typeof modifiers === 'boolean' && modifiers) {
|
||||
actionToKeyMap[slot.ondown] = {user: modifiers}
|
||||
actionToKeyMap[slot.ondown] = {user: modifiers};
|
||||
} else {
|
||||
delete actionToKeyMap[slot.ondown];
|
||||
}
|
||||
@@ -423,11 +433,11 @@ RED.keyboard = (function() {
|
||||
function formatKey(key,plain) {
|
||||
var formattedKey = isMac?key.replace(/ctrl-?/,"⌘"):key;
|
||||
formattedKey = isMac?formattedKey.replace(/alt-?/,"⌥"):key;
|
||||
formattedKey = formattedKey.replace(/shift-?/,"⇧")
|
||||
formattedKey = formattedKey.replace(/left/,"←")
|
||||
formattedKey = formattedKey.replace(/up/,"↑")
|
||||
formattedKey = formattedKey.replace(/right/,"→")
|
||||
formattedKey = formattedKey.replace(/down/,"↓")
|
||||
formattedKey = formattedKey.replace(/shift-?/,"⇧");
|
||||
formattedKey = formattedKey.replace(/left/,"←");
|
||||
formattedKey = formattedKey.replace(/up/,"↑");
|
||||
formattedKey = formattedKey.replace(/right/,"→");
|
||||
formattedKey = formattedKey.replace(/down/,"↓");
|
||||
if (plain) {
|
||||
return formattedKey;
|
||||
}
|
||||
@@ -451,7 +461,6 @@ RED.keyboard = (function() {
|
||||
var container = $(this);
|
||||
var object = container.data('data');
|
||||
|
||||
|
||||
if (!container.hasClass('keyboard-shortcut-entry-expanded')) {
|
||||
endEditShortcut();
|
||||
|
||||
@@ -475,7 +484,7 @@ RED.keyboard = (function() {
|
||||
}
|
||||
$(this).toggleClass("input-error",!valid);
|
||||
okButton.attr("disabled",!valid);
|
||||
})
|
||||
});
|
||||
|
||||
var scopeSelect = $('<select><option value="*" data-i18n="keyboard.global"></option><option value="red-ui-workspace" data-i18n="keyboard.workspace"></option></select>').appendTo(scope);
|
||||
scopeSelect.i18n();
|
||||
@@ -485,7 +494,7 @@ RED.keyboard = (function() {
|
||||
scopeSelect.val(object.scope||'*');
|
||||
scopeSelect.on("change", function() {
|
||||
keyInput.trigger("change");
|
||||
})
|
||||
});
|
||||
|
||||
var div = $('<div class="keyboard-shortcut-edit button-group-vertical"></div>').appendTo(scope);
|
||||
var okButton = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-check"></i></button>').appendTo(div);
|
||||
@@ -511,10 +520,13 @@ RED.keyboard = (function() {
|
||||
id:object.id,
|
||||
scope:shortcut?shortcut.scope:undefined,
|
||||
key:shortcut?shortcut.key:undefined,
|
||||
user:shortcut?shortcut.user:undefined
|
||||
}
|
||||
user:shortcut?shortcut.user:undefined,
|
||||
|
||||
label: object.label,
|
||||
options: object.options,
|
||||
};
|
||||
buildShortcutRow(container,obj);
|
||||
})
|
||||
});
|
||||
|
||||
keyInput.trigger("focus");
|
||||
}
|
||||
@@ -549,7 +561,7 @@ RED.keyboard = (function() {
|
||||
delete object.scope;
|
||||
} else {
|
||||
keyDiv.parent().removeClass("keyboard-shortcut-entry-unassigned");
|
||||
keyDiv.append(RED.keyboard.formatKey(key))
|
||||
keyDiv.append(RED.keyboard.formatKey(key));
|
||||
$("<span>").text(scope).appendTo(scopeDiv);
|
||||
object.key = key;
|
||||
object.scope = scope;
|
||||
@@ -562,7 +574,7 @@ RED.keyboard = (function() {
|
||||
userKeymap[object.id] = {
|
||||
scope:shortcut.scope,
|
||||
key:shortcut.key
|
||||
}
|
||||
};
|
||||
RED.settings.set('editor.keymap',userKeymap);
|
||||
}
|
||||
}
|
||||
@@ -578,13 +590,7 @@ RED.keyboard = (function() {
|
||||
var item = $('<div class="keyboard-shortcut-entry">').appendTo(container);
|
||||
container.data('data',object);
|
||||
|
||||
var text = object.id.replace(/(^.+:([a-z]))|(-([a-z]))/g,function() {
|
||||
if (arguments[5] === 0) {
|
||||
return arguments[2].toUpperCase();
|
||||
} else {
|
||||
return " "+arguments[4].toUpperCase();
|
||||
}
|
||||
});
|
||||
var text = object.label;
|
||||
var label = $('<div>').addClass("keyboard-shortcut-entry-text").text(text).appendTo(item);
|
||||
|
||||
var user = $('<i class="fa fa-user"></i>').prependTo(label);
|
||||
@@ -619,14 +625,15 @@ RED.keyboard = (function() {
|
||||
pane.find("#red-ui-settings-tab-keyboard-filter").searchBox({
|
||||
delay: 100,
|
||||
change: function() {
|
||||
var filterValue = $(this).val().trim();
|
||||
var filterValue = $(this).val().trim().toLowerCase();
|
||||
if (filterValue === "") {
|
||||
shortcutList.editableList('filter', null);
|
||||
} else {
|
||||
filterValue = filterValue.replace(/\s/g,"");
|
||||
shortcutList.editableList('filter', function(data) {
|
||||
return data.id.toLowerCase().replace(/^.*:/,"").replace("-","").indexOf(filterValue) > -1;
|
||||
})
|
||||
var label = data.label.toLowerCase();
|
||||
return label.indexOf(filterValue) > -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -647,9 +654,9 @@ RED.keyboard = (function() {
|
||||
});
|
||||
var shortcuts = RED.actions.list();
|
||||
shortcuts.sort(function(A,B) {
|
||||
var Aid = A.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase();
|
||||
var Bid = B.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase();
|
||||
return Aid.localeCompare(Bid);
|
||||
var Akey = A.label;
|
||||
var Bkey = B.label;
|
||||
return Akey.localeCompare(Bkey);
|
||||
});
|
||||
knownShortcuts = new Set();
|
||||
shortcuts.forEach(function(s) {
|
||||
|
||||
@@ -363,106 +363,112 @@ RED.library = (function() {
|
||||
options.onconfirm(item);
|
||||
}
|
||||
});
|
||||
var itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
|
||||
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
var elementPos = menuButton.offset();
|
||||
|
||||
var menuOptionMenu = RED.menu.init({id:"red-ui-library-browser-menu",
|
||||
options: [
|
||||
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
|
||||
var defaultFolderName = "new-folder";
|
||||
var defaultFolderNameMatches = {};
|
||||
|
||||
var selected = dirList.treeList('selected');
|
||||
if (!selected.children) {
|
||||
selected = selected.parent;
|
||||
}
|
||||
var complete = function() {
|
||||
selected.children.forEach(function(c) {
|
||||
if (/^new-folder/.test(c.label)) {
|
||||
defaultFolderNameMatches[c.label] = true
|
||||
}
|
||||
});
|
||||
var folderIndex = 2;
|
||||
while(defaultFolderNameMatches[defaultFolderName]) {
|
||||
defaultFolderName = "new-folder-"+(folderIndex++)
|
||||
}
|
||||
|
||||
selected.treeList.expand();
|
||||
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
|
||||
var newItem = {
|
||||
icon: "fa fa-folder-o",
|
||||
children:[],
|
||||
path: selected.path,
|
||||
element: input
|
||||
}
|
||||
var confirmAdd = function() {
|
||||
var val = input.val().trim();
|
||||
if (val === "") {
|
||||
cancelAdd();
|
||||
return;
|
||||
} else {
|
||||
for (var i=0;i<selected.children.length;i++) {
|
||||
if (selected.children[i].label === val) {
|
||||
cancelAdd();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newItem.treeList.remove();
|
||||
var finalItem = {
|
||||
library: selected.library,
|
||||
type: selected.type,
|
||||
icon: "fa fa-folder",
|
||||
children:[],
|
||||
label: val,
|
||||
path: newItem.path+val+"/"
|
||||
}
|
||||
selected.treeList.addChild(finalItem,true);
|
||||
}
|
||||
var cancelAdd = function() {
|
||||
newItem.treeList.remove();
|
||||
}
|
||||
input.on('keydown', function(evt) {
|
||||
evt.stopPropagation();
|
||||
if (evt.keyCode === 13) {
|
||||
confirmAdd();
|
||||
} else if (evt.keyCode === 27) {
|
||||
cancelAdd();
|
||||
}
|
||||
})
|
||||
input.on("blur", function() {
|
||||
confirmAdd();
|
||||
})
|
||||
selected.treeList.addChild(newItem);
|
||||
setTimeout(function() {
|
||||
input.trigger("focus");
|
||||
input.select();
|
||||
},400);
|
||||
}
|
||||
selected.treeList.expand(complete);
|
||||
|
||||
} },
|
||||
// null,
|
||||
// {id:"red-ui-library-browser-menu-rename",label:"Rename", onselect: function() {} },
|
||||
// {id:"red-ui-library-browser-menu-delete",label:"Delete", onselect: function() {} }
|
||||
]
|
||||
}).on('mouseleave', function(){ $(this).remove(); dirList.focus() })
|
||||
.on('mouseup', function() { var self = $(this);self.hide(); dirList.focus(); setTimeout(function() { self.remove() },100)})
|
||||
.appendTo("body");
|
||||
menuOptionMenu.css({
|
||||
position: "absolute",
|
||||
top: elementPos.top+"px",
|
||||
left: (elementPos.left - menuOptionMenu.width() + 20)+"px"
|
||||
}).show();
|
||||
|
||||
}).appendTo(itemTools);
|
||||
var itemTools = null;
|
||||
if (options.folderTools) {
|
||||
dirList.on('treelistselect', function(event, item) {
|
||||
if (item.writable !== false && item.treeList) {
|
||||
if (itemTools) {
|
||||
itemTools.remove();
|
||||
}
|
||||
itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
|
||||
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
var elementPos = menuButton.offset();
|
||||
|
||||
var menuOptionMenu
|
||||
= RED.menu.init({id:"red-ui-library-browser-menu",
|
||||
options: [
|
||||
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
|
||||
var defaultFolderName = "new-folder";
|
||||
var defaultFolderNameMatches = {};
|
||||
|
||||
var selected = dirList.treeList('selected');
|
||||
if (!selected.children) {
|
||||
selected = selected.parent;
|
||||
}
|
||||
var complete = function() {
|
||||
selected.children.forEach(function(c) {
|
||||
if (/^new-folder/.test(c.label)) {
|
||||
defaultFolderNameMatches[c.label] = true
|
||||
}
|
||||
});
|
||||
var folderIndex = 2;
|
||||
while(defaultFolderNameMatches[defaultFolderName]) {
|
||||
defaultFolderName = "new-folder-"+(folderIndex++)
|
||||
}
|
||||
|
||||
selected.treeList.expand();
|
||||
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
|
||||
var newItem = {
|
||||
icon: "fa fa-folder-o",
|
||||
children:[],
|
||||
path: selected.path,
|
||||
element: input
|
||||
}
|
||||
var confirmAdd = function() {
|
||||
var val = input.val().trim();
|
||||
if (val === "") {
|
||||
cancelAdd();
|
||||
return;
|
||||
} else {
|
||||
for (var i=0;i<selected.children.length;i++) {
|
||||
if (selected.children[i].label === val) {
|
||||
cancelAdd();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newItem.treeList.remove();
|
||||
var finalItem = {
|
||||
library: selected.library,
|
||||
type: selected.type,
|
||||
icon: "fa fa-folder",
|
||||
children:[],
|
||||
label: val,
|
||||
path: newItem.path+val+"/"
|
||||
}
|
||||
selected.treeList.addChild(finalItem,true);
|
||||
}
|
||||
var cancelAdd = function() {
|
||||
newItem.treeList.remove();
|
||||
}
|
||||
input.on('keydown', function(evt) {
|
||||
evt.stopPropagation();
|
||||
if (evt.keyCode === 13) {
|
||||
confirmAdd();
|
||||
} else if (evt.keyCode === 27) {
|
||||
cancelAdd();
|
||||
}
|
||||
})
|
||||
input.on("blur", function() {
|
||||
confirmAdd();
|
||||
})
|
||||
selected.treeList.addChild(newItem);
|
||||
setTimeout(function() {
|
||||
input.trigger("focus");
|
||||
input.select();
|
||||
},400);
|
||||
}
|
||||
selected.treeList.expand(complete);
|
||||
|
||||
} },
|
||||
// null,
|
||||
// {id:"red-ui-library-browser-menu-rename",label:"Rename", onselect: function() {} },
|
||||
// {id:"red-ui-library-browser-menu-delete",label:"Delete", onselect: function() {} }
|
||||
]
|
||||
}).on('mouseleave', function(){ $(this).remove(); dirList.focus() })
|
||||
.on('mouseup', function() { var self = $(this);self.hide(); dirList.focus(); setTimeout(function() { self.remove() },100)})
|
||||
.appendTo("body");
|
||||
menuOptionMenu.css({
|
||||
position: "absolute",
|
||||
top: elementPos.top+"px",
|
||||
left: (elementPos.left - menuOptionMenu.width() + 20)+"px"
|
||||
}).show();
|
||||
|
||||
}).appendTo(itemTools);
|
||||
|
||||
itemTools.appendTo(item.treeList.label);
|
||||
}
|
||||
});
|
||||
@@ -536,7 +542,7 @@ RED.library = (function() {
|
||||
// evt.preventDefault();
|
||||
// var icon = libraryFields['icon'].input.val() || "";
|
||||
// var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
|
||||
// RED.editor.showIconPicker(iconButton, null, iconPath, true, function (newIcon) {
|
||||
// RED.editor.iconPicker.show(iconButton, null, iconPath, true, function (newIcon) {
|
||||
// iconButton.empty();
|
||||
// var path = newIcon || "";
|
||||
// var newPath = RED.utils.separateIconPath(path);
|
||||
@@ -820,7 +826,7 @@ RED.library = (function() {
|
||||
close: function(e) {
|
||||
RED.keyboard.enable();
|
||||
if (libraryEditor) {
|
||||
libraryEditor.remove();
|
||||
libraryEditor.destroy();
|
||||
libraryEditor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,22 @@ RED.notifications = (function() {
|
||||
|
||||
var persistentNotifications = {};
|
||||
|
||||
var shade = (function() {
|
||||
var shadeUsers = 0;
|
||||
return {
|
||||
show: function() {
|
||||
shadeUsers++;
|
||||
$("#red-ui-full-shade").show();
|
||||
},
|
||||
hide: function() {
|
||||
shadeUsers--;
|
||||
if (shadeUsers === 0) {
|
||||
$("#red-ui-full-shade").hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
var currentNotifications = [];
|
||||
var c = 0;
|
||||
function notify(msg,type,fixed,timeout) {
|
||||
@@ -54,6 +70,10 @@ RED.notifications = (function() {
|
||||
fixed = options.fixed;
|
||||
timeout = options.timeout;
|
||||
type = options.type;
|
||||
} else {
|
||||
options.type = type;
|
||||
options.fixed = fixed;
|
||||
options.timeout = options.timeout;
|
||||
}
|
||||
|
||||
if (options.id && persistentNotifications.hasOwnProperty(options.id)) {
|
||||
@@ -62,7 +82,7 @@ RED.notifications = (function() {
|
||||
}
|
||||
|
||||
if (options.modal) {
|
||||
$("#red-ui-full-shade").show();
|
||||
shade.show();
|
||||
}
|
||||
|
||||
if (currentNotifications.length > 4) {
|
||||
@@ -79,6 +99,8 @@ RED.notifications = (function() {
|
||||
var n = document.createElement("div");
|
||||
n.id="red-ui-notification-"+c;
|
||||
n.className = "red-ui-notification";
|
||||
n.options = options;
|
||||
|
||||
n.fixed = fixed;
|
||||
if (type) {
|
||||
n.className = "red-ui-notification red-ui-notification-"+type;
|
||||
@@ -115,7 +137,6 @@ RED.notifications = (function() {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
$("#red-ui-notifications").append(n);
|
||||
if (!RED.notifications.hide) {
|
||||
$(n).slideDown(300);
|
||||
@@ -141,8 +162,8 @@ RED.notifications = (function() {
|
||||
} else {
|
||||
nn.parentNode.removeChild(nn);
|
||||
}
|
||||
if (options.modal) {
|
||||
$("#red-ui-full-shade").hide();
|
||||
if (nn.options.modal) {
|
||||
shade.hide();
|
||||
}
|
||||
};
|
||||
})();
|
||||
@@ -173,7 +194,7 @@ RED.notifications = (function() {
|
||||
|
||||
n.update = (function() {
|
||||
var nn = n;
|
||||
return function(msg,options) {
|
||||
return function(msg,newOptions) {
|
||||
if (typeof msg === "string") {
|
||||
if (!/<p>/i.test(msg)) {
|
||||
msg = "<p>"+msg+"</p>";
|
||||
@@ -182,16 +203,31 @@ RED.notifications = (function() {
|
||||
} else {
|
||||
$(nn).empty().append(msg);
|
||||
}
|
||||
var timeout;
|
||||
if (typeof options === 'number') {
|
||||
timeout = options;
|
||||
} else if (options !== undefined) {
|
||||
if (!options.fixed) {
|
||||
timeout = options.timeout || 5000;
|
||||
var newTimeout;
|
||||
if (typeof newOptions === 'number') {
|
||||
newTimeout = newOptions;
|
||||
nn.options.timeout = newTimeout;
|
||||
} else if (newOptions !== undefined) {
|
||||
|
||||
if (!options.modal && newOptions.modal) {
|
||||
nn.options.modal = true;
|
||||
shade.show();
|
||||
} else if (options.modal && newOptions.modal === false) {
|
||||
nn.options.modal = false;
|
||||
shade.hide();
|
||||
}
|
||||
if (options.buttons) {
|
||||
|
||||
var newType = newOptions.hasOwnProperty('type')?newOptions.type:type;
|
||||
if (newType) {
|
||||
n.className = "red-ui-notification red-ui-notification-"+newType;
|
||||
}
|
||||
|
||||
if (!fixed || newOptions.fixed === false) {
|
||||
newTimeout = (newOptions.hasOwnProperty('timeout')?newOptions.timeout:timeout)||5000;
|
||||
}
|
||||
if (newOptions.buttons) {
|
||||
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(nn)
|
||||
options.buttons.forEach(function(buttonDef) {
|
||||
newOptions.buttons.forEach(function(buttonDef) {
|
||||
var b = $('<button>').text(buttonDef.text).on("click", buttonDef.click).appendTo(buttonSet);
|
||||
if (buttonDef.id) {
|
||||
b.attr('id',buttonDef.id);
|
||||
@@ -202,15 +238,22 @@ RED.notifications = (function() {
|
||||
})
|
||||
}
|
||||
}
|
||||
if (timeout !== undefined && timeout > 0) {
|
||||
$(nn).off("click.red-ui-notification-close");
|
||||
if (newTimeout !== undefined && newTimeout > 0) {
|
||||
window.clearTimeout(nn.timeoutid);
|
||||
nn.timeoutid = window.setTimeout(nn.close,timeout);
|
||||
nn.timeoutid = window.setTimeout(nn.close,newTimeout);
|
||||
setTimeout(function() {
|
||||
$(nn).on("click.red-ui-notification-close", function() {
|
||||
nn.close();
|
||||
window.clearTimeout(nn.timeoutid);
|
||||
});
|
||||
},50);
|
||||
} else {
|
||||
window.clearTimeout(nn.timeoutid);
|
||||
}
|
||||
if (nn.hidden) {
|
||||
nn.showNotification();
|
||||
} else if (!options || !options.silent){
|
||||
} else if (!newOptions || !newOptions.silent){
|
||||
$(nn).addClass("red-ui-notification-shake-horizontal");
|
||||
setTimeout(function() {
|
||||
$(nn).removeClass("red-ui-notification-shake-horizontal");
|
||||
@@ -221,7 +264,7 @@ RED.notifications = (function() {
|
||||
})();
|
||||
|
||||
if (!fixed) {
|
||||
$(n).on("click", (function() {
|
||||
$(n).on("click.red-ui-notification-close", (function() {
|
||||
var nn = n;
|
||||
return function() {
|
||||
nn.close();
|
||||
|
||||
@@ -264,6 +264,8 @@ RED.palette.editor = (function() {
|
||||
var errMessage = set.err;
|
||||
if (set.err.message) {
|
||||
errMessage = set.err.message;
|
||||
} else if (set.err.code) {
|
||||
errMessage = set.err.code;
|
||||
}
|
||||
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
|
||||
}
|
||||
@@ -331,7 +333,10 @@ RED.palette.editor = (function() {
|
||||
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
|
||||
nodeEntry.updateButton.text(RED._('palette.editor.updated')).addClass('disabled').css('display', 'inline-block');
|
||||
} else if (loadedIndex.hasOwnProperty(module)) {
|
||||
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) > 0) {
|
||||
if (updateAllowed &&
|
||||
semVerCompare(loadedIndex[module].version,moduleInfo.version) > 0 &&
|
||||
RED.utils.checkModuleAllowed(module,null,updateAllowList,updateDenyList)
|
||||
) {
|
||||
nodeEntry.updateButton.show();
|
||||
nodeEntry.updateButton.text(RED._('palette.editor.update',{version:loadedIndex[module].version}));
|
||||
} else {
|
||||
@@ -482,6 +487,9 @@ RED.palette.editor = (function() {
|
||||
|
||||
var installAllowList = ['*'];
|
||||
var installDenyList = [];
|
||||
var updateAllowed = true;
|
||||
var updateAllowList = ['*'];
|
||||
var updateDenyList = [];
|
||||
|
||||
function init() {
|
||||
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
|
||||
@@ -496,6 +504,17 @@ RED.palette.editor = (function() {
|
||||
installAllowList = RED.utils.parseModuleList(installAllowList);
|
||||
installDenyList = RED.utils.parseModuleList(installDenyList);
|
||||
|
||||
var settingsUpdateAllowList = RED.settings.get("externalModules.palette.allowUpdateList")
|
||||
var settingsUpdateDenyList = RED.settings.get("externalModules.palette.denyUpdateList")
|
||||
if (settingsUpdateAllowList || settingsUpdateDenyList) {
|
||||
updateAllowList = settingsUpdateAllowList;
|
||||
updateDenyList = settingsUpdateDenyList;
|
||||
}
|
||||
updateAllowList = RED.utils.parseModuleList(updateAllowList);
|
||||
updateDenyList = RED.utils.parseModuleList(updateDenyList);
|
||||
updateAllowed = RED.settings.get("externalModules.palette.allowUpdate",true);
|
||||
|
||||
|
||||
createSettingsPane();
|
||||
|
||||
RED.userSettings.add({
|
||||
|
||||
@@ -208,7 +208,7 @@ RED.palette = (function() {
|
||||
}
|
||||
|
||||
function escapeCategory(category) {
|
||||
return category.replace(/[ /.]/g,"_");
|
||||
return category.replace(/[\x00-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]/g,"_");
|
||||
}
|
||||
function addNodeType(nt,def) {
|
||||
if (getPaletteNode(nt).length) {
|
||||
@@ -224,14 +224,7 @@ RED.palette = (function() {
|
||||
|
||||
var d = $('<div>',{class:"red-ui-palette-node"}).attr("data-palette-type",nt).data('category',rootCategory);
|
||||
|
||||
var label = nt;///^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
|
||||
if (typeof def.paletteLabel !== "undefined") {
|
||||
try {
|
||||
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+nt+".paletteLabel",err);
|
||||
}
|
||||
}
|
||||
var label = RED.utils.getPaletteLabel(nt, def);///^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
|
||||
|
||||
$('<div/>', {
|
||||
class: "red-ui-palette-label"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-label-right" : "")
|
||||
|
||||
@@ -120,6 +120,7 @@ RED.projects.settings = (function() {
|
||||
title: RED._('sidebar.project.editDescription'),
|
||||
header: $('<span><i class="fa fa-book"></i> README.md</span>'),
|
||||
value: activeProject.description,
|
||||
stateId: "sidebar.project.editDescription",
|
||||
complete: function(v) {
|
||||
container.empty();
|
||||
var spinner = utils.addSpinnerOverlay(container);
|
||||
|
||||
@@ -1212,6 +1212,9 @@ RED.projects = (function() {
|
||||
}
|
||||
}).appendTo(row);
|
||||
|
||||
row = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-open"></div>').hide().appendTo(container);
|
||||
$('<span style="display: flex; align-items: center;"><input style="padding:0; margin: 0 5px 0 0" checked type="checkbox" id="red-ui-projects-dialog-screen-clear-context"> <label for="red-ui-projects-dialog-screen-clear-context" style="padding:0; margin: 0"> <span data-i18n="projects.create.clearContext"></span></label></span>').appendTo(row).i18n();
|
||||
|
||||
row = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-empty red-ui-projects-dialog-screen-create-row-clone"></div>').appendTo(container);
|
||||
$('<label for="red-ui-projects-dialog-screen-create-project-name">'+RED._("projects.create.project-name")+'</label>').appendTo(row);
|
||||
|
||||
@@ -1501,7 +1504,8 @@ RED.projects = (function() {
|
||||
};
|
||||
}
|
||||
} else if (projectType === 'open') {
|
||||
return switchProject(selectedProject.name,function(err,data) {
|
||||
var clearContext = $("#red-ui-projects-dialog-screen-clear-context").prop("checked")
|
||||
return switchProject(selectedProject.name, clearContext, function(err,data) {
|
||||
if (err) {
|
||||
if (err.code !== 'credentials_load_failed') {
|
||||
console.log(RED._("projects.create.unexpected_error"),err)
|
||||
@@ -1595,7 +1599,7 @@ RED.projects = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function switchProject(name,done) {
|
||||
function switchProject(name,clearContext,done) {
|
||||
RED.deploy.setDeployInflight(true);
|
||||
RED.projects.settings.switchProject(name);
|
||||
sendRequest({
|
||||
@@ -1614,7 +1618,7 @@ RED.projects = (function() {
|
||||
'*': done
|
||||
},
|
||||
}
|
||||
},{active:true}).then(function() {
|
||||
},{active:true, clearContext:clearContext}).then(function() {
|
||||
dialog.dialog( "close" );
|
||||
RED.events.emit("project:change", {name:name});
|
||||
}).always(function() {
|
||||
@@ -1687,7 +1691,7 @@ RED.projects = (function() {
|
||||
dialogHeight = 590 - (750 - winHeight);
|
||||
}
|
||||
$(".red-ui-projects-dialog-box").height(dialogHeight);
|
||||
$(".red-ui-projects-dialog-project-list-inner-container").height(Math.max(500,dialogHeight) - 180);
|
||||
$(".red-ui-projects-dialog-project-list-inner-container").height(Math.max(500,dialogHeight) - 210);
|
||||
dialog.dialog('option','title',screen.title||"");
|
||||
dialog.dialog("open");
|
||||
}
|
||||
@@ -2387,6 +2391,7 @@ RED.projects = (function() {
|
||||
return {
|
||||
init: init,
|
||||
showStartup: function() {
|
||||
console.warn("showStartup")
|
||||
if (!RED.user.hasPermission("projects.write")) {
|
||||
RED.notify(RED._("user.errors.notAuthorized"),"error");
|
||||
return;
|
||||
|
||||
@@ -22,8 +22,11 @@ RED.search = (function() {
|
||||
var selected = -1;
|
||||
var visible = false;
|
||||
|
||||
var searchHistory = [];
|
||||
var index = {};
|
||||
var currentResults = [];
|
||||
var activeResults = [];
|
||||
var currentIndex = 0;
|
||||
var previousActiveElement;
|
||||
|
||||
function indexProperty(node,label,property) {
|
||||
@@ -52,10 +55,22 @@ RED.search = (function() {
|
||||
}
|
||||
l = l||n.label||n.name||n.id||"";
|
||||
|
||||
|
||||
var properties = ['id','type','name','label','info'];
|
||||
if (n._def && n._def.defaults) {
|
||||
properties = properties.concat(Object.keys(n._def.defaults));
|
||||
const node_def = n && n._def;
|
||||
if (node_def) {
|
||||
if (node_def.defaults) {
|
||||
properties = properties.concat(Object.keys(node_def.defaults));
|
||||
}
|
||||
if (n.type !== "group" && node_def.paletteLabel && node_def.paletteLabel !== node_def.type) {
|
||||
try {
|
||||
const label = ("" + (typeof node_def.paletteLabel === "function" ? node_def.paletteLabel.call(node_def) : node_def.paletteLabel)).toLowerCase();
|
||||
if(label && label !== (""+node_def.type).toLowerCase()) {
|
||||
indexProperty(n, l, label);
|
||||
}
|
||||
} catch(err) {
|
||||
console.warn(`error indexing ${l}`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0;i<properties.length;i++) {
|
||||
if (n.hasOwnProperty(properties[i])) {
|
||||
@@ -93,7 +108,6 @@ RED.search = (function() {
|
||||
|
||||
function search(val) {
|
||||
var results = [];
|
||||
var keys = [];
|
||||
var typeFilter;
|
||||
var m = /(?:^| )type:([^ ]+)/.exec(val);
|
||||
if (m) {
|
||||
@@ -105,19 +119,26 @@ RED.search = (function() {
|
||||
val = extractFlag(val,"unused",flags);
|
||||
val = extractFlag(val,"config",flags);
|
||||
val = extractFlag(val,"subflow",flags);
|
||||
// uses:<node-id>
|
||||
val = extractValue(val,"uses",flags);
|
||||
|
||||
var hasFlags = Object.keys(flags).length > 0;
|
||||
|
||||
val = extractFlag(val,"hidden",flags);
|
||||
val = extractFlag(val,"modified",flags);
|
||||
val = extractValue(val,"flow",flags);// flow:active or flow:<flow-id>
|
||||
val = extractValue(val,"uses",flags);// uses:<node-id>
|
||||
val = val.trim();
|
||||
|
||||
var hasFlags = Object.keys(flags).length > 0;
|
||||
if (flags.flow && flags.flow.indexOf("current") >= 0) {
|
||||
let idx = flags.flow.indexOf("current");
|
||||
flags.flow[idx] = RED.workspaces.active();//convert active to flow ID
|
||||
}
|
||||
if (flags.flow && flags.flow.length) {
|
||||
flags.flow = [ ...new Set(flags.flow) ]; //deduplicate
|
||||
}
|
||||
if (val.length > 0 || typeFilter || hasFlags) {
|
||||
val = val.toLowerCase();
|
||||
var i;
|
||||
var j;
|
||||
var list = [];
|
||||
var nodes = {};
|
||||
let keys = [];
|
||||
if (flags.uses) {
|
||||
keys = flags.uses;
|
||||
} else {
|
||||
@@ -127,7 +148,7 @@ RED.search = (function() {
|
||||
var key = keys[i];
|
||||
var kpos = keys[i].indexOf(val);
|
||||
if (kpos > -1) {
|
||||
var ids = Object.keys(index[key]);
|
||||
var ids = Object.keys(index[key]||{});
|
||||
for (j=0;j<ids.length;j++) {
|
||||
var node = index[key][ids[j]];
|
||||
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
|
||||
@@ -150,7 +171,20 @@ RED.search = (function() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.hasOwnProperty("modified")) {
|
||||
if (!node.node.changed && !node.node.moved) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("hidden")) {
|
||||
// Only tabs can be hidden
|
||||
if (node.node.type !== 'tab') {
|
||||
continue
|
||||
}
|
||||
if (!RED.workspaces.isHidden(node.node.id)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("unused")) {
|
||||
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
|
||||
(isConfigNode && node.node.users.length === 0)
|
||||
@@ -158,6 +192,11 @@ RED.search = (function() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("flow")) {
|
||||
if (flags.flow.indexOf(node.node.z || node.node.id) < 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!typeFilter || node.node.type === typeFilter) {
|
||||
nodes[node.node.id] = nodes[node.node.id] = {
|
||||
node: node.node,
|
||||
@@ -196,6 +235,20 @@ RED.search = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function populateSearchHistory() {
|
||||
if (searchHistory.length > 0) {
|
||||
searchResults.editableList('addItem',{
|
||||
historyHeader: true
|
||||
});
|
||||
searchHistory.forEach(function(entry) {
|
||||
searchResults.editableList('addItem',{
|
||||
history: true,
|
||||
value: entry
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
function createDialog() {
|
||||
dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#red-ui-main-container");
|
||||
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
|
||||
@@ -204,9 +257,14 @@ RED.search = (function() {
|
||||
change: function() {
|
||||
searchResults.editableList('empty');
|
||||
selected = -1;
|
||||
currentResults = search($(this).val());
|
||||
var value = $(this).val();
|
||||
if (value === "") {
|
||||
populateSearchHistory();
|
||||
return;
|
||||
}
|
||||
currentResults = search(value);
|
||||
if (currentResults.length > 0) {
|
||||
for (i=0;i<Math.min(currentResults.length,25);i++) {
|
||||
for (let i=0;i<Math.min(currentResults.length,25);i++) {
|
||||
searchResults.editableList('addItem',currentResults[i])
|
||||
}
|
||||
if (currentResults.length > 25) {
|
||||
@@ -220,9 +278,8 @@ RED.search = (function() {
|
||||
} else {
|
||||
searchResults.editableList('addItem',{});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
options: getSearchOptions()
|
||||
});
|
||||
var copySearchContainer = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-caret-right"></button>').appendTo(searchDiv).on('click', function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -276,9 +333,15 @@ RED.search = (function() {
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} if ($(children[selected]).hasClass("red-ui-search-history")) {
|
||||
var object = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
|
||||
if (object) {
|
||||
searchInput.searchBox('value',object.value)
|
||||
}
|
||||
} else if (!$(children[selected]).hasClass("red-ui-search-historyHeader")) {
|
||||
if (currentResults.length > 0) {
|
||||
reveal(currentResults[Math.max(0,selected)].node);
|
||||
currentIndex = Math.max(0,selected);
|
||||
reveal(currentResults[currentIndex].node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +355,32 @@ RED.search = (function() {
|
||||
addItem: function(container,i,object) {
|
||||
var node = object.node;
|
||||
var div;
|
||||
if (object.more) {
|
||||
if (object.historyHeader) {
|
||||
container.parent().addClass("red-ui-search-historyHeader")
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._("search.history")).appendTo(container);
|
||||
$('<button type="button" class="red-ui-button red-ui-button-small"></button>').text(RED._("search.clear")).appendTo(container).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
searchHistory = [];
|
||||
searchResults.editableList('empty');
|
||||
});
|
||||
} else if (object.history) {
|
||||
container.parent().addClass("red-ui-search-history")
|
||||
div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
|
||||
div.text(object.value);
|
||||
div.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
searchInput.searchBox('value',object.value)
|
||||
searchInput.focus();
|
||||
})
|
||||
$('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-remove"></i></button>').appendTo(container).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var index = searchHistory.indexOf(object.value);
|
||||
searchHistory.splice(index,1);
|
||||
searchResults.editableList('removeItem', object);
|
||||
});
|
||||
|
||||
|
||||
} else if (object.more) {
|
||||
container.parent().addClass("red-ui-search-more")
|
||||
div = $('<a>',{href:'#',class:"red-ui-search-result red-ui-search-empty"}).appendTo(container);
|
||||
div.text(RED._("palette.editor.more",{count:object.more.results.length-object.more.start}));
|
||||
@@ -337,6 +425,7 @@ RED.search = (function() {
|
||||
|
||||
div.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
currentIndex = i;
|
||||
reveal(node);
|
||||
});
|
||||
}
|
||||
@@ -347,12 +436,64 @@ RED.search = (function() {
|
||||
}
|
||||
|
||||
function reveal(node) {
|
||||
hide();
|
||||
var searchVal = searchInput.val();
|
||||
var existingIndex = searchHistory.indexOf(searchVal);
|
||||
if (existingIndex > -1) {
|
||||
searchHistory.splice(existingIndex,1);
|
||||
}
|
||||
searchHistory.unshift(searchVal);
|
||||
$("#red-ui-view-searchtools-search").data("term", searchVal);
|
||||
activeResults = Object.assign([], currentResults);
|
||||
hide(null, activeResults.length > 0);
|
||||
RED.view.reveal(node.id);
|
||||
}
|
||||
|
||||
function revealPrev() {
|
||||
if (disabled) {
|
||||
updateSearchToolbar();
|
||||
return;
|
||||
}
|
||||
if (!searchResults || !activeResults.length) {
|
||||
show();
|
||||
return;
|
||||
}
|
||||
if (currentIndex > 0) {
|
||||
currentIndex--;
|
||||
} else {
|
||||
currentIndex = activeResults.length - 1;
|
||||
}
|
||||
const n = activeResults[currentIndex];
|
||||
if (n && n.node && n.node.id) {
|
||||
RED.view.reveal(n.node.id);
|
||||
$("#red-ui-view-searchtools-prev").trigger("focus");
|
||||
}
|
||||
updateSearchToolbar();
|
||||
}
|
||||
function revealNext() {
|
||||
if (disabled) {
|
||||
updateSearchToolbar();
|
||||
return;
|
||||
}
|
||||
if (!searchResults || !activeResults.length) {
|
||||
show();
|
||||
return;
|
||||
}
|
||||
if (currentIndex < activeResults.length - 1) {
|
||||
currentIndex++
|
||||
} else {
|
||||
currentIndex = 0;
|
||||
}
|
||||
const n = activeResults[currentIndex];
|
||||
if (n && n.node && n.node.id) {
|
||||
RED.view.reveal(n.node.id);
|
||||
$("#red-ui-view-searchtools-next").trigger("focus");
|
||||
}
|
||||
updateSearchToolbar();
|
||||
}
|
||||
|
||||
function show(v) {
|
||||
if (disabled) {
|
||||
updateSearchToolbar();
|
||||
return;
|
||||
}
|
||||
if (!visible) {
|
||||
@@ -365,16 +506,21 @@ RED.search = (function() {
|
||||
|
||||
if (dialog === null) {
|
||||
createDialog();
|
||||
} else {
|
||||
searchResults.editableList('empty');
|
||||
}
|
||||
dialog.slideDown(300);
|
||||
searchInput.searchBox('value',v)
|
||||
if (!v || v === "") {
|
||||
populateSearchHistory();
|
||||
}
|
||||
RED.events.emit("search:open");
|
||||
visible = true;
|
||||
}
|
||||
searchInput.trigger("focus");
|
||||
}
|
||||
|
||||
function hide() {
|
||||
function hide(el, keepSearchToolbar) {
|
||||
if (visible) {
|
||||
visible = false;
|
||||
$("#red-ui-header-shade").hide();
|
||||
@@ -388,13 +534,37 @@ RED.search = (function() {
|
||||
});
|
||||
}
|
||||
RED.events.emit("search:close");
|
||||
if (previousActiveElement) {
|
||||
if (previousActiveElement && (!keepSearchToolbar || !activeResults.length)) {
|
||||
$(previousActiveElement).trigger("focus");
|
||||
previousActiveElement = null;
|
||||
}
|
||||
previousActiveElement = null;
|
||||
}
|
||||
if(!keepSearchToolbar) {
|
||||
clearActiveSearch();
|
||||
}
|
||||
updateSearchToolbar();
|
||||
if(keepSearchToolbar && activeResults.length) {
|
||||
$("#red-ui-view-searchtools-next").trigger("focus");
|
||||
}
|
||||
}
|
||||
function updateSearchToolbar() {
|
||||
if (!disabled && currentIndex >= 0 && activeResults && activeResults.length) {
|
||||
let term = $("#red-ui-view-searchtools-search").data("term") || "";
|
||||
if (term.length > 16) {
|
||||
term = term.substring(0, 12) + "..."
|
||||
}
|
||||
const i18nSearchCounterData = {
|
||||
term: term,
|
||||
result: (currentIndex + 1),
|
||||
count: activeResults.length
|
||||
}
|
||||
$("#red-ui-view-searchtools-counter").text(RED._('actions.search-counter', i18nSearchCounterData));
|
||||
$("#view-search-tools > :not(:first-child)").show(); //show other tools
|
||||
} else {
|
||||
clearActiveSearch();
|
||||
$("#view-search-tools > :not(:first-child)").hide(); //hide all but search button
|
||||
}
|
||||
}
|
||||
|
||||
function clearIndex() {
|
||||
index = {};
|
||||
}
|
||||
@@ -416,9 +586,29 @@ RED.search = (function() {
|
||||
addItemToIndex(item);
|
||||
}
|
||||
|
||||
function clearActiveSearch() {
|
||||
activeResults = [];
|
||||
currentIndex = 0;
|
||||
$("#red-ui-view-searchtools-search").data("term", "");
|
||||
}
|
||||
|
||||
function getSearchOptions() {
|
||||
return [
|
||||
{label:RED._("search.options.configNodes"), value:"is:config"},
|
||||
{label:RED._("search.options.unusedConfigNodes"), value:"is:config is:unused"},
|
||||
{label:RED._("search.options.modifiedNodes"), value:"is:modified"},
|
||||
{label:RED._("search.options.invalidNodes"), value: "is:invalid"},
|
||||
{label:RED._("search.options.uknownNodes"), value: "type:unknown"},
|
||||
{label:RED._("search.options.unusedSubflows"), value:"is:subflow is:unused"},
|
||||
{label:RED._("search.options.hiddenFlows"), value:"is:hidden"},
|
||||
{label:RED._("search.options.thisFlow"), value:"flow:current"},
|
||||
]
|
||||
}
|
||||
|
||||
function init() {
|
||||
RED.actions.add("core:search",show);
|
||||
RED.actions.add("core:search-previous",revealPrev);
|
||||
RED.actions.add("core:search-next",revealNext);
|
||||
|
||||
RED.events.on("editor:open",function() { disabled = true; });
|
||||
RED.events.on("editor:close",function() { disabled = false; });
|
||||
@@ -429,11 +619,21 @@ RED.search = (function() {
|
||||
|
||||
RED.keyboard.add("red-ui-search","escape",hide);
|
||||
|
||||
RED.keyboard.add("view-search-tools","escape",function() {
|
||||
clearActiveSearch();
|
||||
updateSearchToolbar();
|
||||
});
|
||||
|
||||
$("#red-ui-header-shade").on('mousedown',hide);
|
||||
$("#red-ui-editor-shade").on('mousedown',hide);
|
||||
$("#red-ui-palette-shade").on('mousedown',hide);
|
||||
$("#red-ui-sidebar-shade").on('mousedown',hide);
|
||||
|
||||
$("#red-ui-view-searchtools-close").on("click", function close() {
|
||||
clearActiveSearch();
|
||||
updateSearchToolbar();
|
||||
});
|
||||
$("#red-ui-view-searchtools-close").trigger("click");
|
||||
|
||||
RED.events.on("workspace:clear", clearIndex);
|
||||
|
||||
@@ -459,7 +659,8 @@ RED.search = (function() {
|
||||
init: init,
|
||||
show: show,
|
||||
hide: hide,
|
||||
search: search
|
||||
search: search,
|
||||
getSearchOptions: getSearchOptions
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -19,6 +19,15 @@ RED.sidebar = (function() {
|
||||
var sidebar_tabs;
|
||||
var knownTabs = {};
|
||||
|
||||
// We store the current sidebar tab id in localStorage as 'last-sidebar-tab'
|
||||
// This is restored when the editor is reloaded.
|
||||
// We use sidebar_tabs.onchange to update localStorage. However that will
|
||||
// also get triggered when the first tab gets added to the tabs - typically
|
||||
// the 'info' tab. So we use the following variable to store the retrieved
|
||||
// value from localStorage before we start adding the actual tabs
|
||||
var lastSessionSelectedTab = null;
|
||||
|
||||
|
||||
function addTab(title,content,closeable,visible) {
|
||||
var options;
|
||||
if (typeof title === "string") {
|
||||
@@ -194,16 +203,16 @@ RED.sidebar = (function() {
|
||||
RED.events.emit("sidebar:resize");
|
||||
}
|
||||
|
||||
function showSidebar(id) {
|
||||
function showSidebar(id, skipShowSidebar) {
|
||||
if (id === ":first") {
|
||||
id = RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])[0]
|
||||
id = lastSessionSelectedTab || RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])[0]
|
||||
}
|
||||
if (id) {
|
||||
if (!containsTab(id) && knownTabs[id]) {
|
||||
sidebar_tabs.addTab(knownTabs[id]);
|
||||
}
|
||||
sidebar_tabs.activateTab(id);
|
||||
if (!RED.menu.isSelected("menu-item-sidebar")) {
|
||||
if (!skipShowSidebar && !RED.menu.isSelected("menu-item-sidebar")) {
|
||||
RED.menu.setSelected("menu-item-sidebar",true);
|
||||
}
|
||||
}
|
||||
@@ -227,6 +236,7 @@ RED.sidebar = (function() {
|
||||
if (tab.toolbar) {
|
||||
$(tab.toolbar).show();
|
||||
}
|
||||
RED.settings.setLocal("last-sidebar-tab", tab.id)
|
||||
},
|
||||
onremove: function(tab) {
|
||||
$(tab.wrapper).hide();
|
||||
@@ -255,7 +265,9 @@ RED.sidebar = (function() {
|
||||
}
|
||||
});
|
||||
RED.popover.tooltip($("#red-ui-sidebar-separator").find(".red-ui-sidebar-control-right"),RED._("keyboard.toggleSidebar"),"core:toggle-sidebar");
|
||||
showSidebar();
|
||||
|
||||
lastSessionSelectedTab = RED.settings.getLocal("last-sidebar-tab")
|
||||
|
||||
RED.sidebar.info.init();
|
||||
RED.sidebar.help.init();
|
||||
RED.sidebar.config.init();
|
||||
|
||||
@@ -27,5 +27,8 @@ RED.state = {
|
||||
PANNING: 10,
|
||||
SELECTING_NODE: 11,
|
||||
GROUP_DRAGGING: 12,
|
||||
GROUP_RESIZE: 13
|
||||
GROUP_RESIZE: 13,
|
||||
DETACHED_DRAGGING: 14,
|
||||
SLICING: 15,
|
||||
SLICING_JUNCTION: 16
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ RED.statusBar = (function() {
|
||||
function addWidget(options) {
|
||||
widgets[options.id] = options;
|
||||
var el = $('<span class="red-ui-statusbar-widget"></span>');
|
||||
el.prop('id', options.id);
|
||||
options.element.appendTo(el);
|
||||
if (options.align === 'left') {
|
||||
leftBucket.append(el);
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
RED.subflow = (function() {
|
||||
|
||||
var currentLocale = "en-US";
|
||||
|
||||
var _subflowEditTemplate = '<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>'+
|
||||
@@ -37,7 +35,7 @@ RED.subflow = (function() {
|
||||
'<div id="subflow-env-tabs-content">'+
|
||||
'<div id="subflow-env-tab-edit">'+
|
||||
'<div class="form-row node-input-env-container-row" id="subflow-input-edit-ui">'+
|
||||
'<ol class="red-ui-editor-subflow-env-list" id="node-input-env-container"></ol>'+
|
||||
'<ol id="node-input-env-container"></ol>'+
|
||||
'<div class="node-input-env-locales-row"><i class="fa fa-language"></i> <select id="subflow-input-env-locale"></select></div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
@@ -47,37 +45,6 @@ RED.subflow = (function() {
|
||||
'</div>'+
|
||||
'</script>';
|
||||
|
||||
var _subflowModulePaneTemplate = '<form class="dialog-form form-horizontal" autocomplete="off">'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-module" data-i18n="[append]editor:subflow.module"><i class="fa fa-cube"></i> </label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-module" data-i18n="[placeholder]common.label.name">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-type" data-i18n="[append]editor:subflow.type"> </label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-type">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-version" data-i18n="[append]editor:subflow.version"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-version" data-i18n="[placeholder]editor:subflow.versionPlaceholder">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-desc" data-i18n="[append]editor:subflow.desc"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-desc">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-license" data-i18n="[append]editor:subflow.license"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-license">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-author" data-i18n="[append]editor:subflow.author"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-author" data-i18n="[placeholder]editor:subflow.authorPlaceholder">'+
|
||||
'</div>'+
|
||||
'<div class="form-row">'+
|
||||
'<label for="subflow-input-module-keywords" data-i18n="[append]editor:subflow.keys"></label>'+
|
||||
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-keywords" data-i18n="[placeholder]editor:subflow.keysPlaceholder">'+
|
||||
'</div>'+
|
||||
'</form>';
|
||||
|
||||
function findAvailableSubflowIOPosition(subflow,isInput) {
|
||||
var pos = {x:50,y:30};
|
||||
if (!isInput) {
|
||||
@@ -637,6 +604,14 @@ RED.subflow = (function() {
|
||||
return x;
|
||||
}
|
||||
|
||||
function nodeOrJunction(id) {
|
||||
var node = RED.nodes.node(id);
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
return RED.nodes.junction(id);
|
||||
}
|
||||
|
||||
function convertToSubflow() {
|
||||
var selection = RED.view.selection();
|
||||
if (!selection.nodes) {
|
||||
@@ -825,14 +800,15 @@ RED.subflow = (function() {
|
||||
|
||||
subflow.in.forEach(function(input) {
|
||||
input.wires.forEach(function(wire) {
|
||||
var link = {source: input, sourcePort: 0, target: RED.nodes.node(wire.id) }
|
||||
var link = {source: input, sourcePort: 0, target: nodeOrJunction(wire.id) }
|
||||
new_links.push(link);
|
||||
RED.nodes.addLink(link);
|
||||
});
|
||||
});
|
||||
|
||||
subflow.out.forEach(function(output,i) {
|
||||
output.wires.forEach(function(wire) {
|
||||
var link = {source: RED.nodes.node(wire.id), sourcePort: wire.port , target: output }
|
||||
var link = {source: nodeOrJunction(wire.id), sourcePort: wire.port , target: output }
|
||||
new_links.push(link);
|
||||
RED.nodes.addLink(link);
|
||||
});
|
||||
@@ -848,7 +824,7 @@ RED.subflow = (function() {
|
||||
n.links = n.links.filter(function(id) {
|
||||
var isLocalLink = nodes.hasOwnProperty(id);
|
||||
if (!isLocalLink) {
|
||||
var otherNode = RED.nodes.node(id);
|
||||
var otherNode = nodeOrJunction(id);
|
||||
if (otherNode && otherNode.links) {
|
||||
var i = otherNode.links.indexOf(n.id);
|
||||
if (i > -1) {
|
||||
@@ -864,7 +840,6 @@ RED.subflow = (function() {
|
||||
RED.nodes.moveNodeToTab(n, subflow.id);
|
||||
}
|
||||
|
||||
|
||||
var historyEvent = {
|
||||
t:'createSubflow',
|
||||
nodes:[subflowInstance.id],
|
||||
@@ -909,7 +884,6 @@ RED.subflow = (function() {
|
||||
* Create interface for controlling env var UI definition
|
||||
*/
|
||||
function buildEnvControl(envList,node) {
|
||||
|
||||
var tabs = RED.tabs.create({
|
||||
id: "subflow-env-tabs",
|
||||
onchange: function(tab) {
|
||||
@@ -950,588 +924,11 @@ RED.subflow = (function() {
|
||||
locales.val(locale);
|
||||
|
||||
locales.on("change", function() {
|
||||
currentLocale = $(this).val();
|
||||
var items = $("#node-input-env-container").editableList("items");
|
||||
items.each(function (i, item) {
|
||||
var entry = $(this).data('data');
|
||||
var labelField = entry.ui.labelField;
|
||||
labelField.val(lookupLabel(entry.ui.label, "", currentLocale));
|
||||
if (labelField.timeout) {
|
||||
clearTimeout(labelField.timeout);
|
||||
delete labelField.timeout;
|
||||
}
|
||||
labelField.addClass("input-updated");
|
||||
labelField.timeout = setTimeout(function() {
|
||||
delete labelField.timeout
|
||||
labelField.removeClass("input-updated");
|
||||
},3000);
|
||||
});
|
||||
RED.editor.envVarList.setLocale($(this).val(), $("#node-input-env-container"));
|
||||
});
|
||||
RED.editor.envVarList.setLocale(locale);
|
||||
}
|
||||
|
||||
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
||||
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
|
||||
|
||||
/**
|
||||
* Create env var edit interface
|
||||
* @param container - container
|
||||
* @param node - subflow node
|
||||
*/
|
||||
function buildPropertiesList(envContainer, node) {
|
||||
|
||||
var isTemplateNode = (node.type === "subflow");
|
||||
|
||||
if (isTemplateNode) {
|
||||
buildEnvControl(envContainer, node);
|
||||
}
|
||||
envContainer
|
||||
.css({
|
||||
'min-height':'150px',
|
||||
'min-width':'450px'
|
||||
})
|
||||
.editableList({
|
||||
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
|
||||
addItem: function(container, i, opt) {
|
||||
// If this is an instance node, these are properties unique to
|
||||
// this instance - ie opt.parent will not be defined.
|
||||
|
||||
if (isTemplateNode) {
|
||||
container.addClass("red-ui-editor-subflow-env-editable")
|
||||
}
|
||||
|
||||
var envRow = $('<div/>').appendTo(container);
|
||||
var nameField = null;
|
||||
var valueField = null;
|
||||
|
||||
nameField = $('<input/>', {
|
||||
class: "node-input-env-name",
|
||||
type: "text",
|
||||
placeholder: RED._("common.label.name")
|
||||
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
|
||||
valueField = $('<input/>',{
|
||||
style: "width:100%",
|
||||
class: "node-input-env-value",
|
||||
type: "text",
|
||||
}).attr("autocomplete","disable").appendTo(envRow)
|
||||
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
|
||||
valueField.typedInput('type', opt.type);
|
||||
if (opt.type === "cred") {
|
||||
if (opt.value) {
|
||||
valueField.typedInput('value', opt.value);
|
||||
} else if (node.credentials && node.credentials[opt.name]) {
|
||||
valueField.typedInput('value', node.credentials[opt.name]);
|
||||
} else if (node.credentials && node.credentials['has_'+opt.name]) {
|
||||
valueField.typedInput('value', "__PWRD__");
|
||||
} else {
|
||||
valueField.typedInput('value', "");
|
||||
}
|
||||
} else {
|
||||
valueField.typedInput('value', opt.value);
|
||||
}
|
||||
|
||||
|
||||
opt.nameField = nameField;
|
||||
opt.valueField = valueField;
|
||||
|
||||
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
|
||||
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
|
||||
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
|
||||
actionButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
removeTip.close();
|
||||
container.parent().addClass("red-ui-editableList-item-deleting")
|
||||
container.fadeOut(300, function() {
|
||||
envContainer.editableList('removeItem',opt);
|
||||
});
|
||||
});
|
||||
|
||||
if (isTemplateNode) {
|
||||
// Add the UI customisation row
|
||||
// if `opt.ui` does not exist, then apply defaults. If these
|
||||
// defaults do not change then they will get stripped off
|
||||
// before saving.
|
||||
if (opt.type === 'cred') {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "cred"
|
||||
}
|
||||
opt.ui.type = "cred";
|
||||
} else {
|
||||
opt.ui = opt.ui || {
|
||||
icon: "",
|
||||
type: "input",
|
||||
opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||
}
|
||||
}
|
||||
opt.ui.label = opt.ui.label || {};
|
||||
opt.ui.type = opt.ui.type || "input";
|
||||
|
||||
var uiRow = $('<div/>').appendTo(container).hide();
|
||||
// save current info for reverting on cancel
|
||||
// var copy = $.extend(true, {}, ui);
|
||||
|
||||
$('<a href="#"><i class="fa fa-angle-right"></a>').prependTo(envRow).on("click", function (evt) {
|
||||
evt.preventDefault();
|
||||
if ($(this).hasClass('expanded')) {
|
||||
uiRow.slideUp();
|
||||
$(this).removeClass('expanded');
|
||||
} else {
|
||||
uiRow.slideDown();
|
||||
$(this).addClass('expanded');
|
||||
}
|
||||
});
|
||||
|
||||
buildEnvEditRow(uiRow, opt.ui, nameField, valueField);
|
||||
nameField.trigger('change');
|
||||
}
|
||||
},
|
||||
sortable: ".red-ui-editableList-item-handle",
|
||||
removable: false
|
||||
});
|
||||
var parentEnv = {};
|
||||
var envList = [];
|
||||
if (/^subflow:/.test(node.type)) {
|
||||
var subflowDef = RED.nodes.subflow(node.type.substring(8));
|
||||
if (subflowDef.env) {
|
||||
subflowDef.env.forEach(function(env) {
|
||||
var item = {
|
||||
name:env.name,
|
||||
parent: {
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
}
|
||||
}
|
||||
envList.push(item);
|
||||
parentEnv[env.name] = item;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (node.env) {
|
||||
for (var i = 0; i < node.env.length; i++) {
|
||||
var env = node.env[i];
|
||||
if (parentEnv.hasOwnProperty(env.name)) {
|
||||
parentEnv[env.name].type = env.type;
|
||||
parentEnv[env.name].value = env.value;
|
||||
} else {
|
||||
envList.push({
|
||||
name: env.name,
|
||||
type: env.type,
|
||||
value: env.value,
|
||||
ui: env.ui
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
envList.forEach(function(env) {
|
||||
if (env.parent && env.parent.ui && env.parent.ui.type === 'hide') {
|
||||
return;
|
||||
}
|
||||
if (!isTemplateNode && env.parent) {
|
||||
return;
|
||||
}
|
||||
envContainer.editableList('addItem', JSON.parse(JSON.stringify(env)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create UI edit interface for environment variable
|
||||
* @param container - container
|
||||
* @param env - env var definition
|
||||
* @param nameField - name field of env var
|
||||
* @param valueField - value field of env var
|
||||
*/
|
||||
function buildEnvEditRow(container, ui, nameField, valueField) {
|
||||
container.addClass("red-ui-editor-subflow-env-ui-row")
|
||||
var topRow = $('<div></div>').appendTo(container);
|
||||
$('<div></div>').appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.icon")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.label")).appendTo(topRow);
|
||||
$('<div>').text(RED._("editor.inputType")).appendTo(topRow);
|
||||
|
||||
var row = $('<div></div>').appendTo(container);
|
||||
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
|
||||
var typeOptions = {
|
||||
'input': {types:DEFAULT_ENV_TYPE_LIST},
|
||||
'select': {opts:[]},
|
||||
'spinner': {},
|
||||
'cred': {}
|
||||
};
|
||||
if (ui.opts) {
|
||||
typeOptions[ui.type] = ui.opts;
|
||||
} else {
|
||||
// Pick up the default values if not otherwise provided
|
||||
ui.opts = typeOptions[ui.type];
|
||||
}
|
||||
var iconCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var iconButton = $('<a href="#"></a>').appendTo(iconCell);
|
||||
iconButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var icon = ui.icon || "";
|
||||
var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
|
||||
RED.editor.showIconPicker(iconButton, null, iconPath, true, function (newIcon) {
|
||||
iconButton.empty();
|
||||
var path = newIcon || "";
|
||||
var newPath = RED.utils.separateIconPath(path);
|
||||
if (newPath) {
|
||||
$('<i class="fa"></i>').addClass(newPath.file).appendTo(iconButton);
|
||||
}
|
||||
ui.icon = path;
|
||||
});
|
||||
})
|
||||
|
||||
if (ui.icon) {
|
||||
var newPath = RED.utils.separateIconPath(ui.icon);
|
||||
$('<i class="fa '+newPath.file+'"></i>').appendTo(iconButton);
|
||||
}
|
||||
|
||||
var labelCell = $('<div></div>').appendTo(row);
|
||||
|
||||
var label = ui.label && ui.label[currentLocale] || "";
|
||||
var labelInput = $('<input type="text">').val(label).appendTo(labelCell);
|
||||
ui.labelField = labelInput;
|
||||
labelInput.on('change', function(evt) {
|
||||
ui.label = ui.label || {};
|
||||
var val = $(this).val().trim();
|
||||
if (val === "") {
|
||||
delete ui.label[currentLocale];
|
||||
} else {
|
||||
ui.label[currentLocale] = val;
|
||||
}
|
||||
})
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelCell);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
var langs = Object.keys(ui.label);
|
||||
var content = $("<div>");
|
||||
if (langs.indexOf(currentLocale) === -1) {
|
||||
langs.push(currentLocale);
|
||||
langs.sort();
|
||||
}
|
||||
langs.forEach(function(l) {
|
||||
var row = $('<div>').appendTo(content);
|
||||
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
|
||||
$('<span>').text(ui.label[l]||"").appendTo(row);
|
||||
});
|
||||
return content;
|
||||
})
|
||||
|
||||
nameField.on('change',function(evt) {
|
||||
labelInput.attr("placeholder",$(this).val())
|
||||
});
|
||||
|
||||
var inputCell = $('<div></div>').appendTo(row);
|
||||
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
|
||||
if (ui.type === "input") {
|
||||
inputCellInput.val(ui.opts.types.join(","));
|
||||
}
|
||||
var checkbox;
|
||||
var selectBox;
|
||||
|
||||
inputCellInput.typedInput({
|
||||
types: [
|
||||
{
|
||||
value:"input",
|
||||
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
|
||||
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
|
||||
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
|
||||
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
|
||||
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
|
||||
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
|
||||
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"},
|
||||
{value: "cred",label: RED._("editor.types.cred"),icon: "fa fa-lock"}
|
||||
],
|
||||
default: DEFAULT_ENV_TYPE_LIST,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
|
||||
if (value.length) {
|
||||
value.forEach(function(v) {
|
||||
if (!/^fa /.test(v.icon)) {
|
||||
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
} else {
|
||||
var s = $('<span>',{style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
|
||||
$("<i>",{class: v.icon}).appendTo(s);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
$('<span class="red-ui-editor-subflow-env-input-type-placeholder"></span>').text(RED._("editor.selectType")).appendTo(input);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value: "cred",
|
||||
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type">').css({
|
||||
"border-top-right-radius": "4px",
|
||||
"border-bottom-right-radius": "4px"
|
||||
}).appendTo(container);
|
||||
$('<div class="placeholder-input">').html("••••••••").appendTo(innerContainer);
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"select",
|
||||
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding","0");
|
||||
|
||||
selectBox = $('<select></select>').appendTo(container);
|
||||
if (ui.opts && Array.isArray(ui.opts.opts)) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
|
||||
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
|
||||
$('<option>').val(o.v).text(label).appendTo(selectBox);
|
||||
})
|
||||
}
|
||||
selectBox.on('change', function(evt) {
|
||||
var v = selectBox.val();
|
||||
// var parts = v.split(":");
|
||||
// var t = parts.shift();
|
||||
// v = parts.join(":");
|
||||
//
|
||||
// valueField.typedInput("type",'str')
|
||||
valueField.typedInput("value",v)
|
||||
});
|
||||
selectBox.val(valueField.typedInput("value"));
|
||||
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
minWidth: 400,
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
var optList = $('<ol>').appendTo(content).editableList({
|
||||
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
|
||||
addItem: function(row,index,itemData) {
|
||||
var labelDiv = $('<div>').appendTo(row);
|
||||
var label = lookupLabel(itemData.l, "", currentLocale);
|
||||
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
|
||||
itemData.label.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
itemData.input.focus();
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
|
||||
RED.popover.tooltip(labelIcon,function() {
|
||||
return currentLocale;
|
||||
})
|
||||
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
|
||||
|
||||
// Problem using a TI here:
|
||||
// - this is in a popout panel
|
||||
// - clicking the expand button in the TI will close the parent edit tray
|
||||
// and open the type editor.
|
||||
// - but it leaves the popout panel over the top.
|
||||
// - there is no way to get back to the popout panel after closing the type editor
|
||||
//.typedInput({default:itemData.t||'str', types:DEFAULT_ENV_TYPE_LIST});
|
||||
itemData.input.on('keydown', function(evt) {
|
||||
if (evt.keyCode === 13) {
|
||||
// Enter or Tab
|
||||
var index = optList.editableList('indexOf',itemData);
|
||||
var length = optList.editableList('length');
|
||||
if (index + 1 === length) {
|
||||
var newItem = {};
|
||||
optList.editableList('addItem',newItem);
|
||||
setTimeout(function() {
|
||||
if (newItem.label) {
|
||||
newItem.label.focus();
|
||||
}
|
||||
},100)
|
||||
} else {
|
||||
var nextItem = optList.editableList('getItemAt',index+1);
|
||||
if (nextItem.label) {
|
||||
nextItem.label.focus()
|
||||
}
|
||||
}
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
},
|
||||
sortable: true,
|
||||
removable: true,
|
||||
height: 160
|
||||
})
|
||||
if (ui.opts.opts.length > 0) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
optList.editableList('addItem',$.extend(true,{},o))
|
||||
})
|
||||
} else {
|
||||
optList.editableList('addItem',{})
|
||||
}
|
||||
return {
|
||||
onclose: function() {
|
||||
var items = optList.editableList('items');
|
||||
var vals = [];
|
||||
items.each(function (i,el) {
|
||||
var data = el.data('data');
|
||||
var l = data.label.val().trim();
|
||||
var v = data.input.val();
|
||||
// var t = data.input.typedInput('type');
|
||||
// var v = data.input.typedInput('value');
|
||||
if (l.length > 0) {
|
||||
data.l = data.l || {};
|
||||
data.l[currentLocale] = l;
|
||||
}
|
||||
data.v = v;
|
||||
|
||||
if (l.length > 0 || v.length > 0) {
|
||||
var val = {l:data.l,v:data.v};
|
||||
// if (t !== 'str') {
|
||||
// val.t = t;
|
||||
// }
|
||||
vals.push(val);
|
||||
}
|
||||
});
|
||||
ui.opts.opts = vals;
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"checkbox",
|
||||
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
checkbox = $('<input type="checkbox">').appendTo(container);
|
||||
checkbox.on('change', function(evt) {
|
||||
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
|
||||
})
|
||||
checkbox.prop('checked',valueField.typedInput('value')==="true");
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"spinner",
|
||||
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
|
||||
valueLabel: function(container,value) {
|
||||
container.css("padding",0);
|
||||
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
|
||||
|
||||
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
|
||||
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
|
||||
|
||||
var min = ui.opts && ui.opts.min;
|
||||
var max = ui.opts && ui.opts.max;
|
||||
var label = "";
|
||||
if (min !== undefined && max !== undefined) {
|
||||
label = Math.min(min,max)+" - "+Math.max(min,max);
|
||||
} else if (min !== undefined) {
|
||||
label = "> "+min;
|
||||
} else if (max !== undefined) {
|
||||
label = "< "+max;
|
||||
}
|
||||
$('<span>').css("margin-left","15px").text(label).appendTo(input);
|
||||
},
|
||||
expand: {
|
||||
icon: "fa-caret-down",
|
||||
content: function(container) {
|
||||
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
|
||||
content.css("padding","8px 5px")
|
||||
var min = ui.opts.min;
|
||||
var max = ui.opts.max;
|
||||
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
minInput.val(min);
|
||||
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
|
||||
maxInput.val(max);
|
||||
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
|
||||
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
|
||||
return {
|
||||
onclose: function() {
|
||||
var min = minInput.val().trim();
|
||||
var max = maxInput.val().trim();
|
||||
if (min !== "") {
|
||||
ui.opts.min = parseInt(min);
|
||||
} else {
|
||||
delete ui.opts.min;
|
||||
}
|
||||
if (max !== "") {
|
||||
ui.opts.max = parseInt(max);
|
||||
} else {
|
||||
delete ui.opts.max;
|
||||
}
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value:"none",
|
||||
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
|
||||
},
|
||||
{
|
||||
value:"hide",
|
||||
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
|
||||
}
|
||||
],
|
||||
default: 'none'
|
||||
}).on("typedinputtypechange", function(evt,type) {
|
||||
ui.type = $(this).typedInput("type");
|
||||
ui.opts = typeOptions[ui.type];
|
||||
if (ui.type === 'input') {
|
||||
// In the case of 'input' type, the typedInput uses the multiple-option
|
||||
// mode. Its value needs to be set to a comma-separately list of the
|
||||
// selected options.
|
||||
inputCellInput.typedInput('value',ui.opts.types.join(","))
|
||||
} else {
|
||||
// No other type cares about `value`, but doing this will
|
||||
// force a refresh of the label now that `ui.opts` has
|
||||
// been updated.
|
||||
inputCellInput.typedInput('value',Date.now())
|
||||
}
|
||||
|
||||
switch (ui.type) {
|
||||
case 'input':
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
break;
|
||||
case 'select':
|
||||
valueField.typedInput('types',['str']);
|
||||
break;
|
||||
case 'checkbox':
|
||||
valueField.typedInput('types',['bool']);
|
||||
break;
|
||||
case 'spinner':
|
||||
valueField.typedInput('types',['num']);
|
||||
break;
|
||||
case 'cred':
|
||||
valueField.typedInput('types',['cred']);
|
||||
break;
|
||||
default:
|
||||
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
|
||||
}
|
||||
if (ui.type === 'checkbox') {
|
||||
valueField.typedInput('type','bool');
|
||||
} else if (ui.type === 'spinner') {
|
||||
valueField.typedInput('type','num');
|
||||
}
|
||||
if (ui.type !== 'checkbox') {
|
||||
checkbox = null;
|
||||
}
|
||||
|
||||
}).on("change", function(evt,type) {
|
||||
if (ui.type === 'input') {
|
||||
var types = inputCellInput.typedInput('value');
|
||||
ui.opts.types = (types === "") ? ["str"] : types.split(",");
|
||||
valueField.typedInput('types',ui.opts.types);
|
||||
}
|
||||
});
|
||||
valueField.on("change", function(evt) {
|
||||
if (checkbox) {
|
||||
checkbox.prop('checked',$(this).typedInput('value')==="true")
|
||||
}
|
||||
})
|
||||
// Set the input to the right type. This will trigger the 'typedinputtypechange'
|
||||
// event handler (just above ^^) to update the value if needed
|
||||
inputCellInput.typedInput('type',ui.type)
|
||||
}
|
||||
|
||||
function buildEnvUIRow(row, tenv, ui, node) {
|
||||
ui.label = ui.label||{};
|
||||
@@ -1540,7 +937,7 @@ RED.subflow = (function() {
|
||||
ui.opts = {};
|
||||
} else if (!ui.type) {
|
||||
ui.type = "input";
|
||||
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
|
||||
ui.opts = { types: RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST }
|
||||
} else {
|
||||
if (!ui.opts) {
|
||||
ui.opts = (ui.type === "select") ? {opts:[]} : {};
|
||||
@@ -1549,7 +946,7 @@ RED.subflow = (function() {
|
||||
|
||||
var labels = ui.label || {};
|
||||
var locale = RED.i18n.lang();
|
||||
var labelText = lookupLabel(labels, labels["en-US"]||tenv.name, locale);
|
||||
var labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"]||tenv.name, locale);
|
||||
var label = $('<label>').appendTo(row);
|
||||
$('<span> </span>').appendTo(row);
|
||||
var labelContainer = $('<span></span>').appendTo(label);
|
||||
@@ -1602,7 +999,7 @@ RED.subflow = (function() {
|
||||
input = $('<select>').css('width','70%').appendTo(row);
|
||||
if (ui.opts.opts) {
|
||||
ui.opts.opts.forEach(function(o) {
|
||||
$('<option>').val(o.v).text(lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
|
||||
$('<option>').val(o.v).text(RED.editor.envVarList.lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
|
||||
})
|
||||
}
|
||||
input.val(val.value);
|
||||
@@ -1668,9 +1065,8 @@ RED.subflow = (function() {
|
||||
* @param uiContainer - container for UI
|
||||
* @param envList - env var definitions of template
|
||||
*/
|
||||
function buildEnvUI(uiContainer, envList,node) {
|
||||
function buildEnvUI(uiContainer, envList, node) {
|
||||
uiContainer.empty();
|
||||
var elementID = 0;
|
||||
for (var i = 0; i < envList.length; i++) {
|
||||
var tenv = envList[i];
|
||||
if (tenv.ui && tenv.ui.type === 'hide') {
|
||||
@@ -1678,8 +1074,6 @@ RED.subflow = (function() {
|
||||
}
|
||||
var row = $("<div/>", { class: "form-row" }).appendTo(uiContainer);
|
||||
buildEnvUIRow(row,tenv, tenv.ui || {}, node);
|
||||
|
||||
// console.log(ui);
|
||||
}
|
||||
}
|
||||
// buildEnvUI
|
||||
@@ -1715,7 +1109,7 @@ RED.subflow = (function() {
|
||||
// icon: "",
|
||||
// label: {},
|
||||
// type: "input",
|
||||
// opts: {types:DEFAULT_ENV_TYPE_LIST}
|
||||
// opts: {types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST}
|
||||
// }
|
||||
if (!ui.icon) {
|
||||
delete ui.icon;
|
||||
@@ -1725,7 +1119,7 @@ RED.subflow = (function() {
|
||||
}
|
||||
switch (ui.type) {
|
||||
case "input":
|
||||
if (JSON.stringify(ui.opts) === JSON.stringify({types:DEFAULT_ENV_TYPE_LIST})) {
|
||||
if (JSON.stringify(ui.opts) === JSON.stringify({types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST})) {
|
||||
// This is the default input config. Delete it as it will
|
||||
// be applied automatically
|
||||
delete ui.type;
|
||||
@@ -1841,7 +1235,6 @@ RED.subflow = (function() {
|
||||
|
||||
function exportSubflowInstanceEnv(node) {
|
||||
var env = [];
|
||||
|
||||
// First, get the values for the SubflowTemplate defined properties
|
||||
// - these are the ones with custom UI elements
|
||||
var parentEnv = getSubflowInstanceParentEnv(node);
|
||||
@@ -1853,7 +1246,7 @@ RED.subflow = (function() {
|
||||
ui.type = "cred";
|
||||
} else {
|
||||
ui.type = "input";
|
||||
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
|
||||
ui.opts = {types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST}
|
||||
}
|
||||
} else {
|
||||
ui.opts = ui.opts || {};
|
||||
@@ -1893,22 +1286,6 @@ RED.subflow = (function() {
|
||||
}
|
||||
}
|
||||
})
|
||||
// Second, get the values from the Properties table tab
|
||||
var items = $('#red-ui-editor-subflow-env-list').editableList('items');
|
||||
items.each(function (i,el) {
|
||||
var data = el.data('data');
|
||||
var item;
|
||||
if (data.nameField && data.valueField) {
|
||||
item = {
|
||||
name: data.nameField.val(),
|
||||
value: data.valueField.typedInput("value"),
|
||||
type: data.valueField.typedInput("type")
|
||||
}
|
||||
if (item.name.trim() !== "") {
|
||||
env.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -1916,164 +1293,18 @@ RED.subflow = (function() {
|
||||
return 'node-input-subflow-env-'+name.replace(/[^a-z0-9-_]/ig,"_");
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup text for specific locale
|
||||
* @param labels - dict of labels
|
||||
* @param defaultLabel - fallback label if not found
|
||||
* @param locale - target locale
|
||||
* @returns {string} text for specified locale
|
||||
*/
|
||||
function lookupLabel(labels, defaultLabel, locale) {
|
||||
if (labels) {
|
||||
if (labels[locale]) {
|
||||
return labels[locale];
|
||||
}
|
||||
if (locale) {
|
||||
var lang = locale.substring(0, 2);
|
||||
if (labels[lang]) {
|
||||
return labels[lang];
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultLabel;
|
||||
}
|
||||
|
||||
// Called by subflow.oneditprepare for both instances and templates
|
||||
function buildEditForm(type,node) {
|
||||
if (type === "subflow-template") {
|
||||
buildPropertiesList($('#node-input-env-container'), node);
|
||||
// This is the tabbed UI that offers the env list - with UI options
|
||||
// plus the preview tab
|
||||
buildEnvControl($('#node-input-env-container'), node);
|
||||
RED.editor.envVarList.create($('#node-input-env-container'), node);
|
||||
} else if (type === "subflow") {
|
||||
// This gets called by the subflow type `oneditprepare` function
|
||||
// registered in nodes.js#addSubflow()
|
||||
// This is the rendered version of the subflow env var list
|
||||
buildEnvUI($("#subflow-input-ui"), getSubflowInstanceParentEnv(node), node);
|
||||
}
|
||||
}
|
||||
function buildPropertiesForm(node) {
|
||||
var container = $('#editor-subflow-envProperties-content');
|
||||
var form = $('<form class="dialog-form form-horizontal"></form>').appendTo(container);
|
||||
var listContainer = $('<div class="form-row node-input-env-container-row"></div>').appendTo(form);
|
||||
var list = $('<ol id="red-ui-editor-subflow-env-list" class="red-ui-editor-subflow-env-list"></ol>').appendTo(listContainer);
|
||||
buildPropertiesList(list, node);
|
||||
}
|
||||
|
||||
function setupInputValidation(input,validator) {
|
||||
var errorTip;
|
||||
var validateTimeout;
|
||||
|
||||
var validateFunction = function() {
|
||||
if (validateTimeout) {
|
||||
return;
|
||||
}
|
||||
validateTimeout = setTimeout(function() {
|
||||
var error = validator(input.val());
|
||||
// if (!error && errorTip) {
|
||||
// errorTip.close();
|
||||
// errorTip = null;
|
||||
// } else if (error && !errorTip) {
|
||||
// errorTip = RED.popover.create({
|
||||
// tooltip: true,
|
||||
// target:input,
|
||||
// size: "small",
|
||||
// direction: "bottom",
|
||||
// content: error,
|
||||
// }).open();
|
||||
// }
|
||||
input.toggleClass("input-error",!!error);
|
||||
validateTimeout = null;
|
||||
})
|
||||
}
|
||||
input.on("change keyup paste", validateFunction);
|
||||
}
|
||||
|
||||
function buildModuleForm(container, node) {
|
||||
$(_subflowModulePaneTemplate).appendTo(container);
|
||||
var moduleProps = node.meta || {};
|
||||
[
|
||||
'module',
|
||||
'type',
|
||||
'version',
|
||||
'author',
|
||||
'desc',
|
||||
'keywords',
|
||||
'license'
|
||||
].forEach(function(property) {
|
||||
$("#subflow-input-module-"+property).val(moduleProps[property]||"")
|
||||
})
|
||||
$("#subflow-input-module-type").attr("placeholder",node.id);
|
||||
|
||||
setupInputValidation($("#subflow-input-module-module"), function(newValue) {
|
||||
newValue = newValue.trim();
|
||||
var isValid = newValue.length < 215;
|
||||
isValid = isValid && !/^[._]/.test(newValue);
|
||||
isValid = isValid && !/[A-Z]/.test(newValue);
|
||||
if (newValue !== encodeURIComponent(newValue)) {
|
||||
var m = /^@([^\/]+)\/([^\/]+)$/.exec(newValue);
|
||||
if (m) {
|
||||
isValid = isValid && (m[1] === encodeURIComponent(m[1]) && m[2] === encodeURIComponent(m[2]))
|
||||
} else {
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
return isValid?"":"Invalid module name"
|
||||
})
|
||||
setupInputValidation($("#subflow-input-module-version"), function(newValue) {
|
||||
newValue = newValue.trim();
|
||||
var isValid = newValue === "" ||
|
||||
/^(\d|[1-9]\d*)\.(\d|[1-9]\d*)\.(\d|[1-9]\d*)(-(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\.(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(newValue);
|
||||
return isValid?"":"Invalid version number"
|
||||
})
|
||||
|
||||
var licenses = ["none", "Apache-2.0", "BSD-3-Clause", "BSD-2-Clause", "GPL-2.0", "GPL-3.0", "MIT", "MPL-2.0", "CDDL-1.0", "EPL-2.0"];
|
||||
var typedLicenses = {
|
||||
types: licenses.map(function(l) {
|
||||
return {
|
||||
value: l,
|
||||
label: l === "none" ? RED._("editor:subflow.licenseNone") : l,
|
||||
hasValue: false
|
||||
};
|
||||
})
|
||||
}
|
||||
typedLicenses.types.push({
|
||||
value:"_custom_", label:RED._("editor:subflow.licenseOther"), icon:"red/images/typedInput/az.svg"
|
||||
})
|
||||
if (!moduleProps.license) {
|
||||
typedLicenses.default = "none";
|
||||
} else if (licenses.indexOf(moduleProps.license) > -1) {
|
||||
typedLicenses.default = moduleProps.license;
|
||||
} else {
|
||||
typedLicenses.default = "_custom_";
|
||||
}
|
||||
$("#subflow-input-module-license").typedInput(typedLicenses)
|
||||
}
|
||||
|
||||
function exportSubflowModuleProperties(node) {
|
||||
var value;
|
||||
var moduleProps = {};
|
||||
[
|
||||
'module',
|
||||
'type',
|
||||
'version',
|
||||
'author',
|
||||
'desc',
|
||||
'keywords'
|
||||
].forEach(function(property) {
|
||||
value = $("#subflow-input-module-"+property).val().trim();
|
||||
if (value) {
|
||||
moduleProps[property] = value;
|
||||
}
|
||||
})
|
||||
var selectedLicenseType = $("#subflow-input-module-license").typedInput("type");
|
||||
|
||||
if (selectedLicenseType === '_custom_') {
|
||||
value = $("#subflow-input-module-license").val();
|
||||
if (value) {
|
||||
moduleProps.license = value;
|
||||
}
|
||||
} else if (selectedLicenseType !== "none") {
|
||||
moduleProps.license = selectedLicenseType;
|
||||
}
|
||||
return moduleProps;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
init: init,
|
||||
@@ -2085,14 +1316,9 @@ RED.subflow = (function() {
|
||||
removeOutput: removeSubflowOutput,
|
||||
removeStatus: removeSubflowStatus,
|
||||
|
||||
|
||||
buildEditForm: buildEditForm,
|
||||
buildPropertiesForm: buildPropertiesForm,
|
||||
buildModuleForm: buildModuleForm,
|
||||
|
||||
exportSubflowTemplateEnv: exportEnvList,
|
||||
exportSubflowInstanceEnv: exportSubflowInstanceEnv,
|
||||
exportSubflowModuleProperties: exportSubflowModuleProperties
|
||||
|
||||
exportSubflowInstanceEnv: exportSubflowInstanceEnv
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
**/
|
||||
RED.sidebar.config = (function() {
|
||||
|
||||
let flashingConfigNode;
|
||||
let flashingConfigNodeTimer;
|
||||
|
||||
var content = document.createElement("div");
|
||||
content.className = "red-ui-sidebar-node-config";
|
||||
@@ -145,6 +147,7 @@ RED.sidebar.config = (function() {
|
||||
var entry = $('<li class="red-ui-palette-node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list);
|
||||
var nodeDiv = $('<div class="red-ui-palette-node-config red-ui-palette-node"></div>').appendTo(entry);
|
||||
entry.data('node',node.id);
|
||||
nodeDiv.data('node',node.id);
|
||||
var label = $('<div class="red-ui-palette-label"></div>').text(label).appendTo(nodeDiv);
|
||||
if (node.d) {
|
||||
nodeDiv.addClass("red-ui-palette-node-config-disabled");
|
||||
@@ -229,7 +232,7 @@ RED.sidebar.config = (function() {
|
||||
var globalConfigNodes = [];
|
||||
var configList = {};
|
||||
RED.nodes.eachConfig(function(cn) {
|
||||
if (cn.z) {//} == RED.workspaces.active()) {
|
||||
if (cn.z) {
|
||||
configList[cn.z.replace(/\./g,"-")] = configList[cn.z.replace(/\./g,"-")]||[];
|
||||
configList[cn.z.replace(/\./g,"-")].push(cn);
|
||||
} else if (!cn.z) {
|
||||
@@ -346,10 +349,36 @@ RED.sidebar.config = (function() {
|
||||
refreshConfigNodeList();
|
||||
}
|
||||
});
|
||||
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllUnusedConfigNodes"));
|
||||
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllConfigNodes"));
|
||||
RED.popover.tooltip($('#red-ui-sidebar-config-filter-unused'), RED._("sidebar.config.showAllUnusedConfigNodes"));
|
||||
|
||||
}
|
||||
|
||||
function flashConfigNode(el) {
|
||||
if(flashingConfigNode && flashingConfigNode.length) {
|
||||
//cancel current flashing node before flashing new node
|
||||
clearInterval(flashingConfigNodeTimer);
|
||||
flashingConfigNodeTimer = null;
|
||||
flashingConfigNode.children("div").removeClass('highlighted');
|
||||
flashingConfigNode = null;
|
||||
}
|
||||
if(!el || !el.children("div").length) { return; }
|
||||
|
||||
flashingConfigNodeTimer = setInterval(function(flashEndTime) {
|
||||
if (flashEndTime >= Date.now()) {
|
||||
const highlighted = el.children("div").hasClass("highlighted");
|
||||
el.children("div").toggleClass('highlighted', !highlighted)
|
||||
} else {
|
||||
clearInterval(flashingConfigNodeTimer);
|
||||
flashingConfigNodeTimer = null;
|
||||
flashingConfigNode = null;
|
||||
el.children("div").removeClass('highlighted');
|
||||
}
|
||||
}, 100, Date.now() + 2200);
|
||||
flashingConfigNode = el;
|
||||
el.children("div").addClass('highlighted');
|
||||
}
|
||||
|
||||
function show(id) {
|
||||
if (typeof id === 'boolean') {
|
||||
if (id) {
|
||||
@@ -374,19 +403,7 @@ RED.sidebar.config = (function() {
|
||||
} else if (y<0) {
|
||||
scrollWindow.animate({scrollTop: '+='+(y-10)},150);
|
||||
}
|
||||
var flash = 21;
|
||||
var flashFunc = function() {
|
||||
if ((flash%2)===0) {
|
||||
node.removeClass('node_highlighted');
|
||||
} else {
|
||||
node.addClass('node_highlighted');
|
||||
}
|
||||
flash--;
|
||||
if (flash >= 0) {
|
||||
setTimeout(flashFunc,100);
|
||||
}
|
||||
}
|
||||
flashFunc();
|
||||
flashConfigNode(node, id);
|
||||
},100);
|
||||
}
|
||||
RED.sidebar.show("config");
|
||||
|
||||
@@ -25,7 +25,6 @@ RED.sidebar.help = (function() {
|
||||
var tocPanel;
|
||||
var helpIndex = {};
|
||||
|
||||
|
||||
function resizeStack() {
|
||||
var h = $(content).parent().height() - toolbar.outerHeight();
|
||||
panels.resize(h)
|
||||
@@ -65,15 +64,17 @@ RED.sidebar.help = (function() {
|
||||
style: "compact",
|
||||
delay: 100,
|
||||
change: function() {
|
||||
var val = $(this).val().toLowerCase();
|
||||
if (val) {
|
||||
const searchFor = $(this).val().toLowerCase();
|
||||
if (searchFor) {
|
||||
showTOC();
|
||||
var c = treeList.treeList('filter',function(item) {
|
||||
treeList.treeList('filter',function(item) {
|
||||
if (item.depth === 0) {
|
||||
return true;
|
||||
}
|
||||
return (item.nodeType && item.nodeType.indexOf(val) > -1) ||
|
||||
(item.subflowLabel && item.subflowLabel.indexOf(val) > -1)
|
||||
let found = item.nodeType && item.nodeType.toLowerCase().indexOf(searchFor) > -1;
|
||||
found = found || item.subflowLabel && item.subflowLabel.toLowerCase().indexOf(searchFor) > -1;
|
||||
found = found || item.palleteLabel && item.palleteLabel.toLowerCase().indexOf(searchFor) > -1;
|
||||
return found;
|
||||
},true)
|
||||
} else {
|
||||
treeList.treeList('filter',null);
|
||||
@@ -93,9 +94,28 @@ RED.sidebar.help = (function() {
|
||||
$('<span class="red-ui-help-info-none">'+RED._("sidebar.help.noHelp")+'</span>').appendTo(helpSection);
|
||||
|
||||
treeList = $("<div>").css({width: "100%"}).appendTo(tocPanel).treeList({data: []})
|
||||
var pendingContentLoad;
|
||||
treeList.on('treelistselect', function(e,item) {
|
||||
pendingContentLoad = item;
|
||||
if (item.nodeType) {
|
||||
showHelp(item.nodeType);
|
||||
showNodeTypeHelp(item.nodeType);
|
||||
} else if (item.content) {
|
||||
helpSection.empty();
|
||||
if (typeof item.content === "string") {
|
||||
setInfoText(item.label, item.content);
|
||||
} else if (typeof item.content === "function") {
|
||||
if (item.content.length === 0) {
|
||||
setInfoText(item.label, item.content());
|
||||
} else {
|
||||
setInfoText(item.label, '<div class="red-ui-component-spinner red-ui-component-spinner-contain"><img src="red/images/spin.svg" /></div>',helpSection)
|
||||
item.content(function(content) {
|
||||
if (pendingContentLoad === item) {
|
||||
helpSection.empty();
|
||||
setInfoText(item.label, content);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -174,21 +194,28 @@ RED.sidebar.help = (function() {
|
||||
var moduleNames = Object.keys(modules);
|
||||
moduleNames.sort();
|
||||
|
||||
var helpData = [{
|
||||
var nodeHelp = {
|
||||
label: RED._("sidebar.help.nodeHelp"),
|
||||
children: [],
|
||||
expanded: true
|
||||
}]
|
||||
|
||||
}
|
||||
var helpData = [
|
||||
{
|
||||
id: 'changelog',
|
||||
label: "Node-RED v"+RED.settings.version,
|
||||
content: getChangelog
|
||||
},
|
||||
nodeHelp
|
||||
]
|
||||
var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)});
|
||||
if (subflows.length > 0) {
|
||||
helpData[0].children.push({
|
||||
nodeHelp.children.push({
|
||||
label: RED._("menu.label.subflows"),
|
||||
children: []
|
||||
})
|
||||
subflows.forEach(function(nodeType) {
|
||||
var sf = RED.nodes.getType(nodeType);
|
||||
helpData[0].children[0].children.push({
|
||||
nodeHelp.children[0].children.push({
|
||||
id:"node-type:"+nodeType,
|
||||
nodeType: nodeType,
|
||||
subflowLabel: sf.label().toLowerCase(),
|
||||
@@ -199,17 +226,21 @@ RED.sidebar.help = (function() {
|
||||
|
||||
|
||||
moduleNames.forEach(function(moduleName) {
|
||||
var module = modules[moduleName];
|
||||
var nodeTypes = [];
|
||||
|
||||
var setNames = Object.keys(module.sets);
|
||||
const module = modules[moduleName];
|
||||
const nodeTypes = [];
|
||||
const moduleSets = module.sets;
|
||||
const setNames = Object.keys(moduleSets);
|
||||
setNames.forEach(function(setName) {
|
||||
module.sets[setName].types.forEach(function(nodeType) {
|
||||
const moduleSet = moduleSets[setName];
|
||||
moduleSet.types.forEach(function(nodeType) {
|
||||
if ($("script[data-help-name='"+nodeType+"']").length) {
|
||||
const n = {_def:RED.nodes.getType(nodeType),type:nodeType}
|
||||
n.name = getNodePaletteLabel(n);
|
||||
nodeTypes.push({
|
||||
id: "node-type:"+nodeType,
|
||||
nodeType: nodeType,
|
||||
element:getNodeLabel({_def:RED.nodes.getType(nodeType),type:nodeType})
|
||||
palleteLabel: n.name,
|
||||
element: getNodeLabel(n)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -218,7 +249,7 @@ RED.sidebar.help = (function() {
|
||||
nodeTypes.sort(function(A,B) {
|
||||
return A.nodeType.localeCompare(B.nodeType)
|
||||
})
|
||||
helpData[0].children.push({
|
||||
nodeHelp.children.push({
|
||||
id: moduleName,
|
||||
icon: "fa fa-cube",
|
||||
label: moduleName,
|
||||
@@ -229,22 +260,25 @@ RED.sidebar.help = (function() {
|
||||
treeList.treeList("data",helpData);
|
||||
}
|
||||
|
||||
function getNodeLabel(n) {
|
||||
var div = $('<div>',{class:"red-ui-node-list-item"});
|
||||
var icon = RED.utils.createNodeIcon(n).appendTo(div);
|
||||
var label = n.name;
|
||||
if (!label && n._def.paletteLabel) {
|
||||
function getNodePaletteLabel(n) {
|
||||
let label = n.name;
|
||||
if (!label && n._def && n._def.paletteLabel) {
|
||||
try {
|
||||
label = (typeof n._def.paletteLabel === "function" ? n._def.paletteLabel.call(n._def) : n._def.paletteLabel)||"";
|
||||
} catch (err) {
|
||||
}
|
||||
}
|
||||
label = label || n.type;
|
||||
$('<div>',{class:"red-ui-node-label"}).text(n.name||n.type).appendTo(icon);
|
||||
return label || n.type;
|
||||
}
|
||||
|
||||
function getNodeLabel(n) {
|
||||
const div = $('<div>',{class:"red-ui-node-list-item"});
|
||||
const icon = RED.utils.createNodeIcon(n).appendTo(div);
|
||||
$('<div>',{class:"red-ui-node-label"}).text(getNodePaletteLabel(n)).appendTo(icon);
|
||||
return div;
|
||||
}
|
||||
|
||||
function showHelp(nodeType) {
|
||||
function showNodeTypeHelp(nodeType) {
|
||||
helpSection.empty();
|
||||
var helpText;
|
||||
var title;
|
||||
@@ -265,7 +299,7 @@ RED.sidebar.help = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
setInfoText(title, helpText, helpSection);
|
||||
setInfoText(title, helpText);
|
||||
|
||||
var ratio = panels.ratio();
|
||||
if (ratio > 0.7) {
|
||||
@@ -282,7 +316,7 @@ RED.sidebar.help = (function() {
|
||||
}
|
||||
if (type) {
|
||||
// hideTOC();
|
||||
showHelp(type);
|
||||
showNodeTypeHelp(type);
|
||||
}
|
||||
resizeStack();
|
||||
}
|
||||
@@ -298,11 +332,12 @@ RED.sidebar.help = (function() {
|
||||
return el;
|
||||
}
|
||||
|
||||
function setInfoText(title, infoText,target) {
|
||||
function setInfoText(title, infoText) {
|
||||
helpSection.empty();
|
||||
if (title) {
|
||||
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(target);
|
||||
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(helpSection);
|
||||
}
|
||||
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
|
||||
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(helpSection);
|
||||
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
|
||||
var foldingHeader = "H3";
|
||||
info.find(foldingHeader).wrapInner('<a class="red-ui-help-info-header expanded" href="#"></a>')
|
||||
@@ -316,12 +351,12 @@ RED.sidebar.help = (function() {
|
||||
}
|
||||
$(this).toggleClass('expanded',!isExpanded);
|
||||
})
|
||||
target.parent().scrollTop(0);
|
||||
helpSection.parent().scrollTop(0);
|
||||
}
|
||||
|
||||
function set(html,title) {
|
||||
$(helpSection).empty();
|
||||
setInfoText(title,html,helpSection);
|
||||
setInfoText(title,html);
|
||||
hideTOC();
|
||||
show();
|
||||
}
|
||||
@@ -335,14 +370,92 @@ RED.sidebar.help = (function() {
|
||||
var node = selection.nodes[0];
|
||||
if (node.type === "subflow" && node.direction) {
|
||||
// ignore subflow virtual ports
|
||||
} else if (node.type !== 'group'){
|
||||
showHelp(node.type);
|
||||
} else if (node.type !== 'group' && node.type !== 'junction'){
|
||||
showNodeTypeHelp(node.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RED.events.on("view:selection-changed",refreshSelection);
|
||||
|
||||
function getChangelog(done) {
|
||||
$.get('red/about', function(data) {
|
||||
// data will be strictly markdown. Any HTML should be escaped.
|
||||
data = RED.utils.sanitize(data);
|
||||
RED.tourGuide.load("./tours/welcome.js", function(err, tour) {
|
||||
var tourHeader = '<div><img width="50px" src="red/images/node-red-icon.svg" /></div>';
|
||||
if (tour) {
|
||||
var currentVersionParts = RED.settings.version.split(".");
|
||||
var tourVersionParts = tour.version.split(".");
|
||||
if (tourVersionParts[0] === currentVersionParts[0] && tourVersionParts[1] === currentVersionParts[1]) {
|
||||
tourHeader = '<div><button type="button" onclick="RED.actions.invoke(\'core:show-welcome-tour\')" class="red-ui-button">' + RED._("tourGuide.takeATour") + '</button></div>';
|
||||
}
|
||||
}
|
||||
var aboutHeader = '<div style="text-align:center;">'+tourHeader+'</div>'
|
||||
done(aboutHeader+RED.utils.renderMarkdown(data))
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
function showAbout() {
|
||||
treeList.treeList("show","changelog")
|
||||
treeList.treeList("select","changelog");
|
||||
show();
|
||||
}
|
||||
function showWelcomeTour(lastSeenVersion, done) {
|
||||
done = done || function() {};
|
||||
RED.tourGuide.load("./tours/welcome.js", function(err, tour) {
|
||||
if (err) {
|
||||
console.warn("Failed to load welcome tour",err);
|
||||
done()
|
||||
return;
|
||||
}
|
||||
var currentVersionParts = RED.settings.version.split(".");
|
||||
var tourVersionParts = tour.version.split(".");
|
||||
|
||||
// Only display the tour if its MAJ.MIN versions the current version
|
||||
// This means if we update MAJ/MIN without updating the tour, the old tour won't get shown
|
||||
if (tourVersionParts[0] !== currentVersionParts[0] || tourVersionParts[1] !== currentVersionParts[1]) {
|
||||
done()
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastSeenVersion) {
|
||||
// Previously displayed a welcome tour.
|
||||
if (lastSeenVersion === RED.settings.version) {
|
||||
// Exact match - don't show the tour
|
||||
done()
|
||||
return;
|
||||
}
|
||||
var lastSeenParts = lastSeenVersion.split(".");
|
||||
if (currentVersionParts[0] < lastSeenParts[0] || (currentVersionParts[0] === lastSeenParts[0] && currentVersionParts[1] < lastSeenParts[1])) {
|
||||
// Running an *older* version than last displayed tour.
|
||||
done()
|
||||
return;
|
||||
}
|
||||
if (currentVersionParts[0] === lastSeenParts[0] && currentVersionParts[1] === lastSeenParts[1]) {
|
||||
if (lastSeenParts.length === 3 && currentVersionParts.length === 3) {
|
||||
// Matching non-beta MAJ.MIN - don't repeat tour
|
||||
done()
|
||||
return;
|
||||
}
|
||||
if (currentVersionParts.length === 4 && (lastSeenParts.length === 3 || currentVersionParts[3] < lastSeenParts[3])) {
|
||||
// Running an *older* beta than last displayed tour.
|
||||
done()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
RED.tourGuide.run("./tours/welcome.js", function(err) {
|
||||
RED.settings.set("editor.tours.welcome", RED.settings.version)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
RED.actions.add("core:show-about", showAbout);
|
||||
RED.actions.add("core:show-welcome-tour", showWelcomeTour);
|
||||
|
||||
return {
|
||||
init: init,
|
||||
show: show,
|
||||
|
||||
@@ -122,11 +122,20 @@ RED.sidebar.info.outliner = (function() {
|
||||
})
|
||||
RED.popover.tooltip(triggerButton,RED._("sidebar.info.triggerAction"));
|
||||
}
|
||||
// $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-eye"></i></button>').appendTo(controls).on("click",function(evt) {
|
||||
// evt.preventDefault();
|
||||
// evt.stopPropagation();
|
||||
// RED.view.reveal(n.id);
|
||||
// })
|
||||
|
||||
if (n.type === "tab") {
|
||||
var toggleVisibleButton = $('<button type="button" class="red-ui-info-outline-item-control-hide red-ui-button red-ui-button-small"><i class="fa fa-eye"></i><i class="fa fa-eye-slash"></i></button>').appendTo(controls).on("click",function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
var isHidden = !div.hasClass("red-ui-info-outline-item-hidden");
|
||||
div.toggleClass("red-ui-info-outline-item-hidden",isHidden);
|
||||
if (isHidden) {
|
||||
RED.workspaces.hide(n.id);
|
||||
} else {
|
||||
RED.workspaces.show(n.id, null, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (n.type !== 'subflow') {
|
||||
var toggleButton = $('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -166,6 +175,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
n.d = true;
|
||||
}
|
||||
n.dirty = true;
|
||||
n.dirtyStatus = true;
|
||||
n.changed = true;
|
||||
RED.events.emit("nodes:change",n);
|
||||
groupHistoryEvent.events.push(historyEvent);
|
||||
@@ -194,6 +204,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
n.d = true;
|
||||
}
|
||||
n.dirty = true;
|
||||
n.dirtyStatus = true;
|
||||
n.changed = true;
|
||||
RED.events.emit("nodes:change",n);
|
||||
RED.history.push(historyEvent);
|
||||
@@ -257,13 +268,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
|
||||
}
|
||||
},
|
||||
options: [
|
||||
{label:RED._("sidebar.info.search.configNodes"), value:"is:config"},
|
||||
{label:RED._("sidebar.info.search.unusedConfigNodes"), value:"is:config is:unused"},
|
||||
{label:RED._("sidebar.info.search.invalidNodes"), value: "is:invalid"},
|
||||
{label:RED._("sidebar.info.search.uknownNodes"), value: "type:unknown"},
|
||||
{label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"},
|
||||
]
|
||||
options: RED.search.getSearchOptions()
|
||||
});
|
||||
|
||||
projectInfo = $('<div class="red-ui-treeList-label red-ui-info-outline-project"><span class="red-ui-treeList-icon"><i class="fa fa-archive"></i></span></div>').hide().appendTo(container)
|
||||
@@ -275,15 +280,18 @@ RED.sidebar.info.outliner = (function() {
|
||||
data:getFlowData()
|
||||
})
|
||||
treeList.on('treelistselect', function(e,item) {
|
||||
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
|
||||
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id) || RED.nodes.workspace(item.id) || RED.nodes.subflow(item.id);
|
||||
if (node) {
|
||||
if (node.type === 'group' || node._def.category !== "config") {
|
||||
RED.view.select({nodes:[node]})
|
||||
} else if (node._def.category === "config") {
|
||||
RED.sidebar.info.refresh(node);
|
||||
} else {
|
||||
RED.view.select({nodes:[]})
|
||||
}
|
||||
RED.sidebar.info.refresh(node);
|
||||
// if (node.type === 'group' || node._def.category !== "config") {
|
||||
// // RED.view.select({nodes:[node]})
|
||||
// } else if (node._def.category === "config") {
|
||||
// RED.sidebar.info.refresh(node);
|
||||
// } else {
|
||||
// // RED.view.select({nodes:[]})
|
||||
// }
|
||||
} else {
|
||||
RED.sidebar.info.refresh(null);
|
||||
}
|
||||
})
|
||||
treeList.on('treelistconfirm', function(e,item) {
|
||||
@@ -311,18 +319,33 @@ RED.sidebar.info.outliner = (function() {
|
||||
RED.events.on("nodes:add",onNodeAdd);
|
||||
RED.events.on("nodes:remove",onObjectRemove);
|
||||
RED.events.on("nodes:change",onNodeChange);
|
||||
// RED.events.on("nodes:reorder",onNodesReorder);
|
||||
|
||||
RED.events.on("groups:add",onNodeAdd);
|
||||
RED.events.on("groups:remove",onObjectRemove);
|
||||
RED.events.on("groups:change",onNodeChange);
|
||||
|
||||
RED.events.on("workspace:clear", onWorkspaceClear)
|
||||
RED.events.on("workspace:show", onWorkspaceShow);
|
||||
RED.events.on("workspace:hide", onWorkspaceHide);
|
||||
RED.events.on("workspace:clear", onWorkspaceClear);
|
||||
|
||||
return container;
|
||||
}
|
||||
function onWorkspaceClear() {
|
||||
treeList.treeList('data',getFlowData());
|
||||
}
|
||||
function onWorkspaceShow(event) {
|
||||
var existingObject = objects[event.workspace];
|
||||
if (existingObject) {
|
||||
existingObject.element.removeClass("red-ui-info-outline-item-hidden")
|
||||
}
|
||||
}
|
||||
function onWorkspaceHide(event) {
|
||||
var existingObject = objects[event.workspace];
|
||||
if (existingObject) {
|
||||
existingObject.element.addClass("red-ui-info-outline-item-hidden")
|
||||
}
|
||||
}
|
||||
function onFlowAdd(ws) {
|
||||
objects[ws.id] = {
|
||||
id: ws.id,
|
||||
@@ -369,6 +392,21 @@ RED.sidebar.info.outliner = (function() {
|
||||
return indexMap[A.id] - indexMap[B.id]
|
||||
})
|
||||
}
|
||||
// function onNodesReorder(event) {
|
||||
// //
|
||||
// var nodes = RED.nodes.getNodeOrder(event.z);
|
||||
// var indexMap = {};
|
||||
// nodes.forEach(function(id,index) {
|
||||
// indexMap[id] = index;
|
||||
// })
|
||||
// var existingObject = objects[event.z];
|
||||
// existingObject.treeList.sortChildren(function(A,B) {
|
||||
// if (A.children && !B.children) { return -1 }
|
||||
// if (!A.children && B.children) { return 1 }
|
||||
// if (A.children && B.children) { return -1 }
|
||||
// return indexMap[A.id] - indexMap[B.id]
|
||||
// })
|
||||
// }
|
||||
function onSubflowAdd(sf) {
|
||||
objects[sf.id] = {
|
||||
id: sf.id,
|
||||
@@ -524,7 +562,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
}
|
||||
}
|
||||
function getGutter(n) {
|
||||
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
|
||||
var span = $("<span>",{class:"red-ui-info-outline-gutter red-ui-treeList-gutter-float"});
|
||||
var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
@@ -163,6 +163,7 @@ RED.sidebar.info = (function() {
|
||||
});
|
||||
return el;
|
||||
}
|
||||
|
||||
function refresh(node) {
|
||||
if (node === undefined) {
|
||||
refreshSelection();
|
||||
@@ -180,6 +181,10 @@ RED.sidebar.info = (function() {
|
||||
|
||||
if (node === null) {
|
||||
RED.sidebar.info.outliner.select(null);
|
||||
propertiesPanelHeaderIcon.empty();
|
||||
propertiesPanelHeaderLabel.text("");
|
||||
propertiesPanelHeaderReveal.hide();
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
return;
|
||||
} else if (Array.isArray(node)) {
|
||||
// Multiple things selected
|
||||
@@ -267,7 +272,7 @@ RED.sidebar.info = (function() {
|
||||
objectType = "group";
|
||||
}
|
||||
$(propRow.children()[0]).text(RED._("sidebar.info."+objectType))
|
||||
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
|
||||
RED.utils.createObjectElement(node.id,{sourceId: node.id}).appendTo(propRow.children()[1]);
|
||||
|
||||
if (node.type === "tab" || node.type === "subflow") {
|
||||
// If nothing is selected, but we're on a flow or subflow tab.
|
||||
@@ -297,8 +302,8 @@ RED.sidebar.info = (function() {
|
||||
if (typeCounts.groups > 0) {
|
||||
$('<div>').text(RED._("clipboard.group",{count:typeCounts.groups})).appendTo(counts);
|
||||
}
|
||||
|
||||
|
||||
} else if (node.type === 'junction') {
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
} else {
|
||||
propertiesPanelHeaderHelp.show();
|
||||
|
||||
@@ -361,7 +366,7 @@ RED.sidebar.info = (function() {
|
||||
|
||||
}
|
||||
} else {
|
||||
RED.utils.createObjectElement(val).appendTo(propRow.children()[1]);
|
||||
RED.utils.createObjectElement(val,{sourceId: node.id}).appendTo(propRow.children()[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -427,6 +432,7 @@ RED.sidebar.info = (function() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
function setInfoText(infoText,target) {
|
||||
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
|
||||
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
|
||||
@@ -443,6 +449,7 @@ RED.sidebar.info = (function() {
|
||||
$(this).toggleClass('expanded',!isExpanded);
|
||||
})
|
||||
}
|
||||
|
||||
var tips = (function() {
|
||||
var enabled = true;
|
||||
var startDelay = 1000;
|
||||
|
||||
445
packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js
vendored
Normal file
445
packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js
vendored
Normal file
@@ -0,0 +1,445 @@
|
||||
RED.tourGuide = (function() {
|
||||
var activeListeners = [];
|
||||
var shade;
|
||||
var focus;
|
||||
var popover;
|
||||
var stepContent;
|
||||
var targetElement;
|
||||
var fullscreen;
|
||||
|
||||
var tourCache = {};
|
||||
|
||||
function run(tourPath, done) {
|
||||
done = done || function(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
loadTour(tourPath, function(err, tour) {
|
||||
if (err) {
|
||||
console.warn("Error loading tour:",err);
|
||||
return;
|
||||
}
|
||||
runTour(tour, done);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function loadTour(tourPath, done) {
|
||||
if (tourCache[tourPath]) {
|
||||
done(null, tourCache[tourPath]);
|
||||
} else {
|
||||
/* jshint ignore:start */
|
||||
// jshint<2.13 doesn't support dynamic imports. Once grunt-contrib-jshint
|
||||
// has been updated with the new jshint, we can stop ignoring this block
|
||||
import(tourPath).then(function(module) {
|
||||
tourCache[tourPath] = module.default;
|
||||
done(null, tourCache[tourPath]);
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
})
|
||||
/* jshint ignore:end */
|
||||
}
|
||||
}
|
||||
|
||||
function repositionFocus() {
|
||||
if (targetElement) {
|
||||
if (!fullscreen) {
|
||||
var pos = targetElement[0].getBoundingClientRect();
|
||||
var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
|
||||
focus.css({
|
||||
left: (pos.left+pos.width/2)+"px",
|
||||
top: (pos.top+pos.height/2)+"px",
|
||||
width: (2*dimension)+"px",
|
||||
height: (2*dimension)+"px"
|
||||
})
|
||||
var flush = focus[0].offsetHeight; // Flush CSS changes
|
||||
focus.addClass("transition");
|
||||
focus.css({
|
||||
width: dimension+"px",
|
||||
height: dimension+"px"
|
||||
})
|
||||
} else {
|
||||
focus.css({
|
||||
left: ($(window).width()/2)+"px",
|
||||
top: ($(window).height()/2)+"px",
|
||||
width: "0px",
|
||||
height: "0px"
|
||||
})
|
||||
}
|
||||
if (popover) {
|
||||
popover.move({
|
||||
target: targetElement,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
function runTour(tour, done) {
|
||||
|
||||
shade = $('<div class="red-ui-tourGuide-shade"></div>').appendTo(document.body);
|
||||
focus = $('<div class="red-ui-tourGuide-shade-focus"></div>').appendTo(shade);
|
||||
|
||||
// var resizeTimer;
|
||||
//
|
||||
$(window).on("resize.red-ui-tourGuide", function() {
|
||||
repositionFocus();
|
||||
})
|
||||
|
||||
|
||||
|
||||
var i = 0;
|
||||
var state = {
|
||||
index: 0,
|
||||
count: tour.steps.length
|
||||
};
|
||||
|
||||
function endTour(err) {
|
||||
$(window).off("resize.red-ui-tourGuide");
|
||||
$(document).off('keydown.red-ui-tourGuide');
|
||||
if (popover) {
|
||||
popover.close();
|
||||
}
|
||||
stepContent = null;
|
||||
popover = null;
|
||||
shade.remove();
|
||||
shade = null;
|
||||
done(err);
|
||||
}
|
||||
function runStep(carryOn) {
|
||||
if (carryOn === false) {
|
||||
endTour(false);
|
||||
return;
|
||||
}
|
||||
if (i === tour.steps.length) {
|
||||
endTour();
|
||||
return
|
||||
}
|
||||
state.index = i;
|
||||
// console.log("TOUR STEP",i+1,"OF",tour.steps.length)
|
||||
try {
|
||||
runTourStep(tour.steps[i++], state, runStep)
|
||||
} catch(err) {
|
||||
endTour(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
runStep();
|
||||
}
|
||||
|
||||
function clearListeners() {
|
||||
activeListeners.forEach(function(listener) {
|
||||
if (listener.type === "dom-event") {
|
||||
listener.target[0].removeEventListener(listener.event,listener.listener,listener.opts);
|
||||
} else if (listener.type === "nr-event") {
|
||||
RED.events.off(listener.event, listener.listener)
|
||||
}
|
||||
})
|
||||
activeListeners = [];
|
||||
}
|
||||
|
||||
function prepareStep(step, state, done) {
|
||||
if (step.prepare) {
|
||||
if (step.prepare.length === 0) {
|
||||
step.prepare.call(state);
|
||||
} else {
|
||||
if (popover) {
|
||||
popover.element.hide();
|
||||
if (!fullscreen) {
|
||||
fullscreen = true;
|
||||
repositionFocus()
|
||||
}
|
||||
}
|
||||
step.prepare.call(state, function() {
|
||||
if (popover) {
|
||||
popover.element.show();
|
||||
}
|
||||
done();
|
||||
})
|
||||
return;
|
||||
}
|
||||
}
|
||||
done();
|
||||
}
|
||||
function completeStep(step, state, done) {
|
||||
function finish() {
|
||||
clearListeners();
|
||||
setTimeout(function() {
|
||||
done();
|
||||
},0)
|
||||
}
|
||||
if (step.complete) {
|
||||
if (step.complete.length === 0) {
|
||||
step.complete.call(state);
|
||||
} else {
|
||||
if (popover) {
|
||||
popover.element.hide();
|
||||
if (!fullscreen) {
|
||||
fullscreen = true;
|
||||
repositionFocus()
|
||||
}
|
||||
}
|
||||
step.complete.call(state, function() {
|
||||
if (popover) {
|
||||
popover.element.show();
|
||||
}
|
||||
finish();
|
||||
})
|
||||
return;
|
||||
}
|
||||
}
|
||||
finish();
|
||||
|
||||
}
|
||||
function getLocaleText(property) {
|
||||
if (typeof property === 'string') {
|
||||
return property;
|
||||
}
|
||||
var currentLang = RED.i18n.lang() || 'en-US';
|
||||
var availableLangs = Object.keys(property);
|
||||
return property[currentLang]||property['en-US']||property[availableLangs[0]]
|
||||
|
||||
}
|
||||
function runTourStep(step, state, done) {
|
||||
shade.fadeIn();
|
||||
prepareStep(step, state, function() {
|
||||
var zIndex;
|
||||
var direction = step.direction || "bottom";
|
||||
fullscreen = false;
|
||||
|
||||
if (typeof step.element === "string") {
|
||||
targetElement = $(step.element)
|
||||
} else if (typeof step.element === "function") {
|
||||
targetElement = step.element.call(state);
|
||||
} else if (!step.element) {
|
||||
targetElement = $(".red-ui-editor")
|
||||
fullscreen = true;
|
||||
direction = "inset";
|
||||
} else {
|
||||
targetElement = step.element;
|
||||
}
|
||||
|
||||
if (targetElement.length === 0) {
|
||||
targetElement = null;
|
||||
shade.hide();
|
||||
throw new Error("Element not found")
|
||||
}
|
||||
if ($(window).width() < 400) {
|
||||
targetElement = $(".red-ui-editor");
|
||||
fullscreen = true;
|
||||
direction = "inset";
|
||||
}
|
||||
|
||||
zIndex = targetElement.css("z-index");
|
||||
if (!fullscreen && (step.interactive || step.wait)) {
|
||||
targetElement.css("z-index",2002);
|
||||
}
|
||||
repositionFocus();
|
||||
|
||||
if (!stepContent) {
|
||||
stepContent = $('<div style="position:relative"></div>');
|
||||
} else {
|
||||
stepContent.empty();
|
||||
}
|
||||
$('<button type="button" class="red-ui-button red-ui-button-small" style="float: right; margin-top: -4px; margin-right: -4px;"><i class="fa fa-times"></i></button>').appendTo(stepContent).click(function(evt) {
|
||||
evt.preventDefault();
|
||||
completeStep(step, state, function() {
|
||||
done(false);
|
||||
});
|
||||
})
|
||||
|
||||
var stepDescription = $('<div class="red-ui-tourGuide-popover-description"></div>').appendTo(stepContent);
|
||||
if (step.titleIcon) {
|
||||
$('<h2><i class="'+step.titleIcon+'"></i></h2>').appendTo(stepDescription);
|
||||
}
|
||||
if (step.title) {
|
||||
$('<h2>').text(getLocaleText(step.title)).appendTo(stepDescription);
|
||||
}
|
||||
$('<div>').css("text-align","left").html(getLocaleText(step.description)).appendTo(stepDescription);
|
||||
|
||||
if (step.image) {
|
||||
$(`<img src="red/tours/${step.image}" />`).appendTo(stepDescription)
|
||||
}
|
||||
|
||||
var stepToolbar = $('<div>',{class:"red-ui-tourGuide-toolbar"}).appendTo(stepContent);
|
||||
|
||||
// var breadcrumbs = $('<div>',{class:"red-ui-tourGuide-breadcrumbs"}).appendTo(stepToolbar);
|
||||
// var bcStart = Math.max(0,state.index - 3);
|
||||
// var bcEnd = Math.min(state.count, bcStart + 7);
|
||||
// if (bcEnd === state.count) {
|
||||
// bcStart = Math.max(0,bcEnd - 7);
|
||||
// }
|
||||
// for (var i = bcStart; i < bcEnd; i++) {
|
||||
// var bullet = $('<i class="fa"></i>').addClass(i===state.index ? "fa-circle":"fa-circle-o").appendTo(breadcrumbs);
|
||||
// if (i === bcStart) {
|
||||
// if (i > 1) {
|
||||
// bullet.css("font-size", "3px");
|
||||
// } else if (i === 1) {
|
||||
// bullet.css("font-size", "4px");
|
||||
// }
|
||||
// } else if (i === bcStart + 1) {
|
||||
// if (i > 2) {
|
||||
// bullet.css("font-size", "4px");
|
||||
// }
|
||||
// }
|
||||
// if (i === bcEnd - 1) {
|
||||
// if (i < state.count - 2) {
|
||||
// bullet.css("font-size", "3px");
|
||||
// } else if (i === state.count - 2) {
|
||||
// bullet.css("font-size", "4px");
|
||||
// }
|
||||
// } else if (i === bcEnd - 2) {
|
||||
// if (i < state.count - 3) {
|
||||
// bullet.css("font-size", "4px");
|
||||
// }
|
||||
// }
|
||||
// // if (i === bcEnd - 1) {
|
||||
// // if (i < state.count - 2) {
|
||||
// // bullet.css("font-size", "3px");
|
||||
// // } else if (i === state.count - 2) {
|
||||
// // bullet.css("font-size", "4px");
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
|
||||
$('<small>').text((state.index+1)+"/"+state.count).appendTo(stepToolbar)
|
||||
var nextButton;
|
||||
if (fullscreen || !step.wait) {
|
||||
nextButton = $('<button type="button" class="red-ui-button" style="position: absolute; right:0;bottom:0;"></button>').appendTo(stepToolbar).one('click',function(evt) {
|
||||
evt.preventDefault();
|
||||
stepEventListener();
|
||||
});
|
||||
if (state.index === state.count - 1) {
|
||||
$('<span></span>').text(RED._("common.label.close")).appendTo(nextButton);
|
||||
} else if (state.index === 0) {
|
||||
$('<span>start</span>').text(RED._("tourGuide.start")).appendTo(nextButton);
|
||||
$('<span style="margin-left: 6px"><i class="fa fa-chevron-right"></i></span>').appendTo(nextButton);
|
||||
} else if (state.index < state.count-1) {
|
||||
$('<span></span>').text(RED._("tourGuide.next")).appendTo(nextButton);
|
||||
$('<span style="margin-left: 6px"><i class="fa fa-chevron-right"></i></span>').appendTo(nextButton);
|
||||
}
|
||||
}
|
||||
|
||||
var width = step.width;
|
||||
if (fullscreen) {
|
||||
width = 500;
|
||||
}
|
||||
var maxWidth = Math.min($(window).width()-10,Math.max(width || 0, 300));
|
||||
if (!popover) {
|
||||
popover = RED.popover.create({
|
||||
target: targetElement,
|
||||
width: width || "auto",
|
||||
maxWidth: maxWidth+"px",
|
||||
direction: direction,
|
||||
class: "red-ui-tourGuide-popover"+(fullscreen?" ":""),
|
||||
trigger: "manual",
|
||||
content: stepContent
|
||||
}).open();
|
||||
}
|
||||
$(document).off('keydown.red-ui-tourGuide');
|
||||
$(document).on('keydown.red-ui-tourGuide', function(evt) {
|
||||
if (evt.key === "Escape" || evt.key === "Esc") {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
completeStep(step, state, function() {
|
||||
done(false);
|
||||
});
|
||||
}
|
||||
})
|
||||
popover.element.toggleClass("red-ui-tourGuide-popover-full",!!fullscreen);
|
||||
popover.move({
|
||||
target: targetElement,
|
||||
width: width || "auto",
|
||||
maxWidth: maxWidth+"px",
|
||||
direction: direction,
|
||||
})
|
||||
setTimeout(function() {
|
||||
var pos = popover.element.position()
|
||||
if (pos.left < 0) {
|
||||
popover.element.css({left: 0});
|
||||
}
|
||||
},100);
|
||||
if (nextButton) {
|
||||
setTimeout(function() {
|
||||
nextButton.focus();
|
||||
},100);
|
||||
}
|
||||
|
||||
var isSVG = targetElement[0] instanceof SVGElement;
|
||||
if (step.fallback) {
|
||||
focus.one("mouseenter", function(evt) {
|
||||
setTimeout(function() {
|
||||
var pos = targetElement[0].getBoundingClientRect();
|
||||
var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
|
||||
focus.css({
|
||||
width: (4*dimension)+"px",
|
||||
height: (4*dimension)+"px"
|
||||
})
|
||||
shade.fadeOut();
|
||||
popover.move({
|
||||
target: $(".red-ui-editor"),
|
||||
direction: step.fallback,
|
||||
offset: 10,
|
||||
transition: true
|
||||
})
|
||||
// popover.element.addClass('red-ui-tourGuide-popover-bounce');
|
||||
},isSVG?0:500);
|
||||
})
|
||||
}
|
||||
|
||||
var stepEventListener = function() {
|
||||
focus.removeClass("transition");
|
||||
targetElement.css("z-index",zIndex);
|
||||
completeStep(step, state, done);
|
||||
}
|
||||
|
||||
if (step.wait) {
|
||||
if (step.wait.type === "dom-event") {
|
||||
var eventTarget = targetElement;
|
||||
if (step.wait.element) {
|
||||
if (typeof step.wait.element === "string") {
|
||||
eventTarget = $(step.wait.element);
|
||||
} else if (typeof step.wait.element === "function") {
|
||||
eventTarget = step.wait.element.call(state);
|
||||
}
|
||||
}
|
||||
var listener = {
|
||||
type: step.wait.type,
|
||||
target: eventTarget,
|
||||
event: step.wait.event,
|
||||
listener: function() {
|
||||
stepEventListener();
|
||||
},
|
||||
opts: { once: true }
|
||||
}
|
||||
activeListeners.push(listener)
|
||||
eventTarget[0].addEventListener(listener.event,listener.listener,listener.opts)
|
||||
} else if (step.wait.type === "nr-event") {
|
||||
var listener = {
|
||||
type: step.wait.type,
|
||||
event: step.wait.event,
|
||||
listener: function() {
|
||||
if (step.wait.filter) {
|
||||
if (!step.wait.filter.apply(state,arguments)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
stepEventListener();
|
||||
}
|
||||
}
|
||||
activeListeners.push(listener);
|
||||
RED.events.on(listener.event,listener.listener);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
load: loadTour,
|
||||
run: run,
|
||||
reset: function() {
|
||||
RED.settings.set("editor.tours.welcome",'');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
@@ -169,7 +169,13 @@
|
||||
raiseTrayZ();
|
||||
handleWindowResize();//cause call to monaco layout
|
||||
},200);
|
||||
body.find(":focusable:first").trigger("focus");
|
||||
if(!options.hasOwnProperty("focusElement")) {
|
||||
//focusElement is not inside options - default to focusing 1st
|
||||
body.find(":focusable:first").trigger("focus");
|
||||
} else if(options.focusElement !== false) {
|
||||
//focusElement IS specified, focus that instead (if not false)
|
||||
$(options.focusElement).trigger("focus");
|
||||
}
|
||||
|
||||
},150);
|
||||
el.css({right:0});
|
||||
|
||||
@@ -104,7 +104,9 @@ RED.typeSearch = (function() {
|
||||
var index = Math.max(0,selected);
|
||||
if (index < children.length) {
|
||||
var n = $(children[index]).find(".red-ui-editableList-item-content").data('data');
|
||||
typesUsed[n.type] = Date.now();
|
||||
if (!/^_action_:/.test(n.type)) {
|
||||
typesUsed[n.type] = Date.now();
|
||||
}
|
||||
if (n.def.outputs === 0) {
|
||||
confirm(n);
|
||||
} else {
|
||||
@@ -171,18 +173,27 @@ RED.typeSearch = (function() {
|
||||
var div = $('<div>',{class:"red-ui-search-result"}).appendTo(container);
|
||||
|
||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
|
||||
var colour = RED.utils.getNodeColor(object.type,def);
|
||||
if (object.type === "junction") {
|
||||
nodeDiv.addClass("red-ui-palette-icon-junction");
|
||||
} else if (/^_action_:/.test(object.type)) {
|
||||
nodeDiv.addClass("red-ui-palette-icon-junction")
|
||||
} else {
|
||||
var colour = RED.utils.getNodeColor(object.type,def);
|
||||
nodeDiv.css('backgroundColor',colour);
|
||||
}
|
||||
var icon_url = RED.utils.getNodeIcon(def);
|
||||
nodeDiv.css('backgroundColor',colour);
|
||||
|
||||
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
||||
RED.utils.createIconElement(icon_url, iconContainer, false);
|
||||
|
||||
if (def.inputs > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
|
||||
}
|
||||
if (def.outputs > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
|
||||
|
||||
if (!/^_action_:/.test(object.type) && object.type !== "junction") {
|
||||
if (def.inputs > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
|
||||
}
|
||||
if (def.outputs > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
|
||||
}
|
||||
}
|
||||
|
||||
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
||||
@@ -203,7 +214,9 @@ RED.typeSearch = (function() {
|
||||
}
|
||||
function confirm(def) {
|
||||
hide();
|
||||
typesUsed[def.type] = Date.now();
|
||||
if (!/^_action_:/.test(def.type)) {
|
||||
typesUsed[def.type] = Date.now();
|
||||
}
|
||||
addCallback(def.type);
|
||||
}
|
||||
|
||||
@@ -312,9 +325,10 @@ RED.typeSearch = (function() {
|
||||
function applyFilter(filter,type,def) {
|
||||
return !filter ||
|
||||
(
|
||||
(!filter.spliceMultiple) &&
|
||||
(!filter.type || type === filter.type) &&
|
||||
(!filter.input || def.inputs > 0) &&
|
||||
(!filter.output || def.outputs > 0)
|
||||
(!filter.input || type === 'junction' || def.inputs > 0) &&
|
||||
(!filter.output || type === 'junction' || def.outputs > 0)
|
||||
)
|
||||
}
|
||||
function refreshTypeList(opts) {
|
||||
@@ -323,9 +337,16 @@ RED.typeSearch = (function() {
|
||||
searchInput.searchBox('value','').focus();
|
||||
selected = -1;
|
||||
var common = [
|
||||
'inject','debug','function','change','switch'
|
||||
'inject','debug','function','change','switch','junction'
|
||||
].filter(function(t) { return applyFilter(opts.filter,t,RED.nodes.getType(t)); });
|
||||
|
||||
// if (opts.filter && opts.filter.input && opts.filter.output && !opts.filter.type) {
|
||||
// if (opts.filter.spliceMultiple) {
|
||||
// common.push('_action_:core:split-wires-with-junctions')
|
||||
// }
|
||||
// common.push('_action_:core:split-wire-with-link-nodes')
|
||||
// }
|
||||
|
||||
var recentlyUsed = Object.keys(typesUsed);
|
||||
recentlyUsed.sort(function(a,b) {
|
||||
return typesUsed[b]-typesUsed[a];
|
||||
@@ -348,6 +369,11 @@ RED.typeSearch = (function() {
|
||||
var index = 0;
|
||||
for(i=0;i<common.length;i++) {
|
||||
var itemDef = RED.nodes.getType(common[i]);
|
||||
if (common[i] === 'junction') {
|
||||
itemDef = { inputs:1, outputs: 1, label: 'junction', type: 'junction'}
|
||||
} else if (/^_action_:/.test(common[i]) ) {
|
||||
itemDef = { inputs:1, outputs: 1, label: common[i], type: common[i]}
|
||||
}
|
||||
if (itemDef) {
|
||||
item = {
|
||||
type: common[i],
|
||||
|
||||
@@ -121,6 +121,13 @@ RED.userSettings = (function() {
|
||||
// {setting:"theme", label:"Theme",options:function(done){ done([{val:'',text:'default'}].concat(RED.settings.theme("themes"))) }},
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
title: "menu.label.view.view",
|
||||
options: [
|
||||
{setting:"view-store-zoom",label:"menu.label.view.storeZoom", default: false, toggle:true, onchange: function(val) { if (!val) { RED.settings.removeLocal("zoom-level")}}},
|
||||
{setting:"view-store-position",label:"menu.label.view.storePosition", default: false, toggle:true, onchange: function(val) { if (!val) { RED.settings.removeLocal("scroll-positions")}}},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "menu.label.view.grid",
|
||||
options: [
|
||||
@@ -139,7 +146,8 @@ RED.userSettings = (function() {
|
||||
{
|
||||
title: "menu.label.other",
|
||||
options: [
|
||||
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"}
|
||||
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"},
|
||||
{setting:"view-show-welcome-tours",label:"menu.label.showWelcomeTours",toggle:true,default:true}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -22,8 +22,82 @@ RED.utils = (function() {
|
||||
return renderMarkdown(txt);
|
||||
}
|
||||
|
||||
_marked.setOptions({
|
||||
renderer: new _marked.Renderer(),
|
||||
const descriptionList = {
|
||||
name: 'descriptionList',
|
||||
level: 'block', // Is this a block-level or inline-level tokenizer?
|
||||
start(src) {
|
||||
if (!src) { return null; }
|
||||
let m = src.match(/:[^:\n]/g);
|
||||
return m && m.index; // Hint to Marked.js to stop and check for a match
|
||||
},
|
||||
tokenizer(src, tokens) {
|
||||
if (!src) { return null; }
|
||||
const rule = /^(?::[^:\n]+:[^:\n]*(?:\n|$))+/; // Regex for the complete token
|
||||
const match = rule.exec(src);
|
||||
if (match) {
|
||||
return { // Token to generate
|
||||
type: 'descriptionList', // Should match "name" above
|
||||
raw: match[0], // Text to consume from the source
|
||||
text: match[0].trim(), // Additional custom properties
|
||||
tokens: this.lexer.inlineTokens(match[0].trim()) // inlineTokens to process **bold**, *italics*, etc.
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer(token) {
|
||||
return `<dl class="message-properties">${this.parser.parseInline(token.tokens)}\n</dl>`; // parseInline to turn child tokens into HTML
|
||||
}
|
||||
};
|
||||
|
||||
const description = {
|
||||
name: 'description',
|
||||
level: 'inline', // Is this a block-level or inline-level tokenizer?
|
||||
start(src) {
|
||||
if (!src) { return null; }
|
||||
let m = src.match(/:/g);
|
||||
return m && m.index; // Hint to Marked.js to stop and check for a match
|
||||
},
|
||||
tokenizer(src, tokens) {
|
||||
if (!src) { return null; }
|
||||
const rule = /^:([^:\n]+)\(([^:\n]+)\).*?:([^:\n]*)(?:\n|$)/; // Regex for the complete token
|
||||
const match = rule.exec(src);
|
||||
if (match) {
|
||||
return { // Token to generate
|
||||
type: 'description', // Should match "name" above
|
||||
raw: match[0], // Text to consume from the source
|
||||
dt: this.lexer.inlineTokens(match[1].trim()), // Additional custom properties
|
||||
types: this.lexer.inlineTokens(match[2].trim()),
|
||||
dd: this.lexer.inlineTokens(match[3].trim()),
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer(token) {
|
||||
return `\n<dt>${this.parser.parseInline(token.dt)}<span class="property-type">${this.parser.parseInline(token.types)}</span></dt><dd>${this.parser.parseInline(token.dd)}</dd>`;
|
||||
},
|
||||
childTokens: ['dt', 'dd'], // Any child tokens to be visited by walkTokens
|
||||
walkTokens(token) { // Post-processing on the completed token tree
|
||||
if (token.type === 'strong') {
|
||||
token.text += ' walked';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const renderer = new window._marked.Renderer();
|
||||
|
||||
//override list creation - add node-ports to order lists
|
||||
renderer.list = function (body, ordered, start) {
|
||||
let addClass = /dl.*?class.*?message-properties.*/.test(body);
|
||||
if (addClass && ordered) {
|
||||
return '<ol class="node-ports">' + body + '</ol>';
|
||||
} else if (ordered) {
|
||||
return '<ol>' + body + '</ol>';
|
||||
} else {
|
||||
return '<ul>' + body + '</ul>'
|
||||
}
|
||||
}
|
||||
|
||||
window._marked.setOptions({
|
||||
renderer: renderer,
|
||||
gfm: true,
|
||||
tables: true,
|
||||
breaks: false,
|
||||
@@ -32,8 +106,10 @@ RED.utils = (function() {
|
||||
smartypants: false
|
||||
});
|
||||
|
||||
window._marked.use({extensions: [descriptionList, description] } );
|
||||
|
||||
function renderMarkdown(txt) {
|
||||
var rendered = _marked(txt);
|
||||
var rendered = _marked.parse(txt);
|
||||
var cleaned = DOMPurify.sanitize(rendered, {SAFE_FOR_JQUERY: true})
|
||||
return cleaned;
|
||||
}
|
||||
@@ -66,6 +142,8 @@ RED.utils = (function() {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('function');
|
||||
} else if (value.hasOwnProperty('type') && (value.type === 'number' || value.type === 'bigint')) {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data);
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'regexp') {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-string"></span>').text(value.data);
|
||||
} else {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>');
|
||||
}
|
||||
@@ -287,7 +365,16 @@ RED.utils = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function buildMessageElement(obj,options) {
|
||||
/**
|
||||
* Create a DOM element representation of obj - as used by Debug sidebar etc
|
||||
*
|
||||
* @params obj - the data to display
|
||||
* @params options - a bag of options
|
||||
*
|
||||
* - If you want the Copy Value button, then set `sourceId`
|
||||
* - If you want the Copy Path button, also set `path` to the value to be copied
|
||||
*/
|
||||
function createObjectElement(obj,options) {
|
||||
options = options || {};
|
||||
var key = options.key;
|
||||
var typeHint = options.typeHint;
|
||||
@@ -364,6 +451,8 @@ RED.utils = (function() {
|
||||
$('<span class="red-ui-debug-msg-type-null">undefined</span>').appendTo(entryObj);
|
||||
} else if (obj.__enc__ && (obj.type === 'number' || obj.type === 'bigint')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>').text(obj.data).appendTo(entryObj);
|
||||
} else if (typeHint === "regexp" || (obj.__enc__ && obj.type === 'regexp')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>').text((typeof obj === "string")?obj:obj.data).appendTo(entryObj);
|
||||
} else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("function").appendTo(entryObj);
|
||||
} else if (typeHint === "internal" || (obj.__enc__ && obj.type === 'internal')) {
|
||||
@@ -475,7 +564,7 @@ RED.utils = (function() {
|
||||
if (fullLength <= 10) {
|
||||
for (i=0;i<fullLength;i++) {
|
||||
row = $('<div class="red-ui-debug-msg-object-entry collapsed"></div>').appendTo(arrayRows);
|
||||
subElements[path+"["+i+"]"] = buildMessageElement(
|
||||
subElements[path+"["+i+"]"] = createObjectElement(
|
||||
data[i],
|
||||
{
|
||||
key: ""+i,
|
||||
@@ -487,7 +576,8 @@ RED.utils = (function() {
|
||||
expandPaths: expandPaths,
|
||||
ontoggle: ontoggle,
|
||||
exposeApi: exposeApi,
|
||||
tools: tools
|
||||
// tools: tools // Do not pass tools down as we
|
||||
// keep them attached to the top-level header
|
||||
}
|
||||
).appendTo(row);
|
||||
}
|
||||
@@ -504,7 +594,7 @@ RED.utils = (function() {
|
||||
return function() {
|
||||
for (var i=min;i<=max;i++) {
|
||||
var row = $('<div class="red-ui-debug-msg-object-entry collapsed"></div>').appendTo(parent);
|
||||
subElements[path+"["+i+"]"] = buildMessageElement(
|
||||
subElements[path+"["+i+"]"] = createObjectElement(
|
||||
data[i],
|
||||
{
|
||||
key: ""+i,
|
||||
@@ -516,7 +606,8 @@ RED.utils = (function() {
|
||||
expandPaths: expandPaths,
|
||||
ontoggle: ontoggle,
|
||||
exposeApi: exposeApi,
|
||||
tools: tools
|
||||
// tools: tools // Do not pass tools down as we
|
||||
// keep them attached to the top-level header
|
||||
}
|
||||
).appendTo(row);
|
||||
}
|
||||
@@ -559,7 +650,7 @@ RED.utils = (function() {
|
||||
newPath += "[\""+keys[i].replace(/"/,"\\\"")+"\"]"
|
||||
}
|
||||
}
|
||||
subElements[newPath] = buildMessageElement(
|
||||
subElements[newPath] = createObjectElement(
|
||||
data[keys[i]],
|
||||
{
|
||||
key: keys[i],
|
||||
@@ -571,7 +662,8 @@ RED.utils = (function() {
|
||||
expandPaths: expandPaths,
|
||||
ontoggle: ontoggle,
|
||||
exposeApi: exposeApi,
|
||||
tools: tools
|
||||
// tools: tools // Do not pass tools down as we
|
||||
// keep them attached to the top-level header
|
||||
}
|
||||
).appendTo(row);
|
||||
}
|
||||
@@ -936,8 +1028,12 @@ RED.utils = (function() {
|
||||
return "font-awesome/fa-object-ungroup";
|
||||
} else if (node && node.type === 'group') {
|
||||
return "font-awesome/fa-object-group"
|
||||
} else if ((node && node.type === 'junction') || (def.type === "junction") ) {
|
||||
return "font-awesome/fa-circle-o"
|
||||
} else if (def.category === 'config') {
|
||||
return RED.settings.apiRootUrl+"icons/node-red/cog.svg"
|
||||
} else if ((node && /^_action_:/.test(node.type)) || /^_action_:/.test(def.type)) {
|
||||
return "font-awesome/fa-cogs"
|
||||
} else if (node && node.type === 'tab') {
|
||||
return "red-ui-icons/red-ui-icons-flow"
|
||||
// return RED.settings.apiRootUrl+"images/subflow_tab.svg"
|
||||
@@ -1001,6 +1097,8 @@ RED.utils = (function() {
|
||||
l = node.label || defaultLabel
|
||||
} else if (node.type === 'group') {
|
||||
l = node.name || defaultLabel
|
||||
} else if (node.type === 'junction') {
|
||||
l = 'junction'
|
||||
} else {
|
||||
l = node._def.label;
|
||||
try {
|
||||
@@ -1013,6 +1111,18 @@ RED.utils = (function() {
|
||||
return RED.text.bidi.enforceTextDirectionWithUCC(l);
|
||||
}
|
||||
|
||||
function getPaletteLabel(nodeType, def) {
|
||||
var label = nodeType;
|
||||
if (typeof def.paletteLabel !== "undefined") {
|
||||
try {
|
||||
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+nodeType+".paletteLabel",err);
|
||||
}
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
var nodeColorCache = {};
|
||||
function clearNodeColorCache() {
|
||||
nodeColorCache = {};
|
||||
@@ -1155,6 +1265,8 @@ RED.utils = (function() {
|
||||
nodeDiv.addClass("red-ui-palette-icon-selection");
|
||||
} else if (node.type === "group") {
|
||||
nodeDiv.addClass("red-ui-palette-icon-group");
|
||||
} else if (node.type === "junction") {
|
||||
nodeDiv.addClass("red-ui-palette-icon-junction");
|
||||
} else if (node.type === 'tab') {
|
||||
nodeDiv.addClass("red-ui-palette-icon-flow");
|
||||
} else {
|
||||
@@ -1286,7 +1398,7 @@ RED.utils = (function() {
|
||||
}
|
||||
|
||||
return {
|
||||
createObjectElement: buildMessageElement,
|
||||
createObjectElement: createObjectElement,
|
||||
getMessageProperty: getMessageProperty,
|
||||
setMessageProperty: setMessageProperty,
|
||||
normalisePropertyExpression: normalisePropertyExpression,
|
||||
@@ -1296,6 +1408,7 @@ RED.utils = (function() {
|
||||
getNodeIcon: getNodeIcon,
|
||||
getNodeLabel: getNodeLabel,
|
||||
getNodeColor: getNodeColor,
|
||||
getPaletteLabel: getPaletteLabel,
|
||||
clearNodeColorCache: clearNodeColorCache,
|
||||
addSpinnerOverlay: addSpinnerOverlay,
|
||||
decodeObject: decodeObject,
|
||||
|
||||
@@ -159,15 +159,15 @@ RED.view.tools = (function() {
|
||||
nodes.forEach(function(n) {
|
||||
var modified = false;
|
||||
var oldValue = n.l === undefined?true:n.l;
|
||||
var isLink = /^link (in|out)$/.test(n._def.type);
|
||||
var showLabel = n._def.hasOwnProperty("showLabel")?n._def.showLabel:true;
|
||||
|
||||
if (labelShown) {
|
||||
if (n.l === false || (isLink && !n.hasOwnProperty('l'))) {
|
||||
if (n.l === false || (!showLabel && !n.hasOwnProperty('l'))) {
|
||||
n.l = true;
|
||||
modified = true;
|
||||
}
|
||||
} else {
|
||||
if ((!isLink && (!n.hasOwnProperty('l') || n.l === true)) || (isLink && n.l === true) ) {
|
||||
if ((showLabel && (!n.hasOwnProperty('l') || n.l === true)) || (!showLabel && n.l === true) ) {
|
||||
n.l = false;
|
||||
modified = true;
|
||||
}
|
||||
@@ -336,17 +336,17 @@ RED.view.tools = (function() {
|
||||
|
||||
}
|
||||
|
||||
function addNode() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].outputs > 0) {
|
||||
var selectedNode = selection.nodes[0];
|
||||
RED.view.showQuickAddDialog([
|
||||
selectedNode.x + selectedNode.w + 50,selectedNode.y
|
||||
])
|
||||
} else {
|
||||
RED.view.showQuickAddDialog();
|
||||
}
|
||||
}
|
||||
// function addNode() {
|
||||
// var selection = RED.view.selection();
|
||||
// if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].outputs > 0) {
|
||||
// var selectedNode = selection.nodes[0];
|
||||
// RED.view.showQuickAddDialog([
|
||||
// selectedNode.x + selectedNode.w + 50,selectedNode.y
|
||||
// ])
|
||||
// } else {
|
||||
// RED.view.showQuickAddDialog();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
function gotoNearestNode(direction) {
|
||||
@@ -427,18 +427,763 @@ RED.view.tools = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function alignSelectionToEdge(direction) {
|
||||
var selection = RED.view.selection();
|
||||
|
||||
if (selection.nodes && selection.nodes.length > 1) {
|
||||
var changedNodes = [];
|
||||
var bounds = {
|
||||
minX: Number.MAX_SAFE_INTEGER,
|
||||
minY: Number.MAX_SAFE_INTEGER,
|
||||
maxX: Number.MIN_SAFE_INTEGER,
|
||||
maxY: Number.MIN_SAFE_INTEGER
|
||||
}
|
||||
selection.nodes.forEach(function(n) {
|
||||
if (n.type === "group") {
|
||||
bounds.minX = Math.min(bounds.minX, n.x);
|
||||
bounds.minY = Math.min(bounds.minY, n.y);
|
||||
bounds.maxX = Math.max(bounds.maxX, n.x + n.w);
|
||||
bounds.maxY = Math.max(bounds.maxY, n.y + n.h);
|
||||
} else {
|
||||
bounds.minX = Math.min(bounds.minX, n.x - n.w/2);
|
||||
bounds.minY = Math.min(bounds.minY, n.y - n.h/2);
|
||||
bounds.maxX = Math.max(bounds.maxX, n.x + n.w/2);
|
||||
bounds.maxY = Math.max(bounds.maxY, n.y + n.h/2);
|
||||
}
|
||||
});
|
||||
|
||||
bounds.midX = bounds.minX + (bounds.maxX - bounds.minX)/2;
|
||||
bounds.midY = bounds.minY + (bounds.maxY - bounds.minY)/2;
|
||||
|
||||
selection.nodes.forEach(function(n) {
|
||||
var targetX;
|
||||
var targetY;
|
||||
var isGroup = n.type==="group";
|
||||
switch(direction) {
|
||||
case 'top':
|
||||
targetX = n.x;
|
||||
targetY = bounds.minY + (isGroup?0:(n.h/2));
|
||||
break;
|
||||
case 'bottom':
|
||||
targetX = n.x;
|
||||
targetY = bounds.maxY - (isGroup?n.h:(n.h/2));
|
||||
break;
|
||||
case 'left':
|
||||
targetX = bounds.minX + (isGroup?0:(n.w/2));
|
||||
targetY = n.y;
|
||||
break;
|
||||
case 'right':
|
||||
targetX = bounds.maxX - (isGroup?n.w:(n.w/2));
|
||||
targetY = n.y;
|
||||
break;
|
||||
case 'middle':
|
||||
targetX = n.x;
|
||||
targetY = bounds.midY - (isGroup?n.h/2:0)
|
||||
break;
|
||||
case 'center':
|
||||
targetX = bounds.midX - (isGroup?n.w/2:0)
|
||||
targetY = n.y;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n.x !== targetX || n.y !== targetY) {
|
||||
if (!isGroup) {
|
||||
changedNodes.push({
|
||||
n:n,
|
||||
ox: n.x,
|
||||
oy: n.y,
|
||||
moved: n.moved
|
||||
});
|
||||
n.x = targetX;
|
||||
n.y = targetY;
|
||||
n.dirty = true;
|
||||
n.moved = true;
|
||||
} else {
|
||||
var groupNodes = RED.group.getNodes(n, true);
|
||||
var deltaX = n.x - targetX;
|
||||
var deltaY = n.y - targetY;
|
||||
groupNodes.forEach(function(gn) {
|
||||
if (gn.type !== "group" ) {
|
||||
changedNodes.push({
|
||||
n:gn,
|
||||
ox: gn.x,
|
||||
oy: gn.y,
|
||||
moved: gn.moved
|
||||
});
|
||||
gn.x = gn.x - deltaX;
|
||||
gn.y = gn.y - deltaY;
|
||||
gn.dirty = true;
|
||||
gn.moved = true;
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
if (changedNodes.length > 0) {
|
||||
RED.history.push({t:"move",nodes:changedNodes,dirty:RED.nodes.dirty()});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function distributeSelection(direction) {
|
||||
var selection = RED.view.selection();
|
||||
|
||||
if (selection.nodes && selection.nodes.length > 2) {
|
||||
var changedNodes = [];
|
||||
var bounds = {
|
||||
minX: Number.MAX_SAFE_INTEGER,
|
||||
minY: Number.MAX_SAFE_INTEGER,
|
||||
maxX: Number.MIN_SAFE_INTEGER,
|
||||
maxY: Number.MIN_SAFE_INTEGER
|
||||
}
|
||||
var startAnchors = [];
|
||||
var endAnchors = [];
|
||||
|
||||
selection.nodes.forEach(function(n) {
|
||||
var nx,ny;
|
||||
if (n.type === "group") {
|
||||
nx = n.x + n.w/2;
|
||||
ny = n.y + n.h/2;
|
||||
} else {
|
||||
nx = n.x;
|
||||
ny = n.y;
|
||||
}
|
||||
if (direction === "h") {
|
||||
if (nx < bounds.minX) {
|
||||
startAnchors = [];
|
||||
bounds.minX = nx;
|
||||
}
|
||||
if (nx === bounds.minX) {
|
||||
startAnchors.push(n);
|
||||
}
|
||||
if (nx > bounds.maxX) {
|
||||
endAnchors = [];
|
||||
bounds.maxX = nx;
|
||||
}
|
||||
if (nx === bounds.maxX) {
|
||||
endAnchors.push(n);
|
||||
}
|
||||
} else {
|
||||
if (ny < bounds.minY) {
|
||||
startAnchors = [];
|
||||
bounds.minY = ny;
|
||||
}
|
||||
if (ny === bounds.minY) {
|
||||
startAnchors.push(n);
|
||||
}
|
||||
if (ny > bounds.maxY) {
|
||||
endAnchors = [];
|
||||
bounds.maxY = ny;
|
||||
}
|
||||
if (ny === bounds.maxY) {
|
||||
endAnchors.push(n);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var startAnchor = startAnchors[0];
|
||||
var endAnchor = endAnchors[0];
|
||||
|
||||
var nodeSpace = 0;
|
||||
var nodesToMove = selection.nodes.filter(function(n) {
|
||||
if (n.id !== startAnchor.id && n.id !== endAnchor.id) {
|
||||
nodeSpace += direction === 'h'?n.w:n.h;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}).sort(function(A,B) {
|
||||
if (direction === 'h') {
|
||||
return A.x - B.x
|
||||
} else {
|
||||
return A.y - B.y
|
||||
}
|
||||
})
|
||||
|
||||
var saX = startAnchor.x + startAnchor.w/2;
|
||||
var saY = startAnchor.y + startAnchor.h/2;
|
||||
if (startAnchor.type === "group") {
|
||||
saX = startAnchor.x + startAnchor.w;
|
||||
saY = startAnchor.y + startAnchor.h;
|
||||
}
|
||||
var eaX = endAnchor.x;
|
||||
var eaY = endAnchor.y;
|
||||
if (endAnchor.type !== "group") {
|
||||
eaX -= endAnchor.w/2;
|
||||
eaY -= endAnchor.h/2;
|
||||
}
|
||||
var spaceToFill = direction === 'h'?(eaX - saX - nodeSpace): (eaY - saY - nodeSpace);
|
||||
var spaceBetweenNodes = spaceToFill / (nodesToMove.length + 1);
|
||||
|
||||
var tx = saX;
|
||||
var ty = saY;
|
||||
while(nodesToMove.length > 0) {
|
||||
if (direction === 'h') {
|
||||
tx += spaceBetweenNodes;
|
||||
} else {
|
||||
ty += spaceBetweenNodes;
|
||||
}
|
||||
var nextNode = nodesToMove.shift();
|
||||
var isGroup = nextNode.type==="group";
|
||||
|
||||
var nx = nextNode.x;
|
||||
var ny = nextNode.y;
|
||||
if (!isGroup) {
|
||||
tx += nextNode.w/2;
|
||||
ty += nextNode.h/2;
|
||||
}
|
||||
if ((direction === 'h' && nx !== tx) || (direction === 'v' && ny !== ty)) {
|
||||
if (!isGroup) {
|
||||
changedNodes.push({
|
||||
n:nextNode,
|
||||
ox: nextNode.x,
|
||||
oy: nextNode.y,
|
||||
moved: nextNode.moved
|
||||
});
|
||||
if (direction === 'h') {
|
||||
nextNode.x = tx;
|
||||
} else {
|
||||
nextNode.y = ty;
|
||||
}
|
||||
nextNode.dirty = true;
|
||||
nextNode.moved = true;
|
||||
} else {
|
||||
var groupNodes = RED.group.getNodes(nextNode, true);
|
||||
var deltaX = direction === 'h'? nx - tx : 0;
|
||||
var deltaY = direction === 'v'? ny - ty : 0;
|
||||
groupNodes.forEach(function(gn) {
|
||||
if (gn.type !== "group" ) {
|
||||
changedNodes.push({
|
||||
n:gn,
|
||||
ox: gn.x,
|
||||
oy: gn.y,
|
||||
moved: gn.moved
|
||||
});
|
||||
gn.x = gn.x - deltaX;
|
||||
gn.y = gn.y - deltaY;
|
||||
gn.dirty = true;
|
||||
gn.moved = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
if (isGroup) {
|
||||
tx += nextNode.w;
|
||||
ty += nextNode.h;
|
||||
} else {
|
||||
tx += nextNode.w/2;
|
||||
ty += nextNode.h/2;
|
||||
}
|
||||
}
|
||||
|
||||
if (changedNodes.length > 0) {
|
||||
RED.history.push({t:"move",nodes:changedNodes,dirty:RED.nodes.dirty()});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reorderSelection(dir) {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nodesToMove = [];
|
||||
selection.nodes.forEach(function(n) {
|
||||
if (n.type === "group") {
|
||||
nodesToMove = nodesToMove.concat(RED.group.getNodes(n, true).filter(function(n) {
|
||||
return n.type !== "group";
|
||||
}))
|
||||
} else if (n.type !== "subflow"){
|
||||
nodesToMove.push(n);
|
||||
}
|
||||
})
|
||||
if (nodesToMove.length > 0) {
|
||||
var z = nodesToMove[0].z;
|
||||
var existingOrder = RED.nodes.getNodeOrder(z);
|
||||
var movedNodes;
|
||||
if (dir === "forwards") {
|
||||
movedNodes = RED.nodes.moveNodesForwards(nodesToMove);
|
||||
} else if (dir === "backwards") {
|
||||
movedNodes = RED.nodes.moveNodesBackwards(nodesToMove);
|
||||
} else if (dir === "front") {
|
||||
movedNodes = RED.nodes.moveNodesToFront(nodesToMove);
|
||||
} else if (dir === "back") {
|
||||
movedNodes = RED.nodes.moveNodesToBack(nodesToMove);
|
||||
}
|
||||
if (movedNodes.length > 0) {
|
||||
var newOrder = RED.nodes.getNodeOrder(z);
|
||||
RED.history.push({t:"reorder",nodes:{z:z,from:existingOrder,to:newOrder},dirty:RED.nodes.dirty()});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function wireSeriesOfNodes() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length > 1) {
|
||||
var i = 0;
|
||||
var newLinks = [];
|
||||
while (i < selection.nodes.length - 1) {
|
||||
var nodeA = selection.nodes[i];
|
||||
var nodeB = selection.nodes[i+1];
|
||||
if (nodeA.outputs > 0 && nodeB.inputs > 0) {
|
||||
var existingLinks = RED.nodes.filterLinks({
|
||||
source: nodeA,
|
||||
target: nodeB,
|
||||
sourcePort: 0
|
||||
})
|
||||
if (existingLinks.length === 0) {
|
||||
var newLink = {
|
||||
source: nodeA,
|
||||
target: nodeB,
|
||||
sourcePort: 0
|
||||
}
|
||||
RED.nodes.addLink(newLink);
|
||||
newLinks.push(newLink);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (newLinks.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'add',
|
||||
links: newLinks,
|
||||
dirty: RED.nodes.dirty()
|
||||
})
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function wireNodeToMultiple() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length > 1) {
|
||||
var sourceNode = selection.nodes[0];
|
||||
if (sourceNode.outputs === 0) {
|
||||
return;
|
||||
}
|
||||
var i = 1;
|
||||
var newLinks = [];
|
||||
while (i < selection.nodes.length) {
|
||||
var targetNode = selection.nodes[i];
|
||||
if (targetNode.inputs > 0) {
|
||||
var existingLinks = RED.nodes.filterLinks({
|
||||
source: sourceNode,
|
||||
target: targetNode,
|
||||
sourcePort: Math.min(sourceNode.outputs-1,i-1)
|
||||
})
|
||||
if (existingLinks.length === 0) {
|
||||
var newLink = {
|
||||
source: sourceNode,
|
||||
target: targetNode,
|
||||
sourcePort: Math.min(sourceNode.outputs-1,i-1)
|
||||
}
|
||||
RED.nodes.addLink(newLink);
|
||||
newLinks.push(newLink);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (newLinks.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'add',
|
||||
links: newLinks,
|
||||
dirty: RED.nodes.dirty()
|
||||
})
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits selected wires and re-joins them with link-out+link-in
|
||||
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
|
||||
*/
|
||||
function splitWiresWithLinkNodes(wires) {
|
||||
let wiresToSplit = wires || RED.view.selection().links;
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
}
|
||||
if (!Array.isArray(wiresToSplit)) {
|
||||
wiresToSplit = [wiresToSplit];
|
||||
}
|
||||
if (wiresToSplit.length < 1) {
|
||||
return; //nothing selected
|
||||
}
|
||||
|
||||
const history = {
|
||||
t: 'multi',
|
||||
events: [],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
const nodeSrcMap = {};
|
||||
const nodeTrgMap = {};
|
||||
const _gridSize = RED.view.gridSize();
|
||||
|
||||
for (let wireIdx = 0; wireIdx < wiresToSplit.length; wireIdx++) {
|
||||
const wire = wiresToSplit[wireIdx];
|
||||
|
||||
//get source and target nodes of this wire link
|
||||
const nSrc = wire.source;
|
||||
const nTrg = wire.target;
|
||||
|
||||
var updateNewNodePosXY = function (origNode, newNode, alignLeft, snap, yOffset) {
|
||||
const nnSize = RED.view.calculateNodeDimensions(newNode);
|
||||
newNode.w = nnSize[0];
|
||||
newNode.h = nnSize[1];
|
||||
const coords = { x: origNode.x || 0, y: origNode.y || 0, w: origNode.w || RED.view.node_width, h: origNode.h || RED.view.node_height };
|
||||
const x = coords.x - (coords.w/2.0);
|
||||
if (alignLeft) {
|
||||
coords.x = x - _gridSize - (newNode.w/2.0);
|
||||
} else {
|
||||
coords.x = x + coords.w + _gridSize + (newNode.w/2.0);
|
||||
}
|
||||
newNode.x = coords.x;
|
||||
newNode.y = coords.y;
|
||||
if (snap !== false) {
|
||||
const offsets = RED.view.tools.calculateGridSnapOffsets(newNode);
|
||||
newNode.x -= offsets.x;
|
||||
newNode.y -= offsets.y;
|
||||
}
|
||||
newNode.y += (yOffset || 0);
|
||||
}
|
||||
const srcPort = (wire.sourcePort || 0);
|
||||
let linkOutMapId = nSrc.id + ':' + srcPort;
|
||||
let nnLinkOut = nodeSrcMap[linkOutMapId];
|
||||
//Create a Link Out if one is not already present
|
||||
if(!nnLinkOut) {
|
||||
const nLinkOut = RED.view.createNode("link out"); //create link node
|
||||
nnLinkOut = nLinkOut.node;
|
||||
nodeSrcMap[linkOutMapId] = nnLinkOut;
|
||||
let yOffset = 0;
|
||||
if(nSrc.outputs > 1) {
|
||||
|
||||
const CENTER_PORT = (((nSrc.outputs-1) / 2) + 1);
|
||||
const offsetCount = Math.abs(CENTER_PORT - (srcPort + 1));
|
||||
yOffset = (_gridSize * 2 * offsetCount);
|
||||
if((srcPort + 1) < CENTER_PORT) {
|
||||
yOffset = -yOffset;
|
||||
}
|
||||
updateNewNodePosXY(nSrc, nnLinkOut, false, false, yOffset);
|
||||
} else {
|
||||
updateNewNodePosXY(nSrc, nnLinkOut, false, RED.view.snapGrid, yOffset);
|
||||
}
|
||||
//add created node
|
||||
RED.nodes.add(nnLinkOut);
|
||||
RED.editor.validateNode(nnLinkOut);
|
||||
history.events.push(nLinkOut.historyEvent);
|
||||
//connect node to link node
|
||||
const link = {
|
||||
source: nSrc,
|
||||
sourcePort: wire.sourcePort || 0,
|
||||
target: nnLinkOut
|
||||
};
|
||||
RED.nodes.addLink(link);
|
||||
history.events.push({
|
||||
t: 'add',
|
||||
links: [link],
|
||||
});
|
||||
}
|
||||
|
||||
let nnLinkIn = nodeTrgMap[nTrg.id];
|
||||
//Create a Link In if one is not already present
|
||||
if(!nnLinkIn) {
|
||||
const nLinkIn = RED.view.createNode("link in"); //create link node
|
||||
nnLinkIn = nLinkIn.node;
|
||||
nodeTrgMap[nTrg.id] = nnLinkIn;
|
||||
updateNewNodePosXY(nTrg, nnLinkIn, true, RED.view.snapGrid, 0);
|
||||
//add created node
|
||||
RED.nodes.add(nnLinkIn);
|
||||
RED.editor.validateNode(nnLinkIn);
|
||||
history.events.push(nLinkIn.historyEvent);
|
||||
//connect node to link node
|
||||
const link = {
|
||||
source: nnLinkIn,
|
||||
sourcePort: 0,
|
||||
target: nTrg
|
||||
};
|
||||
RED.nodes.addLink(link);
|
||||
history.events.push({
|
||||
t: 'add',
|
||||
links: [link],
|
||||
});
|
||||
}
|
||||
|
||||
//connect the link out/link in virtual wires
|
||||
if(nnLinkIn.links.indexOf(nnLinkOut.id) == -1) {
|
||||
nnLinkIn.links.push(nnLinkOut.id);
|
||||
}
|
||||
if(nnLinkOut.links.indexOf(nnLinkIn.id) == -1) {
|
||||
nnLinkOut.links.push(nnLinkIn.id);
|
||||
}
|
||||
|
||||
//delete the original wire
|
||||
RED.nodes.removeLink(wire);
|
||||
history.events.push({
|
||||
t: "delete",
|
||||
links: [wire]
|
||||
});
|
||||
}
|
||||
//add all history events to stack
|
||||
RED.history.push(history);
|
||||
|
||||
//select all downstream of new link-in nodes so user can drag to new location
|
||||
RED.view.clearSelection();
|
||||
RED.view.select({nodes: Object.values(nodeTrgMap) });
|
||||
selectConnected("down");
|
||||
|
||||
//update the view
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the required offsets to snap a node
|
||||
* @param {Object} node The node to calculate grid snap offsets for
|
||||
* @param {Object} [options] Options: `align` can be "nearest", "left" or "right"
|
||||
* @returns `{x:number, y:number}` as the offsets to deduct from `x` and `y`
|
||||
*/
|
||||
function calculateGridSnapOffsets(node, options) {
|
||||
options = options || { align: "nearest" };
|
||||
const gridOffset = { x: 0, y: 0 };
|
||||
const gridSize = RED.view.gridSize();
|
||||
const offsetLeft = node.x - (gridSize * Math.round((node.x - node.w / 2) / gridSize) + node.w / 2);
|
||||
const offsetRight = node.x - (gridSize * Math.round((node.x + node.w / 2) / gridSize) - node.w / 2);
|
||||
gridOffset.x = offsetRight;
|
||||
if (options.align === "right") {
|
||||
//skip - already set to right
|
||||
} else if (options.align === "left" || Math.abs(offsetLeft) < Math.abs(offsetRight)) {
|
||||
gridOffset.x = offsetLeft;
|
||||
}
|
||||
gridOffset.y = node.y - (gridSize * Math.round(node.y / gridSize));
|
||||
return gridOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate names for the select nodes.
|
||||
* - it only sets the name if it is currently blank
|
||||
* - it uses `<paletteLabel> <N>` - where N is the next available integer that
|
||||
* doesn't clash with any existing nodes of that type
|
||||
* @param {Object} node The node to set the name of - if not provided, uses current selection
|
||||
*/
|
||||
function generateNodeNames(node, options) {
|
||||
options = options || {
|
||||
renameBlank: true,
|
||||
renameClash: true,
|
||||
generateHistory: true
|
||||
}
|
||||
let nodes = node;
|
||||
if (node) {
|
||||
if (!Array.isArray(node)) {
|
||||
nodes = [ node ]
|
||||
}
|
||||
} else {
|
||||
nodes = RED.view.selection().nodes;
|
||||
}
|
||||
if (nodes && nodes.length > 0) {
|
||||
// Generate history event if using the workspace selection,
|
||||
// or if the provided node already exists
|
||||
const generateHistory = options.generateHistory && (!node || !!RED.nodes.node(node.id))
|
||||
const historyEvents = []
|
||||
const typeIndex = {}
|
||||
let changed = false;
|
||||
nodes.forEach(n => {
|
||||
const nodeDef = n._def || RED.nodes.getType(n.type)
|
||||
if (nodeDef && nodeDef.defaults && nodeDef.defaults.name) {
|
||||
const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef)
|
||||
const defaultNodeNameRE = new RegExp('^'+paletteLabel+' (\\d+)$')
|
||||
if (!typeIndex.hasOwnProperty(n.type)) {
|
||||
const existingNodes = RED.nodes.filterNodes({type: n.type})
|
||||
let maxNameNumber = 0;
|
||||
existingNodes.forEach(n => {
|
||||
let match = defaultNodeNameRE.exec(n.name)
|
||||
if (match) {
|
||||
let nodeNumber = parseInt(match[1])
|
||||
if (nodeNumber > maxNameNumber) {
|
||||
maxNameNumber = nodeNumber
|
||||
}
|
||||
}
|
||||
})
|
||||
typeIndex[n.type] = maxNameNumber + 1
|
||||
}
|
||||
if ((options.renameBlank && n.name === '') || (options.renameClash && defaultNodeNameRE.test(n.name))) {
|
||||
if (generateHistory) {
|
||||
historyEvents.push({
|
||||
t:'edit',
|
||||
node: n,
|
||||
changes: { name: n.name },
|
||||
dirty: RED.nodes.dirty(),
|
||||
changed: n.changed
|
||||
})
|
||||
}
|
||||
n.name = paletteLabel+" "+typeIndex[n.type]
|
||||
n.dirty = true
|
||||
typeIndex[n.type]++
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
})
|
||||
if (changed) {
|
||||
if (historyEvents.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'multi',
|
||||
events: historyEvents
|
||||
})
|
||||
}
|
||||
RED.nodes.dirty(true)
|
||||
RED.view.redraw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addJunctionsToWires(wires) {
|
||||
let wiresToSplit = wires || RED.view.selection().links;
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
}
|
||||
if (!Array.isArray(wiresToSplit)) {
|
||||
wiresToSplit = [wiresToSplit];
|
||||
}
|
||||
if (wiresToSplit.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var removedLinks = new Set()
|
||||
var addedLinks = []
|
||||
var addedJunctions = []
|
||||
|
||||
var groupedLinks = {}
|
||||
wiresToSplit.forEach(function(l) {
|
||||
var sourceId = l.source.id+":"+l.sourcePort
|
||||
groupedLinks[sourceId] = groupedLinks[sourceId] || []
|
||||
groupedLinks[sourceId].push(l)
|
||||
|
||||
groupedLinks[l.target.id] = groupedLinks[l.target.id] || []
|
||||
groupedLinks[l.target.id].push(l)
|
||||
});
|
||||
var linkGroups = Object.keys(groupedLinks)
|
||||
linkGroups.sort(function(A,B) {
|
||||
return groupedLinks[B].length - groupedLinks[A].length
|
||||
})
|
||||
linkGroups.forEach(function(gid) {
|
||||
var links = groupedLinks[gid]
|
||||
var junction = {
|
||||
_def: {defaults:{}},
|
||||
type: 'junction',
|
||||
z: RED.workspaces.active(),
|
||||
id: RED.nodes.id(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0, h: 0,
|
||||
outputs: 1,
|
||||
inputs: 1,
|
||||
dirty: true
|
||||
}
|
||||
links = links.filter(function(l) { return !removedLinks.has(l) })
|
||||
if (links.length === 0) {
|
||||
return
|
||||
}
|
||||
let pointCount = 0
|
||||
links.forEach(function(l) {
|
||||
if (l._sliceLocation) {
|
||||
junction.x += l._sliceLocation.x
|
||||
junction.y += l._sliceLocation.y
|
||||
delete l._sliceLocation
|
||||
pointCount++
|
||||
} else {
|
||||
junction.x += l.source.x + l.source.w/2 + l.target.x - l.target.w/2
|
||||
junction.y += l.source.y + l.target.y
|
||||
pointCount += 2
|
||||
}
|
||||
})
|
||||
junction.x = Math.round(junction.x/pointCount)
|
||||
junction.y = Math.round(junction.y/pointCount)
|
||||
if (RED.view.snapGrid) {
|
||||
let gridSize = RED.view.gridSize()
|
||||
junction.x = (gridSize*Math.round(junction.x/gridSize));
|
||||
junction.y = (gridSize*Math.round(junction.y/gridSize));
|
||||
}
|
||||
|
||||
var nodeGroups = new Set()
|
||||
|
||||
RED.nodes.addJunction(junction)
|
||||
addedJunctions.push(junction)
|
||||
let newLink
|
||||
if (gid === links[0].source.id+":"+links[0].sourcePort) {
|
||||
newLink = {
|
||||
source: links[0].source,
|
||||
sourcePort: links[0].sourcePort,
|
||||
target: junction
|
||||
}
|
||||
} else {
|
||||
newLink = {
|
||||
source: junction,
|
||||
sourcePort: 0,
|
||||
target: links[0].target
|
||||
}
|
||||
}
|
||||
addedLinks.push(newLink)
|
||||
RED.nodes.addLink(newLink)
|
||||
links.forEach(function(l) {
|
||||
removedLinks.add(l)
|
||||
RED.nodes.removeLink(l)
|
||||
let newLink
|
||||
if (gid === l.target.id) {
|
||||
newLink = {
|
||||
source: l.source,
|
||||
sourcePort: l.sourcePort,
|
||||
target: junction
|
||||
}
|
||||
} else {
|
||||
newLink = {
|
||||
source: junction,
|
||||
sourcePort: 0,
|
||||
target: l.target
|
||||
}
|
||||
}
|
||||
addedLinks.push(newLink)
|
||||
RED.nodes.addLink(newLink)
|
||||
nodeGroups.add(l.source.g || "__NONE__")
|
||||
nodeGroups.add(l.target.g || "__NONE__")
|
||||
})
|
||||
if (nodeGroups.size === 1) {
|
||||
var group = nodeGroups.values().next().value
|
||||
if (group !== "__NONE__") {
|
||||
RED.group.addToGroup(RED.nodes.group(group), junction)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (addedJunctions.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'add',
|
||||
links: addedLinks,
|
||||
junctions: addedJunctions,
|
||||
removedLinks: Array.from(removedLinks)
|
||||
})
|
||||
RED.nodes.dirty(true)
|
||||
}
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
||||
RED.actions.add("core:hide-selected-node-labels", function() { setSelectedNodeLabelState(false); })
|
||||
|
||||
RED.actions.add("core:align-selection-to-grid", alignToGrid);
|
||||
|
||||
RED.actions.add("core:scroll-view-up", function() { RED.view.scroll(0,-RED.view.gridSize());});
|
||||
RED.actions.add("core:scroll-view-right", function() { RED.view.scroll(RED.view.gridSize(),0);});
|
||||
RED.actions.add("core:scroll-view-down", function() { RED.view.scroll(0,RED.view.gridSize());});
|
||||
@@ -454,6 +1199,12 @@ RED.view.tools = (function() {
|
||||
RED.actions.add("core:move-selection-down", function() { moveSelection(0,1);});
|
||||
RED.actions.add("core:move-selection-left", function() { moveSelection(-1,0);});
|
||||
|
||||
RED.actions.add("core:move-selection-forwards", function() { reorderSelection('forwards') })
|
||||
RED.actions.add("core:move-selection-backwards", function() { reorderSelection('backwards') })
|
||||
RED.actions.add("core:move-selection-to-front", function() { reorderSelection('front') })
|
||||
RED.actions.add("core:move-selection-to-back", function() { reorderSelection('back') })
|
||||
|
||||
|
||||
RED.actions.add("core:step-selection-up", function() { moveSelection(0,-RED.view.gridSize());});
|
||||
RED.actions.add("core:step-selection-right", function() { moveSelection(RED.view.gridSize(),0);});
|
||||
RED.actions.add("core:step-selection-down", function() { moveSelection(0,RED.view.gridSize());});
|
||||
@@ -474,6 +1225,26 @@ RED.view.tools = (function() {
|
||||
RED.actions.add("core:go-to-nearest-node-on-right", function() { gotoNearestNode('right')})
|
||||
RED.actions.add("core:go-to-nearest-node-above", function() { gotoNearestNode('up') })
|
||||
RED.actions.add("core:go-to-nearest-node-below", function() { gotoNearestNode('down') })
|
||||
|
||||
RED.actions.add("core:align-selection-to-grid", alignToGrid);
|
||||
RED.actions.add("core:align-selection-to-left", function() { alignSelectionToEdge('left') })
|
||||
RED.actions.add("core:align-selection-to-right", function() { alignSelectionToEdge('right') })
|
||||
RED.actions.add("core:align-selection-to-top", function() { alignSelectionToEdge('top') })
|
||||
RED.actions.add("core:align-selection-to-bottom", function() { alignSelectionToEdge('bottom') })
|
||||
RED.actions.add("core:align-selection-to-middle", function() { alignSelectionToEdge('middle') })
|
||||
RED.actions.add("core:align-selection-to-center", function() { alignSelectionToEdge('center') })
|
||||
|
||||
RED.actions.add("core:distribute-selection-horizontally", function() { distributeSelection('h') })
|
||||
RED.actions.add("core:distribute-selection-vertically", function() { distributeSelection('v') })
|
||||
|
||||
RED.actions.add("core:wire-series-of-nodes", function() { wireSeriesOfNodes() })
|
||||
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
|
||||
|
||||
RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
|
||||
RED.actions.add("core:split-wires-with-junctions", function () { addJunctionsToWires() });
|
||||
|
||||
RED.actions.add("core:generate-node-names", generateNodeNames )
|
||||
|
||||
// RED.actions.add("core:add-node", function() { addNode() })
|
||||
},
|
||||
/**
|
||||
@@ -485,7 +1256,8 @@ RED.view.tools = (function() {
|
||||
* @param {Number} dx
|
||||
* @param {Number} dy
|
||||
*/
|
||||
moveSelection: moveSelection
|
||||
moveSelection: moveSelection,
|
||||
calculateGridSnapOffsets: calculateGridSnapOffsets
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,8 +21,11 @@ RED.workspaces = (function() {
|
||||
var workspaceIndex = 0;
|
||||
|
||||
var viewStack = [];
|
||||
var hideStack = [];
|
||||
var viewStackPos = 0;
|
||||
|
||||
let flashingTab;
|
||||
let flashingTabTimer;
|
||||
|
||||
function addToViewStack(id) {
|
||||
if (viewStackPos !== viewStack.length) {
|
||||
@@ -30,31 +33,68 @@ RED.workspaces = (function() {
|
||||
}
|
||||
viewStack.push(id);
|
||||
viewStackPos = viewStack.length;
|
||||
// console.warn("addToViewStack",id,viewStack);
|
||||
}
|
||||
|
||||
function removeFromHideStack(id) {
|
||||
hideStack = hideStack.filter(function(v) {
|
||||
if (v === id) {
|
||||
return false;
|
||||
} else if (Array.isArray(v)) {
|
||||
var i = v.indexOf(id);
|
||||
if (i > -1) {
|
||||
v.splice(i,1);
|
||||
}
|
||||
if (v.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true;
|
||||
})
|
||||
}
|
||||
|
||||
function addWorkspace(ws,skipHistoryEntry,targetIndex) {
|
||||
if (ws) {
|
||||
if (!ws.closeable) {
|
||||
ws.hideable = true;
|
||||
}
|
||||
workspace_tabs.addTab(ws,targetIndex);
|
||||
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
if (hiddenTabs[ws.id]) {
|
||||
workspace_tabs.hideTab(ws.id);
|
||||
}
|
||||
workspace_tabs.resize();
|
||||
} else {
|
||||
var tabId = RED.nodes.id();
|
||||
do {
|
||||
workspaceIndex += 1;
|
||||
} while ($("#red-ui-workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
|
||||
} while ($("#red-ui-workspace-tabs li[flowname='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
|
||||
|
||||
ws = {type:"tab",id:tabId,disabled: false,info:"",label:RED._('workspace.defaultName',{number:workspaceIndex})};
|
||||
ws = {
|
||||
type: "tab",
|
||||
id: tabId,
|
||||
disabled: false,
|
||||
info: "",
|
||||
label: RED._('workspace.defaultName',{number:workspaceIndex}),
|
||||
env: [],
|
||||
hideable: true
|
||||
};
|
||||
RED.nodes.addWorkspace(ws,targetIndex);
|
||||
workspace_tabs.addTab(ws,targetIndex);
|
||||
|
||||
workspace_tabs.activateTab(tabId);
|
||||
if (!skipHistoryEntry) {
|
||||
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
|
||||
|
||||
RED.view.focus();
|
||||
return ws;
|
||||
}
|
||||
|
||||
function deleteWorkspace(ws) {
|
||||
if (workspaceTabCount === 1) {
|
||||
return;
|
||||
@@ -78,165 +118,9 @@ RED.workspaces = (function() {
|
||||
if (subflow) {
|
||||
RED.editor.editSubflow(subflow);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
RED.editor.editFlow(workspace);
|
||||
}
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var tabflowEditor;
|
||||
var trayOptions = {
|
||||
title: RED._("workspace.editFlow",{name:RED.utils.sanitize(workspace.label)}),
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-delete",
|
||||
class: 'leftButton'+((workspaceTabCount === 1)?" disabled":""),
|
||||
text: RED._("common.label.delete"), //'<i class="fa fa-trash"></i>',
|
||||
click: function() {
|
||||
deleteWorkspace(workspace);
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
class: "primary",
|
||||
text: RED._("common.label.done"),
|
||||
click: function() {
|
||||
var label = $( "#node-input-name" ).val();
|
||||
var changed = false;
|
||||
var changes = {};
|
||||
if (workspace.label != label) {
|
||||
changes.label = workspace.label;
|
||||
changed = true;
|
||||
workspace.label = label;
|
||||
workspace_tabs.renameTab(workspace.id,label);
|
||||
}
|
||||
var disabled = $("#node-input-disabled").prop("checked");
|
||||
if (workspace.disabled !== disabled) {
|
||||
changes.disabled = workspace.disabled;
|
||||
changed = true;
|
||||
workspace.disabled = disabled;
|
||||
}
|
||||
var info = tabflowEditor.getValue();
|
||||
if (workspace.info !== info) {
|
||||
changes.info = workspace.info;
|
||||
changed = true;
|
||||
workspace.info = info;
|
||||
}
|
||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
|
||||
|
||||
if (changed) {
|
||||
var historyEvent = {
|
||||
t: "edit",
|
||||
changes:changes,
|
||||
node: workspace,
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
workspace.changed = true;
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
RED.sidebar.config.refresh();
|
||||
if (changes.hasOwnProperty('disabled')) {
|
||||
RED.nodes.eachNode(function(n) {
|
||||
if (n.z === workspace.id) {
|
||||
n.dirty = true;
|
||||
}
|
||||
});
|
||||
RED.view.redraw();
|
||||
}
|
||||
RED.events.emit("flows:change",workspace);
|
||||
}
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
||||
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
||||
var height = $("#dialog-form").height();
|
||||
for (var i=0; i<rows.size(); i++) {
|
||||
height -= $(rows[i]).outerHeight(true);
|
||||
}
|
||||
height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
tabflowEditor.resize();
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayFooter = tray.find(".red-ui-tray-footer");
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
|
||||
|
||||
var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(trayBody);
|
||||
$('<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" data-i18n="[placeholder]common.label.name">'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
|
||||
|
||||
if (!workspace.hasOwnProperty("disabled")) {
|
||||
workspace.disabled = false;
|
||||
}
|
||||
|
||||
$('<input id="node-input-disabled" type="checkbox">').prop("checked",workspace.disabled).appendTo(trayFooterLeft).toggleButton({
|
||||
enabledIcon: "fa-circle-thin",
|
||||
disabledIcon: "fa-ban",
|
||||
invertState: true
|
||||
})
|
||||
|
||||
|
||||
var row = $('<div class="form-row node-text-editor-row">'+
|
||||
'<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+
|
||||
'<div style="min-height:250px;" class="node-text-editor" id="node-input-info"></div>'+
|
||||
'</div>').appendTo(dialogForm);
|
||||
tabflowEditor = RED.editor.createEditor({
|
||||
id: 'node-input-info',
|
||||
mode: 'ace/mode/markdown',
|
||||
value: ""
|
||||
});
|
||||
|
||||
$('#node-info-input-info-expand').on("click", function(e) {
|
||||
e.preventDefault();
|
||||
var value = tabflowEditor.getValue();
|
||||
RED.editor.editMarkdown({
|
||||
value: value,
|
||||
width: "Infinity",
|
||||
cursor: tabflowEditor.getCursorPosition(),
|
||||
complete: function(v,cursor) {
|
||||
tabflowEditor.setValue(v, -1);
|
||||
tabflowEditor.gotoLine(cursor.row+1,cursor.column,false);
|
||||
setTimeout(function() {
|
||||
tabflowEditor.focus();
|
||||
},300);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
|
||||
dialogForm.on("submit", function(e) { e.preventDefault();});
|
||||
$("#node-input-name").val(workspace.label);
|
||||
RED.text.bidi.prepareInput($("#node-input-name"));
|
||||
tabflowEditor.getSession().setValue(workspace.info || "", -1);
|
||||
dialogForm.i18n();
|
||||
},
|
||||
close: function() {
|
||||
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
|
||||
RED.view.state(RED.state.DEFAULT);
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
|
||||
RED.sidebar.info.refresh(workspace);
|
||||
}
|
||||
tabflowEditor.destroy();
|
||||
}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
|
||||
|
||||
@@ -249,11 +133,18 @@ RED.workspaces = (function() {
|
||||
var event = {
|
||||
old: activeWorkspace
|
||||
}
|
||||
activeWorkspace = tab.id;
|
||||
if (tab) {
|
||||
$("#red-ui-workspace-chart").show();
|
||||
activeWorkspace = tab.id;
|
||||
window.location.hash = 'flow/'+tab.id;
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!tab.disabled);
|
||||
} else {
|
||||
$("#red-ui-workspace-chart").hide();
|
||||
activeWorkspace = 0;
|
||||
window.location.hash = '';
|
||||
}
|
||||
event.workspace = activeWorkspace;
|
||||
RED.events.emit("workspace:change",event);
|
||||
window.location.hash = 'flow/'+tab.id;
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!tab.disabled);
|
||||
RED.sidebar.config.refresh();
|
||||
RED.view.focus();
|
||||
},
|
||||
@@ -278,7 +169,7 @@ RED.workspaces = (function() {
|
||||
if (tab.disabled) {
|
||||
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-disabled');
|
||||
}
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
|
||||
if (workspaceTabCount === 1) {
|
||||
showWorkspace();
|
||||
}
|
||||
@@ -286,14 +177,23 @@ RED.workspaces = (function() {
|
||||
onremove: function(tab) {
|
||||
if (tab.type === "tab") {
|
||||
workspaceTabCount--;
|
||||
} else {
|
||||
hideStack.push(tab.id);
|
||||
}
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
|
||||
if (workspaceTabCount === 0) {
|
||||
hideWorkspace();
|
||||
}
|
||||
},
|
||||
onreorder: function(oldOrder, newOrder) {
|
||||
RED.history.push({t:'reorder',order:oldOrder,dirty:RED.nodes.dirty()});
|
||||
RED.history.push({
|
||||
t:'reorder',
|
||||
workspaces: {
|
||||
from:oldOrder,
|
||||
to:newOrder
|
||||
},
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
setWorkspaceOrder(newOrder);
|
||||
},
|
||||
@@ -312,12 +212,86 @@ RED.workspaces = (function() {
|
||||
$(".red-ui-sidebar-shade").show();
|
||||
}
|
||||
},
|
||||
onhide: function(tab) {
|
||||
hideStack.push(tab.id);
|
||||
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
hiddenTabs[tab.id] = true;
|
||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||
|
||||
RED.events.emit("workspace:hide",{workspace: tab.id})
|
||||
},
|
||||
onshow: function(tab) {
|
||||
removeFromHideStack(tab.id);
|
||||
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
delete hiddenTabs[tab.id];
|
||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||
|
||||
RED.events.emit("workspace:show",{workspace: tab.id})
|
||||
},
|
||||
minimumActiveTabWidth: 150,
|
||||
scrollable: true,
|
||||
addButton: "core:add-flow",
|
||||
addButtonCaption: RED._("workspace.addFlow"),
|
||||
searchButton: "core:list-flows",
|
||||
searchButtonCaption: RED._("workspace.listFlows")
|
||||
menu: function() {
|
||||
var menuItems = [
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-flows",
|
||||
label: RED._("workspace.listFlows"),
|
||||
onselect: "core:list-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-subflows",
|
||||
label: RED._("workspace.listSubflows"),
|
||||
onselect: "core:list-subflows"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
onselect: "core:add-flow-to-right"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-flows",
|
||||
label: RED._("workspace.hideFlow"),
|
||||
onselect: "core:hide-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-other-flows",
|
||||
label: RED._("workspace.hideOtherFlows"),
|
||||
onselect: "core:hide-other-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-show-all-flows",
|
||||
label: RED._("workspace.showAllFlows"),
|
||||
onselect: "core:show-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-all-flows",
|
||||
label: RED._("workspace.hideAllFlows"),
|
||||
onselect: "core:hide-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-show-last-flow",
|
||||
label: RED._("workspace.showLastHiddenFlow"),
|
||||
onselect: "core:show-last-hidden-flow"
|
||||
}
|
||||
]
|
||||
if (hideStack.length > 0) {
|
||||
menuItems.unshift({
|
||||
label: RED._("workspace.hiddenFlows",{count: hideStack.length}),
|
||||
onselect: "core:list-hidden-flows"
|
||||
})
|
||||
}
|
||||
return menuItems;
|
||||
}
|
||||
});
|
||||
workspaceTabCount = 0;
|
||||
}
|
||||
@@ -368,15 +342,107 @@ RED.workspaces = (function() {
|
||||
});
|
||||
|
||||
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
|
||||
RED.actions.add("core:add-flow-to-right",function(opts) { addWorkspace(undefined,undefined,workspace_tabs.activeIndex()+1)});
|
||||
RED.actions.add("core:edit-flow",editWorkspace);
|
||||
RED.actions.add("core:remove-flow",removeWorkspace);
|
||||
RED.actions.add("core:enable-flow",enableWorkspace);
|
||||
RED.actions.add("core:disable-flow",disableWorkspace);
|
||||
|
||||
RED.actions.add("core:hide-flow", function() {
|
||||
var selection = workspace_tabs.selection();
|
||||
if (selection.length === 0) {
|
||||
selection = [{id:activeWorkspace}]
|
||||
}
|
||||
var hiddenTabs = [];
|
||||
selection.forEach(function(ws) {
|
||||
RED.workspaces.hide(ws.id);
|
||||
hideStack.pop();
|
||||
hiddenTabs.push(ws.id);
|
||||
})
|
||||
if (hiddenTabs.length > 0) {
|
||||
hideStack.push(hiddenTabs);
|
||||
}
|
||||
workspace_tabs.clearSelection();
|
||||
})
|
||||
|
||||
RED.actions.add("core:hide-other-flows", function() {
|
||||
var selection = workspace_tabs.selection();
|
||||
if (selection.length === 0) {
|
||||
selection = [{id:activeWorkspace}]
|
||||
}
|
||||
var selected = new Set(selection.map(function(ws) { return ws.id }))
|
||||
|
||||
var currentTabs = workspace_tabs.listTabs();
|
||||
var hiddenTabs = [];
|
||||
currentTabs.forEach(function(id) {
|
||||
if (!selected.has(id)) {
|
||||
RED.workspaces.hide(id);
|
||||
hideStack.pop();
|
||||
hiddenTabs.push(id);
|
||||
}
|
||||
})
|
||||
if (hiddenTabs.length > 0) {
|
||||
hideStack.push(hiddenTabs);
|
||||
}
|
||||
})
|
||||
|
||||
RED.actions.add("core:hide-all-flows", function() {
|
||||
var currentTabs = workspace_tabs.listTabs();
|
||||
currentTabs.forEach(function(id) {
|
||||
RED.workspaces.hide(id);
|
||||
hideStack.pop();
|
||||
})
|
||||
if (currentTabs.length > 0) {
|
||||
hideStack.push(currentTabs);
|
||||
}
|
||||
workspace_tabs.clearSelection();
|
||||
})
|
||||
RED.actions.add("core:show-all-flows", function() {
|
||||
var currentTabs = workspace_tabs.listTabs();
|
||||
currentTabs.forEach(function(id) {
|
||||
RED.workspaces.show(id, null, true)
|
||||
})
|
||||
})
|
||||
// RED.actions.add("core:toggle-flows", function() {
|
||||
// var currentTabs = workspace_tabs.listTabs();
|
||||
// var visibleCount = workspace_tabs.count();
|
||||
// currentTabs.forEach(function(id) {
|
||||
// if (visibleCount === 0) {
|
||||
// RED.workspaces.show(id)
|
||||
// } else {
|
||||
// RED.workspaces.hide(id)
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
RED.actions.add("core:show-last-hidden-flow", function() {
|
||||
var id = hideStack.pop();
|
||||
if (id) {
|
||||
if (typeof id === 'string') {
|
||||
RED.workspaces.show(id);
|
||||
} else {
|
||||
var last = id.pop();
|
||||
id.forEach(function(i) {
|
||||
RED.workspaces.show(i, null, true);
|
||||
})
|
||||
setTimeout(function() {
|
||||
RED.workspaces.show(last);
|
||||
},150)
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
RED.actions.add("core:list-modified-nodes",function() {
|
||||
RED.actions.invoke("core:search","is:modified ");
|
||||
})
|
||||
RED.actions.add("core:list-hidden-flows",function() {
|
||||
RED.actions.invoke("core:search","is:hidden ");
|
||||
})
|
||||
RED.actions.add("core:list-flows",function() {
|
||||
RED.actions.invoke("core:search","type:tab ");
|
||||
})
|
||||
|
||||
RED.actions.add("core:list-subflows",function() {
|
||||
RED.actions.invoke("core:search","type:subflow ");
|
||||
})
|
||||
RED.actions.add("core:go-to-previous-location", function() {
|
||||
if (viewStackPos > 0) {
|
||||
if (viewStackPos === viewStack.length) {
|
||||
@@ -392,8 +458,6 @@ RED.workspaces = (function() {
|
||||
RED.workspaces.show(viewStack[++viewStackPos],true);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
hideWorkspace();
|
||||
}
|
||||
|
||||
@@ -416,7 +480,7 @@ RED.workspaces = (function() {
|
||||
var changes = { disabled: workspace.disabled };
|
||||
workspace.disabled = disabled;
|
||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
|
||||
if (id === activeWorkspace) {
|
||||
if (!id || (id === activeWorkspace)) {
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
|
||||
}
|
||||
var historyEvent = {
|
||||
@@ -445,7 +509,6 @@ RED.workspaces = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function removeWorkspace(ws) {
|
||||
if (!ws) {
|
||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||
@@ -471,10 +534,38 @@ RED.workspaces = (function() {
|
||||
workspace_tabs.order(order);
|
||||
}
|
||||
|
||||
function flashTab(tabId) {
|
||||
if(flashingTab && flashingTab.length) {
|
||||
//cancel current flashing node before flashing new node
|
||||
clearInterval(flashingTabTimer);
|
||||
flashingTabTimer = null;
|
||||
flashingTab.removeClass('highlighted');
|
||||
flashingTab = null;
|
||||
}
|
||||
let tab = $("#red-ui-tab-" + tabId);
|
||||
if(!tab || !tab.length) { return; }
|
||||
|
||||
flashingTabTimer = setInterval(function(flashEndTime) {
|
||||
if (flashEndTime >= Date.now()) {
|
||||
const highlighted = tab.hasClass("highlighted");
|
||||
tab.toggleClass('highlighted', !highlighted)
|
||||
} else {
|
||||
clearInterval(flashingTabTimer);
|
||||
flashingTabTimer = null;
|
||||
flashingTab = null;
|
||||
tab.removeClass('highlighted');
|
||||
}
|
||||
}, 100, Date.now() + 2200);
|
||||
flashingTab = tab;
|
||||
tab.addClass('highlighted');
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
add: addWorkspace,
|
||||
// remove: remove workspace without editor history etc
|
||||
remove: removeWorkspace,
|
||||
// delete: remove workspace and update editor history
|
||||
delete: deleteWorkspace,
|
||||
order: setWorkspaceOrder,
|
||||
edit: editWorkspace,
|
||||
contains: function(id) {
|
||||
@@ -489,7 +580,18 @@ RED.workspaces = (function() {
|
||||
selection: function() {
|
||||
return workspace_tabs.selection();
|
||||
},
|
||||
show: function(id,skipStack) {
|
||||
hide: function(id) {
|
||||
if (!id) {
|
||||
id = activeWorkspace;
|
||||
}
|
||||
if (workspace_tabs.contains(id)) {
|
||||
workspace_tabs.hideTab(id);
|
||||
}
|
||||
},
|
||||
isHidden: function(id) {
|
||||
return hideStack.includes(id)
|
||||
},
|
||||
show: function(id,skipStack,unhideOnly,flash) {
|
||||
if (!workspace_tabs.contains(id)) {
|
||||
var sf = RED.nodes.subflow(id);
|
||||
if (sf) {
|
||||
@@ -498,19 +600,27 @@ RED.workspaces = (function() {
|
||||
null,
|
||||
workspace_tabs.activeIndex()+1
|
||||
);
|
||||
removeFromHideStack(id);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!skipStack && activeWorkspace !== id) {
|
||||
addToViewStack(activeWorkspace)
|
||||
if (unhideOnly) {
|
||||
workspace_tabs.showTab(id);
|
||||
} else {
|
||||
if (!skipStack && activeWorkspace !== id) {
|
||||
addToViewStack(activeWorkspace)
|
||||
}
|
||||
workspace_tabs.activateTab(id);
|
||||
}
|
||||
if(flash) {
|
||||
flashTab(id.replace(".","-"))
|
||||
}
|
||||
workspace_tabs.activateTab(id);
|
||||
},
|
||||
refresh: function() {
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
workspace_tabs.renameTab(ws.id,ws.label);
|
||||
|
||||
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
|
||||
})
|
||||
RED.nodes.eachSubflow(function(sf) {
|
||||
if (workspace_tabs.contains(sf.id)) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user