mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
439 Commits
2.0.1
...
link-effec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1a706f811 | ||
|
|
c27dd336d9 | ||
|
|
5e9ff98c49 | ||
|
|
50cb074172 | ||
|
|
510a09ecba | ||
|
|
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 | ||
|
|
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 | ||
|
|
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 |
245
CHANGELOG.md
245
CHANGELOG.md
@@ -1,3 +1,248 @@
|
||||
#### 2.2.0-beta.1: Beta Release
|
||||
|
||||
|
||||
|
||||
#### 2.1.4: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- fix env var access using $parent for groups (#3278) @HiroyasuNishiyama
|
||||
- Add proper error handling for 404 errors when serving debug files (#3277) @knolleary
|
||||
- Add Japanese translations for Node-RED v2.1.0-beta.1 (#3179) @kazuhitoyokoi
|
||||
- Include full user object on login audit events (#3269) @knolleary
|
||||
- Remove styling from de locale files (#3237) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Change tab hide button icon to an eye and add search option (#3282) @knolleary
|
||||
- Fix i18n handling of namespaces with spaces in (#3281) @knolleary
|
||||
- Trigger change event when autoComplete fills in input (#3280) @knolleary
|
||||
- Apply CN i18n fix (#3279) @knolleary
|
||||
- fix select menu label of config node to use paletteLabel (#3273) @HiroyasuNishiyama
|
||||
- fix removed tab not to cause node conflict (#3275) @HiroyasuNishiyama
|
||||
- Group diff fix (#3239) @knolleary
|
||||
- Only toggle disabled workspace flag if on activeWorkspace (#3252) @knolleary
|
||||
- Do not show status for disabled nodes (#3253) @knolleary
|
||||
- Set dimension value for tour guide (#3265) @kazuhitoyokoi
|
||||
- Avoid redundant initialisation of TypedInput type (#3263) @knolleary
|
||||
- Don't let themes change flow port label color (#3270) @bonanitech
|
||||
- Fix treeList gutter calculation to handle floating gutters (#3238) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Debug: Handle RegExp types in Debug sidebar (#3251) @knolleary
|
||||
- Delay: fix 2nd output when in rate limit per topic modes (#3261) @dceejay
|
||||
- Link: fix to show link target when selected (#3267) @HiroyasuNishiyama
|
||||
- Inject: Do not modify inject node props in oneditprepare (#3242) @knolleary
|
||||
- HTTP Request: HTTP Basic Auth should always add : between username and password even if empty (#3236) @hardillb
|
||||
|
||||
#### 2.1.3: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Update gen-publish script to update 'next' tag for main releases
|
||||
- Add environment variable to enable/disable tours (#3221) @hardillb
|
||||
- Fix loading non-default language files leaving runtime in wrong locale (#3225) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Refresh editor settings whenever a node is added or enabled (#3227) @knolleary
|
||||
- Revert spinner css change that made it shrink in some cases (#3229) @knolleary
|
||||
- Fix import notification message when importing config nodes (#3224) @knolleary
|
||||
- Handle changing types of TypedInput repeatedly (#3223) @knolleary
|
||||
|
||||
|
||||
#### 2.1.2: Maintenance Release
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- node-red-pi: Remove bash dependency (#3216) @a16bitsysop
|
||||
|
||||
Editor
|
||||
|
||||
- Improved regex for markdown renderer (#3213) @GerwinvBeek
|
||||
- Fix TypedInput initialisation (#3220) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- MQTT: fix datatype in node config not used. fixes #3215 (#3219) @Steve-Mcl
|
||||
|
||||
#### 2.1.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Ensure tourGuide popover doesn't fall offscreen (#3212) @knolleary
|
||||
- Fix issue with old inject nodes that migrated topic to 'string' type (#3210) @knolleary
|
||||
- Add cache-busting query params to index.mst (#3211) @knolleary
|
||||
- Fix TypedInput validation of type without options (#3207) @knolleary
|
||||
|
||||
#### 2.1.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Position popover properly on a scrolled page
|
||||
- Fixes from 2.1.0-beta.2 (#3202) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Link Out: Fix saving link out node links (#3201) @knolleary
|
||||
- Switch: Refix #3170 - copy switch rule type when adding new rule
|
||||
- TCP Request: Add string option to TCP request node output (#3204) @dceejay
|
||||
|
||||
#### 2.1.0-beta.2: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix switching projects (#3199) @knolleary
|
||||
- Use locale setting when installing/enabling node (#3198) @knolleary
|
||||
- Do not show projects-wecome dialog until welcome tour completes (#3197) @knolleary
|
||||
- Fix converting selection to subflow (#3196) @knolleary
|
||||
- Avoid conflicts with native browser cmd-ctrl type shortcuts (#3195) @knolleary
|
||||
- Ensure message tools stay attached to top-level entry in Debug/Context (#3186) @knolleary
|
||||
- Ensure tab state updates properly when toggling enable state (#3175) @knolleary
|
||||
- Improve handling of long labels in TreeList (#3176) @knolleary
|
||||
- Shift-click tab scroll arrows to jump to start/end (#3177) @knolleary
|
||||
|
||||
Runtime
|
||||
|
||||
- Update package dependencies
|
||||
- Update to latest node-red-admin
|
||||
|
||||
Nodes
|
||||
|
||||
- Dynamic MQTT connections (#3189)
|
||||
- Link: Filter out Link Out Return nodes in Link In edit dialog Fixes #3187
|
||||
- Link: Fix link call label (#3200) @knolleary
|
||||
- Debug: Redesign debug filter options and make them persistant (#3183) @knolleary
|
||||
- Inject: Widen Inject interval box for >1 digit (#3184) @knolleary
|
||||
- Switch: Fix rule focus when switch 'otherwise' rule is used (#3185) @knolleary
|
||||
|
||||
#### 2.1.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add Tour Guide component (#3136) @knolleary
|
||||
- Allow tabs to be hidden (#3120) @knolleary
|
||||
- Add align actions to editor (#3110) @knolleary
|
||||
- Add support of environment variable for tab & group (#3112) @HiroyasuNishiyama
|
||||
- Add autoComplete widget and add to TypedInput for msg. props (#3171) @knolleary
|
||||
- Render node documentation to node-red style guide when written in markdown. (#3169) @Steve-Mcl
|
||||
- Allow colouring of tab icon svg (#3140) @harmonic7
|
||||
- Restore tab selection after merging conflicts (#3151) @GerwinvBeek
|
||||
- Fix serving of theme files on Windows (#3154) @knolleary
|
||||
- Ensure config-node select inherits width properly from input (#3155) @knolleary
|
||||
- Do better remembering TypedInput values whilst switching types (#3159) @knolleary
|
||||
- Update monaco to 0.28.1 (#3153) @knolleary
|
||||
- Improve themeing of tourGuide (#3161) @knolleary
|
||||
- Allow a node to specify a filter for the config nodes it can pick from (#3160) @knolleary
|
||||
- Allow RED.notify.update to modify any notification setting (#3163) @knolleary
|
||||
- Fix typo in ko editor.json Fixes #3119
|
||||
- Improve RED.actions api to ensure actions cannot be overridden
|
||||
- Ensure treeList row has suitable min-height when no content Fixes #3109
|
||||
- Refactor edit dialogs to use separate edit panes
|
||||
- Ensure type select button is not focussable when TypedInput only has one type
|
||||
- Place close tab link in front of fade
|
||||
|
||||
Runtime
|
||||
|
||||
- Improve error reporting with oauth login strategies (#3148) @knolleary
|
||||
- Add allowUpdate feature to externalModules.palette (#3143) @knolleary
|
||||
- Improve node install error reporting (#3158) @knolleary
|
||||
- Improve unit test coverage (#3168) @knolleary
|
||||
- Allow coreNodesDir to be set to false (#3149) @hardillb
|
||||
- Update package dependencies
|
||||
- uncaughtException debug improvements (#3146) @renatojuniorrs
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Add option to deep-clone properties in Change node (#3156) @knolleary
|
||||
- Delay: Add push to front of rate limit queue. (#3069) @dceejay
|
||||
- File: Add paletteLabel to file nodes to make read/write more obvious (#3157) @knolleary
|
||||
- HTTP Request: Extend HTTP request node to log detailed timing information (#3116) @k-toumura
|
||||
- HTTP Response: Fix sizing of HTTP Response header fields (#3164) @knolleary
|
||||
- Join: Support for msg.restartTimeout (#3121) @magma1447
|
||||
- Link Call: Add Link Call node (#3152) @knolleary
|
||||
- Switch: Copy previous rule type when adding rule to switch node (#3170) @knolleary
|
||||
- Delay node: add option to send intermediate messages on separate output (#3166) @knolleary
|
||||
- Typo in http request set method translation (#3173) @mailsvb
|
||||
|
||||
#### 2.0.6: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix typo in ko editor.json Fixes #3119
|
||||
- Change fade color when hovering an inactive tab (#3106) @bonanitech
|
||||
- Ensure treeList row has suitable min-height when no content Fixes #3109
|
||||
|
||||
Runtime
|
||||
|
||||
- Update tar to latest (#3128) @aksswami
|
||||
- Give passport verify callback the same arity as the original callback (#3117) @dschmidt
|
||||
- Handle HTTPS Key and certificate as string or buffer (#3115) @bartbutenaers
|
||||
|
||||
#### 2.0.5: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Remove default ctrl-enter keybinding from monaco editor Fixes #3093
|
||||
|
||||
Runtime
|
||||
|
||||
- Update tar dependency
|
||||
- Add support for maintenance streams in generate-publish-script
|
||||
|
||||
|
||||
Nodes
|
||||
|
||||
- Fix regression in Join node when manual joining array with msg.parts present Fixes #3096
|
||||
|
||||
#### 2.0.4: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix tab fade CSS for when using themes (#3085) @bonanitech
|
||||
- Handle just-copied-but-not-deployed node with credentials in editor Fixes #3090
|
||||
|
||||
Nodes
|
||||
|
||||
- Filter: Fix RBE node handling of default topi property Fixes #3087
|
||||
- HTTP Request: Handle partially encoded url query strings in request node
|
||||
- HTTP Request: Fix support for supplied CA certs (#3089) @hardillb
|
||||
- HTTP Request: Ensure TLS Cert is used (#3092) @hardillb
|
||||
- Inject: Fix inject now button unable to send empty props
|
||||
- Inject: Inject now button success notification should use label with updated props
|
||||
|
||||
#### 2.0.3: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- HTML: Fix HTML parsing when body is included in the select tag Fixes #3079
|
||||
- HTTP Request: Preserve case of user-provided http headers in request node Fixes #3081
|
||||
- HTTP Request: Set decompress to false for HTTP Request to keep 1.x compatibility Fixes #3083
|
||||
- HTTP Request: Add unit tests for HTTP Request encodeURI and error response
|
||||
- HTTP Request: Do not throw HTTP errors in request node Fixes #3082
|
||||
- HTTP Request: Ensure uri is properly encoded before passing to got module Fixes #3080
|
||||
|
||||
#### 2.0.2: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Use file:// url with dynamic import
|
||||
- Detect if agent-base has patched https.request and undo it Fixes #3072
|
||||
|
||||
Editor
|
||||
|
||||
- Fix tab fade css because Safari Fixes #3073
|
||||
- Fix error closing library dialog with monaco
|
||||
- Handle other error types in Manage Palette view
|
||||
|
||||
|
||||
Nodes
|
||||
|
||||
- HTTP Request node - ignore invalid cookies rather than fail request Fixes #3075
|
||||
- Fix msg.reset handling in Delay node Fixes #3074
|
||||
|
||||
#### 2.0.1: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
20
Gruntfile.js
20
Gruntfile.js
@@ -162,7 +162,7 @@ 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/diff.js",
|
||||
@@ -182,6 +182,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",
|
||||
@@ -199,7 +200,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 +328,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 +431,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 +583,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"+
|
||||
|
||||
56
package.json
56
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "2.0.1",
|
||||
"version": "2.2.0-beta.1",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -26,10 +26,10 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"acorn": "8.4.1",
|
||||
"acorn-walk": "8.1.1",
|
||||
"ajv": "8.6.0",
|
||||
"async-mutex": "0.3.1",
|
||||
"acorn": "8.6.0",
|
||||
"acorn-walk": "8.2.0",
|
||||
"ajv": "8.8.2",
|
||||
"async-mutex": "0.3.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
@@ -37,45 +37,45 @@
|
||||
"clone": "2.1.2",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.1",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
"denque": "1.5.0",
|
||||
"denque": "2.0.1",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.2",
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"got": "11.8.2",
|
||||
"got": "11.8.3",
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "^0.1.2",
|
||||
"hpagent": "0.1.2",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"i18next": "20.3.2",
|
||||
"i18next": "21.5.4",
|
||||
"iconv-lite": "0.6.3",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.1",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.4",
|
||||
"jsonata": "1.8.5",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.6",
|
||||
"mime": "2.5.2",
|
||||
"moment-timezone": "0.5.33",
|
||||
"moment-timezone": "0.5.34",
|
||||
"mqtt": "4.2.8",
|
||||
"multer": "1.4.2",
|
||||
"multer": "1.4.3",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^2.2.0",
|
||||
"node-red-admin": "^2.2.1",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.4.1",
|
||||
"passport": "0.5.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.4.1",
|
||||
"raw-body": "2.4.2",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.0",
|
||||
"tar": "6.1.11",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uglify-js": "3.13.10",
|
||||
"uglify-js": "3.14.4",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.1",
|
||||
"xml2js": "0.4.23"
|
||||
@@ -84,7 +84,7 @@
|
||||
"bcrypt": "5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dompurify": "2.2.9",
|
||||
"dompurify": "2.3.3",
|
||||
"grunt": "1.4.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.4.3",
|
||||
@@ -93,7 +93,7 @@
|
||||
"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-jshint": "3.1.1",
|
||||
"grunt-contrib-uglify": "5.0.1",
|
||||
"grunt-contrib-watch": "~1.1.0",
|
||||
"grunt-jsdoc": "2.4.1",
|
||||
@@ -104,20 +104,20 @@
|
||||
"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.3.1",
|
||||
"jquery-i18next": "1.2.1",
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "2.1.3",
|
||||
"marked": "3.0.7",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "9.0.1",
|
||||
"mocha": "9.1.3",
|
||||
"node-red-node-test-helper": "^0.2.7",
|
||||
"nodemon": "2.0.8",
|
||||
"nodemon": "2.0.15",
|
||||
"proxy": "^1.0.2",
|
||||
"sass": "1.35.1",
|
||||
"sass": "1.44.0",
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.1",
|
||||
"sinon": "11.1.2",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "6.1.3"
|
||||
"supertest": "6.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
|
||||
@@ -141,7 +141,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 +173,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(null,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 +212,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 +228,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,
|
||||
|
||||
@@ -93,7 +93,7 @@ var passwordTokenExchange = function(client, username, password, scope, done) {
|
||||
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});
|
||||
log.audit({event: "auth.login",user,username:username,client:client.id,scope:scope});
|
||||
done(null,tokens.accessToken,null,{expires_in:tokens.expires_in});
|
||||
});
|
||||
} else {
|
||||
@@ -146,7 +146,7 @@ function authenticateUserToken(req) {
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}).catch(reject);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
@@ -163,6 +163,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.0.1",
|
||||
"@node-red/editor-client": "2.0.1",
|
||||
"@node-red/util": "2.2.0-beta.1",
|
||||
"@node-red/editor-client": "2.2.0-beta.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
"clone": "2.1.2",
|
||||
@@ -26,12 +26,12 @@
|
||||
"express": "4.17.1",
|
||||
"memorystore": "1.6.6",
|
||||
"mime": "2.5.2",
|
||||
"multer": "1.4.2",
|
||||
"multer": "1.4.3",
|
||||
"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",
|
||||
"passport": "0.5.0",
|
||||
"ws": "7.5.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
||||
@@ -53,8 +53,17 @@
|
||||
"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",
|
||||
@@ -83,6 +92,7 @@
|
||||
"palette": {
|
||||
"show": "Show palette"
|
||||
},
|
||||
"edit": "Edit",
|
||||
"settings": "Settings",
|
||||
"userSettings": "User Settings",
|
||||
"nodes": "Nodes",
|
||||
@@ -105,6 +115,7 @@
|
||||
"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,7 +127,20 @@
|
||||
"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": {
|
||||
@@ -450,8 +474,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,7 +489,10 @@
|
||||
"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"
|
||||
@@ -519,7 +547,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",
|
||||
@@ -642,7 +671,8 @@
|
||||
"unusedConfigNodes": "Unused configuration nodes",
|
||||
"invalidNodes": "Invalid nodes",
|
||||
"uknownNodes": "Unknown nodes",
|
||||
"unusedSubflows": "Unused subflows"
|
||||
"unusedSubflows": "Unused subflows",
|
||||
"hiddenFlows": "Hidden flows"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@@ -864,6 +894,8 @@
|
||||
"addTitle": "add an item"
|
||||
},
|
||||
"search": {
|
||||
"history": "Search history",
|
||||
"clear": "clear all",
|
||||
"empty": "No matches found",
|
||||
"addNode": "add a node..."
|
||||
},
|
||||
@@ -1108,6 +1140,11 @@
|
||||
"preview": "UI Preview",
|
||||
"defaultValue": "Default value"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "Take a tour",
|
||||
"start": "Start",
|
||||
"next": "Next"
|
||||
},
|
||||
"languages" : {
|
||||
"de": "German",
|
||||
"en-US": "English",
|
||||
|
||||
@@ -54,7 +54,16 @@
|
||||
"delete": "本当に '__label__' を削除しますか?",
|
||||
"dropFlowHere": "ここにフローをドロップしてください",
|
||||
"addFlow": "フローの追加",
|
||||
"addFlowToRight": "右側にフローを追加",
|
||||
"hideFlow": "フローを非表示",
|
||||
"hideOtherFlows": "他のフローを非表示",
|
||||
"showAllFlows": "全てのフローを表示",
|
||||
"hideAllFlows": "全てのフローを非表示",
|
||||
"hiddenFlows": "__count__ 個の非表示のフロー一覧",
|
||||
"hiddenFlows_plural": "__count__ 個の非表示のフロー一覧",
|
||||
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
|
||||
"listFlows": "フロー一覧",
|
||||
"listSubflows": "サブフロー一覧",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
@@ -83,6 +92,7 @@
|
||||
"palette": {
|
||||
"show": "パレットを表示"
|
||||
},
|
||||
"edit": "編集",
|
||||
"settings": "設定",
|
||||
"userSettings": "ユーザ設定",
|
||||
"nodes": "ノード",
|
||||
@@ -105,6 +115,7 @@
|
||||
"editPalette": "パレットの管理",
|
||||
"other": "その他",
|
||||
"showTips": "ヒントを表示",
|
||||
"showWelcomeTours": "新バージョンのガイドツアーを表示",
|
||||
"help": "Node-REDウェブサイト",
|
||||
"projects": "プロジェクト",
|
||||
"projects-new": "新規",
|
||||
@@ -116,7 +127,20 @@
|
||||
"groupSelection": "選択部分をグループ化",
|
||||
"ungroupSelection": "選択部分をグループ解除",
|
||||
"groupMergeSelection": "選択部分をマージ",
|
||||
"groupRemoveSelection": "グループから削除"
|
||||
"groupRemoveSelection": "グループから削除",
|
||||
"arrange": "配置",
|
||||
"alignLeft": "左揃え",
|
||||
"alignCenter": "左右中央揃え",
|
||||
"alignRight": "右揃え",
|
||||
"alignTop": "上揃え",
|
||||
"alignMiddle": "上下中央揃え",
|
||||
"alignBottom": "下揃え",
|
||||
"distributeHorizontally": "左右に整列",
|
||||
"distributeVertically": "上下に整列",
|
||||
"moveToBack": "最背面へ移動",
|
||||
"moveToFront": "最前面へ移動",
|
||||
"moveBackwards": "背面へ移動",
|
||||
"moveForwards": "前面へ移動"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
@@ -451,7 +475,8 @@
|
||||
"global": "グローバル",
|
||||
"workspace": "ワークスペース",
|
||||
"selectAll": "全てのノードを選択",
|
||||
"selectAllConnected": "接続された全てのノードを選択",
|
||||
"selectNone": "選択を外す",
|
||||
"selectAllConnected": "接続されたノードを選択",
|
||||
"addRemoveNode": "ノードの選択、選択解除",
|
||||
"editSelected": "選択したノードを編集",
|
||||
"deleteSelected": "選択したノードや接続を削除",
|
||||
@@ -461,10 +486,13 @@
|
||||
"moveNode": "選択したノードを移動(移動量大)",
|
||||
"toggleSidebar": "サイドバーの表示/非表示",
|
||||
"togglePalette": "パレットの表示/非表示",
|
||||
"copyNode": "選択したノードをコピー",
|
||||
"cutNode": "選択したノードを切り取り",
|
||||
"copyNode": "ノードをコピー",
|
||||
"cutNode": "ノードを切り取り",
|
||||
"pasteNode": "ノードを貼り付け",
|
||||
"copyGroupStyle": "グループ様式をコピー",
|
||||
"pasteGroupStyle": "グループ様式を貼り付け",
|
||||
"undoChange": "変更操作を戻す",
|
||||
"redoChange": "変更操作をやり直し",
|
||||
"searchBox": "ノードを検索",
|
||||
"managePalette": "パレットの管理",
|
||||
"actionList": "動作一覧"
|
||||
@@ -519,7 +547,8 @@
|
||||
"nodeEnabled_plural": "ノードを有効化しました:",
|
||||
"nodeDisabled": "ノードを無効化しました:",
|
||||
"nodeDisabled_plural": "ノードを無効化しました:",
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました",
|
||||
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
|
||||
},
|
||||
"editor": {
|
||||
"title": "パレットの管理",
|
||||
@@ -642,7 +671,8 @@
|
||||
"unusedConfigNodes": "未使用の設定ノード",
|
||||
"invalidNodes": "不正なノード",
|
||||
"uknownNodes": "未知のノード",
|
||||
"unusedSubflows": "未使用のサブフロー"
|
||||
"unusedSubflows": "未使用のサブフロー",
|
||||
"hiddenFlows": "非表示のフロー"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@@ -1108,6 +1138,11 @@
|
||||
"preview": "UIプレビュー",
|
||||
"defaultValue": "デフォルト値"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "ツアーを開始",
|
||||
"start": "開始",
|
||||
"next": "次へ"
|
||||
},
|
||||
"languages": {
|
||||
"de": "ドイツ語",
|
||||
"en-US": "英語",
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"displayConfig": "설정노드 보기",
|
||||
"import": "가져오기",
|
||||
"export": "내보내기",
|
||||
"search": "플로우 겅색",
|
||||
"search": "플로우 검색",
|
||||
"searchInput": "플로우 검색",
|
||||
"subflows": "보조 플로우",
|
||||
"createSubflow": "보조 플로우 생성",
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
"compact": "紧凑",
|
||||
"formatted": "已格式化",
|
||||
"copy": "导出到剪贴板",
|
||||
"export": "到处到库",
|
||||
"export": "导出到库",
|
||||
"exportAs": "导出为",
|
||||
"overwrite": "替换",
|
||||
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "2.0.1",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,5 +14,5 @@
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"main": "./lib/index.js"
|
||||
"main": "./index.js"
|
||||
}
|
||||
|
||||
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 |
@@ -558,11 +558,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 +669,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 +678,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 +705,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,15 @@
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
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,9 @@ var RED = (function() {
|
||||
if (/^#flow\/.+$/.test(currentHash)) {
|
||||
RED.workspaces.show(currentHash.substring(6),true);
|
||||
}
|
||||
if (RED.workspaces.active() === 0 && RED.workspaces.count() > 0) {
|
||||
RED.workspaces.show(RED.nodes.getWorkspaceOrder()[0])
|
||||
}
|
||||
} catch(err) {
|
||||
console.warn(err);
|
||||
RED.notify(
|
||||
@@ -267,7 +271,7 @@ var RED = (function() {
|
||||
});
|
||||
}
|
||||
|
||||
function completeLoad() {
|
||||
function completeLoad(showProjectWelcome) {
|
||||
var persistentNotifications = {};
|
||||
RED.comms.subscribe("notification/#",function(topic,msg) {
|
||||
var parts = topic.split("/");
|
||||
@@ -471,22 +475,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 +514,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) {
|
||||
@@ -535,19 +561,24 @@ var RED = (function() {
|
||||
|
||||
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 +590,22 @@ 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"}
|
||||
]});
|
||||
|
||||
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 +613,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 +692,6 @@ var RED = (function() {
|
||||
RED.user.init();
|
||||
RED.notifications.init();
|
||||
RED.library.init();
|
||||
RED.keyboard.init();
|
||||
RED.palette.init();
|
||||
RED.eventLog.init();
|
||||
|
||||
@@ -655,16 +720,13 @@ var RED = (function() {
|
||||
|
||||
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
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -4,6 +4,12 @@ RED.actions = (function() {
|
||||
}
|
||||
|
||||
function addAction(name,handler) {
|
||||
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;
|
||||
}
|
||||
function removeAction(name) {
|
||||
@@ -12,9 +18,11 @@ RED.actions = (function() {
|
||||
function getAction(name) {
|
||||
return actions[name];
|
||||
}
|
||||
function invokeAction(name,args) {
|
||||
function invokeAction() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var name = args.shift();
|
||||
if (actions.hasOwnProperty(name)) {
|
||||
actions[name](args);
|
||||
actions[name].apply(null, args);
|
||||
}
|
||||
}
|
||||
function 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: []
|
||||
})
|
||||
@@ -738,16 +747,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") {
|
||||
|
||||
115
packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js
vendored
Normal file
115
packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
(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
|
||||
*
|
||||
* 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() {
|
||||
var that = this;
|
||||
this.completionMenuShown = false;
|
||||
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) {
|
||||
var that = this;
|
||||
if (val.trim() === "") {
|
||||
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) {
|
||||
var 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
@@ -82,12 +82,19 @@ RED.menu = (function() {
|
||||
linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+opt.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>'+opt.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;
|
||||
|
||||
@@ -276,6 +283,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 +307,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) {
|
||||
@@ -236,8 +408,10 @@ RED.popover = (function() {
|
||||
},autoClose);
|
||||
}
|
||||
var res = {
|
||||
get element() { return div },
|
||||
setContent: function(_content) {
|
||||
content = _content;
|
||||
|
||||
return res;
|
||||
},
|
||||
open: function (instant) {
|
||||
@@ -249,6 +423,10 @@ RED.popover = (function() {
|
||||
active = false;
|
||||
closePopup(instant);
|
||||
return res;
|
||||
},
|
||||
move: function(options) {
|
||||
movePopup(options);
|
||||
return
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@@ -258,18 +436,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 +455,14 @@ RED.popover = (function() {
|
||||
content: label,
|
||||
delay: { show: 750, hide: 50 }
|
||||
});
|
||||
popover.setContent = function(newContent) {
|
||||
content = newContent;
|
||||
}
|
||||
popover.setAction = function(newAction) {
|
||||
action = newAction;
|
||||
}
|
||||
return popover;
|
||||
|
||||
},
|
||||
menu: function(options) {
|
||||
var list = $('<ul class="red-ui-menu"></ul>');
|
||||
@@ -286,20 +471,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 +545,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 +569,7 @@ RED.popover = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
menu.options(menuOptions);
|
||||
return menu;
|
||||
},
|
||||
panel: function(content) {
|
||||
@@ -380,12 +598,12 @@ RED.popover = (function() {
|
||||
|
||||
var pos = target.offset();
|
||||
var targetWidth = target.width();
|
||||
var targetHeight = target.height();
|
||||
var targetHeight = 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) {
|
||||
|
||||
@@ -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,24 +544,104 @@ 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--;
|
||||
|
||||
li.one("transitionend", function(evt) {
|
||||
li.remove();
|
||||
if (tabs[id].pinned) {
|
||||
pinnedTabsCount--;
|
||||
}
|
||||
if (options.onremove) {
|
||||
options.onremove(tabs[id]);
|
||||
}
|
||||
delete tabs[id];
|
||||
updateTabWidths();
|
||||
if (collapsibleMenu) {
|
||||
collapsibleMenu.remove();
|
||||
collapsibleMenu = null;
|
||||
}
|
||||
})
|
||||
li.addClass("hide-tab");
|
||||
li.width(0);
|
||||
}
|
||||
|
||||
function findPreviousVisibleTab(li) {
|
||||
if (!li) {
|
||||
li = ul.find("li.active");
|
||||
}
|
||||
if (options.onremove) {
|
||||
options.onremove(tabs[id]);
|
||||
var previous = li.prev();
|
||||
while(previous.length > 0 && previous.hasClass("hide-tab")) {
|
||||
previous = previous.prev();
|
||||
}
|
||||
delete tabs[id];
|
||||
updateTabWidths();
|
||||
if (collapsibleMenu) {
|
||||
collapsibleMenu.remove();
|
||||
collapsibleMenu = null;
|
||||
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})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,6 +801,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 +811,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 +831,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 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 +937,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 +945,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');}));
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
* - 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 +44,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 +53,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 +94,99 @@
|
||||
$.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 (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 +340,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 +489,9 @@
|
||||
container.addClass("expanded");
|
||||
}
|
||||
item.treeList.collapse = function() {
|
||||
if (item.collapsible === false) {
|
||||
return
|
||||
}
|
||||
if (!item.children) {
|
||||
return;
|
||||
}
|
||||
@@ -532,10 +562,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 +613,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 +664,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 +712,7 @@
|
||||
}
|
||||
}
|
||||
selectWrapper.appendTo(label)
|
||||
item.treeList.radio = cb;
|
||||
} else {
|
||||
label.on("click", function(e) {
|
||||
if (!that.options.multi) {
|
||||
@@ -647,10 +720,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 +875,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 +885,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,88 @@
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
var autoComplete = function(options) {
|
||||
return function(val) {
|
||||
var matches = [];
|
||||
options.forEach(opt => {
|
||||
let v = opt.value;
|
||||
var i = v.toLowerCase().indexOf(val.toLowerCase());
|
||||
if (i > -1) {
|
||||
var pre = v.substring(0,i);
|
||||
var matchedVal = v.substring(i,i+val.length);
|
||||
var post = v.substring(i+val.length)
|
||||
|
||||
var el = $('<div/>',{style:"white-space:nowrap; overflow: hidden; flex-grow:1"});
|
||||
$('<span/>').text(pre).appendTo(el);
|
||||
$('<span/>',{style:"font-weight: bold"}).text(matchedVal).appendTo(el);
|
||||
$('<span/>').text(post).appendTo(el);
|
||||
|
||||
var element = $('<div>',{style: "display: flex"});
|
||||
el.appendTo(element);
|
||||
if (opt.source) {
|
||||
$('<div>').css({
|
||||
"font-size": "0.8em"
|
||||
}).text(opt.source.join(",")).appendTo(element);
|
||||
}
|
||||
|
||||
matches.push({
|
||||
value: v,
|
||||
label: element,
|
||||
i:i
|
||||
})
|
||||
}
|
||||
})
|
||||
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: "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: "complete", source: ["join"] },
|
||||
{ value: "contentType", source: ["mqtt"] },
|
||||
{ value: "cookies", source: ["http in","http request"] },
|
||||
{ value: "correlationData", source: ["mqtt"] },
|
||||
{ value: "delay", source: ["delay","trigger"] },
|
||||
{ value: "encoding", source: ["file"] },
|
||||
{ value: "error", source: ["catch"] },
|
||||
{ value: "filename", source: ["file","file in"] },
|
||||
{ value: "flush", source: ["delay"] },
|
||||
{ value: "followRedirects", source: ["http request"] },
|
||||
{ value: "headers", source: ["http in"," http request"] },
|
||||
{ value: "kill", source: ["exec"] },
|
||||
{ value: "messageExpiryInterval", source: ["mqtt"] },
|
||||
{ value: "method", source: ["http-request"] },
|
||||
{ value: "options", source: ["xml"] },
|
||||
{ value: "parts", source: ["split","join"] },
|
||||
{ value: "pid", source: ["exec"] },
|
||||
{ value: "qos", source: ["mqtt"] },
|
||||
{ value: "rate", source: ["delay"] },
|
||||
{ value: "rejectUnauthorized", source: ["http request"] },
|
||||
{ value: "requestTimeout", source: ["http request"] },
|
||||
{ value: "reset", source: ["delay","trigger","join","rbe"] },
|
||||
{ value: "responseTopic", source: ["mqtt"] },
|
||||
{ value: "restartTimeout", source: ["join"] },
|
||||
{ value: "retain", source: ["mqtt"] },
|
||||
{ value: "select", source: ["html"] },
|
||||
{ value: "statusCode", source: ["http in"] },
|
||||
{ value: "template", source: ["template"] },
|
||||
{ value: "toFront", source: ["delay"] },
|
||||
{ value: "topic", source: ["inject","mqtt","rbe"] },
|
||||
{ value: "url", source: ["http request"] },
|
||||
{ value: "userProperties", source: ["mqtt"] }
|
||||
]
|
||||
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,
|
||||
@@ -265,6 +345,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 +419,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 +450,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 +504,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 +534,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 +555,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);
|
||||
}
|
||||
@@ -579,7 +708,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 +805,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 +818,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 +830,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 +853,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 +864,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 +920,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);
|
||||
}
|
||||
@@ -836,22 +1046,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 +1062,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 +1098,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 +1131,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 +1143,13 @@
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
if (this.optionExpandButton) {
|
||||
if (opt.expand) {
|
||||
@@ -1042,6 +1234,9 @@
|
||||
},
|
||||
disabled: function() {
|
||||
return this.uiSelect.attr("disabled") === "disabled";
|
||||
},
|
||||
focus: function() {
|
||||
this.input.focus();
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
@@ -333,6 +333,16 @@ RED.deploy = (function() {
|
||||
var unknownNodes = [];
|
||||
var invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(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);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
|
||||
@@ -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
@@ -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().")
|
||||
@@ -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"); }
|
||||
@@ -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'
|
||||
@@ -742,12 +761,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 +944,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 +999,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
if (cb && typeof cb == "function") {
|
||||
cb();
|
||||
}
|
||||
if(resize) {
|
||||
if(resize) {
|
||||
this.resize(); //cause a call to layout()
|
||||
}
|
||||
}
|
||||
@@ -1158,7 +1190,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) {
|
||||
@@ -1218,7 +1253,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
}
|
||||
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) {
|
||||
@@ -1240,15 +1275,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 {
|
||||
@@ -1267,7 +1302,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
function onVisibilityChange(visible, delay, element) {
|
||||
if(visible) {
|
||||
if(ed._mode == "javascript" && ed._tempMode == "text") {
|
||||
ed._tempMode = "";
|
||||
ed._tempMode = "";
|
||||
setTimeout(function() {
|
||||
if(element.parentElement) { //ensure el is still in DOM
|
||||
ed.setMode('javascript', undefined, false);
|
||||
@@ -1277,7 +1312,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
} 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1353,4 +1388,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
|
||||
}
|
||||
})();
|
||||
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
|
||||
}
|
||||
})();
|
||||
@@ -81,7 +81,8 @@
|
||||
clearTimeout: true,
|
||||
setInterval: true,
|
||||
clearInterval: true
|
||||
}
|
||||
},
|
||||
extraLibs: options.extraLibs
|
||||
});
|
||||
if (options.cursor) {
|
||||
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
||||
|
||||
517
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/appearance.js
vendored
Normal file
517
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/appearance.js
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
;(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) {
|
||||
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!== "";
|
||||
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;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
70
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/description.js
vendored
Normal file
70
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/description.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
;(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);
|
||||
RED.e = this.editor;
|
||||
},
|
||||
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',
|
||||
value: ""
|
||||
});
|
||||
if (node.info) {
|
||||
nodeInfoEditor.getSession().setValue(node.info, -1);
|
||||
}
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
181
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/properties.js
vendored
Normal file
181
packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/properties.js
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
;(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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -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() {
|
||||
@@ -584,12 +590,14 @@ RED.group = (function() {
|
||||
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;
|
||||
|
||||
@@ -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,6 +175,9 @@ RED.keyboard = (function() {
|
||||
setTimeout(function() {
|
||||
$("#red-ui-settings-tab-keyboard-filter").trigger("focus");
|
||||
},200);
|
||||
},
|
||||
close: function() {
|
||||
RED.menu.refreshShortcuts();
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -536,7 +536,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 +820,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({
|
||||
|
||||
@@ -2387,6 +2387,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,6 +22,7 @@ RED.search = (function() {
|
||||
var selected = -1;
|
||||
var visible = false;
|
||||
|
||||
var searchHistory = [];
|
||||
var index = {};
|
||||
var currentResults = [];
|
||||
var previousActiveElement;
|
||||
@@ -105,6 +106,7 @@ RED.search = (function() {
|
||||
val = extractFlag(val,"unused",flags);
|
||||
val = extractFlag(val,"config",flags);
|
||||
val = extractFlag(val,"subflow",flags);
|
||||
val = extractFlag(val,"hidden",flags);
|
||||
// uses:<node-id>
|
||||
val = extractValue(val,"uses",flags);
|
||||
|
||||
@@ -150,7 +152,15 @@ RED.search = (function() {
|
||||
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)
|
||||
@@ -196,6 +206,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,7 +228,12 @@ 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++) {
|
||||
searchResults.editableList('addItem',currentResults[i])
|
||||
@@ -276,7 +305,12 @@ 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);
|
||||
}
|
||||
@@ -292,7 +326,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}));
|
||||
@@ -347,6 +406,12 @@ RED.search = (function() {
|
||||
}
|
||||
|
||||
function reveal(node) {
|
||||
var searchVal = searchInput.val();
|
||||
var existingIndex = searchHistory.indexOf(searchVal);
|
||||
if (existingIndex > -1) {
|
||||
searchHistory.splice(existingIndex,1);
|
||||
}
|
||||
searchHistory.unshift(searchInput.val());
|
||||
hide();
|
||||
RED.view.reveal(node.id);
|
||||
}
|
||||
@@ -365,9 +430,14 @@ 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;
|
||||
}
|
||||
|
||||
@@ -27,5 +27,7 @@ RED.state = {
|
||||
PANNING: 10,
|
||||
SELECTING_NODE: 11,
|
||||
GROUP_DRAGGING: 12,
|
||||
GROUP_RESIZE: 13
|
||||
GROUP_RESIZE: 13,
|
||||
DETACHED_DRAGGING: 14,
|
||||
SLICING: 15
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -909,7 +876,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 +916,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 +929,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 +938,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 +991,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 +1057,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 +1066,6 @@ RED.subflow = (function() {
|
||||
}
|
||||
var row = $("<div/>", { class: "form-row" }).appendTo(uiContainer);
|
||||
buildEnvUIRow(row,tenv, tenv.ui || {}, node);
|
||||
|
||||
// console.log(ui);
|
||||
}
|
||||
}
|
||||
// buildEnvUI
|
||||
@@ -1715,7 +1101,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 +1111,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 +1227,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 +1238,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 +1278,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 +1285,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 +1308,9 @@ RED.subflow = (function() {
|
||||
removeOutput: removeSubflowOutput,
|
||||
removeStatus: removeSubflowStatus,
|
||||
|
||||
|
||||
buildEditForm: buildEditForm,
|
||||
buildPropertiesForm: buildPropertiesForm,
|
||||
buildModuleForm: buildModuleForm,
|
||||
|
||||
exportSubflowTemplateEnv: exportEnvList,
|
||||
exportSubflowInstanceEnv: exportSubflowInstanceEnv,
|
||||
exportSubflowModuleProperties: exportSubflowModuleProperties
|
||||
|
||||
exportSubflowInstanceEnv: exportSubflowInstanceEnv
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -229,7 +229,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) {
|
||||
|
||||
@@ -25,7 +25,6 @@ RED.sidebar.help = (function() {
|
||||
var tocPanel;
|
||||
var helpIndex = {};
|
||||
|
||||
|
||||
function resizeStack() {
|
||||
var h = $(content).parent().height() - toolbar.outerHeight();
|
||||
panels.resize(h)
|
||||
@@ -93,9 +92,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 +192,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(),
|
||||
@@ -218,7 +243,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,
|
||||
@@ -233,7 +258,7 @@ RED.sidebar.help = (function() {
|
||||
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) {
|
||||
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) {
|
||||
@@ -244,7 +269,7 @@ RED.sidebar.help = (function() {
|
||||
return div;
|
||||
}
|
||||
|
||||
function showHelp(nodeType) {
|
||||
function showNodeTypeHelp(nodeType) {
|
||||
helpSection.empty();
|
||||
var helpText;
|
||||
var title;
|
||||
@@ -265,7 +290,7 @@ RED.sidebar.help = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
setInfoText(title, helpText, helpSection);
|
||||
setInfoText(title, helpText);
|
||||
|
||||
var ratio = panels.ratio();
|
||||
if (ratio > 0.7) {
|
||||
@@ -282,7 +307,7 @@ RED.sidebar.help = (function() {
|
||||
}
|
||||
if (type) {
|
||||
// hideTOC();
|
||||
showHelp(type);
|
||||
showNodeTypeHelp(type);
|
||||
}
|
||||
resizeStack();
|
||||
}
|
||||
@@ -298,11 +323,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 +342,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();
|
||||
}
|
||||
@@ -336,13 +362,91 @@ RED.sidebar.help = (function() {
|
||||
if (node.type === "subflow" && node.direction) {
|
||||
// ignore subflow virtual ports
|
||||
} else if (node.type !== 'group'){
|
||||
showHelp(node.type);
|
||||
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);
|
||||
@@ -263,6 +274,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
{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"},
|
||||
{label:RED._("sidebar.info.search.hiddenFlows"), value:"is:hidden"},
|
||||
]
|
||||
});
|
||||
|
||||
@@ -278,11 +290,11 @@ RED.sidebar.info.outliner = (function() {
|
||||
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
|
||||
if (node) {
|
||||
if (node.type === 'group' || node._def.category !== "config") {
|
||||
RED.view.select({nodes:[node]})
|
||||
// RED.view.select({nodes:[node]})
|
||||
} else if (node._def.category === "config") {
|
||||
RED.sidebar.info.refresh(node);
|
||||
} else {
|
||||
RED.view.select({nodes:[]})
|
||||
// RED.view.select({nodes:[]})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -311,18 +323,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 +396,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 +566,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();
|
||||
|
||||
@@ -180,6 +180,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
|
||||
|
||||
441
packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js
vendored
Normal file
441
packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js
vendored
Normal file
@@ -0,0 +1,441 @@
|
||||
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);
|
||||
|
||||
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",'');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
@@ -139,7 +139,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,6 +106,8 @@ RED.utils = (function() {
|
||||
smartypants: false
|
||||
});
|
||||
|
||||
window._marked.use({extensions: [descriptionList, description] } );
|
||||
|
||||
function renderMarkdown(txt) {
|
||||
var rendered = _marked(txt);
|
||||
var cleaned = DOMPurify.sanitize(rendered, {SAFE_FOR_JQUERY: true})
|
||||
@@ -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>');
|
||||
}
|
||||
@@ -364,6 +442,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')) {
|
||||
@@ -487,7 +567,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);
|
||||
}
|
||||
@@ -516,7 +597,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);
|
||||
}
|
||||
@@ -571,7 +653,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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -427,18 +427,393 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 +829,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 +855,21 @@ 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:add-node", function() { addNode() })
|
||||
},
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,21 +21,46 @@ RED.workspaces = (function() {
|
||||
var workspaceIndex = 0;
|
||||
|
||||
var viewStack = [];
|
||||
var hideStack = [];
|
||||
var viewStackPos = 0;
|
||||
|
||||
|
||||
function addToViewStack(id) {
|
||||
if (viewStackPos !== viewStack.length) {
|
||||
viewStack.splice(viewStackPos);
|
||||
}
|
||||
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();
|
||||
@@ -43,7 +68,15 @@ RED.workspaces = (function() {
|
||||
workspaceIndex += 1;
|
||||
} while ($("#red-ui-workspace-tabs a[title='"+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);
|
||||
@@ -55,6 +88,7 @@ RED.workspaces = (function() {
|
||||
RED.view.focus();
|
||||
return ws;
|
||||
}
|
||||
|
||||
function deleteWorkspace(ws) {
|
||||
if (workspaceTabCount === 1) {
|
||||
return;
|
||||
@@ -78,165 +112,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 +127,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 +163,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 +171,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 +206,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 +336,104 @@ 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-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 +449,6 @@ RED.workspaces = (function() {
|
||||
RED.workspaces.show(viewStack[++viewStackPos],true);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
hideWorkspace();
|
||||
}
|
||||
|
||||
@@ -416,7 +471,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 +500,6 @@ RED.workspaces = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function removeWorkspace(ws) {
|
||||
if (!ws) {
|
||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||
@@ -474,7 +528,10 @@ RED.workspaces = (function() {
|
||||
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 +546,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) {
|
||||
if (!workspace_tabs.contains(id)) {
|
||||
var sf = RED.nodes.subflow(id);
|
||||
if (sf) {
|
||||
@@ -498,14 +566,19 @@ 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);
|
||||
}
|
||||
workspace_tabs.activateTab(id);
|
||||
},
|
||||
refresh: function() {
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
|
||||
@@ -21,10 +21,10 @@ RED.user = (function() {
|
||||
opts = {};
|
||||
}
|
||||
|
||||
var dialog = $('<div id="node-dialog-login" class="hide">'+
|
||||
'<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img id="node-dialog-login-image" src=""/></div>'+
|
||||
'<div style="display: inline-block; width: 250px; vertical-align: bottom; margin-left: 10px; margin-bottom: 20px;">'+
|
||||
'<form id="node-dialog-login-fields" class="form-horizontal" style="margin-bottom: 0px;"></form>'+
|
||||
var dialog = $('<div id="node-dialog-login" class="hide" style="display: flex; align-items: flex-end;">'+
|
||||
'<div style="width: 250px; flex-grow: 0;"><img id="node-dialog-login-image" src=""/></div>'+
|
||||
'<div style="flex-grow: 1;">'+
|
||||
'<form id="node-dialog-login-fields" class="form-horizontal" style="margin-bottom: 0px; margin-left:20px;"></form>'+
|
||||
'</div>'+
|
||||
'</div>');
|
||||
|
||||
@@ -76,7 +76,7 @@ RED.user = (function() {
|
||||
}
|
||||
row.appendTo("#node-dialog-login-fields");
|
||||
}
|
||||
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">'+RED._("user.loginFailed")+'</span><img src="red/images/spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
|
||||
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;color:var(--red-ui-text-color-error);" class="hide">'+RED._("user.loginFailed")+'</span><img src="red/images/spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
|
||||
(opts.cancelable?'<a href="#" id="node-dialog-login-cancel" class="red-ui-button" style="margin-right: 20px;" tabIndex="'+(i+1)+'">'+RED._("common.label.cancel")+'</a>':'')+
|
||||
'<input type="submit" id="node-dialog-login-submit" class="red-ui-button" style="width: auto;" tabIndex="'+(i+2)+'" value="'+RED._("user.login")+'"></div>').appendTo("#node-dialog-login-fields");
|
||||
|
||||
@@ -121,6 +121,24 @@ RED.user = (function() {
|
||||
i = 0;
|
||||
for (;i<data.prompts.length;i++) {
|
||||
var field = data.prompts[i];
|
||||
var sessionMessage = /[?&]session_message=(.*?)(?:$|&)/.exec(window.location.search);
|
||||
if (sessionMessage) {
|
||||
RED.sessionMessages = RED.sessionMessages || [];
|
||||
RED.sessionMessages.push(sessionMessage[1]);
|
||||
if (history.pushState) {
|
||||
var newurl = window.location.protocol+"//"+window.location.host+window.location.pathname
|
||||
window.history.replaceState({ path: newurl }, "", newurl);
|
||||
} else {
|
||||
window.location.search = "";
|
||||
}
|
||||
}
|
||||
if (RED.sessionMessages) {
|
||||
var sessionMessages = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
|
||||
RED.sessionMessages.forEach(function (msg) {
|
||||
$('<div>').css("color","var(--red-ui-text-color-error)").text(msg).appendTo(sessionMessages);
|
||||
});
|
||||
delete RED.sessionMessages;
|
||||
}
|
||||
var row = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
|
||||
|
||||
var loginButton = $('<a href="#" class="red-ui-button"></a>',{style: "padding: 10px"}).appendTo(row).on("click", function() {
|
||||
@@ -152,7 +170,7 @@ RED.user = (function() {
|
||||
});
|
||||
}
|
||||
|
||||
var loginImageSrc = data.image || "red/images/node-red-256.png";
|
||||
var loginImageSrc = data.image || "red/images/node-red-256.svg";
|
||||
|
||||
$("#node-dialog-login-image").load(function() {
|
||||
dialog.dialog("open");
|
||||
|
||||
@@ -140,8 +140,8 @@ $workspace-button-color-focus-outline: $form-input-focus-color;
|
||||
|
||||
$shade-color: rgba(160,160,160,0.5);
|
||||
|
||||
|
||||
$popover-background: #333;
|
||||
$popover-border: $popover-background;
|
||||
$popover-color: #eee;
|
||||
$popover-button-border-color: #bbb;
|
||||
$popover-button-border-color-hover: #666;
|
||||
@@ -196,14 +196,26 @@ $view-background: $secondary-background;
|
||||
$view-select-mode-background: $secondary-background-selected;
|
||||
$view-grid-color: #eee;
|
||||
|
||||
$link-color: #999;
|
||||
$link-link-color: #aaa;
|
||||
$link-disabled-color: #ccc;
|
||||
$link-link-active-color: #ff7f0e;
|
||||
$link-unknown-color: #f00;
|
||||
|
||||
$node-label-color: #333;
|
||||
$node-port-label-color: #888;
|
||||
$node-border: #999;
|
||||
$node-border-unknown: #f33;
|
||||
$node-border-placeholder: #aaa;
|
||||
$node-background-placeholder: #eee;
|
||||
|
||||
$node-port-border: $node-border;
|
||||
$node-port-border-connected: $link-color;
|
||||
|
||||
$node-port-background: #d9d9d9;
|
||||
$node-port-background-hover: #eee;
|
||||
$node-port-background-connected: $link-color;
|
||||
|
||||
$node-icon-color: #fff;
|
||||
$node-icon-background-color: rgba(0,0,0,0.05);
|
||||
$node-icon-background-color-fill: #000;
|
||||
@@ -231,12 +243,6 @@ $node-status-colors: (
|
||||
$node-selected-color: #ff7f0e;
|
||||
$port-selected-color: #ff7f0e;
|
||||
|
||||
$link-color: #999;
|
||||
$link-link-color: #aaa;
|
||||
$link-disabled-color: #ccc;
|
||||
$link-link-active-color: #ff7f0e;
|
||||
$link-unknown-color: #f00;
|
||||
|
||||
$clipboard-textarea-background: #F3E7E7;
|
||||
|
||||
|
||||
@@ -295,6 +301,9 @@ $group-default-stroke: #999;
|
||||
$group-default-stroke-opacity: 1;
|
||||
$group-default-label-color: #a4a4a4;
|
||||
|
||||
$tourGuide-border: #c56c6c;
|
||||
$tourGuide-heading-color: #c56c6c;
|
||||
|
||||
// Deprecated
|
||||
$text-color-green: $text-color-success;
|
||||
$info-text-code-color: $text-color-code;
|
||||
|
||||
@@ -43,12 +43,24 @@
|
||||
border-bottom: 1px solid $secondary-border-color;
|
||||
box-shadow: 0 2px 6px $shadow;
|
||||
}
|
||||
.red-ui-debug-filter-row {
|
||||
.red-ui-nodeList {
|
||||
margin: 10px 0;
|
||||
#red-ui-sidebar-debug-filter-node-list-row {
|
||||
.red-ui-treeList-label.disabled {
|
||||
font-style: italic;
|
||||
color: $secondary-text-color-disabled;
|
||||
}
|
||||
|
||||
.red-ui-treeList-label {
|
||||
&.selected, &.selected .red-ui-treeList-sublabel-text {
|
||||
background: inherit;
|
||||
}
|
||||
&.selected, &.selected .red-ui-treeList-sublabel-text {
|
||||
background: inherit;
|
||||
}
|
||||
&.focus, &.focus .red-ui-treeList-sublabel-text {
|
||||
background: $list-item-background-hover !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-debug-msg {
|
||||
position: relative;
|
||||
border-bottom: 1px solid $debug-message-border;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
font-size: $primary-font-size;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
width: 200px;
|
||||
width: 230px;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
@@ -46,7 +46,7 @@
|
||||
& > li > a,
|
||||
& > li > a:focus {
|
||||
display: block;
|
||||
padding: 4px 0 4px 32px;
|
||||
padding: 4px 12px 4px 32px;
|
||||
clear: both;
|
||||
font-weight: normal;
|
||||
line-height: 20px;
|
||||
@@ -68,6 +68,10 @@
|
||||
& > .disabled > a:hover,
|
||||
& > .disabled > a:focus {
|
||||
color: $menuDisabledColor;
|
||||
.red-ui-popover-key {
|
||||
color: $menuDisabledColor;
|
||||
border-color: $menuDisabledColor;
|
||||
}
|
||||
}
|
||||
|
||||
& > .disabled > a:hover,
|
||||
@@ -83,6 +87,7 @@
|
||||
max-width: 14px;
|
||||
}
|
||||
.fa {
|
||||
float: left;
|
||||
width: 20px;
|
||||
margin-left: -25px;
|
||||
margin-top: 3px;
|
||||
@@ -102,6 +107,20 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.red-ui-menu-label {
|
||||
display: flex;
|
||||
& > :first-child {
|
||||
flex-grow: 1
|
||||
}
|
||||
}
|
||||
.red-ui-popover-key {
|
||||
border: none;
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
// float: right;
|
||||
color: $menuColor;
|
||||
border-color: $menuColor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -113,6 +132,7 @@
|
||||
|
||||
|
||||
.red-ui-menu-dropdown > li > a:hover,
|
||||
.red-ui-menu-dropdown > li.open > a,
|
||||
.red-ui-menu-dropdown > li > a:focus,
|
||||
.red-ui-menu-dropdown-submenu:hover > a,
|
||||
.red-ui-menu-dropdown-submenu:focus > a {
|
||||
@@ -129,6 +149,7 @@
|
||||
margin-top: -6px;
|
||||
margin-left: -1px;
|
||||
}
|
||||
&.open > .red-ui-menu-dropdown,
|
||||
&:hover > .red-ui-menu-dropdown {
|
||||
display: block;
|
||||
}
|
||||
@@ -209,4 +230,4 @@ ul.red-ui-menu:not(.red-ui-menu-dropdown) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
stroke-dasharray: 10 5;
|
||||
}
|
||||
|
||||
.nr-ui-view-slice {
|
||||
stroke-width: 1px;
|
||||
stroke: $view-lasso-stroke;
|
||||
fill: none;
|
||||
stroke-dasharray: 10 5;
|
||||
}
|
||||
|
||||
.node_label_italic, // deprecated: use red-ui-flow-node-label-italic
|
||||
.red-ui-flow-node-label-italic {
|
||||
font-style: italic;
|
||||
@@ -47,7 +54,7 @@
|
||||
|
||||
.red-ui-flow-port-label {
|
||||
stroke-width: 0;
|
||||
fill: $secondary-text-color;
|
||||
fill: $node-port-label-color;
|
||||
font-size: 16px;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
@@ -178,12 +185,29 @@
|
||||
}
|
||||
|
||||
.red-ui-flow-port {
|
||||
stroke: $node-border;
|
||||
stroke: $node-port-border;
|
||||
stroke-width: 1;
|
||||
fill: $node-port-background;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.red-ui-flow-port-background {
|
||||
opacity: 0;
|
||||
stroke: none;
|
||||
fill: #f00;
|
||||
cursor: crosshair;
|
||||
}
|
||||
.red-ui-flow-port-shape {
|
||||
pointer-events: none;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.red-ui-flow-port-connected .red-ui-flow-port {
|
||||
fill: $node-port-background-connected;
|
||||
stroke: $node-port-border-connected;
|
||||
}
|
||||
|
||||
|
||||
.red-ui-flow-node-error {
|
||||
fill: $node-status-error-background;
|
||||
stroke: $node-status-error-border;
|
||||
@@ -273,9 +297,10 @@ g.red-ui-flow-node-selected {
|
||||
text-anchor:start;
|
||||
}
|
||||
|
||||
.red-ui-flow-port-hovered {
|
||||
stroke: $port-selected-color;
|
||||
fill: $port-selected-color;
|
||||
.red-ui-flow-port-hovered:not(.red-ui-flow-port-background),
|
||||
.red-ui-flow-port-background.red-ui-flow-port-hovered + .red-ui-flow-port-shape {
|
||||
stroke: $port-selected-color !important;
|
||||
fill: $port-selected-color !important;
|
||||
}
|
||||
|
||||
.red-ui-flow-subflow-port {
|
||||
|
||||
@@ -187,18 +187,21 @@
|
||||
ul.red-ui-menu-dropdown {
|
||||
background: $header-menu-background;
|
||||
border: 1px solid $header-menu-background;
|
||||
width: 250px !important;
|
||||
width: 260px !important;
|
||||
margin-top: 0;
|
||||
li a {
|
||||
color: $header-menu-color;
|
||||
padding: 3px 40px;
|
||||
padding: 3px 10px 3px 40px;
|
||||
img {
|
||||
max-width: 100%;
|
||||
margin-right: 10px;
|
||||
padding: 4px;
|
||||
border: 3px solid transparent;
|
||||
}
|
||||
|
||||
.red-ui-popover-key {
|
||||
color: $header-menu-color-disabled !important;
|
||||
border-color: $header-menu-color-disabled !important;
|
||||
}
|
||||
&.active img {
|
||||
border: 3px solid $header-menu-item-border-active;
|
||||
}
|
||||
@@ -211,7 +214,6 @@
|
||||
}
|
||||
span.red-ui-menu-label {
|
||||
font-size: 14px;
|
||||
display: inline-block;
|
||||
text-indent: 0px;
|
||||
}
|
||||
span.red-ui-menu-sublabel {
|
||||
@@ -222,6 +224,7 @@
|
||||
}
|
||||
}
|
||||
> li > a:hover,
|
||||
> li.open > a,
|
||||
> li > a:focus,
|
||||
> li:hover > a,
|
||||
> li:focus > a {
|
||||
|
||||
@@ -19,19 +19,23 @@
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
padding: 10px;
|
||||
padding: 2px;
|
||||
height: auto;
|
||||
background: $popover-background;
|
||||
color: $popover-color;
|
||||
background: var(--red-ui-popover-border);
|
||||
color: var(--red-ui-popover-color);
|
||||
border-radius: 4px;
|
||||
z-index: 1000;
|
||||
font-family: $primary-font;
|
||||
font-size: 14px;
|
||||
line-height: 1.4em;
|
||||
@include component-shadow;
|
||||
border-color: $popover-background;
|
||||
border-color: var(--red-ui-popover-border);
|
||||
}
|
||||
.red-ui-popover-content {
|
||||
padding: 8px;
|
||||
border-radius: 2px;
|
||||
background: var(--red-ui-popover-background);
|
||||
}
|
||||
|
||||
.red-ui-popover:after, .red-ui-popover:before {
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
@@ -61,26 +65,26 @@
|
||||
|
||||
.red-ui-popover.red-ui-popover-right:after {
|
||||
border-color: transparent;
|
||||
border-right-color: $popover-background;
|
||||
border-right-color: var(--red-ui-popover-border);
|
||||
border-width: 10px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-right:before {
|
||||
border-color: transparent;
|
||||
border-right-color: $popover-background;
|
||||
border-right-color: var(--red-ui-popover-border);
|
||||
border-width: 11px;
|
||||
margin-top: -11px;
|
||||
}
|
||||
|
||||
.red-ui-popover.red-ui-popover-left:after {
|
||||
border-color: transparent;
|
||||
border-left-color: $popover-background;
|
||||
border-left-color: var(--red-ui-popover-border);
|
||||
border-width: 10px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-left:before {
|
||||
border-color: transparent;
|
||||
border-left-color: $popover-background;
|
||||
border-left-color: var(--red-ui-popover-border);
|
||||
border-width: 11px;
|
||||
margin-top: -11px;
|
||||
}
|
||||
@@ -88,26 +92,26 @@
|
||||
|
||||
.red-ui-popover.red-ui-popover-bottom:after {
|
||||
border-color: transparent;
|
||||
border-bottom-color: $popover-background;
|
||||
border-bottom-color: var(--red-ui-popover-border);
|
||||
border-width: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-bottom:before {
|
||||
border-color: transparent;
|
||||
border-bottom-color: $popover-background;
|
||||
border-bottom-color: var(--red-ui-popover-border);
|
||||
border-width: 11px;
|
||||
margin-left: -11px;
|
||||
}
|
||||
|
||||
.red-ui-popover.red-ui-popover-top:after {
|
||||
border-color: transparent;
|
||||
border-top-color: $popover-background;
|
||||
border-top-color: var(--red-ui-popover-border);
|
||||
border-width: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-top:before {
|
||||
border-color: transparent;
|
||||
border-top-color: $popover-background;
|
||||
border-top-color: var(--red-ui-popover-border);
|
||||
border-width: 11px;
|
||||
margin-left: -11px;
|
||||
}
|
||||
@@ -116,9 +120,10 @@
|
||||
|
||||
.red-ui-popover-size-small {
|
||||
font-size: 12px;
|
||||
padding: 5px 7px;
|
||||
line-height: 1.8em;
|
||||
|
||||
.red-ui-popover-content {
|
||||
padding: 1px 4px;
|
||||
}
|
||||
&.red-ui-popover-right:after, &.red-ui-popover-left:after {
|
||||
border-width: 7px;
|
||||
margin-top: -7px;
|
||||
@@ -143,7 +148,7 @@
|
||||
font-size: 11px;
|
||||
font-family: $monospace-font;
|
||||
margin-left: 3px;
|
||||
border: 1px solid $popover-color;
|
||||
border: 1px solid var(--red-ui-popover-color);
|
||||
border-radius:3px;
|
||||
padding: 1px 2px;
|
||||
}
|
||||
@@ -152,8 +157,8 @@
|
||||
.red-ui-popover button.red-ui-button {
|
||||
&:not(.primary) {
|
||||
border-color: $popover-button-border-color;
|
||||
background: $popover-background;
|
||||
color: $popover-color !important;
|
||||
background: var(--red-ui-popover-background);
|
||||
color: var(--red-ui-popover-color) !important;
|
||||
}
|
||||
&:not(.primary):not(.disabled):not(.ui-button-disabled):hover {
|
||||
border-color: $popover-button-border-color-hover;
|
||||
|
||||
@@ -73,13 +73,13 @@
|
||||
.red-ui-projects-dialog-screen-start {
|
||||
.red-ui-projects-dialog-screen-start-hero {
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
font-size: 1.4em;
|
||||
padding: 10px;
|
||||
min-height: 60px;
|
||||
min-height: 40px;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
.red-ui-projects-dialog-screen-start-body {
|
||||
min-height: 400px;
|
||||
min-height: 300px;
|
||||
line-height: 1.6em;
|
||||
p {
|
||||
font-size: 1.1em;
|
||||
@@ -92,7 +92,7 @@
|
||||
}
|
||||
button.red-ui-button.red-ui-projects-dialog-button {
|
||||
width: calc(50% - 80px);
|
||||
margin: 20px;
|
||||
margin: 10px 20px;
|
||||
height: auto;
|
||||
line-height: 2em;
|
||||
padding: 10px;
|
||||
|
||||
@@ -204,6 +204,28 @@
|
||||
font-style: italic;
|
||||
color: $form-placeholder-color;
|
||||
}
|
||||
.red-ui-search-history {
|
||||
button {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
&:hover button {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
.red-ui-search-historyHeader {
|
||||
button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 7px;
|
||||
}
|
||||
}
|
||||
.red-ui-search-history-result {
|
||||
|
||||
}
|
||||
|
||||
.red-ui-search-result-action {
|
||||
color: $primary-text-color;
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
@import "ui/common/checkboxSet";
|
||||
@import "ui/common/stack";
|
||||
@import "ui/common/treeList";
|
||||
@import "ui/common/autoComplete";
|
||||
|
||||
@import "dragdrop";
|
||||
|
||||
@@ -69,3 +70,5 @@
|
||||
@import "debug";
|
||||
|
||||
@import "radialMenu";
|
||||
|
||||
@import "tourGuide";
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
.red-ui-sidebar-info {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.red-ui-sidebar-info hr {
|
||||
margin: 10px 0;
|
||||
@@ -212,6 +213,9 @@ div.red-ui-info-table {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
p {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
.red-ui-help-info-header {
|
||||
i {
|
||||
@@ -230,7 +234,26 @@ div.red-ui-info-table {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border: 1px solid var(--red-ui-secondary-border-color);
|
||||
margin : 8px 0 8px 0;
|
||||
min-width : 300px;
|
||||
overflow : hidden;
|
||||
}
|
||||
table thead tr {
|
||||
background-color: var(--red-ui-primary-background); //$primary-text-color;
|
||||
border-bottom: 1px solid var(--red-ui-secondary-border-color);
|
||||
color: var(--red-ui-header-text-color);
|
||||
text-align: left;
|
||||
}
|
||||
table th,
|
||||
table td {
|
||||
padding: 6px 8px;
|
||||
}
|
||||
table tbody tr:nth-of-type(even) {
|
||||
background-color: var(--red-ui-tertiary-background); //$primary-background;
|
||||
}
|
||||
}
|
||||
.red-ui-sidebar-info-stack {
|
||||
height: 100%;
|
||||
@@ -411,16 +434,19 @@ div.red-ui-info-table {
|
||||
}
|
||||
.red-ui-info-outline-item-controls {
|
||||
position: absolute;
|
||||
top:0;
|
||||
bottom: 0;
|
||||
right: 0px;
|
||||
padding: 2px 3px 0 1px;
|
||||
top:1px;
|
||||
bottom: 1px;
|
||||
right: 1px;
|
||||
padding: 1px 2px 0 1px;
|
||||
text-align: right;
|
||||
background: $list-item-background;
|
||||
|
||||
.red-ui-treeList-label:hover & {
|
||||
background: $list-item-background-hover;
|
||||
}
|
||||
.red-ui-treeList-label.focus & {
|
||||
background: $list-item-background-hover;
|
||||
}
|
||||
.red-ui-treeList-label.selected & {
|
||||
background: $list-item-background-selected;
|
||||
}
|
||||
@@ -435,6 +461,12 @@ div.red-ui-info-table {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
.fa-circle-thin {
|
||||
display: none;
|
||||
}
|
||||
.fa-eye {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.red-ui-info-outline-item-control-reveal,
|
||||
.red-ui-info-outline-item-control-action {
|
||||
@@ -446,7 +478,17 @@ div.red-ui-info-table {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.fa-eye-slash {
|
||||
display: none;
|
||||
}
|
||||
.red-ui-info-outline-item.red-ui-info-outline-item-hidden & {
|
||||
.fa-eye-slash {
|
||||
display: inline-block;
|
||||
}
|
||||
.fa-eye {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.fa-ban {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
height: 35px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.hide-tab {
|
||||
transition: width 0.1s ease-in;
|
||||
}
|
||||
.red-ui-tabs-scroll-container {
|
||||
height: 60px;
|
||||
overflow-x: scroll;
|
||||
@@ -104,7 +107,7 @@
|
||||
}
|
||||
|
||||
.red-ui-tabs-fade {
|
||||
background-image: linear-gradient(to right, transparent, $tab-background-active);
|
||||
background-image: linear-gradient(to right, change-color($tab-background-active, $alpha: 0.001), $tab-background-active);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -112,7 +115,7 @@
|
||||
&:not(.active) {
|
||||
background: $tab-background-selected;
|
||||
.red-ui-tabs-fade {
|
||||
background-image: linear-gradient(to right, transparent, $tab-background-selected);
|
||||
background-image: linear-gradient(to right, change-color($tab-background-selected, $alpha: 0.001), $tab-background-selected);
|
||||
}
|
||||
.red-ui-tabs-badge-selected {
|
||||
background: $tab-background-selected;
|
||||
@@ -131,6 +134,9 @@
|
||||
&:not(.active) a:hover {
|
||||
color: $workspace-button-color-hover;
|
||||
background: $tab-background-hover;
|
||||
&+.red-ui-tabs-fade {
|
||||
background-image: linear-gradient(to right, change-color($tab-background-hover, $alpha: 0.001), $tab-background-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,13 +145,18 @@
|
||||
padding-right: 21px;
|
||||
}
|
||||
&.red-ui-tabs-add {
|
||||
padding-right: 35px;
|
||||
padding-right: 29px;
|
||||
}
|
||||
&.red-ui-tabs-add.red-ui-tabs-scrollable {
|
||||
padding-right: 59px;
|
||||
padding-right: 53px;
|
||||
}
|
||||
&.red-ui-tabs-add.red-ui-tabs-menu.red-ui-tabs-scrollable,
|
||||
&.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-scrollable {
|
||||
padding-right: 95px;
|
||||
padding-right: 83px;
|
||||
}
|
||||
|
||||
&.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-menu.red-ui-tabs-scrollable {
|
||||
padding-right: 113px;
|
||||
}
|
||||
|
||||
&.red-ui-tabs-collapsible {
|
||||
@@ -229,13 +240,14 @@
|
||||
|
||||
a {
|
||||
@include workspace-button;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
line-height: 30px;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
margin-top: 3px;
|
||||
margin-right:3px;
|
||||
margin-left:3px;
|
||||
border: 1px solid $primary-border-color;
|
||||
margin-bottom: 3px;
|
||||
border: none;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
@@ -277,6 +289,8 @@
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
border-bottom: 1px solid $primary-border-color;
|
||||
line-height: 34px;
|
||||
}
|
||||
}
|
||||
.red-ui-tab-scroll-left {
|
||||
@@ -293,22 +307,37 @@
|
||||
|
||||
}
|
||||
.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right {
|
||||
right: 38px;
|
||||
right: 32px;
|
||||
}
|
||||
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-menu .red-ui-tab-scroll-right,
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search .red-ui-tab-scroll-right {
|
||||
right: 76px;
|
||||
right: 64px;
|
||||
}
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-menu .red-ui-tabs-add,
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search .red-ui-tabs-add {
|
||||
right: 38px;
|
||||
right: 32px;
|
||||
}
|
||||
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-menu {
|
||||
.red-ui-tab-scroll-right {
|
||||
right: 96px;
|
||||
}
|
||||
.red-ui-tabs-add {
|
||||
right: 64px;
|
||||
}
|
||||
.red-ui-tabs-search {
|
||||
right: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-tabs-fade {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 15px;
|
||||
background-image: linear-gradient(to right, transparent, $tab-background-inactive);
|
||||
background-image: linear-gradient(to right, change-color($tab-background-inactive, $alpha: 0.001), $tab-background-inactive);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -360,7 +389,19 @@ i.red-ui-tab-icon {
|
||||
vertical-align: top;
|
||||
|
||||
}
|
||||
|
||||
.red-ui-tab-hide {
|
||||
.fa-eye-slash {
|
||||
display: none;
|
||||
}
|
||||
&:hover {
|
||||
.fa-eye-slash {
|
||||
display: inline
|
||||
}
|
||||
.fa-eye {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-tab-close {
|
||||
display: none;
|
||||
background: $tab-background-inactive;
|
||||
|
||||
118
packages/node_modules/@node-red/editor-client/src/sass/tourGuide.scss
vendored
Normal file
118
packages/node_modules/@node-red/editor-client/src/sass/tourGuide.scss
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
.red-ui-tourGuide-shade {
|
||||
position: absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
bottom:0;
|
||||
right:0;
|
||||
z-index: 2000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.red-ui-tourGuide-shade-focus {
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
z-index: 2001;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--red-ui-tourGuide-border);
|
||||
|
||||
&.transition {
|
||||
transition: 0.4s ease;
|
||||
transition-property: width,height;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
border: solid 6000px var(--red-ui-shade-color);
|
||||
margin-left: -6000px;
|
||||
margin-top: -6000px;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.red-ui-popover.red-ui-tourGuide-popover {
|
||||
z-index: 2003;
|
||||
--red-ui-popover-background: var(--red-ui-secondary-background);
|
||||
--red-ui-popover-border: var(--red-ui-tourGuide-border);
|
||||
--red-ui-popover-color: var(--red-ui-primary-text-color);
|
||||
|
||||
.red-ui-popover-content {
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-top: 0px;
|
||||
line-height: 1.2em;
|
||||
color: var(--red-ui-tourGuide-heading-color);
|
||||
i.fa {
|
||||
font-size: 1.5em
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.red-ui-tourGuide-toolbar {
|
||||
min-height: 36px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.red-ui-tourGuide-breadcrumbs {
|
||||
flex-grow: 1;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 6px;
|
||||
& > div {
|
||||
display: inline-block;
|
||||
}
|
||||
i {
|
||||
line-height: 16px;
|
||||
margin: 0 3px;
|
||||
}
|
||||
}
|
||||
.red-ui-tourGuide-popover-description {
|
||||
padding: 10px 20px 5px;
|
||||
}
|
||||
.red-ui-tourGuide-popover-full {
|
||||
.red-ui-tourGuide-popover-description {
|
||||
padding: 20px 40px 10px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.red-ui-popover.red-ui-tourGuide-popover button.red-ui-button {
|
||||
&:not(.primary) {
|
||||
background: var(--red-ui-secondary-background);
|
||||
color: var(--red-ui-primary-text-color) !important;
|
||||
}
|
||||
&:not(.primary):not(.disabled):not(.ui-button-disabled):hover {
|
||||
border-color: $popover-button-border-color-hover;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// .red-ui-tourGuide-popover-bounce {
|
||||
// animation: 10s ease-in 5s infinite both red-ui-tourGuide-popover-bounce;
|
||||
// }
|
||||
// // @keyframes *must* be on multiple lines so build-custom-theme can filter them out
|
||||
// @keyframes red-ui-tourGuide-popover-bounce {
|
||||
// 0%,
|
||||
// 10%,
|
||||
// 100% {
|
||||
// -webkit-transform: translateY(0);
|
||||
// transform: translateY(0);
|
||||
// }
|
||||
// 2%,8% {
|
||||
// -webkit-transform: translateY(-5px);
|
||||
// transform: translateY(-5px);
|
||||
// }
|
||||
// 5% {
|
||||
// -webkit-transform: translateY(5px);
|
||||
// transform: translateY(5px);
|
||||
// }
|
||||
// }
|
||||
5
packages/node_modules/@node-red/editor-client/src/sass/ui/common/autoComplete.scss
vendored
Normal file
5
packages/node_modules/@node-red/editor-client/src/sass/ui/common/autoComplete.scss
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.red-ui-autoComplete-container {
|
||||
&.red-ui-popover-panel {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
@@ -89,18 +89,30 @@
|
||||
color: $list-item-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
&.focus, &.focus .red-ui-treeList-sublabel-text {
|
||||
background: $list-item-background-hover;
|
||||
outline: 1px solid $form-input-focus-color !important;
|
||||
outline-offset: -1px;
|
||||
color: $list-item-color;
|
||||
}
|
||||
&.selected, &.selected .red-ui-treeList-sublabel-text {
|
||||
background: $list-item-background-selected;
|
||||
outline: none;
|
||||
color: $list-item-color;
|
||||
}
|
||||
|
||||
input.red-ui-treeList-checkbox {
|
||||
input.red-ui-treeList-checkbox,
|
||||
input.red-ui-treeList-radio {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.red-ui-treeList-label-text {
|
||||
margin-left: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
&:empty {
|
||||
min-height: 20px;
|
||||
}
|
||||
}
|
||||
.red-ui-treeList-sublabel-text {
|
||||
top: 0;
|
||||
@@ -117,6 +129,7 @@
|
||||
|
||||
.red-ui-treeList-icon {
|
||||
display: inline-block;
|
||||
flex-shrink: 0;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@
|
||||
z-index: 2000;
|
||||
a {
|
||||
padding: 6px 18px 6px 6px;
|
||||
display: block;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid $secondary-border-color;
|
||||
color: $form-text-color;
|
||||
&:hover {
|
||||
@@ -98,7 +99,7 @@
|
||||
background: $workspace-button-background-active;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
margin-right: 6px;
|
||||
margin: 0 6px 0 0;
|
||||
}
|
||||
}
|
||||
.red-ui-typedInput-icon {
|
||||
|
||||
@@ -81,12 +81,18 @@
|
||||
--red-ui-node-status-changed-border: #{$node-status-changed-border};
|
||||
--red-ui-node-status-changed-background: #{$node-status-changed-background};
|
||||
|
||||
|
||||
|
||||
--red-ui-node-border: #{$node-border};
|
||||
--red-ui-node-port-background:#{$node-port-background};
|
||||
|
||||
--red-ui-node-label-color: #{$node-label-color};
|
||||
--red-ui-node-selected-color: #{$node-selected-color};
|
||||
--red-ui-port-selected-color: #{$port-selected-color};
|
||||
|
||||
--red-ui-popover-background: #{$popover-background};
|
||||
--red-ui-popover-border: #{$popover-border};
|
||||
--red-ui-popover-color: #{$popover-color};
|
||||
|
||||
--red-ui-tourGuide-border: #{$tourGuide-border};
|
||||
--red-ui-tourGuide-heading-color: #{$tourGuide-heading-color};
|
||||
|
||||
}
|
||||
|
||||
101
packages/node_modules/@node-red/editor-client/src/tours/first-flow.js
vendored
Normal file
101
packages/node_modules/@node-red/editor-client/src/tours/first-flow.js
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
export default {
|
||||
steps: [
|
||||
{
|
||||
title: {
|
||||
'en-US': 'Create your first flow',
|
||||
'ja': 'はじめてのフローを作成'
|
||||
},
|
||||
width: 400,
|
||||
description: {
|
||||
'en-US': 'This tutorial will guide you through creating your first flow',
|
||||
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。'
|
||||
},
|
||||
nextButton: 'start'
|
||||
},
|
||||
{
|
||||
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
|
||||
description: {
|
||||
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
|
||||
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。'
|
||||
},
|
||||
wait: {
|
||||
type: "dom-event",
|
||||
event: "click",
|
||||
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add a"
|
||||
},
|
||||
},
|
||||
{
|
||||
element: '.red-ui-palette-node[data-palette-type="inject"]',
|
||||
direction: 'right',
|
||||
description: {
|
||||
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
|
||||
'ja': 'パレットには、利用できる全てのノードが一覧表示されます。injectノードをワークスペースにドラッグします。'
|
||||
},
|
||||
fallback: 'inset-bottom-right',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
event: "nodes:add",
|
||||
filter: function(event) {
|
||||
if (event.type === "inject") {
|
||||
this.injectNode = event;
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
$('.red-ui-palette-node[data-palette-type="inject"]').css("z-index","auto");
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '.red-ui-palette-node[data-palette-type="debug"]',
|
||||
direction: 'right',
|
||||
description: {
|
||||
'en-US': 'Next, drag a new Debug node into the workspace.',
|
||||
'ja': '次に、debugノードをワークスペースにドラッグします。'
|
||||
},
|
||||
fallback: 'inset-bottom-right',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
event: "nodes:add",
|
||||
filter: function(event) {
|
||||
if (event.type === "debug") {
|
||||
this.debugNode = event;
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
$('.red-ui-palette-node[data-palette-type="debug"]').css("z-index","auto");
|
||||
},
|
||||
},
|
||||
{
|
||||
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
|
||||
description: {
|
||||
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
|
||||
'ja': 'injectノードの出力から、debugノードの入力へワイヤーで接続します。'
|
||||
},
|
||||
fallback: 'inset-bottom-right',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
event: "links:add",
|
||||
filter: function(event) {
|
||||
return event.source.id === this.injectNode.id && event.target.id === this.debugNode.id;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
element: "#red-ui-header-button-deploy",
|
||||
description: {
|
||||
'en-US': 'Deploy your changes so the flow is active in the runtime',
|
||||
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。'
|
||||
},
|
||||
width: 200,
|
||||
wait: {
|
||||
type: "dom-event",
|
||||
event: "click"
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
229
packages/node_modules/@node-red/editor-client/src/tours/welcome.js
vendored
Normal file
229
packages/node_modules/@node-red/editor-client/src/tours/welcome.js
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
export default {
|
||||
version: "2.1.0",
|
||||
steps: [
|
||||
{
|
||||
titleIcon: "fa fa-map-o",
|
||||
title: {
|
||||
"en-US": "Welcome to Node-RED 2.1!",
|
||||
"ja": "Node-RED 2.1へようこそ!"
|
||||
},
|
||||
description: {
|
||||
"en-US": "Let's take a moment to discover the new features in this release.",
|
||||
"ja": "本リリースの新機能を見つけてみましょう。"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "A new Tour Guide",
|
||||
"ja": "新しいツアーガイド"
|
||||
},
|
||||
description: {
|
||||
"en-US": "<p>First, as you've already found, we now have this tour of new features. We'll only show the tour the first time you open the editor for each new version of Node-RED.</p>" +
|
||||
"<p>You can choose not to see this tour in the future by disabling it under the View tab of User Settings.</p>",
|
||||
"ja": "<p>最初に、既に見つけている様に、新機能の本ツアーがあります。本ツアーは、新バージョンのNode-REDフローエディタを初めて開いた時のみ表示されます。</p>" +
|
||||
"<p>ユーザ設定の表示タブの中で、この機能を無効化することで、本ツアーを表示しないようにすることもできます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "New Edit menu",
|
||||
"ja": "新しい編集メニュー"
|
||||
},
|
||||
prepare() {
|
||||
$("#red-ui-header-button-sidemenu").trigger("click");
|
||||
$("#menu-item-edit-menu").parent().addClass("open");
|
||||
},
|
||||
complete() {
|
||||
$("#menu-item-edit-menu").parent().removeClass("open");
|
||||
},
|
||||
element: "#menu-item-edit-menu-submenu",
|
||||
interactive: false,
|
||||
direction: "left",
|
||||
description: {
|
||||
"en-US": "<p>The main menu has been updated with a new 'Edit' section. This includes all of the familar options, like cut/paste and undo/redo.</p>" +
|
||||
"<p>The menu now displays keyboard shortcuts for the options.</p>",
|
||||
"ja": "<p>メインメニューに「編集」セクションが追加されました。本セクションには、切り取り/貼り付けや、変更操作を戻す/やり直しの様な使い慣れたオプションが含まれています。</p>" +
|
||||
"<p>本メニューには、オプションのためのキーボードショートカットも表示されるようになりました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Arranging nodes",
|
||||
"ja": "ノードの配置"
|
||||
},
|
||||
prepare() {
|
||||
$("#red-ui-header-button-sidemenu").trigger("click");
|
||||
$("#menu-item-arrange-menu").parent().addClass("open");
|
||||
},
|
||||
complete() {
|
||||
$("#menu-item-arrange-menu").parent().removeClass("open");
|
||||
},
|
||||
element: "#menu-item-arrange-menu-submenu",
|
||||
interactive: false,
|
||||
direction: "left",
|
||||
description: {
|
||||
"en-US": "<p>The new 'Arrange' section of the menu provides new options to help arrange your nodes. You can align them to a common edge, spread them out evenly or change their order.</p>",
|
||||
"ja": "<p>メニューの新しい「配置」セクションには、ノードの配置を助ける新しいオプションが提供されています。ノードの端を揃えたり、均等に配置したり、表示順序を変更したりできます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Hiding tabs",
|
||||
"ja": "タブの非表示"
|
||||
},
|
||||
element: "#red-ui-workspace-tabs > li.active",
|
||||
description: {
|
||||
"en-US": '<p>Tabs can now be hidden by clicking their <i class="fa fa-eye-slash"></i> icon.</p><p>The Info Sidebar will still list all of your tabs, and tell you which ones are currently hidden.',
|
||||
"ja": '<p><i class="fa fa-eye-slash"></i> アイコンをクリックすることで、タブを非表示にできます。</p><p>情報サイドバーには、全てのタブが一覧表示されており、現在非表示になっているタブを確認できます。'
|
||||
},
|
||||
interactive: false,
|
||||
prepare() {
|
||||
$("#red-ui-workspace-tabs > li.active .red-ui-tab-close").css("display","block");
|
||||
},
|
||||
complete() {
|
||||
$("#red-ui-workspace-tabs > li.active .red-ui-tab-close").css("display","");
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Tab menu",
|
||||
"ja": "タブメニュー"
|
||||
},
|
||||
element: "#red-ui-workspace-tabs-menu",
|
||||
description: {
|
||||
"en-US": "<p>The new tab menu also provides lots of new options for your tabs.</p>",
|
||||
"ja": "<p>新しいタブメニューには、タブに関する沢山の新しいオプションが提供されています。</p>"
|
||||
},
|
||||
interactive: false,
|
||||
direction: "left",
|
||||
prepare() {
|
||||
$("#red-ui-workspace > .red-ui-tabs > .red-ui-tabs-menu a").trigger("click");
|
||||
},
|
||||
complete() {
|
||||
$(document).trigger("click");
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Flow and Group level environment variables",
|
||||
"ja": "フローとグループの環境変数"
|
||||
},
|
||||
element: "#red-ui-workspace-tabs > li.active",
|
||||
interactive: false,
|
||||
description: {
|
||||
"en-US": "<p>Flows and Groups can now have their own environment variables that can be referenced by nodes inside them.</p>",
|
||||
"ja": "<p>フローとグループには、内部のノードから参照できる環境変数を設定できるようになりました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
prepare(done) {
|
||||
RED.editor.editFlow(RED.nodes.workspace(RED.workspaces.active()),"editor-tab-envProperties");
|
||||
setTimeout(done,700);
|
||||
},
|
||||
element: "#red-ui-tab-editor-tab-envProperties-link-button",
|
||||
description: {
|
||||
"en-US": "<p>Their edit dialogs have a new Environment Variables section.</p>",
|
||||
"ja": "<p>編集ダイアログに環境変数セクションが追加されました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
element: ".node-input-env-container-row",
|
||||
direction: "left",
|
||||
description: {
|
||||
"en-US": '<p>The environment variables are listed in this table and new ones can be added by clicking the <i class="fa fa-plus"></i> button.</p>',
|
||||
"ja": '<p>この表に環境変数が一覧表示されており、<i class="fa fa-plus"></i>ボタンをクリックすることで新しい変数を追加できます。</p>'
|
||||
},
|
||||
complete(done) {
|
||||
$("#node-dialog-cancel").trigger("click");
|
||||
setTimeout(done,500);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Link Call node added",
|
||||
"ja": "Link Callノードを追加"
|
||||
},
|
||||
prepare(done) {
|
||||
this.paletteWasClosed = $("#red-ui-main-container").hasClass("red-ui-palette-closed");
|
||||
RED.actions.invoke("core:toggle-palette",true)
|
||||
$('[data-palette-type="link call"]')[0].scrollIntoView({block:"center"})
|
||||
setTimeout(done,100);
|
||||
},
|
||||
element: '[data-palette-type="link call"]',
|
||||
direction: "right",
|
||||
description: {
|
||||
"en-US": "<p>The <code>Link Call</code> node lets you call another flow that begins with a <code>Link In</code> node and get the result back when the message reaches a <code>Link Out</code> node.</p>",
|
||||
"ja": "<p><code>Link Call</code>ノードを用いることで、<code>Link In</code>ノードから始まるフローを呼び出し、<code>Link Out</code>ノードに到達した時に、結果を取得できます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "MQTT nodes support dynamic connections",
|
||||
"ja": "MQTTノードが動的接続をサポート"
|
||||
},
|
||||
prepare(done) {
|
||||
$('[data-palette-type="mqtt out"]')[0].scrollIntoView({block:"center"})
|
||||
setTimeout(done,100);
|
||||
},
|
||||
element: '[data-palette-type="mqtt out"]',
|
||||
direction: "right",
|
||||
description: {
|
||||
"en-US": '<p>The <code>MQTT</code> nodes now support creating their connections and subscriptions dynamically.</p>',
|
||||
"ja": '<p><code>MQTT</code>ノードは、動的な接続や購読ができるようになりました。</p>'
|
||||
},
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "File nodes renamed",
|
||||
"ja": "ファイルノードの名前変更"
|
||||
},
|
||||
prepare(done) {
|
||||
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"});
|
||||
setTimeout(done,100);
|
||||
},
|
||||
complete() {
|
||||
if (this.paletteWasClosed) {
|
||||
RED.actions.invoke("core:toggle-palette",false)
|
||||
}
|
||||
},
|
||||
element: '[data-palette-type="file"]',
|
||||
direction: "right",
|
||||
description: {
|
||||
"en-US": "<p>The file nodes have been renamed to make it clearer which node does what.</p>",
|
||||
"ja": "<p>fileノードの名前が変更され、どのノードが何を行うかが明確になりました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Deep copy option on Change node",
|
||||
"ja": "Changeノードのディープコピーオプション"
|
||||
},
|
||||
prepare(done) {
|
||||
var def = RED.nodes.getType('change');
|
||||
RED.editor.edit({id:"test",type:"change",rules:[{t:"set",p:"payload",pt:"msg", tot:"msg",to:"anotherProperty"}],_def:def, _:def._});
|
||||
setTimeout(done,700);
|
||||
},
|
||||
complete(done) {
|
||||
$("#node-dialog-cancel").trigger("click");
|
||||
setTimeout(done,500);
|
||||
},
|
||||
element: function() {
|
||||
return $(".node-input-rule-property-deepCopy").next();
|
||||
},
|
||||
description: {
|
||||
"en-US": "<p>The Set rule has a new option to create a deep copy of the value. This ensures a complete copy is made, rather than using a reference.</p>",
|
||||
"ja": "<p>値を代入に、値のディープコピーを作成するオプションが追加されました。これによって参照ではなく、完全なコピーが作成されます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "And that's not all...",
|
||||
"ja": "これが全てではありません..."
|
||||
},
|
||||
description: {
|
||||
"en-US": "<p>There are many more smaller changes, including:</p><ul><li>Auto-complete suggestions in the <code>msg</code> TypedInput.</li><li>Support for <code>msg.resetTimeout</code> in the <code>Join</code> node.</li><li>Pushing messages to the front of the queue in the <code>Delay</code> node's rate limiting mode.</li><li>An optional second output on the <code>Delay</code> node for rate limited messages.</li></ul>",
|
||||
"ja": "<p>以下の様な小さな変更が沢山あります:</p><ul><li><code>msg</code> TypedInputの自動補完提案</li><li><code>Join</code>ノードで<code>msg.resetTimeout</code>のサポート</li><li><code>Delay</code>ノードの流量制御モードにおいて先頭メッセージをキューに追加</li><li><code>Delay</code>ノードで流量制限されたメッセージ向けの任意の2つ目の出力</li></ul>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using \`npm run update-types\` in https://github.com/Steve-Mcl/monaco-editor-esm-i18n */
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
|
||||
interface NodeMessage {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using \`npm run update-types\` in https://github.com/Steve-Mcl/monaco-editor-esm-i18n */
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
127
packages/node_modules/@node-red/editor-client/src/types/node/assert.d.ts
vendored
Normal file
127
packages/node_modules/@node-red/editor-client/src/types/node/assert.d.ts
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'assert' {
|
||||
/** An alias of `assert.ok()`. */
|
||||
function assert(value: any, message?: string | Error): asserts value;
|
||||
namespace assert {
|
||||
class AssertionError extends Error {
|
||||
actual: any;
|
||||
expected: any;
|
||||
operator: string;
|
||||
generatedMessage: boolean;
|
||||
code: 'ERR_ASSERTION';
|
||||
|
||||
constructor(options?: {
|
||||
/** If provided, the error message is set to this value. */
|
||||
message?: string | undefined;
|
||||
/** The `actual` property on the error instance. */
|
||||
actual?: any;
|
||||
/** The `expected` property on the error instance. */
|
||||
expected?: any;
|
||||
/** The `operator` property on the error instance. */
|
||||
operator?: string | undefined;
|
||||
/** If provided, the generated stack trace omits frames before this function. */
|
||||
// tslint:disable-next-line:ban-types
|
||||
stackStartFn?: Function | undefined;
|
||||
});
|
||||
}
|
||||
|
||||
class CallTracker {
|
||||
calls(exact?: number): () => void;
|
||||
calls<Func extends (...args: any[]) => any>(fn?: Func, exact?: number): Func;
|
||||
report(): CallTrackerReportInformation[];
|
||||
verify(): void;
|
||||
}
|
||||
interface CallTrackerReportInformation {
|
||||
message: string;
|
||||
/** The actual number of times the function was called. */
|
||||
actual: number;
|
||||
/** The number of times the function was expected to be called. */
|
||||
expected: number;
|
||||
/** The name of the function that is wrapped. */
|
||||
operator: string;
|
||||
/** A stack trace of the function. */
|
||||
stack: object;
|
||||
}
|
||||
|
||||
type AssertPredicate = RegExp | (new () => object) | ((thrown: any) => boolean) | object | Error;
|
||||
|
||||
function fail(message?: string | Error): never;
|
||||
/** @deprecated since v10.0.0 - use fail([message]) or other assert functions instead. */
|
||||
function fail(
|
||||
actual: any,
|
||||
expected: any,
|
||||
message?: string | Error,
|
||||
operator?: string,
|
||||
// tslint:disable-next-line:ban-types
|
||||
stackStartFn?: Function,
|
||||
): never;
|
||||
function ok(value: any, message?: string | Error): asserts value;
|
||||
/** @deprecated since v9.9.0 - use strictEqual() instead. */
|
||||
function equal(actual: any, expected: any, message?: string | Error): void;
|
||||
/** @deprecated since v9.9.0 - use notStrictEqual() instead. */
|
||||
function notEqual(actual: any, expected: any, message?: string | Error): void;
|
||||
/** @deprecated since v9.9.0 - use deepStrictEqual() instead. */
|
||||
function deepEqual(actual: any, expected: any, message?: string | Error): void;
|
||||
/** @deprecated since v9.9.0 - use notDeepStrictEqual() instead. */
|
||||
function notDeepEqual(actual: any, expected: any, message?: string | Error): void;
|
||||
function strictEqual<T>(actual: any, expected: T, message?: string | Error): asserts actual is T;
|
||||
function notStrictEqual(actual: any, expected: any, message?: string | Error): void;
|
||||
function deepStrictEqual<T>(actual: any, expected: T, message?: string | Error): asserts actual is T;
|
||||
function notDeepStrictEqual(actual: any, expected: any, message?: string | Error): void;
|
||||
|
||||
function throws(block: () => any, message?: string | Error): void;
|
||||
function throws(block: () => any, error: AssertPredicate, message?: string | Error): void;
|
||||
function doesNotThrow(block: () => any, message?: string | Error): void;
|
||||
function doesNotThrow(block: () => any, error: AssertPredicate, message?: string | Error): void;
|
||||
|
||||
function ifError(value: any): asserts value is null | undefined;
|
||||
|
||||
function rejects(block: (() => Promise<any>) | Promise<any>, message?: string | Error): Promise<void>;
|
||||
function rejects(
|
||||
block: (() => Promise<any>) | Promise<any>,
|
||||
error: AssertPredicate,
|
||||
message?: string | Error,
|
||||
): Promise<void>;
|
||||
function doesNotReject(block: (() => Promise<any>) | Promise<any>, message?: string | Error): Promise<void>;
|
||||
function doesNotReject(
|
||||
block: (() => Promise<any>) | Promise<any>,
|
||||
error: AssertPredicate,
|
||||
message?: string | Error,
|
||||
): Promise<void>;
|
||||
|
||||
function match(value: string, regExp: RegExp, message?: string | Error): void;
|
||||
function doesNotMatch(value: string, regExp: RegExp, message?: string | Error): void;
|
||||
|
||||
const strict: Omit<
|
||||
typeof assert,
|
||||
| 'equal'
|
||||
| 'notEqual'
|
||||
| 'deepEqual'
|
||||
| 'notDeepEqual'
|
||||
| 'ok'
|
||||
| 'strictEqual'
|
||||
| 'deepStrictEqual'
|
||||
| 'ifError'
|
||||
| 'strict'
|
||||
> & {
|
||||
(value: any, message?: string | Error): asserts value;
|
||||
equal: typeof strictEqual;
|
||||
notEqual: typeof notStrictEqual;
|
||||
deepEqual: typeof deepStrictEqual;
|
||||
notDeepEqual: typeof notDeepStrictEqual;
|
||||
|
||||
// Mapped types and assertion functions are incompatible?
|
||||
// TS2775: Assertions require every name in the call target
|
||||
// to be declared with an explicit type annotation.
|
||||
ok: typeof ok;
|
||||
strictEqual: typeof strictEqual;
|
||||
deepStrictEqual: typeof deepStrictEqual;
|
||||
ifError: typeof ifError;
|
||||
strict: typeof strict;
|
||||
};
|
||||
}
|
||||
|
||||
export = assert;
|
||||
}
|
||||
229
packages/node_modules/@node-red/editor-client/src/types/node/async_hooks.d.ts
vendored
Normal file
229
packages/node_modules/@node-red/editor-client/src/types/node/async_hooks.d.ts
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
/**
|
||||
* Async Hooks module: https://nodejs.org/api/async_hooks.html
|
||||
*/
|
||||
declare module 'async_hooks' {
|
||||
/**
|
||||
* Returns the asyncId of the current execution context.
|
||||
*/
|
||||
function executionAsyncId(): number;
|
||||
|
||||
/**
|
||||
* The resource representing the current execution.
|
||||
* Useful to store data within the resource.
|
||||
*
|
||||
* Resource objects returned by `executionAsyncResource()` are most often internal
|
||||
* Node.js handle objects with undocumented APIs. Using any functions or properties
|
||||
* on the object is likely to crash your application and should be avoided.
|
||||
*
|
||||
* Using `executionAsyncResource()` in the top-level execution context will
|
||||
* return an empty object as there is no handle or request object to use,
|
||||
* but having an object representing the top-level can be helpful.
|
||||
*/
|
||||
function executionAsyncResource(): object;
|
||||
|
||||
/**
|
||||
* Returns the ID of the resource responsible for calling the callback that is currently being executed.
|
||||
*/
|
||||
function triggerAsyncId(): number;
|
||||
|
||||
interface HookCallbacks {
|
||||
/**
|
||||
* Called when a class is constructed that has the possibility to emit an asynchronous event.
|
||||
* @param asyncId a unique ID for the async resource
|
||||
* @param type the type of the async resource
|
||||
* @param triggerAsyncId the unique ID of the async resource in whose execution context this async resource was created
|
||||
* @param resource reference to the resource representing the async operation, needs to be released during destroy
|
||||
*/
|
||||
init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
|
||||
|
||||
/**
|
||||
* When an asynchronous operation is initiated or completes a callback is called to notify the user.
|
||||
* The before callback is called just before said callback is executed.
|
||||
* @param asyncId the unique identifier assigned to the resource about to execute the callback.
|
||||
*/
|
||||
before?(asyncId: number): void;
|
||||
|
||||
/**
|
||||
* Called immediately after the callback specified in before is completed.
|
||||
* @param asyncId the unique identifier assigned to the resource which has executed the callback.
|
||||
*/
|
||||
after?(asyncId: number): void;
|
||||
|
||||
/**
|
||||
* Called when a promise has resolve() called. This may not be in the same execution id
|
||||
* as the promise itself.
|
||||
* @param asyncId the unique id for the promise that was resolve()d.
|
||||
*/
|
||||
promiseResolve?(asyncId: number): void;
|
||||
|
||||
/**
|
||||
* Called after the resource corresponding to asyncId is destroyed
|
||||
* @param asyncId a unique ID for the async resource
|
||||
*/
|
||||
destroy?(asyncId: number): void;
|
||||
}
|
||||
|
||||
interface AsyncHook {
|
||||
/**
|
||||
* Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.
|
||||
*/
|
||||
enable(): this;
|
||||
|
||||
/**
|
||||
* Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.
|
||||
*/
|
||||
disable(): this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers functions to be called for different lifetime events of each async operation.
|
||||
* @param options the callbacks to register
|
||||
* @return an AsyncHooks instance used for disabling and enabling hooks
|
||||
*/
|
||||
function createHook(options: HookCallbacks): AsyncHook;
|
||||
|
||||
interface AsyncResourceOptions {
|
||||
/**
|
||||
* The ID of the execution context that created this async event.
|
||||
* @default executionAsyncId()
|
||||
*/
|
||||
triggerAsyncId?: number | undefined;
|
||||
|
||||
/**
|
||||
* Disables automatic `emitDestroy` when the object is garbage collected.
|
||||
* This usually does not need to be set (even if `emitDestroy` is called
|
||||
* manually), unless the resource's `asyncId` is retrieved and the
|
||||
* sensitive API's `emitDestroy` is called with it.
|
||||
* @default false
|
||||
*/
|
||||
requireManualDestroy?: boolean | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The class AsyncResource was designed to be extended by the embedder's async resources.
|
||||
* Using this users can easily trigger the lifetime events of their own resources.
|
||||
*/
|
||||
class AsyncResource {
|
||||
/**
|
||||
* AsyncResource() is meant to be extended. Instantiating a
|
||||
* new AsyncResource() also triggers init. If triggerAsyncId is omitted then
|
||||
* async_hook.executionAsyncId() is used.
|
||||
* @param type The type of async event.
|
||||
* @param triggerAsyncId The ID of the execution context that created
|
||||
* this async event (default: `executionAsyncId()`), or an
|
||||
* AsyncResourceOptions object (since 9.3)
|
||||
*/
|
||||
constructor(type: string, triggerAsyncId?: number|AsyncResourceOptions);
|
||||
|
||||
/**
|
||||
* Binds the given function to the current execution context.
|
||||
* @param fn The function to bind to the current execution context.
|
||||
* @param type An optional name to associate with the underlying `AsyncResource`.
|
||||
*/
|
||||
static bind<Func extends (...args: any[]) => any>(fn: Func, type?: string): Func & { asyncResource: AsyncResource };
|
||||
|
||||
/**
|
||||
* Binds the given function to execute to this `AsyncResource`'s scope.
|
||||
* @param fn The function to bind to the current `AsyncResource`.
|
||||
*/
|
||||
bind<Func extends (...args: any[]) => any>(fn: Func): Func & { asyncResource: AsyncResource };
|
||||
|
||||
/**
|
||||
* Call the provided function with the provided arguments in the
|
||||
* execution context of the async resource. This will establish the
|
||||
* context, trigger the AsyncHooks before callbacks, call the function,
|
||||
* trigger the AsyncHooks after callbacks, and then restore the original
|
||||
* execution context.
|
||||
* @param fn The function to call in the execution context of this
|
||||
* async resource.
|
||||
* @param thisArg The receiver to be used for the function call.
|
||||
* @param args Optional arguments to pass to the function.
|
||||
*/
|
||||
runInAsyncScope<This, Result>(fn: (this: This, ...args: any[]) => Result, thisArg?: This, ...args: any[]): Result;
|
||||
|
||||
/**
|
||||
* Call AsyncHooks destroy callbacks.
|
||||
*/
|
||||
emitDestroy(): this;
|
||||
|
||||
/**
|
||||
* @return the unique ID assigned to this AsyncResource instance.
|
||||
*/
|
||||
asyncId(): number;
|
||||
|
||||
/**
|
||||
* @return the trigger ID for this AsyncResource instance.
|
||||
*/
|
||||
triggerAsyncId(): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* When having multiple instances of `AsyncLocalStorage`, they are independent
|
||||
* from each other. It is safe to instantiate this class multiple times.
|
||||
*/
|
||||
class AsyncLocalStorage<T> {
|
||||
/**
|
||||
* This method disables the instance of `AsyncLocalStorage`. All subsequent calls
|
||||
* to `asyncLocalStorage.getStore()` will return `undefined` until
|
||||
* `asyncLocalStorage.run()` is called again.
|
||||
*
|
||||
* When calling `asyncLocalStorage.disable()`, all current contexts linked to the
|
||||
* instance will be exited.
|
||||
*
|
||||
* Calling `asyncLocalStorage.disable()` is required before the
|
||||
* `asyncLocalStorage` can be garbage collected. This does not apply to stores
|
||||
* provided by the `asyncLocalStorage`, as those objects are garbage collected
|
||||
* along with the corresponding async resources.
|
||||
*
|
||||
* This method is to be used when the `asyncLocalStorage` is not in use anymore
|
||||
* in the current process.
|
||||
*/
|
||||
disable(): void;
|
||||
|
||||
/**
|
||||
* This method returns the current store. If this method is called outside of an
|
||||
* asynchronous context initialized by calling `asyncLocalStorage.run`, it will
|
||||
* return `undefined`.
|
||||
*/
|
||||
getStore(): T | undefined;
|
||||
|
||||
/**
|
||||
* This methods runs a function synchronously within a context and return its
|
||||
* return value. The store is not accessible outside of the callback function or
|
||||
* the asynchronous operations created within the callback.
|
||||
*
|
||||
* Optionally, arguments can be passed to the function. They will be passed to the
|
||||
* callback function.
|
||||
*
|
||||
* I the callback function throws an error, it will be thrown by `run` too. The
|
||||
* stacktrace will not be impacted by this call and the context will be exited.
|
||||
*/
|
||||
// TODO: Apply generic vararg once available
|
||||
run<R>(store: T, callback: (...args: any[]) => R, ...args: any[]): R;
|
||||
|
||||
/**
|
||||
* This methods runs a function synchronously outside of a context and return its
|
||||
* return value. The store is not accessible within the callback function or the
|
||||
* asynchronous operations created within the callback.
|
||||
*
|
||||
* Optionally, arguments can be passed to the function. They will be passed to the
|
||||
* callback function.
|
||||
*
|
||||
* If the callback function throws an error, it will be thrown by `exit` too. The
|
||||
* stacktrace will not be impacted by this call and the context will be
|
||||
* re-entered.
|
||||
*/
|
||||
// TODO: Apply generic vararg once available
|
||||
exit<R>(callback: (...args: any[]) => R, ...args: any[]): R;
|
||||
|
||||
/**
|
||||
* Calling `asyncLocalStorage.enterWith(store)` will transition into the context
|
||||
* for the remainder of the current synchronous execution and will persist
|
||||
* through any following asynchronous calls.
|
||||
*/
|
||||
enterWith(store: T): void;
|
||||
}
|
||||
}
|
||||
@@ -1 +1,25 @@
|
||||
declare module'node:buffer'{export*from'buffer';}declare module'buffer'{export const INSPECT_MAX_BYTES:number;export const kMaxLength:number;export const kStringMaxLength:number;export const constants:{MAX_LENGTH:number;MAX_STRING_LENGTH:number;};const BuffType:typeof Buffer;export type TranscodeEncoding="ascii"|"utf8"|"utf16le"|"ucs2"|"latin1"|"binary";export function transcode(source:Uint8Array,fromEnc:TranscodeEncoding,toEnc:TranscodeEncoding):Buffer;export const SlowBuffer:{new(size:number):Buffer;prototype:Buffer;};export{BuffType as Buffer};}
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'buffer' {
|
||||
export const INSPECT_MAX_BYTES: number;
|
||||
export const kMaxLength: number;
|
||||
export const kStringMaxLength: number;
|
||||
export const constants: {
|
||||
MAX_LENGTH: number;
|
||||
MAX_STRING_LENGTH: number;
|
||||
};
|
||||
const BuffType: typeof Buffer;
|
||||
|
||||
export type TranscodeEncoding = "ascii" | "utf8" | "utf16le" | "ucs2" | "latin1" | "binary";
|
||||
|
||||
export function transcode(source: Uint8Array, fromEnc: TranscodeEncoding, toEnc: TranscodeEncoding): Buffer;
|
||||
|
||||
export const SlowBuffer: {
|
||||
/** @deprecated since v6.0.0, use `Buffer.allocUnsafeSlow()` */
|
||||
new(size: number): Buffer;
|
||||
prototype: Buffer;
|
||||
};
|
||||
|
||||
export { BuffType as Buffer };
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
265
packages/node_modules/@node-red/editor-client/src/types/node/cluster.d.ts
vendored
Normal file
265
packages/node_modules/@node-red/editor-client/src/types/node/cluster.d.ts
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'cluster' {
|
||||
import * as child from 'child_process';
|
||||
import EventEmitter = require('events');
|
||||
import * as net from 'net';
|
||||
|
||||
// interfaces
|
||||
interface ClusterSettings {
|
||||
execArgv?: string[] | undefined; // default: process.execArgv
|
||||
exec?: string | undefined;
|
||||
args?: string[] | undefined;
|
||||
silent?: boolean | undefined;
|
||||
stdio?: any[] | undefined;
|
||||
uid?: number | undefined;
|
||||
gid?: number | undefined;
|
||||
inspectPort?: number | (() => number) | undefined;
|
||||
}
|
||||
|
||||
interface Address {
|
||||
address: string;
|
||||
port: number;
|
||||
addressType: number | "udp4" | "udp6"; // 4, 6, -1, "udp4", "udp6"
|
||||
}
|
||||
|
||||
class Worker extends EventEmitter {
|
||||
id: number;
|
||||
process: child.ChildProcess;
|
||||
send(message: child.Serializable, sendHandle?: child.SendHandle, callback?: (error: Error | null) => void): boolean;
|
||||
kill(signal?: string): void;
|
||||
destroy(signal?: string): void;
|
||||
disconnect(): void;
|
||||
isConnected(): boolean;
|
||||
isDead(): boolean;
|
||||
exitedAfterDisconnect: boolean;
|
||||
|
||||
/**
|
||||
* events.EventEmitter
|
||||
* 1. disconnect
|
||||
* 2. error
|
||||
* 3. exit
|
||||
* 4. listening
|
||||
* 5. message
|
||||
* 6. online
|
||||
*/
|
||||
addListener(event: string, listener: (...args: any[]) => void): this;
|
||||
addListener(event: "disconnect", listener: () => void): this;
|
||||
addListener(event: "error", listener: (error: Error) => void): this;
|
||||
addListener(event: "exit", listener: (code: number, signal: string) => void): this;
|
||||
addListener(event: "listening", listener: (address: Address) => void): this;
|
||||
addListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
addListener(event: "online", listener: () => void): this;
|
||||
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
emit(event: "disconnect"): boolean;
|
||||
emit(event: "error", error: Error): boolean;
|
||||
emit(event: "exit", code: number, signal: string): boolean;
|
||||
emit(event: "listening", address: Address): boolean;
|
||||
emit(event: "message", message: any, handle: net.Socket | net.Server): boolean;
|
||||
emit(event: "online"): boolean;
|
||||
|
||||
on(event: string, listener: (...args: any[]) => void): this;
|
||||
on(event: "disconnect", listener: () => void): this;
|
||||
on(event: "error", listener: (error: Error) => void): this;
|
||||
on(event: "exit", listener: (code: number, signal: string) => void): this;
|
||||
on(event: "listening", listener: (address: Address) => void): this;
|
||||
on(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
on(event: "online", listener: () => void): this;
|
||||
|
||||
once(event: string, listener: (...args: any[]) => void): this;
|
||||
once(event: "disconnect", listener: () => void): this;
|
||||
once(event: "error", listener: (error: Error) => void): this;
|
||||
once(event: "exit", listener: (code: number, signal: string) => void): this;
|
||||
once(event: "listening", listener: (address: Address) => void): this;
|
||||
once(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
once(event: "online", listener: () => void): this;
|
||||
|
||||
prependListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependListener(event: "disconnect", listener: () => void): this;
|
||||
prependListener(event: "error", listener: (error: Error) => void): this;
|
||||
prependListener(event: "exit", listener: (code: number, signal: string) => void): this;
|
||||
prependListener(event: "listening", listener: (address: Address) => void): this;
|
||||
prependListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
prependListener(event: "online", listener: () => void): this;
|
||||
|
||||
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependOnceListener(event: "disconnect", listener: () => void): this;
|
||||
prependOnceListener(event: "error", listener: (error: Error) => void): this;
|
||||
prependOnceListener(event: "exit", listener: (code: number, signal: string) => void): this;
|
||||
prependOnceListener(event: "listening", listener: (address: Address) => void): this;
|
||||
prependOnceListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
prependOnceListener(event: "online", listener: () => void): this;
|
||||
}
|
||||
|
||||
interface Cluster extends EventEmitter {
|
||||
Worker: Worker;
|
||||
disconnect(callback?: () => void): void;
|
||||
fork(env?: any): Worker;
|
||||
isMaster: boolean;
|
||||
isWorker: boolean;
|
||||
schedulingPolicy: number;
|
||||
settings: ClusterSettings;
|
||||
setupMaster(settings?: ClusterSettings): void;
|
||||
worker?: Worker | undefined;
|
||||
workers?: NodeJS.Dict<Worker> | undefined;
|
||||
|
||||
readonly SCHED_NONE: number;
|
||||
readonly SCHED_RR: number;
|
||||
|
||||
/**
|
||||
* events.EventEmitter
|
||||
* 1. disconnect
|
||||
* 2. exit
|
||||
* 3. fork
|
||||
* 4. listening
|
||||
* 5. message
|
||||
* 6. online
|
||||
* 7. setup
|
||||
*/
|
||||
addListener(event: string, listener: (...args: any[]) => void): this;
|
||||
addListener(event: "disconnect", listener: (worker: Worker) => void): this;
|
||||
addListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
|
||||
addListener(event: "fork", listener: (worker: Worker) => void): this;
|
||||
addListener(event: "listening", listener: (worker: Worker, address: Address) => void): this;
|
||||
addListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
addListener(event: "online", listener: (worker: Worker) => void): this;
|
||||
addListener(event: "setup", listener: (settings: ClusterSettings) => void): this;
|
||||
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
emit(event: "disconnect", worker: Worker): boolean;
|
||||
emit(event: "exit", worker: Worker, code: number, signal: string): boolean;
|
||||
emit(event: "fork", worker: Worker): boolean;
|
||||
emit(event: "listening", worker: Worker, address: Address): boolean;
|
||||
emit(event: "message", worker: Worker, message: any, handle: net.Socket | net.Server): boolean;
|
||||
emit(event: "online", worker: Worker): boolean;
|
||||
emit(event: "setup", settings: ClusterSettings): boolean;
|
||||
|
||||
on(event: string, listener: (...args: any[]) => void): this;
|
||||
on(event: "disconnect", listener: (worker: Worker) => void): this;
|
||||
on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
|
||||
on(event: "fork", listener: (worker: Worker) => void): this;
|
||||
on(event: "listening", listener: (worker: Worker, address: Address) => void): this;
|
||||
on(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
on(event: "online", listener: (worker: Worker) => void): this;
|
||||
on(event: "setup", listener: (settings: ClusterSettings) => void): this;
|
||||
|
||||
once(event: string, listener: (...args: any[]) => void): this;
|
||||
once(event: "disconnect", listener: (worker: Worker) => void): this;
|
||||
once(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
|
||||
once(event: "fork", listener: (worker: Worker) => void): this;
|
||||
once(event: "listening", listener: (worker: Worker, address: Address) => void): this;
|
||||
once(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
once(event: "online", listener: (worker: Worker) => void): this;
|
||||
once(event: "setup", listener: (settings: ClusterSettings) => void): this;
|
||||
|
||||
prependListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependListener(event: "disconnect", listener: (worker: Worker) => void): this;
|
||||
prependListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
|
||||
prependListener(event: "fork", listener: (worker: Worker) => void): this;
|
||||
prependListener(event: "listening", listener: (worker: Worker, address: Address) => void): this;
|
||||
prependListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
prependListener(event: "online", listener: (worker: Worker) => void): this;
|
||||
prependListener(event: "setup", listener: (settings: ClusterSettings) => void): this;
|
||||
|
||||
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependOnceListener(event: "disconnect", listener: (worker: Worker) => void): this;
|
||||
prependOnceListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this;
|
||||
prependOnceListener(event: "fork", listener: (worker: Worker) => void): this;
|
||||
prependOnceListener(event: "listening", listener: (worker: Worker, address: Address) => void): this;
|
||||
// the handle is a net.Socket or net.Server object, or undefined.
|
||||
prependOnceListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this;
|
||||
prependOnceListener(event: "online", listener: (worker: Worker) => void): this;
|
||||
prependOnceListener(event: "setup", listener: (settings: ClusterSettings) => void): this;
|
||||
}
|
||||
|
||||
const SCHED_NONE: number;
|
||||
const SCHED_RR: number;
|
||||
|
||||
function disconnect(callback?: () => void): void;
|
||||
function fork(env?: any): Worker;
|
||||
const isMaster: boolean;
|
||||
const isWorker: boolean;
|
||||
let schedulingPolicy: number;
|
||||
const settings: ClusterSettings;
|
||||
function setupMaster(settings?: ClusterSettings): void;
|
||||
const worker: Worker;
|
||||
const workers: NodeJS.Dict<Worker>;
|
||||
|
||||
/**
|
||||
* events.EventEmitter
|
||||
* 1. disconnect
|
||||
* 2. exit
|
||||
* 3. fork
|
||||
* 4. listening
|
||||
* 5. message
|
||||
* 6. online
|
||||
* 7. setup
|
||||
*/
|
||||
function addListener(event: string, listener: (...args: any[]) => void): Cluster;
|
||||
function addListener(event: "disconnect", listener: (worker: Worker) => void): Cluster;
|
||||
function addListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
|
||||
function addListener(event: "fork", listener: (worker: Worker) => void): Cluster;
|
||||
function addListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
|
||||
// the handle is a net.Socket or net.Server object, or undefined.
|
||||
function addListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;
|
||||
function addListener(event: "online", listener: (worker: Worker) => void): Cluster;
|
||||
function addListener(event: "setup", listener: (settings: ClusterSettings) => void): Cluster;
|
||||
|
||||
function emit(event: string | symbol, ...args: any[]): boolean;
|
||||
function emit(event: "disconnect", worker: Worker): boolean;
|
||||
function emit(event: "exit", worker: Worker, code: number, signal: string): boolean;
|
||||
function emit(event: "fork", worker: Worker): boolean;
|
||||
function emit(event: "listening", worker: Worker, address: Address): boolean;
|
||||
function emit(event: "message", worker: Worker, message: any, handle: net.Socket | net.Server): boolean;
|
||||
function emit(event: "online", worker: Worker): boolean;
|
||||
function emit(event: "setup", settings: ClusterSettings): boolean;
|
||||
|
||||
function on(event: string, listener: (...args: any[]) => void): Cluster;
|
||||
function on(event: "disconnect", listener: (worker: Worker) => void): Cluster;
|
||||
function on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
|
||||
function on(event: "fork", listener: (worker: Worker) => void): Cluster;
|
||||
function on(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
|
||||
function on(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
function on(event: "online", listener: (worker: Worker) => void): Cluster;
|
||||
function on(event: "setup", listener: (settings: ClusterSettings) => void): Cluster;
|
||||
|
||||
function once(event: string, listener: (...args: any[]) => void): Cluster;
|
||||
function once(event: "disconnect", listener: (worker: Worker) => void): Cluster;
|
||||
function once(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
|
||||
function once(event: "fork", listener: (worker: Worker) => void): Cluster;
|
||||
function once(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
|
||||
function once(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster; // the handle is a net.Socket or net.Server object, or undefined.
|
||||
function once(event: "online", listener: (worker: Worker) => void): Cluster;
|
||||
function once(event: "setup", listener: (settings: ClusterSettings) => void): Cluster;
|
||||
|
||||
function removeListener(event: string, listener: (...args: any[]) => void): Cluster;
|
||||
function removeAllListeners(event?: string): Cluster;
|
||||
function setMaxListeners(n: number): Cluster;
|
||||
function getMaxListeners(): number;
|
||||
function listeners(event: string): Function[];
|
||||
function listenerCount(type: string): number;
|
||||
|
||||
function prependListener(event: string, listener: (...args: any[]) => void): Cluster;
|
||||
function prependListener(event: "disconnect", listener: (worker: Worker) => void): Cluster;
|
||||
function prependListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
|
||||
function prependListener(event: "fork", listener: (worker: Worker) => void): Cluster;
|
||||
function prependListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
|
||||
// the handle is a net.Socket or net.Server object, or undefined.
|
||||
function prependListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;
|
||||
function prependListener(event: "online", listener: (worker: Worker) => void): Cluster;
|
||||
function prependListener(event: "setup", listener: (settings: ClusterSettings) => void): Cluster;
|
||||
|
||||
function prependOnceListener(event: string, listener: (...args: any[]) => void): Cluster;
|
||||
function prependOnceListener(event: "disconnect", listener: (worker: Worker) => void): Cluster;
|
||||
function prependOnceListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster;
|
||||
function prependOnceListener(event: "fork", listener: (worker: Worker) => void): Cluster;
|
||||
function prependOnceListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster;
|
||||
// the handle is a net.Socket or net.Server object, or undefined.
|
||||
function prependOnceListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster;
|
||||
function prependOnceListener(event: "online", listener: (worker: Worker) => void): Cluster;
|
||||
function prependOnceListener(event: "setup", listener: (settings: ClusterSettings) => void): Cluster;
|
||||
|
||||
function eventNames(): string[];
|
||||
}
|
||||
@@ -1 +1,136 @@
|
||||
declare module'node:console'{export=console;}declare module'console'{import{InspectOptions}from'node:util';global{interface Console{Console:NodeJS.ConsoleConstructor;assert(value:any,message?:string,...optionalParams:any[]):void;clear():void;count(label?:string):void;countReset(label?:string):void;debug(message?:any,...optionalParams:any[]):void;dir(obj:any,options?:InspectOptions):void;dirxml(...data:any[]):void;error(message?:any,...optionalParams:any[]):void;group(...label:any[]):void;groupCollapsed(...label:any[]):void;groupEnd():void;info(message?:any,...optionalParams:any[]):void;log(message?:any,...optionalParams:any[]):void;table(tabularData:any,properties?:ReadonlyArray<string>):void;time(label?:string):void;timeEnd(label?:string):void;timeLog(label?:string,...data:any[]):void;trace(message?:any,...optionalParams:any[]):void;warn(message?:any,...optionalParams:any[]):void;profile(label?:string):void;profileEnd(label?:string):void;timeStamp(label?:string):void;}var console:Console;namespace NodeJS{interface ConsoleConstructorOptions{stdout:WritableStream;stderr?:WritableStream;ignoreErrors?:boolean;colorMode?:boolean|'auto';inspectOptions?:InspectOptions;}interface ConsoleConstructor{prototype:Console;new(stdout:WritableStream,stderr?:WritableStream,ignoreErrors?:boolean):Console;new(options:ConsoleConstructorOptions):Console;}interface Global{console:typeof console;}}}export=console;}
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'console' {
|
||||
import { InspectOptions } from 'util';
|
||||
|
||||
global {
|
||||
// This needs to be global to avoid TS2403 in case lib.dom.d.ts is present in the same build
|
||||
interface Console {
|
||||
Console: NodeJS.ConsoleConstructor;
|
||||
/**
|
||||
* A simple assertion test that verifies whether `value` is truthy.
|
||||
* If it is not, an `AssertionError` is thrown.
|
||||
* If provided, the error `message` is formatted using `util.format()` and used as the error message.
|
||||
*/
|
||||
assert(value: any, message?: string, ...optionalParams: any[]): void;
|
||||
/**
|
||||
* When `stdout` is a TTY, calling `console.clear()` will attempt to clear the TTY.
|
||||
* When `stdout` is not a TTY, this method does nothing.
|
||||
*/
|
||||
clear(): void;
|
||||
/**
|
||||
* Maintains an internal counter specific to `label` and outputs to `stdout` the number of times `console.count()` has been called with the given `label`.
|
||||
*/
|
||||
count(label?: string): void;
|
||||
/**
|
||||
* Resets the internal counter specific to `label`.
|
||||
*/
|
||||
countReset(label?: string): void;
|
||||
/**
|
||||
* The `console.debug()` function is an alias for {@link console.log}.
|
||||
*/
|
||||
debug(message?: any, ...optionalParams: any[]): void;
|
||||
/**
|
||||
* Uses {@link util.inspect} on `obj` and prints the resulting string to `stdout`.
|
||||
* This function bypasses any custom `inspect()` function defined on `obj`.
|
||||
*/
|
||||
dir(obj: any, options?: InspectOptions): void;
|
||||
/**
|
||||
* This method calls {@link console.log} passing it the arguments received. Please note that this method does not produce any XML formatting
|
||||
*/
|
||||
dirxml(...data: any[]): void;
|
||||
/**
|
||||
* Prints to `stderr` with newline.
|
||||
*/
|
||||
error(message?: any, ...optionalParams: any[]): void;
|
||||
/**
|
||||
* Increases indentation of subsequent lines by two spaces.
|
||||
* If one or more `label`s are provided, those are printed first without the additional indentation.
|
||||
*/
|
||||
group(...label: any[]): void;
|
||||
/**
|
||||
* The `console.groupCollapsed()` function is an alias for {@link console.group}.
|
||||
*/
|
||||
groupCollapsed(...label: any[]): void;
|
||||
/**
|
||||
* Decreases indentation of subsequent lines by two spaces.
|
||||
*/
|
||||
groupEnd(): void;
|
||||
/**
|
||||
* The {@link console.info} function is an alias for {@link console.log}.
|
||||
*/
|
||||
info(message?: any, ...optionalParams: any[]): void;
|
||||
/**
|
||||
* Prints to `stdout` with newline.
|
||||
*/
|
||||
log(message?: any, ...optionalParams: any[]): void;
|
||||
/**
|
||||
* This method does not display anything unless used in the inspector.
|
||||
* Prints to `stdout` the array `array` formatted as a table.
|
||||
*/
|
||||
table(tabularData: any, properties?: ReadonlyArray<string>): void;
|
||||
/**
|
||||
* Starts a timer that can be used to compute the duration of an operation. Timers are identified by a unique `label`.
|
||||
*/
|
||||
time(label?: string): void;
|
||||
/**
|
||||
* Stops a timer that was previously started by calling {@link console.time} and prints the result to `stdout`.
|
||||
*/
|
||||
timeEnd(label?: string): void;
|
||||
/**
|
||||
* For a timer that was previously started by calling {@link console.time}, prints the elapsed time and other `data` arguments to `stdout`.
|
||||
*/
|
||||
timeLog(label?: string, ...data: any[]): void;
|
||||
/**
|
||||
* Prints to `stderr` the string 'Trace :', followed by the {@link util.format} formatted message and stack trace to the current position in the code.
|
||||
*/
|
||||
trace(message?: any, ...optionalParams: any[]): void;
|
||||
/**
|
||||
* The {@link console.warn} function is an alias for {@link console.error}.
|
||||
*/
|
||||
warn(message?: any, ...optionalParams: any[]): void;
|
||||
|
||||
// --- Inspector mode only ---
|
||||
/**
|
||||
* This method does not display anything unless used in the inspector.
|
||||
* Starts a JavaScript CPU profile with an optional label.
|
||||
*/
|
||||
profile(label?: string): void;
|
||||
/**
|
||||
* This method does not display anything unless used in the inspector.
|
||||
* Stops the current JavaScript CPU profiling session if one has been started and prints the report to the Profiles panel of the inspector.
|
||||
*/
|
||||
profileEnd(label?: string): void;
|
||||
/**
|
||||
* This method does not display anything unless used in the inspector.
|
||||
* Adds an event with the label `label` to the Timeline panel of the inspector.
|
||||
*/
|
||||
timeStamp(label?: string): void;
|
||||
}
|
||||
|
||||
var console: Console;
|
||||
|
||||
namespace NodeJS {
|
||||
interface ConsoleConstructorOptions {
|
||||
stdout: WritableStream;
|
||||
stderr?: WritableStream | undefined;
|
||||
ignoreErrors?: boolean | undefined;
|
||||
colorMode?: boolean | 'auto' | undefined;
|
||||
inspectOptions?: InspectOptions | undefined;
|
||||
}
|
||||
|
||||
interface ConsoleConstructor {
|
||||
prototype: Console;
|
||||
new(stdout: WritableStream, stderr?: WritableStream, ignoreErrors?: boolean): Console;
|
||||
new(options: ConsoleConstructorOptions): Console;
|
||||
}
|
||||
|
||||
interface Global {
|
||||
console: typeof console;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export = console;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1,144 @@
|
||||
declare module'node:dgram'{export*from'dgram';}declare module'dgram'{import{AddressInfo}from'node:net';import*as dns from'node:dns';import EventEmitter=require('node:events');interface RemoteInfo{address:string;family:'IPv4'|'IPv6';port:number;size:number;}interface BindOptions{port?:number;address?:string;exclusive?:boolean;fd?:number;}type SocketType="udp4"|"udp6";interface SocketOptions{type:SocketType;reuseAddr?:boolean;ipv6Only?:boolean;recvBufferSize?:number;sendBufferSize?:number;lookup?:(hostname:string,options:dns.LookupOneOptions,callback:(err:NodeJS.ErrnoException|null,address:string,family:number)=>void)=>void;}function createSocket(type:SocketType,callback?:(msg:Buffer,rinfo:RemoteInfo)=>void):Socket;function createSocket(options:SocketOptions,callback?:(msg:Buffer,rinfo:RemoteInfo)=>void):Socket;class Socket extends EventEmitter{addMembership(multicastAddress:string,multicastInterface?:string):void;address():AddressInfo;bind(port?:number,address?:string,callback?:()=>void):void;bind(port?:number,callback?:()=>void):void;bind(callback?:()=>void):void;bind(options:BindOptions,callback?:()=>void):void;close(callback?:()=>void):void;connect(port:number,address?:string,callback?:()=>void):void;connect(port:number,callback:()=>void):void;disconnect():void;dropMembership(multicastAddress:string,multicastInterface?:string):void;getRecvBufferSize():number;getSendBufferSize():number;ref():this;remoteAddress():AddressInfo;send(msg:string|Uint8Array|ReadonlyArray<any>,port?:number,address?:string,callback?:(error:Error|null,bytes:number)=>void):void;send(msg:string|Uint8Array|ReadonlyArray<any>,port?:number,callback?:(error:Error|null,bytes:number)=>void):void;send(msg:string|Uint8Array|ReadonlyArray<any>,callback?:(error:Error|null,bytes:number)=>void):void;send(msg:string|Uint8Array,offset:number,length:number,port?:number,address?:string,callback?:(error:Error|null,bytes:number)=>void):void;send(msg:string|Uint8Array,offset:number,length:number,port?:number,callback?:(error:Error|null,bytes:number)=>void):void;send(msg:string|Uint8Array,offset:number,length:number,callback?:(error:Error|null,bytes:number)=>void):void;setBroadcast(flag:boolean):void;setMulticastInterface(multicastInterface:string):void;setMulticastLoopback(flag:boolean):void;setMulticastTTL(ttl:number):void;setRecvBufferSize(size:number):void;setSendBufferSize(size:number):void;setTTL(ttl:number):void;unref():this;addSourceSpecificMembership(sourceAddress:string,groupAddress:string,multicastInterface?:string):void;dropSourceSpecificMembership(sourceAddress:string,groupAddress:string,multicastInterface?:string):void;addListener(event:string,listener:(...args:any[])=>void):this;addListener(event:"close",listener:()=>void):this;addListener(event:"connect",listener:()=>void):this;addListener(event:"error",listener:(err:Error)=>void):this;addListener(event:"listening",listener:()=>void):this;addListener(event:"message",listener:(msg:Buffer,rinfo:RemoteInfo)=>void):this;emit(event:string|symbol,...args:any[]):boolean;emit(event:"close"):boolean;emit(event:"connect"):boolean;emit(event:"error",err:Error):boolean;emit(event:"listening"):boolean;emit(event:"message",msg:Buffer,rinfo:RemoteInfo):boolean;on(event:string,listener:(...args:any[])=>void):this;on(event:"close",listener:()=>void):this;on(event:"connect",listener:()=>void):this;on(event:"error",listener:(err:Error)=>void):this;on(event:"listening",listener:()=>void):this;on(event:"message",listener:(msg:Buffer,rinfo:RemoteInfo)=>void):this;once(event:string,listener:(...args:any[])=>void):this;once(event:"close",listener:()=>void):this;once(event:"connect",listener:()=>void):this;once(event:"error",listener:(err:Error)=>void):this;once(event:"listening",listener:()=>void):this;once(event:"message",listener:(msg:Buffer,rinfo:RemoteInfo)=>void):this;prependListener(event:string,listener:(...args:any[])=>void):this;prependListener(event:"close",listener:()=>void):this;prependListener(event:"connect",listener:()=>void):this;prependListener(event:"error",listener:(err:Error)=>void):this;prependListener(event:"listening",listener:()=>void):this;prependListener(event:"message",listener:(msg:Buffer,rinfo:RemoteInfo)=>void):this;prependOnceListener(event:string,listener:(...args:any[])=>void):this;prependOnceListener(event:"close",listener:()=>void):this;prependOnceListener(event:"connect",listener:()=>void):this;prependOnceListener(event:"error",listener:(err:Error)=>void):this;prependOnceListener(event:"listening",listener:()=>void):this;prependOnceListener(event:"message",listener:(msg:Buffer,rinfo:RemoteInfo)=>void):this;}}
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'dgram' {
|
||||
import { AddressInfo } from 'net';
|
||||
import * as dns from 'dns';
|
||||
import EventEmitter = require('events');
|
||||
|
||||
interface RemoteInfo {
|
||||
address: string;
|
||||
family: 'IPv4' | 'IPv6';
|
||||
port: number;
|
||||
size: number;
|
||||
}
|
||||
|
||||
interface BindOptions {
|
||||
port?: number | undefined;
|
||||
address?: string | undefined;
|
||||
exclusive?: boolean | undefined;
|
||||
fd?: number | undefined;
|
||||
}
|
||||
|
||||
type SocketType = "udp4" | "udp6";
|
||||
|
||||
interface SocketOptions {
|
||||
type: SocketType;
|
||||
reuseAddr?: boolean | undefined;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
ipv6Only?: boolean | undefined;
|
||||
recvBufferSize?: number | undefined;
|
||||
sendBufferSize?: number | undefined;
|
||||
lookup?: ((hostname: string, options: dns.LookupOneOptions, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void) => void) | undefined;
|
||||
}
|
||||
|
||||
function createSocket(type: SocketType, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket;
|
||||
function createSocket(options: SocketOptions, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket;
|
||||
|
||||
class Socket extends EventEmitter {
|
||||
addMembership(multicastAddress: string, multicastInterface?: string): void;
|
||||
address(): AddressInfo;
|
||||
bind(port?: number, address?: string, callback?: () => void): void;
|
||||
bind(port?: number, callback?: () => void): void;
|
||||
bind(callback?: () => void): void;
|
||||
bind(options: BindOptions, callback?: () => void): void;
|
||||
close(callback?: () => void): void;
|
||||
connect(port: number, address?: string, callback?: () => void): void;
|
||||
connect(port: number, callback: () => void): void;
|
||||
disconnect(): void;
|
||||
dropMembership(multicastAddress: string, multicastInterface?: string): void;
|
||||
getRecvBufferSize(): number;
|
||||
getSendBufferSize(): number;
|
||||
ref(): this;
|
||||
remoteAddress(): AddressInfo;
|
||||
send(msg: string | Uint8Array | ReadonlyArray<any>, port?: number, address?: string, callback?: (error: Error | null, bytes: number) => void): void;
|
||||
send(msg: string | Uint8Array | ReadonlyArray<any>, port?: number, callback?: (error: Error | null, bytes: number) => void): void;
|
||||
send(msg: string | Uint8Array | ReadonlyArray<any>, callback?: (error: Error | null, bytes: number) => void): void;
|
||||
send(msg: string | Uint8Array, offset: number, length: number, port?: number, address?: string, callback?: (error: Error | null, bytes: number) => void): void;
|
||||
send(msg: string | Uint8Array, offset: number, length: number, port?: number, callback?: (error: Error | null, bytes: number) => void): void;
|
||||
send(msg: string | Uint8Array, offset: number, length: number, callback?: (error: Error | null, bytes: number) => void): void;
|
||||
setBroadcast(flag: boolean): void;
|
||||
setMulticastInterface(multicastInterface: string): void;
|
||||
setMulticastLoopback(flag: boolean): void;
|
||||
setMulticastTTL(ttl: number): void;
|
||||
setRecvBufferSize(size: number): void;
|
||||
setSendBufferSize(size: number): void;
|
||||
setTTL(ttl: number): void;
|
||||
unref(): this;
|
||||
/**
|
||||
* Tells the kernel to join a source-specific multicast channel at the given
|
||||
* `sourceAddress` and `groupAddress`, using the `multicastInterface` with the
|
||||
* `IP_ADD_SOURCE_MEMBERSHIP` socket option.
|
||||
* If the `multicastInterface` argument
|
||||
* is not specified, the operating system will choose one interface and will add
|
||||
* membership to it.
|
||||
* To add membership to every available interface, call
|
||||
* `socket.addSourceSpecificMembership()` multiple times, once per interface.
|
||||
*/
|
||||
addSourceSpecificMembership(sourceAddress: string, groupAddress: string, multicastInterface?: string): void;
|
||||
|
||||
/**
|
||||
* Instructs the kernel to leave a source-specific multicast channel at the given
|
||||
* `sourceAddress` and `groupAddress` using the `IP_DROP_SOURCE_MEMBERSHIP`
|
||||
* socket option. This method is automatically called by the kernel when the
|
||||
* socket is closed or the process terminates, so most apps will never have
|
||||
* reason to call this.
|
||||
*
|
||||
* If `multicastInterface` is not specified, the operating system will attempt to
|
||||
* drop membership on all valid interfaces.
|
||||
*/
|
||||
dropSourceSpecificMembership(sourceAddress: string, groupAddress: string, multicastInterface?: string): void;
|
||||
|
||||
/**
|
||||
* events.EventEmitter
|
||||
* 1. close
|
||||
* 2. connect
|
||||
* 3. error
|
||||
* 4. listening
|
||||
* 5. message
|
||||
*/
|
||||
addListener(event: string, listener: (...args: any[]) => void): this;
|
||||
addListener(event: "close", listener: () => void): this;
|
||||
addListener(event: "connect", listener: () => void): this;
|
||||
addListener(event: "error", listener: (err: Error) => void): this;
|
||||
addListener(event: "listening", listener: () => void): this;
|
||||
addListener(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this;
|
||||
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
emit(event: "close"): boolean;
|
||||
emit(event: "connect"): boolean;
|
||||
emit(event: "error", err: Error): boolean;
|
||||
emit(event: "listening"): boolean;
|
||||
emit(event: "message", msg: Buffer, rinfo: RemoteInfo): boolean;
|
||||
|
||||
on(event: string, listener: (...args: any[]) => void): this;
|
||||
on(event: "close", listener: () => void): this;
|
||||
on(event: "connect", listener: () => void): this;
|
||||
on(event: "error", listener: (err: Error) => void): this;
|
||||
on(event: "listening", listener: () => void): this;
|
||||
on(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this;
|
||||
|
||||
once(event: string, listener: (...args: any[]) => void): this;
|
||||
once(event: "close", listener: () => void): this;
|
||||
once(event: "connect", listener: () => void): this;
|
||||
once(event: "error", listener: (err: Error) => void): this;
|
||||
once(event: "listening", listener: () => void): this;
|
||||
once(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this;
|
||||
|
||||
prependListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependListener(event: "close", listener: () => void): this;
|
||||
prependListener(event: "connect", listener: () => void): this;
|
||||
prependListener(event: "error", listener: (err: Error) => void): this;
|
||||
prependListener(event: "listening", listener: () => void): this;
|
||||
prependListener(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this;
|
||||
|
||||
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
|
||||
prependOnceListener(event: "close", listener: () => void): this;
|
||||
prependOnceListener(event: "connect", listener: () => void): this;
|
||||
prependOnceListener(event: "error", listener: (err: Error) => void): this;
|
||||
prependOnceListener(event: "listening", listener: () => void): this;
|
||||
prependOnceListener(event: "message", listener: (msg: Buffer, rinfo: RemoteInfo) => void): this;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1,27 @@
|
||||
declare module'node:domain'{export*from'domain';}declare module'domain'{import EventEmitter=require('node:events');global{namespace NodeJS{interface Domain extends EventEmitter{run<T>(fn:(...args:any[])=>T,...args:any[]):T;add(emitter:EventEmitter|Timer):void;remove(emitter:EventEmitter|Timer):void;bind<T extends Function>(cb:T):T;intercept<T extends Function>(cb:T):T;}}}interface Domain extends NodeJS.Domain{}class Domain extends EventEmitter{members:Array<EventEmitter|NodeJS.Timer>;enter():void;exit():void;}function create():Domain;}
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'domain' {
|
||||
import EventEmitter = require('events');
|
||||
|
||||
global {
|
||||
namespace NodeJS {
|
||||
interface Domain extends EventEmitter {
|
||||
run<T>(fn: (...args: any[]) => T, ...args: any[]): T;
|
||||
add(emitter: EventEmitter | Timer): void;
|
||||
remove(emitter: EventEmitter | Timer): void;
|
||||
bind<T extends Function>(cb: T): T;
|
||||
intercept<T extends Function>(cb: T): T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Domain extends NodeJS.Domain {}
|
||||
class Domain extends EventEmitter {
|
||||
members: Array<EventEmitter | NodeJS.Timer>;
|
||||
enter(): void;
|
||||
exit(): void;
|
||||
}
|
||||
|
||||
function create(): Domain;
|
||||
}
|
||||
|
||||
@@ -1 +1,81 @@
|
||||
declare module'node:events'{import EventEmitter=require('events');export=EventEmitter;}declare module'events'{interface EventEmitterOptions{captureRejections?:boolean;}interface NodeEventTarget{once(event:string|symbol,listener:(...args:any[])=>void):this;}interface DOMEventTarget{addEventListener(event:string,listener:(...args:any[])=>void,opts?:{once:boolean}):any;}interface EventEmitter extends NodeJS.EventEmitter{}class EventEmitter{constructor(options?:EventEmitterOptions);static once(emitter:NodeEventTarget,event:string|symbol):Promise<any[]>;static once(emitter:DOMEventTarget,event:string):Promise<any[]>;static on(emitter:NodeJS.EventEmitter,event:string):AsyncIterableIterator<any>;static listenerCount(emitter:NodeJS.EventEmitter,event:string|symbol):number;static readonly errorMonitor:unique symbol;static readonly captureRejectionSymbol:unique symbol;static captureRejections:boolean;static defaultMaxListeners:number;}import internal=require('events');namespace EventEmitter{export{internal as EventEmitter};}global{namespace NodeJS{interface EventEmitter{addListener(event:string|symbol,listener:(...args:any[])=>void):this;on(event:string|symbol,listener:(...args:any[])=>void):this;once(event:string|symbol,listener:(...args:any[])=>void):this;removeListener(event:string|symbol,listener:(...args:any[])=>void):this;off(event:string|symbol,listener:(...args:any[])=>void):this;removeAllListeners(event?:string|symbol):this;setMaxListeners(n:number):this;getMaxListeners():number;listeners(event:string|symbol):Function[];rawListeners(event:string|symbol):Function[];emit(event:string|symbol,...args:any[]):boolean;listenerCount(event:string|symbol):number;prependListener(event:string|symbol,listener:(...args:any[])=>void):this;prependOnceListener(event:string|symbol,listener:(...args:any[])=>void):this;eventNames():Array<string|symbol>;}}}export=EventEmitter;}
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'events' {
|
||||
interface EventEmitterOptions {
|
||||
/**
|
||||
* Enables automatic capturing of promise rejection.
|
||||
*/
|
||||
captureRejections?: boolean | undefined;
|
||||
}
|
||||
|
||||
interface NodeEventTarget {
|
||||
once(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
}
|
||||
|
||||
interface DOMEventTarget {
|
||||
addEventListener(event: string, listener: (...args: any[]) => void, opts?: { once: boolean }): any;
|
||||
}
|
||||
|
||||
interface EventEmitter extends NodeJS.EventEmitter {}
|
||||
class EventEmitter {
|
||||
constructor(options?: EventEmitterOptions);
|
||||
|
||||
static once(emitter: NodeEventTarget, event: string | symbol): Promise<any[]>;
|
||||
static once(emitter: DOMEventTarget, event: string): Promise<any[]>;
|
||||
static on(emitter: NodeJS.EventEmitter, event: string): AsyncIterableIterator<any>;
|
||||
|
||||
/** @deprecated since v4.0.0 */
|
||||
static listenerCount(emitter: NodeJS.EventEmitter, event: string | symbol): number;
|
||||
|
||||
/**
|
||||
* This symbol shall be used to install a listener for only monitoring `'error'`
|
||||
* events. Listeners installed using this symbol are called before the regular
|
||||
* `'error'` listeners are called.
|
||||
*
|
||||
* Installing a listener using this symbol does not change the behavior once an
|
||||
* `'error'` event is emitted, therefore the process will still crash if no
|
||||
* regular `'error'` listener is installed.
|
||||
*/
|
||||
static readonly errorMonitor: unique symbol;
|
||||
static readonly captureRejectionSymbol: unique symbol;
|
||||
|
||||
/**
|
||||
* Sets or gets the default captureRejection value for all emitters.
|
||||
*/
|
||||
// TODO: These should be described using static getter/setter pairs:
|
||||
static captureRejections: boolean;
|
||||
static defaultMaxListeners: number;
|
||||
}
|
||||
|
||||
import internal = require('events');
|
||||
namespace EventEmitter {
|
||||
// Should just be `export { EventEmitter }`, but that doesn't work in TypeScript 3.4
|
||||
export { internal as EventEmitter };
|
||||
}
|
||||
|
||||
global {
|
||||
namespace NodeJS {
|
||||
interface EventEmitter {
|
||||
addListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
once(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
removeListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
off(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
removeAllListeners(event?: string | symbol): this;
|
||||
setMaxListeners(n: number): this;
|
||||
getMaxListeners(): number;
|
||||
listeners(event: string | symbol): Function[];
|
||||
rawListeners(event: string | symbol): Function[];
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
listenerCount(event: string | symbol): number;
|
||||
// Added in Node 6...
|
||||
prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
eventNames(): Array<string | symbol>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export = EventEmitter;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
568
packages/node_modules/@node-red/editor-client/src/types/node/fs/promises.d.ts
vendored
Normal file
568
packages/node_modules/@node-red/editor-client/src/types/node/fs/promises.d.ts
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
|
||||
/* NOTE: Do not edit directly! This file is generated using `npm run update-types` in https://github.com/node-red/nr-monaco-build */
|
||||
|
||||
declare module 'fs/promises' {
|
||||
import {
|
||||
Stats,
|
||||
BigIntStats,
|
||||
StatOptions,
|
||||
WriteVResult,
|
||||
ReadVResult,
|
||||
PathLike,
|
||||
RmDirOptions,
|
||||
RmOptions,
|
||||
MakeDirectoryOptions,
|
||||
Dirent,
|
||||
OpenDirOptions,
|
||||
Dir,
|
||||
BaseEncodingOptions,
|
||||
BufferEncodingOption,
|
||||
OpenMode,
|
||||
Mode,
|
||||
} from 'fs';
|
||||
|
||||
interface FileHandle {
|
||||
/**
|
||||
* Gets the file descriptor for this file handle.
|
||||
*/
|
||||
readonly fd: number;
|
||||
|
||||
/**
|
||||
* Asynchronously append data to a file, creating the file if it does not exist. The underlying file will _not_ be closed automatically.
|
||||
* The `FileHandle` must have been opened for appending.
|
||||
* @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string.
|
||||
* @param options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `mode` is not supplied, the default of `0o666` is used.
|
||||
* If `mode` is a string, it is parsed as an octal integer.
|
||||
* If `flag` is not supplied, the default of `'a'` is used.
|
||||
*/
|
||||
appendFile(data: string | Uint8Array, options?: BaseEncodingOptions & { mode?: Mode | undefined, flag?: OpenMode | undefined } | BufferEncoding | null): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fchown(2) - Change ownership of a file.
|
||||
*/
|
||||
chown(uid: number, gid: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fchmod(2) - Change permissions of a file.
|
||||
* @param mode A file mode. If a string is passed, it is parsed as an octal integer.
|
||||
*/
|
||||
chmod(mode: Mode): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fdatasync(2) - synchronize a file's in-core state with storage device.
|
||||
*/
|
||||
datasync(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fsync(2) - synchronize a file's in-core state with the underlying storage device.
|
||||
*/
|
||||
sync(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads data from the file.
|
||||
* The `FileHandle` must have been opened for reading.
|
||||
* @param buffer The buffer that the data will be written to.
|
||||
* @param offset The offset in the buffer at which to start writing.
|
||||
* @param length The number of bytes to read.
|
||||
* @param position The offset from the beginning of the file from which data should be read. If `null`, data will be read from the current position.
|
||||
*/
|
||||
read<TBuffer extends Uint8Array>(buffer: TBuffer, offset?: number | null, length?: number | null, position?: number | null): Promise<{ bytesRead: number, buffer: TBuffer }>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads the entire contents of a file. The underlying file will _not_ be closed automatically.
|
||||
* The `FileHandle` must have been opened for reading.
|
||||
* @param options An object that may contain an optional flag.
|
||||
* If a flag is not provided, it defaults to `'r'`.
|
||||
*/
|
||||
readFile(options?: { encoding?: null | undefined, flag?: OpenMode | undefined } | null): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads the entire contents of a file. The underlying file will _not_ be closed automatically.
|
||||
* The `FileHandle` must have been opened for reading.
|
||||
* @param options An object that may contain an optional flag.
|
||||
* If a flag is not provided, it defaults to `'r'`.
|
||||
*/
|
||||
readFile(options: { encoding: BufferEncoding, flag?: OpenMode | undefined } | BufferEncoding): Promise<string>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads the entire contents of a file. The underlying file will _not_ be closed automatically.
|
||||
* The `FileHandle` must have been opened for reading.
|
||||
* @param options An object that may contain an optional flag.
|
||||
* If a flag is not provided, it defaults to `'r'`.
|
||||
*/
|
||||
readFile(options?: BaseEncodingOptions & { flag?: OpenMode | undefined } | BufferEncoding | null): Promise<string | Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronous fstat(2) - Get file status.
|
||||
*/
|
||||
stat(opts?: StatOptions & { bigint?: false | undefined }): Promise<Stats>;
|
||||
stat(opts: StatOptions & { bigint: true }): Promise<BigIntStats>;
|
||||
stat(opts?: StatOptions): Promise<Stats | BigIntStats>;
|
||||
|
||||
/**
|
||||
* Asynchronous ftruncate(2) - Truncate a file to a specified length.
|
||||
* @param len If not specified, defaults to `0`.
|
||||
*/
|
||||
truncate(len?: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously change file timestamps of the file.
|
||||
* @param atime The last access time. If a string is provided, it will be coerced to number.
|
||||
* @param mtime The last modified time. If a string is provided, it will be coerced to number.
|
||||
*/
|
||||
utimes(atime: string | number | Date, mtime: string | number | Date): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously writes `buffer` to the file.
|
||||
* The `FileHandle` must have been opened for writing.
|
||||
* @param buffer The buffer that the data will be written to.
|
||||
* @param offset The part of the buffer to be written. If not supplied, defaults to `0`.
|
||||
* @param length The number of bytes to write. If not supplied, defaults to `buffer.length - offset`.
|
||||
* @param position The offset from the beginning of the file where this data should be written. If not supplied, defaults to the current position.
|
||||
*/
|
||||
write<TBuffer extends Uint8Array>(buffer: TBuffer, offset?: number | null, length?: number | null, position?: number | null): Promise<{ bytesWritten: number, buffer: TBuffer }>;
|
||||
|
||||
/**
|
||||
* Asynchronously writes `string` to the file.
|
||||
* The `FileHandle` must have been opened for writing.
|
||||
* It is unsafe to call `write()` multiple times on the same file without waiting for the `Promise`
|
||||
* to be resolved (or rejected). For this scenario, `fs.createWriteStream` is strongly recommended.
|
||||
* @param string A string to write.
|
||||
* @param position The offset from the beginning of the file where this data should be written. If not supplied, defaults to the current position.
|
||||
* @param encoding The expected string encoding.
|
||||
*/
|
||||
write(data: string | Uint8Array, position?: number | null, encoding?: BufferEncoding | null): Promise<{ bytesWritten: number, buffer: string }>;
|
||||
|
||||
/**
|
||||
* Asynchronously writes data to a file, replacing the file if it already exists. The underlying file will _not_ be closed automatically.
|
||||
* The `FileHandle` must have been opened for writing.
|
||||
* It is unsafe to call `writeFile()` multiple times on the same file without waiting for the `Promise` to be resolved (or rejected).
|
||||
* @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string.
|
||||
* @param options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `mode` is not supplied, the default of `0o666` is used.
|
||||
* If `mode` is a string, it is parsed as an octal integer.
|
||||
* If `flag` is not supplied, the default of `'w'` is used.
|
||||
*/
|
||||
writeFile(data: string | Uint8Array, options?: BaseEncodingOptions & { mode?: Mode | undefined, flag?: OpenMode | undefined } | BufferEncoding | null): Promise<void>;
|
||||
|
||||
/**
|
||||
* See `fs.writev` promisified version.
|
||||
*/
|
||||
writev(buffers: ReadonlyArray<NodeJS.ArrayBufferView>, position?: number): Promise<WriteVResult>;
|
||||
|
||||
/**
|
||||
* See `fs.readv` promisified version.
|
||||
*/
|
||||
readv(buffers: ReadonlyArray<NodeJS.ArrayBufferView>, position?: number): Promise<ReadVResult>;
|
||||
|
||||
/**
|
||||
* Asynchronous close(2) - close a `FileHandle`.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously tests a user's permissions for the file specified by path.
|
||||
* @param path A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
|
||||
* URL support is _experimental_.
|
||||
*/
|
||||
function access(path: PathLike, mode?: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously copies `src` to `dest`. By default, `dest` is overwritten if it already exists.
|
||||
* Node.js makes no guarantees about the atomicity of the copy operation.
|
||||
* If an error occurs after the destination file has been opened for writing, Node.js will attempt
|
||||
* to remove the destination.
|
||||
* @param src A path to the source file.
|
||||
* @param dest A path to the destination file.
|
||||
* @param flags An optional integer that specifies the behavior of the copy operation. The only
|
||||
* supported flag is `fs.constants.COPYFILE_EXCL`, which causes the copy operation to fail if
|
||||
* `dest` already exists.
|
||||
*/
|
||||
function copyFile(src: PathLike, dest: PathLike, flags?: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous open(2) - open and possibly create a file.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param mode A file mode. If a string is passed, it is parsed as an octal integer. If not
|
||||
* supplied, defaults to `0o666`.
|
||||
*/
|
||||
function open(path: PathLike, flags: string | number, mode?: Mode): Promise<FileHandle>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads data from the file referenced by the supplied `FileHandle`.
|
||||
* @param handle A `FileHandle`.
|
||||
* @param buffer The buffer that the data will be written to.
|
||||
* @param offset The offset in the buffer at which to start writing.
|
||||
* @param length The number of bytes to read.
|
||||
* @param position The offset from the beginning of the file from which data should be read. If
|
||||
* `null`, data will be read from the current position.
|
||||
*/
|
||||
function read<TBuffer extends Uint8Array>(
|
||||
handle: FileHandle,
|
||||
buffer: TBuffer,
|
||||
offset?: number | null,
|
||||
length?: number | null,
|
||||
position?: number | null,
|
||||
): Promise<{ bytesRead: number, buffer: TBuffer }>;
|
||||
|
||||
/**
|
||||
* Asynchronously writes `buffer` to the file referenced by the supplied `FileHandle`.
|
||||
* It is unsafe to call `fsPromises.write()` multiple times on the same file without waiting for the `Promise`
|
||||
* to be resolved (or rejected). For this scenario, `fs.createWriteStream` is strongly recommended.
|
||||
* @param handle A `FileHandle`.
|
||||
* @param buffer The buffer that the data will be written to.
|
||||
* @param offset The part of the buffer to be written. If not supplied, defaults to `0`.
|
||||
* @param length The number of bytes to write. If not supplied, defaults to `buffer.length - offset`.
|
||||
* @param position The offset from the beginning of the file where this data should be written. If not supplied, defaults to the current position.
|
||||
*/
|
||||
function write<TBuffer extends Uint8Array>(
|
||||
handle: FileHandle,
|
||||
buffer: TBuffer,
|
||||
offset?: number | null,
|
||||
length?: number | null, position?: number | null): Promise<{ bytesWritten: number, buffer: TBuffer }>;
|
||||
|
||||
/**
|
||||
* Asynchronously writes `string` to the file referenced by the supplied `FileHandle`.
|
||||
* It is unsafe to call `fsPromises.write()` multiple times on the same file without waiting for the `Promise`
|
||||
* to be resolved (or rejected). For this scenario, `fs.createWriteStream` is strongly recommended.
|
||||
* @param handle A `FileHandle`.
|
||||
* @param string A string to write.
|
||||
* @param position The offset from the beginning of the file where this data should be written. If not supplied, defaults to the current position.
|
||||
* @param encoding The expected string encoding.
|
||||
*/
|
||||
function write(handle: FileHandle, string: string, position?: number | null, encoding?: BufferEncoding | null): Promise<{ bytesWritten: number, buffer: string }>;
|
||||
|
||||
/**
|
||||
* Asynchronous rename(2) - Change the name or location of a file or directory.
|
||||
* @param oldPath A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* URL support is _experimental_.
|
||||
* @param newPath A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* URL support is _experimental_.
|
||||
*/
|
||||
function rename(oldPath: PathLike, newPath: PathLike): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous truncate(2) - Truncate a file to a specified length.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param len If not specified, defaults to `0`.
|
||||
*/
|
||||
function truncate(path: PathLike, len?: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous ftruncate(2) - Truncate a file to a specified length.
|
||||
* @param handle A `FileHandle`.
|
||||
* @param len If not specified, defaults to `0`.
|
||||
*/
|
||||
function ftruncate(handle: FileHandle, len?: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous rmdir(2) - delete a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
function rmdir(path: PathLike, options?: RmDirOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously removes files and directories (modeled on the standard POSIX `rm` utility).
|
||||
*/
|
||||
function rm(path: PathLike, options?: RmOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fdatasync(2) - synchronize a file's in-core state with storage device.
|
||||
* @param handle A `FileHandle`.
|
||||
*/
|
||||
function fdatasync(handle: FileHandle): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fsync(2) - synchronize a file's in-core state with the underlying storage device.
|
||||
* @param handle A `FileHandle`.
|
||||
*/
|
||||
function fsync(handle: FileHandle): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous mkdir(2) - create a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options Either the file mode, or an object optionally specifying the file mode and whether parent folders
|
||||
* should be created. If a string is passed, it is parsed as an octal integer. If not specified, defaults to `0o777`.
|
||||
*/
|
||||
function mkdir(path: PathLike, options: MakeDirectoryOptions & { recursive: true; }): Promise<string | undefined>;
|
||||
|
||||
/**
|
||||
* Asynchronous mkdir(2) - create a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options Either the file mode, or an object optionally specifying the file mode and whether parent folders
|
||||
* should be created. If a string is passed, it is parsed as an octal integer. If not specified, defaults to `0o777`.
|
||||
*/
|
||||
function mkdir(path: PathLike, options?: Mode | (MakeDirectoryOptions & { recursive?: false | undefined; }) | null): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous mkdir(2) - create a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options Either the file mode, or an object optionally specifying the file mode and whether parent folders
|
||||
* should be created. If a string is passed, it is parsed as an octal integer. If not specified, defaults to `0o777`.
|
||||
*/
|
||||
function mkdir(path: PathLike, options?: Mode | MakeDirectoryOptions | null): Promise<string | undefined>;
|
||||
|
||||
/**
|
||||
* Asynchronous readdir(3) - read a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function readdir(path: PathLike, options?: BaseEncodingOptions & { withFileTypes?: false | undefined } | BufferEncoding | null): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* Asynchronous readdir(3) - read a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function readdir(path: PathLike, options: { encoding: "buffer"; withFileTypes?: false | undefined } | "buffer"): Promise<Buffer[]>;
|
||||
|
||||
/**
|
||||
* Asynchronous readdir(3) - read a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function readdir(path: PathLike, options?: BaseEncodingOptions & { withFileTypes?: false | undefined } | BufferEncoding | null): Promise<string[] | Buffer[]>;
|
||||
|
||||
/**
|
||||
* Asynchronous readdir(3) - read a directory.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options If called with `withFileTypes: true` the result data will be an array of Dirent.
|
||||
*/
|
||||
function readdir(path: PathLike, options: BaseEncodingOptions & { withFileTypes: true }): Promise<Dirent[]>;
|
||||
|
||||
/**
|
||||
* Asynchronous readlink(2) - read value of a symbolic link.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function readlink(path: PathLike, options?: BaseEncodingOptions | BufferEncoding | null): Promise<string>;
|
||||
|
||||
/**
|
||||
* Asynchronous readlink(2) - read value of a symbolic link.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function readlink(path: PathLike, options: BufferEncodingOption): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronous readlink(2) - read value of a symbolic link.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function readlink(path: PathLike, options?: BaseEncodingOptions | string | null): Promise<string | Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronous symlink(2) - Create a new symbolic link to an existing file.
|
||||
* @param target A path to an existing file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param path A path to the new symlink. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param type May be set to `'dir'`, `'file'`, or `'junction'` (default is `'file'`) and is only available on Windows (ignored on other platforms).
|
||||
* When using `'junction'`, the `target` argument will automatically be normalized to an absolute path.
|
||||
*/
|
||||
function symlink(target: PathLike, path: PathLike, type?: string | null): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous lstat(2) - Get file status. Does not dereference symbolic links.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
function lstat(path: PathLike, opts?: StatOptions & { bigint?: false | undefined }): Promise<Stats>;
|
||||
function lstat(path: PathLike, opts: StatOptions & { bigint: true }): Promise<BigIntStats>;
|
||||
function lstat(path: PathLike, opts?: StatOptions): Promise<Stats | BigIntStats>;
|
||||
|
||||
/**
|
||||
* Asynchronous stat(2) - Get file status.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
function stat(path: PathLike, opts?: StatOptions & { bigint?: false | undefined }): Promise<Stats>;
|
||||
function stat(path: PathLike, opts: StatOptions & { bigint: true }): Promise<BigIntStats>;
|
||||
function stat(path: PathLike, opts?: StatOptions): Promise<Stats | BigIntStats>;
|
||||
|
||||
/**
|
||||
* Asynchronous link(2) - Create a new link (also known as a hard link) to an existing file.
|
||||
* @param existingPath A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param newPath A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
function link(existingPath: PathLike, newPath: PathLike): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous unlink(2) - delete a name and possibly the file it refers to.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
function unlink(path: PathLike): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fchmod(2) - Change permissions of a file.
|
||||
* @param handle A `FileHandle`.
|
||||
* @param mode A file mode. If a string is passed, it is parsed as an octal integer.
|
||||
*/
|
||||
function fchmod(handle: FileHandle, mode: Mode): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous chmod(2) - Change permissions of a file.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param mode A file mode. If a string is passed, it is parsed as an octal integer.
|
||||
*/
|
||||
function chmod(path: PathLike, mode: Mode): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous lchmod(2) - Change permissions of a file. Does not dereference symbolic links.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param mode A file mode. If a string is passed, it is parsed as an octal integer.
|
||||
*/
|
||||
function lchmod(path: PathLike, mode: Mode): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous lchown(2) - Change ownership of a file. Does not dereference symbolic links.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
function lchown(path: PathLike, uid: number, gid: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Changes the access and modification times of a file in the same way as `fsPromises.utimes()`,
|
||||
* with the difference that if the path refers to a symbolic link, then the link is not
|
||||
* dereferenced: instead, the timestamps of the symbolic link itself are changed.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param atime The last access time. If a string is provided, it will be coerced to number.
|
||||
* @param mtime The last modified time. If a string is provided, it will be coerced to number.
|
||||
*/
|
||||
function lutimes(path: PathLike, atime: string | number | Date, mtime: string | number | Date): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous fchown(2) - Change ownership of a file.
|
||||
* @param handle A `FileHandle`.
|
||||
*/
|
||||
function fchown(handle: FileHandle, uid: number, gid: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous chown(2) - Change ownership of a file.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
*/
|
||||
function chown(path: PathLike, uid: number, gid: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously change file timestamps of the file referenced by the supplied path.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param atime The last access time. If a string is provided, it will be coerced to number.
|
||||
* @param mtime The last modified time. If a string is provided, it will be coerced to number.
|
||||
*/
|
||||
function utimes(path: PathLike, atime: string | number | Date, mtime: string | number | Date): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously change file timestamps of the file referenced by the supplied `FileHandle`.
|
||||
* @param handle A `FileHandle`.
|
||||
* @param atime The last access time. If a string is provided, it will be coerced to number.
|
||||
* @param mtime The last modified time. If a string is provided, it will be coerced to number.
|
||||
*/
|
||||
function futimes(handle: FileHandle, atime: string | number | Date, mtime: string | number | Date): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronous realpath(3) - return the canonicalized absolute pathname.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function realpath(path: PathLike, options?: BaseEncodingOptions | BufferEncoding | null): Promise<string>;
|
||||
|
||||
/**
|
||||
* Asynchronous realpath(3) - return the canonicalized absolute pathname.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function realpath(path: PathLike, options: BufferEncodingOption): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronous realpath(3) - return the canonicalized absolute pathname.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function realpath(path: PathLike, options?: BaseEncodingOptions | BufferEncoding | null): Promise<string | Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronously creates a unique temporary directory.
|
||||
* Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function mkdtemp(prefix: string, options?: BaseEncodingOptions | BufferEncoding | null): Promise<string>;
|
||||
|
||||
/**
|
||||
* Asynchronously creates a unique temporary directory.
|
||||
* Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function mkdtemp(prefix: string, options: BufferEncodingOption): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronously creates a unique temporary directory.
|
||||
* Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory.
|
||||
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'` is used.
|
||||
*/
|
||||
function mkdtemp(prefix: string, options?: BaseEncodingOptions | BufferEncoding | null): Promise<string | Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronously writes data to a file, replacing the file if it already exists.
|
||||
* It is unsafe to call `fsPromises.writeFile()` multiple times on the same file without waiting for the `Promise` to be resolved (or rejected).
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* URL support is _experimental_.
|
||||
* If a `FileHandle` is provided, the underlying file will _not_ be closed automatically.
|
||||
* @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string.
|
||||
* @param options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `mode` is not supplied, the default of `0o666` is used.
|
||||
* If `mode` is a string, it is parsed as an octal integer.
|
||||
* If `flag` is not supplied, the default of `'w'` is used.
|
||||
*/
|
||||
function writeFile(
|
||||
path: PathLike | FileHandle,
|
||||
data: string | Uint8Array,
|
||||
options?: BaseEncodingOptions & { mode?: Mode | undefined, flag?: OpenMode | undefined } | BufferEncoding | null
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously append data to a file, creating the file if it does not exist.
|
||||
* @param file A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* URL support is _experimental_.
|
||||
* If a `FileHandle` is provided, the underlying file will _not_ be closed automatically.
|
||||
* @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string.
|
||||
* @param options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag.
|
||||
* If `encoding` is not supplied, the default of `'utf8'` is used.
|
||||
* If `mode` is not supplied, the default of `0o666` is used.
|
||||
* If `mode` is a string, it is parsed as an octal integer.
|
||||
* If `flag` is not supplied, the default of `'a'` is used.
|
||||
*/
|
||||
function appendFile(
|
||||
path: PathLike | FileHandle,
|
||||
data: string | Uint8Array,
|
||||
options?: BaseEncodingOptions & { mode?: Mode | undefined, flag?: OpenMode | undefined } | BufferEncoding | null
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads the entire contents of a file.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* If a `FileHandle` is provided, the underlying file will _not_ be closed automatically.
|
||||
* @param options An object that may contain an optional flag.
|
||||
* If a flag is not provided, it defaults to `'r'`.
|
||||
*/
|
||||
function readFile(path: PathLike | FileHandle, options?: { encoding?: null | undefined, flag?: OpenMode | undefined } | null): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads the entire contents of a file.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* If a `FileHandle` is provided, the underlying file will _not_ be closed automatically.
|
||||
* @param options An object that may contain an optional flag.
|
||||
* If a flag is not provided, it defaults to `'r'`.
|
||||
*/
|
||||
function readFile(path: PathLike | FileHandle, options: { encoding: BufferEncoding, flag?: OpenMode | undefined } | BufferEncoding): Promise<string>;
|
||||
|
||||
/**
|
||||
* Asynchronously reads the entire contents of a file.
|
||||
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
||||
* If a `FileHandle` is provided, the underlying file will _not_ be closed automatically.
|
||||
* @param options An object that may contain an optional flag.
|
||||
* If a flag is not provided, it defaults to `'r'`.
|
||||
*/
|
||||
function readFile(path: PathLike | FileHandle, options?: BaseEncodingOptions & { flag?: OpenMode | undefined } | BufferEncoding | null): Promise<string | Buffer>;
|
||||
|
||||
function opendir(path: string, options?: OpenDirOptions): Promise<Dir>;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user