mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
500 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
042409f870 | ||
|
|
5b8f4f4069 | ||
|
|
d132d63c1d | ||
|
|
ef8b936069 | ||
|
|
36e3bfffb4 | ||
|
|
91a38bdb60 | ||
|
|
f169a68319 | ||
|
|
ee886f98dd | ||
|
|
a3826cc6a7 | ||
|
|
ba33b832ba | ||
|
|
f6c017176b | ||
|
|
7a01b115bb | ||
|
|
1dc021e871 | ||
|
|
c9f916ebab | ||
|
|
ff627fd128 | ||
|
|
dfa077fd5f | ||
|
|
5155770213 | ||
|
|
f1d5bbb036 | ||
|
|
69ed0aebc3 | ||
|
|
549e56e220 | ||
|
|
450f4d9a5a | ||
|
|
6533a9793c | ||
|
|
2000cadb17 | ||
|
|
083c321efa | ||
|
|
f64c4a981f | ||
|
|
3ac8ce03bf | ||
|
|
66fca8710e | ||
|
|
1e245ece46 | ||
|
|
81efce03ba | ||
|
|
4e549dd426 | ||
|
|
52f74ff7e0 | ||
|
|
3c71b815f5 | ||
|
|
9efd48fe51 | ||
|
|
4609ee75b6 | ||
|
|
963ea4177e | ||
|
|
17e6940a42 | ||
|
|
315a9ceba3 | ||
|
|
a2bdeedb09 | ||
|
|
da5700d2d7 | ||
|
|
90e7f30247 | ||
|
|
3ccf6ba892 | ||
|
|
e50cd5b745 | ||
|
|
db77be5d72 | ||
|
|
c36870c23e | ||
|
|
e9be007040 | ||
|
|
9e400d9aa6 | ||
|
|
490c8dae75 | ||
|
|
3bcffe375d | ||
|
|
9f81a591e1 | ||
|
|
3db5306c70 | ||
|
|
45029dd084 | ||
|
|
b01cd30339 | ||
|
|
09329e1104 | ||
|
|
ab0fc2ecfa | ||
|
|
bf5d36d6bd | ||
|
|
a29527ec96 | ||
|
|
45e7ad8049 | ||
|
|
4d54663efd | ||
|
|
29d386cc51 | ||
|
|
ba1a67969b | ||
|
|
390ea5419e | ||
|
|
0fdeec7cc4 | ||
|
|
e34d883e50 | ||
|
|
507871687b | ||
|
|
ed58f62cd1 | ||
|
|
94bc4e7125 | ||
|
|
5832f7930d | ||
|
|
0066a20c22 | ||
|
|
774e4bfced | ||
|
|
054c7a76a4 | ||
|
|
c7f3b77aac | ||
|
|
a6a4620374 | ||
|
|
5148c62d1c | ||
|
|
6fc863a91e | ||
|
|
e066a154a1 | ||
|
|
d432edaed2 | ||
|
|
8f34f4e80b | ||
|
|
39b751acf5 | ||
|
|
bd5e8ba961 | ||
|
|
ed20327c41 | ||
|
|
991c68c394 | ||
|
|
2acc31a4e7 | ||
|
|
b9733e3dfa | ||
|
|
bb106bfce7 | ||
|
|
daf1388a6a | ||
|
|
8226f1fa75 | ||
|
|
e675512fa3 | ||
|
|
65e67b6c3e | ||
|
|
7612481570 | ||
|
|
f6c7cb5804 | ||
|
|
2201c9062f | ||
|
|
ca3da262da | ||
|
|
5847f92bef | ||
|
|
31ee1be81e | ||
|
|
6bccdd015f | ||
|
|
cecea318da | ||
|
|
8663ec6880 | ||
|
|
9b03f128aa | ||
|
|
8a51f97616 | ||
|
|
ee74ed9ce9 | ||
|
|
0f947c756e | ||
|
|
cae7949a48 | ||
|
|
be58b614e1 | ||
|
|
b0a01fa4b2 | ||
|
|
9734228001 | ||
|
|
9df1d44bc4 | ||
|
|
13d887028a | ||
|
|
83a8979309 | ||
|
|
75c29f1cb7 | ||
|
|
d9d15e41c7 | ||
|
|
d3598d5854 | ||
|
|
3a8aaee5d7 | ||
|
|
4fcf57d42c | ||
|
|
adb0891335 | ||
|
|
d21e719cc1 | ||
|
|
5807ab82c1 | ||
|
|
65cb04da63 | ||
|
|
312e3611b1 | ||
|
|
46acc62279 | ||
|
|
529b358c9b | ||
|
|
7fca04404e | ||
|
|
3a1cc6a2be | ||
|
|
5b76c91004 | ||
|
|
cf87837f7d | ||
|
|
5a0a7b907b | ||
|
|
6a2b1669b3 | ||
|
|
ca8264b3f4 | ||
|
|
b44ecd8819 | ||
|
|
987942959e | ||
|
|
91992b48c1 | ||
|
|
c9a335a6f9 | ||
|
|
b7ed159b50 | ||
|
|
c72961a52a | ||
|
|
afe6afca36 | ||
|
|
050acd239c | ||
|
|
24505ee4f5 | ||
|
|
63a249aba3 | ||
|
|
7bd94df2a0 | ||
|
|
761161a8e5 | ||
|
|
513579a7ee | ||
|
|
7165483d83 | ||
|
|
f8bcf219cb | ||
|
|
590506e306 | ||
|
|
9a5439c580 | ||
|
|
6b2f5fbb19 | ||
|
|
051c147b41 | ||
|
|
9111adf15f | ||
|
|
ba18b27371 | ||
|
|
2a287b2ae6 | ||
|
|
fc9040f715 | ||
|
|
0029022ef6 | ||
|
|
94f728d3fd | ||
|
|
d53ced7830 | ||
|
|
053d8c44c2 | ||
|
|
9f5767ea16 | ||
|
|
e8d76b0555 | ||
|
|
c2675600f6 | ||
|
|
6f087b4ec1 | ||
|
|
e94708606d | ||
|
|
c248f1a762 | ||
|
|
28402b0894 | ||
|
|
7dd98e99f9 | ||
|
|
dba195b396 | ||
|
|
88b153bc12 | ||
|
|
d4a47dc974 | ||
|
|
fe3ea6edfd | ||
|
|
6c8fc4846b | ||
|
|
54d9656f09 | ||
|
|
49da324c5d | ||
|
|
9bf87697fd | ||
|
|
f368f5a9c4 | ||
|
|
eea85485e6 | ||
|
|
1a544b3b82 | ||
|
|
8b38fe9fe0 | ||
|
|
1bf4addf63 | ||
|
|
407e16e900 | ||
|
|
6e9fe3248a | ||
|
|
d8cf86fd6f | ||
|
|
f8aa4a9588 | ||
|
|
c249907846 | ||
|
|
57c1524a9a | ||
|
|
d8d82e2ba3 | ||
|
|
807b512ef7 | ||
|
|
b2f06b6777 | ||
|
|
d7adff9a65 | ||
|
|
b0d7e11d48 | ||
|
|
fc9cdb61f2 | ||
|
|
9c00492dc2 | ||
|
|
1a6babd199 | ||
|
|
1b693eed37 | ||
|
|
afb566b6b4 | ||
|
|
f870e9ed3e | ||
|
|
4bcf13cb58 | ||
|
|
946a6d6041 | ||
|
|
372c213c2c | ||
|
|
a5a79d3ab7 | ||
|
|
e6c5cfb703 | ||
|
|
7843eccae8 | ||
|
|
7ca153abd0 | ||
|
|
33b4774c49 | ||
|
|
c243481432 | ||
|
|
80873e4ea9 | ||
|
|
4e4a1f11e6 | ||
|
|
9bbe405cd0 | ||
|
|
c440a4c730 | ||
|
|
a1251371d7 | ||
|
|
7d702e8332 | ||
|
|
43d7c8d48c | ||
|
|
7423583508 | ||
|
|
08b0838f9a | ||
|
|
038d821a7c | ||
|
|
6a218814d3 | ||
|
|
905f89b0f5 | ||
|
|
14882bda78 | ||
|
|
781fa4634b | ||
|
|
cdb173fd6e | ||
|
|
466cb4be89 | ||
|
|
c39e2ffd56 | ||
|
|
17bf09e276 | ||
|
|
bc01f9f8fd | ||
|
|
c0870c5694 | ||
|
|
3b5174a2ea | ||
|
|
af6885f3e8 | ||
|
|
e01996095f | ||
|
|
5d86f7b6ba | ||
|
|
8d6ac6406d | ||
|
|
40ff54f67e | ||
|
|
cce7ac09d0 | ||
|
|
73a18891c5 | ||
|
|
fe22cedc1d | ||
|
|
fa09c7c8b2 | ||
|
|
15e28e3cc0 | ||
|
|
2cb4f6b1fc | ||
|
|
b17a483b85 | ||
|
|
7c3e5443ab | ||
|
|
f95a2851c8 | ||
|
|
2b2eee352f | ||
|
|
11569d8056 | ||
|
|
bdf87452b6 | ||
|
|
0c6bf81c24 | ||
|
|
f2fa26fb07 | ||
|
|
f5e212ff1e | ||
|
|
461e6562ca | ||
|
|
fd67d08402 | ||
|
|
e6411d11b1 | ||
|
|
dd81d947fc | ||
|
|
23b887c30e | ||
|
|
c4eae3f130 | ||
|
|
41a04a2849 | ||
|
|
ed1d34e678 | ||
|
|
f44487338d | ||
|
|
7aced85a31 | ||
|
|
fbe0e2d6eb | ||
|
|
6e34f0697c | ||
|
|
a835f9f0cb | ||
|
|
16715673c3 | ||
|
|
c48c74f173 | ||
|
|
f262348497 | ||
|
|
7185bcd51f | ||
|
|
28d05e2449 | ||
|
|
7fafa21a1b | ||
|
|
84f598e143 | ||
|
|
e30f8628db | ||
|
|
0be9c88106 | ||
|
|
e046fc1ac5 | ||
|
|
3a476ac493 | ||
|
|
e33ec0cf50 | ||
|
|
b4b70a988e | ||
|
|
e66b381070 | ||
|
|
771b598c09 | ||
|
|
cd44f13171 | ||
|
|
aa6b72ac87 | ||
|
|
a467fe5ed7 | ||
|
|
467411c6c3 | ||
|
|
2648b7ca54 | ||
|
|
de35c7024a | ||
|
|
9d219c163d | ||
|
|
f7434b5ec8 | ||
|
|
5ed3360c0b | ||
|
|
6f5974f875 | ||
|
|
56db1da3cf | ||
|
|
fef71f29c4 | ||
|
|
d46b66878a | ||
|
|
6cad80c4ad | ||
|
|
68779caa2e | ||
|
|
2a122ed283 | ||
|
|
17c5fdf0d5 | ||
|
|
f6274445a2 | ||
|
|
3b0300b834 | ||
|
|
4fbf1fe780 | ||
|
|
dcf44fed58 | ||
|
|
7136dc1c72 | ||
|
|
0e4cedbc5e | ||
|
|
dc139bcc30 | ||
|
|
b204b183de | ||
|
|
ab788bc1e3 | ||
|
|
95b4c8d515 | ||
|
|
b025644525 | ||
|
|
9e87a60597 | ||
|
|
5a70bea67a | ||
|
|
2a95af3928 | ||
|
|
0a0ca380d3 | ||
|
|
4cfbf7f71c | ||
|
|
de43148341 | ||
|
|
0a2aab7d68 | ||
|
|
745821c420 | ||
|
|
57c4c754d0 | ||
|
|
4b5c437533 | ||
|
|
8d63b6a1ed | ||
|
|
245a8adbf9 | ||
|
|
4f7d98aace | ||
|
|
b0c693cc3a | ||
|
|
b2cca10e8b | ||
|
|
a84b2ab5bb | ||
|
|
4565342b05 | ||
|
|
0ad54cc2d1 | ||
|
|
865853da19 | ||
|
|
392ed706fd | ||
|
|
0ff0f25aaf | ||
|
|
c157960846 | ||
|
|
a5c00b5c81 | ||
|
|
472bbdb59f | ||
|
|
7877093713 | ||
|
|
8cb2e51407 | ||
|
|
d5cee81fb6 | ||
|
|
bca020bc4d | ||
|
|
5069f2844c | ||
|
|
252df81f59 | ||
|
|
7f89a4a26f | ||
|
|
40f4167894 | ||
|
|
0ef16989cd | ||
|
|
3df3d6f516 | ||
|
|
10395ef254 | ||
|
|
83854c28db | ||
|
|
fcbea2629c | ||
|
|
26bc142cc2 | ||
|
|
a4eb8e11c3 | ||
|
|
9fd5d1db56 | ||
|
|
1d05b4c981 | ||
|
|
61f6535be8 | ||
|
|
7dd329b5ee | ||
|
|
b761904424 | ||
|
|
36105412b1 | ||
|
|
184b1b018c | ||
|
|
f3e1b85d82 | ||
|
|
626d012775 | ||
|
|
9ad9c0ec6a | ||
|
|
e13fed9fc6 | ||
|
|
eb6d093e56 | ||
|
|
af1ea610ea | ||
|
|
d4d9190919 | ||
|
|
4d3d1a02a8 | ||
|
|
30c2aa96d6 | ||
|
|
4edb1f80b0 | ||
|
|
0a82459233 | ||
|
|
db87b0dfa5 | ||
|
|
cd42cf7583 | ||
|
|
2d5980ff2a | ||
|
|
d49c7a3adb | ||
|
|
4fdd09a262 | ||
|
|
d6878512c4 | ||
|
|
8b1b8250ff | ||
|
|
9dccbf747e | ||
|
|
08727e1938 | ||
|
|
7584820987 | ||
|
|
d572356642 | ||
|
|
3b5a2815a9 | ||
|
|
f3cf01df25 | ||
|
|
63e6e64ad3 | ||
|
|
e8d7b48bff | ||
|
|
12944d1ebd | ||
|
|
fa1ff6e393 | ||
|
|
98546b6e6a | ||
|
|
2fef6fd1fa | ||
|
|
20cf91f1dc | ||
|
|
2efa78d590 | ||
|
|
880af0671a | ||
|
|
62471e4531 | ||
|
|
b15f8535f8 | ||
|
|
7a3a4493da | ||
|
|
11078235c4 | ||
|
|
f3e05cd08a | ||
|
|
0ca3cabbe8 | ||
|
|
44a75c1291 | ||
|
|
4a4513a746 | ||
|
|
60ff8660de | ||
|
|
6fa0d671c0 | ||
|
|
f478d7c9f0 | ||
|
|
53e3e08d70 | ||
|
|
c4d1ccb6f5 | ||
|
|
e3520309fc | ||
|
|
27bf72372e | ||
|
|
ae4b1b17a9 | ||
|
|
94cb03f4b5 | ||
|
|
e691351976 | ||
|
|
3190de873e | ||
|
|
e8a637498d | ||
|
|
e1195ac00a | ||
|
|
6cd9ccc37c | ||
|
|
25345302e8 | ||
|
|
eccd5e9801 | ||
|
|
ff355af9f2 | ||
|
|
5967f4b0d4 | ||
|
|
ff18618032 | ||
|
|
20f03c356c | ||
|
|
27fdc9e56e | ||
|
|
52d9578a19 | ||
|
|
f4c2938b41 | ||
|
|
9f703de5ec | ||
|
|
a327fd85e2 | ||
|
|
9d22a86ec8 | ||
|
|
29e0b194dd | ||
|
|
ae9cf13fc2 | ||
|
|
64ae67586a | ||
|
|
838c7a5e89 | ||
|
|
89bfc90f40 | ||
|
|
acad9f57f9 | ||
|
|
0d08dc410e | ||
|
|
ebb3fb96cd | ||
|
|
f31f23ff07 | ||
|
|
d2aa3d1868 | ||
|
|
c9e2fce94d | ||
|
|
8b0e76dd55 | ||
|
|
884618adfe | ||
|
|
6e2e36e7a0 | ||
|
|
9994df9601 | ||
|
|
98f7271ac8 | ||
|
|
087cd121b8 | ||
|
|
2d52527fb4 | ||
|
|
fe289e62b5 | ||
|
|
2845475e3f | ||
|
|
b307492487 | ||
|
|
d48284f7ea | ||
|
|
7e416797e9 | ||
|
|
5d54ca7477 | ||
|
|
b979b4e61a | ||
|
|
2527f7984a | ||
|
|
d9350b2362 | ||
|
|
bd0b903f1a | ||
|
|
f243c0df19 | ||
|
|
7482978953 | ||
|
|
77966689d4 | ||
|
|
cf43939d65 | ||
|
|
391ac4b351 | ||
|
|
e1e48aadd9 | ||
|
|
0681f206c4 | ||
|
|
d257c6f3d3 | ||
|
|
fa45c82cdc | ||
|
|
e805b58da6 | ||
|
|
943976d207 | ||
|
|
3a2e5a6ccd | ||
|
|
35ef036246 | ||
|
|
e09c3bbdd3 | ||
|
|
3b12076d4b | ||
|
|
cfcf78ae28 | ||
|
|
341ff9bf5c | ||
|
|
10d8ca30b0 | ||
|
|
4ebb5d099e | ||
|
|
1e82b66bf0 | ||
|
|
06a5e4273b | ||
|
|
e123e7b0b0 | ||
|
|
aeadc40c65 | ||
|
|
7ef418ec52 | ||
|
|
2ed52820b6 | ||
|
|
e8fd7484b6 | ||
|
|
ce5242cfe8 | ||
|
|
af947879d8 | ||
|
|
3ed112cde6 | ||
|
|
99c6a9eccd | ||
|
|
2029f6ea0a | ||
|
|
e984e1f30f | ||
|
|
f21260370f | ||
|
|
fdae75c99b | ||
|
|
a0489f2a0d | ||
|
|
0123eacbdb | ||
|
|
53401b6aa7 | ||
|
|
9a5139f452 | ||
|
|
2ee0c8c228 | ||
|
|
c53562cc9c | ||
|
|
ec5d7c2e5c | ||
|
|
d6fc258485 | ||
|
|
f953612695 | ||
|
|
2ab93acca8 | ||
|
|
326c6c496e | ||
|
|
9f7f50664c | ||
|
|
f6f1436123 | ||
|
|
c3c519419d | ||
|
|
e569a80b72 | ||
|
|
284f437c1a | ||
|
|
1fd44a9958 | ||
|
|
cad34742f6 | ||
|
|
323359b3c8 | ||
|
|
35db8b45f0 | ||
|
|
7face138fd | ||
|
|
382b83b093 | ||
|
|
691687d1bc | ||
|
|
5814b80a72 | ||
|
|
e147fbb1fa | ||
|
|
ce9643d21b | ||
|
|
c316284924 |
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@@ -8,7 +8,9 @@ If your issue is:
|
||||
- a feature request or suggestion for a change,
|
||||
- or problems with 3rd party (`node-red-contrib-`) nodes
|
||||
|
||||
please use the [mailing list](https://groups.google.com/forum/#!forum/node-red), [slack team](https://nodered.org/slack) or ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
|
||||
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
||||
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -16,7 +16,7 @@ Put an `x` in the boxes that apply
|
||||
<!--
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it **may well get rejected** if it hasn't been discussed on
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) or
|
||||
the [forum](https://discourse.nodered.org) or
|
||||
[slack team](https://nodered.org/slack) first.
|
||||
|
||||
-->
|
||||
|
||||
28
.travis.yml
28
.travis.yml
@@ -1,20 +1,12 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
env:
|
||||
- CXX="g++-4.8"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- gcc-4.8
|
||||
node_js:
|
||||
- "8"
|
||||
- "6"
|
||||
- "4"
|
||||
script:
|
||||
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
|
||||
before_script:
|
||||
- npm install -g istanbul
|
||||
- npm install coveralls
|
||||
matrix:
|
||||
include:
|
||||
- node_js: "10"
|
||||
script:
|
||||
- ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
|
||||
before_script:
|
||||
- npm install -g istanbul coveralls
|
||||
- node_js: "8"
|
||||
- node_js: "6"
|
||||
- node_js: "4"
|
||||
|
||||
183
CHANGELOG.md
183
CHANGELOG.md
@@ -1,3 +1,186 @@
|
||||
#### 0.19.1: Maintenance Release
|
||||
|
||||
- Pull in latest twitter node
|
||||
- Handle windows paths for context storage
|
||||
- Handle persisting objects with circular refs in context
|
||||
- Ensure js editor can expand to fill available space
|
||||
- Add example localfilesystem contextStorage to settings
|
||||
- Fix template node handling of nested context tags
|
||||
|
||||
#### 0.19: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add editorTheme.palette.theme to allow overriding colours
|
||||
- Index all node properties when searching Fixes #1446
|
||||
- Handle NaN and Infinity properly in debug sidebar Fixes #1778 #1779
|
||||
- Prevent horizontal scroll when palette name cannot wrap
|
||||
- Ignore middle-click on node/ports to enable panning
|
||||
- Better wire layout when looping back
|
||||
- fix appearence of retry button of remote branch management dialog
|
||||
- Handle releasing ctrl when using quick-add node dialog
|
||||
- Add $env function to JSONata expressions
|
||||
- Widen support for env var to use ${} or $() syntax
|
||||
- Add env-var support to TypedInput
|
||||
- Show unknown node properties in info tab
|
||||
- Add node icon picker widget
|
||||
- Only edit nodes on dbl click on primary button with no modifiers
|
||||
- Allow subflows to be put in any palette category
|
||||
- Add flow navigator widget
|
||||
- Cache flow library result to improve response time Fixes #1753
|
||||
- Add middle-button-drag to pan the workspace
|
||||
- allow multi-line category name in editor
|
||||
- Redesign sidebar tabs
|
||||
- Do not disable the export-clipboard menu option with empty selection
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Ensure runtime errors in Change node can be caught Fixes #1769
|
||||
- File: Add output to File Out node
|
||||
- Function: add expandable JavaScript editor pane
|
||||
- Function: allow id and name reference in function node code (#1731)
|
||||
- HTTP Request: Move to request module
|
||||
- HTTP: Ensure apiMaxLength applies to HTTP Nodes Fixes #1278
|
||||
- Join: accumulate top level properties
|
||||
- Join: allow environment variable as reduce init value
|
||||
- JSON: add JSON schema validation via msg.schema
|
||||
- Pi: Let nrgpio code work with python 3
|
||||
- Pi: let Pi nodes be visible/editable on all platforms
|
||||
- Switch: add isEmpty rule
|
||||
- TCP: queue messages while connecting; closes #1414
|
||||
- TLS: Add servername option to TLS config node for SNI Fixes #1805
|
||||
- UDP: Don't accidentally re-use udp port when set to not do so
|
||||
|
||||
Persistent Context
|
||||
|
||||
- Add Context data sidebar
|
||||
- Add persistable context option
|
||||
- Add default memory store
|
||||
- Add file-based context store
|
||||
- Add async mode to evaluateJSONataExpression
|
||||
- Update RED.util.evaluateNodeProperty to support context stores
|
||||
|
||||
Runtime
|
||||
|
||||
- Support flow.disabled and .info in /flow API
|
||||
- Node errors should be Strings not Errors Fixes #1781
|
||||
- Add detection of connection timeout in git communication Fixes #1770
|
||||
- Handle loading empty nodesDir
|
||||
- Add 'private' property to userDir generated package.json
|
||||
- Add RED.require to allow nodes to access other modules
|
||||
- Ensure add/remove modules are run sequentially
|
||||
|
||||
#### 0.18.7: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Do not trim wires if node declares outputs in defaults but misses value Fixes #1737
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Relax twitter node version ready for major version bump
|
||||
- Pass Date into the Function node sandbox to fix instanceof tests
|
||||
- let TCP in node report remote ip and port when in single packet mode
|
||||
- typo fix in node help (#1735)
|
||||
|
||||
Other Fixes
|
||||
- Tidy up default grunt task and fixup test break due to reorder Fixes #1738
|
||||
- Bump jsonata version
|
||||
|
||||
#### 0.18.6: Maintenance Release
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Handle a node having wires in the editor on ports it no longer has Fixes #1724
|
||||
- Add missing ACE snippet files
|
||||
- Fix wireClippedNodes is not defined Fixes #1726
|
||||
- Split node html to isolate bad nodes when loading
|
||||
- Avoid unnecessary use of .html() where .text() will do
|
||||
|
||||
- Add editorTheme.projects.enabled to default settings.js"
|
||||
|
||||
#### 0.18.5: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Add clone project to welcome screen
|
||||
- Handle cloning a project without package.json
|
||||
- Keep remote branch state in sync between editor and runtime
|
||||
|
||||
New Features
|
||||
|
||||
- Add type checks to switch node options (#1714)
|
||||
- add output property select to HTML parse node (#1701)
|
||||
- Add Prevent Following Redirect to HTTP Request node (#615) (#1684)
|
||||
- Add debug and trace functions to function node (#1654)
|
||||
- Enable user defined icon for subflow
|
||||
- Add MQTT disconnect message and rework broker node UI (#1719)
|
||||
- Japanese message catalogue updates (#1723)
|
||||
- Show node load errors in the Palette Manager view
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Highlight subflow node when log msg comes from inside Fixes #1698
|
||||
- Ensure node wires array is not longer than outputs value Fixes #1678
|
||||
- Allow importing an unknown config node to be undone Fixes #1681
|
||||
- Ensure keyboard shortcuts get saved in runtime settings Fixes #1696
|
||||
- Don't mark a subflow changed when actually modified nothing (#1665)
|
||||
|
||||
Node Fixes
|
||||
|
||||
- bind to correct port when doing udp broadcast/multicast (#1686)
|
||||
- Provide full error stack in Function node log message (#1700)
|
||||
- Fix http request doc type Fixes #1690
|
||||
- Make debug slightly larger to pass WCAG AA rating
|
||||
- Make core nodes labels more consistent, to close #1673
|
||||
- Allow template node to be updated more than once Fixes #1671
|
||||
- Fix the problem that output labels of switch node sometimes disappear (#1664)
|
||||
- Chinese translations for core nodes (#1607)
|
||||
|
||||
Runtime Fixes
|
||||
|
||||
- Handle and display for invalid flow credentials when project is disabled #1689 (#1694)
|
||||
- node-red-pi: fix behavior with old bash version (#1713)
|
||||
- Fix ENOENT error on first start when no user dir (#1711)
|
||||
- Handle null error object in Flow.handleError Fixes #1721
|
||||
- update settings comments to describe how to setup for ipv6 (#1675)
|
||||
- Remove credential props after diffing flow to prevent future false positives Fixes #1359
|
||||
- Log error if settings unavailable when saving user settings Fixes #1645
|
||||
- Keep backup of .config.json
|
||||
- Add warning if using \_credentialSecret from .config.json
|
||||
- Filter req.user in /settings to prevent potentially leaking info
|
||||
|
||||
#### 0.18.4: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
- Ensure sshkey file path is properly escaped on Windows
|
||||
- Normalize ssh key paths for Windows file names
|
||||
- Ensure userDir is an absolute path when used with sshkeygen
|
||||
- Detect if there are no existing flows to migrate into a project
|
||||
- Use relative urls when retriving flow history
|
||||
- Add credentialSecret to clone pane
|
||||
- Delay clearing inflight when changing credentials key
|
||||
- Mark deploy inflight when reverting a file change
|
||||
- Handle missing_flow_file error on clone properly
|
||||
- Remote project from cached list on delete so it can be reused
|
||||
- Fix tests for existing file flag in settings
|
||||
|
||||
Editor Fixes
|
||||
|
||||
- Fix merging a remote diff
|
||||
- Fixed the problems when using a node without defaults
|
||||
- Disable user defined icon for subflow
|
||||
- getDefaultNodeIcon should handle subflow instance nodes Fixes #1635
|
||||
- Add Japanese info text for core nodes
|
||||
- Fix message lookup for core nodes in case of i18 locales directory exists
|
||||
- Prevent the last tab from being deleted
|
||||
|
||||
Node Fixes
|
||||
|
||||
- Ensure trigger gets reset when 2nd output is null
|
||||
|
||||
|
||||
#### 0.18.3: Maintenance Release
|
||||
|
||||
Projects
|
||||
|
||||
@@ -30,13 +30,13 @@ At a minimum, please include:
|
||||
|
||||
## Feature requests
|
||||
|
||||
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
For feature requests, please raise them on the [forum](https://discourse.nodered.org).
|
||||
|
||||
## Pull-Requests
|
||||
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it may well get rejected if you haven't discussed it on
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
|
||||
the [forum](https://discourse.nodered.org) first.
|
||||
|
||||
All contributors need to sign the JS Foundation's Contributor License Agreement.
|
||||
It is an online process and quick to do. You can read the details of the agreement
|
||||
|
||||
11
Gruntfile.js
11
Gruntfile.js
@@ -24,6 +24,10 @@ module.exports = function(grunt) {
|
||||
nodemonArgs.push(flowFile);
|
||||
}
|
||||
|
||||
var nonHeadless = grunt.option('non-headless');
|
||||
if (nonHeadless) {
|
||||
process.env.NODE_RED_NON_HEADLESS = 'true';
|
||||
}
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
paths: {
|
||||
@@ -55,7 +59,7 @@ module.exports = function(grunt) {
|
||||
reportFormats: ['lcov','html'],
|
||||
print: 'both'
|
||||
},
|
||||
all: { src: ['test/**/*_spec.js'] },
|
||||
all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] },
|
||||
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
|
||||
nodes: { src: ["test/nodes/**/*_spec.js"]}
|
||||
},
|
||||
@@ -144,12 +148,15 @@ module.exports = function(grunt) {
|
||||
"editor/js/ui/keyboard.js",
|
||||
"editor/js/ui/workspaces.js",
|
||||
"editor/js/ui/view.js",
|
||||
"editor/js/ui/view-navigator.js",
|
||||
"editor/js/ui/sidebar.js",
|
||||
"editor/js/ui/palette.js",
|
||||
"editor/js/ui/tab-info.js",
|
||||
"editor/js/ui/tab-config.js",
|
||||
"editor/js/ui/tab-context.js",
|
||||
"editor/js/ui/palette-editor.js",
|
||||
"editor/js/ui/editor.js",
|
||||
"editor/js/ui/editors/*.js",
|
||||
"editor/js/ui/tray.js",
|
||||
"editor/js/ui/clipboard.js",
|
||||
"editor/js/ui/library.js",
|
||||
@@ -474,7 +481,7 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('default',
|
||||
'Builds editor content then runs code style checks and unit tests on all components',
|
||||
['build','test-core','test-editor','test-nodes']);
|
||||
['build','jshint:editor','mocha_istanbul:all']);
|
||||
|
||||
grunt.registerTask('test-core',
|
||||
'Runs code style check and unit tests on core runtime code',
|
||||
|
||||
@@ -22,8 +22,7 @@ started.
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the
|
||||
[mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
## Developers
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ done
|
||||
# Find the real location of this script
|
||||
CURRENT_PATH=`pwd`
|
||||
SCRIPT_PATH="${BASH_SOURCE[0]}";
|
||||
while([ -h "${SCRIPT_PATH}" ]); do
|
||||
while [ -h "${SCRIPT_PATH}" ]; do
|
||||
cd "`dirname "${SCRIPT_PATH}"`"
|
||||
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
|
||||
done
|
||||
|
||||
BIN
editor/icons/file-in.png
Normal file
BIN
editor/icons/file-in.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 542 B |
BIN
editor/icons/file-out.png
Normal file
BIN
editor/icons/file-out.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 503 B |
BIN
editor/images/typedInput/env.png
Normal file
BIN
editor/images/typedInput/env.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 809 B |
@@ -191,7 +191,7 @@ RED.history = (function() {
|
||||
} else if (ev.t == "edit") {
|
||||
for (i in ev.changes) {
|
||||
if (ev.changes.hasOwnProperty(i)) {
|
||||
if (ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
|
||||
if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
|
||||
// This is a config node property
|
||||
var currentConfigNode = RED.nodes.node(ev.node[i]);
|
||||
if (currentConfigNode) {
|
||||
@@ -229,10 +229,12 @@ RED.history = (function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.editor.validateNode(ev.node);
|
||||
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
||||
n.inputs = ev.node.in.length;
|
||||
n.outputs = ev.node.out.length;
|
||||
RED.editor.updateNodeProperties(n);
|
||||
RED.editor.validateNode(n);
|
||||
});
|
||||
} else {
|
||||
var outputMap;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"ctrl-g i": "core:show-info-tab",
|
||||
"ctrl-g d": "core:show-debug-tab",
|
||||
"ctrl-g c": "core:show-config-tab",
|
||||
"ctrl-g x": "core:show-context-tab",
|
||||
"ctrl-e": "core:show-export-dialog",
|
||||
"ctrl-i": "core:show-import-dialog",
|
||||
"ctrl-space": "core:toggle-sidebar",
|
||||
|
||||
@@ -15,6 +15,25 @@
|
||||
**/
|
||||
(function() {
|
||||
|
||||
function appendNodeConfig(nodeConfig) {
|
||||
var m = /<!-- --- \[red-module:(\S+)\] --- -->/.exec(nodeConfig.trim());
|
||||
var moduleId;
|
||||
if (m) {
|
||||
moduleId = m[1];
|
||||
} else {
|
||||
moduleId = "unknown";
|
||||
}
|
||||
try {
|
||||
$("body").append(nodeConfig);
|
||||
} catch(err) {
|
||||
RED.notify(RED._("notification.errors.failedToAppendNode",{module:moduleId, error:err.toString()}),{
|
||||
type: "error",
|
||||
timeout: 10000
|
||||
});
|
||||
console.log("["+moduleId+"] "+err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
function loadNodeList() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
@@ -55,7 +74,11 @@
|
||||
cache: false,
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
$("body").append(data);
|
||||
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
|
||||
configs.forEach(function(data) {
|
||||
appendNodeConfig(data);
|
||||
});
|
||||
|
||||
$("body").i18n();
|
||||
$("#palette > .palette-spinner").hide();
|
||||
$(".palette-scroll").removeClass("hide");
|
||||
@@ -130,13 +153,13 @@
|
||||
loadFlows(function() {
|
||||
var project = RED.projects.getActiveProject();
|
||||
var message = {
|
||||
"change-branch":"Change to local branch '"+project.git.branches.local+"'",
|
||||
"merge-abort":"Git merge aborted",
|
||||
"loaded":"Project '"+msg.project+"' loaded",
|
||||
"updated":"Project '"+msg.project+"' updated",
|
||||
"pull":"Project '"+msg.project+"' reloaded",
|
||||
"revert": "Project '"+msg.project+"' reloaded",
|
||||
"merge-complete":"Git merge completed"
|
||||
"change-branch": RED._("notification.project.change-branch", {project: project.git.branches.local}),
|
||||
"merge-abort": RED._("notification.project.merge-abort"),
|
||||
"loaded": RED._("notification.project.loaded", {project: msg.project}),
|
||||
"updated": RED._("notification.project.updated", {project: msg.project}),
|
||||
"pull": RED._("notification.project.pull", {project: msg.project}),
|
||||
"revert": RED._("notification.project.revert", {project: msg.project}),
|
||||
"merge-complete": RED._("notification.project.merge-complete")
|
||||
}[msg.action];
|
||||
RED.notify("<p>"+message+"</p>");
|
||||
RED.sidebar.info.refresh()
|
||||
@@ -160,7 +183,7 @@
|
||||
if (!!RED.projects.getActiveProject()) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Manage project dependencies",
|
||||
text: RED._("notification.label.manage-project-dep"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.settings.show('deps');
|
||||
@@ -171,7 +194,7 @@
|
||||
} else {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Close",
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
}
|
||||
@@ -179,13 +202,25 @@
|
||||
]
|
||||
}
|
||||
} else if (msg.error === "credentials_load_failed") {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
if (RED.settings.theme("projects.enabled",false)) {
|
||||
// projects enabled
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: RED._("notification.label.setup-cred"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.showCredentialsPrompt();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
} else {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Setup credentials",
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.showCredentialsPrompt();
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -194,7 +229,7 @@
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Setup project files",
|
||||
text: RED._("notification.label.setup-project"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.showFilesPrompt();
|
||||
@@ -202,17 +237,29 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
} else if (msg.error === "missing_package_file") {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: RED._("notification.label.create-default-package"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.createDefaultPackageFile();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
} else if (msg.error === "project_empty") {
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "No thanks",
|
||||
text: RED._("notification.label.no-thanks"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Create default project files",
|
||||
text: RED._("notification.label.create-default-project"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.projects.createDefaultFileSet();
|
||||
@@ -226,7 +273,7 @@
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
options.buttons = [
|
||||
{
|
||||
text: "Show merge conflicts",
|
||||
text: RED._("notification.label.show-merge-conflicts"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
RED.sidebar.versionControl.showLocalChanges();
|
||||
@@ -272,7 +319,7 @@
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadCatalog(id, function() {
|
||||
$.get('nodes/'+id, function(data) {
|
||||
$("body").append(data);
|
||||
appendNodeConfig(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -300,7 +347,7 @@
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
$.get('nodes/'+msg.id, function(data) {
|
||||
$("body").append(data);
|
||||
appendNodeConfig(data);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
});
|
||||
@@ -335,10 +382,10 @@
|
||||
function loadEditor() {
|
||||
var menuOptions = [];
|
||||
if (RED.settings.theme("projects.enabled",false)) {
|
||||
menuOptions.push({id:"menu-item-projects-menu",label:"Projects",options:[
|
||||
{id:"menu-item-projects-new",label:"New",disabled:false,onselect:"core:new-project"},
|
||||
{id:"menu-item-projects-open",label:"Open",disabled:false,onselect:"core:open-project"},
|
||||
{id:"menu-item-projects-settings",label:"Project Settings",disabled:false,onselect:"core:show-project-settings"}
|
||||
menuOptions.push({id:"menu-item-projects-menu",label:RED._("menu.label.projects"),options:[
|
||||
{id:"menu-item-projects-new",label:RED._("menu.label.projects-new"),disabled:false,onselect:"core:new-project"},
|
||||
{id:"menu-item-projects-open",label:RED._("menu.label.projects-open"),disabled:false,onselect:"core:open-project"},
|
||||
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
|
||||
]});
|
||||
}
|
||||
|
||||
@@ -363,8 +410,8 @@
|
||||
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"},
|
||||
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
|
||||
]});
|
||||
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
|
||||
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:"core:show-export-dialog"},
|
||||
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),options:[
|
||||
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-export-dialog"},
|
||||
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"}
|
||||
]});
|
||||
menuOptions.push(null);
|
||||
|
||||
@@ -133,7 +133,7 @@ RED.nodes = (function() {
|
||||
registerNodeType: function(nt,def) {
|
||||
nodeDefinitions[nt] = def;
|
||||
def.type = nt;
|
||||
if (def.category != "subflows") {
|
||||
if (nt.substring(0,8) != "subflow:") {
|
||||
def.set = nodeSets[typeToId[nt]];
|
||||
nodeSets[typeToId[nt]].added = true;
|
||||
nodeSets[typeToId[nt]].enabled = true;
|
||||
@@ -355,8 +355,8 @@ RED.nodes = (function() {
|
||||
RED.nodes.registerType("subflow:"+sf.id, {
|
||||
defaults:{name:{value:""}},
|
||||
info: sf.info,
|
||||
icon:"subflow.png",
|
||||
category: "subflows",
|
||||
icon: function() { return sf.icon||"subflow.png" },
|
||||
category: sf.category || "subflows",
|
||||
inputs: sf.in.length,
|
||||
outputs: sf.out.length,
|
||||
color: "#da9",
|
||||
@@ -491,7 +491,9 @@ RED.nodes = (function() {
|
||||
for (var j=0;j<wires.length;j++) {
|
||||
var w = wires[j];
|
||||
if (w.target.type != "subflow") {
|
||||
node.wires[w.sourcePort].push(w.target.id);
|
||||
if (w.sourcePort < node.wires.length) {
|
||||
node.wires[w.sourcePort].push(w.target.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,6 +519,7 @@ RED.nodes = (function() {
|
||||
node.type = n.type;
|
||||
node.name = n.name;
|
||||
node.info = n.info;
|
||||
node.category = n.category;
|
||||
node.in = [];
|
||||
node.out = [];
|
||||
|
||||
@@ -550,7 +553,11 @@ RED.nodes = (function() {
|
||||
if (node.out.length > 0 && n.outputLabels && !/^\s*$/.test(n.outputLabels.join(""))) {
|
||||
node.outputLabels = n.outputLabels.slice();
|
||||
}
|
||||
|
||||
if (n.icon) {
|
||||
if (n.icon !== "node-red/subflow.png") {
|
||||
node.icon = n.icon;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -749,7 +756,7 @@ RED.nodes = (function() {
|
||||
if (!isInitialLoad && unknownTypes.length > 0) {
|
||||
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
|
||||
var type = "type"+(unknownTypes.length > 1?"s":"");
|
||||
RED.notify("<strong>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</strong>"+typeList,"error",false,10000);
|
||||
RED.notify("<p>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</p>"+typeList,"error",false,10000);
|
||||
}
|
||||
|
||||
var activeWorkspace = RED.workspaces.active();
|
||||
@@ -1008,6 +1015,13 @@ RED.nodes = (function() {
|
||||
set: registry.getNodeSet("node-red/unknown")
|
||||
};
|
||||
node.users = [];
|
||||
// This is a config node, so delete the default
|
||||
// non-config node properties
|
||||
delete node.x;
|
||||
delete node.y;
|
||||
delete node.wires;
|
||||
delete node.inputLabels;
|
||||
delete node.outputLabels;
|
||||
}
|
||||
var orig = {};
|
||||
for (var p in n) {
|
||||
@@ -1020,10 +1034,31 @@ RED.nodes = (function() {
|
||||
node.type = "unknown";
|
||||
}
|
||||
if (node._def.category != "config") {
|
||||
node.inputs = n.inputs||node._def.inputs;
|
||||
node.outputs = n.outputs||node._def.outputs;
|
||||
if (n.hasOwnProperty('inputs')) {
|
||||
node.inputs = n.inputs;
|
||||
node._config.inputs = JSON.stringify(n.inputs);
|
||||
} else {
|
||||
node.inputs = node._def.inputs;
|
||||
}
|
||||
if (n.hasOwnProperty('outputs')) {
|
||||
node.outputs = n.outputs;
|
||||
node._config.outputs = JSON.stringify(n.outputs);
|
||||
} else {
|
||||
node.outputs = node._def.outputs;
|
||||
}
|
||||
if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) {
|
||||
if (!node._def.defaults.hasOwnProperty("outputs") || !isNaN(parseInt(n.outputs))) {
|
||||
// If 'wires' is longer than outputs, clip wires
|
||||
console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs);
|
||||
node.wires = node.wires.slice(0,node.outputs);
|
||||
} else {
|
||||
// The node declares outputs in its defaults, but has not got a valid value
|
||||
// Defer to the length of the wires array
|
||||
node.outputs = node.wires.length;
|
||||
}
|
||||
}
|
||||
for (d in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d)) {
|
||||
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
|
||||
node[d] = n[d];
|
||||
node._config[d] = JSON.stringify(n[d]);
|
||||
}
|
||||
@@ -1043,7 +1078,9 @@ RED.nodes = (function() {
|
||||
addNode(node);
|
||||
RED.editor.validateNode(node);
|
||||
node_map[n.id] = node;
|
||||
if (node._def.category != "config") {
|
||||
// If an 'unknown' config node, it will not have been caught by the
|
||||
// proper config node handling, so needs adding to new_nodes here
|
||||
if (node.type === "unknown" || node._def.category !== "config") {
|
||||
new_nodes.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,9 +276,20 @@ RED.clipboard = (function() {
|
||||
if (typeof value !== "string" ) {
|
||||
value = JSON.stringify(value, function(key,value) {
|
||||
if (value !== null && typeof value === 'object') {
|
||||
if (value.__encoded__ && value.hasOwnProperty('data') && value.hasOwnProperty('length')) {
|
||||
truncated = value.data.length !== value.length;
|
||||
return value.data;
|
||||
if (value.__enc__) {
|
||||
if (value.hasOwnProperty('data') && value.hasOwnProperty('length')) {
|
||||
truncated = value.data.length !== value.length;
|
||||
return value.data;
|
||||
}
|
||||
if (value.type === 'function' || value.type === 'internal') {
|
||||
return undefined
|
||||
}
|
||||
if (value.type === 'number') {
|
||||
// Handle NaN and Infinity - they are not permitted
|
||||
// in JSON. We can either substitute with a String
|
||||
// representation or null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
@@ -309,18 +320,6 @@ RED.clipboard = (function() {
|
||||
|
||||
$('<input type="text" id="clipboard-hidden">').appendTo("body");
|
||||
|
||||
RED.events.on("view:selection-changed",function(selection) {
|
||||
if (!selection.nodes) {
|
||||
RED.menu.setDisabled("menu-item-export",true);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",true);
|
||||
RED.menu.setDisabled("menu-item-export-library",true);
|
||||
} else {
|
||||
RED.menu.setDisabled("menu-item-export",false);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",false);
|
||||
RED.menu.setDisabled("menu-item-export-library",false);
|
||||
}
|
||||
});
|
||||
|
||||
RED.actions.add("core:show-export-dialog",exportNodes);
|
||||
RED.actions.add("core:show-import-dialog",importNodes);
|
||||
|
||||
|
||||
@@ -19,12 +19,14 @@ RED.popover = (function() {
|
||||
"default": {
|
||||
top: 10,
|
||||
leftRight: 17,
|
||||
leftLeft: 25
|
||||
leftLeft: 25,
|
||||
leftBottom: 8,
|
||||
},
|
||||
"small": {
|
||||
top: 5,
|
||||
leftRight: 17,
|
||||
leftLeft: 16
|
||||
leftLeft: 16,
|
||||
leftBottom: 3,
|
||||
}
|
||||
}
|
||||
function createPopover(options) {
|
||||
@@ -46,29 +48,39 @@ RED.popover = (function() {
|
||||
|
||||
var openPopup = function(instant) {
|
||||
if (active) {
|
||||
div = $('<div class="red-ui-popover red-ui-popover-'+direction+'"></div>').appendTo("body");
|
||||
div = $('<div class="red-ui-popover red-ui-popover-'+direction+'"></div>');
|
||||
if (size !== "default") {
|
||||
div.addClass("red-ui-popover-size-"+size);
|
||||
}
|
||||
if (typeof content === 'function') {
|
||||
content.call(res).appendTo(div);
|
||||
var result = content.call(res);
|
||||
if (result === null) {
|
||||
return;
|
||||
}
|
||||
if (typeof result === 'string') {
|
||||
div.text(result);
|
||||
} else {
|
||||
div.append(result);
|
||||
}
|
||||
} else {
|
||||
div.html(content);
|
||||
}
|
||||
if (width !== "auto") {
|
||||
div.width(width);
|
||||
}
|
||||
|
||||
div.appendTo("body");
|
||||
|
||||
var targetPos = target.offset();
|
||||
var targetWidth = target.width();
|
||||
var targetHeight = target.height();
|
||||
var targetWidth = target.outerWidth();
|
||||
var targetHeight = target.outerHeight();
|
||||
var divHeight = div.height();
|
||||
var divWidth = div.width();
|
||||
if (direction === 'right') {
|
||||
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight});
|
||||
} else if (direction === 'left') {
|
||||
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth});
|
||||
} else if (direction === 'bottom') {
|
||||
div.css({top: targetPos.top+targetHeight+deltaSizes[size].top,left:targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom});
|
||||
}
|
||||
if (instant) {
|
||||
div.show();
|
||||
@@ -143,7 +155,17 @@ RED.popover = (function() {
|
||||
}
|
||||
|
||||
return {
|
||||
create: createPopover
|
||||
create: createPopover,
|
||||
tooltip: function(target,content) {
|
||||
RED.popover.create({
|
||||
target:target,
|
||||
trigger: "hover",
|
||||
size: "small",
|
||||
direction: "bottom",
|
||||
content: content,
|
||||
delay: { show: 550, hide: 10 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
|
||||
|
||||
RED.tabs = (function() {
|
||||
|
||||
var defaultTabIcon = "fa fa-lemon-o";
|
||||
|
||||
function createTabs(options) {
|
||||
var tabs = {};
|
||||
var pinnedTabsCount = 0;
|
||||
var currentTabWidth;
|
||||
var currentActiveTabWidth = 0;
|
||||
var collapsibleMenu;
|
||||
|
||||
var ul = options.element || $("#"+options.id);
|
||||
var wrapper = ul.wrap( "<div>" ).parent();
|
||||
@@ -50,6 +55,56 @@ RED.tabs = (function() {
|
||||
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();});
|
||||
}
|
||||
|
||||
if (options.collapsible) {
|
||||
// var dropDown = $('<div>',{class:"red-ui-tabs-select"}).appendTo(wrapper);
|
||||
// ul.hide();
|
||||
wrapper.addClass("red-ui-tabs-collapsible");
|
||||
|
||||
var collapsedButtonsRow = $('<div class="red-ui-tab-link-buttons"></div>').appendTo(wrapper);
|
||||
|
||||
var selectButton = $('<a href="#"><i class="fa fa-caret-down"></i></a>').appendTo(collapsedButtonsRow);
|
||||
selectButton.addClass("red-ui-tab-link-button-menu")
|
||||
selectButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
if (!collapsibleMenu) {
|
||||
var pinnedOptions = [];
|
||||
var options = [];
|
||||
ul.children().each(function(i,el) {
|
||||
var id = $(el).data('tabId');
|
||||
var opt = {
|
||||
id:"red-ui-tabs-menu-option-"+id,
|
||||
icon: tabs[id].iconClass || defaultTabIcon,
|
||||
label: tabs[id].name,
|
||||
onselect: function() {
|
||||
activateTab(id);
|
||||
}
|
||||
};
|
||||
if (tabs[id].pinned) {
|
||||
pinnedOptions.push(opt);
|
||||
} else {
|
||||
options.push(opt);
|
||||
}
|
||||
});
|
||||
options = pinnedOptions.concat(options);
|
||||
collapsibleMenu = RED.menu.init({id:"debug-message-option-menu",options: options});
|
||||
collapsibleMenu.css({
|
||||
position: "absolute"
|
||||
})
|
||||
collapsibleMenu.on('mouseleave', function(){ $(this).hide() });
|
||||
collapsibleMenu.on('mouseup', function() { $(this).hide() });
|
||||
collapsibleMenu.appendTo("body");
|
||||
}
|
||||
var elementPos = selectButton.offset();
|
||||
collapsibleMenu.css({
|
||||
top: (elementPos.top+selectButton.height()-20)+"px",
|
||||
left: (elementPos.left - collapsibleMenu.width() + selectButton.width())+"px"
|
||||
})
|
||||
collapsibleMenu.toggle();
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function scrollEventHandler(evt,dir) {
|
||||
evt.preventDefault();
|
||||
if ($(this).hasClass('disabled')) {
|
||||
@@ -118,6 +173,9 @@ RED.tabs = (function() {
|
||||
ul.children().removeClass("active");
|
||||
ul.children().css({"transition": "width 100ms"});
|
||||
link.parent().addClass("active");
|
||||
var parentId = link.parent().attr('id');
|
||||
wrapper.find(".red-ui-tab-link-button").removeClass("active selected");
|
||||
$("#"+parentId+"-link-button").addClass("active selected");
|
||||
if (options.scrollable) {
|
||||
var pos = link.parent().position().left;
|
||||
if (pos-21 < 0) {
|
||||
@@ -155,41 +213,70 @@ RED.tabs = (function() {
|
||||
var tabs = ul.find("li.red-ui-tab");
|
||||
var width = wrapper.width();
|
||||
var tabCount = tabs.size();
|
||||
var tabWidth = (width-12-(tabCount*6))/tabCount;
|
||||
currentTabWidth = (100*tabWidth/width)+"%";
|
||||
currentActiveTabWidth = currentTabWidth+"%";
|
||||
if (options.scrollable) {
|
||||
tabWidth = Math.max(tabWidth,140);
|
||||
currentTabWidth = tabWidth+"px";
|
||||
currentActiveTabWidth = 0;
|
||||
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
|
||||
ul.width(listWidth);
|
||||
updateScroll();
|
||||
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
|
||||
if (tabWidth < options.minimumActiveTabWidth) {
|
||||
tabCount -= 1;
|
||||
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
|
||||
currentTabWidth = (100*tabWidth/width)+"%";
|
||||
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
|
||||
var tabWidth;
|
||||
|
||||
if (options.collapsible) {
|
||||
tabWidth = width - collapsedButtonsRow.width()-10;
|
||||
if (tabWidth < 198) {
|
||||
var delta = 198 - tabWidth;
|
||||
var b = collapsedButtonsRow.find("a:last").prev();
|
||||
while (b.is(":not(:visible)")) {
|
||||
b = b.prev();
|
||||
}
|
||||
if (!b.hasClass("red-ui-tab-link-button-pinned")) {
|
||||
b.hide();
|
||||
}
|
||||
tabWidth = width - collapsedButtonsRow.width()-10;
|
||||
} else {
|
||||
currentActiveTabWidth = 0;
|
||||
var space = width - 198 - collapsedButtonsRow.width();
|
||||
if (space > 40) {
|
||||
collapsedButtonsRow.find("a:not(:visible):first").show();
|
||||
tabWidth = width - collapsedButtonsRow.width()-10;
|
||||
}
|
||||
}
|
||||
}
|
||||
tabs.css({width:currentTabWidth});
|
||||
if (tabWidth < 50) {
|
||||
ul.find(".red-ui-tab-close").hide();
|
||||
ul.find(".red-ui-tab-icon").hide();
|
||||
ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"})
|
||||
tabs.css({width:tabWidth});
|
||||
|
||||
} else {
|
||||
ul.find(".red-ui-tab-close").show();
|
||||
ul.find(".red-ui-tab-icon").show();
|
||||
ul.find(".red-ui-tab-label").css({paddingLeft:""})
|
||||
}
|
||||
if (currentActiveTabWidth !== 0) {
|
||||
ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth});
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-close").show();
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-icon").show();
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""})
|
||||
var tabWidth = (width-12-(tabCount*6))/tabCount;
|
||||
currentTabWidth = (100*tabWidth/width)+"%";
|
||||
currentActiveTabWidth = currentTabWidth+"%";
|
||||
if (options.scrollable) {
|
||||
tabWidth = Math.max(tabWidth,140);
|
||||
currentTabWidth = tabWidth+"px";
|
||||
currentActiveTabWidth = 0;
|
||||
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
|
||||
ul.width(listWidth);
|
||||
updateScroll();
|
||||
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
|
||||
if (tabWidth < options.minimumActiveTabWidth) {
|
||||
tabCount -= 1;
|
||||
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
|
||||
currentTabWidth = (100*tabWidth/width)+"%";
|
||||
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
|
||||
} else {
|
||||
currentActiveTabWidth = 0;
|
||||
}
|
||||
}
|
||||
if (options.collapsible) {
|
||||
console.log(currentTabWidth);
|
||||
}
|
||||
|
||||
tabs.css({width:currentTabWidth});
|
||||
if (tabWidth < 50) {
|
||||
ul.find(".red-ui-tab-close").hide();
|
||||
ul.find(".red-ui-tab-icon").hide();
|
||||
ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"})
|
||||
} else {
|
||||
ul.find(".red-ui-tab-close").show();
|
||||
ul.find(".red-ui-tab-icon").show();
|
||||
ul.find(".red-ui-tab-label").css({paddingLeft:""})
|
||||
}
|
||||
if (currentActiveTabWidth !== 0) {
|
||||
ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth});
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-close").show();
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-icon").show();
|
||||
ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -210,11 +297,15 @@ RED.tabs = (function() {
|
||||
activateTab(tab.find("a"));
|
||||
}
|
||||
li.remove();
|
||||
if (tabs[id].pinned) {
|
||||
pinnedTabsCount--;
|
||||
}
|
||||
if (options.onremove) {
|
||||
options.onremove(tabs[id]);
|
||||
}
|
||||
delete tabs[id];
|
||||
updateTabWidths();
|
||||
collapsibleMenu = null;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -223,13 +314,48 @@ RED.tabs = (function() {
|
||||
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
|
||||
li.attr('id',"red-ui-tab-"+(tab.id.replace(".","-")));
|
||||
li.data("tabId",tab.id);
|
||||
|
||||
if (options.maximumTabWidth) {
|
||||
li.css("maxWidth",options.maximumTabWidth+"px");
|
||||
}
|
||||
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
||||
if (tab.icon) {
|
||||
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
||||
} else if (tab.iconClass) {
|
||||
$('<i>',{class:"red-ui-tab-icon "+tab.iconClass}).appendTo(link);
|
||||
}
|
||||
var span = $('<span/>',{class:"bidiAware"}).text(tab.label).appendTo(link);
|
||||
span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label));
|
||||
if (options.collapsible) {
|
||||
li.addClass("red-ui-tab-pinned");
|
||||
var pinnedLink = $('<a href="#'+tab.id+'" class="red-ui-tab-link-button"></a>');
|
||||
if (tab.pinned) {
|
||||
if (pinnedTabsCount === 0) {
|
||||
pinnedLink.prependTo(collapsedButtonsRow)
|
||||
} else {
|
||||
pinnedLink.insertAfter(collapsedButtonsRow.find("a.red-ui-tab-link-button-pinned:last"));
|
||||
}
|
||||
} else {
|
||||
pinnedLink.insertBefore(collapsedButtonsRow.find("a:last"));
|
||||
}
|
||||
|
||||
pinnedLink.attr('id',li.attr('id')+"-link-button");
|
||||
if (tab.iconClass) {
|
||||
$('<i>',{class:tab.iconClass}).appendTo(pinnedLink);
|
||||
} else {
|
||||
$('<i>',{class:defaultTabIcon}).appendTo(pinnedLink);
|
||||
}
|
||||
pinnedLink.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
activateTab(tab.id);
|
||||
});
|
||||
if (tab.pinned) {
|
||||
pinnedLink.addClass("red-ui-tab-link-button-pinned");
|
||||
pinnedTabsCount++;
|
||||
}
|
||||
RED.popover.tooltip($(pinnedLink), tab.name);
|
||||
|
||||
}
|
||||
link.on("click",onTabClick);
|
||||
link.on("dblclick",onTabDblClick);
|
||||
if (tab.closeable) {
|
||||
@@ -241,7 +367,6 @@ RED.tabs = (function() {
|
||||
removeTab(tab.id);
|
||||
});
|
||||
}
|
||||
updateTabWidths();
|
||||
if (options.onadd) {
|
||||
options.onadd(tab);
|
||||
}
|
||||
@@ -326,6 +451,10 @@ RED.tabs = (function() {
|
||||
}
|
||||
})
|
||||
}
|
||||
setTimeout(function() {
|
||||
updateTabWidths();
|
||||
},10);
|
||||
collapsibleMenu = null;
|
||||
},
|
||||
removeTab: removeTab,
|
||||
activateTab: activateTab,
|
||||
|
||||
@@ -14,10 +14,38 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
(function($) {
|
||||
var contextParse = function(v) {
|
||||
var parts = RED.utils.parseContextKey(v);
|
||||
return {
|
||||
option: parts.store,
|
||||
value: parts.key
|
||||
}
|
||||
}
|
||||
var contextExport = function(v,opt) {
|
||||
if (!opt) {
|
||||
return v;
|
||||
}
|
||||
var store = ((typeof opt === "string")?opt:opt.value)
|
||||
if (store !== RED.settings.context.default) {
|
||||
return "#:("+store+")::"+v;
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
var allOptions = {
|
||||
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression},
|
||||
flow: {value:"flow",label:"flow.",validate:RED.utils.validatePropertyExpression},
|
||||
global: {value:"global",label:"global.",validate:RED.utils.validatePropertyExpression},
|
||||
flow: {value:"flow",label:"flow.",hasValue:true,
|
||||
options:[],
|
||||
validate:RED.utils.validatePropertyExpression,
|
||||
parse: contextParse,
|
||||
export: contextExport
|
||||
},
|
||||
global: {value:"global",label:"global.",hasValue:true,
|
||||
options:[],
|
||||
validate:RED.utils.validatePropertyExpression,
|
||||
parse: contextParse,
|
||||
export: contextExport
|
||||
},
|
||||
str: {value:"str",label:"string",icon:"red/images/typedInput/az.png"},
|
||||
num: {value:"num",label:"number",icon:"red/images/typedInput/09.png",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/},
|
||||
bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.png",options:["true","false"]},
|
||||
@@ -76,31 +104,51 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
env: {
|
||||
value: "env",
|
||||
label: "env variable",
|
||||
icon: "red/images/typedInput/env.png"
|
||||
}
|
||||
};
|
||||
var nlsd = false;
|
||||
|
||||
$.widget( "nodered.typedInput", {
|
||||
_create: function() {
|
||||
try {
|
||||
if (!nlsd && RED && RED._) {
|
||||
for (var i in allOptions) {
|
||||
if (allOptions.hasOwnProperty(i)) {
|
||||
allOptions[i].label = RED._("typedInput.type."+i,{defaultValue:allOptions[i].label});
|
||||
}
|
||||
}
|
||||
var contextStores = RED.settings.context.stores;
|
||||
var contextOptions = contextStores.map(function(store) {
|
||||
return {value:store,label: store, icon:'<i class="red-ui-typedInput-icon fa fa-database" style="color: #'+(store==='memory'?'ddd':'777')+'"></i>'}
|
||||
})
|
||||
if (contextOptions.length < 2) {
|
||||
allOptions.flow.options = [];
|
||||
allOptions.global.options = [];
|
||||
} else {
|
||||
allOptions.flow.options = contextOptions;
|
||||
allOptions.global.options = contextOptions;
|
||||
}
|
||||
}
|
||||
nlsd = true;
|
||||
var that = this;
|
||||
|
||||
this.disarmClick = false;
|
||||
this.input = $('<input type="text"></input>');
|
||||
this.input.insertAfter(this.element);
|
||||
this.input.val(this.element.val());
|
||||
this.element.addClass('red-ui-typedInput');
|
||||
this.uiWidth = this.element.outerWidth();
|
||||
this.elementDiv = this.element.wrap("<div>").parent().addClass('red-ui-typedInput-input');
|
||||
this.elementDiv = this.input.wrap("<div>").parent().addClass('red-ui-typedInput-input');
|
||||
this.uiSelect = this.elementDiv.wrap( "<div>" ).parent();
|
||||
var attrStyle = this.element.attr('style');
|
||||
var m;
|
||||
if ((m = /width\s*:\s*(calc\s*\(.*\)|\d+(%|px))/i.exec(attrStyle)) !== null) {
|
||||
this.element.css('width','100%');
|
||||
this.input.css('width','100%');
|
||||
this.uiSelect.width(m[1]);
|
||||
this.uiWidth = null;
|
||||
} else {
|
||||
@@ -109,15 +157,19 @@
|
||||
["Right","Left"].forEach(function(d) {
|
||||
var m = that.element.css("margin"+d);
|
||||
that.uiSelect.css("margin"+d,m);
|
||||
that.element.css("margin"+d,0);
|
||||
that.input.css("margin"+d,0);
|
||||
});
|
||||
|
||||
this.uiSelect.addClass("red-ui-typedInput-container");
|
||||
|
||||
this.element.attr('type','hidden');
|
||||
|
||||
this.options.types = this.options.types||Object.keys(allOptions);
|
||||
|
||||
this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect);
|
||||
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
|
||||
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
|
||||
$('<i class="red-ui-typedInput-icon fa fa-sort-desc"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger);
|
||||
|
||||
this.selectLabel = $('<span class="red-ui-typedInput-type-label"></span>').appendTo(this.selectTrigger);
|
||||
|
||||
this.types(this.options.types);
|
||||
|
||||
@@ -131,14 +183,16 @@
|
||||
this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect);
|
||||
}
|
||||
|
||||
this.element.on('focus', function() {
|
||||
this.input.on('focus', function() {
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
});
|
||||
this.element.on('blur', function() {
|
||||
this.input.on('blur', function() {
|
||||
that.uiSelect.removeClass('red-ui-typedInput-focus');
|
||||
});
|
||||
this.element.on('change', function() {
|
||||
this.input.on('change', function() {
|
||||
that.validate();
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('change',that.propertyType,that.value());
|
||||
})
|
||||
this.selectTrigger.click(function(event) {
|
||||
event.preventDefault();
|
||||
@@ -154,8 +208,11 @@
|
||||
})
|
||||
|
||||
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
|
||||
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect);
|
||||
this.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-sort-desc"></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;
|
||||
});
|
||||
this.optionSelectTrigger.click(function(event) {
|
||||
event.preventDefault();
|
||||
that._showOptionSelectMenu();
|
||||
@@ -170,17 +227,18 @@
|
||||
that.uiSelect.addClass('red-ui-typedInput-focus');
|
||||
});
|
||||
|
||||
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"><i class="fa fa-ellipsis-h"></i></button>').appendTo(this.uiSelect);
|
||||
|
||||
|
||||
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"><i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i></button>').appendTo(this.uiSelect);
|
||||
this.type(this.options.default||this.typeList[0].value);
|
||||
}catch(err) {
|
||||
console.log(err.stack);
|
||||
}
|
||||
},
|
||||
_showTypeMenu: function() {
|
||||
if (this.typeList.length > 1) {
|
||||
this._showMenu(this.menu,this.selectTrigger);
|
||||
this.menu.find("[value='"+this.propertyType+"']").focus();
|
||||
} else {
|
||||
this.element.focus();
|
||||
this.input.focus();
|
||||
}
|
||||
},
|
||||
_showOptionSelectMenu: function() {
|
||||
@@ -189,8 +247,8 @@
|
||||
minWidth:this.optionSelectLabel.width()
|
||||
});
|
||||
|
||||
this._showMenu(this.optionMenu,this.optionSelectLabel);
|
||||
var selectedOption = this.optionMenu.find("[value='"+this.value()+"']");
|
||||
this._showMenu(this.optionMenu,this.optionSelectTrigger);
|
||||
var selectedOption = this.optionMenu.find("[value='"+this.optionValue+"']");
|
||||
if (selectedOption.length === 0) {
|
||||
selectedOption = this.optionMenu.children(":first");
|
||||
}
|
||||
@@ -202,7 +260,7 @@
|
||||
$(document).off("mousedown.close-property-select");
|
||||
menu.hide();
|
||||
if (this.elementDiv.is(":visible")) {
|
||||
this.element.focus();
|
||||
this.input.focus();
|
||||
} else if (this.optionSelectTrigger.is(":visible")){
|
||||
this.optionSelectTrigger.focus();
|
||||
} else {
|
||||
@@ -221,10 +279,19 @@
|
||||
op.text(opt.label);
|
||||
}
|
||||
if (opt.icon) {
|
||||
$('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op);
|
||||
if (opt.icon.indexOf("<") === 0) {
|
||||
$(opt.icon).prependTo(op);
|
||||
} else if (opt.icon.indexOf("/") !== -1) {
|
||||
$('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op);
|
||||
} else {
|
||||
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(op);
|
||||
}
|
||||
} else {
|
||||
op.css({paddingLeft: "18px"});
|
||||
}
|
||||
if (!opt.icon && !opt.label) {
|
||||
op.text(opt.value);
|
||||
}
|
||||
|
||||
op.click(function(event) {
|
||||
event.preventDefault();
|
||||
@@ -303,7 +370,8 @@
|
||||
if (this.uiWidth !== null) {
|
||||
this.uiSelect.width(this.uiWidth);
|
||||
}
|
||||
if (this.typeMap[this.propertyType] && this.typeMap[this.propertyType].hasValue === false) {
|
||||
var type = this.typeMap[this.propertyType];
|
||||
if (type && type.hasValue === false) {
|
||||
this.selectTrigger.addClass("red-ui-typedInput-full-width");
|
||||
} else {
|
||||
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
|
||||
@@ -313,13 +381,68 @@
|
||||
this.elementDiv.css('right',"22px");
|
||||
} else {
|
||||
this.elementDiv.css('right','0');
|
||||
this.input.css({
|
||||
'border-top-right-radius': '4px',
|
||||
'border-bottom-right-radius': '4px'
|
||||
});
|
||||
}
|
||||
|
||||
// if (this.optionSelectTrigger) {
|
||||
// this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'});
|
||||
// }
|
||||
|
||||
if (this.optionSelectTrigger) {
|
||||
this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'});
|
||||
if (type && type.options && type.hasValue === true) {
|
||||
this.optionSelectLabel.css({'left':'auto'})
|
||||
var lw = this._getLabelWidth(this.optionSelectLabel);
|
||||
this.optionSelectTrigger.css({'width':(23+lw)+"px"});
|
||||
this.elementDiv.css('right',(23+lw)+"px");
|
||||
this.input.css({
|
||||
'border-top-right-radius': 0,
|
||||
'border-bottom-right-radius': 0
|
||||
});
|
||||
} else {
|
||||
this.optionSelectLabel.css({'left':'0'})
|
||||
this.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'});
|
||||
if (!this.optionExpandButton.is(":visible")) {
|
||||
this.elementDiv.css({'right':0});
|
||||
this.input.css({
|
||||
'border-top-right-radius': '4px',
|
||||
'border-bottom-right-radius': '4px'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_updateOptionSelectLabel: function(o) {
|
||||
var opt = this.typeMap[this.propertyType];
|
||||
this.optionSelectLabel.empty();
|
||||
if (o.icon) {
|
||||
if (o.icon.indexOf("<") === 0) {
|
||||
$(o.icon).prependTo(this.optionSelectLabel);
|
||||
} else if (o.icon.indexOf("/") !== -1) {
|
||||
// url
|
||||
$('<img>',{src:o.icon,style:"height: 18px;"}).prependTo(this.optionSelectLabel);
|
||||
} else {
|
||||
// icon class
|
||||
$('<i>',{class:"red-ui-typedInput-icon "+o.icon}).prependTo(this.optionSelectLabel);
|
||||
}
|
||||
} else if (o.label) {
|
||||
this.optionSelectLabel.text(o.label);
|
||||
} else {
|
||||
this.optionSelectLabel.text(o.value);
|
||||
}
|
||||
if (opt.hasValue) {
|
||||
this.optionValue = o.value;
|
||||
this._resize();
|
||||
this.input.trigger('change',this.propertyType,this.value());
|
||||
}
|
||||
},
|
||||
_destroy: function() {
|
||||
if (this.optionMenu) {
|
||||
this.optionMenu.remove();
|
||||
}
|
||||
this.menu.remove();
|
||||
},
|
||||
types: function(types) {
|
||||
@@ -337,13 +460,18 @@
|
||||
return result;
|
||||
});
|
||||
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
|
||||
this.selectTrigger.find(".fa-sort-desc").toggle(this.typeList.length > 1)
|
||||
if (this.menu) {
|
||||
this.menu.remove();
|
||||
}
|
||||
this.menu = this._createMenu(this.typeList, function(v) { that.type(v) });
|
||||
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
|
||||
this.type(this.typeList[0].value);
|
||||
} else {
|
||||
this.propertyType = null;
|
||||
this.type(currentType);
|
||||
}
|
||||
setTimeout(function() {that._resize();},0);
|
||||
},
|
||||
width: function(desiredWidth) {
|
||||
this.uiWidth = desiredWidth;
|
||||
@@ -351,33 +479,33 @@
|
||||
},
|
||||
value: function(value) {
|
||||
if (!arguments.length) {
|
||||
return this.element.val();
|
||||
var v = this.input.val();
|
||||
if (this.typeMap[this.propertyType].export) {
|
||||
v = this.typeMap[this.propertyType].export(v,this.optionValue)
|
||||
}
|
||||
return v;
|
||||
} else {
|
||||
var selectedOption;
|
||||
if (this.typeMap[this.propertyType].options) {
|
||||
var validValue = false;
|
||||
var label;
|
||||
for (var i=0;i<this.typeMap[this.propertyType].options.length;i++) {
|
||||
var op = this.typeMap[this.propertyType].options[i];
|
||||
if (typeof op === "string") {
|
||||
if (op === value) {
|
||||
label = value;
|
||||
validValue = true;
|
||||
selectedOption = this.activeOptions[op];
|
||||
break;
|
||||
}
|
||||
} else if (op.value === value) {
|
||||
label = op.label||op.value;
|
||||
validValue = true;
|
||||
selectedOption = op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!validValue) {
|
||||
value = "";
|
||||
label = "";
|
||||
if (!selectedOption) {
|
||||
selectedOption = {value:""}
|
||||
}
|
||||
this.optionSelectLabel.text(label);
|
||||
this._updateOptionSelectLabel(selectedOption)
|
||||
}
|
||||
this.element.val(value);
|
||||
this.element.trigger('change',this.type(),value);
|
||||
this.input.val(value);
|
||||
this.input.trigger('change',this.type(),value);
|
||||
}
|
||||
},
|
||||
type: function(type) {
|
||||
@@ -388,7 +516,9 @@
|
||||
var opt = this.typeMap[type];
|
||||
if (opt && this.propertyType !== type) {
|
||||
this.propertyType = type;
|
||||
this.typeField.val(type);
|
||||
if (this.typeField) {
|
||||
this.typeField.val(type);
|
||||
}
|
||||
this.selectLabel.empty();
|
||||
var image;
|
||||
if (opt.icon) {
|
||||
@@ -405,37 +535,88 @@
|
||||
}
|
||||
if (this.optionSelectTrigger) {
|
||||
this.optionSelectTrigger.show();
|
||||
this.elementDiv.hide();
|
||||
this.optionMenu = this._createMenu(opt.options,function(v){
|
||||
that.optionSelectLabel.text(v);
|
||||
that.value(v);
|
||||
if (!opt.hasValue) {
|
||||
this.elementDiv.hide();
|
||||
} else {
|
||||
this.elementDiv.show();
|
||||
}
|
||||
this.activeOptions = {};
|
||||
opt.options.forEach(function(o) {
|
||||
if (typeof o === 'string') {
|
||||
that.activeOptions[o] = {label:o,value:o};
|
||||
} else {
|
||||
that.activeOptions[o.value] = o;
|
||||
}
|
||||
});
|
||||
|
||||
if (!that.activeOptions.hasOwnProperty(that.optionValue)) {
|
||||
that.optionValue = null;
|
||||
}
|
||||
this.optionMenu = this._createMenu(opt.options,function(v){
|
||||
that._updateOptionSelectLabel(that.activeOptions[v]);
|
||||
if (!opt.hasValue) {
|
||||
that.value(that.activeOptions[v].value)
|
||||
}
|
||||
});
|
||||
var currentVal = this.element.val();
|
||||
var validValue = false;
|
||||
var op;
|
||||
for (var i=0;i<opt.options.length;i++) {
|
||||
op = opt.options[i];
|
||||
if (typeof op === "string") {
|
||||
if (op === currentVal) {
|
||||
this.optionSelectLabel.text(currentVal);
|
||||
if (!opt.hasValue) {
|
||||
var currentVal = this.input.val();
|
||||
var validValue = false;
|
||||
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;
|
||||
}
|
||||
} else if (op.value === currentVal) {
|
||||
this.optionSelectLabel.text(op.label||op.value);
|
||||
validValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!validValue) {
|
||||
op = opt.options[0];
|
||||
if (typeof op === "string") {
|
||||
this.value(op);
|
||||
if (!validValue) {
|
||||
op = opt.options[0];
|
||||
if (typeof op === "string") {
|
||||
this.value(op);
|
||||
that._updateOptionSelectLabel({value:op});
|
||||
} else {
|
||||
this.value(op.value);
|
||||
that._updateOptionSelectLabel(op);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var selectedOption = this.optionValue||opt.options[0];
|
||||
if (opt.parse) {
|
||||
var parts = opt.parse(this.input.val());
|
||||
if (parts.option) {
|
||||
selectedOption = parts.option;
|
||||
if (!this.activeOptions.hasOwnProperty(selectedOption)) {
|
||||
parts.option = Object.keys(this.activeOptions)[0];
|
||||
selectedOption = parts.option
|
||||
}
|
||||
}
|
||||
this.input.val(parts.value);
|
||||
if (opt.export) {
|
||||
this.element.val(opt.export(parts.value,parts.option||selectedOption));
|
||||
}
|
||||
}
|
||||
if (typeof selectedOption === "string") {
|
||||
this.optionValue = selectedOption;
|
||||
if (!this.activeOptions.hasOwnProperty(selectedOption)) {
|
||||
selectedOption = Object.keys(this.activeOptions)[0];
|
||||
}
|
||||
if (!selectedOption) {
|
||||
this.optionSelectTrigger.hide();
|
||||
} else {
|
||||
this._updateOptionSelectLabel(this.activeOptions[selectedOption]);
|
||||
}
|
||||
} else if (selectedOption) {
|
||||
this.optionValue = selectedOption.value;
|
||||
this._updateOptionSelectLabel(selectedOption);
|
||||
} else {
|
||||
this.value(op.value);
|
||||
this.optionSelectTrigger.hide();
|
||||
}
|
||||
}
|
||||
console.log(validValue);
|
||||
}
|
||||
} else {
|
||||
if (this.optionMenu) {
|
||||
@@ -446,27 +627,29 @@
|
||||
this.optionSelectTrigger.hide();
|
||||
}
|
||||
if (opt.hasValue === false) {
|
||||
this.oldValue = this.element.val();
|
||||
this.element.val("");
|
||||
this.oldValue = this.input.val();
|
||||
this.input.val("");
|
||||
this.elementDiv.hide();
|
||||
} else {
|
||||
if (this.oldValue !== undefined) {
|
||||
this.element.val(this.oldValue);
|
||||
this.input.val(this.oldValue);
|
||||
delete this.oldValue;
|
||||
}
|
||||
this.elementDiv.show();
|
||||
}
|
||||
if (opt.expand && typeof opt.expand === 'function') {
|
||||
this.optionExpandButton.show();
|
||||
this.optionExpandButton.off('click');
|
||||
this.optionExpandButton.on('click',function(evt) {
|
||||
evt.preventDefault();
|
||||
opt.expand.call(that);
|
||||
})
|
||||
} else {
|
||||
this.optionExpandButton.hide();
|
||||
if (this.optionExpandButton) {
|
||||
if (opt.expand && typeof opt.expand === 'function') {
|
||||
this.optionExpandButton.show();
|
||||
this.optionExpandButton.off('click');
|
||||
this.optionExpandButton.on('click',function(evt) {
|
||||
evt.preventDefault();
|
||||
opt.expand.call(that);
|
||||
})
|
||||
} else {
|
||||
this.optionExpandButton.hide();
|
||||
}
|
||||
}
|
||||
this.element.trigger('change',this.propertyType,this.value());
|
||||
this.input.trigger('change',this.propertyType,this.value());
|
||||
}
|
||||
if (image) {
|
||||
image.onload = function() { that._resize(); }
|
||||
|
||||
@@ -408,9 +408,12 @@ RED.deploy = (function() {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachSubflow(function(subflow) {
|
||||
subflow.changed = false;
|
||||
});
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
ws.changed = false;
|
||||
})
|
||||
});
|
||||
// Once deployed, cannot undo back to a clean state
|
||||
RED.history.markAllDirty();
|
||||
RED.view.redraw();
|
||||
|
||||
@@ -51,11 +51,11 @@ RED.diff = (function() {
|
||||
var tabForLabel = (object.newTab || object.tab).n;
|
||||
var titleSpan = $('<span>',{class:"node-diff-tab-title-meta"}).appendTo(originalCell);
|
||||
if (tabForLabel.type === 'tab') {
|
||||
titleSpan.html(tabForLabel.label||tabForLabel.id);
|
||||
titleSpan.text(tabForLabel.label||tabForLabel.id);
|
||||
} else if (tab.type === 'subflow') {
|
||||
titleSpan.html((tabForLabel.name||tabForLabel.id));
|
||||
titleSpan.text((tabForLabel.name||tabForLabel.id));
|
||||
} else {
|
||||
titleSpan.html(RED._("diff.globalNodes"));
|
||||
titleSpan.text(RED._("diff.globalNodes"));
|
||||
}
|
||||
var flowStats = {
|
||||
local: {
|
||||
@@ -131,7 +131,7 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
$('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalNodeDiv);
|
||||
$('<span>').html(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
|
||||
$('<span>').text(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
|
||||
|
||||
row.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -206,7 +206,7 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
var localStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(localCell);
|
||||
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
|
||||
$('<span class="node-diff-status"></span>').text(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
|
||||
|
||||
if (flowStats.conflicts + flowStats.local.addedCount + flowStats.local.changedCount + flowStats.local.deletedCount > 0) {
|
||||
$('<span class="node-diff-status"> [ </span>').appendTo(localStats);
|
||||
@@ -245,7 +245,7 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
var remoteStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(remoteCell);
|
||||
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
|
||||
$('<span class="node-diff-status"></span>').text(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
|
||||
if (flowStats.conflicts + flowStats.remote.addedCount + flowStats.remote.changedCount + flowStats.remote.deletedCount > 0) {
|
||||
$('<span class="node-diff-status"> [ </span>').appendTo(remoteStats);
|
||||
if (flowStats.conflicts > 0) {
|
||||
@@ -464,7 +464,7 @@ RED.diff = (function() {
|
||||
wires.forEach(function(p,i) {
|
||||
var port = $("<li>").appendTo(list);
|
||||
if (p && p.length > 0) {
|
||||
$("<span>").html(i+1).appendTo(port);
|
||||
$("<span>").text(i+1).appendTo(port);
|
||||
var links = $("<ul>").appendTo(port);
|
||||
p.forEach(function(d) {
|
||||
c++;
|
||||
@@ -474,15 +474,15 @@ RED.diff = (function() {
|
||||
var def = RED.nodes.getType(node.type)||{};
|
||||
createNode(node,def).appendTo(entry);
|
||||
} else {
|
||||
entry.html(d);
|
||||
entry.text(d);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
port.html('none');
|
||||
port.text('none');
|
||||
}
|
||||
})
|
||||
if (c === 0) {
|
||||
result.html("none");
|
||||
result.text("none");
|
||||
} else {
|
||||
list.appendTo(result);
|
||||
}
|
||||
@@ -490,7 +490,7 @@ RED.diff = (function() {
|
||||
}
|
||||
function createNodeIcon(node,def) {
|
||||
var nodeDiv = $("<div>",{class:"node-diff-node-entry-node"});
|
||||
var colour = def.color;
|
||||
var colour = RED.utils.getNodeColor(node.type,def);
|
||||
var icon_url = RED.utils.getNodeIcon(def,node);
|
||||
if (node.type === 'tab') {
|
||||
colour = "#C0DEED";
|
||||
@@ -507,7 +507,7 @@ RED.diff = (function() {
|
||||
createNodeIcon(node,def).appendTo(nodeTitleDiv);
|
||||
var contentDiv = $('<div>',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
|
||||
var nodeLabel = node.label || node.name || node.id;
|
||||
$('<span>',{class:"node-diff-node-label"}).html(nodeLabel).appendTo(contentDiv);
|
||||
$('<span>',{class:"node-diff-node-label"}).text(nodeLabel).appendTo(contentDiv);
|
||||
return nodeTitleDiv;
|
||||
}
|
||||
function createNodeDiffRow(node,stats,CurrentDiff) {
|
||||
@@ -739,7 +739,7 @@ RED.diff = (function() {
|
||||
var status;
|
||||
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).html("id").appendTo(row);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).text("id").appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
localCell.addClass("node-diff-node-unchanged");
|
||||
@@ -782,7 +782,7 @@ RED.diff = (function() {
|
||||
conflict = true;
|
||||
}
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).html("position").appendTo(row);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).text("position").appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged"));
|
||||
@@ -850,7 +850,7 @@ RED.diff = (function() {
|
||||
conflict = true;
|
||||
}
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).html("wires").appendTo(row);
|
||||
$("<td>",{class:"node-diff-property-cell-label"}).text("wires").appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
if (!conflict) {
|
||||
@@ -917,7 +917,7 @@ RED.diff = (function() {
|
||||
}
|
||||
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).html(d).appendTo(row);
|
||||
var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).text(d).appendTo(row);
|
||||
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
if (!conflict) {
|
||||
@@ -1233,7 +1233,7 @@ RED.diff = (function() {
|
||||
// currentDiff = diff;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title||"Review Changes", //TODO: nls
|
||||
title: options.title||RED._("diff.reviewChanges"),
|
||||
width: Infinity,
|
||||
overlay: true,
|
||||
buttons: [
|
||||
@@ -1391,7 +1391,7 @@ RED.diff = (function() {
|
||||
}
|
||||
})
|
||||
|
||||
RED.nodes.version(remoteDiff.rev);
|
||||
RED.nodes.version(diff.remoteDiff.rev);
|
||||
|
||||
RED.view.redraw(true);
|
||||
RED.palette.refresh();
|
||||
@@ -1416,7 +1416,7 @@ RED.diff = (function() {
|
||||
|
||||
function showTextDiff(textA,textB) {
|
||||
var trayOptions = {
|
||||
title: "Compare Changes", //TODO: nls
|
||||
title: RED._("diff.compareChanges"),
|
||||
width: Infinity,
|
||||
overlay: true,
|
||||
buttons: [
|
||||
@@ -1721,80 +1721,17 @@ RED.diff = (function() {
|
||||
if (commitOptions.unmerged) {
|
||||
$('<span style="float: right;"><span id="node-diff-toolbar-resolved-conflicts"></span></span>').appendTo(content);
|
||||
}
|
||||
// var tools = $('<span style="float: right;" class="button-group"></span>').appendTo(content);
|
||||
// $('<button class="editor-button editor-button-small">show flow diff</button>').appendTo(tools).click(function(e) {
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
// var projectName = commitOptions.project.name;
|
||||
// var filename = commitOptions.project.files.flow;
|
||||
// var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
|
||||
// var oldVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
|
||||
// var newVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
|
||||
// var promises = [];
|
||||
// if (commitOptions.commonRev) {
|
||||
// var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
|
||||
// promises.push($.getJSON(commonVersionUrl));
|
||||
// } else {
|
||||
// promises.push($.when(null));
|
||||
// }
|
||||
// promises.push($.getJSON(oldVersionUrl));
|
||||
// promises.push($.getJSON(newVersionUrl));
|
||||
// $.when.apply($,promises).done(function(commonVersion, oldVersion,newVersion) {
|
||||
// var commonFlow;
|
||||
// var oldFlow;
|
||||
// var newFlow;
|
||||
// if (commonVersion) {
|
||||
// try {
|
||||
// commonFlow = JSON.parse(commonVersion[0].content||"[]");
|
||||
// } catch(err) {
|
||||
// console.log("Common Version doesn't contain valid JSON:",commonVersionUrl);
|
||||
// console.log(err);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// try {
|
||||
// oldFlow = JSON.parse(oldVersion[0].content||"[]");
|
||||
// } catch(err) {
|
||||
// console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
|
||||
// console.log(err);
|
||||
// return;
|
||||
// }
|
||||
// if (!commonFlow) {
|
||||
// commonFlow = oldFlow;
|
||||
// }
|
||||
// try {
|
||||
// newFlow = JSON.parse(newVersion[0].content||"[]");
|
||||
// } catch(err) {
|
||||
// console.log("New Version doesn't contain valid JSON:",newFlow);
|
||||
// console.log(err);
|
||||
// return;
|
||||
// }
|
||||
// var localDiff = generateDiff(commonFlow,oldFlow);
|
||||
// var remoteDiff = generateDiff(commonFlow,newFlow);
|
||||
// var diff = resolveDiffs(localDiff,remoteDiff);
|
||||
// showDiff(diff,{
|
||||
// title: filename,
|
||||
// mode: commitOptions.commonRev?'merge':'view',
|
||||
// oldRevTitle: commitOptions.oldRevTitle,
|
||||
// newRevTitle: commitOptions.newRevTitle
|
||||
// });
|
||||
// // var flowDiffRow = $("<tr>").insertAfter(diffRow);
|
||||
// // var content = $('<td colspan="3"></td>').appendTo(flowDiffRow);
|
||||
// // currentDiff = diff;
|
||||
// // var diffTable = buildDiffPanel(content,diff,{mode:"view"}).finish();
|
||||
// });
|
||||
// })
|
||||
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
||||
var flowDiffContent = $('<td class="flow-diff" colspan="3"></td>').appendTo(diffRow);
|
||||
|
||||
var projectName = commitOptions.project.name;
|
||||
var filename = commitOptions.project.files.flow;
|
||||
var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
|
||||
var oldVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
|
||||
var newVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
|
||||
var commonVersionUrl = "projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
|
||||
var oldVersionUrl = "projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
|
||||
var newVersionUrl = "projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
|
||||
var promises = [$.Deferred(),$.Deferred(),$.Deferred()];
|
||||
if (commitOptions.commonRev) {
|
||||
var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
|
||||
var commonVersionUrl = "projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
|
||||
$.ajax({dataType: "json",url: commonVersionUrl}).then(function(data) { promises[0].resolve(data); }).fail(function() { promises[0].resolve(null);})
|
||||
} else {
|
||||
promises[0].resolve(null);
|
||||
@@ -1810,7 +1747,7 @@ RED.diff = (function() {
|
||||
try {
|
||||
commonFlow = JSON.parse(commonVersion.content||"[]");
|
||||
} catch(err) {
|
||||
console.log("Common Version doesn't contain valid JSON:",commonVersionUrl);
|
||||
console.log(RED._("diff.commonVersionError"),commonVersionUrl);
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
@@ -1818,7 +1755,7 @@ RED.diff = (function() {
|
||||
try {
|
||||
oldFlow = JSON.parse(oldVersion.content||"[]");
|
||||
} catch(err) {
|
||||
console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
|
||||
console.log(RED._("diff.oldVersionError"),oldVersionUrl);
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
@@ -1828,7 +1765,7 @@ RED.diff = (function() {
|
||||
try {
|
||||
newFlow = JSON.parse(newVersion.content||"[]");
|
||||
} catch(err) {
|
||||
console.log("New Version doesn't contain valid JSON:",newFlow);
|
||||
console.log(RED._("diff.newVersionError"),newFlow);
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
@@ -1860,11 +1797,11 @@ RED.diff = (function() {
|
||||
if (isBinary) {
|
||||
var diffBinaryRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
||||
var binaryContent = $('<td colspan="3"></td>').appendTo(diffBinaryRow);
|
||||
$('<span></span>').text("Cannot show binary file contents").appendTo(binaryContent);
|
||||
$('<span></span>').text(RED._("diff.noBinaryFileShowed")).appendTo(binaryContent);
|
||||
|
||||
} else {
|
||||
if (commitOptions.unmerged) {
|
||||
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content);
|
||||
conflictHeader = $('<span style="float: right;">'+RED._("diff.conflictHeader",{resolved:resolvedConflicts, unresolved:unresolvedConflicts})+'</span>').appendTo(content);
|
||||
}
|
||||
hunks.forEach(function(hunk) {
|
||||
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
||||
@@ -1977,7 +1914,7 @@ RED.diff = (function() {
|
||||
diffRow.remove();
|
||||
addedRows.find(".linetext").addClass('added');
|
||||
conflictHeader.empty();
|
||||
$('<span><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(conflictHeader);
|
||||
$('<span>'+RED._("diff.conflictHeader",{resolved:resolvedConflicts, unresolved:unresolvedConflicts})+'</span>').appendTo(conflictHeader);
|
||||
|
||||
conflictResolutions[file.file] = conflictResolutions[file.file] || {};
|
||||
conflictResolutions[file.file][hunk.localChangeStart] = {
|
||||
@@ -2009,7 +1946,7 @@ RED.diff = (function() {
|
||||
function showCommitDiff(options) {
|
||||
var commit = parseCommitDiff(options.commit);
|
||||
var trayOptions = {
|
||||
title: "View Commit Changes", //TODO: nls
|
||||
title: RED._("diff.viewCommitDiff"),
|
||||
width: Infinity,
|
||||
overlay: true,
|
||||
buttons: [
|
||||
@@ -2071,7 +2008,7 @@ RED.diff = (function() {
|
||||
}
|
||||
|
||||
var trayOptions = {
|
||||
title: title||"Compare Changes", //TODO: nls
|
||||
title: title|| RED._("diff.compareChanges"),
|
||||
width: Infinity,
|
||||
overlay: true,
|
||||
buttons: [
|
||||
@@ -2104,7 +2041,7 @@ RED.diff = (function() {
|
||||
trayOptions.buttons.push(
|
||||
{
|
||||
id: "node-diff-view-resolve-diff",
|
||||
text: "Save conflict resolution",
|
||||
text: RED._("diff.saveConflict"),
|
||||
class: "primary disabled",
|
||||
click: function() {
|
||||
if (!$("#node-diff-view-resolve-diff").hasClass('disabled')) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
209
editor/js/ui/editors/buffer.js
Normal file
209
editor/js/ui/editors/buffer.js
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.editor.types._buffer = (function() {
|
||||
|
||||
|
||||
var template = '<script type="text/x-red" data-template-name="_buffer"><div id="node-input-buffer-panels"><div id="node-input-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><span class="node-input-buffer-type"><i class="fa fa-exclamation-circle"></i> <span id="node-input-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="node-input-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></span></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="node-input-buffer-str"></div></div></div><div id="node-input-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px"><div class="node-text-editor" id="node-input-buffer-bin"></div></div></div></div></script>';
|
||||
|
||||
function stringToUTF8Array(str) {
|
||||
var data = [];
|
||||
var i=0, l = str.length;
|
||||
for (i=0; i<l; i++) {
|
||||
var char = str.charCodeAt(i);
|
||||
if (char < 0x80) {
|
||||
data.push(char);
|
||||
} else if (char < 0x800) {
|
||||
data.push(0xc0 | (char >> 6));
|
||||
data.push(0x80 | (char & 0x3f));
|
||||
} else if (char < 0xd800 || char >= 0xe000) {
|
||||
data.push(0xe0 | (char >> 12));
|
||||
data.push(0x80 | ((char>>6) & 0x3f));
|
||||
data.push(0x80 | (char & 0x3f));
|
||||
} else {
|
||||
i++;
|
||||
char = 0x10000 + (((char & 0x3ff)<<10) | (str.charAt(i) & 0x3ff));
|
||||
data.push(0xf0 | (char >>18));
|
||||
data.push(0x80 | ((char>>12) & 0x3f));
|
||||
data.push(0x80 | ((char>>6) & 0x3f));
|
||||
data.push(0x80 | (char & 0x3f));
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
$(template).appendTo(document.body);
|
||||
},
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onComplete = options.complete;
|
||||
var type = "_buffer"
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var bufferStringEditor = [];
|
||||
var bufferBinValue;
|
||||
|
||||
var panels;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(JSON.stringify(bufferBinValue));
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
var height = $("#dialog-form").height();
|
||||
if (panels) {
|
||||
panels.resize(height);
|
||||
}
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
|
||||
|
||||
bufferStringEditor = RED.editor.createEditor({
|
||||
id: 'node-input-buffer-str',
|
||||
value: "",
|
||||
mode:"ace/mode/text"
|
||||
});
|
||||
bufferStringEditor.getSession().setValue(value||"",-1);
|
||||
|
||||
bufferBinEditor = RED.editor.createEditor({
|
||||
id: 'node-input-buffer-bin',
|
||||
value: "",
|
||||
mode:"ace/mode/text",
|
||||
readOnly: true
|
||||
});
|
||||
|
||||
var changeTimer;
|
||||
var buildBuffer = function(data) {
|
||||
var valid = true;
|
||||
var isString = typeof data === 'string';
|
||||
var binBuffer = [];
|
||||
if (isString) {
|
||||
bufferBinValue = stringToUTF8Array(data);
|
||||
} else {
|
||||
bufferBinValue = data;
|
||||
}
|
||||
var i=0,l=bufferBinValue.length;
|
||||
var c = 0;
|
||||
for(i=0;i<l;i++) {
|
||||
var d = parseInt(bufferBinValue[i]);
|
||||
if (!isString && (isNaN(d) || d < 0 || d > 255)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (i>0) {
|
||||
if (i%8 === 0) {
|
||||
if (i%16 === 0) {
|
||||
binBuffer.push("\n");
|
||||
} else {
|
||||
binBuffer.push(" ");
|
||||
}
|
||||
} else {
|
||||
binBuffer.push(" ");
|
||||
}
|
||||
}
|
||||
binBuffer.push((d<16?"0":"")+d.toString(16).toUpperCase());
|
||||
}
|
||||
if (valid) {
|
||||
$("#node-input-buffer-type-string").toggle(isString);
|
||||
$("#node-input-buffer-type-array").toggle(!isString);
|
||||
bufferBinEditor.setValue(binBuffer.join(""),1);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
var bufferStringUpdate = function() {
|
||||
var value = bufferStringEditor.getValue();
|
||||
var isValidArray = false;
|
||||
if (/^[\s]*\[[\s\S]*\][\s]*$/.test(value)) {
|
||||
isValidArray = true;
|
||||
try {
|
||||
var data = JSON.parse(value);
|
||||
isValidArray = buildBuffer(data);
|
||||
} catch(err) {
|
||||
isValidArray = false;
|
||||
}
|
||||
}
|
||||
if (!isValidArray) {
|
||||
buildBuffer(value);
|
||||
}
|
||||
|
||||
}
|
||||
bufferStringEditor.getSession().on('change', function() {
|
||||
clearTimeout(changeTimer);
|
||||
changeTimer = setTimeout(bufferStringUpdate,200);
|
||||
});
|
||||
|
||||
bufferStringUpdate();
|
||||
|
||||
dialogForm.i18n();
|
||||
|
||||
panels = RED.panels.create({
|
||||
id:"node-input-buffer-panels",
|
||||
resize: function(p1Height,p2Height) {
|
||||
var p1 = $("#node-input-buffer-panel-str");
|
||||
p1Height -= $(p1.children()[0]).outerHeight(true);
|
||||
var editorRow = $(p1.children()[1]);
|
||||
p1Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-buffer-str").css("height",(p1Height-5)+"px");
|
||||
bufferStringEditor.resize();
|
||||
|
||||
var p2 = $("#node-input-buffer-panel-bin");
|
||||
editorRow = $(p2.children()[0]);
|
||||
p2Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-buffer-bin").css("height",(p2Height-5)+"px");
|
||||
bufferBinEditor.resize();
|
||||
}
|
||||
});
|
||||
|
||||
$(".node-input-buffer-type").click(function(e) {
|
||||
e.preventDefault();
|
||||
RED.sidebar.info.set(RED._("bufferEditor.modeDesc"));
|
||||
RED.sidebar.info.show();
|
||||
})
|
||||
|
||||
|
||||
},
|
||||
close: function() {
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
bufferStringEditor.destroy();
|
||||
bufferBinEditor.destroy();
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
}
|
||||
})();
|
||||
325
editor/js/ui/editors/expression.js
Normal file
325
editor/js/ui/editors/expression.js
Normal file
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.editor.types._expression = (function() {
|
||||
|
||||
|
||||
var template = '<script type="text/x-red" data-template-name="_expression"><div id="node-input-expression-panels"><div id="node-input-expression-panel-expr" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><span class="node-input-expression-legacy"><i class="fa fa-exclamation-circle"></i> <span data-i18n="expressionEditor.compatMode"></span></span><button id="node-input-expression-reformat" class="editor-button editor-button-small"><span data-i18n="expressionEditor.format"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="node-input-expression"></div></div></div><div id="node-input-expression-panel-info" class="red-ui-panel"><div class="form-row"><ul id="node-input-expression-tabs"></ul><div id="node-input-expression-tab-help" class="node-input-expression-tab-content hide"><div><select id="node-input-expression-func"></select><button id="node-input-expression-func-insert" class="editor-button" data-i18n="expressionEditor.insert"></button></div><div id="node-input-expression-help"></div></div><div id="node-input-expression-tab-test" class="node-input-expression-tab-content hide"><div><span style="display: inline-block; width: calc(50% - 5px);"><span data-i18n="expressionEditor.data"></span><button style="float: right; margin-right: 5px;" id="node-input-example-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button></span><span style="display: inline-block; width: calc(50% - 5px);" data-i18n="expressionEditor.result"></span></div><div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-data"></div><div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-result"></div></div></div></div></div></script>';
|
||||
var expressionTestCache = {};
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
$(template).appendTo(document.body);
|
||||
},
|
||||
show: function(options) {
|
||||
var expressionTestCacheId = options.parent||"_";
|
||||
var value = options.value;
|
||||
var onComplete = options.complete;
|
||||
var type = "_expression"
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
var testDataEditor;
|
||||
var testResultEditor
|
||||
var panels;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
$("#node-input-expression-help").text("");
|
||||
onComplete(expressionEditor.getValue());
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
var height = $("#dialog-form").height();
|
||||
if (panels) {
|
||||
panels.resize(height);
|
||||
}
|
||||
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
trayBody.addClass("node-input-expression-editor")
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form','_expression','editor');
|
||||
var funcSelect = $("#node-input-expression-func");
|
||||
Object.keys(jsonata.functions).forEach(function(f) {
|
||||
funcSelect.append($("<option></option>").val(f).text(f));
|
||||
})
|
||||
funcSelect.change(function(e) {
|
||||
var f = $(this).val();
|
||||
var args = RED._('jsonata:'+f+".args",{defaultValue:''});
|
||||
var title = "<h5>"+f+"("+args+")</h5>";
|
||||
var body = marked(RED._('jsonata:'+f+'.desc',{defaultValue:''}));
|
||||
$("#node-input-expression-help").html(title+"<p>"+body+"</p>");
|
||||
|
||||
})
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-expression',
|
||||
value: "",
|
||||
mode:"ace/mode/jsonata",
|
||||
options: {
|
||||
enableBasicAutocompletion:true,
|
||||
enableSnippets:true,
|
||||
enableLiveAutocompletion: true
|
||||
}
|
||||
});
|
||||
var currentToken = null;
|
||||
var currentTokenPos = -1;
|
||||
var currentFunctionMarker = null;
|
||||
|
||||
expressionEditor.getSession().setValue(value||"",-1);
|
||||
expressionEditor.on("changeSelection", function() {
|
||||
var c = expressionEditor.getCursorPosition();
|
||||
var token = expressionEditor.getSession().getTokenAt(c.row,c.column);
|
||||
if (token !== currentToken || (token && /paren/.test(token.type) && c.column !== currentTokenPos)) {
|
||||
currentToken = token;
|
||||
var r,p;
|
||||
var scopedFunction = null;
|
||||
if (token && token.type === 'keyword') {
|
||||
r = c.row;
|
||||
scopedFunction = token;
|
||||
} else {
|
||||
var depth = 0;
|
||||
var next = false;
|
||||
if (token) {
|
||||
if (token.type === 'paren.rparen') {
|
||||
// If this is a block of parens ')))', set
|
||||
// depth to offset against the cursor position
|
||||
// within the block
|
||||
currentTokenPos = c.column;
|
||||
depth = c.column - (token.start + token.value.length);
|
||||
}
|
||||
r = c.row;
|
||||
p = token.index;
|
||||
} else {
|
||||
r = c.row-1;
|
||||
p = -1;
|
||||
}
|
||||
while ( scopedFunction === null && r > -1) {
|
||||
var rowTokens = expressionEditor.getSession().getTokens(r);
|
||||
if (p === -1) {
|
||||
p = rowTokens.length-1;
|
||||
}
|
||||
while (p > -1) {
|
||||
var type = rowTokens[p].type;
|
||||
if (next) {
|
||||
if (type === 'keyword') {
|
||||
scopedFunction = rowTokens[p];
|
||||
// console.log("HIT",scopedFunction);
|
||||
break;
|
||||
}
|
||||
next = false;
|
||||
}
|
||||
if (type === 'paren.lparen') {
|
||||
depth-=rowTokens[p].value.length;
|
||||
} else if (type === 'paren.rparen') {
|
||||
depth+=rowTokens[p].value.length;
|
||||
}
|
||||
if (depth < 0) {
|
||||
next = true;
|
||||
depth = 0;
|
||||
}
|
||||
// console.log(r,p,depth,next,rowTokens[p]);
|
||||
p--;
|
||||
}
|
||||
if (!scopedFunction) {
|
||||
r--;
|
||||
}
|
||||
}
|
||||
}
|
||||
expressionEditor.session.removeMarker(currentFunctionMarker);
|
||||
if (scopedFunction) {
|
||||
//console.log(token,.map(function(t) { return t.type}));
|
||||
funcSelect.val(scopedFunction.value).change();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialogForm.i18n();
|
||||
$("#node-input-expression-func-insert").click(function(e) {
|
||||
e.preventDefault();
|
||||
var pos = expressionEditor.getCursorPosition();
|
||||
var f = funcSelect.val();
|
||||
var snippet = jsonata.getFunctionSnippet(f);
|
||||
expressionEditor.insertSnippet(snippet);
|
||||
expressionEditor.focus();
|
||||
});
|
||||
$("#node-input-expression-reformat").click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var v = expressionEditor.getValue()||"";
|
||||
try {
|
||||
v = jsonata.format(v);
|
||||
} catch(err) {
|
||||
// TODO: do an optimistic auto-format
|
||||
}
|
||||
expressionEditor.getSession().setValue(v||"",-1);
|
||||
});
|
||||
|
||||
var tabs = RED.tabs.create({
|
||||
element: $("#node-input-expression-tabs"),
|
||||
onchange:function(tab) {
|
||||
$(".node-input-expression-tab-content").hide();
|
||||
tab.content.show();
|
||||
trayOptions.resize();
|
||||
}
|
||||
})
|
||||
|
||||
tabs.addTab({
|
||||
id: 'expression-help',
|
||||
label: RED._('expressionEditor.functionReference'),
|
||||
content: $("#node-input-expression-tab-help")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: 'expression-tests',
|
||||
label: RED._('expressionEditor.test'),
|
||||
content: $("#node-input-expression-tab-test")
|
||||
});
|
||||
testDataEditor = RED.editor.createEditor({
|
||||
id: 'node-input-expression-test-data',
|
||||
value: expressionTestCache[expressionTestCacheId] || '{\n "payload": "hello world"\n}',
|
||||
mode:"ace/mode/json",
|
||||
lineNumbers: false
|
||||
});
|
||||
var changeTimer;
|
||||
$(".node-input-expression-legacy").click(function(e) {
|
||||
e.preventDefault();
|
||||
RED.sidebar.info.set(RED._("expressionEditor.compatModeDesc"));
|
||||
RED.sidebar.info.show();
|
||||
})
|
||||
var testExpression = function() {
|
||||
var value = testDataEditor.getValue();
|
||||
var parsedData;
|
||||
var currentExpression = expressionEditor.getValue();
|
||||
var expr;
|
||||
var usesContext = false;
|
||||
var legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
|
||||
$(".node-input-expression-legacy").toggle(legacyMode);
|
||||
try {
|
||||
expr = jsonata(currentExpression);
|
||||
expr.assign('flowContext',function(val) {
|
||||
usesContext = true;
|
||||
return null;
|
||||
});
|
||||
expr.assign('globalContext',function(val) {
|
||||
usesContext = true;
|
||||
return null;
|
||||
});
|
||||
} catch(err) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.invalid-expr",{message:err.message}),-1);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
parsedData = JSON.parse(value);
|
||||
} catch(err) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.invalid-msg",{message:err.toString()}))
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var result = expr.evaluate(legacyMode?{msg:parsedData}:parsedData);
|
||||
if (usesContext) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
|
||||
return;
|
||||
}
|
||||
|
||||
var formattedResult;
|
||||
if (result !== undefined) {
|
||||
formattedResult = JSON.stringify(result,null,4);
|
||||
} else {
|
||||
formattedResult = RED._("expressionEditor.noMatch");
|
||||
}
|
||||
testResultEditor.setValue(formattedResult,-1);
|
||||
} catch(err) {
|
||||
testResultEditor.setValue(RED._("expressionEditor.errors.eval",{message:err.message}),-1);
|
||||
}
|
||||
}
|
||||
|
||||
testDataEditor.getSession().on('change', function() {
|
||||
clearTimeout(changeTimer);
|
||||
changeTimer = setTimeout(testExpression,200);
|
||||
expressionTestCache[expressionTestCacheId] = testDataEditor.getValue();
|
||||
});
|
||||
expressionEditor.getSession().on('change', function() {
|
||||
clearTimeout(changeTimer);
|
||||
changeTimer = setTimeout(testExpression,200);
|
||||
});
|
||||
|
||||
testResultEditor = RED.editor.createEditor({
|
||||
id: 'node-input-expression-test-result',
|
||||
value: "",
|
||||
mode:"ace/mode/json",
|
||||
lineNumbers: false,
|
||||
readOnly: true
|
||||
});
|
||||
panels = RED.panels.create({
|
||||
id:"node-input-expression-panels",
|
||||
resize: function(p1Height,p2Height) {
|
||||
var p1 = $("#node-input-expression-panel-expr");
|
||||
p1Height -= $(p1.children()[0]).outerHeight(true);
|
||||
var editorRow = $(p1.children()[1]);
|
||||
p1Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
|
||||
$("#node-input-expression").css("height",(p1Height-5)+"px");
|
||||
expressionEditor.resize();
|
||||
|
||||
var p2 = $("#node-input-expression-panel-info > .form-row > div:first-child");
|
||||
p2Height -= p2.outerHeight(true) + 20;
|
||||
$(".node-input-expression-tab-content").height(p2Height);
|
||||
$("#node-input-expression-test-data").css("height",(p2Height-5)+"px");
|
||||
testDataEditor.resize();
|
||||
$("#node-input-expression-test-result").css("height",(p2Height-5)+"px");
|
||||
testResultEditor.resize();
|
||||
}
|
||||
});
|
||||
|
||||
$("#node-input-example-reformat").click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var v = testDataEditor.getValue()||"";
|
||||
try {
|
||||
v = JSON.stringify(JSON.parse(v),null,4);
|
||||
} catch(err) {
|
||||
// TODO: do an optimistic auto-format
|
||||
}
|
||||
testDataEditor.getSession().setValue(v||"",-1);
|
||||
});
|
||||
|
||||
testExpression();
|
||||
},
|
||||
close: function() {
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
expressionEditor.destroy();
|
||||
testDataEditor.destroy();
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
}
|
||||
})();
|
||||
102
editor/js/ui/editors/js.js
Normal file
102
editor/js/ui/editors/js.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.editor.types._js = (function() {
|
||||
|
||||
|
||||
var template = '<script type="text/x-red" data-template-name="_js"><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-js"></div></div></script>';
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
$(template).appendTo(document.body);
|
||||
},
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onComplete = options.complete;
|
||||
var type = "_js"
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
var changeTimer;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(expressionEditor.getValue(),expressionEditor.getCursorPosition());
|
||||
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);
|
||||
}
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
expressionEditor.resize();
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-js',
|
||||
mode: 'ace/mode/javascript',
|
||||
value: value,
|
||||
globals: {
|
||||
msg:true,
|
||||
context:true,
|
||||
RED: true,
|
||||
util: true,
|
||||
flow: true,
|
||||
global: true,
|
||||
console: true,
|
||||
Buffer: true,
|
||||
setTimeout: true,
|
||||
clearTimeout: true,
|
||||
setInterval: true,
|
||||
clearInterval: true
|
||||
}
|
||||
});
|
||||
if (options.cursor) {
|
||||
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
||||
}
|
||||
dialogForm.i18n();
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
}
|
||||
})();
|
||||
118
editor/js/ui/editors/json.js
Normal file
118
editor/js/ui/editors/json.js
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.editor.types._json = (function() {
|
||||
|
||||
|
||||
var template = '<script type="text/x-red" data-template-name="_json"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div></div></script>';
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
$(template).appendTo(document.body);
|
||||
},
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onComplete = options.complete;
|
||||
var type = "_json"
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
var changeTimer;
|
||||
|
||||
var checkValid = function() {
|
||||
var v = expressionEditor.getValue();
|
||||
try {
|
||||
JSON.parse(v);
|
||||
$("#node-dialog-ok").removeClass('disabled');
|
||||
return true;
|
||||
} catch(err) {
|
||||
$("#node-dialog-ok").addClass('disabled');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
if (options.requireValid && !checkValid()) {
|
||||
return;
|
||||
}
|
||||
onComplete(expressionEditor.getValue());
|
||||
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");
|
||||
expressionEditor.resize();
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-json',
|
||||
value: "",
|
||||
mode:"ace/mode/json"
|
||||
});
|
||||
expressionEditor.getSession().setValue(value||"",-1);
|
||||
if (options.requireValid) {
|
||||
expressionEditor.getSession().on('change', function() {
|
||||
clearTimeout(changeTimer);
|
||||
changeTimer = setTimeout(checkValid,200);
|
||||
});
|
||||
checkValid();
|
||||
}
|
||||
$("#node-input-json-reformat").click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var v = expressionEditor.getValue()||"";
|
||||
try {
|
||||
v = JSON.stringify(JSON.parse(v),null,4);
|
||||
} catch(err) {
|
||||
// TODO: do an optimistic auto-format
|
||||
}
|
||||
expressionEditor.getSession().setValue(v||"",-1);
|
||||
});
|
||||
dialogForm.i18n();
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
}
|
||||
}
|
||||
})();
|
||||
90
editor/js/ui/editors/markdown.js
Normal file
90
editor/js/ui/editors/markdown.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.editor.types._markdown = (function() {
|
||||
|
||||
|
||||
var template = '<script type="text/x-red" data-template-name="_markdown"><div class="form-row" id="node-input-markdown-title" style="margin-bottom: 3px; text-align: right;"></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-markdown"></div></div></script>';
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
$(template).appendTo(document.body);
|
||||
},
|
||||
show: function(options) {
|
||||
var value = options.value;
|
||||
var onComplete = options.complete;
|
||||
var type = "_markdown"
|
||||
RED.view.state(RED.state.EDITING);
|
||||
var expressionEditor;
|
||||
|
||||
var trayOptions = {
|
||||
title: options.title,
|
||||
width: "inherit",
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
onComplete(expressionEditor.getValue());
|
||||
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");
|
||||
expressionEditor.resize();
|
||||
},
|
||||
open: function(tray) {
|
||||
var trayBody = tray.find('.editor-tray-body');
|
||||
var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
|
||||
expressionEditor = RED.editor.createEditor({
|
||||
id: 'node-input-markdown',
|
||||
value: value,
|
||||
mode:"ace/mode/markdown"
|
||||
});
|
||||
if (options.header) {
|
||||
options.header.appendTo(tray.find('#node-input-markdown-title'));
|
||||
}
|
||||
|
||||
dialogForm.i18n();
|
||||
},
|
||||
close: function() {
|
||||
expressionEditor.destroy();
|
||||
if (options.onclose) {
|
||||
options.onclose();
|
||||
}
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
RED.tray.show(trayOptions);
|
||||
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -389,6 +389,7 @@ RED.keyboard = (function() {
|
||||
var currentEditorSettings = RED.settings.get('editor') || {};
|
||||
var userKeymap = currentEditorSettings.keymap || {};
|
||||
userKeymap[object.id] = null;
|
||||
currentEditorSettings.keymap = userKeymap;
|
||||
RED.settings.set('editor',currentEditorSettings);
|
||||
|
||||
var obj = {
|
||||
@@ -442,6 +443,7 @@ RED.keyboard = (function() {
|
||||
var currentEditorSettings = RED.settings.get('editor') || {};
|
||||
var userKeymap = currentEditorSettings.keymap || {};
|
||||
userKeymap[object.id] = RED.keyboard.getShortcut(object.id);
|
||||
currentEditorSettings.keymap = userKeymap;
|
||||
RED.settings.set('editor',currentEditorSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,12 +414,8 @@ RED.library = (function() {
|
||||
|
||||
RED.events.on("view:selection-changed",function(selection) {
|
||||
if (!selection.nodes) {
|
||||
RED.menu.setDisabled("menu-item-export",true);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",true);
|
||||
RED.menu.setDisabled("menu-item-export-library",true);
|
||||
} else {
|
||||
RED.menu.setDisabled("menu-item-export",false);
|
||||
RED.menu.setDisabled("menu-item-export-clipboard",false);
|
||||
RED.menu.setDisabled("menu-item-export-library",false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -171,7 +171,7 @@ RED.notifications = (function() {
|
||||
if (options.buttons) {
|
||||
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(nn)
|
||||
options.buttons.forEach(function(buttonDef) {
|
||||
var b = $('<button>').html(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
|
||||
var b = $('<button>').text(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
|
||||
if (buttonDef.id) {
|
||||
b.attr('id',buttonDef.id);
|
||||
}
|
||||
|
||||
@@ -208,6 +208,8 @@ RED.palette.editor = (function() {
|
||||
if (nodeEntry) {
|
||||
var activeTypeCount = 0;
|
||||
var typeCount = 0;
|
||||
var errorCount = 0;
|
||||
nodeEntry.errorList.empty();
|
||||
nodeEntries[module].totalUseCount = 0;
|
||||
nodeEntries[module].setUseCount = {};
|
||||
|
||||
@@ -216,7 +218,10 @@ RED.palette.editor = (function() {
|
||||
var inUseCount = 0;
|
||||
var set = moduleInfo.sets[setName];
|
||||
var setElements = nodeEntry.sets[setName];
|
||||
|
||||
if (set.err) {
|
||||
errorCount++;
|
||||
$("<li>").text(set.err).appendTo(nodeEntry.errorList);
|
||||
}
|
||||
if (set.enabled) {
|
||||
activeTypeCount += set.types.length;
|
||||
}
|
||||
@@ -228,7 +233,7 @@ RED.palette.editor = (function() {
|
||||
if (set.enabled) {
|
||||
var def = RED.nodes.getType(t);
|
||||
if (def && def.color) {
|
||||
swatch.css({background:def.color});
|
||||
swatch.css({background:RED.utils.getNodeColor(t,def)});
|
||||
swatch.css({border: "1px solid "+getContrastingBorder(swatch.css('backgroundColor'))})
|
||||
|
||||
} else {
|
||||
@@ -242,24 +247,31 @@ RED.palette.editor = (function() {
|
||||
nodeEntries[module].totalUseCount += inUseCount;
|
||||
|
||||
if (inUseCount > 0) {
|
||||
setElements.enableButton.html(RED._('palette.editor.inuse'));
|
||||
setElements.enableButton.text(RED._('palette.editor.inuse'));
|
||||
setElements.enableButton.addClass('disabled');
|
||||
} else {
|
||||
setElements.enableButton.removeClass('disabled');
|
||||
if (set.enabled) {
|
||||
setElements.enableButton.html(RED._('palette.editor.disable'));
|
||||
setElements.enableButton.text(RED._('palette.editor.disable'));
|
||||
} else {
|
||||
setElements.enableButton.html(RED._('palette.editor.enable'));
|
||||
setElements.enableButton.text(RED._('palette.editor.enable'));
|
||||
}
|
||||
}
|
||||
setElements.setRow.toggleClass("palette-module-set-disabled",!set.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCount === 0) {
|
||||
nodeEntry.errorRow.hide()
|
||||
} else {
|
||||
nodeEntry.errorRow.show();
|
||||
}
|
||||
|
||||
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
|
||||
nodeEntry.setCount.html(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
||||
nodeEntry.setCount.text(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
||||
|
||||
if (nodeEntries[module].totalUseCount > 0) {
|
||||
nodeEntry.enableButton.html(RED._('palette.editor.inuse'));
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.inuse'));
|
||||
nodeEntry.enableButton.addClass('disabled');
|
||||
nodeEntry.removeButton.hide();
|
||||
} else {
|
||||
@@ -268,20 +280,20 @@ RED.palette.editor = (function() {
|
||||
nodeEntry.removeButton.css('display', 'inline-block');
|
||||
}
|
||||
if (activeTypeCount === 0) {
|
||||
nodeEntry.enableButton.html(RED._('palette.editor.enableall'));
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.enableall'));
|
||||
} else {
|
||||
nodeEntry.enableButton.html(RED._('palette.editor.disableall'));
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.disableall'));
|
||||
}
|
||||
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
|
||||
}
|
||||
}
|
||||
if (moduleInfo.pending_version) {
|
||||
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
|
||||
nodeEntry.updateButton.html(RED._('palette.editor.updated')).addClass('disabled').show();
|
||||
nodeEntry.updateButton.text(RED._('palette.editor.updated')).addClass('disabled').show();
|
||||
} else if (loadedIndex.hasOwnProperty(module)) {
|
||||
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) === 1) {
|
||||
nodeEntry.updateButton.show();
|
||||
nodeEntry.updateButton.html(RED._('palette.editor.update',{version:loadedIndex[module].version}));
|
||||
nodeEntry.updateButton.text(RED._('palette.editor.update',{version:loadedIndex[module].version}));
|
||||
} else {
|
||||
nodeEntry.updateButton.hide();
|
||||
}
|
||||
@@ -355,7 +367,7 @@ RED.palette.editor = (function() {
|
||||
loadedIndex = {};
|
||||
packageList.editableList('empty');
|
||||
|
||||
$(".palette-module-shade-status").html(RED._('palette.editor.loading'));
|
||||
$(".palette-module-shade-status").text(RED._('palette.editor.loading'));
|
||||
var catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json'];
|
||||
catalogueLoadStatus = [];
|
||||
catalogueLoadErrors = false;
|
||||
@@ -461,7 +473,7 @@ RED.palette.editor = (function() {
|
||||
if (filteredList[i].info.id === ns.module) {
|
||||
var installButton = filteredList[i].elements.installButton;
|
||||
installButton.addClass('disabled');
|
||||
installButton.html(RED._('palette.editor.installed'));
|
||||
installButton.text(RED._('palette.editor.installed'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -477,7 +489,7 @@ RED.palette.editor = (function() {
|
||||
if (filteredList[i].info.id === ns.module) {
|
||||
var installButton = filteredList[i].elements.installButton;
|
||||
installButton.removeClass('disabled');
|
||||
installButton.html(RED._('palette.editor.install'));
|
||||
installButton.text(RED._('palette.editor.install'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -583,15 +595,18 @@ RED.palette.editor = (function() {
|
||||
if (entry) {
|
||||
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
|
||||
var titleRow = $('<div class="palette-module-meta palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
|
||||
$('<span>').html(entry.name).appendTo(titleRow);
|
||||
$('<span>').text(entry.name).appendTo(titleRow);
|
||||
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
|
||||
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
|
||||
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
|
||||
|
||||
var errorRow = $('<div class="palette-module-meta palette-module-errors"><i class="fa fa-warning"></i></div>').hide().appendTo(headerRow);
|
||||
var errorList = $('<ul class="palette-module-error-list"></ul>').appendTo(errorRow);
|
||||
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
|
||||
var setButton = $('<a href="#" class="editor-button editor-button-small palette-module-set-button"><i class="fa fa-angle-right palette-module-node-chevron"></i> </a>').appendTo(buttonRow);
|
||||
var setCount = $('<span>').appendTo(setButton);
|
||||
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
|
||||
|
||||
var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.update')).appendTo(buttonGroup);
|
||||
var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.update')).appendTo(buttonGroup);
|
||||
updateButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
|
||||
updateButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -602,7 +617,7 @@ RED.palette.editor = (function() {
|
||||
})
|
||||
|
||||
|
||||
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.remove')).appendTo(buttonGroup);
|
||||
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.remove')).appendTo(buttonGroup);
|
||||
removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
|
||||
removeButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -611,7 +626,7 @@ RED.palette.editor = (function() {
|
||||
if (!entry.local) {
|
||||
removeButton.hide();
|
||||
}
|
||||
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.disableall')).appendTo(buttonGroup);
|
||||
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.disableall')).appendTo(buttonGroup);
|
||||
|
||||
var contentRow = $('<div>',{class:"palette-module-content"}).appendTo(container);
|
||||
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
|
||||
@@ -620,6 +635,8 @@ RED.palette.editor = (function() {
|
||||
updateButton: updateButton,
|
||||
removeButton: removeButton,
|
||||
enableButton: enableButton,
|
||||
errorRow: errorRow,
|
||||
errorList: errorList,
|
||||
setCount: setCount,
|
||||
container: container,
|
||||
shade: shade,
|
||||
@@ -649,9 +666,8 @@ RED.palette.editor = (function() {
|
||||
set.types.forEach(function(t) {
|
||||
var typeDiv = $('<div>',{class:"palette-module-type"}).appendTo(setRow);
|
||||
typeSwatches[t] = $('<span>',{class:"palette-module-type-swatch"}).appendTo(typeDiv);
|
||||
$('<span>',{class:"palette-module-type-node"}).html(t).appendTo(typeDiv);
|
||||
$('<span>',{class:"palette-module-type-node"}).text(t).appendTo(typeDiv);
|
||||
})
|
||||
|
||||
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').appendTo(buttonGroup);
|
||||
enableButton.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -689,7 +705,7 @@ RED.palette.editor = (function() {
|
||||
})
|
||||
refreshNodeModule(entry.name);
|
||||
} else {
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -729,7 +745,7 @@ RED.palette.editor = (function() {
|
||||
});
|
||||
|
||||
|
||||
$('<span>').html(RED._("palette.editor.sort")+' ').appendTo(toolBar);
|
||||
$('<span>').text(RED._("palette.editor.sort")+' ').appendTo(toolBar);
|
||||
var sortGroup = $('<span class="button-group"></span>').appendTo(toolBar);
|
||||
var sortAZ = $('<a href="#" class="sidebar-header-button-toggle selected" data-i18n="palette.editor.sortAZ"></a>').appendTo(sortGroup);
|
||||
var sortRecent = $('<a href="#" class="sidebar-header-button-toggle" data-i18n="palette.editor.sortRecent"></a>').appendTo(sortGroup);
|
||||
@@ -771,13 +787,13 @@ RED.palette.editor = (function() {
|
||||
scrollOnAdd: false,
|
||||
addItem: function(container,i,object) {
|
||||
if (object.count) {
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container);
|
||||
return
|
||||
}
|
||||
if (object.more) {
|
||||
container.addClass('palette-module-more');
|
||||
var moreRow = $('<div>',{class:"palette-module-header palette-module"}).appendTo(container);
|
||||
var moreLink = $('<a href="#"></a>').html(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
|
||||
var moreLink = $('<a href="#"></a>').text(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
|
||||
moreLink.click(function(e) {
|
||||
e.preventDefault();
|
||||
packageList.editableList('removeItem',object);
|
||||
@@ -794,17 +810,17 @@ RED.palette.editor = (function() {
|
||||
var entry = object.info;
|
||||
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
|
||||
var titleRow = $('<div class="palette-module-meta"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
|
||||
$('<span>',{class:"palette-module-name"}).html(entry.name||entry.id).appendTo(titleRow);
|
||||
$('<span>',{class:"palette-module-name"}).text(entry.name||entry.id).appendTo(titleRow);
|
||||
$('<a target="_blank" class="palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow);
|
||||
var descRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||
$('<div>',{class:"palette-module-description"}).html(entry.description).appendTo(descRow);
|
||||
$('<div>',{class:"palette-module-description"}).text(entry.description).appendTo(descRow);
|
||||
|
||||
var metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||
$('<span class="palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
|
||||
$('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
|
||||
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
|
||||
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
|
||||
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup);
|
||||
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.install')).appendTo(buttonGroup);
|
||||
installButton.click(function(e) {
|
||||
e.preventDefault();
|
||||
if (!$(this).hasClass('disabled')) {
|
||||
@@ -813,14 +829,14 @@ RED.palette.editor = (function() {
|
||||
})
|
||||
if (nodeEntries.hasOwnProperty(entry.id)) {
|
||||
installButton.addClass('disabled');
|
||||
installButton.html(RED._('palette.editor.installed'));
|
||||
installButton.text(RED._('palette.editor.installed'));
|
||||
}
|
||||
|
||||
object.elements = {
|
||||
installButton:installButton
|
||||
}
|
||||
} else {
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,7 +21,18 @@ RED.palette = (function() {
|
||||
|
||||
var categoryContainers = {};
|
||||
|
||||
function createCategoryContainer(category, label) {
|
||||
|
||||
function createCategory(originalCategory,rootCategory,category,ns) {
|
||||
if ($("#palette-base-category-"+rootCategory).length === 0) {
|
||||
createCategoryContainer(originalCategory,rootCategory, ns+":palette.label."+rootCategory);
|
||||
}
|
||||
$("#palette-container-"+rootCategory).show();
|
||||
if ($("#palette-"+category).length === 0) {
|
||||
$("#palette-base-category-"+rootCategory).append('<div id="palette-'+category+'"></div>');
|
||||
}
|
||||
}
|
||||
function createCategoryContainer(originalCategory,category, labelId) {
|
||||
var label = RED._(labelId, {defaultValue:category});
|
||||
label = (label || category).replace(/_/g, " ");
|
||||
var catDiv = $('<div id="palette-container-'+category+'" class="palette-category palette-close hide">'+
|
||||
'<div id="palette-header-'+category+'" class="palette-header"><i class="expanded fa fa-angle-down"></i><span>'+label+'</span></div>'+
|
||||
@@ -31,7 +42,8 @@ RED.palette = (function() {
|
||||
'<div id="palette-'+category+'-function"></div>'+
|
||||
'</div>'+
|
||||
'</div>').appendTo("#palette-container");
|
||||
|
||||
catDiv.data('category',originalCategory);
|
||||
catDiv.data('label',label);
|
||||
categoryContainers[category] = {
|
||||
container: catDiv,
|
||||
close: function() {
|
||||
@@ -116,6 +128,12 @@ RED.palette = (function() {
|
||||
el.data('popover').setContent(popOverContent);
|
||||
}
|
||||
|
||||
function setIcon(element,sf) {
|
||||
var iconElement = element.find(".palette_icon");
|
||||
var icon_url = RED.utils.getNodeIcon(sf._def,sf);
|
||||
iconElement.attr("style", "background-image: url("+icon_url+")");
|
||||
}
|
||||
|
||||
function escapeNodeType(nt) {
|
||||
return nt.replace(" ","_").replace(".","_").replace(":","_");
|
||||
}
|
||||
@@ -127,6 +145,7 @@ RED.palette = (function() {
|
||||
}
|
||||
if (exclusion.indexOf(def.category)===-1) {
|
||||
|
||||
var originalCategory = def.category;
|
||||
var category = def.category.replace(/ /g,"_");
|
||||
var rootCategory = category.split("-")[0];
|
||||
|
||||
@@ -147,14 +166,13 @@ RED.palette = (function() {
|
||||
|
||||
d.className="palette_node";
|
||||
|
||||
|
||||
if (def.icon) {
|
||||
var icon_url = RED.utils.getNodeIcon(def);
|
||||
var iconContainer = $('<div/>',{class:"palette_icon_container"+(def.align=="right"?" palette_icon_container_right":"")}).appendTo(d);
|
||||
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
|
||||
}
|
||||
|
||||
d.style.backgroundColor = def.color;
|
||||
d.style.backgroundColor = RED.utils.getNodeColor(nt,def);
|
||||
|
||||
if (def.outputs > 0) {
|
||||
var portOut = document.createElement("div");
|
||||
@@ -168,21 +186,12 @@ RED.palette = (function() {
|
||||
d.appendChild(portIn);
|
||||
}
|
||||
|
||||
if ($("#palette-base-category-"+rootCategory).length === 0) {
|
||||
if(coreCategories.indexOf(rootCategory) !== -1){
|
||||
createCategoryContainer(rootCategory, RED._("node-red:palette.label."+rootCategory, {defaultValue:rootCategory}));
|
||||
} else {
|
||||
var ns = def.set.id;
|
||||
createCategoryContainer(rootCategory, RED._(ns+":palette.label."+rootCategory, {defaultValue:rootCategory}));
|
||||
}
|
||||
}
|
||||
$("#palette-container-"+rootCategory).show();
|
||||
|
||||
if ($("#palette-"+category).length === 0) {
|
||||
$("#palette-base-category-"+rootCategory).append('<div id="palette-'+category+'"></div>');
|
||||
}
|
||||
createCategory(def.category,rootCategory,category,(coreCategories.indexOf(rootCategory) !== -1)?"node-red":def.set.id);
|
||||
|
||||
$("#palette-"+category).append(d);
|
||||
|
||||
$(d).data('category',rootCategory);
|
||||
|
||||
d.onmousedown = function(e) { e.preventDefault(); };
|
||||
|
||||
var popover = RED.popover.create({
|
||||
@@ -302,7 +311,7 @@ RED.palette = (function() {
|
||||
});
|
||||
|
||||
var nodeInfo = null;
|
||||
if (def.category == "subflows") {
|
||||
if (nt.indexOf("subflow:") === 0) {
|
||||
$(d).dblclick(function(e) {
|
||||
RED.workspaces.show(nt.substring(8));
|
||||
e.preventDefault();
|
||||
@@ -375,6 +384,32 @@ RED.palette = (function() {
|
||||
portOutput.remove();
|
||||
}
|
||||
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||""));
|
||||
setIcon(paletteNode,sf);
|
||||
|
||||
var currentCategory = paletteNode.data('category');
|
||||
var newCategory = (sf.category||"subflows");
|
||||
if (currentCategory !== newCategory) {
|
||||
var category = newCategory.replace(/ /g,"_");
|
||||
createCategory(newCategory,category,category,"node-red");
|
||||
|
||||
var currentCategoryNode = paletteNode.closest(".palette-category");
|
||||
var newCategoryNode = $("#palette-"+category);
|
||||
newCategoryNode.append(paletteNode);
|
||||
if (newCategoryNode.find(".palette_node").length === 1) {
|
||||
categoryContainers[category].open();
|
||||
}
|
||||
|
||||
paletteNode.data('category',newCategory);
|
||||
if (currentCategoryNode.find(".palette_node").length === 0) {
|
||||
if (currentCategoryNode.find("i").hasClass("expanded")) {
|
||||
currentCategoryNode.find(".palette-content").slideToggle();
|
||||
currentCategoryNode.find("i").toggleClass("expanded");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -464,7 +499,7 @@ RED.palette = (function() {
|
||||
categoryList = coreCategories
|
||||
}
|
||||
categoryList.forEach(function(category){
|
||||
createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category}));
|
||||
createCategoryContainer(category, category, "palette.label."+category);
|
||||
});
|
||||
|
||||
$("#palette-collapse-all").on("click", function(e) {
|
||||
@@ -484,13 +519,20 @@ RED.palette = (function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getCategories() {
|
||||
var categories = [];
|
||||
$("#palette-container .palette-category").each(function(i,d) {
|
||||
categories.push({id:$(d).data('category'),label:$(d).data('label')});
|
||||
})
|
||||
return categories;
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
add:addNodeType,
|
||||
remove:removeNodeType,
|
||||
hide:hideNodeType,
|
||||
show:showNodeType,
|
||||
refresh:refreshNodeTypes
|
||||
refresh:refreshNodeTypes,
|
||||
getCategories: getCategories
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -49,7 +49,7 @@ RED.projects.settings = (function() {
|
||||
var tabContainer;
|
||||
|
||||
var trayOptions = {
|
||||
title: "Project Settings",// RED._("menu.label.userSettings"),, // TODO: nls
|
||||
title: RED._("menu.label.userSettings"),
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
@@ -173,14 +173,14 @@ RED.projects.settings = (function() {
|
||||
container.empty();
|
||||
var bg = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').appendTo(container);
|
||||
var input = $('<input type="text" style="width: calc(100% - 150px); margin-right: 10px;">').val(summary||"").appendTo(container);
|
||||
$('<button class="editor-button">Cancel</button>')
|
||||
$('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
updateProjectSummary(activeProject.summary, container);
|
||||
editButton.show();
|
||||
});
|
||||
$('<button class="editor-button">Save</button>')
|
||||
$('<button class="editor-button">' + RED._("common.label.save") + '</button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -223,7 +223,7 @@ RED.projects.settings = (function() {
|
||||
if (summary) {
|
||||
container.text(summary).removeClass('node-info-node');
|
||||
} else {
|
||||
container.text("No summary available").addClass('node-info-none');// TODO: nls
|
||||
container.text(RED._("sidebar.project.projectSettings.noSummaryAvailable")).addClass('node-info-none');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ RED.projects.settings = (function() {
|
||||
var summaryContent = $('<div></div>',{style:"color: #999"}).appendTo(summary);
|
||||
updateProjectSummary(activeProject.summary, summaryContent);
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
$('<button class="editor-button editor-button-small" style="float: right;">edit description</button>')
|
||||
$('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.editDescription') + '</button>')
|
||||
.prependTo(summary)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -250,7 +250,7 @@ RED.projects.settings = (function() {
|
||||
updateProjectDescription(activeProject, descriptionContent);
|
||||
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
$('<button class="editor-button editor-button-small" style="float: right;">edit README.md</button>')
|
||||
$('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.editReadme') + '</button>')
|
||||
.prependTo(description)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -316,7 +316,7 @@ RED.projects.settings = (function() {
|
||||
// depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls
|
||||
// }
|
||||
if (totalCount === 0) {
|
||||
depsList.editableList('addItem',{index:0, label:"None"}); // TODO: nls
|
||||
depsList.editableList('addItem',{index:0, label:RED._("sidebar.project.projectSettings.none")});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -381,7 +381,7 @@ RED.projects.settings = (function() {
|
||||
function createDependenciesPane(activeProject) {
|
||||
var pane = $('<div id="project-settings-tab-deps" class="project-settings-tab-pane node-help"></div>');
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">edit</button>')
|
||||
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">' + RED._("sidebar.project.projectSettings.edit") + '</button>')
|
||||
.appendTo(pane)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -444,14 +444,14 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
var icon = $('<i class="fa '+iconClass+'"></i>').appendTo(titleRow);
|
||||
entry.icon = icon;
|
||||
$('<span>').html(entry.id).appendTo(titleRow);
|
||||
$('<span>').text(entry.id).appendTo(titleRow);
|
||||
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
|
||||
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
|
||||
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
|
||||
metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||
var buttons = $('<div class="palette-module-button-group"></div>').appendTo(metaRow);
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
if (!entry.installed && RED.settings.theme('palette.editable') !== false) {
|
||||
$('<a href="#" class="editor-button editor-button-small">install</a>').appendTo(buttons)
|
||||
$('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.install") + '</a>').appendTo(buttons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
RED.palette.editor.install(entry,row,function(err) {
|
||||
@@ -468,7 +468,7 @@ RED.projects.settings = (function() {
|
||||
});
|
||||
})
|
||||
} else if (entry.known && entry.count === 0) {
|
||||
$('<a href="#" class="editor-button editor-button-small">remove from project</a>').appendTo(buttons)
|
||||
$('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.removeFromProject") + '</a>').appendTo(buttons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var deps = $.extend(true, {}, activeProject.dependencies);
|
||||
@@ -484,7 +484,7 @@ RED.projects.settings = (function() {
|
||||
});
|
||||
});
|
||||
} else if (!entry.known) {
|
||||
$('<a href="#" class="editor-button editor-button-small">add to project</a>').appendTo(buttons)
|
||||
$('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.addToProject") + '</a>').appendTo(buttons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var deps = $.extend(true, {}, activeProject.dependencies);
|
||||
@@ -723,10 +723,10 @@ RED.projects.settings = (function() {
|
||||
// }
|
||||
|
||||
function createFilesSection(activeProject,pane) {
|
||||
var title = $('<h3></h3>').text("Files").appendTo(pane);
|
||||
var title = $('<h3></h3>').text(RED._("sidebar.project.projectSettings.files")).appendTo(pane);
|
||||
var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||
if (RED.user.hasPermission("projects.write")) {
|
||||
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
|
||||
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.projectSettings.edit') + '</button>')
|
||||
.appendTo(title)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -750,7 +750,7 @@ RED.projects.settings = (function() {
|
||||
|
||||
// Flow files
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
|
||||
$('<label for=""></label>').text('Flow').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.flow")).appendTo(row);
|
||||
var flowFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
|
||||
var flowFileLabelText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.files.flow).appendTo(flowFileLabel);
|
||||
|
||||
@@ -787,7 +787,7 @@ RED.projects.settings = (function() {
|
||||
})
|
||||
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
|
||||
$('<label for=""></label>').text('Credentials').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.credentials")).appendTo(row);
|
||||
var credFileLabel = $('<div class="uneditable-input">').text(activeProject.files.credentials).appendTo(row);
|
||||
var credFileInput = $('<div class="uneditable-input">').text(activeProject.files.credentials).hide().insertAfter(credFileLabel);
|
||||
|
||||
@@ -899,12 +899,12 @@ RED.projects.settings = (function() {
|
||||
|
||||
var credentialFormRows = $('<div>',{style:"margin-top:10px"}).hide().appendTo(credentialStateLabel);
|
||||
|
||||
var credentialSetLabel = $('<div style="margin: 20px 0 10px 5px;">Set the encryption key:</div>').hide().appendTo(credentialFormRows);
|
||||
var credentialChangeLabel = $('<div style="margin: 20px 0 10px 5px;">Change the encryption key:</div>').hide().appendTo(credentialFormRows);
|
||||
var credentialResetLabel = $('<div style="margin: 20px 0 10px 5px;">Reset the encryption key:</div>').hide().appendTo(credentialFormRows);
|
||||
var credentialSetLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.setTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
|
||||
var credentialChangeLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.changeTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
|
||||
var credentialResetLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.resetTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
|
||||
|
||||
var credentialSecretExistingRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows);
|
||||
$('<label for=""></label>').text('Current key').appendTo(credentialSecretExistingRow);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.currentKey")).appendTo(credentialSecretExistingRow);
|
||||
var credentialSecretExistingInput = $('<input type="password">').appendTo(credentialSecretExistingRow)
|
||||
.on("change keyup paste",function() {
|
||||
if (popover) {
|
||||
@@ -917,10 +917,10 @@ RED.projects.settings = (function() {
|
||||
var credentialSecretNewRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows);
|
||||
|
||||
|
||||
$('<label for=""></label>').text('New key').appendTo(credentialSecretNewRow);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.newKey")).appendTo(credentialSecretNewRow);
|
||||
var credentialSecretNewInput = $('<input type="password">').appendTo(credentialSecretNewRow).on("change keyup paste",checkFiles);
|
||||
|
||||
var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i> This will delete all existing credentials</div>').hide().appendTo(credentialFormRows);
|
||||
var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i>' + RED._("sidebar.project.projectSettings.credentialsAlert") + '</div>').hide().appendTo(credentialFormRows);
|
||||
|
||||
|
||||
var hideEditForm = function() {
|
||||
@@ -950,13 +950,13 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
|
||||
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer);
|
||||
$('<button class="editor-button">Cancel</button>')
|
||||
$('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
hideEditForm();
|
||||
});
|
||||
var saveButton = $('<button class="editor-button">Save</button>')
|
||||
var saveButton = $('<button class="editor-button">' + RED._("common.label.save") + '</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -1024,19 +1024,21 @@ RED.projects.settings = (function() {
|
||||
},
|
||||
}
|
||||
},payload).always(function() {
|
||||
RED.deploy.setDeployInflight(false);
|
||||
setTimeout(function() {
|
||||
RED.deploy.setDeployInflight(false);
|
||||
},500);
|
||||
});
|
||||
});
|
||||
var updateForm = function() {
|
||||
if (activeProject.settings.credentialSecretInvalid) {
|
||||
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-warning");
|
||||
credentialStateLabel.find(".user-settings-credentials-state").text("Invalid encryption key");
|
||||
credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.invalidEncryptionKey"));
|
||||
} else if (activeProject.settings.credentialsEncrypted) {
|
||||
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-lock");
|
||||
credentialStateLabel.find(".user-settings-credentials-state").text("Encryption enabled");
|
||||
credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.encryptionEnabled"));
|
||||
} else {
|
||||
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-unlock");
|
||||
credentialStateLabel.find(".user-settings-credentials-state").text("Encryption disabled");
|
||||
credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.encryptionDisabled"));
|
||||
}
|
||||
credentialSecretResetButton.toggleClass('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
|
||||
credentialSecretResetButton.prop('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
|
||||
@@ -1048,7 +1050,7 @@ RED.projects.settings = (function() {
|
||||
|
||||
function createLocalBranchListSection(activeProject,pane) {
|
||||
var localBranchContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||
$('<h4></h4>').text("Branches").appendTo(localBranchContainer);
|
||||
$('<h4></h4>').text(RED._("sidebar.project.projectSettings.branches")).appendTo(localBranchContainer);
|
||||
|
||||
var row = $('<div class="user-settings-row projects-dialog-list"></div>').appendTo(localBranchContainer);
|
||||
|
||||
@@ -1061,7 +1063,7 @@ RED.projects.settings = (function() {
|
||||
var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
|
||||
if (entry.empty) {
|
||||
container.addClass('red-ui-search-empty');
|
||||
container.text("No branches");
|
||||
container.text(RED._("sidebar.project.projectSettings.noBranches"));
|
||||
return;
|
||||
}
|
||||
if (entry.current) {
|
||||
@@ -1093,7 +1095,7 @@ RED.projects.settings = (function() {
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
|
||||
var notification = RED.notify("Are you sure you want to delete the local branch '"+entry.name+"'? This cannot be undone.", {
|
||||
var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteConfirm", { name: entry.name }), {
|
||||
type: "warning",
|
||||
modal: true,
|
||||
fixed: true,
|
||||
@@ -1121,7 +1123,7 @@ RED.projects.settings = (function() {
|
||||
},
|
||||
400: {
|
||||
'git_delete_branch_unmerged': function(error) {
|
||||
notification = RED.notify("The local branch '"+entry.name+"' has unmerged changes that will be lost. Are you sure you want to delete it?", {
|
||||
notification = RED.notify(RED._("sidebar.project.projectSettings.unmergedConfirm", { name: entry.name }), {
|
||||
type: "warning",
|
||||
modal: true,
|
||||
fixed: true,
|
||||
@@ -1133,7 +1135,7 @@ RED.projects.settings = (function() {
|
||||
notification.close();
|
||||
}
|
||||
},{
|
||||
text: 'Delete unmerged branch',
|
||||
text: RED._("sidebar.project.projectSettings.deleteUnmergedBranch"),
|
||||
click: function() {
|
||||
options.url += "?force=true";
|
||||
notification.close();
|
||||
@@ -1181,14 +1183,14 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
|
||||
function createRemoteRepositorySection(activeProject,pane) {
|
||||
$('<h3></h3>').text("Version Control").appendTo(pane);
|
||||
$('<h3></h3>').text(RED._("sidebar.project.projectSettings.versionControl")).appendTo(pane);
|
||||
|
||||
createLocalBranchListSection(activeProject,pane);
|
||||
|
||||
var repoContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||
var title = $('<h4></h4>').text("Git remotes").appendTo(repoContainer);
|
||||
var title = $('<h4></h4>').text(RED._("sidebar.project.projectSettings.gitRemotes")).appendTo(repoContainer);
|
||||
|
||||
var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right; margin-right: 10px;">add remote</button>')
|
||||
var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right; margin-right: 10px;">' + RED._("sidebar.project.projectSettings.addRemote") + '</button>')
|
||||
.appendTo(title)
|
||||
.click(function(evt) {
|
||||
editRepoButton.attr('disabled',true);
|
||||
@@ -1219,7 +1221,7 @@ RED.projects.settings = (function() {
|
||||
var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
|
||||
if (entry.empty) {
|
||||
container.addClass('red-ui-search-empty');
|
||||
container.text("No remotes");
|
||||
container.text(RED._("sidebar.project.projectSettings.noRemotes"));
|
||||
return;
|
||||
} else {
|
||||
$('<span class="entry-icon"><i class="fa fa-globe"></i></span>').appendTo(container);
|
||||
@@ -1238,7 +1240,7 @@ RED.projects.settings = (function() {
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
|
||||
var notification = RED.notify("Are you sure you want to delete the remote '"+entry.name+"'?", {
|
||||
var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteRemoteConfrim", { name: entry.name }), {
|
||||
type: "warning",
|
||||
modal: true,
|
||||
fixed: true,
|
||||
@@ -1250,9 +1252,17 @@ RED.projects.settings = (function() {
|
||||
notification.close();
|
||||
}
|
||||
},{
|
||||
text: 'Delete remote',
|
||||
text: RED._("sidebar.project.projectSettings.deleteRemote"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
|
||||
if (activeProject.git.branches.remote && activeProject.git.branches.remote.indexOf(entry.name+"/") === 0) {
|
||||
delete activeProject.git.branches.remote;
|
||||
}
|
||||
if (activeProject.git.branches.remoteAlt && activeProject.git.branches.remoteAlt.indexOf(entry.name+"/") === 0) {
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
|
||||
var url = "projects/"+activeProject.name+"/remotes/"+entry.name;
|
||||
var options = {
|
||||
url: url,
|
||||
@@ -1274,6 +1284,7 @@ RED.projects.settings = (function() {
|
||||
activeProject.git.remotes[name] = remote;
|
||||
});
|
||||
}
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
RED.sidebar.versionControl.refresh();
|
||||
});
|
||||
},
|
||||
@@ -1304,10 +1315,10 @@ RED.projects.settings = (function() {
|
||||
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\.git)?(?:\/?|\#[\d\w\.\-_]+?)$/.test(remoteURLInput.val());
|
||||
var validRepo = repo.length > 0 && !/\s/.test(repo);
|
||||
if (/^https?:\/\/[^/]+@/i.test(repo)) {
|
||||
remoteURLLabel.text("Do not include the username/password in the url");
|
||||
remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule2"));
|
||||
validRepo = false;
|
||||
} else {
|
||||
remoteURLLabel.text("https://, ssh:// or file://");
|
||||
remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule"));
|
||||
}
|
||||
saveButton.attr('disabled',(!validName || !validRepo))
|
||||
remoteNameInput.toggleClass('input-error',remoteNameInputChanged&&!validName);
|
||||
@@ -1321,22 +1332,22 @@ RED.projects.settings = (function() {
|
||||
var remoteNameInputChanged = false;
|
||||
var remoteURLInputChanged = false;
|
||||
|
||||
$('<div class="projects-dialog-list-dialog-header">').text('Add remote').appendTo(addRemoteDialog);
|
||||
$('<div class="projects-dialog-list-dialog-header">').text(RED._('sidebar.project.projectSettings.addRemote2')).appendTo(addRemoteDialog);
|
||||
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
|
||||
$('<label for=""></label>').text('Remote name').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.remoteName")).appendTo(row);
|
||||
var remoteNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
|
||||
remoteNameInputChanged = true;
|
||||
validateForm();
|
||||
});
|
||||
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
|
||||
$('<label class="projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.nameRule") + '</small></label>').appendTo(row).find("small");
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
|
||||
$('<label for=""></label>').text('URL').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.url")).appendTo(row);
|
||||
var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
|
||||
remoteURLInputChanged = true;
|
||||
validateForm()
|
||||
});
|
||||
var remoteURLLabel = $('<label class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row).find("small");
|
||||
var remoteURLLabel = $('<label class="projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.urlRule") +'</small></label>').appendTo(row).find("small");
|
||||
|
||||
var hideEditForm = function() {
|
||||
editRepoButton.attr('disabled',false);
|
||||
@@ -1350,13 +1361,13 @@ RED.projects.settings = (function() {
|
||||
}
|
||||
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>')
|
||||
.appendTo(addRemoteDialog);
|
||||
$('<button class="editor-button">Cancel</button>')
|
||||
$('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
hideEditForm();
|
||||
});
|
||||
var saveButton = $('<button class="editor-button">Add remote</button>')
|
||||
var saveButton = $('<button class="editor-button">' + RED._("sidebar.project.projectSettings.addRemote2") + '</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -1473,19 +1484,19 @@ RED.projects.settings = (function() {
|
||||
utils = _utils;
|
||||
addPane({
|
||||
id:'main',
|
||||
title: "Project", // TODO: nls
|
||||
title: RED._("sidebar.project.name"),
|
||||
get: createMainPane,
|
||||
close: function() { }
|
||||
});
|
||||
addPane({
|
||||
id:'deps',
|
||||
title: "Dependencies", // TODO: nls
|
||||
title: RED._("sidebar.project.dependencies"),
|
||||
get: createDependenciesPane,
|
||||
close: function() { }
|
||||
});
|
||||
addPane({
|
||||
id:'settings',
|
||||
title: "Settings", // TODO: nls
|
||||
title: RED._("sidebar.project.settings"),
|
||||
get: createSettingsPane,
|
||||
close: function() {
|
||||
if (popover) {
|
||||
|
||||
@@ -24,18 +24,18 @@ RED.projects.userSettings = (function() {
|
||||
var currentGitSettings = RED.settings.get('git') || {};
|
||||
currentGitSettings.user = currentGitSettings.user || {};
|
||||
|
||||
var title = $('<h3></h3>').text("Committer Details").appendTo(pane);
|
||||
var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.committerDetail")).appendTo(pane);
|
||||
|
||||
var gitconfigContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||
$('<div style="color:#aaa;"></div>').appendTo(gitconfigContainer).text("Leave blank to use system default");
|
||||
$('<div style="color:#aaa;"></div>').appendTo(gitconfigContainer).text(RED._("editor:sidebar.project.userSettings.committerTip"));
|
||||
|
||||
var row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer);
|
||||
$('<label for=""></label>').text('Username').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row);
|
||||
gitUsernameInput = $('<input type="text">').appendTo(row);
|
||||
gitUsernameInput.val(currentGitSettings.user.name||"");
|
||||
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer);
|
||||
$('<label for=""></label>').text('Email').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row);
|
||||
gitEmailInput = $('<input type="text">').appendTo(row);
|
||||
gitEmailInput.val(currentGitSettings.user.email||"");
|
||||
}
|
||||
@@ -44,10 +44,10 @@ RED.projects.userSettings = (function() {
|
||||
function createSSHKeySection(pane) {
|
||||
var container = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||
var popover;
|
||||
var title = $('<h3></h3>').text("SSH Keys").appendTo(container);
|
||||
var subtitle = $('<div style="color:#aaa;"></div>').appendTo(container).text("Allows you to create secure connections to remote git repositories.");
|
||||
var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.sshKeys")).appendTo(container);
|
||||
var subtitle = $('<div style="color:#aaa;"></div>').appendTo(container).text(RED._("editor:sidebar.project.userSettings.sshKeysTip"));
|
||||
|
||||
var addKeyButton = $('<button id="user-settings-gitconfig-add-key" class="editor-button editor-button-small" style="float: right; margin-right: 10px;">add key</button>')
|
||||
var addKeyButton = $('<button id="user-settings-gitconfig-add-key" class="editor-button editor-button-small" style="float: right; margin-right: 10px;">'+RED._("editor:sidebar.project.userSettings.add")+'</button>')
|
||||
.appendTo(subtitle)
|
||||
.click(function(evt) {
|
||||
addKeyButton.attr('disabled',true);
|
||||
@@ -72,9 +72,9 @@ RED.projects.userSettings = (function() {
|
||||
var validPassphrase = passphrase.length === 0 || passphrase.length >= 8;
|
||||
passphraseInput.toggleClass('input-error',!validPassphrase);
|
||||
if (!validPassphrase) {
|
||||
passphraseInputSubLabel.text("Passphrase too short");
|
||||
passphraseInputSubLabel.text(RED._("editor:sidebar.project.userSettings.passphraseShort"));
|
||||
} else if (passphrase.length === 0) {
|
||||
passphraseInputSubLabel.text("Optional");
|
||||
passphraseInputSubLabel.text(RED._("editor:sidebar.project.userSettings.optional"));
|
||||
} else {
|
||||
passphraseInputSubLabel.text("");
|
||||
}
|
||||
@@ -91,11 +91,11 @@ RED.projects.userSettings = (function() {
|
||||
|
||||
var row = $('<div class="user-settings-row"></div>').appendTo(container);
|
||||
var addKeyDialog = $('<div class="projects-dialog-list-dialog"></div>').hide().appendTo(row);
|
||||
$('<div class="projects-dialog-list-dialog-header">').text('Add SSH Key').appendTo(addKeyDialog);
|
||||
$('<div class="projects-dialog-list-dialog-header">').text(RED._("editor:sidebar.project.userSettings.addSshKey")).appendTo(addKeyDialog);
|
||||
var addKeyDialogBody = $('<div>').appendTo(addKeyDialog);
|
||||
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody);
|
||||
$('<div style="color:#aaa;"></div>').appendTo(row).text("Generate a new public/private key pair");
|
||||
$('<div style="color:#aaa;"></div>').appendTo(row).text(RED._("editor:sidebar.project.userSettings.addSshKeyTip"));
|
||||
// var bg = $('<div></div>',{class:"button-group", style:"text-align: center"}).appendTo(row);
|
||||
// var addLocalButton = $('<button class="editor-button toggle selected">use local key</button>').appendTo(bg);
|
||||
// var uploadButton = $('<button class="editor-button toggle">upload key</button>').appendTo(bg);
|
||||
@@ -125,19 +125,19 @@ RED.projects.userSettings = (function() {
|
||||
|
||||
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody);
|
||||
$('<label for=""></label>').text('Name').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.name")).appendTo(row);
|
||||
var keyNameInputChanged = false;
|
||||
var keyNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
|
||||
keyNameInputChanged = true;
|
||||
validateForm();
|
||||
});
|
||||
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
|
||||
$('<label class="projects-edit-form-sublabel"><small>'+RED._("editor:sidebar.project.userSettings.nameRule")+'</small></label>').appendTo(row).find("small");
|
||||
|
||||
var generateKeyPane = $('<div>').appendTo(addKeyDialogBody);
|
||||
row = $('<div class="user-settings-row"></div>').appendTo(generateKeyPane);
|
||||
$('<label for=""></label>').text('Passphrase').appendTo(row);
|
||||
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.passphrase")).appendTo(row);
|
||||
var passphraseInput = $('<input type="password">').appendTo(row).on("change keyup paste",validateForm);
|
||||
var passphraseInputSubLabel = $('<label class="projects-edit-form-sublabel"><small>Optional</small></label>').appendTo(row).find("small");
|
||||
var passphraseInputSubLabel = $('<label class="projects-edit-form-sublabel"><small>'+RED._("editor:sidebar.project.userSettings.optional")+'</small></label>').appendTo(row).find("small");
|
||||
|
||||
// var addLocalKeyPane = $('<div>').hide().appendTo(addKeyDialogBody);
|
||||
// row = $('<div class="user-settings-row"></div>').appendTo(addLocalKeyPane);
|
||||
@@ -179,13 +179,13 @@ RED.projects.userSettings = (function() {
|
||||
}
|
||||
}
|
||||
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(addKeyDialog);
|
||||
$('<button class="editor-button">Cancel</button>')
|
||||
$('<button class="editor-button">'+RED._("editor:sidebar.project.userSettings.cancel")+'</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
hideEditForm();
|
||||
});
|
||||
var saveButton = $('<button class="editor-button">Generate key</button>')
|
||||
var saveButton = $('<button class="editor-button">'+RED._("editor:sidebar.project.userSettings.generate")+'</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -264,7 +264,7 @@ RED.projects.userSettings = (function() {
|
||||
utils.sendRequest(options);
|
||||
|
||||
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(row);
|
||||
$('<button class="editor-button editor-button-small">Copy public key to clipboard</button>')
|
||||
$('<button class="editor-button editor-button-small">'+RED._("editor:sidebar.project.userSettings.copyPublicKey")+'</button>')
|
||||
.appendTo(formButtons)
|
||||
.click(function(evt) {
|
||||
try {
|
||||
@@ -289,7 +289,7 @@ RED.projects.userSettings = (function() {
|
||||
var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
|
||||
if (entry.empty) {
|
||||
container.addClass('red-ui-search-empty');
|
||||
container.text("No SSH keys");
|
||||
container.text(RED._("editor:sidebar.project.userSettings.noSshKeys"));
|
||||
return;
|
||||
}
|
||||
var topRow = $('<div class="projects-dialog-ssh-key-header">').appendTo(container);
|
||||
@@ -313,7 +313,7 @@ RED.projects.userSettings = (function() {
|
||||
.click(function(e) {
|
||||
e.stopPropagation();
|
||||
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
|
||||
var notification = RED.notify("Are you sure you want to delete the SSH key '"+entry.name+"'? This cannot be undone.", {
|
||||
var notification = RED.notify(RED._("editor:sidebar.project.userSettings.deleteConfirm", {name:entry.name}), {
|
||||
type: 'warning',
|
||||
modal: true,
|
||||
fixed: true,
|
||||
@@ -326,7 +326,7 @@ RED.projects.userSettings = (function() {
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "Delete key",
|
||||
text: RED._("editor:sidebar.project.userSettings.delete"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
var url = "settings/user/keys/"+entry.name;
|
||||
@@ -400,7 +400,7 @@ RED.projects.userSettings = (function() {
|
||||
utils = _utils;
|
||||
RED.userSettings.add({
|
||||
id:'gitconfig',
|
||||
title: "Git config", // TODO: nls
|
||||
title: RED._("editor:sidebar.project.userSettings.gitConfig"),
|
||||
get: createSettingsPane,
|
||||
close: function() {
|
||||
var currentGitSettings = RED.settings.get('git') || {};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,11 +52,11 @@ RED.sidebar.versionControl = (function() {
|
||||
200: function(data) {
|
||||
var title;
|
||||
if (state === 'unstaged') {
|
||||
title = 'Unstaged changes : '+entry.file
|
||||
title = RED._("sidebar.project.versionControl.unstagedChanges")+' : '+entry.file
|
||||
} else if (state === 'staged') {
|
||||
title = 'Staged changes : '+entry.file
|
||||
title = RED._("sidebar.project.versionControl.stagedChanges")+' : '+entry.file
|
||||
} else {
|
||||
title = 'Resolve conflicts : '+entry.file
|
||||
title = RED._("sidebar.project.versionControl.resolveConflicts")+' : '+entry.file
|
||||
}
|
||||
var options = {
|
||||
diff: data.diff,
|
||||
@@ -65,18 +65,18 @@ RED.sidebar.versionControl = (function() {
|
||||
project: activeProject
|
||||
}
|
||||
if (state == 'unstaged') {
|
||||
options.oldRevTitle = entry.indexStatus === " "?"HEAD":"Staged";
|
||||
options.newRevTitle = "Unstaged";
|
||||
options.oldRevTitle = entry.indexStatus === " "?RED._("sidebar.project.versionControl.head"):RED._("sidebar.project.versionControl.staged");
|
||||
options.newRevTitle = RED._("sidebar.project.versionControl.unstaged");
|
||||
options.oldRev = entry.indexStatus === " "?"@":":0";
|
||||
options.newRev = "_";
|
||||
} else if (state === 'staged') {
|
||||
options.oldRevTitle = "HEAD";
|
||||
options.newRevTitle = "Staged";
|
||||
options.oldRevTitle = RED._("sidebar.project.versionControl.head");
|
||||
options.newRevTitle = RED._("sidebar.project.versionControl.staged");
|
||||
options.oldRev = "@";
|
||||
options.newRev = ":0";
|
||||
} else {
|
||||
options.oldRevTitle = "Local";
|
||||
options.newRevTitle = "Remote";
|
||||
options.oldRevTitle = RED._("sidebar.project.versionControl.local");
|
||||
options.newRevTitle = RED._("sidebar.project.versionControl.remote");
|
||||
options.commonRev = ":1";
|
||||
options.oldRev = ":2";
|
||||
options.newRev = ":3";
|
||||
@@ -154,8 +154,9 @@ RED.sidebar.versionControl = (function() {
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
var spinner = utils.addSpinnerOverlay(container).addClass('projects-dialog-spinner-contain');
|
||||
var notification = RED.notify("Are you sure you want to revert the changes to '"+entry.file+"'? This cannot be undone.", {
|
||||
var notification = RED.notify(RED._("sidebar.project.versionControl.revert",{file:entry.file}), {
|
||||
type: "warning",
|
||||
modal: true,
|
||||
fixed: true,
|
||||
@@ -167,7 +168,7 @@ RED.sidebar.versionControl = (function() {
|
||||
notification.close();
|
||||
}
|
||||
},{
|
||||
text: 'Revert changes',
|
||||
text: RED._("sidebar.project.versionControl.revertChanges"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
var activeProject = RED.projects.getActiveProject();
|
||||
@@ -188,7 +189,12 @@ RED.sidebar.versionControl = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
utils.sendRequest(options);
|
||||
RED.deploy.setDeployInflight(true);
|
||||
utils.sendRequest(options).always(function() {
|
||||
setTimeout(function() {
|
||||
RED.deploy.setDeployInflight(false);
|
||||
},500);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,6 +281,8 @@ RED.sidebar.versionControl = (function() {
|
||||
entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status);
|
||||
}
|
||||
var utils;
|
||||
var emptyStagedItem;
|
||||
var emptyMergedItem;
|
||||
function init(_utils) {
|
||||
utils = _utils;
|
||||
|
||||
@@ -306,7 +314,7 @@ RED.sidebar.versionControl = (function() {
|
||||
});
|
||||
|
||||
localChanges = sections.add({
|
||||
title: "Local Changes",
|
||||
title: RED._("sidebar.project.versionControl.localChanges"),
|
||||
collapsible: true
|
||||
});
|
||||
localChanges.expand();
|
||||
@@ -320,10 +328,12 @@ RED.sidebar.versionControl = (function() {
|
||||
refresh(true);
|
||||
})
|
||||
|
||||
emptyStagedItem = { label: RED._("sidebar.project.versionControl.none") };
|
||||
emptyMergedItem = { label: RED._("sidebar.project.versionControl.conflictResolve") };
|
||||
|
||||
var unstagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
|
||||
var header = $('<div class="sidebar-version-control-change-header">Local files</div>').appendTo(unstagedContent);
|
||||
stageAllButton = $('<button class="editor-button editor-button-small" style="float: right"><i class="fa fa-plus"></i> all</button>')
|
||||
var header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.localFiles")+'</div>').appendTo(unstagedContent);
|
||||
stageAllButton = $('<button class="editor-button editor-button-small" style="float: right"><i class="fa fa-plus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
|
||||
.appendTo(header)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -353,9 +363,9 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
unmergedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
|
||||
|
||||
header = $('<div class="sidebar-version-control-change-header">Unmerged changes</div>').appendTo(unmergedContent);
|
||||
header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.unmergedChanges")+'</div>').appendTo(unmergedContent);
|
||||
bg = $('<div style="float: right"></div>').appendTo(header);
|
||||
var abortMergeButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">abort merge</button>')
|
||||
var abortMergeButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">'+RED._("sidebar.project.versionControl.abortMerge")+'</button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -393,7 +403,7 @@ RED.sidebar.versionControl = (function() {
|
||||
addItem: function(row,index,entry) {
|
||||
if (entry === emptyMergedItem) {
|
||||
entry.button = {
|
||||
label: 'commit',
|
||||
label: RED._("sidebar.project.versionControl.commit"),
|
||||
click: function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
@@ -417,7 +427,7 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
var stagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
|
||||
|
||||
header = $('<div class="sidebar-version-control-change-header">Changes to commit</div>').appendTo(stagedContent);
|
||||
header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.changeToCommit")+'</div>').appendTo(stagedContent);
|
||||
|
||||
bg = $('<div style="float: right"></div>').appendTo(header);
|
||||
var showCommitBox = function() {
|
||||
@@ -440,14 +450,14 @@ RED.sidebar.versionControl = (function() {
|
||||
abortMergeButton.attr("disabled",true);
|
||||
commitMessage.focus();
|
||||
}
|
||||
commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">commit</button>')
|
||||
commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">'+RED._("sidebar.project.versionControl.commit")+'</button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
showCommitBox();
|
||||
});
|
||||
unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> all</button>')
|
||||
unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -474,14 +484,14 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
commitBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-bottom"></div>').hide().appendTo(localChanges.content);
|
||||
|
||||
var commitMessage = $('<textarea placeholder="Enter your commit message"></textarea>')
|
||||
var commitMessage = $('<textarea placeholder='+RED._("sidebar.project.versionControl.commitPlaceholder")+'></textarea>')
|
||||
.appendTo(commitBox)
|
||||
.on("change keyup paste",function() {
|
||||
submitCommitButton.attr('disabled',$(this).val().trim()==="");
|
||||
});
|
||||
var commitToolbar = $('<div class="sidebar-version-control-slide-box-toolbar button-group">').appendTo(commitBox);
|
||||
|
||||
var cancelCommitButton = $('<button class="editor-button">Cancel</button>')
|
||||
var cancelCommitButton = $('<button class="editor-button">'+RED._("sidebar.project.versionControl.cancelCapital")+'</button>')
|
||||
.appendTo(commitToolbar)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -499,7 +509,7 @@ RED.sidebar.versionControl = (function() {
|
||||
abortMergeButton.attr("disabled",false);
|
||||
|
||||
})
|
||||
var submitCommitButton = $('<button class="editor-button">Commit</button>')
|
||||
var submitCommitButton = $('<button class="editor-button">'+RED._("sidebar.project.versionControl.commitCapital")+'</button>')
|
||||
.appendTo(commitToolbar)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -535,7 +545,7 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
|
||||
var localHistory = sections.add({
|
||||
title: "Commit History",
|
||||
title: RED._("sidebar.project.versionControl.commitHistory"),
|
||||
collapsible: true
|
||||
});
|
||||
|
||||
@@ -549,7 +559,7 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
var localBranchToolbar = $('<div class="sidebar-version-control-change-header" style="text-align: right;"></div>').appendTo(localHistory.content);
|
||||
|
||||
var localBranchButton = $('<button class="editor-button editor-button-small"><i class="fa fa-code-fork"></i> Branch: <span id="sidebar-version-control-local-branch"></span></button>')
|
||||
var localBranchButton = $('<button class="editor-button editor-button-small"><i class="fa fa-code-fork"></i> '+RED._("sidebar.project.versionControl.branch")+' <span id="sidebar-version-control-local-branch"></span></button>')
|
||||
.appendTo(localBranchToolbar)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -586,7 +596,10 @@ RED.sidebar.versionControl = (function() {
|
||||
closeBranchBox();
|
||||
localCommitListShade.show();
|
||||
$(this).addClass('selected');
|
||||
var activeProject = RED.projects.getActiveProject();
|
||||
$("#sidebar-version-control-repo-toolbar-set-upstream-row").toggle(!!activeProject.git.branches.remoteAlt);
|
||||
remoteBox.show();
|
||||
|
||||
setTimeout(function() {
|
||||
remoteBox.css("height","265px");
|
||||
},100);
|
||||
@@ -603,7 +616,7 @@ RED.sidebar.versionControl = (function() {
|
||||
row.addClass('sidebar-version-control-commit-entry');
|
||||
if (entry.url) {
|
||||
row.addClass('sidebar-version-control-commit-more');
|
||||
row.text("+ "+(entry.total-entry.totalKnown)+" more commit(s)");
|
||||
row.text("+ "+(entry.total-entry.totalKnown)+RED._("sidebar.project.versionControl.moreCommits"));
|
||||
row.click(function(e) {
|
||||
e.preventDefault();
|
||||
getCommits(entry.url,localCommitList,row,entry.limit,entry.before);
|
||||
@@ -617,8 +630,8 @@ RED.sidebar.versionControl = (function() {
|
||||
result.parents = entry.parents;
|
||||
result.oldRev = entry.sha+"~1";
|
||||
result.newRev = entry.sha;
|
||||
result.oldRevTitle = "Commit "+entry.sha.substring(0,7)+"~1";
|
||||
result.newRevTitle = "Commit "+entry.sha.substring(0,7);
|
||||
result.oldRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7)+"~1";
|
||||
result.newRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7);
|
||||
result.date = humanizeSinceDate(parseInt(entry.date));
|
||||
RED.diff.showCommitDiff(result);
|
||||
});
|
||||
@@ -657,10 +670,10 @@ RED.sidebar.versionControl = (function() {
|
||||
}
|
||||
var localBranchBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-top" style="top:30px;"></div>').hide().appendTo(localHistory.content);
|
||||
|
||||
$('<div class="sidebar-version-control-slide-box-header"></div>').text("Change local branch").appendTo(localBranchBox);
|
||||
$('<div class="sidebar-version-control-slide-box-header"></div>').text(RED._("sidebar.project.versionControl.changeLocalBranch")).appendTo(localBranchBox);
|
||||
|
||||
var localBranchList = utils.createBranchList({
|
||||
placeholder: "Find or create a branch",
|
||||
placeholder: RED._("sidebar.project.versionControl.createBranchPlaceholder"),
|
||||
container: localBranchBox,
|
||||
onselect: function(body) {
|
||||
if (body.current) {
|
||||
@@ -692,7 +705,7 @@ RED.sidebar.versionControl = (function() {
|
||||
400: {
|
||||
'git_local_overwrite': function(error) {
|
||||
spinner.remove();
|
||||
RED.notify("You have local changes that would be overwritten by changing the branch. You must either commit or undo those changes first.",{
|
||||
RED.notify(RED._("sidebar.project.versionControl.localOverwrite"),{
|
||||
type:'error',
|
||||
timeout: 8000
|
||||
});
|
||||
@@ -735,10 +748,10 @@ RED.sidebar.versionControl = (function() {
|
||||
},200);
|
||||
}
|
||||
}
|
||||
$('<div class="sidebar-version-control-slide-box-header"></div>').text("Manage remote branch").appendTo(remoteBox);
|
||||
$('<div class="sidebar-version-control-slide-box-header"></div>').text(RED._("sidebar.project.versionControl.manageRemoteBranch")).appendTo(remoteBox);
|
||||
|
||||
var remoteBranchRow = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox);
|
||||
var remoteBranchButton = $('<button id="sidebar-version-control-repo-branch" class="sidebar-version-control-repo-action editor-button"><i class="fa fa-code-fork"></i> Remote: <span id="sidebar-version-control-remote-branch"></span></button>')
|
||||
var remoteBranchButton = $('<button id="sidebar-version-control-repo-branch" class="sidebar-version-control-repo-action editor-button"><i class="fa fa-code-fork"></i> '+RED._("sidebar.project.versionControl.remote")+': <span id="sidebar-version-control-remote-branch"></span></button>')
|
||||
.appendTo(remoteBranchRow)
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -761,9 +774,9 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
|
||||
var errorMessage = $('<div id="sidebar-version-control-repo-toolbar-error-message" class="sidebar-version-control-slide-box-header" style="min-height: 100px;"></div>').hide().appendTo(remoteBox);
|
||||
$('<div style="margin-top: 10px;"><i class="fa fa-warning"></i> Unable to access remote repository</div>').appendTo(errorMessage)
|
||||
$('<div style="margin-top: 10px;"><i class="fa fa-warning"></i> '+RED._("sidebar.project.versionControl.unableToAccess")+'</div>').appendTo(errorMessage)
|
||||
var buttonRow = $('<div style="margin: 10px 30px; text-align: center"></div>').appendTo(errorMessage);
|
||||
$('<button class="editor-button" style="width: 80%;"><i class="fa fa-refresh"></i> Retry</button>')
|
||||
$('<button class="editor-button" style="width: 80%;"><i class="fa fa-refresh"></i> '+RED._("sidebar.project.versionControl.retry")+'</button>')
|
||||
.appendTo(buttonRow)
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
@@ -801,12 +814,12 @@ RED.sidebar.versionControl = (function() {
|
||||
});
|
||||
})
|
||||
|
||||
$('<div class="sidebar-version-control-slide-box-header" style="height: 20px;"><label id="sidebar-version-control-repo-toolbar-set-upstream-row" for="sidebar-version-control-repo-toolbar-set-upstream" class="hide"><input type="checkbox" id="sidebar-version-control-repo-toolbar-set-upstream"> Set as upstream branch</label></div>').appendTo(remoteBox);
|
||||
$('<div class="sidebar-version-control-slide-box-header" style="height: 20px;"><label id="sidebar-version-control-repo-toolbar-set-upstream-row" for="sidebar-version-control-repo-toolbar-set-upstream" class="hide"><input type="checkbox" id="sidebar-version-control-repo-toolbar-set-upstream"> '+RED._("sidebar.project.versionControl.setUpstreamBranch")+'</label></div>').appendTo(remoteBox);
|
||||
|
||||
var remoteBranchSubRow = $('<div style="height: 0;overflow:hidden; transition: height 0.2s ease-in-out;"></div>').hide().appendTo(remoteBranchRow);
|
||||
var remoteBranchList = utils.createBranchList({
|
||||
placeholder: "Find or create a remote branch",
|
||||
currentLabel: "upstream",
|
||||
placeholder: RED._("sidebar.project.versionControl.createRemoteBranchPlaceholder"),
|
||||
currentLabel: RED._("sidebar.project.versionControl.upstream"),
|
||||
remote: function() {
|
||||
var project = RED.projects.getActiveProject();
|
||||
var remotes = Object.keys(project.git.remotes);
|
||||
@@ -836,11 +849,11 @@ RED.sidebar.versionControl = (function() {
|
||||
})
|
||||
} else {
|
||||
if (!activeProject.git.branches.remote) {
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("The created branch will be set as the tracked upstream branch.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.trackedUpstreamBranch"));
|
||||
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked',true);
|
||||
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('disabled',true);
|
||||
} else {
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("The branch will be created. Select below to set it as the tracked upstream branch.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.selectUpstreamBranch"));
|
||||
}
|
||||
$("#sidebar-version-control-repo-pull").attr('disabled',true);
|
||||
$("#sidebar-version-control-repo-push").attr('disabled',false);
|
||||
@@ -852,7 +865,7 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
var row = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox);
|
||||
|
||||
$('<button id="sidebar-version-control-repo-push" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-up"></i> <span>push</span></button>')
|
||||
$('<button id="sidebar-version-control-repo-push" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-up"></i> <span data-i18n="sidebar.project.versionControl.push"></span></button>')
|
||||
.appendTo(row)
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
@@ -862,7 +875,8 @@ RED.sidebar.versionControl = (function() {
|
||||
if (activeProject.git.branches.remoteAlt) {
|
||||
url+="/"+activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
if ($("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')) {
|
||||
var setUpstream = $("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked');
|
||||
if (setUpstream) {
|
||||
url+="?u=true"
|
||||
}
|
||||
utils.sendRequest({
|
||||
@@ -874,13 +888,17 @@ RED.sidebar.versionControl = (function() {
|
||||
// done(error,null);
|
||||
},
|
||||
200: function(data) {
|
||||
if (setUpstream && activeProject.git.branches.remoteAlt) {
|
||||
activeProject.git.branches.remote = activeProject.git.branches.remoteAlt;
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
refresh(true);
|
||||
closeRemoteBox();
|
||||
},
|
||||
400: {
|
||||
'git_push_failed': function(err) {
|
||||
// TODO: better message + NLS
|
||||
RED.notify("NLS: Push failed as the remote has more recent commits. Pull first and write a better error message!","error");
|
||||
// TODO: better message
|
||||
RED.notify(RED._("sidebar.project.versionControl.pushFailed"),"error");
|
||||
},
|
||||
'unexpected_error': function(error) {
|
||||
console.log(error);
|
||||
@@ -922,23 +940,27 @@ RED.sidebar.versionControl = (function() {
|
||||
// done(error,null);
|
||||
},
|
||||
200: function(data) {
|
||||
if (options.setUpstream && activeProject.git.branches.remoteAlt) {
|
||||
activeProject.git.branches.remote = activeProject.git.branches.remoteAlt;
|
||||
delete activeProject.git.branches.remoteAlt;
|
||||
}
|
||||
refresh(true);
|
||||
closeRemoteBox();
|
||||
},
|
||||
400: {
|
||||
'git_local_overwrite': function(err) {
|
||||
RED.notify("<p>Unable to pull remote changes; your unstaged local changes would be overwritten.</p><p>Commit your changes and try again.</p>"+
|
||||
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show unstaged changes'+'</a></p>',"error",false,10000000);
|
||||
RED.notify(RED._("sidebar.project.versionControl.unablePull")+
|
||||
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+RED._("sidebar.project.versionControl.showUnstagedChanges")+'</a></p>',"error",false,10000000);
|
||||
},
|
||||
'git_pull_merge_conflict': function(err) {
|
||||
refresh(true);
|
||||
closeRemoteBox();
|
||||
},
|
||||
'git_connection_failed': function(err) {
|
||||
RED.notify("Could not connect to remote repository: "+err.toString(),"warning")
|
||||
RED.notify(RED._("sidebar.project.versionControl.connectionFailed")+err.toString(),"warning")
|
||||
},
|
||||
'git_pull_unrelated_history': function(error) {
|
||||
var notification = RED.notify("<p>The remote has an unrelated history of commits.</p><p>Are you sure you want to pull the changes into your local repository?</p>",{
|
||||
var notification = RED.notify(RED._("sidebar.project.versionControl.pullUnrelatedHistory"),{
|
||||
type: 'error',
|
||||
modal: true,
|
||||
fixed: true,
|
||||
@@ -949,7 +971,7 @@ RED.sidebar.versionControl = (function() {
|
||||
notification.close();
|
||||
}
|
||||
},{
|
||||
text: 'Pull changes',
|
||||
text: RED._("sidebar.project.versionControl.pullChanges"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
options.allowUnrelatedHistories = true;
|
||||
@@ -968,7 +990,7 @@ RED.sidebar.versionControl = (function() {
|
||||
spinner.remove();
|
||||
});
|
||||
}
|
||||
$('<button id="sidebar-version-control-repo-pull" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-down"></i> <span>pull</span></button>')
|
||||
$('<button id="sidebar-version-control-repo-pull" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-down"></i> <span data-i18n="sidebar.project.versionControl.pull"></span></button>')
|
||||
.appendTo(row)
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
@@ -981,10 +1003,12 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
RED.sidebar.addTab({
|
||||
id: "version-control",
|
||||
label: "history",
|
||||
label: RED._("sidebar.project.versionControl.history"),
|
||||
name: "Project History",
|
||||
content: sidebarContent,
|
||||
enableOnEdit: false,
|
||||
pinned: true,
|
||||
iconClass: "fa fa-code-fork",
|
||||
onchange: function() {
|
||||
setTimeout(function() {
|
||||
sections.resize();
|
||||
@@ -1001,17 +1025,17 @@ RED.sidebar.versionControl = (function() {
|
||||
if (daysDelta > 30) {
|
||||
return (new Date(date*1000)).toLocaleDateString();
|
||||
} else if (daysDelta > 0) {
|
||||
return daysDelta+" day"+(daysDelta>1?"s":"")+" ago";
|
||||
return RED._("sidebar.project.versionControl.daysAgo", {count:daysDelta})
|
||||
}
|
||||
var hoursDelta = Math.floor(delta / (60*60));
|
||||
if (hoursDelta > 0) {
|
||||
return hoursDelta+" hour"+(hoursDelta>1?"s":"")+" ago";
|
||||
return RED._("sidebar.project.versionControl.hoursAgo", {count:hoursDelta})
|
||||
}
|
||||
var minutesDelta = Math.floor(delta / 60);
|
||||
if (minutesDelta > 0) {
|
||||
return minutesDelta+" minute"+(minutesDelta>1?"s":"")+" ago";
|
||||
return RED._("sidebar.project.versionControl.minsAgo", {count:minutesDelta})
|
||||
}
|
||||
return "Seconds ago";
|
||||
return RED._("sidebar.project.versionControl.secondsAgo");
|
||||
}
|
||||
|
||||
function updateBulk(files,unstaged) {
|
||||
@@ -1046,9 +1070,6 @@ RED.sidebar.versionControl = (function() {
|
||||
|
||||
var refreshInProgress = false;
|
||||
|
||||
var emptyStagedItem = { label:"None" };
|
||||
var emptyMergedItem = { label:"All conflicts resolved. Commit the changes to complete the merge." };
|
||||
|
||||
function getCommits(url,targetList,spinnerTarget,limit,before) {
|
||||
var spinner = utils.addSpinnerOverlay(spinnerTarget);
|
||||
var fullUrl = url+"?limit="+(limit||20);
|
||||
@@ -1256,7 +1277,7 @@ RED.sidebar.versionControl = (function() {
|
||||
refreshFiles(result);
|
||||
|
||||
$('#sidebar-version-control-local-branch').text(result.branches.local);
|
||||
$('#sidebar-version-control-remote-branch').text(result.branches.remote||"none");
|
||||
$('#sidebar-version-control-remote-branch').text(result.branches.remote||RED._("sidebar.project.versionControl.none"));
|
||||
|
||||
var commitsAhead = result.commits.ahead || 0;
|
||||
var commitsBehind = result.commits.behind || 0;
|
||||
@@ -1286,7 +1307,7 @@ RED.sidebar.versionControl = (function() {
|
||||
$('#sidebar-version-control-commits-ahead').text("");
|
||||
$('#sidebar-version-control-commits-behind').text("");
|
||||
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("Your local branch is not currently tracking a remote branch.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.notTracking"));
|
||||
$("#sidebar-version-control-repo-pull").attr('disabled',true);
|
||||
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||
}
|
||||
@@ -1312,23 +1333,26 @@ RED.sidebar.versionControl = (function() {
|
||||
$('#sidebar-version-control-commits-ahead').text(commitsAhead);
|
||||
$('#sidebar-version-control-commits-behind').text(commitsBehind);
|
||||
if (isMerging) {
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("Your repository has unmerged changes. You need to fix the conflicts and commit the result.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.statusUnmergedChanged"));
|
||||
$("#sidebar-version-control-repo-pull").attr('disabled',true);
|
||||
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||
} else if (commitsAhead > 0 && commitsBehind === 0) {
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsAhead+" commit"+(commitsAhead===1?'':'s')+" ahead of the remote. You can push "+(commitsAhead===1?'this commit':'these commits')+" now.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.commitsAhead", {count:commitsAhead}));
|
||||
$("#sidebar-version-control-repo-pull").attr('disabled',true);
|
||||
$("#sidebar-version-control-repo-push").attr('disabled',false);
|
||||
} else if (commitsAhead === 0 && commitsBehind > 0) {
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsBehind+" commit"+(commitsBehind===1?'':'s')+" behind of the remote. You can pull "+(commitsBehind===1?'this commit':'these commits')+" now.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.commitsBehind",{ count: commitsBehind }));
|
||||
$("#sidebar-version-control-repo-pull").attr('disabled',false);
|
||||
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||
} else if (commitsAhead > 0 && commitsBehind > 0) {
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsBehind+" commit"+(commitsBehind===1?'':'s')+" behind and "+commitsAhead+" commit"+(commitsAhead===1?'':'s')+" ahead of the remote. You must pull the remote commit"+(commitsBehind===1?'':'s')+" down before pushing.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(
|
||||
RED._("sidebar.project.versionControl.commitsAheadAndBehind1",{ count:commitsBehind })+
|
||||
RED._("sidebar.project.versionControl.commitsAheadAndBehind2",{ count:commitsAhead })+
|
||||
RED._("sidebar.project.versionControl.commitsAheadAndBehind3",{ count:commitsBehind }));
|
||||
$("#sidebar-version-control-repo-pull").attr('disabled',false);
|
||||
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||
} else if (commitsAhead === 0 && commitsBehind === 0) {
|
||||
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is up to date.");
|
||||
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.repositoryUpToDate"));
|
||||
$("#sidebar-version-control-repo-pull").attr('disabled',true);
|
||||
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,24 @@ RED.search = (function() {
|
||||
var keys = [];
|
||||
var results = [];
|
||||
|
||||
|
||||
function indexProperty(node,label,property) {
|
||||
if (typeof property === 'string' || typeof property === 'number') {
|
||||
property = (""+property).toLowerCase();
|
||||
index[property] = index[property] || {};
|
||||
index[property][node.id] = {node:node,label:label};
|
||||
} else if (Array.isArray(property)) {
|
||||
property.forEach(function(prop) {
|
||||
indexProperty(node,label,prop);
|
||||
})
|
||||
} else if (typeof property === 'object') {
|
||||
for (var prop in property) {
|
||||
if (property.hasOwnProperty(prop)) {
|
||||
indexProperty(node,label,property[prop])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function indexNode(n) {
|
||||
var l = RED.utils.getNodeLabel(n);
|
||||
if (l) {
|
||||
@@ -42,17 +60,11 @@ RED.search = (function() {
|
||||
}
|
||||
for (var i=0;i<properties.length;i++) {
|
||||
if (n.hasOwnProperty(properties[i])) {
|
||||
var v = n[properties[i]];
|
||||
if (typeof v === 'string' || typeof v === 'number') {
|
||||
v = (""+v).toLowerCase();
|
||||
index[v] = index[v] || {};
|
||||
index[v][n.id] = {node:n,label:l};
|
||||
}
|
||||
indexProperty(n, l, n[properties[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function indexWorkspace() {
|
||||
index = {};
|
||||
RED.nodes.eachWorkspace(indexNode);
|
||||
@@ -174,14 +186,14 @@ RED.search = (function() {
|
||||
addItem: function(container,i,object) {
|
||||
var node = object.node;
|
||||
if (node === undefined) {
|
||||
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
|
||||
|
||||
} else {
|
||||
var def = node._def;
|
||||
var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
|
||||
|
||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
|
||||
var colour = def.color;
|
||||
var colour = RED.utils.getNodeColor(node.type,def);
|
||||
var icon_url = RED.utils.getNodeIcon(def,node);
|
||||
if (node.type === 'tab') {
|
||||
colour = "#C0DEED";
|
||||
@@ -200,12 +212,12 @@ RED.search = (function() {
|
||||
} else {
|
||||
workspace = "flow:"+workspace.label;
|
||||
}
|
||||
$('<div>',{class:"red-ui-search-result-node-flow"}).html(workspace).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-flow"}).text(workspace).appendTo(contentDiv);
|
||||
}
|
||||
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).html(object.label || node.id).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).text(object.label || node.id).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-type"}).text(node.type).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-id"}).text(node.id).appendTo(contentDiv);
|
||||
|
||||
div.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -35,7 +35,8 @@ RED.sidebar = (function() {
|
||||
tab.onremove.call(tab);
|
||||
}
|
||||
},
|
||||
minimumActiveTabWidth: 70
|
||||
// minimumActiveTabWidth: 70,
|
||||
collapsible: true
|
||||
// scrollable: true
|
||||
});
|
||||
|
||||
@@ -59,6 +60,8 @@ RED.sidebar = (function() {
|
||||
options = title;
|
||||
}
|
||||
|
||||
delete options.closeable;
|
||||
|
||||
options.wrapper = $('<div>',{style:"height:100%"}).appendTo("#sidebar-content")
|
||||
options.wrapper.append(options.content);
|
||||
options.wrapper.hide();
|
||||
@@ -82,6 +85,8 @@ RED.sidebar = (function() {
|
||||
group: "sidebar-tabs"
|
||||
});
|
||||
|
||||
options.iconClass = options.iconClass || "fa fa-square-o"
|
||||
|
||||
knownTabs[options.id] = options;
|
||||
|
||||
if (options.visible !== false) {
|
||||
@@ -213,6 +218,7 @@ RED.sidebar = (function() {
|
||||
showSidebar();
|
||||
RED.sidebar.info.init();
|
||||
RED.sidebar.config.init();
|
||||
RED.sidebar.context.init();
|
||||
// hide info bar at start if screen rather narrow...
|
||||
if ($(window).width() < 600) { RED.menu.setSelected("menu-item-sidebar",false); }
|
||||
}
|
||||
|
||||
@@ -23,5 +23,6 @@ RED.state = {
|
||||
EXPORT: 6,
|
||||
IMPORT: 7,
|
||||
IMPORT_DRAGGING: 8,
|
||||
QUICK_JOINING: 9
|
||||
QUICK_JOINING: 9,
|
||||
PANNING: 10
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ RED.subflow = (function() {
|
||||
RED.view.select();
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
$("#workspace-subflow-output .spinner-value").html(subflow.out.length);
|
||||
$("#workspace-subflow-output .spinner-value").text(subflow.out.length);
|
||||
}
|
||||
|
||||
function removeSubflowOutput(removedSubflowOutputs) {
|
||||
@@ -216,7 +216,7 @@ RED.subflow = (function() {
|
||||
$("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0);
|
||||
$("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0);
|
||||
|
||||
$("#workspace-subflow-output .spinner-value").html(activeSubflow.out.length);
|
||||
$("#workspace-subflow-output .spinner-value").text(activeSubflow.out.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,8 +221,7 @@ RED.sidebar.config = (function() {
|
||||
name: RED._("sidebar.config.name"),
|
||||
content: content,
|
||||
toolbar: toolbar,
|
||||
closeable: true,
|
||||
visible: false,
|
||||
iconClass: "fa fa-cog",
|
||||
onchange: function() { refreshConfigNodeList(); }
|
||||
});
|
||||
RED.actions.add("core:show-config-tab",function() {RED.sidebar.show('config')});
|
||||
|
||||
292
editor/js/ui/tab-context.js
Normal file
292
editor/js/ui/tab-context.js
Normal file
@@ -0,0 +1,292 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.sidebar.context = (function() {
|
||||
|
||||
var content;
|
||||
var sections;
|
||||
|
||||
var localCache = {};
|
||||
|
||||
|
||||
var nodeSection;
|
||||
// var subflowSection;
|
||||
var flowSection;
|
||||
var globalSection;
|
||||
|
||||
var currentNode;
|
||||
var currentFlow;
|
||||
|
||||
function init() {
|
||||
|
||||
content = $("<div>").css({"position":"relative","height":"100%"});
|
||||
content.className = "sidebar-context"
|
||||
// var toolbar = $('<div class="sidebar-header">'+
|
||||
// '</div>').appendTo(content);
|
||||
|
||||
var footerToolbar = $('<div>'+
|
||||
// '<span class="button-group"><a class="sidebar-footer-button" href="#" data-i18n="[title]node-red:debug.sidebar.openWindow"><i class="fa fa-desktop"></i></a></span> ' +
|
||||
'</div>');
|
||||
|
||||
|
||||
|
||||
var stackContainer = $("<div>",{class:"sidebar-context-stack"}).appendTo(content);
|
||||
sections = RED.stack.create({
|
||||
container: stackContainer
|
||||
});
|
||||
|
||||
nodeSection = sections.add({
|
||||
title: RED._("sidebar.context.node"),
|
||||
collapsible: true,
|
||||
// onexpand: function() {
|
||||
// updateNode(currentNode,true);
|
||||
// }
|
||||
});
|
||||
nodeSection.expand();
|
||||
nodeSection.content.css({height:"100%"});
|
||||
nodeSection.timestamp = $('<div class="sidebar-context-updated"> </div>').appendTo(nodeSection.content);
|
||||
var table = $('<table class="node-info"></table>').appendTo(nodeSection.content);
|
||||
nodeSection.table = $('<tbody>').appendTo(table);
|
||||
var bg = $('<div style="float: right"></div>').appendTo(nodeSection.header);
|
||||
$('<button class="editor-button editor-button-small"><i class="fa fa-refresh"></i></button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
updateNode(currentNode, true);
|
||||
})
|
||||
|
||||
// subflowSection = sections.add({
|
||||
// title: "Subflow",
|
||||
// collapsible: true
|
||||
// });
|
||||
// subflowSection.expand();
|
||||
// subflowSection.content.css({height:"100%"});
|
||||
// bg = $('<div style="float: right"></div>').appendTo(subflowSection.header);
|
||||
// $('<button class="editor-button editor-button-small"><i class="fa fa-refresh"></i></button>')
|
||||
// .appendTo(bg)
|
||||
// .click(function(evt) {
|
||||
// evt.stopPropagation();
|
||||
// evt.preventDefault();
|
||||
// })
|
||||
//
|
||||
// subflowSection.container.hide();
|
||||
|
||||
flowSection = sections.add({
|
||||
title: RED._("sidebar.context.flow"),
|
||||
collapsible: true
|
||||
});
|
||||
flowSection.expand();
|
||||
flowSection.content.css({height:"100%"});
|
||||
flowSection.timestamp = $('<div class="sidebar-context-updated"> </div>').appendTo(flowSection.content);
|
||||
var table = $('<table class="node-info"></table>').appendTo(flowSection.content);
|
||||
flowSection.table = $('<tbody>').appendTo(table);
|
||||
bg = $('<div style="float: right"></div>').appendTo(flowSection.header);
|
||||
$('<button class="editor-button editor-button-small"><i class="fa fa-refresh"></i></button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
updateFlow(currentFlow);
|
||||
})
|
||||
|
||||
globalSection = sections.add({
|
||||
title: RED._("sidebar.context.global"),
|
||||
collapsible: true
|
||||
});
|
||||
globalSection.expand();
|
||||
globalSection.content.css({height:"100%"});
|
||||
globalSection.timestamp = $('<div class="sidebar-context-updated"> </div>').appendTo(globalSection.content);
|
||||
var table = $('<table class="node-info"></table>').appendTo(globalSection.content);
|
||||
globalSection.table = $('<tbody>').appendTo(table);
|
||||
|
||||
bg = $('<div style="float: right"></div>').appendTo(globalSection.header);
|
||||
$('<button class="editor-button editor-button-small"><i class="fa fa-refresh"></i></button>')
|
||||
.appendTo(bg)
|
||||
.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
updateEntry(globalSection,"context/global","global");
|
||||
})
|
||||
|
||||
|
||||
RED.actions.add("core:show-context-tab",show);
|
||||
|
||||
RED.sidebar.addTab({
|
||||
id: "context",
|
||||
label: RED._("sidebar.context.label"),
|
||||
name: RED._("sidebar.context.name"),
|
||||
iconClass: "fa fa-database",
|
||||
content: content,
|
||||
toolbar: footerToolbar,
|
||||
// pinned: true,
|
||||
enableOnEdit: false
|
||||
});
|
||||
|
||||
// var toggleLiveButton = $("#sidebar-context-toggle-live");
|
||||
// toggleLiveButton.click(function(evt) {
|
||||
// evt.preventDefault();
|
||||
// if ($(this).hasClass("selected")) {
|
||||
// $(this).removeClass("selected");
|
||||
// $(this).find("i").removeClass("fa-pause");
|
||||
// $(this).find("i").addClass("fa-play");
|
||||
// } else {
|
||||
// $(this).addClass("selected");
|
||||
// $(this).find("i").removeClass("fa-play");
|
||||
// $(this).find("i").addClass("fa-pause");
|
||||
// }
|
||||
// });
|
||||
// RED.popover.tooltip(toggleLiveButton, function() {
|
||||
// if (toggleLiveButton.hasClass("selected")) {
|
||||
// return "Pause live updates"
|
||||
// } else {
|
||||
// return "Start live updates"
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
RED.events.on("view:selection-changed", function(event) {
|
||||
var selectedNode = event.nodes && event.nodes.length === 1 && event.nodes[0];
|
||||
updateNode(selectedNode);
|
||||
})
|
||||
|
||||
RED.events.on("workspace:change", function(event) {
|
||||
updateFlow(RED.nodes.workspace(event.workspace));
|
||||
})
|
||||
|
||||
updateEntry(globalSection,"context/global","global");
|
||||
|
||||
}
|
||||
|
||||
function updateNode(node,force) {
|
||||
currentNode = node;
|
||||
if (force) {
|
||||
if (node) {
|
||||
updateEntry(nodeSection,"context/node/"+node.id,node.id);
|
||||
// if (/^subflow:/.test(node.type)) {
|
||||
// subflowSection.container.show();
|
||||
// updateEntry(subflowSection,"context/flow/"+node.id,node.id);
|
||||
// } else {
|
||||
// subflowSection.container.hide();
|
||||
// }
|
||||
} else {
|
||||
// subflowSection.container.hide();
|
||||
updateEntry(nodeSection)
|
||||
}
|
||||
} else {
|
||||
$(nodeSection.table).empty();
|
||||
if (node) {
|
||||
$('<tr class="node-info-node-row red-ui-search-empty blank" colspan="2"><td data-i18n="sidebar.context.refresh"></td></tr>').appendTo(nodeSection.table).i18n();
|
||||
} else {
|
||||
$('<tr class="node-info-node-row red-ui-search-empty blank" colspan="2"><td data-i18n="sidebar.context.none"></td></tr>').appendTo(nodeSection.table).i18n();
|
||||
}
|
||||
nodeSection.timestamp.html(" ");
|
||||
|
||||
}
|
||||
}
|
||||
function updateFlow(flow) {
|
||||
currentFlow = flow;
|
||||
if (flow) {
|
||||
updateEntry(flowSection,"context/flow/"+flow.id,flow.id);
|
||||
} else {
|
||||
updateEntry(flowSection)
|
||||
}
|
||||
}
|
||||
|
||||
function refreshEntry(section,baseUrl,id) {
|
||||
|
||||
var contextStores = RED.settings.context.stores;
|
||||
var container = section.table;
|
||||
|
||||
$.getJSON(baseUrl, function(data) {
|
||||
$(container).empty();
|
||||
var sortedData = {};
|
||||
for (var store in data) {
|
||||
if (data.hasOwnProperty(store)) {
|
||||
for (var key in data[store]) {
|
||||
if (data[store].hasOwnProperty(key)) {
|
||||
if (!sortedData.hasOwnProperty(key)) {
|
||||
sortedData[key] = [];
|
||||
}
|
||||
data[store][key].store = store;
|
||||
sortedData[key].push(data[store][key])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var keys = Object.keys(sortedData);
|
||||
keys.sort();
|
||||
var l = keys.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
sortedData[keys[i]].forEach(function(v) {
|
||||
var k = keys[i];
|
||||
var l2 = sortedData[k].length;
|
||||
var propRow = $('<tr class="node-info-node-row"><td class="sidebar-context-property"></td><td></td></tr>').appendTo(container);
|
||||
var obj = $(propRow.children()[0]);
|
||||
obj.text(k);
|
||||
var tools = $('<span class="debug-message-tools button-group"></span>').appendTo(obj);
|
||||
var refreshItem = $('<button class="editor-button editor-button-small"><i class="fa fa-refresh"></i></button>').appendTo(tools).click(function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$.getJSON(baseUrl+"/"+k+"?store="+v.store, function(data) {
|
||||
$(propRow.children()[1]).empty();
|
||||
var payload = data.msg;
|
||||
var format = data.format;
|
||||
payload = RED.utils.decodeObject(payload,format);
|
||||
RED.utils.createObjectElement(payload, {
|
||||
typeHint: data.format,
|
||||
sourceId: id+"."+k
|
||||
}).appendTo(propRow.children()[1]);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var payload = v.msg;
|
||||
var format = v.format;
|
||||
payload = RED.utils.decodeObject(payload,format);
|
||||
RED.utils.createObjectElement(payload, {
|
||||
typeHint: v.format,
|
||||
sourceId: id+"."+k
|
||||
}).appendTo(propRow.children()[1]);
|
||||
if (contextStores.length > 1) {
|
||||
$("<span>",{class:"sidebar-context-property-storename"}).text(v.store).appendTo($(propRow.children()[0]))
|
||||
}
|
||||
});
|
||||
}
|
||||
if (l === 0) {
|
||||
$('<tr class="node-info-node-row red-ui-search-empty blank" colspan="2"><td data-i18n="sidebar.context.empty"></td></tr>').appendTo(container).i18n();
|
||||
}
|
||||
$(section.timestamp).text(new Date().toLocaleString());
|
||||
});
|
||||
}
|
||||
function updateEntry(section,baseUrl,id) {
|
||||
var container = section.table;
|
||||
if (id) {
|
||||
refreshEntry(section,baseUrl,id);
|
||||
} else {
|
||||
$(container).empty();
|
||||
$('<tr class="node-info-node-row red-ui-search-empty blank" colspan="2"><td data-i18n="sidebar.context.none"></td></tr>').appendTo(container).i18n();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function show() {
|
||||
RED.sidebar.show("context");
|
||||
}
|
||||
return {
|
||||
init: init
|
||||
}
|
||||
})();
|
||||
@@ -83,7 +83,9 @@ RED.sidebar.info = (function() {
|
||||
id: "info",
|
||||
label: RED._("sidebar.info.label"),
|
||||
name: RED._("sidebar.info.name"),
|
||||
iconClass: "fa fa-info",
|
||||
content: content,
|
||||
pinned: true,
|
||||
enableOnEdit: true
|
||||
});
|
||||
if (tips.enabled()) {
|
||||
@@ -167,24 +169,42 @@ RED.sidebar.info = (function() {
|
||||
$(propRow.children()[1]).text(node.label||node.name||"");
|
||||
if (node.type === "tab") {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
$(propRow.children()[1]).html((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
|
||||
$(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
|
||||
} else if (node.type === "subflow") {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
var category = node.category||"subflows";
|
||||
$(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category}))
|
||||
}
|
||||
} else {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
|
||||
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
|
||||
|
||||
|
||||
if (node.type !== "subflow" && node.name) {
|
||||
$('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody);
|
||||
if (node.type !== "subflow" && node.type !== "unknown" && node.name) {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
$('<span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
|
||||
}
|
||||
if (!m) {
|
||||
$('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td>"+node.type+"</td></tr>").appendTo(tableBody);
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td></td></tr>").appendTo(tableBody);
|
||||
$(propRow.children()[1]).text((node.type === "unknown")?node._orig.type:node.type);
|
||||
if (node.type === "unknown") {
|
||||
$('<span style="float: right; font-size: 0.8em"><i class="fa fa-warning"></i></span>').prependTo($(propRow.children()[1]))
|
||||
}
|
||||
}
|
||||
|
||||
if (!m && node.type != "subflow" && node.type != "comment") {
|
||||
if (node._def) {
|
||||
var defaults;
|
||||
if (node.type === 'unknown') {
|
||||
defaults = {};
|
||||
Object.keys(node._orig).forEach(function(k) {
|
||||
if (k !== 'type') {
|
||||
defaults[k] = {};
|
||||
}
|
||||
})
|
||||
} else if (node._def) {
|
||||
defaults = node._def.defaults;
|
||||
}
|
||||
if (defaults) {
|
||||
var count = 0;
|
||||
var defaults = node._def.defaults;
|
||||
for (var n in defaults) {
|
||||
if (n != "name" && defaults.hasOwnProperty(n)) {
|
||||
var val = node[n];
|
||||
@@ -201,12 +221,12 @@ RED.sidebar.info = (function() {
|
||||
|
||||
var div = $('<span>',{class:""}).appendTo(container);
|
||||
var nodeDiv = $('<div>',{class:"palette_node palette_node_small"}).appendTo(div);
|
||||
var colour = configNode._def.color;
|
||||
var colour = RED.utils.getNodeColor(configNode.type,configNode._def);
|
||||
var icon_url = RED.utils.getNodeIcon(configNode._def);
|
||||
nodeDiv.css({'backgroundColor':colour, "cursor":"pointer"});
|
||||
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
|
||||
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
|
||||
var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).html(configLabel).appendTo(container);
|
||||
var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).text(configLabel).appendTo(container);
|
||||
|
||||
nodeDiv.on('dblclick',function() {
|
||||
RED.editor.editConfig("", configNode.type, configNode.id);
|
||||
@@ -231,24 +251,27 @@ RED.sidebar.info = (function() {
|
||||
}
|
||||
}
|
||||
if (m) {
|
||||
propRow = $('<tr class="node-info-node-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
var category = subflowNode.category||"subflows";
|
||||
$(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category}))
|
||||
$('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+subflowUserCount+'</td></tr>').appendTo(tableBody);
|
||||
}
|
||||
|
||||
var infoText = "";
|
||||
if (!subflowNode && node.type !== "comment" && node.type !== "tab") {
|
||||
infoSection.title.html(RED._("sidebar.info.nodeHelp"));
|
||||
infoSection.title.text(RED._("sidebar.info.nodeHelp"));
|
||||
var helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>');
|
||||
infoText = helpText;
|
||||
} else if (node.type === "tab") {
|
||||
infoSection.title.html(RED._("sidebar.info.flowDesc"));
|
||||
infoSection.title.text(RED._("sidebar.info.flowDesc"));
|
||||
infoText = marked(node.info||"")||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>');
|
||||
}
|
||||
|
||||
if (subflowNode) {
|
||||
infoText = infoText + (marked(subflowNode.info||"")||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>'));
|
||||
infoSection.title.html(RED._("sidebar.info.subflowDesc"));
|
||||
infoSection.title.text(RED._("sidebar.info.subflowDesc"));
|
||||
} else if (node._def && node._def.info) {
|
||||
infoSection.title.html(RED._("sidebar.info.nodeHelp"));
|
||||
infoSection.title.text(RED._("sidebar.info.nodeHelp"));
|
||||
var info = node._def.info;
|
||||
var textInfo = (typeof info === "function" ? info.call(node) : info);
|
||||
// TODO: help
|
||||
@@ -257,8 +280,7 @@ RED.sidebar.info = (function() {
|
||||
if (infoText) {
|
||||
setInfoText(infoText);
|
||||
}
|
||||
|
||||
|
||||
$(".sidebar-node-info-stack").scrollTop(0);
|
||||
$(".node-info-property-header").click(function(e) {
|
||||
e.preventDefault();
|
||||
expandedSections["property"] = !expandedSections["property"];
|
||||
@@ -372,10 +394,9 @@ RED.sidebar.info = (function() {
|
||||
function set(html,title) {
|
||||
// tips.stop();
|
||||
// sections.show();
|
||||
// nodeSection.container.hide();
|
||||
infoSection.title.text(title||"");
|
||||
refresh(null);
|
||||
$(infoSection.content).empty();
|
||||
nodeSection.container.hide();
|
||||
infoSection.title.text(title||RED._("sidebar.info.info"));
|
||||
setInfoText(html);
|
||||
$(".sidebar-node-info-stack").scrollTop(0);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ RED.tray = (function() {
|
||||
b.attr('id',button.id);
|
||||
}
|
||||
if (button.text) {
|
||||
b.html(button.text);
|
||||
b.text(button.text);
|
||||
}
|
||||
if (button.click) {
|
||||
b.click((function(action) {
|
||||
|
||||
@@ -128,7 +128,7 @@ RED.typeSearch = (function() {
|
||||
var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
|
||||
|
||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
|
||||
var colour = def.color;
|
||||
var colour = RED.utils.getNodeColor(object.type,def);
|
||||
var icon_url = RED.utils.getNodeIcon(def);
|
||||
nodeDiv.css('backgroundColor',colour);
|
||||
|
||||
@@ -147,7 +147,7 @@ RED.typeSearch = (function() {
|
||||
var label = object.label;
|
||||
object.index += "|"+label.toLowerCase();
|
||||
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).html(label).appendTo(contentDiv);
|
||||
$('<div>',{class:"red-ui-search-result-node-label"}).text(label).appendTo(contentDiv);
|
||||
|
||||
div.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -26,14 +26,18 @@ RED.utils = (function() {
|
||||
function buildMessageSummaryValue(value) {
|
||||
var result;
|
||||
if (Array.isArray(value)) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('array['+value.length+']');
|
||||
} else if (value === null) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-null">null</span>');
|
||||
} else if (typeof value === 'object') {
|
||||
if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.length+']');
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('buffer['+value.length+']');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('array['+value.length+']');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'function') {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('function');
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'number') {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-number"></span>').text(value.data);
|
||||
} else {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-meta">object</span>');
|
||||
}
|
||||
@@ -45,6 +49,8 @@ RED.utils = (function() {
|
||||
subvalue = sanitize(value);
|
||||
}
|
||||
result = $('<span class="debug-message-object-value debug-message-type-string"></span>').html('"'+formatString(subvalue)+'"');
|
||||
} else if (typeof value === 'number') {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-number"></span>').text(""+value);
|
||||
} else {
|
||||
result = $('<span class="debug-message-object-value debug-message-type-other"></span>').text(""+value);
|
||||
}
|
||||
@@ -125,7 +131,7 @@ RED.utils = (function() {
|
||||
e.stopPropagation();
|
||||
RED.clipboard.copyText(msg,copyPayload,"clipboard.copyMessageValue");
|
||||
})
|
||||
if (strippedKey !== '') {
|
||||
if (strippedKey !== undefined && strippedKey !== '') {
|
||||
var isPinned = pinnedPaths[sourceId].hasOwnProperty(strippedKey);
|
||||
|
||||
var pinPath = $('<button class="editor-button editor-button-small debug-message-tools-pin"><i class="fa fa-map-pin"></i></button>').appendTo(tools).click(function(e) {
|
||||
@@ -292,19 +298,24 @@ RED.utils = (function() {
|
||||
|
||||
var isArray = Array.isArray(obj);
|
||||
var isArrayObject = false;
|
||||
if (obj && typeof obj === 'object' && obj.hasOwnProperty('type') && obj.hasOwnProperty('data') && ((obj.__encoded__ && obj.type === 'array') || obj.type === 'Buffer')) {
|
||||
if (obj && typeof obj === 'object' && obj.hasOwnProperty('type') && obj.hasOwnProperty('data') && ((obj.__enc__ && obj.type === 'array') || obj.type === 'Buffer')) {
|
||||
isArray = true;
|
||||
isArrayObject = true;
|
||||
}
|
||||
|
||||
if (obj === null || obj === undefined) {
|
||||
$('<span class="debug-message-type-null">'+obj+'</span>').appendTo(entryObj);
|
||||
} else if (obj.__enc__ && obj.type === 'number') {
|
||||
e = $('<span class="debug-message-type-number debug-message-object-header"></span>').text(obj.data).appendTo(entryObj);
|
||||
} else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) {
|
||||
e = $('<span class="debug-message-type-meta debug-message-object-header"></span>').text("function").appendTo(entryObj);
|
||||
} else if (typeHint === "internal" || (obj.__enc__ && obj.type === 'internal')) {
|
||||
e = $('<span class="debug-message-type-meta debug-message-object-header"></span>').text("[internal]").appendTo(entryObj);
|
||||
} else if (typeof obj === 'string') {
|
||||
if (/[\t\n\r]/.test(obj)) {
|
||||
element.addClass('collapsed');
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
|
||||
makeExpandable(header, function() {
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header);
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text(typeHint||'string').appendTo(header);
|
||||
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
|
||||
$('<pre class="debug-message-type-string"></pre>').text(obj).appendTo(row);
|
||||
},function(state) {if (ontoggle) { ontoggle(path,state);}}, checkExpanded(strippedKey,expandPaths));
|
||||
@@ -343,7 +354,7 @@ RED.utils = (function() {
|
||||
if (originalLength === undefined) {
|
||||
originalLength = data.length;
|
||||
}
|
||||
if (data.__encoded__) {
|
||||
if (data.__enc__) {
|
||||
data = data.data;
|
||||
}
|
||||
type = obj.type.toLowerCase();
|
||||
@@ -358,7 +369,7 @@ RED.utils = (function() {
|
||||
element.addClass('debug-message-buffer-raw');
|
||||
}
|
||||
if (key) {
|
||||
headerHead = $('<span class="debug-message-type-meta"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
|
||||
headerHead = $('<span class="debug-message-type-meta"></span>').text(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
|
||||
} else {
|
||||
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
|
||||
$('<span>[ </span>').appendTo(headerHead);
|
||||
@@ -381,7 +392,7 @@ RED.utils = (function() {
|
||||
|
||||
makeExpandable(header,function() {
|
||||
if (!key) {
|
||||
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(header);
|
||||
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text(typeHint||(type+'['+originalLength+']')).appendTo(header);
|
||||
}
|
||||
if (type === 'buffer') {
|
||||
var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element);
|
||||
@@ -394,7 +405,7 @@ RED.utils = (function() {
|
||||
}
|
||||
$('<pre class="debug-message-type-string"></pre>').text(stringEncoding).appendTo(sr);
|
||||
var bufferOpts = $('<span class="debug-message-buffer-opts"></span>').appendTo(headerHead);
|
||||
var switchFormat = $('<a href="#"></a>').addClass('selected').html('raw').appendTo(bufferOpts).click(function(e) {
|
||||
var switchFormat = $('<a href="#"></a>').addClass('selected').text('raw').appendTo(bufferOpts).click(function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
formatBuffer(element,$(this),sourceId,path,true);
|
||||
@@ -471,7 +482,7 @@ RED.utils = (function() {
|
||||
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
|
||||
makeExpandable(header, function() {
|
||||
if (!key) {
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html('object').appendTo(header);
|
||||
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text('object').appendTo(header);
|
||||
}
|
||||
for (i=0;i<keys.length;i++) {
|
||||
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
|
||||
@@ -507,7 +518,7 @@ RED.utils = (function() {
|
||||
checkExpanded(strippedKey,expandPaths));
|
||||
}
|
||||
if (key) {
|
||||
$('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj);
|
||||
$('<span class="debug-message-type-meta"></span>').text('object').appendTo(entryObj);
|
||||
} else {
|
||||
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
|
||||
$('<span>{ </span>').appendTo(headerHead);
|
||||
@@ -708,7 +719,9 @@ RED.utils = (function() {
|
||||
|
||||
function getDefaultNodeIcon(def,node) {
|
||||
var icon_url;
|
||||
if (typeof def.icon === "function") {
|
||||
if (node && node.type === "subflow") {
|
||||
icon_url = "node-red/subflow.png";
|
||||
} else if (typeof def.icon === "function") {
|
||||
try {
|
||||
icon_url = def.icon.call(node);
|
||||
} catch(err) {
|
||||
@@ -721,11 +734,26 @@ RED.utils = (function() {
|
||||
|
||||
var iconPath = separateIconPath(icon_url);
|
||||
if (!iconPath.module) {
|
||||
iconPath.module = def.set.module;
|
||||
if (def.set) {
|
||||
iconPath.module = def.set.module;
|
||||
} else {
|
||||
// Handle subflow instance nodes that don't have def.set
|
||||
iconPath.module = "node-red";
|
||||
}
|
||||
}
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
function isIconExists(iconPath) {
|
||||
var iconSets = RED.nodes.getIconSets();
|
||||
var iconFileList = iconSets[iconPath.module];
|
||||
if (iconFileList && iconFileList.indexOf(iconPath.file) !== -1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getNodeIcon(def,node) {
|
||||
if (def.category === 'config') {
|
||||
return "icons/node-red/cog.png"
|
||||
@@ -733,18 +761,19 @@ RED.utils = (function() {
|
||||
return "icons/node-red/subflow.png"
|
||||
} else if (node && node.type === 'unknown') {
|
||||
return "icons/node-red/alert.png"
|
||||
} else if (node && node.type === 'subflow') {
|
||||
return "icons/node-red/subflow.png"
|
||||
} else if (node && node.icon) {
|
||||
var iconPath = separateIconPath(node.icon);
|
||||
var iconSets = RED.nodes.getIconSets();
|
||||
var iconFileList = iconSets[iconPath.module];
|
||||
if (iconFileList && iconFileList.indexOf(iconPath.file) !== -1) {
|
||||
if (isIconExists(iconPath)) {
|
||||
return "icons/" + node.icon;
|
||||
}
|
||||
}
|
||||
|
||||
var iconPath = getDefaultNodeIcon(def, node);
|
||||
if (def.category === 'subflows') {
|
||||
if (!isIconExists(iconPath)) {
|
||||
return "icons/node-red/subflow.png";
|
||||
}
|
||||
}
|
||||
return "icons/"+iconPath.module+"/"+iconPath.file;
|
||||
}
|
||||
|
||||
@@ -765,6 +794,40 @@ RED.utils = (function() {
|
||||
return RED.text.bidi.enforceTextDirectionWithUCC(l);
|
||||
}
|
||||
|
||||
var nodeColorCache = {};
|
||||
function getNodeColor(type, def) {
|
||||
var result = def.color;
|
||||
var paletteTheme = RED.settings.theme('palette.theme') || [];
|
||||
if (paletteTheme.length > 0) {
|
||||
if (!nodeColorCache.hasOwnProperty(type)) {
|
||||
var l = paletteTheme.length;
|
||||
for (var i=0;i<l;i++ ){
|
||||
var themeRule = paletteTheme[i];
|
||||
if (themeRule.hasOwnProperty('category')) {
|
||||
if (!themeRule.hasOwnProperty('_category')) {
|
||||
themeRule._category = new RegExp(themeRule.category);
|
||||
}
|
||||
if (!themeRule._category.test(def.category)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (themeRule.hasOwnProperty('type')) {
|
||||
if (!themeRule.hasOwnProperty('_type')) {
|
||||
themeRule._type = new RegExp(themeRule.type);
|
||||
}
|
||||
if (!themeRule._type.test(type)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodeColorCache[type] = themeRule.color || def.color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = nodeColorCache[type];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function addSpinnerOverlay(container,contain) {
|
||||
var spinner = $('<div class="projects-dialog-spinner "><img src="red/images/spin.svg"/></div>').appendTo(container);
|
||||
if (contain) {
|
||||
@@ -773,6 +836,47 @@ RED.utils = (function() {
|
||||
return spinner;
|
||||
}
|
||||
|
||||
function decodeObject(payload,format) {
|
||||
if ((format === 'number') && (payload === "NaN")) {
|
||||
payload = Number.NaN;
|
||||
} else if ((format === 'number') && (payload === "Infinity")) {
|
||||
payload = Infinity;
|
||||
} else if ((format === 'number') && (payload === "-Infinity")) {
|
||||
payload = -Infinity;
|
||||
} else if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number' ) {
|
||||
payload = JSON.parse(payload);
|
||||
} else if (/error/i.test(format)) {
|
||||
payload = JSON.parse(payload);
|
||||
payload = (payload.name?payload.name+": ":"")+payload.message;
|
||||
} else if (format === 'null') {
|
||||
payload = null;
|
||||
} else if (format === 'undefined') {
|
||||
payload = undefined;
|
||||
} else if (/^buffer/.test(format)) {
|
||||
var buffer = payload;
|
||||
payload = [];
|
||||
for (var c = 0; c < buffer.length; c += 2) {
|
||||
payload.push(parseInt(buffer.substr(c, 2), 16));
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
function parseContextKey(key) {
|
||||
var parts = {};
|
||||
var m = /^#:\((\S+?)\)::(.*)$/.exec(key);
|
||||
if (m) {
|
||||
parts.store = m[1];
|
||||
parts.key = m[2];
|
||||
} else {
|
||||
parts.key = key;
|
||||
if (RED.settings.context) {
|
||||
parts.store = RED.settings.context.default;
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
return {
|
||||
createObjectElement: buildMessageElement,
|
||||
getMessageProperty: getMessageProperty,
|
||||
@@ -782,6 +886,9 @@ RED.utils = (function() {
|
||||
getDefaultNodeIcon: getDefaultNodeIcon,
|
||||
getNodeIcon: getNodeIcon,
|
||||
getNodeLabel: getNodeLabel,
|
||||
addSpinnerOverlay: addSpinnerOverlay
|
||||
getNodeColor: getNodeColor,
|
||||
addSpinnerOverlay: addSpinnerOverlay,
|
||||
decodeObject: decodeObject,
|
||||
parseContextKey: parseContextKey
|
||||
}
|
||||
})();
|
||||
|
||||
168
editor/js/ui/view-navigator.js
Normal file
168
editor/js/ui/view-navigator.js
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
RED.view.navigator = (function() {
|
||||
|
||||
var nav_scale = 25;
|
||||
var nav_width = 5000/nav_scale;
|
||||
var nav_height = 5000/nav_scale;
|
||||
|
||||
var navContainer;
|
||||
var navBox;
|
||||
var navBorder;
|
||||
var navVis;
|
||||
var scrollPos;
|
||||
var scaleFactor;
|
||||
var chartSize;
|
||||
var dimensions;
|
||||
var isDragging;
|
||||
var isShowing = false;
|
||||
|
||||
function refreshNodes() {
|
||||
if (!isShowing) {
|
||||
return;
|
||||
}
|
||||
var navNode = navVis.selectAll(".navnode").data(RED.view.getActiveNodes(),function(d){return d.id});
|
||||
navNode.exit().remove();
|
||||
navNode.enter().insert("rect")
|
||||
.attr('class','navnode')
|
||||
.attr("pointer-events", "none");
|
||||
navNode.each(function(d) {
|
||||
d3.select(this).attr("x",function(d) { return (d.x-d.w/2)/nav_scale })
|
||||
.attr("y",function(d) { return (d.y-d.h/2)/nav_scale })
|
||||
.attr("width",function(d) { return Math.max(9,d.w/nav_scale) })
|
||||
.attr("height",function(d) { return Math.max(3,d.h/nav_scale) })
|
||||
.attr("fill",function(d) { return RED.utils.getNodeColor(d.type,d._def);})
|
||||
});
|
||||
}
|
||||
function onScroll() {
|
||||
if (!isDragging) {
|
||||
resizeNavBorder();
|
||||
}
|
||||
}
|
||||
function resizeNavBorder() {
|
||||
if (navBorder) {
|
||||
scaleFactor = RED.view.scale();
|
||||
chartSize = [ $("#chart").width(), $("#chart").height()];
|
||||
scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
|
||||
navBorder.attr('x',scrollPos[0]/nav_scale)
|
||||
.attr('y',scrollPos[1]/nav_scale)
|
||||
.attr('width',chartSize[0]/nav_scale/scaleFactor)
|
||||
.attr('height',chartSize[1]/nav_scale/scaleFactor)
|
||||
}
|
||||
}
|
||||
function toggle() {
|
||||
if (!isShowing) {
|
||||
isShowing = true;
|
||||
$("#btn-navigate").addClass("selected");
|
||||
resizeNavBorder();
|
||||
refreshNodes();
|
||||
$("#chart").on("scroll",onScroll);
|
||||
navContainer.fadeIn(200);
|
||||
} else {
|
||||
isShowing = false;
|
||||
navContainer.fadeOut(100);
|
||||
$("#chart").off("scroll",onScroll);
|
||||
$("#btn-navigate").removeClass("selected");
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
|
||||
$(window).resize(resizeNavBorder);
|
||||
RED.events.on("sidebar:resize",resizeNavBorder);
|
||||
RED.actions.add("core:toggle-navigator",toggle);
|
||||
var hideTimeout;
|
||||
|
||||
navContainer = $('<div>').css({
|
||||
"position":"absolute",
|
||||
"bottom":$("#workspace-footer").height(),
|
||||
"right":0,
|
||||
zIndex: 1
|
||||
}).appendTo("#workspace").hide();
|
||||
|
||||
navBox = d3.select(navContainer[0])
|
||||
.append("svg:svg")
|
||||
.attr("width", nav_width)
|
||||
.attr("height", nav_height)
|
||||
.attr("pointer-events", "all")
|
||||
.style({
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
right:0,
|
||||
zIndex: 101,
|
||||
"border-left": "1px solid #ccc",
|
||||
"border-top": "1px solid #ccc",
|
||||
background: "rgba(245,245,245,0.5)",
|
||||
"box-shadow": "-1px 0 3px rgba(0,0,0,0.1)"
|
||||
});
|
||||
|
||||
navBox.append("rect").attr("x",0).attr("y",0).attr("width",nav_width).attr("height",nav_height).style({
|
||||
fill:"none",
|
||||
stroke:"none",
|
||||
pointerEvents:"all"
|
||||
}).on("mousedown", function() {
|
||||
// Update these in case they have changed
|
||||
scaleFactor = RED.view.scale();
|
||||
chartSize = [ $("#chart").width(), $("#chart").height()];
|
||||
dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor];
|
||||
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||
navBorder.attr('x',newX).attr('y',newY);
|
||||
isDragging = true;
|
||||
$("#chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||
$("#chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||
}).on("mousemove", function() {
|
||||
if (!isDragging) { return }
|
||||
if (d3.event.buttons === 0) {
|
||||
isDragging = false;
|
||||
return;
|
||||
}
|
||||
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||
navBorder.attr('x',newX).attr('y',newY);
|
||||
$("#chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||
$("#chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||
}).on("mouseup", function() {
|
||||
isDragging = false;
|
||||
})
|
||||
|
||||
navBorder = navBox.append("rect")
|
||||
.attr("stroke-dasharray","5,5")
|
||||
.attr("pointer-events", "none")
|
||||
.style({
|
||||
stroke: "#999",
|
||||
strokeWidth: 1,
|
||||
fill: "white",
|
||||
});
|
||||
|
||||
navVis = navBox.append("svg:g")
|
||||
|
||||
|
||||
$("#btn-navigate").click(function(evt) {
|
||||
evt.preventDefault();
|
||||
toggle();
|
||||
})
|
||||
},
|
||||
refresh: refreshNodes,
|
||||
resize: resizeNavBorder,
|
||||
toggle: toggle
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
@@ -58,7 +58,10 @@ RED.view = (function() {
|
||||
lastClickNode = null,
|
||||
dblClickPrimed = null,
|
||||
clickTime = 0,
|
||||
clickElapsed = 0;
|
||||
clickElapsed = 0,
|
||||
scroll_position = [],
|
||||
quickAddActive = false,
|
||||
quickAddLink = null;
|
||||
|
||||
var clipboard = "";
|
||||
|
||||
@@ -73,6 +76,8 @@ RED.view = (function() {
|
||||
var PORT_TYPE_INPUT = 1;
|
||||
var PORT_TYPE_OUTPUT = 0;
|
||||
|
||||
var chart = $("#chart");
|
||||
|
||||
var outer = d3.select("#chart")
|
||||
.append("svg:svg")
|
||||
.attr("width", space_width)
|
||||
@@ -94,6 +99,16 @@ RED.view = (function() {
|
||||
.on("mousemove", canvasMouseMove)
|
||||
.on("mousedown", canvasMouseDown)
|
||||
.on("mouseup", canvasMouseUp)
|
||||
.on("mouseenter", function() {
|
||||
if (lasso) {
|
||||
if (d3.event.buttons !== 1) {
|
||||
lasso.remove();
|
||||
lasso = null;
|
||||
}
|
||||
} else if (mouse_mode === RED.state.PANNING && d3.event.buttons !== 4) {
|
||||
resetMouseVars();
|
||||
}
|
||||
})
|
||||
.on("touchend", function() {
|
||||
clearTimeout(touchStartTime);
|
||||
touchStartTime = null;
|
||||
@@ -283,7 +298,6 @@ RED.view = (function() {
|
||||
function init() {
|
||||
|
||||
RED.events.on("workspace:change",function(event) {
|
||||
var chart = $("#chart");
|
||||
if (event.old !== 0) {
|
||||
workspaceScrollPositions[event.old] = {
|
||||
left:chart.scrollLeft(),
|
||||
@@ -320,6 +334,8 @@ RED.view = (function() {
|
||||
redraw();
|
||||
});
|
||||
|
||||
RED.view.navigator.init();
|
||||
|
||||
$("#btn-zoom-out").click(function() {zoomOut();});
|
||||
$("#btn-zoom-zero").click(function() {zoomZero();});
|
||||
$("#btn-zoom-in").click(function() {zoomIn();});
|
||||
@@ -448,6 +464,82 @@ RED.view = (function() {
|
||||
RED.actions.add("core:step-selection-left", function() { moveSelection(-20,0);});
|
||||
}
|
||||
|
||||
function generateLinkPath(origX,origY, destX, destY, sc) {
|
||||
var dy = destY-origY;
|
||||
var dx = destX-origX;
|
||||
var delta = Math.sqrt(dy*dy+dx*dx);
|
||||
var scale = lineCurveScale;
|
||||
var scaleY = 0;
|
||||
if (dx*sc > 0) {
|
||||
if (delta < node_width) {
|
||||
scale = 0.75-0.75*((node_width-delta)/node_width);
|
||||
// scale += 2*(Math.min(5*node_width,Math.abs(dx))/(5*node_width));
|
||||
// if (Math.abs(dy) < 3*node_height) {
|
||||
// scaleY = ((dy>0)?0.5:-0.5)*(((3*node_height)-Math.abs(dy))/(3*node_height))*(Math.min(node_width,Math.abs(dx))/(node_width)) ;
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
scale = 0.4-0.2*(Math.max(0,(node_width-Math.min(Math.abs(dx),Math.abs(dy)))/node_width));
|
||||
}
|
||||
if (dx*sc > 0) {
|
||||
return "M "+origX+" "+origY+
|
||||
" C "+(origX+sc*(node_width*scale))+" "+(origY+scaleY*node_height)+" "+
|
||||
(destX-sc*(scale)*node_width)+" "+(destY-scaleY*node_height)+" "+
|
||||
destX+" "+destY
|
||||
} else {
|
||||
|
||||
var midX = Math.floor(destX-dx/2);
|
||||
var midY = Math.floor(destY-dy/2);
|
||||
//
|
||||
if (dy === 0) {
|
||||
midY = destY + node_height;
|
||||
}
|
||||
var cp_height = node_height/2;
|
||||
var y1 = (destY + midY)/2
|
||||
var topX =origX + sc*node_width*scale;
|
||||
var topY = dy>0?Math.min(y1 - dy/2 , origY+cp_height):Math.max(y1 - dy/2 , origY-cp_height);
|
||||
var bottomX = destX - sc*node_width*scale;
|
||||
var bottomY = dy>0?Math.max(y1, destY-cp_height):Math.min(y1, destY+cp_height);
|
||||
var x1 = (origX+topX)/2;
|
||||
var scy = dy>0?1:-1;
|
||||
var cp = [
|
||||
// Orig -> Top
|
||||
[x1,origY],
|
||||
[topX,dy>0?Math.max(origY, topY-cp_height):Math.min(origY, topY+cp_height)],
|
||||
// Top -> Mid
|
||||
// [Mirror previous cp]
|
||||
[x1,dy>0?Math.min(midY, topY+cp_height):Math.max(midY, topY-cp_height)],
|
||||
// Mid -> Bottom
|
||||
// [Mirror previous cp]
|
||||
[bottomX,dy>0?Math.max(midY, bottomY-cp_height):Math.min(midY, bottomY+cp_height)],
|
||||
// Bottom -> Dest
|
||||
// [Mirror previous cp]
|
||||
[(destX+bottomX)/2,destY]
|
||||
];
|
||||
if (cp[2][1] === topY+scy*cp_height) {
|
||||
if (Math.abs(dy) < cp_height*10) {
|
||||
cp[1][1] = topY-scy*cp_height/2;
|
||||
cp[3][1] = bottomY-scy*cp_height/2;
|
||||
}
|
||||
cp[2][0] = topX;
|
||||
}
|
||||
return "M "+origX+" "+origY+
|
||||
" C "+
|
||||
cp[0][0]+" "+cp[0][1]+" "+
|
||||
cp[1][0]+" "+cp[1][1]+" "+
|
||||
topX+" "+topY+
|
||||
" S "+
|
||||
cp[2][0]+" "+cp[2][1]+" "+
|
||||
midX+" "+midY+
|
||||
" S "+
|
||||
cp[3][0]+" "+cp[3][1]+" "+
|
||||
bottomX+" "+bottomY+
|
||||
" S "+
|
||||
cp[4][0]+" "+cp[4][1]+" "+
|
||||
destX+" "+destY
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addNode(type,x,y) {
|
||||
var m = /^subflow:(.+)$/.exec(type);
|
||||
@@ -490,6 +582,7 @@ RED.view = (function() {
|
||||
}
|
||||
} else {
|
||||
var subflow = RED.nodes.subflow(m[1]);
|
||||
nn.name = "";
|
||||
nn.inputs = subflow.in.length;
|
||||
nn.outputs = subflow.out.length;
|
||||
}
|
||||
@@ -525,6 +618,15 @@ RED.view = (function() {
|
||||
function canvasMouseDown() {
|
||||
var point;
|
||||
|
||||
if (d3.event.button === 1) {
|
||||
// Middle Click pan
|
||||
mouse_mode = RED.state.PANNING;
|
||||
mouse_position = [d3.event.pageX,d3.event.pageY]
|
||||
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mousedown_node && !mousedown_link) {
|
||||
selected_link = null;
|
||||
updateSelection();
|
||||
@@ -545,14 +647,16 @@ RED.view = (function() {
|
||||
mouse_mode = RED.state.QUICK_JOINING;
|
||||
$(window).on('keyup',disableQuickJoinEventHandler);
|
||||
}
|
||||
|
||||
quickAddActive = true;
|
||||
RED.typeSearch.show({
|
||||
x:d3.event.clientX-mainPos.left-node_width/2,
|
||||
y:d3.event.clientY-mainPos.top-node_height/2,
|
||||
cancel: function() {
|
||||
quickAddActive = false;
|
||||
resetMouseVars();
|
||||
},
|
||||
add: function(type) {
|
||||
quickAddActive = false;
|
||||
var result = addNode(type);
|
||||
if (!result) {
|
||||
return;
|
||||
@@ -561,11 +665,10 @@ RED.view = (function() {
|
||||
var historyEvent = result.historyEvent;
|
||||
nn.x = point[0];
|
||||
nn.y = point[1];
|
||||
if (mouse_mode === RED.state.QUICK_JOINING) {
|
||||
if (drag_lines.length > 0) {
|
||||
var drag_line = drag_lines[0];
|
||||
if (mouse_mode === RED.state.QUICK_JOINING || quickAddLink) {
|
||||
if (quickAddLink || drag_lines.length > 0) {
|
||||
var drag_line = quickAddLink||drag_lines[0];
|
||||
var src = null,dst,src_port;
|
||||
|
||||
if (drag_line.portType === PORT_TYPE_OUTPUT && nn.inputs > 0) {
|
||||
src = drag_line.node;
|
||||
src_port = drag_line.port;
|
||||
@@ -580,9 +683,9 @@ RED.view = (function() {
|
||||
RED.nodes.addLink(link);
|
||||
historyEvent.links = [link];
|
||||
hideDragLines();
|
||||
if (drag_line.portType === PORT_TYPE_OUTPUT && nn.outputs > 0) {
|
||||
if (!quickAddLink && drag_line.portType === PORT_TYPE_OUTPUT && nn.outputs > 0) {
|
||||
showDragLines([{node:nn,port:0,portType:PORT_TYPE_OUTPUT}]);
|
||||
} else if (drag_line.portType === PORT_TYPE_INPUT && nn.inputs > 0) {
|
||||
} else if (!quickAddLink && drag_line.portType === PORT_TYPE_INPUT && nn.inputs > 0) {
|
||||
showDragLines([{node:nn,port:0,portType:PORT_TYPE_INPUT}]);
|
||||
} else {
|
||||
resetMouseVars();
|
||||
@@ -600,9 +703,9 @@ RED.view = (function() {
|
||||
resetMouseVars();
|
||||
}
|
||||
}
|
||||
quickAddLink = null;
|
||||
}
|
||||
|
||||
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.add(nn);
|
||||
RED.editor.validateNode(nn);
|
||||
@@ -643,7 +746,6 @@ RED.view = (function() {
|
||||
function canvasMouseMove() {
|
||||
var i;
|
||||
var node;
|
||||
mouse_position = d3.touches(this)[0]||d3.mouse(this);
|
||||
// Prevent touch scrolling...
|
||||
//if (d3.touches(this)[0]) {
|
||||
// d3.event.preventDefault();
|
||||
@@ -654,6 +756,22 @@ RED.view = (function() {
|
||||
//if (point[0]-container.scrollLeft < 30 && container.scrollLeft > 0) { container.scrollLeft -= 15; }
|
||||
//console.log(d3.mouse(this),container.offsetWidth,container.offsetHeight,container.scrollLeft,container.scrollTop);
|
||||
|
||||
if (mouse_mode === RED.state.PANNING) {
|
||||
|
||||
var pos = [d3.event.pageX,d3.event.pageY];
|
||||
var deltaPos = [
|
||||
mouse_position[0]-pos[0],
|
||||
mouse_position[1]-pos[1]
|
||||
];
|
||||
|
||||
chart.scrollLeft(scroll_position[0]+deltaPos[0])
|
||||
chart.scrollTop(scroll_position[1]+deltaPos[1])
|
||||
return
|
||||
}
|
||||
|
||||
mouse_position = d3.touches(this)[0]||d3.mouse(this);
|
||||
|
||||
|
||||
if (lasso) {
|
||||
var ox = parseInt(lasso.attr("ox"));
|
||||
var oy = parseInt(lasso.attr("oy"));
|
||||
@@ -752,28 +870,7 @@ RED.view = (function() {
|
||||
|
||||
var sc = (drag_line.portType === PORT_TYPE_OUTPUT)?1:-1;
|
||||
|
||||
var dy = mousePos[1]-(drag_line.node.y+portY);
|
||||
var dx = mousePos[0]-(drag_line.node.x+sc*drag_line.node.w/2);
|
||||
var delta = Math.sqrt(dy*dy+dx*dx);
|
||||
var scale = lineCurveScale;
|
||||
var scaleY = 0;
|
||||
|
||||
if (delta < node_width) {
|
||||
scale = 0.75-0.75*((node_width-delta)/node_width);
|
||||
}
|
||||
if (dx*sc < 0) {
|
||||
scale += 2*(Math.min(5*node_width,Math.abs(dx))/(5*node_width));
|
||||
if (Math.abs(dy) < 3*node_height) {
|
||||
scaleY = ((dy>0)?0.5:-0.5)*(((3*node_height)-Math.abs(dy))/(3*node_height))*(Math.min(node_width,Math.abs(dx))/(node_width)) ;
|
||||
}
|
||||
}
|
||||
|
||||
drag_line.el.attr("d",
|
||||
"M "+(drag_line.node.x+sc*drag_line.node.w/2)+" "+(drag_line.node.y+portY)+
|
||||
" C "+(drag_line.node.x+sc*(drag_line.node.w/2+node_width*scale))+" "+(drag_line.node.y+portY+scaleY*node_height)+" "+
|
||||
(mousePos[0]-sc*(scale)*node_width)+" "+(mousePos[1]-scaleY*node_height)+" "+
|
||||
mousePos[0]+" "+mousePos[1]
|
||||
);
|
||||
drag_line.el.attr("d",generateLinkPath(drag_line.node.x+sc*drag_line.node.w/2,drag_line.node.y+portY,mousePos[0],mousePos[1],sc));
|
||||
}
|
||||
d3.event.preventDefault();
|
||||
} else if (mouse_mode == RED.state.MOVING) {
|
||||
@@ -905,6 +1002,10 @@ RED.view = (function() {
|
||||
function canvasMouseUp() {
|
||||
var i;
|
||||
var historyEvent;
|
||||
if (mouse_mode === RED.state.PANNING) {
|
||||
resetMouseVars();
|
||||
return
|
||||
}
|
||||
if (mouse_mode === RED.state.QUICK_JOINING) {
|
||||
return;
|
||||
}
|
||||
@@ -1019,17 +1120,20 @@ RED.view = (function() {
|
||||
function zoomIn() {
|
||||
if (scaleFactor < 2) {
|
||||
scaleFactor += 0.1;
|
||||
RED.view.navigator.resize();
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
function zoomOut() {
|
||||
if (scaleFactor > 0.3) {
|
||||
scaleFactor -= 0.1;
|
||||
RED.view.navigator.resize();
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
function zoomZero() {
|
||||
scaleFactor = 1;
|
||||
RED.view.navigator.resize();
|
||||
redraw();
|
||||
}
|
||||
|
||||
@@ -1366,6 +1470,9 @@ RED.view = (function() {
|
||||
function disableQuickJoinEventHandler(evt) {
|
||||
// Check for ctrl (all browsers), "Meta" (Chrome/FF), keyCode 91 (Safari)
|
||||
if (evt.keyCode === 17 || evt.key === "Meta" || evt.keyCode === 91) {
|
||||
if (quickAddActive && drag_lines.length > 0) {
|
||||
quickAddLink = drag_lines[0];
|
||||
}
|
||||
resetMouseVars();
|
||||
hideDragLines();
|
||||
redraw();
|
||||
@@ -1377,6 +1484,10 @@ RED.view = (function() {
|
||||
//console.log(d,portType,portIndex);
|
||||
// disable zoom
|
||||
//vis.call(d3.behavior.zoom().on("zoom"), null);
|
||||
if (d3.event.button === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
mousedown_node = d;
|
||||
mousedown_port_type = portType;
|
||||
mousedown_port_index = portIndex || 0;
|
||||
@@ -1608,6 +1719,9 @@ RED.view = (function() {
|
||||
|
||||
function nodeMouseDown(d) {
|
||||
focusView();
|
||||
if (d3.event.button === 1) {
|
||||
return;
|
||||
}
|
||||
//var touch0 = d3.event;
|
||||
//var pos = [touch0.pageX,touch0.pageY];
|
||||
//RED.touch.radialMenu.show(d3.select(this),pos);
|
||||
@@ -1651,7 +1765,9 @@ RED.view = (function() {
|
||||
clickElapsed = now-clickTime;
|
||||
clickTime = now;
|
||||
|
||||
dblClickPrimed = (lastClickNode == mousedown_node);
|
||||
dblClickPrimed = (lastClickNode == mousedown_node &&
|
||||
d3.event.buttons === 1 &&
|
||||
!d3.event.shiftKey && !d3.event.metaKey && !d3.event.altKey && !d3.event.ctrlKey);
|
||||
lastClickNode = mousedown_node;
|
||||
|
||||
var i;
|
||||
@@ -1922,7 +2038,7 @@ RED.view = (function() {
|
||||
.attr("ry",4)
|
||||
.attr("width",16)
|
||||
.attr("height",node_height-12)
|
||||
.attr("fill",function(d) { return d._def.color;})
|
||||
.attr("fill",function(d) { return RED.utils.getNodeColor(d.type,d._def); /*d._def.color;*/})
|
||||
.attr("cursor","pointer")
|
||||
.on("mousedown",function(d) {if (!lasso && isButtonEnabled(d)) {focusView();d3.select(this).attr("fill-opacity",0.2);d3.event.preventDefault(); d3.event.stopPropagation();}})
|
||||
.on("mouseup",function(d) {if (!lasso && isButtonEnabled(d)) { d3.select(this).attr("fill-opacity",0.4);d3.event.preventDefault();d3.event.stopPropagation();}})
|
||||
@@ -1943,7 +2059,7 @@ RED.view = (function() {
|
||||
.classed("node_unknown",function(d) { return d.type == "unknown"; })
|
||||
.attr("rx", 5)
|
||||
.attr("ry", 5)
|
||||
.attr("fill",function(d) { return d._def.color;})
|
||||
.attr("fill",function(d) { return RED.utils.getNodeColor(d.type,d._def); /*d._def.color;*/})
|
||||
.on("mouseup",nodeMouseUp)
|
||||
.on("mousedown",nodeMouseDown)
|
||||
.on("touchstart",function(d) {
|
||||
@@ -2340,32 +2456,17 @@ RED.view = (function() {
|
||||
var numOutputs = d.source.outputs || 1;
|
||||
var sourcePort = d.sourcePort || 0;
|
||||
var y = -((numOutputs-1)/2)*13 +13*sourcePort;
|
||||
|
||||
var dy = d.target.y-(d.source.y+y);
|
||||
var dx = (d.target.x-d.target.w/2)-(d.source.x+d.source.w/2);
|
||||
var delta = Math.sqrt(dy*dy+dx*dx);
|
||||
var scale = lineCurveScale;
|
||||
var scaleY = 0;
|
||||
if (delta < node_width) {
|
||||
scale = 0.75-0.75*((node_width-delta)/node_width);
|
||||
}
|
||||
|
||||
if (dx < 0) {
|
||||
scale += 2*(Math.min(5*node_width,Math.abs(dx))/(5*node_width));
|
||||
if (Math.abs(dy) < 3*node_height) {
|
||||
scaleY = ((dy>0)?0.5:-0.5)*(((3*node_height)-Math.abs(dy))/(3*node_height))*(Math.min(node_width,Math.abs(dx))/(node_width)) ;
|
||||
}
|
||||
}
|
||||
|
||||
d.x1 = d.source.x+d.source.w/2;
|
||||
d.y1 = d.source.y+y;
|
||||
d.x2 = d.target.x-d.target.w/2;
|
||||
d.y2 = d.target.y;
|
||||
|
||||
return "M "+d.x1+" "+d.y1+
|
||||
" C "+(d.x1+scale*node_width)+" "+(d.y1+scaleY*node_height)+" "+
|
||||
(d.x2-scale*node_width)+" "+(d.y2-scaleY*node_height)+" "+
|
||||
d.x2+" "+d.y2;
|
||||
// return "M "+d.x1+" "+d.y1+
|
||||
// " C "+(d.x1+scale*node_width)+" "+(d.y1+scaleY*node_height)+" "+
|
||||
// (d.x2-scale*node_width)+" "+(d.y2-scaleY*node_height)+" "+
|
||||
// d.x2+" "+d.y2;
|
||||
|
||||
return generateLinkPath(d.x1,d.y1,d.x2,d.y2,1);
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -2501,7 +2602,7 @@ RED.view = (function() {
|
||||
}
|
||||
).classed("link_selected", false);
|
||||
}
|
||||
|
||||
RED.view.navigator.refresh();
|
||||
if (d3.event) {
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
@@ -2775,7 +2876,9 @@ RED.view = (function() {
|
||||
gridSize = Math.max(5,v);
|
||||
updateGrid();
|
||||
}
|
||||
},
|
||||
getActiveNodes: function() {
|
||||
return activeNodes;
|
||||
}
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -43,7 +43,7 @@ RED.workspaces = (function() {
|
||||
return ws;
|
||||
}
|
||||
function deleteWorkspace(ws) {
|
||||
if (workspace_tabs.count() == 1) {
|
||||
if (workspaceTabCount === 1) {
|
||||
return;
|
||||
}
|
||||
removeWorkspace(ws);
|
||||
@@ -65,7 +65,7 @@ RED.workspaces = (function() {
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-delete",
|
||||
class: 'leftButton'+((workspace_tabs.count() == 1)?" disabled":""),
|
||||
class: 'leftButton'+((workspaceTabCount === 1)?" disabled":""),
|
||||
text: RED._("common.label.delete"), //'<i class="fa fa-trash"></i>',
|
||||
click: function() {
|
||||
deleteWorkspace(workspace);
|
||||
@@ -172,12 +172,12 @@ RED.workspaces = (function() {
|
||||
i.addClass('fa-toggle-on');
|
||||
i.removeClass('fa-toggle-off');
|
||||
$("#node-input-disabled").prop("checked",false);
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
|
||||
} else {
|
||||
i.addClass('fa-toggle-off');
|
||||
i.removeClass('fa-toggle-on');
|
||||
$("#node-input-disabled").prop("checked",true);
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.disabled"));
|
||||
}
|
||||
})
|
||||
|
||||
@@ -185,13 +185,13 @@ RED.workspaces = (function() {
|
||||
$("#node-input-disabled").prop("checked",workspace.disabled);
|
||||
if (workspace.disabled) {
|
||||
dialogForm.find("#node-input-disabled-btn i").removeClass('fa-toggle-on').addClass('fa-toggle-off');
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.disabled"));
|
||||
} else {
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
|
||||
}
|
||||
} else {
|
||||
workspace.disabled = false;
|
||||
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
|
||||
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
|
||||
}
|
||||
|
||||
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
|
||||
@@ -214,6 +214,7 @@ RED.workspaces = (function() {
|
||||
|
||||
|
||||
var workspace_tabs;
|
||||
var workspaceTabCount = 0;
|
||||
function createWorkspaceTabs() {
|
||||
workspace_tabs = RED.tabs.create({
|
||||
id: "workspace-tabs",
|
||||
@@ -240,18 +241,24 @@ RED.workspaces = (function() {
|
||||
}
|
||||
},
|
||||
onadd: function(tab) {
|
||||
if (tab.type === "tab") {
|
||||
workspaceTabCount++;
|
||||
}
|
||||
$('<span class="workspace-disabled-icon"><i class="fa fa-ban"></i> </span>').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label");
|
||||
if (tab.disabled) {
|
||||
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('workspace-disabled');
|
||||
}
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() <= 1);
|
||||
if (workspace_tabs.count() === 1) {
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
|
||||
if (workspaceTabCount === 1) {
|
||||
showWorkspace();
|
||||
}
|
||||
},
|
||||
onremove: function(tab) {
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() <= 1);
|
||||
if (workspace_tabs.count() === 0) {
|
||||
if (tab.type === "tab") {
|
||||
workspaceTabCount--;
|
||||
}
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
|
||||
if (workspaceTabCount === 0) {
|
||||
hideWorkspace();
|
||||
}
|
||||
},
|
||||
@@ -266,6 +273,7 @@ RED.workspaces = (function() {
|
||||
addWorkspace();
|
||||
}
|
||||
});
|
||||
workspaceTabCount = 0;
|
||||
}
|
||||
function showWorkspace() {
|
||||
$("#workspace .red-ui-tabs").show()
|
||||
@@ -334,7 +342,7 @@ RED.workspaces = (function() {
|
||||
return workspace_tabs.contains(id);
|
||||
},
|
||||
count: function() {
|
||||
return workspace_tabs.count();
|
||||
return workspaceTabCount;
|
||||
},
|
||||
active: function() {
|
||||
return activeWorkspace
|
||||
|
||||
4
editor/sass/bootstrap.scss
vendored
4
editor/sass/bootstrap.scss
vendored
@@ -19,3 +19,7 @@
|
||||
div.btn-group, a.btn {
|
||||
@include disable-selection;
|
||||
}
|
||||
|
||||
.dropdown-menu>li>a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
@@ -64,22 +64,22 @@
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.debug-message-row {
|
||||
.debug-message-tools-pin {
|
||||
display: none;
|
||||
}
|
||||
&.debug-message-row-pinned .debug-message-tools-pin {
|
||||
display: inline-block;
|
||||
}
|
||||
&:hover {
|
||||
background: #f3f3f3;
|
||||
&>.debug-message-tools {
|
||||
.debug-message-tools-copy {
|
||||
display: inline-block;
|
||||
}
|
||||
.debug-message-tools-pin {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.debug-message-row {
|
||||
.debug-message-tools-pin {
|
||||
display: none;
|
||||
}
|
||||
&.debug-message-row-pinned .debug-message-tools-pin {
|
||||
display: inline-block;
|
||||
}
|
||||
&:hover {
|
||||
background: #f3f3f3;
|
||||
&>.debug-message-tools {
|
||||
.debug-message-tools-copy {
|
||||
display: inline-block;
|
||||
}
|
||||
.debug-message-tools-pin {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,8 @@
|
||||
|
||||
.debug-message-meta {
|
||||
background: #fff;
|
||||
font-size: 10px;
|
||||
color: #777;
|
||||
font-size: 11px;
|
||||
color: #707070;
|
||||
}
|
||||
.debug-message-date {
|
||||
padding: 1px 5px 1px 1px;
|
||||
@@ -125,7 +125,7 @@
|
||||
}
|
||||
.debug-message-name {
|
||||
padding: 1px 5px;
|
||||
color: #777;
|
||||
color: #707070;
|
||||
}
|
||||
.debug-message-tools {
|
||||
position: absolute;
|
||||
@@ -159,7 +159,7 @@
|
||||
.debug-message-element {
|
||||
color: #333;
|
||||
font-family: Menlo, monospace;
|
||||
font-size: 12px !important;
|
||||
font-size: 13px !important;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
.debug-message-object-key {
|
||||
@@ -188,11 +188,9 @@
|
||||
.debug-message-element.collapsed>span>.debug-message-object-handle {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.debug-message-object-entry.collapsed > .debug-message-object-entry {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.debug-message-element.collapsed .debug-message-object-entry {
|
||||
display:none;
|
||||
}
|
||||
@@ -202,14 +200,13 @@
|
||||
.debug-message-element.collapsed .debug-message-buffer-opts {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.debug-message-element.collapsed .debug-message-object-type-header {
|
||||
display:none;
|
||||
}
|
||||
.debug-message-object-entry pre {
|
||||
font-family: Menlo, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.4em;
|
||||
font-size: 13px;
|
||||
line-height: 1.2em;
|
||||
margin: 0 0 0 -1em;
|
||||
}
|
||||
|
||||
|
||||
@@ -353,3 +353,64 @@
|
||||
}
|
||||
|
||||
}
|
||||
#node-settings-icon {
|
||||
margin-left: 10px;
|
||||
width: calc(100% - 163px);
|
||||
}
|
||||
.red-ui-icon-picker {
|
||||
position: absolute;
|
||||
border: 1px solid $primary-border-color;
|
||||
box-shadow: 0 1px 6px -3px black;
|
||||
background: white;
|
||||
z-Index: 21;
|
||||
display: none;
|
||||
select {
|
||||
box-sizing: border-box;
|
||||
margin: 3px;
|
||||
width: calc(100% - 6px);
|
||||
}
|
||||
}
|
||||
.red-ui-icon-list {
|
||||
width: 308px;
|
||||
height: 200px;
|
||||
overflow-y: scroll;
|
||||
line-height: 0px;
|
||||
}
|
||||
.red-ui-icon-list-icon {
|
||||
display: inline-block;
|
||||
margin: 2px;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
background: lighten($node-selected-color,20%);
|
||||
}
|
||||
&.selected {
|
||||
background: lighten($node-selected-color,20%);
|
||||
.red-ui-search-result-node {
|
||||
border-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-icon-list-module {
|
||||
background: $palette-header-background;
|
||||
font-size: 0.9em;
|
||||
padding: 3px;
|
||||
color: #666;
|
||||
clear: both;
|
||||
i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.red-ui-icon-meta {
|
||||
border-top: 1px solid $secondary-border-color;
|
||||
span {
|
||||
padding: 4px;
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
button {
|
||||
float: right;
|
||||
margin: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
|
||||
.link_outline {
|
||||
stroke: #fff;
|
||||
stroke-width: 4;
|
||||
stroke-width: 5;
|
||||
cursor: crosshair;
|
||||
fill: none;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -134,15 +134,18 @@
|
||||
color: $workspace-button-toggle-color !important;
|
||||
background:$workspace-button-background-active;
|
||||
margin-bottom: 1px;
|
||||
&.selected:not(.disabled) {
|
||||
|
||||
&.selected:not(.disabled):not(:disabled) {
|
||||
color: $workspace-button-toggle-color-selected !important;
|
||||
background: $workspace-button-background;
|
||||
border-bottom-width: 2px;
|
||||
border-bottom-color: $form-input-border-selected-color;
|
||||
margin-bottom: 0;
|
||||
cursor: default;
|
||||
&:not(.single) {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
&.disabled,&:disabled {
|
||||
color: $workspace-button-toggle-color-disabled !important;
|
||||
}
|
||||
}
|
||||
@@ -203,7 +206,7 @@
|
||||
height: 25px;
|
||||
line-height: 23px;
|
||||
padding: 0 10px;
|
||||
|
||||
user-select: none;
|
||||
|
||||
.button-group:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
@@ -227,6 +230,7 @@
|
||||
font-size: 11px;
|
||||
line-height: 17px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
&.text-button {
|
||||
width: auto;
|
||||
padding: 0 5px;
|
||||
|
||||
@@ -49,7 +49,12 @@
|
||||
.palette-module-version {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.palette-module-errors .fa-warning {
|
||||
opacity: 0.5;
|
||||
}
|
||||
ul.palette-module-error-list li {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -222,6 +227,20 @@
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
.palette-module-meta .fa-warning {
|
||||
color: #AD1625;
|
||||
}
|
||||
ul.palette-module-error-list {
|
||||
display: inline-block;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
li {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
.palette-module-shade {
|
||||
@include shade;
|
||||
text-align: center;
|
||||
|
||||
@@ -90,13 +90,14 @@
|
||||
text-align: left;
|
||||
padding: 9px;
|
||||
font-weight: bold;
|
||||
padding-left: 30px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
.palette-header > i {
|
||||
margin: 3px 10px 3px 3px;
|
||||
position: absolute;
|
||||
left: 11px;
|
||||
top: 12px;
|
||||
-webkit-transition: all 0.2s ease-in-out;
|
||||
-moz-transition: all 0.2s ease-in-out;
|
||||
-o-transition: all 0.2s ease-in-out;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
}
|
||||
|
||||
.red-ui-popover:after, .red-ui-popover:before {
|
||||
top: 50%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
@@ -39,12 +38,18 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-right:after, .red-ui-popover.red-ui-popover-right:before {
|
||||
top: 50%;
|
||||
right: 100%;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-left:after, .red-ui-popover.red-ui-popover-left:before {
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.red-ui-popover.red-ui-popover-bottom:after, .red-ui-popover.red-ui-popover-bottom:before {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.red-ui-popover.red-ui-popover-right:after {
|
||||
border-color: rgba(136, 183, 213, 0);
|
||||
@@ -72,6 +77,21 @@
|
||||
margin-top: -11px;
|
||||
}
|
||||
|
||||
|
||||
.red-ui-popover.red-ui-popover-bottom:after {
|
||||
border-color: rgba(136, 183, 213, 0);
|
||||
border-bottom-color: #fff;
|
||||
border-width: 10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
.red-ui-popover.red-ui-popover-bottom:before {
|
||||
border-color: rgba(194, 225, 245, 0);
|
||||
border-bottom-color: $primary-border-color;
|
||||
border-width: 11px;
|
||||
margin-left: -11px;
|
||||
}
|
||||
|
||||
|
||||
.red-ui-popover-size-small {
|
||||
font-size: 11px;
|
||||
padding: 5px;
|
||||
@@ -93,4 +113,12 @@
|
||||
border-width: 6px;
|
||||
margin-top: -6px;
|
||||
}
|
||||
&.red-ui-popover-bottom:after {
|
||||
border-width: 5px;
|
||||
margin-left: -5px;
|
||||
}
|
||||
&.red-ui-popover-bottom:before {
|
||||
border-width: 6px;
|
||||
margin-left: -6px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,16 +139,17 @@
|
||||
}
|
||||
}
|
||||
button.editor-button {
|
||||
width: calc(50% - 40px);
|
||||
width: calc(50% - 80px);
|
||||
margin: 20px;
|
||||
height: 175px;
|
||||
height: auto;
|
||||
line-height: 2em;
|
||||
font-size: 1.5em !important;
|
||||
padding: 10px;
|
||||
border-color: #aaa;
|
||||
i {
|
||||
color: #ccc;
|
||||
color: #aaa;
|
||||
}
|
||||
&:hover i {
|
||||
color: #aaa;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.button-group {
|
||||
@@ -160,7 +161,6 @@
|
||||
button.projects-dialog-screen-create-type {
|
||||
height: auto;
|
||||
padding: 10px;
|
||||
|
||||
}
|
||||
.button-group {
|
||||
text-align: center;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
@import "panels";
|
||||
@import "tabs";
|
||||
@import "tab-config";
|
||||
@import "tab-context";
|
||||
@import "tab-info";
|
||||
@import "popover";
|
||||
@import "flow";
|
||||
|
||||
54
editor/sass/tab-context.scss
Normal file
54
editor/sass/tab-context.scss
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
.sidebar-context-stack {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-y: scroll;
|
||||
|
||||
.palette-category {
|
||||
&:not(.palette-category-expanded) button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-context-property {
|
||||
position: relative;
|
||||
.debug-message-tools {
|
||||
right: 0px;
|
||||
margin-right: 5px;
|
||||
display: none;
|
||||
}
|
||||
&:hover .debug-message-tools {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.sidebar-context-updated {
|
||||
text-align: right;
|
||||
font-size: 11px;
|
||||
color: #bbb;
|
||||
padding: 1px 3px;
|
||||
}
|
||||
.sidebar-context-property-storename {
|
||||
display: block;
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
color: #aaa;
|
||||
}
|
||||
@@ -93,7 +93,7 @@
|
||||
color: $workspace-button-color-hover;
|
||||
}
|
||||
}
|
||||
.red-ui-tab-icon {
|
||||
img.red-ui-tab-icon {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
@@ -113,6 +113,21 @@
|
||||
&.red-ui-tabs-add.red-ui-tabs-scrollable {
|
||||
padding-right: 59px;
|
||||
}
|
||||
&.red-ui-tabs-collapsible {
|
||||
li:not(.active) {
|
||||
display: none;
|
||||
&.red-ui-tab-pinned {
|
||||
a {
|
||||
padding-left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.red-ui-tabs-vertical {
|
||||
box-sizing: border-box;
|
||||
@@ -157,6 +172,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-tabs-select {
|
||||
position: absolute;
|
||||
top:0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
opacity: 0.4;
|
||||
background: red;
|
||||
}
|
||||
}
|
||||
.red-ui-tab-button {
|
||||
position: absolute;
|
||||
@@ -180,7 +204,32 @@
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-tab-link-buttons {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 35px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid $primary-border-color;
|
||||
z-index: 2;
|
||||
a {
|
||||
@include workspace-button-toggle;
|
||||
line-height: 26px;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
margin: 4px 3px 3px;
|
||||
z-index: 2;
|
||||
&.red-ui-tab-link-button {
|
||||
&:not(.active) {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
&.red-ui-tab-link-button-menu {
|
||||
border-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-tab-scroll {
|
||||
width: 21px;
|
||||
top: 0;
|
||||
@@ -216,7 +265,7 @@
|
||||
right: 38px;
|
||||
}
|
||||
|
||||
.red-ui-tab-icon {
|
||||
img.red-ui-tab-icon {
|
||||
margin-left: -8px;
|
||||
margin-right: 3px;
|
||||
margin-top: -2px;
|
||||
@@ -225,6 +274,11 @@
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
i.red-ui-tab-icon {
|
||||
opacity: 0.7;
|
||||
width: 18px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.red-ui-tabs-badges {
|
||||
position: absolute;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
overflow:hidden;
|
||||
overflow:visible;
|
||||
position: relative;
|
||||
.red-ui-typedInput-input {
|
||||
position: absolute;
|
||||
@@ -43,6 +43,7 @@
|
||||
border-bottom-left-radius: 0;
|
||||
box-shadow: none;
|
||||
vertical-align: middle;
|
||||
// backgroun/d: #f0fff0;
|
||||
}
|
||||
|
||||
&.red-ui-typedInput-focus:not(.input-error) {
|
||||
@@ -63,10 +64,11 @@
|
||||
line-height: 32px;
|
||||
vertical-align: middle;
|
||||
color: #555;
|
||||
i {
|
||||
position:relative;
|
||||
top:-3px;
|
||||
margin-right:4px;
|
||||
i.red-ui-typedInput-icon {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
margin-left: 1px;
|
||||
margin-right: 2px;
|
||||
margin-top: 1px;
|
||||
vertical-align: middle;
|
||||
&.fa-ellipsis-h {
|
||||
@@ -75,11 +77,11 @@
|
||||
}
|
||||
&.disabled {
|
||||
cursor: default;
|
||||
i {
|
||||
i.red-ui-typedInput-icon {
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
span {
|
||||
.red-ui-typedInput-type-label,.red-ui-typedInput-option-label {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
padding: 0 1px 0 5px;
|
||||
@@ -120,26 +122,25 @@
|
||||
border-bottom-right-radius: 4px;
|
||||
padding: 0 0 0 0;
|
||||
position:absolute;
|
||||
width: calc( 100% );
|
||||
|
||||
i {
|
||||
position:absolute;
|
||||
right: 4px;
|
||||
top: 7px;
|
||||
}
|
||||
right: 0;
|
||||
.red-ui-typedInput-option-label {
|
||||
background:#fff;
|
||||
background:$typedInput-button-background;
|
||||
position:absolute;
|
||||
left:0;
|
||||
right:23px;
|
||||
top: 0;
|
||||
padding: 0 5px 0 5px;
|
||||
padding: 0 5px 0 8px;
|
||||
i.red-ui-typedInput-icon {
|
||||
margin-right: 4px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
.red-ui-typedInput-option-caret {
|
||||
top: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 17px;
|
||||
padding-left: 6px;
|
||||
}
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
@@ -174,4 +175,7 @@
|
||||
background: $typedInput-button-background-active;
|
||||
}
|
||||
}
|
||||
.red-ui-typedInput-icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,13 @@
|
||||
}
|
||||
|
||||
#user-settings-tab-view {
|
||||
position: absolute;
|
||||
top:0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
padding: 8px 20px 20px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.user-settings-row {
|
||||
padding: 5px 10px 2px;
|
||||
|
||||
@@ -47,7 +47,9 @@
|
||||
.workspace-footer-button {
|
||||
@include component-footer-button;
|
||||
}
|
||||
|
||||
.workspace-footer-button-toggle {
|
||||
@include component-footer-button-toggle;
|
||||
}
|
||||
#workspace-footer {
|
||||
@include component-footer;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
<a class="workspace-footer-button" id="btn-zoom-out" href="#"><i class="fa fa-minus"></i></a>
|
||||
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
|
||||
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
||||
<a class="workspace-footer-button-toggle single" id="btn-navigate" href="#"><i class="fa fa-map-o"></i></a>
|
||||
</div>
|
||||
<div id="editor-shade" class="hide"></div>
|
||||
</div>
|
||||
@@ -131,6 +132,10 @@
|
||||
<i class="fa fa-tag"></i>
|
||||
<label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<i class="fa fa-folder-o"></i>
|
||||
<label for="subflow-input-category" data-i18n="editor:subflow.category"></label><select style="width: 250px;" id="subflow-input-category"></select><input style="display:none; margin-left: 10px; width:calc(100% - 250px)" type="text" id="subflow-input-custom-category">
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom: 0px;">
|
||||
<label for="subflow-input-info" data-i18n="editor:subflow.info"></label>
|
||||
<a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a>
|
||||
@@ -140,76 +145,6 @@
|
||||
</div>
|
||||
<div class="form-row form-tips" id="subflow-dialog-user-count"></div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="_expression">
|
||||
<div id="node-input-expression-panels">
|
||||
<div id="node-input-expression-panel-expr" class="red-ui-panel">
|
||||
<div class="form-row" style="margin-bottom: 3px; text-align: right;">
|
||||
<span class="node-input-expression-legacy"><i class="fa fa-exclamation-circle"></i> <span data-i18n="expressionEditor.compatMode"></span></span>
|
||||
<button id="node-input-expression-reformat" class="editor-button editor-button-small"><span data-i18n="expressionEditor.format"></span></button>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div class="node-text-editor" id="node-input-expression"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="node-input-expression-panel-info" class="red-ui-panel">
|
||||
<div class="form-row">
|
||||
<ul id="node-input-expression-tabs"></ul>
|
||||
<div id="node-input-expression-tab-help" class="node-input-expression-tab-content hide">
|
||||
<div>
|
||||
<select id="node-input-expression-func"></select>
|
||||
<button id="node-input-expression-func-insert" class="editor-button" data-i18n="expressionEditor.insert"></button>
|
||||
</div>
|
||||
<div id="node-input-expression-help"></div>
|
||||
</div>
|
||||
<div id="node-input-expression-tab-test" class="node-input-expression-tab-content hide">
|
||||
<div>
|
||||
<span style="display: inline-block; width: calc(50% - 5px);">
|
||||
<span data-i18n="expressionEditor.data"></span>
|
||||
<button style="float: right; margin-right: 5px;" id="node-input-example-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
|
||||
</span>
|
||||
<span style="display: inline-block; width: calc(50% - 5px);" data-i18n="expressionEditor.result"></span>
|
||||
</div>
|
||||
<div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-data"></div>
|
||||
<div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-result"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="_json">
|
||||
<div class="form-row" style="margin-bottom: 3px; text-align: right;">
|
||||
<button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="_markdown">
|
||||
<div class="form-row" id="node-input-markdown-title" style="margin-bottom: 3px; text-align: right;">
|
||||
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-markdown"></div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="_buffer">
|
||||
<div id="node-input-buffer-panels">
|
||||
<div id="node-input-buffer-panel-str" class="red-ui-panel">
|
||||
<div class="form-row" style="margin-bottom: 3px; text-align: right;">
|
||||
<span class="node-input-buffer-type"><i class="fa fa-exclamation-circle"></i> <span id="node-input-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="node-input-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></span>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div class="node-text-editor" id="node-input-buffer-str"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="node-input-buffer-panel-bin" class="red-ui-panel">
|
||||
<div class="form-row node-text-editor-row" style="margin-top: 10px">
|
||||
<div class="node-text-editor" id="node-input-buffer-bin"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script src="vendor/vendor.js"></script>
|
||||
<script src="vendor/jsonata/jsonata.min.js"></script>
|
||||
<script src="vendor/ace/ace.js"></script>
|
||||
|
||||
1
editor/vendor/ace/snippets/json.js
vendored
Normal file
1
editor/vendor/ace/snippets/json.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ace.define("ace/snippets/json",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="json"})
|
||||
1
editor/vendor/ace/snippets/sql.js
vendored
Normal file
1
editor/vendor/ace/snippets/sql.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ace.define("ace/snippets/sql",["require","exports","module"],function(e,t,n){"use strict";t.snippetText="snippet tbl\n create table ${1:table} (\n ${2:columns}\n );\nsnippet col\n ${1:name} ${2:type} ${3:default ''} ${4:not null}\nsnippet ccol\n ${1:name} varchar2(${2:size}) ${3:default ''} ${4:not null}\nsnippet ncol\n ${1:name} number ${3:default 0} ${4:not null}\nsnippet dcol\n ${1:name} date ${3:default sysdate} ${4:not null}\nsnippet ind\n create index ${3:$1_$2} on ${1:table}(${2:column});\nsnippet uind\n create unique index ${1:name} on ${2:table}(${3:column});\nsnippet tblcom\n comment on table ${1:table} is '${2:comment}';\nsnippet colcom\n comment on column ${1:table}.${2:column} is '${3:comment}';\nsnippet addcol\n alter table ${1:table} add (${2:column} ${3:type});\nsnippet seq\n create sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\nsnippet s*\n select * from ${1:table}\n",t.scope="sql"})
|
||||
1
editor/vendor/ace/snippets/swift.js
vendored
Normal file
1
editor/vendor/ace/snippets/swift.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ace.define("ace/snippets/swift",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="swift"})
|
||||
1
editor/vendor/jsonata/formatter.js
vendored
1
editor/vendor/jsonata/formatter.js
vendored
@@ -117,6 +117,7 @@
|
||||
'$contains':{ args:[ 'str', 'pattern' ]},
|
||||
'$count':{ args:[ 'array' ]},
|
||||
'$each':{ args:[ 'object', 'function' ]},
|
||||
'$env': { args:[ 'arg' ]},
|
||||
'$exists':{ args:[ 'arg' ]},
|
||||
'$filter':{ args:[ 'array', 'function' ]},
|
||||
'$floor':{ args:[ 'number' ]},
|
||||
|
||||
@@ -237,10 +237,9 @@ If you want every 20 minutes from now - use the <i>"interval"</i> option.</p>
|
||||
} else {
|
||||
return this._("inject.timestamp")+suffix;
|
||||
}
|
||||
} else if (this.payloadType === 'flow' && this.payload.length < 19) {
|
||||
return 'flow.'+this.payload+suffix;
|
||||
} else if (this.payloadType === 'global' && this.payload.length < 17) {
|
||||
return 'global.'+this.payload+suffix;
|
||||
} else if (this.payloadType === 'flow' || this.payloadType === 'global') {
|
||||
var key = RED.utils.parseContextKey(this.payload);
|
||||
return this.payloadType+"."+key.key+suffix;
|
||||
} else {
|
||||
return this._("inject.inject")+suffix;
|
||||
}
|
||||
@@ -263,7 +262,7 @@ If you want every 20 minutes from now - use the <i>"interval"</i> option.</p>
|
||||
$("#node-input-payload").typedInput({
|
||||
default: 'str',
|
||||
typeField: $("#node-input-payloadType"),
|
||||
types:['flow','global','str','num','bool','json','bin','date']
|
||||
types:['flow','global','str','num','bool','json','bin','date','env']
|
||||
});
|
||||
|
||||
$("#inject-time-type-select").change(function() {
|
||||
@@ -502,7 +501,13 @@ If you want every 20 minutes from now - use the <i>"interval"</i> option.</p>
|
||||
if (this.changed) {
|
||||
return RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.undeployedChanges")}),"warning");
|
||||
}
|
||||
var label = (this.name||this.payload);
|
||||
var payload = this.payload;
|
||||
if ((this.payloadType === 'flow') ||
|
||||
(this.payloadType === 'global')) {
|
||||
var key = RED.utils.parseContextKey(payload);
|
||||
payload = this.payloadType+"."+key.key;
|
||||
}
|
||||
var label = (this.name||payload);
|
||||
if (label.length > 30) {
|
||||
label = label.substring(0,50)+"...";
|
||||
}
|
||||
|
||||
@@ -63,21 +63,33 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
this.on("input",function(msg) {
|
||||
try {
|
||||
msg.topic = this.topic;
|
||||
if ( (this.payloadType == null && this.payload === "") || this.payloadType === "date") {
|
||||
msg.payload = Date.now();
|
||||
} else if (this.payloadType == null) {
|
||||
msg.payload = this.payload;
|
||||
} else if (this.payloadType === 'none') {
|
||||
msg.payload = "";
|
||||
} else {
|
||||
msg.payload = RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg);
|
||||
msg.topic = this.topic;
|
||||
if (this.payloadType !== 'flow' && this.payloadType !== 'global') {
|
||||
try {
|
||||
if ( (this.payloadType == null && this.payload === "") || this.payloadType === "date") {
|
||||
msg.payload = Date.now();
|
||||
} else if (this.payloadType == null) {
|
||||
msg.payload = this.payload;
|
||||
} else if (this.payloadType === 'none') {
|
||||
msg.payload = "";
|
||||
} else {
|
||||
msg.payload = RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg);
|
||||
}
|
||||
this.send(msg);
|
||||
msg = null;
|
||||
} catch(err) {
|
||||
this.error(err,msg);
|
||||
}
|
||||
this.send(msg);
|
||||
msg = null;
|
||||
} catch(err) {
|
||||
this.error(err,msg);
|
||||
} else {
|
||||
RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg, function(err,res) {
|
||||
if (err) {
|
||||
node.error(err,msg);
|
||||
} else {
|
||||
msg.payload = res;
|
||||
node.send(msg);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -154,7 +154,9 @@
|
||||
name: this._("debug.sidebar.name"),
|
||||
content: uiComponents.content,
|
||||
toolbar: uiComponents.footer,
|
||||
enableOnEdit: true
|
||||
enableOnEdit: true,
|
||||
pinned: true,
|
||||
iconClass: "fa fa-bug"
|
||||
});
|
||||
RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); });
|
||||
|
||||
@@ -181,7 +183,7 @@
|
||||
this.handleDebugMessage = function(t,o) {
|
||||
var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
|
||||
if (sourceNode) {
|
||||
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name};
|
||||
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name,type:sourceNode.type,_alias:o._alias};
|
||||
}
|
||||
RED.debug.handleDebugMessage(o);
|
||||
if (subWindow) {
|
||||
|
||||
@@ -4,7 +4,6 @@ module.exports = function(RED) {
|
||||
var util = require("util");
|
||||
var events = require("events");
|
||||
var path = require("path");
|
||||
var safeJSONStringify = require("json-stringify-safe");
|
||||
var debuglength = RED.settings.debugMaxLength || 1000;
|
||||
var useColors = RED.settings.debugUseColors || false;
|
||||
util.inspect.styles.boolean = "red";
|
||||
@@ -104,111 +103,7 @@ module.exports = function(RED) {
|
||||
function sendDebug(msg) {
|
||||
// don't put blank errors in sidebar (but do add to logs)
|
||||
//if ((msg.msg === "") && (msg.hasOwnProperty("level")) && (msg.level === 20)) { return; }
|
||||
if (msg.msg instanceof Error) {
|
||||
msg.format = "error";
|
||||
var errorMsg = {};
|
||||
if (msg.msg.name) {
|
||||
errorMsg.name = msg.msg.name;
|
||||
}
|
||||
if (msg.msg.hasOwnProperty('message')) {
|
||||
errorMsg.message = msg.msg.message;
|
||||
} else {
|
||||
errorMsg.message = msg.msg.toString();
|
||||
}
|
||||
msg.msg = JSON.stringify(errorMsg);
|
||||
} else if (msg.msg instanceof Buffer) {
|
||||
msg.format = "buffer["+msg.msg.length+"]";
|
||||
msg.msg = msg.msg.toString('hex');
|
||||
if (msg.msg.length > debuglength) {
|
||||
msg.msg = msg.msg.substring(0,debuglength);
|
||||
}
|
||||
} else if (msg.msg && typeof msg.msg === 'object') {
|
||||
try {
|
||||
msg.format = msg.msg.constructor.name || "Object";
|
||||
// Handle special case of msg.req/res objects from HTTP In node
|
||||
if (msg.format === "IncomingMessage" || msg.format === "ServerResponse") {
|
||||
msg.format = "Object";
|
||||
}
|
||||
} catch(err) {
|
||||
msg.format = "Object";
|
||||
}
|
||||
if (/error/i.test(msg.format)) {
|
||||
msg.msg = JSON.stringify({
|
||||
name: msg.msg.name,
|
||||
message: msg.msg.message
|
||||
});
|
||||
} else {
|
||||
var isArray = util.isArray(msg.msg);
|
||||
if (isArray) {
|
||||
msg.format = "array["+msg.msg.length+"]";
|
||||
if (msg.msg.length > debuglength) {
|
||||
// msg.msg = msg.msg.slice(0,debuglength);
|
||||
msg.msg = {
|
||||
__encoded__: true,
|
||||
type: "array",
|
||||
data: msg.msg.slice(0,debuglength),
|
||||
length: msg.msg.length
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isArray || (msg.format === "Object")) {
|
||||
msg.msg = safeJSONStringify(msg.msg, function(key, value) {
|
||||
if (key === '_req' || key === '_res') {
|
||||
value = "[internal]"
|
||||
} else if (value instanceof Error) {
|
||||
value = value.toString()
|
||||
} else if (util.isArray(value) && value.length > debuglength) {
|
||||
value = {
|
||||
__encoded__: true,
|
||||
type: "array",
|
||||
data: value.slice(0,debuglength),
|
||||
length: value.length
|
||||
}
|
||||
} else if (typeof value === 'string') {
|
||||
if (value.length > debuglength) {
|
||||
value = value.substring(0,debuglength)+"...";
|
||||
}
|
||||
} else if (value && value.constructor) {
|
||||
if (value.type === "Buffer") {
|
||||
value.__encoded__ = true;
|
||||
value.length = value.data.length;
|
||||
if (value.length > debuglength) {
|
||||
value.data = value.data.slice(0,debuglength);
|
||||
}
|
||||
} else if (value.constructor.name === "ServerResponse") {
|
||||
value = "[internal]"
|
||||
} else if (value.constructor.name === "Socket") {
|
||||
value = "[internal]"
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}," ");
|
||||
} else {
|
||||
try { msg.msg = msg.msg.toString(); }
|
||||
catch(e) { msg.msg = "[Type not printable]"; }
|
||||
}
|
||||
}
|
||||
} else if (typeof msg.msg === "boolean") {
|
||||
msg.format = "boolean";
|
||||
msg.msg = msg.msg.toString();
|
||||
} else if (typeof msg.msg === "number") {
|
||||
msg.format = "number";
|
||||
msg.msg = msg.msg.toString();
|
||||
} else if (msg.msg === 0) {
|
||||
msg.format = "number";
|
||||
msg.msg = "0";
|
||||
} else if (msg.msg === null || typeof msg.msg === "undefined") {
|
||||
msg.format = (msg.msg === null)?"null":"undefined";
|
||||
msg.msg = "(undefined)";
|
||||
} else {
|
||||
msg.format = "string["+msg.msg.length+"]";
|
||||
if (msg.msg.length > debuglength) {
|
||||
msg.msg = msg.msg.substring(0,debuglength)+"...";
|
||||
}
|
||||
}
|
||||
// if (msg.msg.length > debuglength) {
|
||||
// msg.msg = msg.msg.substr(0,debuglength) +" ....";
|
||||
// }
|
||||
msg = RED.util.encodeObject(msg,{maxLength:debuglength});
|
||||
RED.comms.publish("debug",msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
icon: "arrow-in.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.command;
|
||||
return this.name||this.command||(this.useSpawn=="true"?this._("exec.spawn"):this._("exec.exec"));
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<input type="hidden" id="node-input-func" autofocus="autofocus">
|
||||
<input type="hidden" id="node-input-noerr">
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div class="form-row node-text-editor-row" style="position:relative">
|
||||
<div style="position: absolute; right:0; bottom:calc(100% + 3px);"><button id="node-function-expand-js" class="editor-button editor-button-small"><i class="fa fa-expand"></i></button></div>
|
||||
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@@ -52,6 +53,12 @@
|
||||
<p>The Catch node can also be used to handle errors. To invoke a Catch node,
|
||||
pass <code>msg</code> as a second argument to <code>node.error</code>:</p>
|
||||
<pre>node.error("Error",msg);</pre>
|
||||
<h4>Referring Node Information</h4>
|
||||
<p>In the function block, id and name of the node can be referenced using the following properties:</p>
|
||||
<ul>
|
||||
<li><code>node.id</code> - id of the node</li>
|
||||
<li><code>node.name</code> - name of the node</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
@@ -68,7 +75,7 @@
|
||||
outputs:1,
|
||||
icon: "function.png",
|
||||
label: function() {
|
||||
return this.name;
|
||||
return this.name||this._("function.function");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
@@ -113,6 +120,22 @@
|
||||
fields:['name','outputs']
|
||||
});
|
||||
this.editor.focus();
|
||||
|
||||
$("#node-function-expand-js").click(function(e) {
|
||||
e.preventDefault();
|
||||
var value = that.editor.getValue();
|
||||
RED.editor.editJavaScript({
|
||||
value: value,
|
||||
cursor: that.editor.getCursorPosition(),
|
||||
complete: function(v,cursor) {
|
||||
that.editor.setValue(v, -1);
|
||||
that.editor.gotoLine(cursor.row+1,cursor.column,false);
|
||||
setTimeout(function() {
|
||||
that.editor.focus();
|
||||
},300);
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
oneditsave: function() {
|
||||
var annot = this.editor.getSession().getAnnotations();
|
||||
|
||||
@@ -62,9 +62,13 @@ module.exports = function(RED) {
|
||||
"results = (function(msg){ "+
|
||||
"var __msgid__ = msg._msgid;"+
|
||||
"var node = {"+
|
||||
"id:__node__.id,"+
|
||||
"name:__node__.name,"+
|
||||
"log:__node__.log,"+
|
||||
"error:__node__.error,"+
|
||||
"warn:__node__.warn,"+
|
||||
"debug:__node__.debug,"+
|
||||
"trace:__node__.trace,"+
|
||||
"on:__node__.on,"+
|
||||
"status:__node__.status,"+
|
||||
"send:function(msgs){ __node__.send(__msgid__,msgs);}"+
|
||||
@@ -78,10 +82,13 @@ module.exports = function(RED) {
|
||||
console:console,
|
||||
util:util,
|
||||
Buffer:Buffer,
|
||||
Date: Date,
|
||||
RED: {
|
||||
util: RED.util
|
||||
},
|
||||
__node__: {
|
||||
id: node.id,
|
||||
name: node.name,
|
||||
log: function() {
|
||||
node.log.apply(node, arguments);
|
||||
},
|
||||
@@ -91,6 +98,12 @@ module.exports = function(RED) {
|
||||
warn: function() {
|
||||
node.warn.apply(node, arguments);
|
||||
},
|
||||
debug: function() {
|
||||
node.debug.apply(node, arguments);
|
||||
},
|
||||
trace: function() {
|
||||
node.trace.apply(node, arguments);
|
||||
},
|
||||
send: function(id, msgs) {
|
||||
sendResults(node, id, msgs);
|
||||
},
|
||||
@@ -196,7 +209,14 @@ module.exports = function(RED) {
|
||||
}
|
||||
var context = vm.createContext(sandbox);
|
||||
try {
|
||||
this.script = vm.createScript(functionText);
|
||||
this.script = vm.createScript(functionText, {
|
||||
filename: 'Function node:'+this.id+(this.name?' ['+this.name+']':''), // filename for stack traces
|
||||
displayErrors: true
|
||||
// Using the following options causes node 4/6 to not include the line number
|
||||
// in the stack output. So don't use them.
|
||||
// lineOffset: -11, // line number offset to be used for stack traces
|
||||
// columnOffset: 0, // column number offset to be used for stack traces
|
||||
});
|
||||
this.on("input", function(msg) {
|
||||
try {
|
||||
var start = process.hrtime();
|
||||
@@ -211,6 +231,13 @@ module.exports = function(RED) {
|
||||
this.status({fill:"yellow",shape:"dot",text:""+converted});
|
||||
}
|
||||
} catch(err) {
|
||||
//remove unwanted part
|
||||
var index = err.stack.search(/\n\s*at ContextifyScript.Script.runInContext/);
|
||||
err.stack = err.stack.slice(0, index).split('\n').slice(0,-1).join('\n');
|
||||
var stack = err.stack.split(/\r?\n/);
|
||||
|
||||
//store the error in msg to be used in flows
|
||||
msg.error = err;
|
||||
|
||||
var line = 0;
|
||||
var errorMessage;
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
}</pre>
|
||||
<p>The resulting property will be:
|
||||
<pre>Hello Fred. Today is Monday</pre>
|
||||
<p>It is possible to use a property from the flow context or global context. Just use <code>{{flow.name}}</code> or <code>{{global.name}}</code>.
|
||||
<p>It is possible to use a property from the flow context or global context. Just use <code>{{flow.name}}</code> or <code>{{global.name}}</code>, or for persistable store <code>store</code> use <code>{{flow[store].name}}</code> or <code>{{flobal[store].name}}</code>.
|
||||
<p><b>Note: </b>By default, <i>mustache</i> will escape any HTML entities in the values it substitutes.
|
||||
To prevent this, use <code>{{{triple}}}</code> braces.
|
||||
</script>
|
||||
@@ -88,7 +88,7 @@
|
||||
category: 'function',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
field: {value:"payload", validate: RED.validators.typedInput("fieldType")},
|
||||
field: {value:"payload", validate:RED.validators.typedInput("fieldType")},
|
||||
fieldType: {value:"msg"},
|
||||
format: {value:"handlebars"},
|
||||
syntax: {value:"mustache"},
|
||||
@@ -99,13 +99,17 @@
|
||||
outputs:1,
|
||||
icon: "template.png",
|
||||
label: function() {
|
||||
return this.name;
|
||||
return this.name||this._("template.template");;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var that = this;
|
||||
if (!this.field) {
|
||||
this.field = 'payload';
|
||||
$("#node-input-field").val("payload");
|
||||
}
|
||||
if (!this.fieldType) {
|
||||
this.fieldType = 'msg';
|
||||
}
|
||||
|
||||
@@ -19,15 +19,41 @@ module.exports = function(RED) {
|
||||
var mustache = require("mustache");
|
||||
var yaml = require("js-yaml");
|
||||
|
||||
function extractTokens(tokens,set) {
|
||||
set = set || new Set();
|
||||
tokens.forEach(function(token) {
|
||||
if (token[0] !== 'text') {
|
||||
set.add(token[1]);
|
||||
if (token.length > 4) {
|
||||
extractTokens(token[4],set);
|
||||
}
|
||||
}
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
function parseContext(key) {
|
||||
var match = /^(flow|global)(\[(\w+)\])?\.(.+)/.exec(key);
|
||||
if (match) {
|
||||
var parts = {};
|
||||
parts.type = match[1];
|
||||
parts.store = (match[3] === '') ? "default" : match[3];
|
||||
parts.field = match[4];
|
||||
return parts;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Mustache Context capable to resolve message property and node
|
||||
* Custom Mustache Context capable to collect message property and node
|
||||
* flow and global context
|
||||
*/
|
||||
function NodeContext(msg, nodeContext, parent, escapeStrings) {
|
||||
|
||||
function NodeContext(msg, nodeContext, parent, escapeStrings, cachedContextTokens) {
|
||||
this.msgContext = new mustache.Context(msg,parent);
|
||||
this.nodeContext = nodeContext;
|
||||
this.escapeStrings = escapeStrings;
|
||||
this.cachedContextTokens = cachedContextTokens;
|
||||
}
|
||||
|
||||
NodeContext.prototype = new mustache.Context();
|
||||
@@ -48,26 +74,26 @@ module.exports = function(RED) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// try node context:
|
||||
var dot = name.indexOf(".");
|
||||
if (dot > 0) {
|
||||
var contextName = name.substr(0, dot);
|
||||
var variableName = name.substr(dot + 1);
|
||||
|
||||
if (contextName === "flow" && this.nodeContext.flow) {
|
||||
return this.nodeContext.flow.get(variableName);
|
||||
}
|
||||
else if (contextName === "global" && this.nodeContext.global) {
|
||||
return this.nodeContext.global.get(variableName);
|
||||
// try flow/global context:
|
||||
var context = parseContext(name);
|
||||
if (context) {
|
||||
var type = context.type;
|
||||
var store = context.store;
|
||||
var field = context.field;
|
||||
var target = this.nodeContext[type];
|
||||
if (target) {
|
||||
return this.cachedContextTokens[name];
|
||||
}
|
||||
}
|
||||
}catch(err) {
|
||||
return '';
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
NodeContext.prototype.push = function push (view) {
|
||||
return new NodeContext(view, this.nodeContext,this.msgContext);
|
||||
return new NodeContext(view, this.nodeContext, this.msgContext, undefined, this.cachedContextTokens);
|
||||
};
|
||||
|
||||
function TemplateNode(n) {
|
||||
@@ -80,45 +106,89 @@ module.exports = function(RED) {
|
||||
this.outputFormat = n.output || "str";
|
||||
|
||||
var node = this;
|
||||
|
||||
function output(msg,value) {
|
||||
/* istanbul ignore else */
|
||||
if (node.outputFormat === "json") {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (node.outputFormat === "yaml") {
|
||||
value = yaml.load(value);
|
||||
}
|
||||
|
||||
if (node.fieldType === 'msg') {
|
||||
RED.util.setMessageProperty(msg, node.field, value);
|
||||
node.send(msg);
|
||||
} else if ((node.fieldType === 'flow') ||
|
||||
(node.fieldType === 'global')) {
|
||||
var context = RED.util.parseContextStore(node.field);
|
||||
var target = node.context()[node.fieldType];
|
||||
target.set(context.key, value, context.store, function (err) {
|
||||
if (err) {
|
||||
node.error(err, msg);
|
||||
} else {
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
node.on("input", function(msg) {
|
||||
|
||||
try {
|
||||
var value;
|
||||
/***
|
||||
* Allow template contents to be defined externally
|
||||
* through inbound msg.template IFF node.template empty
|
||||
*/
|
||||
var template = node.template;
|
||||
if (msg.hasOwnProperty("template")) {
|
||||
if (node.template == "" || node.template === null) {
|
||||
node.template = msg.template;
|
||||
if (template == "" || template === null) {
|
||||
template = msg.template;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.syntax === "mustache") {
|
||||
if (node.outputFormat === "json") {
|
||||
value = mustache.render(node.template,new NodeContext(msg, node.context(), null, true));
|
||||
} else {
|
||||
value = mustache.render(node.template,new NodeContext(msg, node.context(), null, false));
|
||||
}
|
||||
} else {
|
||||
value = node.template;
|
||||
}
|
||||
if (node.outputFormat === "json") {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
if (node.outputFormat === "yaml") {
|
||||
value = yaml.load(value);
|
||||
}
|
||||
var is_json = (node.outputFormat === "json");
|
||||
var promises = [];
|
||||
var tokens = extractTokens(mustache.parse(template));
|
||||
var resolvedTokens = {};
|
||||
tokens.forEach(function(name) {
|
||||
var context = parseContext(name);
|
||||
if (context) {
|
||||
var type = context.type;
|
||||
var store = context.store;
|
||||
var field = context.field;
|
||||
var target = node.context()[type];
|
||||
if (target) {
|
||||
var promise = new Promise((resolve, reject) => {
|
||||
target.get(field, store, (err, val) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolvedTokens[name] = val;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
promises.push(promise);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (node.fieldType === 'msg') {
|
||||
RED.util.setMessageProperty(msg,node.field,value);
|
||||
} else if (node.fieldType === 'flow') {
|
||||
node.context().flow.set(node.field,value);
|
||||
} else if (node.fieldType === 'global') {
|
||||
node.context().global.set(node.field,value);
|
||||
Promise.all(promises).then(function() {
|
||||
var value = mustache.render(template, new NodeContext(msg, node.context(), null, is_json, resolvedTokens));
|
||||
output(msg, value);
|
||||
}).catch(function (err) {
|
||||
node.error(err.message,msg);
|
||||
});
|
||||
} else {
|
||||
output(msg, template);
|
||||
}
|
||||
node.send(msg);
|
||||
} catch(err) {
|
||||
node.error(err.message);
|
||||
}
|
||||
catch(err) {
|
||||
node.error(err.message, msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
$("#node-input-op1").typedInput({
|
||||
default: 'str',
|
||||
typeField: $("#node-input-op1type"),
|
||||
types:['flow','global','str','num','bool','json',
|
||||
types:['flow','global','str','num','bool','json','bin','date','env',
|
||||
optionPayload,
|
||||
optionNothing
|
||||
]
|
||||
@@ -170,7 +170,7 @@
|
||||
$("#node-input-op2").typedInput({
|
||||
default: 'str',
|
||||
typeField: $("#node-input-op2type"),
|
||||
types:['flow','global','str','num','bool','json',
|
||||
types:['flow','global','str','num','bool','json','bin','date','env',
|
||||
optionOriginalPayload,
|
||||
optionLatestPayload,
|
||||
optionNothing
|
||||
|
||||
@@ -76,8 +76,43 @@ module.exports = function(RED) {
|
||||
var node = this;
|
||||
node.topics = {};
|
||||
|
||||
this.on("input", function(msg) {
|
||||
var pendingMessages = [];
|
||||
var activeMessagePromise = null;
|
||||
var processMessageQueue = function(msg) {
|
||||
if (msg) {
|
||||
// A new message has arrived - add it to the message queue
|
||||
pendingMessages.push(msg);
|
||||
if (activeMessagePromise !== null) {
|
||||
// The node is currently processing a message, so do nothing
|
||||
// more with this message
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (pendingMessages.length === 0) {
|
||||
// There are no more messages to process, clear the active flag
|
||||
// and return
|
||||
activeMessagePromise = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// There are more messages to process. Get the next message and
|
||||
// start processing it. Recurse back in to check for any more
|
||||
var nextMsg = pendingMessages.shift();
|
||||
activeMessagePromise = processMessage(nextMsg)
|
||||
.then(processMessageQueue)
|
||||
.catch((err) => {
|
||||
node.error(err,nextMsg);
|
||||
return processMessageQueue();
|
||||
});
|
||||
}
|
||||
|
||||
this.on('input', function(msg) {
|
||||
processMessageQueue(msg);
|
||||
});
|
||||
|
||||
var processMessage = function(msg) {
|
||||
var topic = msg.topic || "_none";
|
||||
var promise;
|
||||
if (node.bytopic === "all") { topic = "_none"; }
|
||||
node.topics[topic] = node.topics[topic] || {};
|
||||
if (msg.hasOwnProperty("reset") || ((node.reset !== '') && msg.hasOwnProperty("payload") && (msg.payload !== null) && msg.payload.toString && (msg.payload.toString() == node.reset)) ) {
|
||||
@@ -88,47 +123,88 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
if (((!node.topics[topic].tout) && (node.topics[topic].tout !== 0)) || (node.loop === true)) {
|
||||
promise = Promise.resolve();
|
||||
if (node.op2type === "pay" || node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
else if (node.op2Templated) { node.topics[topic].m2 = mustache.render(node.op2,msg); }
|
||||
else if (node.op2type !== "nul") {
|
||||
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
|
||||
if (node.op1type === "pay") { }
|
||||
else if (node.op1Templated) { msg.payload = mustache.render(node.op1,msg); }
|
||||
else if (node.op1type !== "nul") {
|
||||
msg.payload = RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg);
|
||||
}
|
||||
|
||||
if (node.duration === 0) { node.topics[topic].tout = 0; }
|
||||
else if (node.loop === true) {
|
||||
/* istanbul ignore else */
|
||||
if (node.topics[topic].tout) { clearInterval(node.topics[topic].tout); }
|
||||
/* istanbul ignore else */
|
||||
if (node.op1type !== "nul") {
|
||||
var msg2 = RED.util.cloneMessage(msg);
|
||||
node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, node.duration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!node.topics[topic].tout) {
|
||||
node.topics[topic].tout = setTimeout(function() {
|
||||
var msg2 = null;
|
||||
if (node.op2type !== "nul") {
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
delete node.topics[topic];
|
||||
node.send(msg2);
|
||||
promise = new Promise((resolve,reject) => {
|
||||
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
node.topics[topic].m2 = value;
|
||||
resolve();
|
||||
}
|
||||
node.status({});
|
||||
}, node.duration);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
node.status({fill:"blue",shape:"dot",text:" "});
|
||||
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
|
||||
|
||||
return promise.then(() => {
|
||||
promise = Promise.resolve();
|
||||
if (node.op1type === "pay") { }
|
||||
else if (node.op1Templated) { msg.payload = mustache.render(node.op1,msg); }
|
||||
else if (node.op1type !== "nul") {
|
||||
promise = new Promise((resolve,reject) => {
|
||||
RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg,(err,value) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
msg.payload = value;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return promise.then(() => {
|
||||
if (node.duration === 0) { node.topics[topic].tout = 0; }
|
||||
else if (node.loop === true) {
|
||||
/* istanbul ignore else */
|
||||
if (node.topics[topic].tout) { clearInterval(node.topics[topic].tout); }
|
||||
/* istanbul ignore else */
|
||||
if (node.op1type !== "nul") {
|
||||
var msg2 = RED.util.cloneMessage(msg);
|
||||
node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, node.duration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!node.topics[topic].tout) {
|
||||
node.topics[topic].tout = setTimeout(function() {
|
||||
var msg2 = null;
|
||||
if (node.op2type !== "nul") {
|
||||
var promise = Promise.resolve();
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
promise = new Promise((resolve,reject) => {
|
||||
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
node.topics[topic].m2 = value;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
promise.then(() => {
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
delete node.topics[topic];
|
||||
node.send(msg2);
|
||||
node.status({});
|
||||
}).catch(err => {
|
||||
node.error(err);
|
||||
});
|
||||
} else {
|
||||
delete node.topics[topic];
|
||||
node.status({});
|
||||
}
|
||||
|
||||
}, node.duration);
|
||||
}
|
||||
}
|
||||
node.status({fill:"blue",shape:"dot",text:" "});
|
||||
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
|
||||
});
|
||||
});
|
||||
}
|
||||
else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) {
|
||||
/* istanbul ignore else */
|
||||
@@ -137,25 +213,43 @@ module.exports = function(RED) {
|
||||
if (node.topics[topic].tout) { clearTimeout(node.topics[topic].tout); }
|
||||
node.topics[topic].tout = setTimeout(function() {
|
||||
var msg2 = null;
|
||||
var promise = Promise.resolve();
|
||||
|
||||
if (node.op2type !== "nul") {
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
|
||||
}
|
||||
if (node.topics[topic] !== undefined) {
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
promise = new Promise((resolve,reject) => {
|
||||
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
node.topics[topic].m2 = value;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
delete node.topics[topic];
|
||||
node.status({});
|
||||
node.send(msg2);
|
||||
promise.then(() => {
|
||||
if (node.op2type !== "nul") {
|
||||
if (node.topics[topic] !== undefined) {
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
}
|
||||
}
|
||||
delete node.topics[topic];
|
||||
node.status({});
|
||||
node.send(msg2);
|
||||
}).catch(err => {
|
||||
node.error(err);
|
||||
});
|
||||
}, node.duration);
|
||||
}
|
||||
else {
|
||||
if (node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
|
||||
}
|
||||
}
|
||||
});
|
||||
return Promise.resolve();
|
||||
}
|
||||
this.on("close", function() {
|
||||
for (var t in node.topics) {
|
||||
/* istanbul ignore else */
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
outputs:0,
|
||||
icon: "comment.png",
|
||||
label: function() {
|
||||
return this.name||"";
|
||||
return this.name||this._("comment.comment");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
|
||||
@@ -222,7 +222,6 @@ RED.debug = (function() {
|
||||
clearMessageList(false);
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
content: content,
|
||||
footer: footerToolbar
|
||||
@@ -238,6 +237,9 @@ RED.debug = (function() {
|
||||
workspaceOrder.forEach(function(ws,i) {
|
||||
workspaceOrderMap[ws] = i;
|
||||
});
|
||||
candidateNodes = candidateNodes.filter(function(node) {
|
||||
return workspaceOrderMap.hasOwnProperty(node.z);
|
||||
})
|
||||
candidateNodes.sort(function(A,B) {
|
||||
var wsA = workspaceOrderMap[A.z];
|
||||
var wsB = workspaceOrderMap[B.z];
|
||||
@@ -339,7 +341,7 @@ RED.debug = (function() {
|
||||
activeMenuMessage.clearPinned();
|
||||
}},
|
||||
null,
|
||||
{id:"debug-message-menu-item-filter",label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
|
||||
{id:"debug-message-menu-item-filter", label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
|
||||
var candidateNodes = RED.nodes.filterNodes({type:'debug'});
|
||||
candidateNodes.forEach(function(n) {
|
||||
filteredNodes[n.id] = true;
|
||||
@@ -361,6 +363,15 @@ RED.debug = (function() {
|
||||
menuOptionMenu.on('mouseup', function() { $(this).hide() });
|
||||
menuOptionMenu.appendTo("body");
|
||||
}
|
||||
|
||||
var filterOptionDisabled = false;
|
||||
var sourceNode = RED.nodes.node(sourceId);
|
||||
if (sourceNode && sourceNode.type !== 'debug') {
|
||||
filterOptionDisabled = true;
|
||||
}
|
||||
RED.menu.setDisabled('debug-message-menu-item-filter',filterOptionDisabled);
|
||||
RED.menu.setDisabled('debug-message-menu-item-clear-filter',filterOptionDisabled);
|
||||
|
||||
var elementPos = button.offset();
|
||||
menuOptionMenu.css({
|
||||
top: elementPos.top+"px",
|
||||
@@ -392,12 +403,19 @@ RED.debug = (function() {
|
||||
$(msg).addClass('debug-message-hover');
|
||||
if (o._source) {
|
||||
config.messageMouseEnter(o._source.id);
|
||||
if (o._source._alias) {
|
||||
config.messageMouseEnter(o._source._alias);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
msg.onmouseleave = function() {
|
||||
$(msg).removeClass('debug-message-hover');
|
||||
if (o._source) {
|
||||
config.messageMouseLeave(o._source.id);
|
||||
if (o._source._alias) {
|
||||
config.messageMouseLeave(o._source._alias);
|
||||
}
|
||||
}
|
||||
};
|
||||
var name = sanitize(((o.name?o.name:o.id)||"").toString());
|
||||
@@ -437,24 +455,8 @@ RED.debug = (function() {
|
||||
$('<span class="debug-message-name">'+name+'</span>').appendTo(metaRow);
|
||||
}
|
||||
|
||||
if ((format === 'number') && (payload === "NaN")) {
|
||||
payload = Number.NaN;
|
||||
} else if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number' ) {
|
||||
payload = JSON.parse(payload);
|
||||
} else if (/error/i.test(format)) {
|
||||
payload = JSON.parse(payload);
|
||||
payload = (payload.name?payload.name+": ":"")+payload.message;
|
||||
} else if (format === 'null') {
|
||||
payload = null;
|
||||
} else if (format === 'undefined') {
|
||||
payload = undefined;
|
||||
} else if (/^buffer/.test(format)) {
|
||||
var buffer = payload;
|
||||
payload = [];
|
||||
for (var c = 0; c < buffer.length; c += 2) {
|
||||
payload.push(parseInt(buffer.substr(c, 2), 16));
|
||||
}
|
||||
}
|
||||
payload = RED.utils.decodeObject(payload,format);
|
||||
|
||||
var el = $('<span class="debug-message-payload"></span>').appendTo(msg);
|
||||
var path = o.property||'';
|
||||
var debugMessage = RED.utils.createObjectElement(payload, {
|
||||
|
||||
@@ -6,35 +6,36 @@ module.exports = function(RED) {
|
||||
var fs = require('fs');
|
||||
|
||||
var gpioCommand = __dirname+'/nrgpio';
|
||||
var allOK = true;
|
||||
|
||||
try {
|
||||
var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString();
|
||||
if (cpuinfo.indexOf(": BCM") === -1) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); }
|
||||
} catch(err) {
|
||||
throw "Info : "+RED._("rpi-gpio.errors.ignorenode");
|
||||
}
|
||||
|
||||
try {
|
||||
fs.statSync("/usr/share/doc/python-rpi.gpio"); // test on Raspbian
|
||||
// /usr/lib/python2.7/dist-packages/RPi/GPIO
|
||||
} catch(err) {
|
||||
if (cpuinfo.indexOf(": BCM") === -1) {
|
||||
allOK = false;
|
||||
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.ignorenode"));
|
||||
}
|
||||
try {
|
||||
fs.statSync("/usr/lib/python2.7/site-packages/RPi/GPIO"); // test on Arch
|
||||
}
|
||||
catch(err) {
|
||||
fs.statSync("/usr/share/doc/python-rpi.gpio"); // test on Raspbian
|
||||
// /usr/lib/python2.7/dist-packages/RPi/GPIO
|
||||
} catch(err) {
|
||||
try {
|
||||
fs.statSync("/usr/lib/python2.7/dist-packages/RPi/GPIO"); // test on Hypriot
|
||||
}
|
||||
catch(err) {
|
||||
RED.log.warn(RED._("rpi-gpio.errors.libnotfound"));
|
||||
throw "Warning : "+RED._("rpi-gpio.errors.libnotfound");
|
||||
fs.statSync("/usr/lib/python2.7/site-packages/RPi/GPIO"); // test on Arch
|
||||
} catch(err) {
|
||||
try {
|
||||
fs.statSync("/usr/lib/python2.7/dist-packages/RPi/GPIO"); // test on Hypriot
|
||||
} catch(err) {
|
||||
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.libnotfound"));
|
||||
allOK = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !(1 & parseInt((fs.statSync(gpioCommand).mode & parseInt("777", 8)).toString(8)[0]) )) {
|
||||
RED.log.error(RED._("rpi-gpio.errors.needtobeexecutable",{command:gpioCommand}));
|
||||
throw "Error : "+RED._("rpi-gpio.errors.mustbeexecutable");
|
||||
if ( !(1 & parseInt((fs.statSync(gpioCommand).mode & parseInt("777", 8)).toString(8)[0]) )) {
|
||||
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.needtobeexecutable",{command:gpioCommand}));
|
||||
allOK = false;
|
||||
}
|
||||
} catch(err) {
|
||||
allOK = false;
|
||||
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.ignorenode"));
|
||||
}
|
||||
|
||||
// the magic to make python print stuff immediately
|
||||
@@ -61,48 +62,62 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
|
||||
if (node.pin !== undefined) {
|
||||
node.child = spawn(gpioCommand, ["in",node.pin,node.intype,node.debounce]);
|
||||
node.running = true;
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
if (allOK === true) {
|
||||
if (node.pin !== undefined) {
|
||||
node.child = spawn(gpioCommand, ["in",node.pin,node.intype,node.debounce]);
|
||||
node.running = true;
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var d = data.toString().trim().split("\n");
|
||||
for (var i = 0; i < d.length; i++) {
|
||||
if (d[i] === '') { return; }
|
||||
if (node.running && node.buttonState !== -1 && !isNaN(Number(d[i])) && node.buttonState !== d[i]) {
|
||||
node.send({ topic:"pi/"+node.pin, payload:Number(d[i]) });
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var d = data.toString().trim().split("\n");
|
||||
for (var i = 0; i < d.length; i++) {
|
||||
if (d[i] === '') { return; }
|
||||
if (node.running && node.buttonState !== -1 && !isNaN(Number(d[i])) && node.buttonState !== d[i]) {
|
||||
node.send({ topic:"pi/"+node.pin, payload:Number(d[i]) });
|
||||
}
|
||||
node.buttonState = d[i];
|
||||
node.status({fill:"green",shape:"dot",text:d[i]});
|
||||
if (RED.settings.verbose) { node.log("out: "+d[i]+" :"); }
|
||||
}
|
||||
node.buttonState = d[i];
|
||||
node.status({fill:"green",shape:"dot",text:d[i]});
|
||||
if (RED.settings.verbose) { node.log("out: "+d[i]+" :"); }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error",{error:err.errno})) }
|
||||
});
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error",{error:err.errno})) }
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
}
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
|
||||
if (node.read === true) {
|
||||
var val;
|
||||
if (node.intype == "up") { val = 1; }
|
||||
if (node.intype == "down") { val = 0; }
|
||||
setTimeout(function(){
|
||||
node.send({ topic:"pi/"+node.pin, payload:val });
|
||||
node.status({fill:"grey",shape:"dot",text:RED._("rpi-gpio.status.na",{value:val})});
|
||||
},250);
|
||||
}
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
@@ -142,9 +157,9 @@ module.exports = function(RED) {
|
||||
var limit = 1;
|
||||
if (node.out === "pwm") { limit = 100; }
|
||||
if ((out >= 0) && (out <= limit)) {
|
||||
if (RED.settings.verbose) { node.log("out: "+msg.payload); }
|
||||
if (RED.settings.verbose) { node.log("out: "+out); }
|
||||
if (node.child !== null) {
|
||||
node.child.stdin.write(msg.payload+"\n");
|
||||
node.child.stdin.write(out+"\n");
|
||||
node.status({fill:"green",shape:"dot",text:msg.payload.toString()});
|
||||
}
|
||||
else {
|
||||
@@ -155,20 +170,83 @@ module.exports = function(RED) {
|
||||
else { node.warn(RED._("rpi-gpio.errors.invalidinput")+": "+out); }
|
||||
}
|
||||
|
||||
if (node.pin !== undefined) {
|
||||
if (node.set && (node.out === "out")) {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin,node.level]);
|
||||
node.status({fill:"green",shape:"dot",text:node.level});
|
||||
} else {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin,node.freq]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
}
|
||||
node.running = true;
|
||||
if (allOK === true) {
|
||||
if (node.pin !== undefined) {
|
||||
if (node.set && (node.out === "out")) {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin,node.level]);
|
||||
node.status({fill:"green",shape:"dot",text:node.level});
|
||||
} else {
|
||||
node.child = spawn(gpioCommand, [node.out,node.pin,node.freq]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
}
|
||||
node.running = true;
|
||||
|
||||
node.on("input", inputlistener);
|
||||
node.on("input", inputlistener);
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("out: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.child = null;
|
||||
node.running = false;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
}
|
||||
}
|
||||
else {
|
||||
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
|
||||
node.on("input", function(msg){
|
||||
node.status({fill:"grey",shape:"dot",text:RED._("rpi-gpio.status.na",{value:msg.payload.toString()})});
|
||||
});
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
delete pinsInUse[node.pin];
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.stdin.write("close "+node.pin);
|
||||
node.child.kill('SIGKILL');
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
|
||||
}
|
||||
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
|
||||
|
||||
function PiMouseNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.butt = n.butt || 7;
|
||||
var node = this;
|
||||
|
||||
if (allOK === true) {
|
||||
node.child = spawn(gpioCommand+".py", ["mouse",node.butt]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("out: "+data+" :"); }
|
||||
data = Number(data);
|
||||
if (data !== 0) { node.send({ topic:"pi/mouse", button:data, payload:1 }); }
|
||||
else { node.send({ topic:"pi/mouse", button:data, payload:0 }); }
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
@@ -192,69 +270,19 @@ module.exports = function(RED) {
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.kill('SIGINT');
|
||||
node.child = null;
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
|
||||
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
delete pinsInUse[node.pin];
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.stdin.write("close "+node.pin);
|
||||
node.child.kill('SIGKILL');
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
|
||||
}
|
||||
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
|
||||
|
||||
function PiMouseNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.butt = n.butt || 7;
|
||||
var node = this;
|
||||
|
||||
node.child = spawn(gpioCommand+".py", ["mouse",node.butt]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
data = Number(data);
|
||||
if (data === 1) { node.send({ topic:"pi/mouse", button:data, payload:1 }); }
|
||||
else { node.send({ topic:"pi/mouse", button:data, payload:0 }); }
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.child = null;
|
||||
node.running = false;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
node.child.kill('SIGINT');
|
||||
node.child = null;
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("rpi-mouse",PiMouseNode);
|
||||
|
||||
@@ -262,39 +290,40 @@ module.exports = function(RED) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
|
||||
node.child = spawn(gpioCommand+".py", ["kbd","0"]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
if (allOK === true) {
|
||||
node.child = spawn(gpioCommand+".py", ["kbd","0"]);
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
|
||||
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var b = data.toString().trim().split(",");
|
||||
var act = "up";
|
||||
if (b[1] === "1") { act = "down"; }
|
||||
if (b[1] === "2") { act = "repeat"; }
|
||||
node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
|
||||
});
|
||||
node.child.stdout.on('data', function (data) {
|
||||
var b = data.toString().trim().split(",");
|
||||
var act = "up";
|
||||
if (b[1] === "1") { act = "down"; }
|
||||
if (b[1] === "2") { act = "repeat"; }
|
||||
node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
|
||||
});
|
||||
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
node.child.stderr.on('data', function (data) {
|
||||
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
|
||||
});
|
||||
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
node.child.on('close', function (code) {
|
||||
node.running = false;
|
||||
node.child = null;
|
||||
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
|
||||
if (node.done) {
|
||||
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
|
||||
node.done();
|
||||
}
|
||||
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
|
||||
});
|
||||
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
node.child.on('error', function (err) {
|
||||
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
|
||||
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
|
||||
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
|
||||
});
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.on("close", function(done) {
|
||||
node.status({});
|
||||
if (node.child != null) {
|
||||
node.done = done;
|
||||
@@ -303,24 +332,30 @@ module.exports = function(RED) {
|
||||
}
|
||||
else { done(); }
|
||||
});
|
||||
}
|
||||
else {
|
||||
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("rpi-keyboard",PiKeyboardNode);
|
||||
|
||||
var pitype = { type:"" };
|
||||
exec(gpioCommand+" info", function(err,stdout,stderr) {
|
||||
if (err) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.version"));
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var info = JSON.parse( stdout.trim().replace(/\'/g,"\"") );
|
||||
pitype.type = info["TYPE"];
|
||||
if (allOK === true) {
|
||||
exec(gpioCommand+" info", function(err,stdout,stderr) {
|
||||
if (err) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.version"));
|
||||
}
|
||||
catch(e) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.sawpitype"),stdout.trim());
|
||||
else {
|
||||
try {
|
||||
var info = JSON.parse( stdout.trim().replace(/\'/g,"\"") );
|
||||
pitype.type = info["TYPE"];
|
||||
}
|
||||
catch(e) {
|
||||
RED.log.info(RED._("rpi-gpio.errors.sawpitype"),stdout.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RED.httpAdmin.get('/rpi-gpio/:id', RED.auth.needsPermission('rpi-gpio.read'), function(req,res) {
|
||||
res.json(pitype);
|
||||
|
||||
@@ -23,10 +23,6 @@ from time import sleep
|
||||
|
||||
bounce = 25;
|
||||
|
||||
if sys.version_info >= (3,0):
|
||||
print("Sorry - currently only configured to work with python 2.x")
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) > 2:
|
||||
cmd = sys.argv[1].lower()
|
||||
pin = int(sys.argv[2])
|
||||
@@ -34,7 +30,7 @@ if len(sys.argv) > 2:
|
||||
GPIO.setwarnings(False)
|
||||
|
||||
if cmd == "pwm":
|
||||
#print "Initialised pin "+str(pin)+" to PWM"
|
||||
#print("Initialised pin "+str(pin)+" to PWM")
|
||||
try:
|
||||
freq = int(sys.argv[3])
|
||||
except:
|
||||
@@ -54,10 +50,10 @@ if len(sys.argv) > 2:
|
||||
GPIO.cleanup(pin)
|
||||
sys.exit(0)
|
||||
except Exception as ex:
|
||||
print "bad data: "+data
|
||||
print("bad data: "+data)
|
||||
|
||||
elif cmd == "buzz":
|
||||
#print "Initialised pin "+str(pin)+" to Buzz"
|
||||
#print("Initialised pin "+str(pin)+" to Buzz")
|
||||
GPIO.setup(pin,GPIO.OUT)
|
||||
p = GPIO.PWM(pin, 100)
|
||||
p.stop()
|
||||
@@ -76,10 +72,10 @@ if len(sys.argv) > 2:
|
||||
GPIO.cleanup(pin)
|
||||
sys.exit(0)
|
||||
except Exception as ex:
|
||||
print "bad data: "+data
|
||||
print("bad data: "+data)
|
||||
|
||||
elif cmd == "out":
|
||||
#print "Initialised pin "+str(pin)+" to OUT"
|
||||
#print("Initialised pin "+str(pin)+" to OUT")
|
||||
GPIO.setup(pin,GPIO.OUT)
|
||||
if len(sys.argv) == 4:
|
||||
GPIO.output(pin,int(sys.argv[3]))
|
||||
@@ -103,11 +99,11 @@ if len(sys.argv) > 2:
|
||||
GPIO.output(pin,data)
|
||||
|
||||
elif cmd == "in":
|
||||
#print "Initialised pin "+str(pin)+" to IN"
|
||||
#print("Initialised pin "+str(pin)+" to IN")
|
||||
bounce = float(sys.argv[4])
|
||||
def handle_callback(chan):
|
||||
sleep(bounce/1000.0)
|
||||
print GPIO.input(chan)
|
||||
print(GPIO.input(chan))
|
||||
|
||||
if sys.argv[3].lower() == "up":
|
||||
GPIO.setup(pin,GPIO.IN,GPIO.PUD_UP)
|
||||
@@ -116,7 +112,7 @@ if len(sys.argv) > 2:
|
||||
else:
|
||||
GPIO.setup(pin,GPIO.IN)
|
||||
|
||||
print GPIO.input(pin)
|
||||
print(GPIO.input(pin))
|
||||
GPIO.add_event_detect(pin, GPIO.BOTH, callback=handle_callback, bouncetime=int(bounce))
|
||||
|
||||
while True:
|
||||
@@ -129,7 +125,7 @@ if len(sys.argv) > 2:
|
||||
sys.exit(0)
|
||||
|
||||
elif cmd == "byte":
|
||||
#print "Initialised BYTE mode - "+str(pin)+
|
||||
#print("Initialised BYTE mode - "+str(pin)+)
|
||||
list = [7,11,13,12,15,16,18,22]
|
||||
GPIO.setup(list,GPIO.OUT)
|
||||
|
||||
@@ -152,7 +148,7 @@ if len(sys.argv) > 2:
|
||||
GPIO.output(list[bit], data & mask)
|
||||
|
||||
elif cmd == "borg":
|
||||
#print "Initialised BORG mode - "+str(pin)+
|
||||
#print("Initialised BORG mode - "+str(pin)+)
|
||||
GPIO.setup(11,GPIO.OUT)
|
||||
GPIO.setup(13,GPIO.OUT)
|
||||
GPIO.setup(15,GPIO.OUT)
|
||||
@@ -190,7 +186,7 @@ if len(sys.argv) > 2:
|
||||
button = ord( buf[0] ) & pin # mask out just the required button(s)
|
||||
if button != oldbutt: # only send if changed
|
||||
oldbutt = button
|
||||
print button
|
||||
print(button)
|
||||
|
||||
while True:
|
||||
try:
|
||||
@@ -215,7 +211,7 @@ if len(sys.argv) > 2:
|
||||
# type,code,value
|
||||
print("%u,%u" % (code, value))
|
||||
event = file.read(EVENT_SIZE)
|
||||
print "0,0"
|
||||
print("0,0")
|
||||
file.close()
|
||||
sys.exit(0)
|
||||
except:
|
||||
@@ -225,14 +221,14 @@ if len(sys.argv) > 2:
|
||||
elif len(sys.argv) > 1:
|
||||
cmd = sys.argv[1].lower()
|
||||
if cmd == "rev":
|
||||
print GPIO.RPI_REVISION
|
||||
print(GPIO.RPI_REVISION)
|
||||
elif cmd == "ver":
|
||||
print GPIO.VERSION
|
||||
print(GPIO.VERSION)
|
||||
elif cmd == "info":
|
||||
print GPIO.RPI_INFO
|
||||
print(GPIO.RPI_INFO)
|
||||
else:
|
||||
print "Bad parameters - in|out|pwm|buzz|byte|borg|mouse|kbd|ver|info {pin} {value|up|down}"
|
||||
print " only ver (gpio version) and info (board information) accept no pin parameter."
|
||||
print("Bad parameters - in|out|pwm|buzz|byte|borg|mouse|kbd|ver|info {pin} {value|up|down}")
|
||||
print(" only ver (gpio version) and info (board information) accept no pin parameter.")
|
||||
|
||||
else:
|
||||
print "Bad parameters - in|out|pwm|buzz|byte|borg|mouse|kbd|ver|info {pin} {value|up|down}"
|
||||
print("Bad parameters - in|out|pwm|buzz|byte|borg|mouse|kbd|ver|info {pin} {value|up|down}")
|
||||
|
||||
@@ -63,6 +63,11 @@
|
||||
<input type="checkbox" id="node-config-input-verifyservercert" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-config-input-verifyservercert" style="width: calc(100% - 170px);" data-i18n="tls.label.verify-server-cert"></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 120px;" for="node-config-input-servername"><i class="fa fa-server"></i> <span data-i18n="tls.label.servername"></span></label>
|
||||
<input style="width: calc(100% - 170px);" type="text" id="node-config-input-servername" data-i18n="[placeholder]tls.placeholder.servername">
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-row">
|
||||
<label style="width: 120px;" for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input style="width: calc(100% - 170px);" type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
|
||||
@@ -96,6 +101,7 @@
|
||||
certname: {value:""},
|
||||
keyname: {value:""},
|
||||
caname: {value:""},
|
||||
servername: {value:""},
|
||||
verifyservercert: {value: true}
|
||||
},
|
||||
credentials: {
|
||||
|
||||
@@ -25,6 +25,7 @@ module.exports = function(RED) {
|
||||
var certPath = n.cert.trim();
|
||||
var keyPath = n.key.trim();
|
||||
var caPath = n.ca.trim();
|
||||
this.servername = (n.servername||"").trim();
|
||||
|
||||
if ((certPath.length > 0) || (keyPath.length > 0)) {
|
||||
|
||||
@@ -102,6 +103,9 @@ module.exports = function(RED) {
|
||||
if (this.credentials && this.credentials.passphrase) {
|
||||
opts.passphrase = this.credentials.passphrase;
|
||||
}
|
||||
if (this.servername) {
|
||||
opts.servername = this.servername;
|
||||
}
|
||||
opts.rejectUnauthorized = this.verifyservercert;
|
||||
}
|
||||
return opts;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<dt>payload <span class="property-type">string | buffer</span></dt>
|
||||
<dd>a string unless detected as a binary buffer.</dd>
|
||||
<dt>topic <span class="property-type">string</span></dt>
|
||||
<dd>the MQTT topic, uses / as a heirarchy separator.</dd>
|
||||
<dd>the MQTT topic, uses / as a hierarchy separator.</dd>
|
||||
<dt>qos <span class="property-type">number</span> </dt>
|
||||
<dd>0, fire and forget - 1, at least once - 2, once and once only.</dd>
|
||||
<dt>retain <span class="property-type">boolean</span></dt>
|
||||
@@ -212,48 +212,84 @@
|
||||
<input type="password" id="node-config-input-password">
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-birth" style="display:none">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
|
||||
<div id="mqtt-broker-tab-messages" style="display:none">
|
||||
<div id="mqtt-broker-section-birth">
|
||||
<div class="palette-header">
|
||||
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.birth-message"></span>
|
||||
</div>
|
||||
<div class="section-content" style="padding:10px 0 0 10px">
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
|
||||
<select id="node-config-input-birthRetain" style="width:75px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-birthQos" style="width:75px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-birthQos" style="width:125px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
<i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span> <select id="node-config-input-birthRetain" style="width:125px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
<div id="mqtt-broker-section-close">
|
||||
<div class="palette-header">
|
||||
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.close-message"></span>
|
||||
</div>
|
||||
<div class="section-content" style="padding:10px 0 0 10px">
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-closeTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closeTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.close-topic">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
|
||||
<select id="node-config-input-closeRetain" style="width:75px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-closePayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closePayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-closeQos" style="width:75px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input type="text" id="node-config-input-birthPayload" data-i18n="[placeholder]common.label.payload">
|
||||
</div>
|
||||
</div>
|
||||
<div id="mqtt-broker-tab-will" style="display:none">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input type="text" id="node-config-input-willTopic" data-i18n="[placeholder]mqtt.placeholder.will-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-willQos" style="width:125px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
<i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span> <select id="node-config-input-willRetain" style="width:125px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input type="text" id="node-config-input-willPayload" data-i18n="[placeholder]common.label.payload">
|
||||
<div id="mqtt-broker-section-will">
|
||||
<div class="palette-header">
|
||||
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.will-message"></span>
|
||||
</div>
|
||||
<div class="section-content" style="padding:10px 0 0 10px">
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.will-topic">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
|
||||
<select id="node-config-input-willRetain" style="width:75px !important">
|
||||
<option value="false" data-i18n="mqtt.false"></option>
|
||||
<option value="true" data-i18n="mqtt.true"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width: 100px !important;" for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
|
||||
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
|
||||
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
|
||||
<select id="node-config-input-willQos" style="width:75px !important">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -269,6 +305,9 @@
|
||||
<h4>Birth Message</h4>
|
||||
<p>This is a message that will be published on the configured topic whenever the
|
||||
connection is established.</p>
|
||||
<h4>Close Message</h4>
|
||||
<p>This is a message that will be published on the configured topic before the
|
||||
connection is closed normally, either by re-deploying the node, or by shutting down.</p>
|
||||
<h4>Will Message</h4>
|
||||
<p>This is a message that will be published by the broker in the event the node
|
||||
unexpectedly loses its connection.</p>
|
||||
@@ -300,14 +339,18 @@
|
||||
compatmode: { value: true},
|
||||
keepalive: {value:60,validate:RED.validators.number()},
|
||||
cleansession: {value: true},
|
||||
willTopic: {value:""},
|
||||
willQos: {value:"0"},
|
||||
willRetain: {value:false},
|
||||
willPayload: {value:""},
|
||||
birthTopic: {value:""},
|
||||
birthQos: {value:"0"},
|
||||
birthRetain: {value:false},
|
||||
birthPayload: {value:""}
|
||||
birthPayload: {value:""},
|
||||
closeTopic: {value:""},
|
||||
closeQos: {value:"0"},
|
||||
closeRetain: {value:false},
|
||||
closePayload: {value:""},
|
||||
willTopic: {value:""},
|
||||
willQos: {value:"0"},
|
||||
willRetain: {value:false},
|
||||
willPayload: {value:""}
|
||||
},
|
||||
credentials: {
|
||||
user: {type:"text"},
|
||||
@@ -343,14 +386,39 @@
|
||||
id: "mqtt-broker-tab-security",
|
||||
label: this._("mqtt.tabs-label.security")
|
||||
});
|
||||
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-birth",
|
||||
label: this._("mqtt.tabs-label.birth")
|
||||
});
|
||||
tabs.addTab({
|
||||
id: "mqtt-broker-tab-will",
|
||||
label: this._("mqtt.tabs-label.will")
|
||||
id: "mqtt-broker-tab-messages",
|
||||
label: this._("mqtt.tabs-label.messages")
|
||||
});
|
||||
|
||||
function setUpSection(sectionId, isExpanded) {
|
||||
var birthMessageSection = $(sectionId);
|
||||
var paletteHeader = birthMessageSection.find('.palette-header');
|
||||
var twistie = paletteHeader.find('i');
|
||||
var sectionContent = birthMessageSection.find('.section-content');
|
||||
|
||||
function toggleSection(expanded) {
|
||||
twistie.toggleClass('expanded', expanded);
|
||||
sectionContent.toggle(expanded);
|
||||
}
|
||||
paletteHeader.click(function(e) {
|
||||
e.preventDefault();
|
||||
var isExpanded = twistie.hasClass('expanded');
|
||||
toggleSection(!isExpanded);
|
||||
});
|
||||
toggleSection(isExpanded);
|
||||
}
|
||||
|
||||
// show first section if none are set so the user gets the idea
|
||||
var showBirthSection = this.birthTopic !== ""
|
||||
|| this.willTopic === ""
|
||||
&& this.birthTopic === ""
|
||||
&& this.closeTopic == "";
|
||||
setUpSection('#mqtt-broker-section-birth', showBirthSection);
|
||||
setUpSection('#mqtt-broker-section-close', this.closeTopic !== "");
|
||||
setUpSection('#mqtt-broker-section-will', this.willTopic !== "");
|
||||
|
||||
setTimeout(function() { tabs.resize(); },0);
|
||||
if (typeof this.cleansession === 'undefined') {
|
||||
this.cleansession = true;
|
||||
@@ -368,14 +436,18 @@
|
||||
this.keepalive = 15;
|
||||
$("#node-config-input-keepalive").val(this.keepalive);
|
||||
}
|
||||
if (typeof this.willQos === 'undefined') {
|
||||
this.willQos = "0";
|
||||
$("#node-config-input-willQos").val("0");
|
||||
}
|
||||
if (typeof this.birthQos === 'undefined') {
|
||||
this.birthQos = "0";
|
||||
$("#node-config-input-birthQos").val("0");
|
||||
}
|
||||
if (typeof this.closeQos === 'undefined') {
|
||||
this.willQos = "0";
|
||||
$("#node-config-input-willQos").val("0");
|
||||
}
|
||||
if (typeof this.willQos === 'undefined') {
|
||||
this.willQos = "0";
|
||||
$("#node-config-input-willQos").val("0");
|
||||
}
|
||||
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-config-input-usetls").is(':checked')) {
|
||||
|
||||
@@ -60,6 +60,15 @@ module.exports = function(RED) {
|
||||
};
|
||||
}
|
||||
|
||||
if (n.closeTopic) {
|
||||
this.closeMessage = {
|
||||
topic: n.closeTopic,
|
||||
payload: n.closePayload || "",
|
||||
qos: Number(n.closeQos||0),
|
||||
retain: n.closeRetain=="true"|| n.closeRetain===true
|
||||
};
|
||||
}
|
||||
|
||||
if (this.credentials) {
|
||||
this.username = this.credentials.user;
|
||||
this.password = this.credentials.password;
|
||||
@@ -314,6 +323,10 @@ module.exports = function(RED) {
|
||||
this.on('close', function(done) {
|
||||
this.closing = true;
|
||||
if (this.connected) {
|
||||
// Send close message
|
||||
if (node.closeMessage) {
|
||||
node.publish(node.closeMessage);
|
||||
}
|
||||
this.client.once('close', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -21,8 +21,6 @@ module.exports = function(RED) {
|
||||
var cookieParser = require("cookie-parser");
|
||||
var getBody = require('raw-body');
|
||||
var cors = require('cors');
|
||||
var jsonParser = bodyParser.json();
|
||||
var urlencParser = bodyParser.urlencoded({extended:true});
|
||||
var onHeaders = require('on-headers');
|
||||
var typer = require('media-typer');
|
||||
var isUtf8 = require('is-utf8');
|
||||
@@ -212,6 +210,10 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxApiRequestSize = RED.settings.apiMaxLength || '5mb';
|
||||
var jsonParser = bodyParser.json({limit:maxApiRequestSize});
|
||||
var urlencParser = bodyParser.urlencoded({limit:maxApiRequestSize,extended:true});
|
||||
|
||||
var metricsHandler = function(req,res,next) { next(); }
|
||||
if (this.metric()) {
|
||||
metricsHandler = function(req, res, next) {
|
||||
|
||||
@@ -86,8 +86,10 @@
|
||||
<dt class="optional">payload</dt>
|
||||
<dd>Sent as the body of the request.</dd>
|
||||
<dt class="optional">rejectUnauthorized</dt>
|
||||
<dd>If set to <code>true</code>, allows requests to be made to https sites that use
|
||||
<dd>If set to <code>false</code>, allows requests to be made to https sites that use
|
||||
self signed certificates.</dd>
|
||||
<dt class="optional">followRedirects</dt>
|
||||
<dd>If set to <code>false</code> prevent following Redirect (HTTP 301).<code>true</code> by default</dd>
|
||||
</dl>
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var http = require("follow-redirects").http;
|
||||
var https = require("follow-redirects").https;
|
||||
var urllib = require("url");
|
||||
var request = require("request");
|
||||
var mustache = require("mustache");
|
||||
var querystring = require("querystring");
|
||||
var cookie = require("cookie");
|
||||
@@ -78,9 +76,13 @@ module.exports = function(RED) {
|
||||
if (msg.method && n.method && (n.method === "use")) {
|
||||
method = msg.method.toUpperCase(); // use the msg parameter
|
||||
}
|
||||
var opts = urllib.parse(url);
|
||||
var opts = {};
|
||||
opts.url = url;
|
||||
opts.timeout = node.reqTimeout;
|
||||
opts.method = method;
|
||||
opts.headers = {};
|
||||
opts.encoding = null; // Force NodeJs to return a Buffer (instead of a string)
|
||||
opts.maxRedirects = 21;
|
||||
var ctSet = "Content-Type"; // set default camel case
|
||||
var clSet = "Content-Length";
|
||||
if (msg.headers) {
|
||||
@@ -108,6 +110,9 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (msg.hasOwnProperty('followRedirects')) {
|
||||
opts.followRedirect = msg.followRedirects;
|
||||
}
|
||||
if (msg.cookies) {
|
||||
var cookies = [];
|
||||
if (opts.headers.hasOwnProperty('cookie')) {
|
||||
@@ -131,7 +136,10 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
if (this.credentials && this.credentials.user) {
|
||||
opts.auth = this.credentials.user+":"+(this.credentials.password||"");
|
||||
opts.auth = {
|
||||
user: this.credentials.user,
|
||||
pass: this.credentials.password||""
|
||||
};
|
||||
}
|
||||
var payload = null;
|
||||
|
||||
@@ -157,6 +165,7 @@ module.exports = function(RED) {
|
||||
opts.headers[clSet] = Buffer.byteLength(payload);
|
||||
}
|
||||
}
|
||||
opts.body = payload;
|
||||
}
|
||||
// revert to user supplied Capitalisation if needed.
|
||||
if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) {
|
||||
@@ -167,7 +176,6 @@ module.exports = function(RED) {
|
||||
opts.headers[clSet] = opts.headers['content-length'];
|
||||
delete opts.headers['content-length'];
|
||||
}
|
||||
var urltotest = url;
|
||||
var noproxy;
|
||||
if (noprox) {
|
||||
for (var i in noprox) {
|
||||
@@ -177,22 +185,11 @@ module.exports = function(RED) {
|
||||
if (prox && !noproxy) {
|
||||
var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i);
|
||||
if (match) {
|
||||
//opts.protocol = "http:";
|
||||
//opts.host = opts.hostname = match[2];
|
||||
//opts.port = (match[3] != null ? match[3] : 80);
|
||||
opts.headers['Host'] = opts.host;
|
||||
var heads = opts.headers;
|
||||
var path = opts.pathname = opts.href;
|
||||
opts = urllib.parse(prox);
|
||||
opts.path = opts.pathname = path;
|
||||
opts.headers = heads;
|
||||
opts.method = method;
|
||||
urltotest = match[0];
|
||||
if (opts.auth) {
|
||||
opts.headers['Proxy-Authorization'] = "Basic "+new Buffer(opts.auth).toString('Base64')
|
||||
}
|
||||
opts.proxy = prox;
|
||||
} else {
|
||||
node.warn("Bad proxy url: "+ prox);
|
||||
opts.proxy = null;
|
||||
}
|
||||
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
|
||||
}
|
||||
if (tlsNode) {
|
||||
tlsNode.addTLSOptions(opts);
|
||||
@@ -201,42 +198,37 @@ module.exports = function(RED) {
|
||||
opts.rejectUnauthorized = msg.rejectUnauthorized;
|
||||
}
|
||||
}
|
||||
var req = ((/^https/.test(urltotest))?https:http).request(opts,function(res) {
|
||||
// Force NodeJs to return a Buffer (instead of a string)
|
||||
// See https://github.com/nodejs/node/issues/6038
|
||||
res.setEncoding(null);
|
||||
delete res._readableState.decoder;
|
||||
|
||||
msg.statusCode = res.statusCode;
|
||||
msg.headers = res.headers;
|
||||
msg.responseUrl = res.responseUrl;
|
||||
msg.payload = [];
|
||||
|
||||
if (msg.headers.hasOwnProperty('set-cookie')) {
|
||||
msg.responseCookies = {};
|
||||
msg.headers['set-cookie'].forEach(function(c) {
|
||||
var parsedCookie = cookie.parse(c);
|
||||
var eq_idx = c.indexOf('=');
|
||||
var key = c.substr(0, eq_idx).trim()
|
||||
parsedCookie.value = parsedCookie[key];
|
||||
delete parsedCookie[key];
|
||||
msg.responseCookies[key] = parsedCookie;
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
|
||||
// msg.url = url; // revert when warning above finally removed
|
||||
res.on('data',function(chunk) {
|
||||
if (!Buffer.isBuffer(chunk)) {
|
||||
// if the 'setEncoding(null)' fix above stops working in
|
||||
// a new Node.js release, throw a noisy error so we know
|
||||
// about it.
|
||||
throw new Error("HTTP Request data chunk not a Buffer");
|
||||
request(opts, function(err, res, body) {
|
||||
if(err){
|
||||
if(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') {
|
||||
node.error(RED._("common.notification.errors.no-response"), msg);
|
||||
node.status({fill:"red", shape:"ring", text:"common.notification.errors.no-response"});
|
||||
}else{
|
||||
node.error(err,msg);
|
||||
node.status({fill:"red", shape:"ring", text:err.code});
|
||||
}
|
||||
msg.payload.push(chunk);
|
||||
});
|
||||
res.on('end',function() {
|
||||
msg.payload = err.toString() + " : " + url;
|
||||
msg.statusCode = err.code;
|
||||
node.send(msg);
|
||||
}else{
|
||||
msg.statusCode = res.statusCode;
|
||||
msg.headers = res.headers;
|
||||
msg.responseUrl = res.request.uri.href;
|
||||
msg.payload = body;
|
||||
|
||||
if (msg.headers.hasOwnProperty('set-cookie')) {
|
||||
msg.responseCookies = {};
|
||||
msg.headers['set-cookie'].forEach(function(c) {
|
||||
var parsedCookie = cookie.parse(c);
|
||||
var eq_idx = c.indexOf('=');
|
||||
var key = c.substr(0, eq_idx).trim()
|
||||
parsedCookie.value = parsedCookie[key];
|
||||
delete parsedCookie[key];
|
||||
msg.responseCookies[key] = parsedCookie;
|
||||
});
|
||||
}
|
||||
msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
|
||||
// msg.url = url; // revert when warning above finally removed
|
||||
if (node.metric()) {
|
||||
// Calculate request time
|
||||
var diff = process.hrtime(preRequestTimestamp);
|
||||
@@ -248,44 +240,19 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check that msg.payload is an array - if the req error
|
||||
// handler has been called, it will have been set to a string
|
||||
// and the error already handled - so no further action should
|
||||
// be taken. #1344
|
||||
if (Array.isArray(msg.payload)) {
|
||||
// Convert the payload to the required return type
|
||||
msg.payload = Buffer.concat(msg.payload); // bin
|
||||
if (node.ret !== "bin") {
|
||||
msg.payload = msg.payload.toString('utf8'); // txt
|
||||
// Convert the payload to the required return type
|
||||
if (node.ret !== "bin") {
|
||||
msg.payload = msg.payload.toString('utf8'); // txt
|
||||
|
||||
if (node.ret === "obj") {
|
||||
try { msg.payload = JSON.parse(msg.payload); } // obj
|
||||
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
|
||||
}
|
||||
if (node.ret === "obj") {
|
||||
try { msg.payload = JSON.parse(msg.payload); } // obj
|
||||
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
|
||||
}
|
||||
node.status({});
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
node.status({});
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
req.setTimeout(node.reqTimeout, function() {
|
||||
node.error(RED._("common.notification.errors.no-response"),msg);
|
||||
setTimeout(function() {
|
||||
node.status({fill:"red",shape:"ring",text:"common.notification.errors.no-response"});
|
||||
},10);
|
||||
req.abort();
|
||||
});
|
||||
req.on('error',function(err) {
|
||||
node.error(err,msg);
|
||||
msg.payload = err.toString() + " : " + url;
|
||||
msg.statusCode = err.code;
|
||||
node.status({fill:"red",shape:"ring",text:err.code});
|
||||
node.send(msg);
|
||||
});
|
||||
if (payload) {
|
||||
req.write(payload);
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
|
||||
this.on("close",function() {
|
||||
|
||||
@@ -212,11 +212,11 @@ module.exports = function(RED) {
|
||||
if (this.serverConfig) {
|
||||
this.serverConfig.registerInputNode(this);
|
||||
// TODO: nls
|
||||
this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:"connected "+n}); });
|
||||
this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"error"}); });
|
||||
this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})}); });
|
||||
this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"common.status.error"}); });
|
||||
this.serverConfig.on('closed', function(n) {
|
||||
if (n > 0) { node.status({fill:"green",shape:"dot",text:"connected "+n}); }
|
||||
else { node.status({fill:"red",shape:"ring",text:"disconnected"}); }
|
||||
if (n > 0) { node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})}); }
|
||||
else { node.status({fill:"red",shape:"ring",text:"common.status.disconnected"}); }
|
||||
});
|
||||
} else {
|
||||
this.error(RED._("websocket.errors.missing-conf"));
|
||||
@@ -240,11 +240,11 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
// TODO: nls
|
||||
this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:"connected "+n}); });
|
||||
this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"error"}); });
|
||||
this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})}); });
|
||||
this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"common.status.error"}); });
|
||||
this.serverConfig.on('closed', function(n) {
|
||||
if (n > 0) { node.status({fill:"green",shape:"dot",text:"connected "+n}); }
|
||||
else { node.status({fill:"red",shape:"ring",text:"disconnected"}); }
|
||||
if (n > 0) { node.status({fill:"green",shape:"dot",text:RED._("websocket.status.connected",{count:n})}); }
|
||||
else { node.status({fill:"red",shape:"ring",text:"common.status.disconnected"}); }
|
||||
});
|
||||
}
|
||||
this.on("input", function(msg) {
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
outputs:1,
|
||||
icon: "watch.png",
|
||||
label: function() {
|
||||
return this.name||this.files;
|
||||
return this.name||this.files||this._("watch.watch");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
|
||||
@@ -18,10 +18,36 @@ module.exports = function(RED) {
|
||||
"use strict";
|
||||
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||
var socketTimeout = RED.settings.socketTimeout||null;
|
||||
const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
|
||||
const Denque = require('denque');
|
||||
var net = require('net');
|
||||
|
||||
var connectionPool = {};
|
||||
|
||||
/**
|
||||
* Enqueue `item` in `queue`
|
||||
* @param {Denque} queue - Queue
|
||||
* @param {*} item - Item to enqueue
|
||||
* @private
|
||||
* @returns {Denque} `queue`
|
||||
*/
|
||||
const enqueue = (queue, item) => {
|
||||
// drop msgs from front of queue if size is going to be exceeded
|
||||
if (queue.size() === msgQueueSize) {
|
||||
queue.shift();
|
||||
}
|
||||
queue.push(item);
|
||||
return queue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shifts item off front of queue
|
||||
* @param {Deque} queue - Queue
|
||||
* @private
|
||||
* @returns {*} Item previously at front of queue
|
||||
*/
|
||||
const dequeue = queue => queue.shift();
|
||||
|
||||
function TcpIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.host = n.host;
|
||||
@@ -130,6 +156,8 @@ module.exports = function(RED) {
|
||||
socket.setKeepAlive(true,120000);
|
||||
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
|
||||
var id = (1+Math.random()*4294967295).toString(16);
|
||||
var fromi;
|
||||
var fromp;
|
||||
connectionPool[id] = socket;
|
||||
count++;
|
||||
node.status({text:RED._("tcpin.status.connections",{count:count})});
|
||||
@@ -155,18 +183,21 @@ module.exports = function(RED) {
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if ((typeof data) === "string") {
|
||||
buffer = buffer+data;
|
||||
} else {
|
||||
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||
}
|
||||
fromi = socket.remoteAddress;
|
||||
fromp = socket.remotePort;
|
||||
}
|
||||
});
|
||||
socket.on('end', function() {
|
||||
if (!node.stream || (node.datatype === "utf8" && node.newline !== "")) {
|
||||
if (buffer.length > 0) {
|
||||
var msg = {topic:node.topic, payload:buffer, ip:socket.remoteAddress, port:socket.remotePort};
|
||||
var msg = {topic:node.topic, payload:buffer, ip:fromi, port:fromp};
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
@@ -430,11 +461,14 @@ module.exports = function(RED) {
|
||||
// the clients object will have:
|
||||
// clients[id].client, clients[id].msg, clients[id].timeout
|
||||
var connection_id = host + ":" + port;
|
||||
clients[connection_id] = clients[connection_id] || {};
|
||||
clients[connection_id].msg = msg;
|
||||
clients[connection_id].connected = clients[connection_id].connected || false;
|
||||
clients[connection_id] = clients[connection_id] || {
|
||||
msgQueue: new Denque(),
|
||||
connected: false,
|
||||
connecting: false
|
||||
};
|
||||
enqueue(clients[connection_id].msgQueue, msg);
|
||||
|
||||
if (!clients[connection_id].connected) {
|
||||
if (!clients[connection_id].connecting && !clients[connection_id].connected) {
|
||||
var buf;
|
||||
if (this.out == "count") {
|
||||
if (this.splitc === 0) { buf = Buffer.alloc(1); }
|
||||
@@ -446,14 +480,19 @@ module.exports = function(RED) {
|
||||
if (socketTimeout !== null) { clients[connection_id].client.setTimeout(socketTimeout);}
|
||||
|
||||
if (host && port) {
|
||||
clients[connection_id].connecting = true;
|
||||
clients[connection_id].client.connect(port, host, function() {
|
||||
//node.log(RED._("tcpin.errors.client-connected"));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
if (clients[connection_id] && clients[connection_id].client) {
|
||||
clients[connection_id].connected = true;
|
||||
clients[connection_id].client.write(clients[connection_id].msg.payload);
|
||||
clients[connection_id].connecting = false;
|
||||
let msg;
|
||||
while (msg = dequeue(clients[connection_id].msgQueue)) {
|
||||
clients[connection_id].client.write(msg.payload);
|
||||
}
|
||||
if (node.out === "time" && node.splitc < 0) {
|
||||
clients[connection_id].connected = false;
|
||||
clients[connection_id].connected = clients[connection_id].connecting = false;
|
||||
clients[connection_id].client.end();
|
||||
delete clients[connection_id];
|
||||
node.status({});
|
||||
@@ -468,9 +507,10 @@ module.exports = function(RED) {
|
||||
clients[connection_id].client.on('data', function(data) {
|
||||
if (node.out === "sit") { // if we are staying connected just send the buffer
|
||||
if (clients[connection_id]) {
|
||||
if (!clients[connection_id].hasOwnProperty("msg")) { clients[connection_id].msg = {}; }
|
||||
clients[connection_id].msg.payload = data;
|
||||
node.send(RED.util.cloneMessage(clients[connection_id].msg));
|
||||
let msg = dequeue(clients[connection_id].msgQueue) || {};
|
||||
clients[connection_id].msgQueue.unshift(msg);
|
||||
msg.payload = data;
|
||||
node.send(RED.util.cloneMessage(msg));
|
||||
}
|
||||
}
|
||||
// else if (node.splitc === 0) {
|
||||
@@ -490,9 +530,11 @@ module.exports = function(RED) {
|
||||
clients[connection_id].timeout = setTimeout(function () {
|
||||
if (clients[connection_id]) {
|
||||
clients[connection_id].timeout = null;
|
||||
clients[connection_id].msg.payload = Buffer.alloc(i+1);
|
||||
buf.copy(clients[connection_id].msg.payload,0,0,i+1);
|
||||
node.send(clients[connection_id].msg);
|
||||
let msg = dequeue(clients[connection_id].msgQueue) || {};
|
||||
clients[connection_id].msgQueue.unshift(msg);
|
||||
msg.payload = Buffer.alloc(i+1);
|
||||
buf.copy(msg.payload,0,0,i+1);
|
||||
node.send(msg);
|
||||
if (clients[connection_id].client) {
|
||||
node.status({});
|
||||
clients[connection_id].client.destroy();
|
||||
@@ -511,9 +553,11 @@ module.exports = function(RED) {
|
||||
i += 1;
|
||||
if ( i >= node.splitc) {
|
||||
if (clients[connection_id]) {
|
||||
clients[connection_id].msg.payload = Buffer.alloc(i);
|
||||
buf.copy(clients[connection_id].msg.payload,0,0,i);
|
||||
node.send(clients[connection_id].msg);
|
||||
let msg = dequeue(clients[connection_id].msgQueue) || {};
|
||||
clients[connection_id].msgQueue.unshift(msg);
|
||||
msg.payload = Buffer.alloc(i);
|
||||
buf.copy(msg.payload,0,0,i);
|
||||
node.send(msg);
|
||||
if (clients[connection_id].client) {
|
||||
node.status({});
|
||||
clients[connection_id].client.destroy();
|
||||
@@ -529,9 +573,11 @@ module.exports = function(RED) {
|
||||
i += 1;
|
||||
if (data[j] == node.splitc) {
|
||||
if (clients[connection_id]) {
|
||||
clients[connection_id].msg.payload = Buffer.alloc(i);
|
||||
buf.copy(clients[connection_id].msg.payload,0,0,i);
|
||||
node.send(clients[connection_id].msg);
|
||||
let msg = dequeue(clients[connection_id].msgQueue) || {};
|
||||
clients[connection_id].msgQueue.unshift(msg);
|
||||
msg.payload = Buffer.alloc(i);
|
||||
buf.copy(msg.payload,0,0,i);
|
||||
node.send(msg);
|
||||
if (clients[connection_id].client) {
|
||||
node.status({});
|
||||
clients[connection_id].client.destroy();
|
||||
@@ -549,7 +595,7 @@ module.exports = function(RED) {
|
||||
//console.log("END");
|
||||
node.status({fill:"grey",shape:"ring",text:"common.status.disconnected"});
|
||||
if (clients[connection_id] && clients[connection_id].client) {
|
||||
clients[connection_id].connected = false;
|
||||
clients[connection_id].connected = clients[connection_id].connecting = false;
|
||||
clients[connection_id].client = null;
|
||||
}
|
||||
});
|
||||
@@ -557,7 +603,7 @@ module.exports = function(RED) {
|
||||
clients[connection_id].client.on('close', function() {
|
||||
//console.log("CLOSE");
|
||||
if (clients[connection_id]) {
|
||||
clients[connection_id].connected = false;
|
||||
clients[connection_id].connected = clients[connection_id].connecting = false;
|
||||
}
|
||||
|
||||
var anyConnected = false;
|
||||
@@ -587,21 +633,23 @@ module.exports = function(RED) {
|
||||
clients[connection_id].client.on('timeout',function() {
|
||||
//console.log("TIMEOUT");
|
||||
if (clients[connection_id]) {
|
||||
clients[connection_id].connected = false;
|
||||
clients[connection_id].connected = clients[connection_id].connecting = false;
|
||||
node.status({fill:"grey",shape:"dot",text:"tcpin.errors.connect-timeout"});
|
||||
//node.warn(RED._("tcpin.errors.connect-timeout"));
|
||||
if (clients[connection_id].client) {
|
||||
clients[connection_id].connecting = true;
|
||||
clients[connection_id].client.connect(port, host, function() {
|
||||
clients[connection_id].connected = true;
|
||||
clients[connection_id].connecting = false;
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
else if (!clients[connection_id].connecting && clients[connection_id].connected) {
|
||||
if (clients[connection_id] && clients[connection_id].client) {
|
||||
clients[connection_id].client.write(clients[connection_id].msg.payload);
|
||||
clients[connection_id].client.write(dequeue(clients[connection_id].msgQueue));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</div>
|
||||
<div class="form-row node-input-iface">
|
||||
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
|
||||
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.label.interfaceprompt">
|
||||
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.placeholder.interfaceprompt">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.onport"></span></label>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var os = require('os');
|
||||
var dgram = require('dgram');
|
||||
var udpInputPortsInUse = {};
|
||||
|
||||
@@ -30,6 +31,29 @@ module.exports = function(RED) {
|
||||
this.ipv = n.ipv || "udp4";
|
||||
var node = this;
|
||||
|
||||
if (node.iface && node.iface.indexOf(".") === -1) {
|
||||
try {
|
||||
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
|
||||
node.iface = null;
|
||||
}
|
||||
}
|
||||
|
||||
var opts = {type:node.ipv, reuseAddr:true};
|
||||
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
|
||||
var server;
|
||||
@@ -39,7 +63,7 @@ module.exports = function(RED) {
|
||||
udpInputPortsInUse[this.port] = server;
|
||||
}
|
||||
else {
|
||||
node.warn(RED._("udp.errors.alreadyused",node.port));
|
||||
node.log(RED._("udp.errors.alreadyused",{port:node.port}));
|
||||
server = udpInputPortsInUse[this.port]; // re-use existing
|
||||
}
|
||||
|
||||
@@ -121,12 +145,37 @@ module.exports = function(RED) {
|
||||
this.ipv = n.ipv || "udp4";
|
||||
var node = this;
|
||||
|
||||
if (node.iface && node.iface.indexOf(".") === -1) {
|
||||
try {
|
||||
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node.ipv === "udp4") {
|
||||
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||
} else {
|
||||
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
|
||||
node.iface = null;
|
||||
}
|
||||
}
|
||||
|
||||
var opts = {type:node.ipv, reuseAddr:true};
|
||||
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
|
||||
|
||||
var sock;
|
||||
if (udpInputPortsInUse[this.outport || this.port]) {
|
||||
sock = udpInputPortsInUse[this.outport || this.port];
|
||||
var p = this.outport || this.port || "0";
|
||||
if (udpInputPortsInUse[p]) {
|
||||
sock = udpInputPortsInUse[p];
|
||||
node.log(RED._("udp.status.re-use",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
}
|
||||
else {
|
||||
sock = dgram.createSocket(opts); // default to udp4
|
||||
@@ -136,36 +185,35 @@ module.exports = function(RED) {
|
||||
// prevent it going to the global error handler and shutting node-red
|
||||
// down.
|
||||
});
|
||||
udpInputPortsInUse[this.outport || this.port] = sock;
|
||||
}
|
||||
udpInputPortsInUse[p] = sock;
|
||||
|
||||
if (node.multicast != "false") {
|
||||
if (node.outport === "") { node.outport = node.port; }
|
||||
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
if (node.multicast == "multi") {
|
||||
try {
|
||||
sock.setMulticastTTL(128);
|
||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||
node.log(RED._("udp.status.mc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
} catch (e) {
|
||||
if (e.errno == "EINVAL") {
|
||||
node.error(RED._("udp.errors.bad-mcaddress"));
|
||||
} else if (e.errno == "ENODEV") {
|
||||
node.error(RED._("udp.errors.interface"));
|
||||
} else {
|
||||
node.error(RED._("udp.errors.error",{error:e.errno}));
|
||||
if (node.multicast != "false") {
|
||||
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
if (node.multicast == "multi") {
|
||||
try {
|
||||
sock.setMulticastTTL(128);
|
||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||
node.log(RED._("udp.status.mc-ready",{iface:node.iface,outport:node.outport,host:node.addr,port:node.port}));
|
||||
} catch (e) {
|
||||
if (e.errno == "EINVAL") {
|
||||
node.error(RED._("udp.errors.bad-mcaddress"));
|
||||
} else if (e.errno == "ENODEV") {
|
||||
node.error(RED._("udp.errors.interface"));
|
||||
} else {
|
||||
node.error(RED._("udp.errors.error",{error:e.errno}));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
}
|
||||
} else {
|
||||
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
}
|
||||
});
|
||||
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
|
||||
sock.bind(node.outport);
|
||||
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
} else {
|
||||
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
|
||||
});
|
||||
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
|
||||
sock.bind(node.outport);
|
||||
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||
} else {
|
||||
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
|
||||
}
|
||||
}
|
||||
|
||||
node.on("input", function(msg) {
|
||||
@@ -198,8 +246,8 @@ module.exports = function(RED) {
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
if (udpInputPortsInUse.hasOwnProperty(node.outport || node.port)) {
|
||||
delete udpInputPortsInUse[node.outport || node.port];
|
||||
if (udpInputPortsInUse.hasOwnProperty(p)) {
|
||||
delete udpInputPortsInUse[p];
|
||||
}
|
||||
try {
|
||||
sock.close();
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
}
|
||||
},
|
||||
"catch": {
|
||||
"catch": "catch all",
|
||||
"catchNodes": "catch (__number__)",
|
||||
"catch": "catch: all",
|
||||
"catchNodes": "catch: __number__",
|
||||
"label": {
|
||||
"source": "Catch errors from",
|
||||
"node": "node",
|
||||
@@ -86,8 +86,8 @@
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"status": "status (all)",
|
||||
"statusNodes": "status (__number__)",
|
||||
"status": "status: all",
|
||||
"statusNodes": "status: __number__",
|
||||
"label": {
|
||||
"source": "Report status from",
|
||||
"node": "node",
|
||||
@@ -153,19 +153,23 @@
|
||||
"key": "Private Key",
|
||||
"passphrase": "Passphrase",
|
||||
"ca": "CA Certificate",
|
||||
"verify-server-cert":"Verify server certificate"
|
||||
"verify-server-cert":"Verify server certificate",
|
||||
"servername": "Server Name"
|
||||
},
|
||||
"placeholder": {
|
||||
"cert":"path to certificate (PEM format)",
|
||||
"key":"path to private key (PEM format)",
|
||||
"ca":"path to CA certificate (PEM format)",
|
||||
"passphrase":"private key passphrase (optional)"
|
||||
"passphrase":"private key passphrase (optional)",
|
||||
"servername":"for use with SNI"
|
||||
},
|
||||
"error": {
|
||||
"missing-file": "No certificate/key file provided"
|
||||
}
|
||||
},
|
||||
"exec": {
|
||||
"exec": "exec",
|
||||
"spawn": "spawn",
|
||||
"label": {
|
||||
"command": "Command",
|
||||
"append": "Append",
|
||||
@@ -184,6 +188,7 @@
|
||||
"oldrc": "Use old style output (compatibility mode)"
|
||||
},
|
||||
"function": {
|
||||
"function": "",
|
||||
"label": {
|
||||
"function": "Function",
|
||||
"outputs": "Outputs"
|
||||
@@ -195,6 +200,7 @@
|
||||
"tip": "See the Info tab for help writing functions."
|
||||
},
|
||||
"template": {
|
||||
"template": "template",
|
||||
"label": {
|
||||
"template": "Template",
|
||||
"property": "Set property",
|
||||
@@ -301,6 +307,7 @@
|
||||
}
|
||||
},
|
||||
"comment": {
|
||||
"comment": "comment",
|
||||
"label": {
|
||||
"title": "Title",
|
||||
"body": "Body"
|
||||
@@ -318,6 +325,7 @@
|
||||
"broker": "Server",
|
||||
"example": "e.g. localhost",
|
||||
"qos": "QoS",
|
||||
"retain": "Retain",
|
||||
"clientid": "Client ID",
|
||||
"port": "Port",
|
||||
"keepalive": "Keep alive time (s)",
|
||||
@@ -327,17 +335,22 @@
|
||||
"verify-server-cert":"Verify server certificate",
|
||||
"compatmode": "Use legacy MQTT 3.1 support"
|
||||
},
|
||||
"sections-label":{
|
||||
"birth-message": "Message sent on connection (birth message)",
|
||||
"will-message":"Message sent on an unexpected disconnection (will message)",
|
||||
"close-message":"Message sent before disconnecting (close message)"
|
||||
},
|
||||
"tabs-label": {
|
||||
"connection": "Connection",
|
||||
"security": "Security",
|
||||
"will": "Will Message",
|
||||
"birth": "Birth Message"
|
||||
"messages": "Messages"
|
||||
},
|
||||
"placeholder": {
|
||||
"clientid": "Leave blank for auto generated",
|
||||
"clientid-nonclean":"Must be set for non-clean sessions",
|
||||
"will-topic": "Leave blank to disable will message",
|
||||
"birth-topic": "Leave blank to disable birth message"
|
||||
"birth-topic": "Leave blank to disable birth message",
|
||||
"close-topic": "Leave blank to disable close message"
|
||||
},
|
||||
"state": {
|
||||
"connected": "Connected to broker: __broker__",
|
||||
@@ -409,6 +422,10 @@
|
||||
"url1": "URL should use ws:// or wss:// scheme and point to an existing websocket listener.",
|
||||
"url2": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The client can be configured to send or receive the entire message object as a JSON formatted string."
|
||||
},
|
||||
"status": {
|
||||
"connected": "connected __count__",
|
||||
"connected_plural": "connected __count__"
|
||||
},
|
||||
"errors": {
|
||||
"connect-error": "An error occured on the ws connection: ",
|
||||
"send-error": "An error occurred while sending: ",
|
||||
@@ -416,6 +433,7 @@
|
||||
}
|
||||
},
|
||||
"watch": {
|
||||
"watch": "watch",
|
||||
"label": {
|
||||
"files": "File(s)",
|
||||
"recursive": "Watch sub-directories recursively"
|
||||
@@ -489,15 +507,15 @@
|
||||
"using": "using",
|
||||
"output": "Output",
|
||||
"group": "Group",
|
||||
"interface": "Local IP",
|
||||
"interfaceprompt": "(optional) local ip address to bind to",
|
||||
"interface": "Local IF",
|
||||
"send": "Send a",
|
||||
"toport": "to port",
|
||||
"address": "Address",
|
||||
"decode-base64": "Decode Base64 encoded payload?"
|
||||
},
|
||||
"placeholder": {
|
||||
"interface": "(optional) ip address of eth0",
|
||||
"interface": "(optional) local interface or address to bind to",
|
||||
"interfaceprompt": "(optional) local interface or address to bind to",
|
||||
"address": "destination ip"
|
||||
},
|
||||
"udpmsgs": "udp messages",
|
||||
@@ -525,10 +543,11 @@
|
||||
"mc-group": "udp multicast group __group__",
|
||||
"listener-stopped": "udp listener stopped",
|
||||
"output-stopped": "udp output stopped",
|
||||
"mc-ready": "udp multicast ready: __outport__ -> __host__:__port__",
|
||||
"mc-ready": "udp multicast ready: __iface__:__outport__ -> __host__:__port__",
|
||||
"bc-ready": "udp broadcast ready: __outport__ -> __host__:__port__",
|
||||
"ready": "udp ready: __outport__ -> __host__:__port__",
|
||||
"ready-nolocal": "udp ready: __host__:__port__"
|
||||
"ready-nolocal": "udp ready: __host__:__port__",
|
||||
"re-use": "udp re-use socket: __outport__ -> __host__:__port__"
|
||||
},
|
||||
"errors": {
|
||||
"access-error": "UDP access error, you may need root access for ports below 1024",
|
||||
@@ -538,10 +557,12 @@
|
||||
"ip-notset": "udp: ip address not set",
|
||||
"port-notset": "udp: port not set",
|
||||
"port-invalid": "udp: port number not valid",
|
||||
"alreadyused": "udp: port already in use"
|
||||
"alreadyused": "udp: port __port__ already in use",
|
||||
"ifnotfound": "udp: interface __iface__ not found"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
"switch": "switch",
|
||||
"label": {
|
||||
"property": "Property",
|
||||
"rule": "rule",
|
||||
@@ -559,6 +580,9 @@
|
||||
"false":"is false",
|
||||
"null":"is null",
|
||||
"nnull":"is not null",
|
||||
"istype":"is of type",
|
||||
"empty":"is empty",
|
||||
"nempty":"is not empty",
|
||||
"head":"head",
|
||||
"tail":"tail",
|
||||
"index":"index between",
|
||||
@@ -597,6 +621,7 @@
|
||||
}
|
||||
},
|
||||
"range": {
|
||||
"range": "range",
|
||||
"label": {
|
||||
"action": "Action",
|
||||
"inputrange": "Map the input range",
|
||||
@@ -663,7 +688,8 @@
|
||||
"html": {
|
||||
"label": {
|
||||
"select": "Selector",
|
||||
"output": "Output"
|
||||
"output": "Output",
|
||||
"in": "in"
|
||||
},
|
||||
"output": {
|
||||
"html": "the html content of the elements",
|
||||
@@ -679,7 +705,9 @@
|
||||
"errors": {
|
||||
"dropped-object": "Ignored non-object payload",
|
||||
"dropped": "Ignored unsupported payload type",
|
||||
"dropped-error": "Failed to convert payload"
|
||||
"dropped-error": "Failed to convert payload",
|
||||
"schema-error": "JSON Schema error",
|
||||
"schema-error-compile": "JSON Schema error: failed to compile schema"
|
||||
},
|
||||
"label": {
|
||||
"o2j": "Object to JSON options",
|
||||
@@ -763,11 +791,13 @@
|
||||
"status": {
|
||||
"stopped": "stopped",
|
||||
"closed": "closed",
|
||||
"not-running": "not running"
|
||||
"not-running": "not running",
|
||||
"not-available": "not available",
|
||||
"na": "N/A : __value__"
|
||||
},
|
||||
"errors": {
|
||||
"ignorenode": "Ignoring Raspberry Pi specific node",
|
||||
"version": "Version command failed",
|
||||
"ignorenode": "Raspberry Pi specific node set inactive",
|
||||
"version": "Failed to get version from Pi",
|
||||
"sawpitype": "Saw Pi Type",
|
||||
"libnotfound": "Cannot find Pi RPi.GPIO python library",
|
||||
"alreadyset": "GPIO pin __pin__ already set as type: __type__",
|
||||
@@ -782,6 +812,7 @@
|
||||
}
|
||||
},
|
||||
"tail": {
|
||||
"tail": "tail",
|
||||
"label": {
|
||||
"filename": "Filename",
|
||||
"type": "File type",
|
||||
@@ -835,6 +866,7 @@
|
||||
"tip": "Tip: The filename should be an absolute path, otherwise it will be relative to the working directory of the Node-RED process."
|
||||
},
|
||||
"split": {
|
||||
"split": "split",
|
||||
"intro":"Split <code>msg.payload</code> based on type:",
|
||||
"object":"<b>Object</b>",
|
||||
"objectSend":"Send a message for each key/value pair",
|
||||
@@ -846,6 +878,7 @@
|
||||
"addname":" Copy key to "
|
||||
},
|
||||
"join":{
|
||||
"join": "join",
|
||||
"mode":{
|
||||
"mode":"Mode",
|
||||
"auto":"automatic",
|
||||
@@ -892,6 +925,7 @@
|
||||
}
|
||||
},
|
||||
"sort" : {
|
||||
"sort": "sort",
|
||||
"target" : "Sort",
|
||||
"seq" : "message sequence",
|
||||
"key" : "Key",
|
||||
@@ -900,11 +934,12 @@
|
||||
"ascending" : "ascending",
|
||||
"descending" : "descending",
|
||||
"as-number" : "as number",
|
||||
"invalid-exp" : "invalid JSONata expression in sort node",
|
||||
"too-many" : "too many pending messages in sort node",
|
||||
"invalid-exp" : "Invalid JSONata expression in sort node: __message__",
|
||||
"too-many" : "Too many pending messages in sort node",
|
||||
"clear" : "clear pending message in sort node"
|
||||
},
|
||||
"batch" : {
|
||||
"batch": "batch",
|
||||
"mode": {
|
||||
"label" : "Mode",
|
||||
"num-msgs" : "Group by number of messages",
|
||||
|
||||
35
nodes/core/locales/ja/analysis/72-sentiment.html
Normal file
35
nodes/core/locales/ja/analysis/72-sentiment.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>指定したプロパティ(デフォルトは<code>payload</code>)を分析し、<code>sentiment</code>オブジェクトを追加します。</p>
|
||||
<h3>出力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>sentiment <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>AFINN-111による感情分析の結果</dd>
|
||||
<dt>sentiment.score <span class="property-type">数値</span></dt>
|
||||
<dd>感情分析スコア</dd>
|
||||
</dl>
|
||||
<h3>入力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>overrides <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>単語スコアの上書きをするためのオブジェクト - <code>{ word:score,... }</code></dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>ゼロ以上のスコアはポジティブ、ゼロ以下はネガティブを意味します。</p>
|
||||
<p>スコアの範囲は通常-5から+5ですが、より大きかったり小さかったりすることもあります。</p>
|
||||
<p>詳細は<a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>を参照してください。</p>
|
||||
</script>
|
||||
34
nodes/core/locales/ja/core/20-inject.html
Normal file
34
nodes/core/locales/ja/core/20-inject.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="inject">
|
||||
<p>手動もしくは一定間隔でメッセージをフローに注入します。メッセージのペイロードには、文字列、JavaScriptオブジェクト、現在の時刻など、さまざまな値を指定できます。</p>
|
||||
<h3>出力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload<span class="property-type">各種</span></dt>
|
||||
<dd>指定したメッセージペイロード。</dd>
|
||||
<dt class="optional">topic <span class="property-type">文字列</span></dt>
|
||||
<dd>任意で指定可能なプロパティ。</dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>injectノードを用いることで、指定したペイロード値を用いてフローを開始できます。デフォルトのペイロード値は現在時刻のタイムスタンプを1970年1月1日からの経過ミリ秒で表現した値です。</p>
|
||||
<p>文字列、数値、論理値、JavaScriptオブジェクト、フロー/グローバルコンテキストの値などの送出も可能です。</p>
|
||||
<p> デフォルト設定では、エディタ内に表示されるボタンをクリックすることで、ノードを手動で起動できます。指定間隔もしくはスケジュールに従ってメッセージを送出するように設定することも可能です。</p>
|
||||
<p>また、フロー開始の際に一度だけメッセージを送出させることもできます。</p>
|
||||
<p>「<i>時間間隔</i>」に指定可能な値の最大値は、約596時間(もしくは24日)です。一日より長い間隔を扱いたい場合は、電源停止や再起動にも対応可能なスケジューラノードの利用を検討すると良いでしょう。</p>
|
||||
<p><b>注</b>:「<i>指定した時間間隔、日時</i>」と「<i>指定した日時</i>」オプションは標準的なcronシステムを内部で利用します。したがって「20分」という指定は、その時点から20分後ではなく、毎時きっかり、20分、40分を意味します。現時刻から20分毎を指定するには「<i>指定した時間間隔</i>」オプションを用います。</p>
|
||||
<p><b>注</b>: 文字列に改行を含めたい場合は、functionノードを使ってペイロードを設定してください。</p>
|
||||
</script>
|
||||
36
nodes/core/locales/ja/core/25-catch.html
Normal file
36
nodes/core/locales/ja/core/25-catch.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="catch">
|
||||
<p>同じタブ内のノードが送出したエラーをキャッチします。</p>
|
||||
<h3>出力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>error.message <span class="property-type">文字列</span></dt>
|
||||
<dd>エラーメッセージ</dd>
|
||||
<dt>error.source.id <span class="property-type">文字列</span></dt>
|
||||
<dd>エラーを送出したノードのID</dd>
|
||||
<dt>error.source.type <span class="property-type">文字列</span></dt>
|
||||
<dd>エラーを送出したノードの種別</dd>
|
||||
<dt>error.source.name <span class="property-type">文字列</span></dt>
|
||||
<dd>エラーを送出したノードの名称(設定されている場合)</dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>メッセージの処理中にノードがエラーを送出した場合、フロー実行は基本的に停止します。このノードを使うと、エラーをキャッチして対応するフローで処理させることができます。</p>
|
||||
<p>デフォルトでは、同じタブの全てのノードが送出したエラーをキャッチします。特定のノードをキャッチ対象とすることも可能です。</p>
|
||||
<p>エラー発生時には、マッチするすべてのcatchノードがメッセージを受け取ります。</p>
|
||||
<p>サブフロー内でエラーが送出された場合、まずサブフロー内のcatchノードで処理されます。対応するノードが存在しない場合には、そのサブフローが配置されたタブにエラーを伝播して処理します。</p>
|
||||
<p>メッセージが<code>error</code>プロパティを持っている場合、元の<code>error</code>は<code>_error</code>へコピーします。</p>
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user