Compare commits

..

671 Commits

Author SHA1 Message Date
Nick O'Leary
f91762ec8f Merge pull request #3832 from node-red/update-gen-pub-script
Update gen pub script
2022-08-04 14:09:28 +01:00
Nick O'Leary
7f698610df Update generate-publish-script with latest release number 2022-08-04 14:08:04 +01:00
Nick O'Leary
bee06f64f5 Merge pull request #3831 from node-red/release-223
Update changelog
2022-08-04 14:01:45 +01:00
Nick O'Leary
53af4231af Update changelog 2022-08-04 14:00:37 +01:00
Nick O'Leary
2ea4b15dca Merge pull request #3829 from Steve-Mcl/backport-3776
Allow HTTP Headers not in spec (backport to v2.x)
2022-08-04 13:49:43 +01:00
Nick O'Leary
ce09f56dcc Update packages/node_modules/@node-red/nodes/locales/en-US/messages.json 2022-08-04 13:49:04 +01:00
Ben Hardill
6c648e4bab Allow HTTP Headers not in spec
potential fix for #3772
2022-08-04 13:48:03 +01:00
Nick O'Leary
72661aa159 Merge pull request #3828 from Steve-Mcl/backport-3762
Fix storing subflow credential type when input has multiple types (backport to v2.x)
2022-08-04 13:00:33 +01:00
Nick O'Leary
16e79d6bd2 Merge pull request #3827 from Steve-Mcl/backport-3754
Fix change node, not handling from field properly when using context (backport to v2.x)
2022-08-04 13:00:16 +01:00
Nick O'Leary
726fac97d2 Merge pull request #3826 from Steve-Mcl/backport-3728
Do not remove unknown credentials of Subflow Modules (backport to v2.x)
2022-08-04 13:00:06 +01:00
Nick O'Leary
efc3882961 Merge pull request #3825 from Steve-Mcl/backport-3716
Fix CSV node to handle \n when outputting text fields (backport to v2.x)
2022-08-04 12:59:15 +01:00
Nick O'Leary
489c456271 Merge pull request #3824 from Steve-Mcl/backport-3709
Fix delay rate limit last timing when empty (backport to v2.x)
2022-08-04 12:59:06 +01:00
Nick O'Leary
970be7b5f2 Merge pull request #3823 from Steve-Mcl/backport-3715
Ensure 'hidden flow' count doesn't include subflows (backport to v2.x)
2022-08-04 12:58:49 +01:00
Nick O'Leary
b94fdd2f79 Merge pull request #3822 from Steve-Mcl/backport-3703
Fix credential type input item of subflow template (backport to v2.x)
2022-08-04 12:58:39 +01:00
Nick O'Leary
66f6bc59fa Merge pull request #3821 from Steve-Mcl/backport-3670
Join-reduce keep existing msg properties (backport to v2.x)
2022-08-04 12:58:21 +01:00
Stephen McLaughlin
455f2dc800 delete console.log artefact 2022-08-04 12:35:34 +01:00
Nick O'Leary
aed2b8e46d Fix storing subflow credential type when input has multiple types
Fixes #3749
2022-08-04 10:39:04 +01:00
Franck Mourre
633afbbb44 Fix change node, not handling from field properly when using context 2022-08-04 10:00:09 +01:00
Nick O'Leary
6c797e35cf Update packages/node_modules/@node-red/runtime/lib/nodes/credentials.js 2022-08-04 09:57:14 +01:00
Nick O'Leary
30b8a95421 Do not remove unknown credentials of Subflow Modules
Fixes #3641
2022-08-04 09:57:14 +01:00
Dave Conway-Jones
7665971b52 Fix CSV node to handle \n when outputting text fields
and add tests
2022-08-04 09:56:26 +01:00
Dave Conway-Jones
ba6dc3117f Delay node - add example for simple queue with release 2022-08-04 09:55:04 +01:00
Dave Conway-Jones
73fcc05a54 Fix delay rate limit last timing when empty 2022-08-04 09:55:04 +01:00
Nick O'Leary
fd409b0636 Ensure 'hidden flow' count doesn't include subflows
Fixes #3707
2022-08-04 09:53:04 +01:00
Hiroyasu Nishiyama
29287149b4 remove line break to prevent jshint error 2022-08-04 09:43:45 +01:00
Hiroyasu Nishiyama
18c0ec990a fix type selector of subflow environment variable 2022-08-04 09:43:45 +01:00
Hiroyasu Nishiyama
ee2b151b7a fix credential type input item of subflow template 2022-08-04 09:43:44 +01:00
Steve-Mcl
2d7a068644 Join-reduce keep existing msg properties
see https://discourse.nodered.org/t/no-response-object-after-split-join/63919
2022-08-04 09:39:43 +01:00
Nick O'Leary
5c5855751c Merge pull request #3735 from kazuhitoyokoi/v2.x-backports
Backports to v2.x
2022-07-04 21:03:03 +01:00
Kazuhito Yokoi
396b3b64ff Fix typo in message catalog (Backport node-red#3724 to v2.x) 2022-07-04 21:38:25 +09:00
Kazuhito Yokoi
48e33a472b Fix use default button for node icon (Backport node-red#3714 to v2.x) 2022-07-04 21:35:44 +09:00
Nick O'Leary
a7375e4e8f Merge pull request #3705 from kazuhitoyokoi/v2.x-addjpn
Backports to v2.x
2022-06-27 14:15:26 +01:00
Kazuhito Yokoi
42732db2b0 Fix typos in message catalog (Backport node-red#3622 to v2.x) 2022-06-26 11:20:05 +09:00
Kazuhito Yokoi
7c830856df Remove unnecessary spaces (Backport node-red#3688 to v2.x) 2022-06-26 11:16:01 +09:00
Kazuhito Yokoi
5dad33dc77 Change indents from tabs to 4 spaces (Backport node-red#3512 to v2.x) 2022-06-26 11:06:12 +09:00
Kazuhito Yokoi
cbdb988d02 Fix indents in other code except message catalog (Backport node-red#3622 to v2.x) 2022-06-26 10:57:17 +09:00
Kazuhito Yokoi
e944dfecc2 Add Japanese translations (Backport node-red#3688 to v2.x) 2022-06-26 10:08:22 +09:00
Kazuhito Yokoi
b2c2b9bd14 Add Japanese translations (Backport node-red#3576 to v2.x) 2022-06-26 09:48:42 +09:00
Nick O'Leary
0ed7f6ce4e Merge pull request #3665 from Steve-Mcl/backport-3647
Fix to extend escaped subflow category characters (backport #3647 to v2.x)
2022-06-16 11:16:54 +01:00
Nick O'Leary
74e3b9e9ed Merge pull request #3664 from Steve-Mcl/backport-3643
Reset mouse state when switching tabs (Backport #3643 to v2.x)
2022-06-16 11:16:34 +01:00
Nick O'Leary
7fd884c68f Merge pull request #3663 from Steve-Mcl/backport-3646
Fix to sanitize tab name (Backport #3646 to v2.x)
2022-06-16 11:16:18 +01:00
Nick O'Leary
3f29283724 Merge pull request #3662 from Steve-Mcl/backport-3645
Fix ESM module loading in Function node (Backport #3645 to v2.x)
2022-06-16 11:15:55 +01:00
Nick O'Leary
ea303495b0 Merge pull request #3661 from Steve-Mcl/backport-3633
fix new folder menu of save to library dialog (backport #3633 to v2.x)
2022-06-16 11:14:43 +01:00
Nick O'Leary
9d39709038 Merge pull request #3660 from Steve-Mcl/backport-3632
Fix JSONata evaluation of inject button (Backport 3632 to v2.x)
2022-06-16 11:14:26 +01:00
Nick O'Leary
facb6143c3 Merge pull request #3659 from Steve-Mcl/backport-3624
fix buffer parse error message of evaluateNodeProperty (backports #3624 for v2.x)
2022-06-16 11:14:13 +01:00
Nick O'Leary
68a2786ff2 Merge pull request #3658 from Steve-Mcl/backport-3630
Dont delete TCP socket twice (backport Backport: #3630 to v2.x)
2022-06-16 11:13:17 +01:00
Nick O'Leary
b2b31670f8 Merge pull request #3657 from Steve-Mcl/backport-3611
Ensure ACE worker options are set (Backport 3611 to v2.x)
2022-06-16 11:13:02 +01:00
Nick O'Leary
355fb724f8 Merge pull request #3656 from Steve-Mcl/backport-3548
Fix browser console error Uncaught TypeError when searching certain terms (Backport #3548 to v2.x)
2022-06-16 11:12:47 +01:00
Nick O'Leary
d925f12aea Merge pull request #3655 from Steve-Mcl/dup-hist-event
Remove duplicate history add of ungroup event (backport #3581to v2.x)
2022-06-16 11:12:11 +01:00
Nick O'Leary
428ed090f3 Merge pull request #3654 from Steve-Mcl/mqtt-backport
Mqtt fixes in v3 for v2.x (backports #3563 #3594 #3626 to v2.x)
2022-06-16 11:11:50 +01:00
Steve-Mcl
9946132658 extend escaped subflow category characters
@HiroyasuNishiyama commit 30d88bbe7e

Co-authored-by: HiroyasuNishiyama <hiroyasu.nishiyama.uq@hitachi.com>
2022-06-14 07:47:54 +01:00
Steve-Mcl
30f08a9f17 Track mouse release outside workspace so current action completes
manual cherry pick a16032a
2022-06-14 07:39:19 +01:00
Nick O'Leary
83f1729d83 Reset mouse state when switching tabs
Fixes #3639
2022-06-14 07:35:11 +01:00
Hiroyasu Nishiyama
3667de18a9 sanitize tab name 2022-06-13 14:56:57 +01:00
Nick O'Leary
bda8e86ea4 Fix ESM module loading in Function node
Fixes #3627
2022-06-13 14:53:06 +01:00
Hiroyasu Nishiyama
7920fa1dd4 fix new folder menu of save to library dialog 2022-06-13 14:48:16 +01:00
Hiroyasu Nishiyama
cb06690553 update test for inject node 2022-06-13 13:52:28 +01:00
Hiroyasu Nishiyama
4b4e5a0861 fix JSONata evaluation of inject button 2022-06-13 13:52:28 +01:00
Hiroyasu Nishiyama
e5952f082e fix buffer parse error message of evaluateNodeProperty 2022-06-13 13:48:22 +01:00
Stephen McLaughlin
c7994b6393 Dont delete TCP socket twice 2022-06-13 13:40:50 +01:00
Steve-Mcl
39ac6b0d46 fix typo 2022-06-13 13:33:30 +01:00
Stephen McLaughlin
e22bf22b61 Ensure ACE worker options are set
fixes #3610
2022-06-13 13:25:43 +01:00
Steve-Mcl
92dd80ac49 declare undeclared loop var 2022-06-13 13:21:46 +01:00
Steve-Mcl
9442e2a993 Prevent error when uses search term is used
fixes #3578
2022-06-13 13:21:46 +01:00
Nick O'Leary
6df7f50f9f Remove duplicate history add of ungroup event
Fixes #3581
2022-06-13 13:16:57 +01:00
Steve-Mcl
933cad888f add changes from #3563
Add client and Runtime MQTT topic validation and fix subsequent connection lockup
(that arises due to bad birth/will topic)
backport-2.x
2022-06-13 12:57:22 +01:00
Stephen McLaughlin
8133c5e834 define noproxy variable 2022-06-13 12:16:10 +01:00
Stephen McLaughlin
e7f6549cb6 Remove unnecessary call to clientRemoveListeners
Also, merge the non JSDOC comment into the JSDOC comment
2022-06-13 12:15:27 +01:00
Phil Day
2ded07c765 call client.end with force=true on timeout 2022-06-13 12:15:27 +01:00
Phil Day
6a799e7e2a Update packages/node_modules/@node-red/nodes/core/network/10-mqtt.js
Co-authored-by: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com>
2022-06-13 12:15:27 +01:00
Phil Day
1d40378f8c Update packages/node_modules/@node-red/nodes/core/network/10-mqtt.js
Co-authored-by: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com>
2022-06-13 12:15:27 +01:00
Phil Day
bcab1cf096 Update packages/node_modules/@node-red/nodes/core/network/10-mqtt.js
Co-authored-by: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com>
2022-06-13 12:15:27 +01:00
Phil Day
03484fd5cd Updated to cover the removal of individual event handlers 2022-06-13 12:15:27 +01:00
Phil Day
1eea371124 Revent change of grunt version 2022-06-13 12:15:27 +01:00
Phil Day
02d9ad479d Track which event handlers we add to the mqtt client so we can removed them cleanly 2022-06-13 12:15:23 +01:00
Phil Day
3be75fa822 Add Force parameter mqtt client.end() when called in disconnect 2022-06-13 12:14:38 +01:00
Stephen McLaughlin
ca204dea2d Use new validation option to return better label
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-06-13 12:11:42 +01:00
Nick O'Leary
a2de514c05 Merge pull request #3540 from hardillb/no-home-dir
Don't start if user has no home directory
2022-05-02 21:12:57 +01:00
Nick O'Leary
ea5d25c794 Merge pull request #3564 from bonanitech/config-nodes-colors
Don't let themes change node config colors
2022-05-02 20:19:40 +01:00
Mauricio Bonani
b51eb7326f Change node config SASS variables 2022-04-29 18:40:34 -04:00
Stephen McLaughlin
3a7a606f6a Merge pull request #3562 from Steve-Mcl/mqttv5-userprops
MQTT Node - save and restore v5 config user props
2022-04-29 12:09:38 +01:00
Stephen McLaughlin
294fc6b62f Ensure userProps makes it through to runtime 2022-04-29 11:25:19 +01:00
Stephen McLaughlin
662a44fccf save and restore v5 config user props 2022-04-29 10:44:19 +01:00
Nick O'Leary
b0a5d4fb6f Merge pull request #3560 from bonanitech/border-radius-gap
Fix gap between typedInput containers borders
2022-04-28 16:32:41 +01:00
Mauricio Bonani
205dbc1a25 Increase typedInput container border-radius
Fixes #3548
2022-04-27 15:00:29 -04:00
Stephen McLaughlin
f717eb7388 Merge pull request #3552 from Steve-Mcl/fix-mqtt-status
Fix incorrect MQTT status
2022-04-26 23:57:55 +01:00
Stephen McLaughlin
020eaef5ba Fix incorrect MQTT status
fixes #3550
2022-04-26 16:12:54 +01:00
Nick O'Leary
c5efdf5ae3 Merge pull request #3547 from node-red/fix-wire-history
Fix recording removed links in edit history
2022-04-26 09:14:33 +01:00
Nick O'Leary
15958cd4a3 Fix recording removed links in edit history
Fixes #3546
2022-04-26 09:13:38 +01:00
Ben Hardill
cdcc8cc59a Update packages/node_modules/node-red/red.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-04-21 15:47:40 +01:00
Ben Hardill
0014fec63f Remove test that exits if no userDir defined
With the storage plugins it is possible to not need a userDir, just a
settings.js
2022-04-21 13:52:38 +01:00
Ben Hardill
812efde342 Also check if there is a useDir defined 2022-04-21 12:00:10 +01:00
Ben Hardill
889f0e1569 Don't start if user has no home directory
If the user doesn't have a defined home dir (env var `HOME`,
`USERPROFILE` or `HOMEPATH`) and the `userDir` is not passed on the
command line then we shouldn't start as we don't know where to copy the
default `settings.js` file to or where to store flows

fixes #3539
2022-04-21 11:40:12 +01:00
Nick O'Leary
3a26c5cd65 Merge pull request #3498 from sammachin/sammachin_credentials
Error on invalid encrypted credentials
2022-04-21 10:59:43 +01:00
Nick O'Leary
4706e20a1d Merge pull request #3526 from node-red-hitachi/fix-status-reference-in-debug-node
fix reference error of msg.status in debug node
2022-04-20 10:56:25 +01:00
Nick O'Leary
58e87b3ddf Merge pull request #3536 from bonanitech/unused-sass-vars
Remove unused SASS vars
2022-04-20 09:30:13 +01:00
Nick O'Leary
ea0abb70a2 Merge pull request #3537 from bonanitech/jquery-borders
Add custom style for jQuery widgets borders
2022-04-20 09:29:52 +01:00
Stephen McLaughlin
e092f41074 Merge #3531 websocket status improvements
call done after ws disconnects
2022-04-19 14:40:59 +01:00
Mauricio Bonani
79a90dc476 Add custom style for jQuery widgets borders
Fixes #3518
2022-04-19 08:53:39 -04:00
Mauricio Bonani
25962dbf39 Remove unused SASS vars
Fixes #3534
2022-04-19 08:00:01 -04:00
Steve-Mcl
8df53e441d remove unused vars 2022-04-19 10:42:00 +01:00
Stephen McLaughlin
6f89efa40b remove unused if block
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-04-19 10:30:08 +01:00
Stephen McLaughlin
d6a1b4e71f Merge pull request #3535 from node-red-hitachi/fix-unknown-config-error
fix out of scope reference of `hasUnusedConfig` variable
2022-04-18 08:52:34 +01:00
Hiroyasu Nishiyama
a2c0e53f87 fix out of scope reference of hasUnusedConfig variable 2022-04-18 08:36:19 +09:00
Steve-Mcl
97678577fb call done after ws disconnects
fixes #3527
2022-04-14 22:07:52 +01:00
Hiroyasu Nishiyama
226f45d8d5 fix reference error of msg.status in debug node 2022-04-12 11:33:02 +09:00
Stephen McLaughlin
0aa80d82d9 Merge pull request #3524 from Steve-Mcl/hadnle-status-typo
correct "non string" check parenthesis
2022-04-11 16:50:55 +01:00
Steve-Mcl
21a0b33645 correct "non string" check parenthesis
fixes #3493
2022-04-11 13:57:26 +01:00
Nick O'Leary
ae76ff0aaf Merge pull request #3516 from Steve-Mcl/status-i18n
Ensure i18n of scoped package name
2022-04-05 23:32:08 +01:00
Nick O'Leary
bba819ba84 Merge pull request #3517 from Steve-Mcl/no-deploy-when-shaded
Prevent shortcut deploy when deploy button shaded
2022-04-05 23:31:45 +01:00
Steve-Mcl
780e41d6a6 Prevent shortcut deploy when deploy button shaded
fixes #3509
2022-04-04 17:06:29 +01:00
Steve-Mcl
6d0b55f753 Ensure i18n of scoped package name
fixes #3452
2022-04-04 16:20:44 +01:00
Dave Conway-Jones
77e2e44abc Fix markdown editor to mark up orderedlists correctly
to close #3513
2022-03-31 13:45:07 +01:00
Sam Machin
50718495da fix test mock 2022-03-24 08:39:31 +00:00
Sam Machin
b7b604aed4 Update packages/node_modules/@node-red/runtime/lib/nodes/credentials.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-03-24 08:37:51 +00:00
Sam Machin
a1f5cabbba Update packages/node_modules/@node-red/runtime/locales/en-US/runtime.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-03-24 08:37:46 +00:00
Sam Machin
c2aae6ddf6 Update packages/node_modules/@node-red/runtime/locales/en-US/runtime.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-03-24 08:37:35 +00:00
Stephen McLaughlin
c8dc2327a3 Merge pull request #3497 from Steve-Mcl/mqtt-unit-tests
Add unit tests for MQTT nodes
2022-03-23 10:10:57 +00:00
Stephen McLaughlin
f660973168 Dont run MQTT tests by default on local
- update skip message to inform use of how to enable test
2022-03-23 10:00:36 +00:00
Stephen McLaughlin
cf2e7744f3 remove copyright header
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-03-23 09:15:57 +00:00
Sam Machin
855d799b21 Update credentials.js 2022-03-22 21:18:11 +00:00
Sam Machin
97dd1d0f4f typo 2022-03-22 07:34:18 +00:00
Stephen McLaughlin
702545e0b2 Merge pull request #3500 from ralphwetzel/master
Fix: Sidebar "Configuration" filter button tooltip
2022-03-21 20:10:55 +00:00
Stephen McLaughlin
fa2787eb5d Merge pull request #3499 from bonanitech/diff-colors
Add the ability to customize diff colors even more
2022-03-21 20:09:21 +00:00
Nick O'Leary
0f37b326a0 Merge pull request #3502 from Steve-Mcl/fix-mqtt-will-props
fix typo of will properties (properies)
2022-03-21 19:29:23 +00:00
Steve-Mcl
7f9f551cfe fix typo of will properties (properies)
Fixes #3501
2022-03-21 15:24:23 +00:00
Steve-Mcl
ecf1847dd2 use CI flag to skip MQTT tests 2022-03-21 14:59:10 +00:00
Steve-Mcl
40a9dce869 try broker.emqx.io 2022-03-21 13:51:20 +00:00
Steve-Mcl
a6696733fa tidy up code 2022-03-21 13:50:24 +00:00
Sam Machin
d9bd736159 change error to warn for moving from unencrypted to encrypted 2022-03-21 09:29:41 +00:00
ralphwetzel
4f5f5d31a3 Merge pull request #1 from ralphwetzel/ralphwetzel-sidebar-filter-button-tooltip
Fix: Sidebar "Configuration" filter button tooltip
2022-03-21 00:06:02 +01:00
ralphwetzel
fad1325427 Fix: Sidebar "Configuration" filter button tooltip
"Configuration" sidebar shows wrong tooltip for filter button "All". Fixed.
2022-03-20 23:59:24 +01:00
Mauricio Bonani
8b6678a453 Add the ability to customize diff colors even more 2022-03-20 15:40:52 -04:00
Sam Machin
c7f48a83c0 add test 2022-03-19 17:57:30 +00:00
Sam Machin
af0f02d63e add locale warning 2022-03-19 17:44:21 +00:00
Steve-Mcl
497d63e67e Add unit tests for MQTT nodes 2022-03-19 17:29:31 +00:00
Sam Machin
4d048af384 Check for missing encrypted credentials 2022-03-19 13:34:46 +00:00
Nick O'Leary
49e69a54bd Merge pull request #3481 from Steve-Mcl/fix-node-val-changed
do JSON comparison of old value/new value
2022-03-14 18:52:25 +00:00
Stephen McLaughlin
73ff852648 backward compatible equality testing of immutables
- make non object equality tests non strict
- this aligns with prior condition
2022-03-10 11:22:59 +00:00
Nick O'Leary
6d50eb5737 Merge pull request #3484 from zettca/node-wires-array
fix nodes losing their wires when in an iframe
2022-03-09 11:42:10 +00:00
Bruno Henriques
a8579fa68a fix nodes losing their wires when in an iframe 2022-03-09 10:39:47 +00:00
Stephen McLaughlin
10f77fdf1a permit non strict comparison of string or number 2022-03-08 23:13:41 +00:00
Steve-Mcl
84a9cf7adf handle errors by circ refs, undefined, BigInt etc 2022-03-08 14:20:12 +00:00
Steve-Mcl
a49927f173 do JSON comparison of old value/new value
fixes #3475
2022-03-08 14:07:03 +00:00
Nick O'Leary
ac97e8c613 Merge pull request #3468 from Steve-Mcl/scroll-into-view-calcs
Improve scroll into view
2022-03-07 12:47:54 +00:00
Nick O'Leary
95fe717ca7 Merge pull request #3472 from Steve-Mcl/fix-mqtt-setboolprop
fix: ensure mqtt v5 props can be set false
2022-03-07 12:47:01 +00:00
Steve-Mcl
10b18de3e0 fix: ensure mqtt v5 props can be set false
fixes #3471
2022-03-05 11:24:25 +00:00
Steve-Mcl
cf1424976f Improve scroll into view
- if a node is behind scrollbar, it is not scrolled into view
- jQuery `.width()` & `.width()` actually includes the scroll bar.
- using native `clientWidth` and `clientHeight` fixes this
2022-03-04 16:08:29 +00:00
Nick O'Leary
fdb868516f Merge pull request #3464 from Steve-Mcl/dont-show-hidden-tab
Dont show 1st tab if hidden when loading
2022-03-03 23:15:07 +00:00
Steve-Mcl
97ebe33d68 Dont show 1st tab if hidden when loading
fixes #3455
2022-02-28 18:15:13 +00:00
Dave Conway-Jones
c0612e6193 Merge branch 'master' of https://github.com/node-red/node-red 2022-02-28 09:59:35 +00:00
萧十一郎
380a08242a fix html label mistake (#3459) 2022-02-26 10:10:17 +00:00
Dave Conway-Jones
0398ef3b90 undo regression in tcp-in node (missed one)
and add test
2022-02-25 16:06:44 +00:00
Dave Conway-Jones
25f4fbf2bb undo regression to tcp-in node
To fix #3454
2022-02-21 20:03:25 +00:00
Nick O'Leary
5f0ea85f47 Bump for 2.2.2 2022-02-18 14:46:01 +00:00
Nick O'Leary
6c7c1202ed Merge pull request #3451 from Steve-Mcl/fix-mqtt-close-timeout
Fix "close timed out" error when performing full deploy or modifying broker node.
2022-02-18 14:43:34 +00:00
Steve-Mcl
669aa769c2 Fix close timeout on MQTT nodes
fixes #2934
2022-02-17 10:18:46 +00:00
Nick O'Leary
fcf2994015 Bump for 2.2.1 2022-02-15 13:41:53 +00:00
Nick O'Leary
bee21ddc9e Update dependencies 2022-02-15 13:36:05 +00:00
Nick O'Leary
263e68e677 Merge pull request #3447 from Steve-Mcl/fix-hook-module-location
Improve module location parsing (of stack info) when adding hook
2022-02-15 13:18:25 +00:00
Steve-Mcl
2b958f5724 Improve module location parsing when adding hook
- fixes #3401
- handles brackets and no brackets in stack line
- handles short stack
2022-02-15 12:40:34 +00:00
Nick O'Leary
95f7177ef4 Merge pull request #3445 from node-red-hitachi/fix-path-substitution
Fix substitution of NR_NODE_PATH
2022-02-15 11:26:19 +00:00
Nick O'Leary
006324b78e Merge pull request #3446 from Steve-Mcl/better-bad-node-err-log
improve "Unexpected Node Error" logging
2022-02-15 11:26:08 +00:00
Steve-Mcl
efd8c1229d improve "Unexpected Node Error" logging
- fixes #3389
- adds additional info to aid sourcing the issue
- removes lots of undefined info when node type is incorrect
- stores and reports original stack before internal try/catch exception
- ensure this._flow is something before attempting to call `handleError`
2022-02-15 10:51:18 +00:00
Hiroyasu Nishiyama
0f1aea3e0d add test case 2022-02-15 14:41:03 +09:00
Hiroyasu Nishiyama
6a41cbebc9 evaluate env var after path initialization 2022-02-15 14:23:01 +09:00
Nick O'Leary
bffb91f196 Merge pull request #3443 from node-red/delay-field-validation
Allow nbRateUnits to be undefined when validating
2022-02-14 23:18:41 +00:00
Nick O'Leary
4573b65639 Merge pull request #3444 from node-red/keyboard-filter-case
Handle mixed-cased filter terms in keyboard shortcut dialog
2022-02-14 23:18:16 +00:00
Nick O'Leary
3d8505385a Merge pull request #3442 from node-red/dupe-links
Prevent duplicate links being added between nodes
2022-02-14 23:18:01 +00:00
Nick O'Leary
99c053f86b Merge pull request #3440 from Steve-Mcl/monaco-env-suggestions
Coding help for recently added node-red Predefined Environment Variables
2022-02-14 23:02:55 +00:00
Nick O'Leary
f2dde705ef Handle mixed-cased filter terms in keyboard shortcut dialog
Fixes #3400
2022-02-14 20:59:43 +00:00
Nick O'Leary
be11fda814 Allow nbRateUnits to be undefined when validating
Fixes #3407
2022-02-14 20:44:55 +00:00
Nick O'Leary
0261105c52 Prevent duplicate links being added between nodes 2022-02-14 20:35:47 +00:00
Nick O'Leary
264047dc0c Merge pull request #3437 from Steve-Mcl/fix-multiple-wires
bug fix: Dont add wires to undo buffer twice
2022-02-14 20:12:46 +00:00
Steve-Mcl
4d84926ed2 Update monaco for Predefined Environment Variables
- add Predefined Environment Variables to snippet suggestions
- update jsdoc for `env.get`
2022-02-14 13:38:37 +00:00
Nick O'Leary
da3211fee6 Merge pull request #3439 from node-red/remove-debug
Remove console.log when ignoring disabled module
2022-02-14 10:48:33 +00:00
Nick O'Leary
1388b03cf2 Remove console.log when ignoring disabled module 2022-02-14 10:46:08 +00:00
Steve-Mcl
b3f1401ab4 Dont add wires to undo buffer twice
Fixes #3433
2022-02-13 16:56:26 +00:00
Hiroyasu Nishiyama
e5e3832809 fix Japanese message of delay node (#3434) 2022-02-12 16:13:59 +00:00
Nick O'Leary
2eff7da171 Merge pull request #3397 from node-red-hitachi/fix-config-node-validation
fix node validation to be applied to config node
2022-02-09 19:47:23 +00:00
Nick O'Leary
e9622bcfe8 Merge pull request #3391 from node-red-hitachi/fix-hide-flow-tooltip
fix to hide tooltip after removing subflow tab
2022-02-09 19:44:05 +00:00
Hiroyasu Nishiyama
dc73997be3 fix not to use hasOwnProperty 2022-02-08 09:21:52 +09:00
Hiroyasu Nishiyama
fb81121bd3 fix node validation to be applied to config node 2022-02-04 17:45:00 +09:00
Nick O'Leary
5293563a6a Merge pull request #3394 from Alkarex/fix-debug-node-hasOwnProperty
Fix no-prototype-builtins bug in debug node and utils
2022-02-03 16:31:46 +00:00
Alexandre Alapetite
2e1e61dabe Remove part of JSDoc 2022-02-03 16:32:51 +01:00
Alexandre Alapetite
280d63fde7 Fix util.encodeObject 2022-02-03 15:59:25 +01:00
Alexandre Alapetite
e55cbb3e3d Fix bug in debug node due to msg.hasOwnProperty construct
`msg.hasOwnProperty("status")` might make the debug node crash/produce an error if the payload was created with `Object.create(null)`.
This is the case e.g. for `ini` (to parse INI files), an official NPM node:
4f289946b3/lib/ini.js (L63)

My Node-RED node `node-red-contrib-parser-ini`, which is using that library, was hit by this bug and I had to ship a workaround
fe6b1eb4b1/parser-ini.js (L14)

The `msg.hasOwnProperty("xxx")` construct should not be used since ECMAScript 5.1.

ESLint advises in the same direction https://eslint.org/docs/rules/no-prototype-builtins

This patch was produced using the following regex:
Search: `\b([\w.]+).hasOwnProperty\(`
Replace: `Object.prototype.hasOwnProperty.call($1, `

This could be applied more gobally if desired.
2022-02-03 02:01:22 +01:00
Hiroyasu Nishiyama
7959d18248 hide tooltip after removing subflow tab 2022-02-02 11:34:58 +09:00
Nick O'Leary
b7bae18849 Update inner package dependency 2022-01-27 12:58:43 +00:00
Nick O'Leary
fbde247c72 Update node-red-admin dependency 2022-01-27 12:57:32 +00:00
Nick O'Leary
3a69af9034 Merge pull request #3383 from node-red/dev
Merge dev to master for 2.2.0
2022-01-27 12:50:45 +00:00
Nick O'Leary
5c87a6cb76 Update package readmes and licenses 2022-01-27 12:49:48 +00:00
Nick O'Leary
9c6bb434e8 Update contributing guide for new cla 2022-01-27 12:44:22 +00:00
Nick O'Leary
d1bd303dfa Update version for 2.2.0 2022-01-27 10:13:28 +00:00
Nick O'Leary
3813c32454 Update marked to latest 2022-01-27 10:12:55 +00:00
Nick O'Leary
3b00a692ee Update changelog 2022-01-27 10:12:06 +00:00
Nick O'Leary
3304ebe9d3 Merge pull request #3382 from node-red-hitachi/fix-subflow-update
fix opening/closing subflow template not to make subflow changed
2022-01-27 09:30:26 +00:00
Nick O'Leary
513120cbfe Merge pull request #3381 from kazuhitoyokoi/dev-addjpn
Add Japanese translations for v2.2.0
2022-01-27 09:28:29 +00:00
Hiroyasu Nishiyama
b06049d5a3 fix opening/closing subflow template not to make subflow changed 2022-01-27 12:57:37 +09:00
Kazuhito Yokoi
0f50355deb Add Japanese translations for v2.2.0 2022-01-27 11:14:24 +09:00
Nick O'Leary
bd6e35fea2 Merge branch 'dev' of github.com:node-red/node-red into dev 2022-01-26 17:46:47 +00:00
Nick O'Leary
a4fd63cd44 Merge pull request #3380 from Steve-Mcl/search-find-filenode
Pallet Label (if different to type) should be indexed for search
2022-01-26 17:00:47 +00:00
Steve-Mcl
fdc4219b68 palletLabel (if different) should be indexed
for search - fixes #3297
2022-01-26 16:14:34 +00:00
Nick O'Leary
5b428bb8e6 Merge pull request #3379 from node-red-hitachi/nr_node_path-support
add NR_NODE_PATH path support
2022-01-26 14:29:03 +00:00
Hiroyasu Nishiyama
c948ff88a5 add support of NR_NODE_PATH 2022-01-26 21:24:48 +09:00
Nick O'Leary
9b9a0d7060 Update dependencies 2022-01-26 12:20:45 +00:00
Nick O'Leary
16578e3677 Update changelog 2022-01-26 12:07:04 +00:00
Nick O'Leary
be7f84bc67 Merge pull request #3377 from Steve-Mcl/function-node-decs
Update `node` declarations in func.d.ts
2022-01-26 12:03:56 +00:00
Nick O'Leary
033d26f2cb Merge pull request #3378 from node-red/tour-update
Update tour for 2.2.0
2022-01-26 12:03:40 +00:00
Nick O'Leary
4c0826b1c4 Update tour for 2.2.0 2022-01-26 12:00:30 +00:00
Steve-Mcl
c4cc204c94 Add static declerations to func ts. fixes #3376 2022-01-26 11:40:05 +00:00
Nick O'Leary
3747db18b1 Update changelog 2022-01-26 11:34:32 +00:00
Nick O'Leary
4173625fca Merge pull request #3243 from node-red/delete-global-context
Clear context contents when switching projects
2022-01-26 11:28:34 +00:00
Nick O'Leary
0e7863a6fb Merge pull request #3375 from node-red/settings-update
Add editorTheme.tours property to default settings file
2022-01-26 11:21:55 +00:00
Nick O'Leary
207ba00ad2 Add editorTheme.tours property to default settings file 2022-01-26 11:21:11 +00:00
Nick O'Leary
87c89586a5 Merge pull request #3356 from node-red-hitachi/node-prop-env-var
Add support for accessing node id & name as environment variable
2022-01-26 11:11:02 +00:00
Nick O'Leary
1cea1ced82 Merge pull request #3371 from node-red/node-alias
Add _path property to nodes and expose as node.path in Function node
2022-01-26 11:10:43 +00:00
Nick O'Leary
08732bac0f Merge pull request #3374 from Steve-Mcl/mqtt-reconnect-fix
Mqtt reconnect fix
2022-01-26 11:03:20 +00:00
Nick O'Leary
283e8d3c08 Merge pull request #3373 from Steve-Mcl/merge-fix
bug: merge issue. fixes #3364
2022-01-26 11:01:35 +00:00
Nick O'Leary
42a7165596 Merge pull request #3372 from Steve-Mcl/use-paletteLabel-in-help
Use a nodes palette label in help tree
2022-01-26 11:00:53 +00:00
Hiroyasu Nishiyama
aa3f5001d5 additional update of test for NR_ prefix addition 2022-01-26 10:52:41 +09:00
Hiroyasu Nishiyama
56580c4005 add test for NR_ prefix addition 2022-01-26 09:26:05 +09:00
Hiroyasu Nishiyama
ba304c9651 add NR_ prefix to special environment variables 2022-01-26 09:25:30 +09:00
Nick O'Leary
703c5adba7 Add _path property to nodes and expose as node.path in Function node 2022-01-25 21:32:28 +00:00
Steve-Mcl
8b85f6e0a6 ensure help search is case insensitive 2022-01-25 18:27:47 +00:00
Nick O'Leary
c136d22382 Merge pull request #3370 from node-red/fix-vertical-align-subflow-port
Fix vertical align subflow port
2022-01-25 17:09:05 +00:00
Nick O'Leary
42358419ad Fix vertical align of subflow port labels 2022-01-25 17:08:04 +00:00
Nick O'Leary
ab2ced5c37 Merge pull request #3352 from ralphwetzel/dev
Subflow: Add labels to OUTPUT nodes
2022-01-25 17:07:12 +00:00
Steve-Mcl
faf31be0dc Ensure label is shown in help tree 2022-01-25 16:30:30 +00:00
Nick O'Leary
ff4c67d068 Merge pull request #3353 from kazuhitoyokoi/dev-addjpn
Add Japanese translations for v2.2.0-beta.1
2022-01-25 16:02:29 +00:00
Steve-Mcl
10b133db02 bug: merge issue. fixes #3364 2022-01-25 14:47:36 +00:00
Nick O'Leary
f0bf607b43 Merge pull request #3359 from node-red-hitachi/fix-action-list-i18n
fix to make actions list i18n ready and Japanese translation
2022-01-25 14:47:18 +00:00
Steve-Mcl
8948ca5323 Merge branch 'dev' into mqtt-reconnect-fix 2022-01-25 12:32:49 +00:00
Steve-Mcl
9c3be51fe9 Improve MQTT broker disconnect situation
* Ensure topic is sane to prevent error 129
* Ensure a log entry is made
* Update node status
2022-01-25 12:29:51 +00:00
Hiroyasu Nishiyama
2da9161f29 Update packages/node_modules/@node-red/editor-client/src/js/ui/actions.js
Oh, I'm sorry about this.

Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-01-25 21:21:39 +09:00
Hiroyasu Nishiyama
983dad5b53 add test for env var access of GROUP_ID & GROUP_NAME 2022-01-25 21:07:38 +09:00
Hiroyasu Nishiyama
8b23d341b4 add support for env var access of GROUP_ID & GROUP_NAME 2022-01-25 21:04:43 +09:00
Hiroyasu Nishiyama
0ad60013aa add test for env var access of FLOW_ID & FLOW_NAME 2022-01-25 20:52:45 +09:00
Hiroyasu Nishiyama
289815e128 add support of FLOW_ID & FLOW_NAME 2022-01-25 20:46:01 +09:00
Kazuhito Yokoi
f7ee83f1b9 Add translations for restoring zoom level and scroll position 2022-01-25 11:18:35 +09:00
Nick O'Leary
f67aafa8d3 Merge pull request #3361 from node-red/zoom-level
Remember Zoom level and Sidebar tab selection between sessions
2022-01-24 23:21:31 +00:00
Nick O'Leary
4e5ddd57bf Merge branch 'dev' of github.com:node-red/node-red into dev 2022-01-24 23:18:43 +00:00
Nick O'Leary
e0d4ecf835 Merge branch 'master' into dev 2022-01-24 23:18:25 +00:00
Nick O'Leary
81a461115b Merge pull request #3365 from node-red-hitachi/fix-http-request-set-cookie
Fix http request set cookie to use sync API
2022-01-24 21:26:29 +00:00
Nick O'Leary
d679b02658 Add option to remember zoom and scroll position in localStorage 2022-01-24 21:04:27 +00:00
Hiroyasu Nishiyama
5effcdb024 use setCookieSync instead of setCookie 2022-01-19 23:45:13 +09:00
Nick O'Leary
211a5eb2bb Bump for 2.1.6 2022-01-18 09:46:57 +00:00
Nick O'Leary
c4465ba58d Merge pull request #3351 from node-red-hitachi/fix-delay-rate-unit-validation
fix unit value validation of delay node
2022-01-18 09:45:56 +00:00
Nick O'Leary
7903c53876 Merge pull request #3363 from node-red/revert-copy-fix
Revert copy-text change and apply alternative fix
2022-01-18 09:28:37 +00:00
Nick O'Leary
dbefe6a560 Revert copy-text change and apply alternative fix
Reverts PR #3331 and applies the alternative fix originally proposed
in PR #3329
2022-01-18 09:27:15 +00:00
Nick O'Leary
8b1f412255 Merge pull request #3362 from node-red/update-marked
Update marked to latest
2022-01-18 09:22:28 +00:00
Nick O'Leary
a2e0074061 Update marked to latest 2022-01-18 09:20:52 +00:00
Nick O'Leary
5fc920087b Store user zoom level in localStorage 2022-01-17 21:27:48 +00:00
Nick O'Leary
085233ab9b Remember last sidebar tab between editor sessions 2022-01-17 21:27:21 +00:00
Hiroyasu Nishiyama
6657b2629f move i18n code to action list according to PR comment 2022-01-16 12:10:19 +09:00
Nick O'Leary
310a279aaf Merge pull request #3358 from node-red-hitachi/fix-property-error-tooltip
fix to make start of property error tooltip messages aligned
2022-01-15 19:44:18 +00:00
Hiroyasu Nishiyama
58f3a76da7 fix to make actions list i18n ready and Japanese translation 2022-01-15 20:39:05 +09:00
Hiroyasu Nishiyama
a2c9458b1b aligin start of property error tooltip messages 2022-01-15 13:11:56 +09:00
Hiroyasu Nishiyama
75bcd9e8d5 add support for accessing node id & name as env var 2022-01-14 23:40:12 +09:00
Kazuhito Yokoi
977e7ef395 Add Japanese translations for v2.2.0-beta.1 2022-01-14 14:43:28 +09:00
ralphwetzel
eb1b8b577f Merge branch 'node-red:dev' into dev 2022-01-13 23:36:23 +01:00
ralphwetzel
28f91685ce Subflow: Add labels to OUTPUT nodes 2022-01-13 23:33:06 +01:00
Nick O'Leary
81a4fe59d9 Update changelog/welcome tour for 2.2 2022-01-13 15:16:16 +00:00
Hiroyasu Nishiyama
e7189ab81f fix unit value validation of delay node 2022-01-13 23:52:06 +09:00
Nick O'Leary
346db89e66 Merge pull request #3349 from node-red-hitachi/fix-inject-property-validation
fix JSON propety validation of inject node
2022-01-13 12:50:17 +00:00
Hiroyasu Nishiyama
f786c7f144 fix JSON propety validation of inject node 2022-01-13 21:42:50 +09:00
Nick O'Leary
51f45293b8 Merge branch 'master' into dev 2022-01-13 10:52:36 +00:00
Nick O'Leary
943b103001 Update changelog 2022-01-13 10:29:20 +00:00
Nick O'Leary
f055d42277 Update package version for 2.1.5 2022-01-13 10:22:41 +00:00
Nick O'Leary
fb7a2a8d5d Update dependencies 2022-01-13 10:19:56 +00:00
Nick O'Leary
1e5ed2a2e3 Merge pull request #3331 from kazuhitoyokoi/master-fixcopybutton2
Fix copy buttons on the debug window (another method)
2022-01-13 09:50:27 +00:00
Nick O'Leary
e1467dfe23 Merge pull request #3348 from node-red/scrollbar-expand
Prevent function scrollbar from obscuring expand button
2022-01-13 09:49:15 +00:00
Nick O'Leary
c480f96d30 Prevent function scrollbar from obscuring expand button
Fixes #2955
2022-01-13 09:46:37 +00:00
Kazuhito Yokoi
cf613aafb2 Update packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2022-01-13 10:35:12 +09:00
Nick O'Leary
20dbf7c5f4 Merge pull request #3346 from node-red/fix-stack-capture
Handle reporting error location when stack is truncated
2022-01-12 22:54:25 +00:00
Nick O'Leary
47c912c25b Merge pull request #3345 from node-red/jsonata-compat-mode-fix
Improve jsonata legacy mode detection regex
2022-01-12 22:54:05 +00:00
Nick O'Leary
48fb1a8127 Merge pull request #3344 from node-red/fix-ws-hb
Only setup ws client heartbeat once it is connected
2022-01-12 22:53:51 +00:00
Nick O'Leary
6c1b55db16 Merge pull request #3347 from node-red/flow-name-increment
Fix generating flow name with incrementing number
2022-01-12 22:53:33 +00:00
Nick O'Leary
df70c8a800 Fix generating flow name with incrementing number
Fixes #3295
2022-01-12 22:45:18 +00:00
Nick O'Leary
82ae2e7118 Handle reporting error location when stack is truncated
Fixes #3292
2022-01-12 22:07:44 +00:00
Nick O'Leary
0cf9b5f3df Improve jsonata legacy mode detection regex
Fixes #3290
2022-01-12 21:56:38 +00:00
Nick O'Leary
036a825892 Only setup ws client heartbeat once it is connected
Fixes #3264
2022-01-12 21:46:56 +00:00
Nick O'Leary
8b43b31c64 Add checkbox on project-open screen to clear context 2022-01-12 21:05:47 +00:00
Nick O'Leary
3abef972a7 Clear context contents when switching projects
Fixes #3240
2022-01-12 18:59:29 +00:00
Nick O'Leary
30b00741b5 Merge pull request #3296 from node-red/Json-try-parse-buffer
Let JSON node attempt to parse buffer if it contains a valid string
2022-01-12 18:58:02 +00:00
Nick O'Leary
f86e743cce Merge branch 'master' into dev 2022-01-12 17:59:26 +00:00
Nick O'Leary
cb96fb735e Merge pull request #3289 from node-red/snap-grid
Snap nodes on grid using either edge as reference
2022-01-12 17:57:26 +00:00
Nick O'Leary
459a52d31d Merge pull request #3340 from node-red/cut-wires
Add wire-slice mode to delete wires with Ctrl-RHClick-Drag
2022-01-12 17:52:54 +00:00
Nick O'Leary
44ef9a13d6 Merge pull request #3338 from node-red/detach-action
Detach action
2022-01-12 17:52:32 +00:00
Nick O'Leary
0bb3652a63 Merge pull request #3323 from node-red/highlight-links
Highlight links when selecting nodes
2022-01-12 17:52:03 +00:00
Nick O'Leary
6a82d683a9 Merge pull request #3262 from node-red/search-history
Add search history to main search box
2022-01-12 17:51:46 +00:00
Nick O'Leary
fad708e8de Merge pull request #3294 from node-red/multi-select-links
Allow multiple links to be selected by ctrl-click
2022-01-12 17:51:15 +00:00
Nick O'Leary
c6a38b8355 Merge pull request #3300 from node-red/remove-use-of-verbose-flag-in-core-nodes
Remove use of verbose flag in core nodes - and use node.debug level instead
2022-01-12 17:38:34 +00:00
Nick O'Leary
ee84eb666b Merge pull request #3307 from node-red/add-tls-option-to-tcp-node
Add TLS option to tcp client nodes
2022-01-12 17:37:43 +00:00
Nick O'Leary
6d2793cac6 Merge pull request #3336 from node-red-hitachi/add-link-call-example
add link call example
2022-01-12 17:31:57 +00:00
Nick O'Leary
86d518fc2e Merge pull request #3343 from node-red/adminAuth-logging
Initialize passport when only adminAuth.tokens is set
2022-01-12 17:31:44 +00:00
Nick O'Leary
25dba1a6d5 Merge pull request #3342 from node-red/add-log-logging
Add log logging
2022-01-12 17:29:29 +00:00
Nick O'Leary
af949c62c2 Allow 'escape' to cancel wire-slicing 2022-01-12 17:24:25 +00:00
Nick O'Leary
ea20342d76 Handle non-error responses from token function 2022-01-12 13:48:06 +00:00
Nick O'Leary
7732d52583 Initialize passport when only adminAuth.tokens is set
Fixes #3341
2022-01-12 13:27:01 +00:00
Nick O'Leary
c801bc5e6b Add error logging if Node.log throws an error
Part of #3327
2022-01-12 11:13:29 +00:00
Nick O'Leary
ea43729063 Add _module to Node object to provide module info 2022-01-12 11:07:25 +00:00
Nick O'Leary
e26bae8027 Merge pull request #3333 from tobiasoort/dev
Implemented support for Websocket Subprotocols in WS Client Node.
2022-01-12 09:31:55 +00:00
Tobias Oort
555f155cad Added support for commaseparated subprotocols
Removed placeholder from html
2022-01-12 09:10:35 +01:00
Nick O'Leary
f8c47f59bc Merge pull request #3339 from node-red/fix-filter-node-start-condition
Fix for filter node narrrowbandEq mode start condition failure
2022-01-11 22:39:14 +00:00
Nick O'Leary
f3997128b9 Add wire-slice mode to delete wires with Ctrl-RHClick-Drag 2022-01-11 19:49:40 +00:00
Nick O'Leary
154a4e23dd Add delete-selection-and-reconnect action 2022-01-11 14:11:55 +00:00
Dave Conway-Jones
52e4e0e569 Fix for narrrowbandEq mode start condition failure
And add test
As discussed https://discourse.nodered.org/t/the-filter-node-or-the-old-rbe-node/56371
2022-01-11 13:56:44 +00:00
Nick O'Leary
30f2b96c68 Pressing escape whilst DETACH_DRAGGING should revert change 2022-01-11 00:24:34 +00:00
Nick O'Leary
58c94b7773 Add core:detach-selected-nodes action 2022-01-11 00:16:24 +00:00
Tobias Oort
83203d5f5d Fixed property name in unit-test 2022-01-10 22:23:45 +01:00
Dave Conway-Jones
f77d161643 remove debug msg from inject close 2022-01-10 20:22:20 +00:00
Nick O'Leary
6580b139c0 Merge pull request #3288 from node-red/wiring-shortcut
Wiring shortcut
2022-01-10 18:34:06 +00:00
Nick O'Leary
2743c7c6ac Merge pull request #3304 from node-red-hitachi/dev-unknownconfig
Check availability of type of config node on deploy
2022-01-10 18:33:36 +00:00
Nick O'Leary
062f76214e Merge pull request #3325 from hardillb/http-basic-username-only
Fix basic auth with empty username or password
2022-01-10 18:27:55 +00:00
Nick O'Leary
ce98ed98a2 Merge pull request #3334 from Steve-Mcl/fix-monaco-expanded
load extralibs when expanding monaco. fixes #3319
2022-01-10 18:23:07 +00:00
Nick O'Leary
dce9d93f6c Merge pull request #3335 from node-red-hitachi/fix-file-node-example
Update file node examples according to node name change
2022-01-10 18:22:39 +00:00
Nick O'Leary
f7e35a6cbe Merge pull request #3337 from node-red-hitachi/fix-selection
resume focus after import/export dialog close
2022-01-10 18:21:55 +00:00
Hiroyasu Nishiyama
931335220f resume focus after import/export dialog close 2022-01-09 23:34:08 +09:00
Hiroyasu Nishiyama
3ce35a8a4b add link call example 2022-01-09 20:24:15 +09:00
Hiroyasu Nishiyama
9ac4e5cf6a update file node examples according to node name change 2022-01-09 19:49:06 +09:00
Tobias Oort
bd77d7eec3 Implemented support for Websocket Subprotocols in WS Client Node. 2022-01-08 22:18:05 +01:00
Steve-Mcl
b5e48aa509 load extralibs when expanding monaco. fixes #3319 2022-01-08 19:29:49 +00:00
Kazuhito Yokoi
b14c42b6a4 Update Japanese translations in node help (#3332)
* Update Japanese translations in node help

* Fix typos
2022-01-07 17:43:53 +00:00
Kazuhito Yokoi
ba794ba58c Use clipboard.writeText() instead of execCommand("copy") 2022-01-07 11:49:26 +09:00
Kazuhito Yokoi
b00282590d Fix copy buttons on the debug window 2022-01-07 09:27:01 +09:00
Ben Hardill
44616c6872 Fix basic auth with empty username or password
fix for #3324
2022-01-05 20:56:46 +00:00
Nick O'Leary
aaa2b4c3db Merge pull request #3322 from node-red/inject-props-fix
Fix incorrect clearing of blank payload property in Inject node
2022-01-04 18:59:05 +00:00
Nick O'Leary
8974d8e4df Merge pull request #3321 from node-red/fix-prev-tab-action
Fix findPreviousVisibleTab action
2022-01-04 18:58:45 +00:00
Nick O'Leary
699063cbb0 Merge pull request #3312 from node-red/hide-tabs-fix
Fix storing hidden tab state when not hidden via action
2022-01-04 18:58:32 +00:00
Nick O'Leary
e76000b713 Merge pull request #3311 from node-red/strip-empty-env
Avoid adding empty env properties to tabs/groups
2022-01-04 18:57:53 +00:00
Nick O'Leary
332b372e31 Merge pull request #3310 from node-red/group-env-fix
Update Function to use correct api to access env vars
2022-01-04 18:57:33 +00:00
Nick O'Leary
cb3fcb7bfa Ctrl-Shift-Click on node should add to existing selection 2022-01-03 23:29:42 +00:00
Nick O'Leary
bef641609e Select links when nodes on either side selected 2022-01-03 23:29:12 +00:00
Nick O'Leary
24b52f09df Add RED.nodes.getNodeLinks to help node-link lookup 2022-01-03 23:27:25 +00:00
Nick O'Leary
942b17b807 Fix incorrect clearing of blank payload property in Inject node
Fixes #3316
2022-01-03 21:51:49 +00:00
Nick O'Leary
cf19d7f3ad Fix findPreviousVisibleTab action
Fixes #3320
2022-01-03 21:20:23 +00:00
Nick O'Leary
ebd62a4112 Fix storing hidden tab state when not hidden via action
Fixes #3305
2021-12-28 10:29:42 +00:00
Nick O'Leary
9af7357ca4 Avoid adding empty env properties to tabs/groups
Fixes #3306
2021-12-27 12:03:40 +00:00
Nick O'Leary
0dbc35c252 Update Function to use correct api to access env vars
Fixes #3299
2021-12-27 11:55:10 +00:00
Dave Conway-Jones
c9f03f1ac5 better tests
(and a small fix as a result)
2021-12-27 09:51:50 +00:00
Dave Conway-Jones
02bd292b8c fix and test 2021-12-26 16:12:47 +00:00
Dave Conway-Jones
e5f1029d0c fix variable names for test 2021-12-26 15:37:41 +00:00
Dave Conway-Jones
cae247160f Let tcprequest split incoming strings on delimiter (as per tcpin node)
and fixup i18n messages
2021-12-26 15:28:16 +00:00
Dave Conway-Jones
6692b1992c TCP add tls option to inbound nodes 2021-12-26 12:12:31 +00:00
Dave Conway-Jones
0937837b7f Add TLS config option to TCP client nodes
(not yet when in server mode)
2021-12-24 16:18:00 +00:00
Kunihiko Toumura
828888490a check availability of config node on deploy 2021-12-21 18:10:42 +09:00
Kazuhito Yokoi
91cb6ba73b Add Japanese translations for hidden flow (#3302) 2021-12-20 09:34:41 +00:00
Nick O'Leary
4ee4d32b2e Merge pull request #3301 from kazuhitoyokoi/master-fixwelcometour
Fix hide icon in tour guide
2021-12-17 11:19:27 +00:00
Kazuhito Yokoi
8df630a2f5 Fix hide button icon in tour guide 2021-12-17 19:37:29 +09:00
Dave Conway-Jones
2cad42870e chaneg exec, file and inject node to use node.debug rather than -v flag 2021-12-17 09:58:10 +00:00
Nick O'Leary
43651135f3 Replace selectedLinks array with wrapped Set object 2021-12-13 21:02:55 +00:00
Dave Conway-Jones
6ae42eb787 Let JSON parser attempt to parse buffers if they contain strings
and add/fix test
2021-12-10 15:21:43 +00:00
Nick O'Leary
ecaf866613 Fix serialisation of selection in view 2021-12-07 09:29:11 +00:00
Nick O'Leary
5ea3329b36 Allow multiple links to be selected by ctrl-click 2021-12-07 09:19:27 +00:00
Nick O'Leary
7bb7149f4c Snap nodes on grid using either edge as reference 2021-12-05 23:23:57 +00:00
Nick O'Leary
5856d043ca Add node wiring actions 2021-12-05 19:52:47 +00:00
Nick O'Leary
7cd3e49f04 Merge branch 'master' into dev 2021-12-05 19:32:13 +00:00
Nick O'Leary
173e75175e update changelog 2021-12-02 09:30:41 +00:00
Nick O'Leary
800006dd76 Merge pull request #3282 from node-red/tab-buttons
Change tab hide button icon to an eye and add search option
2021-12-02 09:29:28 +00:00
Nick O'Leary
a824b6910a Add tooltips to tabs and close/hide buttons 2021-12-02 09:23:13 +00:00
Nick O'Leary
dcea382b38 Change tab hide button icon to an eye and add search option 2021-12-01 17:54:17 +00:00
Nick O'Leary
d9f976baea Update package for 2.1.4 2021-12-01 16:06:03 +00:00
Nick O'Leary
1fa13efe19 Merge pull request #3281 from node-red/i18n-space-ns-fix
Fix i18n handling of namespaces with spaces in
2021-12-01 15:15:38 +00:00
Nick O'Leary
33af5cd7c6 Apply i18n namespace fix to runtime component 2021-12-01 15:15:08 +00:00
Nick O'Leary
7cb8f97ef1 Fix i18n handling of namespaces with spaces in 2021-12-01 15:08:04 +00:00
Nick O'Leary
bf965a9cde Merge pull request #3280 from node-red/auto-complete-fix
Trigger change event when autoComplete fills in input
2021-12-01 14:38:10 +00:00
Nick O'Leary
17ffff685a Trigger change event when autoComplete fills in input
Fixes #3271
2021-12-01 14:35:45 +00:00
Nick O'Leary
ae76271cff Merge pull request #3279 from node-red/cn-fix
Apply CN i18n fix
2021-12-01 14:26:37 +00:00
Nick O'Leary
8f3a96d615 Apply CN i18n fix
Fixes #3272

Verified with Google Translate this is a better translation for
"Export to library"
2021-12-01 14:25:35 +00:00
Nick O'Leary
30e750dfe5 Merge pull request #3278 from node-red-hitachi/fix-env-var-access
fix env var access using $parent for groups
2021-12-01 14:23:44 +00:00
Nick O'Leary
682dff7c6f Merge pull request #3273 from node-red-hitachi/fix-config-select-name
fix select menu label of config node to use paletteLabel
2021-12-01 14:02:55 +00:00
Nick O'Leary
85415eb8a8 Merge pull request #3275 from node-red-hitachi/fix-node-conflict
fix removed tab not to cause node conflict
2021-12-01 14:01:50 +00:00
Nick O'Leary
68a80b9244 Merge pull request #3277 from node-red/debug-path-fix
Add proper error handling for 404 errors when serving debug files
2021-12-01 13:48:25 +00:00
Hiroyasu Nishiyama
c331da7323 fix env var access using $env for groups 2021-11-27 19:29:57 +09:00
Nick O'Leary
04ffa06221 Add proper error handling for 404 errors when serving debug files 2021-11-26 11:30:51 +00:00
Hiroyasu Nishiyama
1f0690c6ec fix removed tab not to cause node conflict 2021-11-25 13:26:52 +09:00
Hiroyasu Nishiyama
711467abcd fix select menu label of config node to use paletteLabel 2021-11-24 14:06:45 +09:00
Nick O'Leary
9439cd0e3d Merge pull request #3179 from kazuhitoyokoi/dev-addjpn
Add Japanese translations for Node-RED v2.1.0-beta.1
2021-11-22 23:25:33 +00:00
Nick O'Leary
314c19650d Merge pull request #3239 from node-red/group-diff-fix
Group diff fix
2021-11-22 23:25:19 +00:00
Nick O'Leary
ed6afcd802 Merge pull request #3251 from node-red/regex-debug
Handle RegExp types in Debug sidebar
2021-11-22 23:24:55 +00:00
Nick O'Leary
082d4fe8e1 Merge pull request #3252 from node-red/disable-hidden-flow
Only toggle disabled workspace flag if on activeWorkspace
2021-11-22 23:24:39 +00:00
Nick O'Leary
cd23b44506 Merge pull request #3253 from node-red/clear-disabled-status
Do not show status for disabled nodes
2021-11-22 23:24:18 +00:00
Nick O'Leary
46b6b024b9 Merge pull request #3269 from node-red/auth-id
Include full user object on login audit events
2021-11-22 23:24:00 +00:00
Nick O'Leary
cb88cc35e5 Merge pull request #3261 from node-red/fix-delay-2nd-output-when-in-per-topic-mode
fix 2nd output when in rate limit per topic modes
2021-11-22 23:23:35 +00:00
Nick O'Leary
75c0c44809 Merge pull request #3265 from kazuhitoyokoi/master-fixtourguide
Set dimension value for tour guide
2021-11-22 23:23:03 +00:00
Nick O'Leary
a091b82ba9 Merge pull request #3263 from node-red/ti-fix
Avoid redundant initialisation of TypedInput type
2021-11-22 23:20:40 +00:00
Nick O'Leary
a3b8f022e6 Merge pull request #3270 from bonanitech/node-port-label-color
Don't let themes change flow port label color
2021-11-22 23:20:30 +00:00
Nick O'Leary
279fcb7c51 Merge pull request #3267 from node-red-hitachi/fix-link-target-select
fix to show link target when selected
2021-11-22 23:20:04 +00:00
Mauricio Bonani
49a9376073 Change flow port label CSS variable 2021-11-22 16:24:14 -05:00
Nick O'Leary
96840ede56 Include full user object on login audit events 2021-11-22 19:58:48 +00:00
Hiroyasu Nishiyama
7e7f481f99 fix to show link target when selected 2021-11-19 17:14:22 +09:00
Kazuhito Yokoi
3edbf52bc6 Set dimension value for tour guide 2021-11-18 15:38:49 +09:00
Nick O'Leary
fba6e801fc Avoid redundant initialisation of TypedInput type 2021-11-16 14:32:09 +00:00
Nick O'Leary
720a163273 Bump dev version 2021-11-15 23:38:01 +00:00
Nick O'Leary
a9b12e5172 Add search history to main search box 2021-11-15 23:24:57 +00:00
Dave Conway-Jones
6ac0c0a367 fix 2nd output when in rate limit per topic modes
to fix issue found in #3260
2021-11-15 14:05:16 +00:00
Kazuhito Yokoi
300402d253 Add Japanese translation for tour button 2021-11-12 18:15:57 +09:00
Kazuhito Yokoi
0d9bfae503 Add Japanese translations to tour guide for first flow 2021-11-11 13:02:52 +09:00
Nick O'Leary
bfe0d3b8a3 Do not show status for disabled nodes
Fixes #3249
2021-11-08 21:12:13 +00:00
Nick O'Leary
5fdd9c0546 Only toggle disabled workspace flag if on activeWorkspace
Fixes #3244
2021-11-08 20:38:34 +00:00
Nick O'Leary
b6570a16b8 Handle RegExp types in Debug sidebar
Fixes #3245
2021-11-08 20:24:10 +00:00
Kazuhito Yokoi
8e2d3ea16f Remove unused messages in language catalog 2021-11-08 13:46:24 +09:00
Kazuhito Yokoi
bc2c81f058 Add Japanese translations for link call, mqtt and file nodes 2021-11-08 13:38:17 +09:00
Nick O'Leary
3e0f080ea7 Merge pull request #3242 from node-red/inject-fix
Do not modify inject node props in oneditprepare
2021-11-01 21:40:47 +00:00
Nick O'Leary
679e07189d Do not modify inject node props in oneditprepare
Fixes #3241
2021-11-01 20:10:52 +00:00
Nick O'Leary
a38ebef100 Display group changes property in diff view 2021-10-28 12:14:56 +01:00
Nick O'Leary
b8ad6475e1 Strip off env property if it is empty - avoid inflated flow files 2021-10-28 12:14:34 +01:00
Nick O'Leary
0f0cb3ac6d Fix setting object env var properties so they can be undone 2021-10-28 12:14:03 +01:00
Nick O'Leary
d3efb9d7cc Merge pull request #3238 from node-red/treeLister-gutter-fix
Fix treeList gutter calculation to handle floating gutters
2021-10-28 10:46:04 +01:00
Nick O'Leary
84a237d3f5 Fix treeList gutter calculation to handle floating gutters
Fixes #3234
2021-10-28 10:44:50 +01:00
Nick O'Leary
e6de52eede Merge pull request #3236 from hardillb/http-basic-username-only
HTTP Basic Auth should always add : between username and password even if empty
2021-10-28 10:14:02 +01:00
Nick O'Leary
98aee964d7 Merge pull request #3237 from node-red/remove-de-style
Remove styling from de locale files
2021-10-28 10:11:54 +01:00
Nick O'Leary
570e5442e0 Remove styling from de locale files
Fixes #3230
2021-10-28 10:10:22 +01:00
Ben Hardill
b77a2dc353 Better fix 2021-10-28 10:08:28 +01:00
Ben Hardill
87af31de20 HTTP Basic Auth should always add : to username
fix for #3235
2021-10-28 09:18:17 +01:00
Nick O'Leary
cfe201dbe1 Bump for 2.1.3 2021-10-26 10:42:53 +01:00
Nick O'Leary
6ccdab35e0 Merge pull request #3227 from node-red/reload-node-settings
Refresh editor settings whenever a node is added or enabled
2021-10-26 09:51:41 +01:00
Nick O'Leary
55b9f36b45 Merge pull request #3229 from node-red/spinner-css
Revert spinner css change that made it shrink in some cases
2021-10-26 09:51:31 +01:00
Nick O'Leary
fbcb1130c9 Merge pull request #3221 from hardillb/disable-tours
Add environment variable to enable/disable tours
2021-10-26 09:47:17 +01:00
Nick O'Leary
d4f7a6d2bc Revert spinner css change that made it shrink in some cases 2021-10-26 09:44:32 +01:00
Nick O'Leary
8a19f71abe Refresh editor settings whenever a node is added or enabled
Fixes #3217

This ensures any node-provided settings are loaded and ready
for use by the nodes
2021-10-25 20:48:01 +01:00
Nick O'Leary
fb153757b5 Merge pull request #3225 from node-red/i18n-fix
Fix loading non-default language files leaving runtime in wrong locale
2021-10-25 16:06:12 +01:00
Nick O'Leary
4f175fc93e Fix loading non-default language files leaving runtime in wrong locale 2021-10-25 15:58:07 +01:00
Nick O'Leary
2d4ca7cec0 Merge pull request #3224 from node-red/import-msg-fix
Fix import notification message when importing config nodes
2021-10-25 15:12:46 +01:00
Nick O'Leary
bf0ea89969 Fix import notification message when importing config nodes 2021-10-25 15:08:30 +01:00
Nick O'Leary
073f0c2a20 Merge pull request #3223 from node-red/ti-fix
Handle changing types of TypedInput repeatedly
2021-10-25 13:55:38 +01:00
Nick O'Leary
ba83be9062 Handle changing types of TypedInput repeatedly
Fixes #3222
2021-10-25 13:54:42 +01:00
Ben Hardill
2e7188ea4f Add environment variable to enable/disable tours
NODE_RED_ENABLE_TOURS

Also had to patch editor-api/lib/editor/themes.js to pass
`editorTheme.tours` to the editor.
2021-10-25 11:25:31 +01:00
Nick O'Leary
5a012182d9 Update gen-publish script to update 'next' tag for main releases 2021-10-25 10:05:23 +01:00
Nick O'Leary
b855438af6 Fix changelog 2021-10-25 09:42:44 +01:00
Nick O'Leary
2ffea143e7 Bump for 2.1.2 2021-10-25 09:38:32 +01:00
Duncan Bellamy
61d85b49e6 Remove bash dependency (#3216)
Change backticks to dollar sign and parentheses
2021-10-25 08:44:49 +01:00
Nick O'Leary
35f617e96c Merge pull request #3213 from GerwinvBeek/markdown-regex
Improved regex for markdown renderer
2021-10-24 23:04:20 +01:00
Nick O'Leary
6b6ad47c35 Merge pull request #3220 from node-red/ti-fixes
Fix TypedInput initialisation
2021-10-24 22:58:55 +01:00
Nick O'Leary
e57183ed0e Merge pull request #3219 from Steve-Mcl/mqtt-use-datatype
fix datatype in node config not used. fixes #3215
2021-10-24 22:58:36 +01:00
Nick O'Leary
ecfd61a822 Fix TypedInput initialisation handle 2021-10-24 22:53:22 +01:00
Steve-Mcl
153f87704b fix datatype in node config not used. fixes #3215 2021-10-24 22:21:44 +01:00
Gerwin van Beek
836f7d2163 Improved regex for markdown renderer 2021-10-22 17:05:37 +02:00
Nick O'Leary
d4d6f71cf4 Bump for 2.1.1 2021-10-22 09:27:52 +01:00
Nick O'Leary
42a9da006e Merge pull request #3212 from node-red/fix-tour-guide-width
Ensure tourGuide popover doesn't fall offscreen
2021-10-22 09:26:31 +01:00
Nick O'Leary
2bd5c4f527 Ensure tourGuide popover doesn't fall offscreen
Only handles the left hand edge - will need expanding to cover
the other edges as needed
2021-10-22 09:24:40 +01:00
Nick O'Leary
6a49b5c106 Merge pull request #3210 from node-red/fix-old-inject-migration
Fix issue with old inject nodes that migrated topic to 'string' type
2021-10-22 09:16:54 +01:00
Nick O'Leary
23e14d1b72 Merge pull request #3211 from node-red/cache-bust
Add cache-busting query params to index.mst
2021-10-22 09:16:45 +01:00
Nick O'Leary
f4f11c8884 Add cache-busting query params to index.mst 2021-10-22 09:14:01 +01:00
Nick O'Leary
2b220abdb7 Fix issue with old inject nodes that migrated topic to 'string' type 2021-10-22 09:01:24 +01:00
Nick O'Leary
c1d947ebe3 Merge pull request #3207 from node-red/fix-debug-all
Fix TypedInput validation of type without options
2021-10-21 14:45:09 +01:00
Nick O'Leary
d695cf392e Fix TypedInput validation of type without options
Fixes #3206
2021-10-21 14:44:15 +01:00
Nick O'Leary
21304a695c Fix tcprequest deprecation warnings 2021-10-21 09:40:25 +01:00
Nick O'Leary
fa51b06c46 Merge pull request #3205 from node-red/dev
Node-RED 2.1.0
2021-10-21 09:13:09 +01:00
Nick O'Leary
7560bb8d7b Bump for 2.1.0 2021-10-21 09:08:35 +01:00
Nick O'Leary
fc9d65abcc Merge pull request #3204 from node-red/tcp-req-text-output
Add string option to TCP request node output
2021-10-20 09:40:44 +01:00
Dave Conway-Jones
a7413cccd0 reuse existing labels for tcp request buffer/string option 2021-10-20 09:36:08 +01:00
Nick O'Leary
7610353f07 Position popover properly on a scrolled page
Not needed in the core editor, but needed in the docs pages that can scroll
2021-10-19 22:22:53 +01:00
Dave Conway-Jones
d3f978c90c Add optional string type output to tcp request node
to be similar to tcp in. node
2021-10-19 21:34:23 +01:00
Kazuhito Yokoi
b55a8ef62a Merge branch 'dev' into dev-addjpn 2021-10-19 19:20:32 +09:00
Nick O'Leary
8d79deffb5 Merge pull request #3202 from node-red/tour-guide-fix
Fixes from 2.1.0-beta.2
2021-10-19 10:20:24 +01:00
Nick O'Leary
8158487c3e Reduce churn in setting Switch rule typedInput type 2021-10-19 10:12:13 +01:00
Nick O'Leary
0cc061196d Handle changing value before type without reseting TypedInput 2021-10-19 10:11:37 +01:00
Nick O'Leary
d0ec055222 Fix Inject/Change node restoring typedInput options 2021-10-18 21:23:42 +01:00
Nick O'Leary
ae12ddd32b Change node: Fix deepCopy checkbox spacing on Safari 2021-10-18 20:38:46 +01:00
Nick O'Leary
31da3adaa9 Fix hide/show of palette in tour and add MQTT nodes 2021-10-18 20:29:37 +01:00
Nick O'Leary
9fd5213f13 Merge pull request #3201 from node-red/link-fixes
Fix saving link out node links
2021-10-18 09:43:30 +01:00
Nick O'Leary
de882f5849 Fix saving link out node links 2021-10-18 09:32:00 +01:00
Nick O'Leary
fded1e0021 Refix #3170 - copy switch rule type when adding new rule 2021-10-14 21:47:49 +01:00
Nick O'Leary
6cb06c146d Update for 2.1.0-beta.2 2021-10-14 13:07:58 +01:00
Nick O'Leary
b8f1386ad0 Dynamic MQTT connections (#3189)
* add mqtt-control
- adds auto-connect option to broker
- add new node mqtt-control
- adds i18n messages
- adds documentation

* documentation tweaks

* built in documentation improvements

* fix tip layout causing oversized editor

* remove unused requires

* add missing `unsubscribe` dropdown option
- oddly forgotten - now added

* ensure clientid is updated dynamically

* [rewrite] move mqtt-control login into mqtt-in

* Remove dynamic label

* remove redundant mqtt-control code left overs

* Callback for brokerConn.connect (improve done())
- done is now called on connect callback

* fix race condition if connect/disconnect too fast
- node.connected and node.client.connected getting out of sync

* fix connection fail when switching protocol 3 ~ 5
- ensure protocolId is correct for protocolVersion

* change msg.subscribe prop to `msg.topic`

* unsub all topics if msg.topic is `true`

* delete temprary debugger statements

* Final rework of dynamic mqtt connections

Co-authored-by: Steve-Mcl <sdmclaughlin@gmail.com>
2021-10-14 12:05:06 +01:00
Nick O'Leary
2b38b5ea50 Merge pull request #3200 from node-red/fix-link-call-label
Fix link call label
2021-10-14 12:04:25 +01:00
Nick O'Leary
2f707a6b16 Merge pull request #3199 from node-red/switch-project-fix
Fix switching projects
2021-10-14 12:04:07 +01:00
Nick O'Leary
d4c2fcd559 Merge pull request #3198 from node-red/locale-fix
Use locale setting when installing/enabling node
2021-10-14 12:03:54 +01:00
Nick O'Leary
082970cdb7 Merge pull request #3197 from node-red/tour-projects-fix
Do not show projects-wecome dialog until welcome tour completes
2021-10-14 12:03:41 +01:00
Nick O'Leary
fe97c78977 Merge pull request #3196 from node-red/link-fixes
Fix converting selection to subflow
2021-10-14 12:03:28 +01:00
Nick O'Leary
79394aa69f Merge pull request #3195 from node-red/keyboard-fix
Avoid conflicts with native browser cmd-ctrl type shortcuts
2021-10-14 12:03:17 +01:00
Nick O'Leary
21fd6e3c21 Ensure link call node label updates when link-in changes 2021-10-14 12:00:27 +01:00
Nick O'Leary
de4944cd83 Ensure node is resized if its label changes 2021-10-14 11:53:55 +01:00
Nick O'Leary
3fde5c27ed Fix switching projects 2021-10-14 11:07:49 +01:00
Nick O'Leary
e1d492813e Use locale setting when installing/enabling node
Fixes #3194
2021-10-14 10:57:11 +01:00
Nick O'Leary
48d0ee3b6d Do not show projects-wecome dialog until welcome tour completes
Fixes #3193
2021-10-14 10:17:27 +01:00
Nick O'Leary
eebb64901c Fix converting selection to subflow
Fixes #3191
2021-10-14 09:48:35 +01:00
Nick O'Leary
60e0ed2af6 Avoid conflicts with native browser cmd-ctrl type shortcuts
Fixes #3190
2021-10-14 09:34:46 +01:00
Nick O'Leary
f030694ef4 Merge pull request #3183 from node-red/debug-filter-opts
Redesign debug filter options and make them persistant
2021-10-13 14:47:08 +01:00
Nick O'Leary
e9ed13459a Merge pull request #3184 from node-red/inject-spinner-css
Widen Inject interval box for >1 digit
2021-10-13 14:41:52 +01:00
Nick O'Leary
af1e38fdf7 Merge pull request #3185 from node-red/switch-focus-fix
Fix rule focus when switch 'otherwise' rule is used
2021-10-13 14:41:42 +01:00
Nick O'Leary
b12900e680 Merge pull request #3186 from node-red/context-tools-fix
Ensure message tools stay attached to top-level entry in Debug/Context
2021-10-13 14:41:29 +01:00
Nick O'Leary
44aa1f4a5e Filter out Link Out Return nodes in Link In edit dialog
Fixes #3187
2021-10-13 14:23:43 +01:00
Nick O'Leary
9425548a85 Ensure message tools stay attached to top-level entry in Debug/Context
Fixes #3180
2021-10-12 21:11:20 +01:00
Nick O'Leary
bfd4fc81fe Widen Inject interval box for >1 digit 2021-10-12 17:25:30 +01:00
Nick O'Leary
439af2a325 Fix rule focus when switch 'otherwise' rule is used
Fixes #3182
2021-10-12 17:25:13 +01:00
Nick O'Leary
3204b04455 Overhaul Debug sidebar filter and clear button options 2021-10-12 17:24:51 +01:00
Nick O'Leary
bed1be14ba Allow toolip action/content to be updated 2021-10-12 17:24:46 +01:00
Nick O'Leary
7cd92faf0d Separate 'focus' from 'selected' state in treeList 2021-10-12 17:24:41 +01:00
Nick O'Leary
be7e28af5d Update package dependencies 2021-10-12 17:24:10 +01:00
Nick O'Leary
8eaa762ec5 Merge branch 'dev' of github.com:node-red/node-red into dev 2021-10-11 10:01:46 +01:00
Nick O'Leary
953a9f7cd4 Update to latest node-red-admin 2021-10-11 09:58:55 +01:00
Kazuhito Yokoi
36f099d68b Add Japanese translations for Node-RED v2.1.0-beta.1 2021-10-11 16:02:18 +09:00
Nick O'Leary
c8fd5090bd Merge pull request #3178 from node-red/fix-md-help
Fix table tokenizer for node help markdown renderer
2021-10-08 18:14:10 +01:00
Nick O'Leary
155e1be494 Fix table tokenizer for node help markdown renderer 2021-10-08 17:56:24 +01:00
Nick O'Leary
cf5e125cb3 Merge pull request #3175 from node-red/tab-disabled-fix
Ensure tab state updates properly when toggling enable state
2021-10-08 15:52:16 +01:00
Nick O'Leary
764fc8477d Merge pull request #3176 from node-red/long-module-names
Improve handling of long labels in TreeList
2021-10-08 15:52:05 +01:00
Nick O'Leary
d35e62f8cf Merge pull request #3177 from node-red/scroll-tab-bar
Shift-click tab scroll arrows to jump to start/end
2021-10-08 15:51:56 +01:00
Nick O'Leary
904babdd13 Shift-click tab scroll arrows to jump to start/end 2021-10-08 15:45:17 +01:00
Nick O'Leary
154d3842a8 Improve handling of long labels in TreeList 2021-10-08 15:30:43 +01:00
Nick O'Leary
edb8a120bd Ensure tab state updates properly when toggling enable state 2021-10-08 15:09:51 +01:00
Nick O'Leary
cdfeba0b82 Update changelog 2021-10-07 09:37:24 +01:00
Nick O'Leary
8ce1465e9f Merge branch 'master' into dev 2021-10-07 09:35:52 +01:00
Nick O'Leary
a296b1c9c8 Merge pull request #3172 from node-red/tour-210
Update welcome tour for 2.1.0-beta.1
2021-10-07 09:34:52 +01:00
Nick O'Leary
bb8d7058a4 Merge pull request #3173 from mailsvb/mailsvb-typo-http-request
Typo in http request set method translation
2021-10-07 09:33:03 +01:00
mailsvb
816cfa1c7e Typo in http request set method translation 2021-10-07 08:07:57 +02:00
Nick O'Leary
53938200fc Update changelog 2021-10-06 17:36:51 +01:00
Nick O'Leary
3885bb039d Merge branch 'dev' of github.com:node-red/node-red into dev 2021-10-06 17:35:34 +01:00
Nick O'Leary
4adad6e424 Merge pull request #3166 from node-red/output-discarded-rate-limit
Delay node: add option to send intermediate messages on separate output
2021-10-06 17:34:44 +01:00
Nick O'Leary
5fb9531338 Merge branch 'pr_3146' into dev 2021-10-06 17:33:28 +01:00
Nick O'Leary
273d9c76a7 Add fallback when logging uncaughtExceptions 2021-10-06 17:33:04 +01:00
Nick O'Leary
79a1d6c561 RED.notifiy.update should not change fixed state unless explicitly set 2021-10-06 13:52:36 +01:00
Nick O'Leary
4b0eb8475d Fix updating shortcuts in menus after keyboard dialog closed 2021-10-06 13:51:38 +01:00
Nick O'Leary
3dc874b517 Update welcome tour for 2.1.0-beta.1 2021-10-06 12:05:49 +01:00
Nick O'Leary
8a3da1ce8d update changelog 2021-10-06 11:41:27 +01:00
Nick O'Leary
42d90542b5 Merge pull request #3171 from node-red/auto-complete
Add autoComplete widget and add to TypedInput for msg. props
2021-10-06 11:40:20 +01:00
Nick O'Leary
690a93d82d Update changelog 2021-10-06 10:04:30 +01:00
Nick O'Leary
8042fe4e2b Merge branch 'master' into dev 2021-10-06 09:12:16 +01:00
Nick O'Leary
a27ce375db Update package dependencies 2021-10-06 09:11:20 +01:00
Nick O'Leary
db3688799d Merge pull request #3170 from node-red/switch-rule-type
Copy previous rule type when adding rule to switch node
2021-10-05 23:32:17 +01:00
Nick O'Leary
a88be35292 Merge pull request #3168 from node-red/improve-unit-test-coverage
Improve unit test coverage
2021-10-05 23:31:58 +01:00
Nick O'Leary
e2d7fcbfc2 Add lots of docs to RED.popover 2021-10-05 23:18:29 +01:00
Nick O'Leary
421d155586 Add some docs to autoComplete widget 2021-10-05 20:41:21 +01:00
Nick O'Leary
7f9e318214 Add autoComplete widget and add to TypedInput for msg. props 2021-10-05 17:59:44 +01:00
Nick O'Leary
57386edb7c Merge branch 'dev' of github.com:node-red/node-red into dev 2021-10-05 11:26:19 +01:00
Nick O'Leary
94d5ba4550 Tweak table styles 2021-10-05 11:25:35 +01:00
Nick O'Leary
2a0b4ea828 Merge pull request #3167 from node-red/httprequest-send-error
Add option to only send http response errors to Catch node
2021-10-05 10:44:08 +01:00
Nick O'Leary
893ef227d4 Merge pull request #3084 from Steve-Mcl/theme-monaco-theme
Permit plugin theme to theme monaco editor
2021-10-05 10:42:08 +01:00
Nick O'Leary
1fe6e5a00d Merge pull request #3104 from hardillb/client-editor-fixes
Fix editor-client package.json
2021-10-05 10:40:28 +01:00
Nick O'Leary
6c96cde73c Copy previous rule type when adding rule to switch node 2021-10-05 10:34:46 +01:00
Steve-Mcl
2b12834d53 fix typo in boolean logic test 2021-10-05 00:06:25 +01:00
Steve-Mcl
8a2e74b3b8 fix grunt errors 2021-10-04 23:52:55 +01:00
Steve-Mcl
aa1721ab3d Only style ordered list with dl.message-properties 2021-10-04 23:36:22 +01:00
Steve-Mcl
c0a256306b clean up temp enable flag 2021-10-04 23:34:38 +01:00
Steve-Mcl
f0b03b4ada add styling for mardown tables 2021-10-04 23:02:23 +01:00
Steve-Mcl
5503f53af2 Handle marked adding a <p> to ordered lists.
- This causes the text after a number in the numbered list to be on a new line.
- To fix this, a new style rule is required
2021-10-04 23:00:30 +01:00
Steve-Mcl
a89d294b27 Custom markdown rendering to generate style guide 2021-10-04 22:59:34 +01:00
Nick O'Leary
012e1cbcc5 Improve unit test coverage 2021-10-04 17:53:14 +01:00
Nick O'Leary
3759e0f778 Add option to only send http response errors to Catch node 2021-10-04 14:04:59 +01:00
Nick O'Leary
1c18641699 Delay node: add option to send intermediate messages on separate output 2021-10-04 13:00:24 +01:00
Nick O'Leary
e50e2201b1 Merge pull request #3108 from sammachin/patch-2
change template characters
2021-10-04 10:57:04 +01:00
Nick O'Leary
1419729458 Merge pull request #3163 from node-red/notification-fixes
Allow RED.notify.update to modify any notification setting
2021-10-04 10:56:26 +01:00
Nick O'Leary
c14177b0e8 Merge pull request #3160 from node-red/filter-configs
Allow a node to specify a filter for the config nodes it can pick from
2021-10-04 10:56:16 +01:00
Nick O'Leary
126df969b3 Merge pull request #3157 from node-red/relabel-file-nodes
Add paletteLabel to file nodes to make read/write more obvious
2021-10-04 10:56:01 +01:00
Nick O'Leary
f8ee92ba06 Merge pull request #3158 from node-red/node-install-err-reporting
Improve node install error reporting
2021-10-04 10:55:47 +01:00
Nick O'Leary
81a278dd8c Merge pull request #3156 from node-red/change-clone
Add option to deep-clone properties in Change node
2021-10-04 10:54:52 +01:00
Nick O'Leary
a98013806c Merge pull request #3164 from node-red/fix-http-response-layout
Fix sizing of HTTP Response header fields
2021-10-04 10:54:01 +01:00
Nick O'Leary
0171ffac6a Fix sizing of HTTP Response header fields 2021-10-04 10:52:36 +01:00
Nick O'Leary
7544241316 Allow RED.notify.update to modify any notification setting
Fixes #3162
2021-10-04 10:31:46 +01:00
Nick O'Leary
061afb3a94 Improve RED.actions api to ensure actions cannot be overridden
Also alows multiple args to be passed to an action.
2021-10-02 23:26:01 +01:00
Nick O'Leary
8a5eda9c1f Ensure type select button is not focussable when TypedInput only has one type 2021-10-02 23:25:56 +01:00
Nick O'Leary
f62040f0ec Merge pull request #3161 from node-red/tour-theme
Improve themeing of tourGuide
2021-10-02 23:24:22 +01:00
Nick O'Leary
f2e51779e4 Improve themeing of tourGuide 2021-10-02 23:15:35 +01:00
Nick O'Leary
da114fa3a5 Merge pull request #3152 from node-red/link-call
Add Link Call node
2021-10-01 15:59:43 +01:00
Nick O'Leary
3775a1657b Merge pull request #3153 from node-red/update-monaco
Update monaco to 0.28.1
2021-10-01 15:59:16 +01:00
Nick O'Leary
2bd7c4bc81 Merge pull request #3159 from node-red/multi-select-typedInput
Do better remembering TypedInput values whilst switching types
2021-10-01 15:40:59 +01:00
Nick O'Leary
253c489a33 Allow a node to specify a filter for the config nodes it can pick from 2021-09-30 19:44:34 +01:00
Nick O'Leary
ac84b6fe3f Do better remembering TypedInput values whilst switching types 2021-09-30 18:14:45 +01:00
Nick O'Leary
8761e61439 Include load error in notification of unknown node 2021-09-30 15:39:45 +01:00
Nick O'Leary
29e903e1c8 Improve error reporting when installing bad nodes 2021-09-30 15:28:09 +01:00
Nick O'Leary
ec27e19e3f Add unit tests for Join restartTimeout and update help 2021-09-30 10:59:45 +01:00
Nick O'Leary
5df0dae11a Merge pull request #3121 from magma1447/dev
SPLIT Join node - support for msg.resetTimeout …
2021-09-30 10:45:42 +01:00
Nick O'Leary
7fffc1a36d Merge pull request #3069 from node-red/delay-push-to-front
Add push to front of rate limit queue.
2021-09-30 10:44:14 +01:00
Nick O'Leary
f3d0179834 Add paletteLabel to file nodes to make read/write more obvious 2021-09-30 10:41:18 +01:00
Nick O'Leary
8bf69c598a Ensure tab scroll handles are cleared when hide-all tabs run 2021-09-30 10:34:18 +01:00
Nick O'Leary
aa5fad6628 Add deep copy option to Change node 'set' action 2021-09-30 09:49:51 +01:00
Nick O'Leary
b0f1fad4e2 Change label for 'set' change node action to make it clearer 2021-09-29 19:43:30 +01:00
Nick O'Leary
3b6d0995b4 Merge pull request #3155 from node-red/config-select
Ensure config-node select inherits width properly from input
2021-09-29 19:14:12 +01:00
Nick O'Leary
0cbf4ac37d Better regex for parsing config select width placeholder style 2021-09-29 19:12:13 +01:00
Nick O'Leary
9ccffee82c Ensure config-node select inherits width properly from input
Fixes #3001
2021-09-29 19:06:34 +01:00
Nick O'Leary
1b38e2eedf Merge pull request #3154 from node-red/fix-windows-themes
Fix serving of theme files on Windows
2021-09-29 18:00:41 +01:00
Nick O'Leary
ce87abe96e Fix serving of theme files on Windows
Fixes #3097
2021-09-29 17:59:25 +01:00
Nick O'Leary
becbda8483 Update monaco types 2021-09-29 17:28:06 +01:00
Nick O'Leary
da210e2ae4 Ignore top-level await errs in monaco
Fixes #3138
2021-09-29 17:19:12 +01:00
Nick O'Leary
d4fc6feeba Update to monaco 0.28.1 2021-09-29 17:17:34 +01:00
Nick O'Leary
f1cbca8d76 Add link-call help 2021-09-29 14:46:09 +01:00
Nick O'Leary
dfd9364061 Add timeout option to link-call node 2021-09-29 14:28:12 +01:00
Nick O'Leary
1931395fdb Add basic link-call/return tests 2021-09-29 13:49:55 +01:00
Nick O'Leary
b01fd24e15 Add link-call node and add return mode for link-out node 2021-09-29 10:45:00 +01:00
Nick O'Leary
c9d1329fc2 Add 'radio' option to treeList 2021-09-29 10:44:09 +01:00
Nick O'Leary
ab2d3bfd80 Fix RED.nodes.filterNodes when searching full node set 2021-09-29 10:43:41 +01:00
Nick O'Leary
36bb172f29 Merge pull request #3151 from GerwinvBeek/dev
Restore tab selection after merging conflicts
2021-09-29 00:43:25 +01:00
Gerwin van Beek
01e64be39d rename 2021-09-28 17:33:23 +02:00
Gerwin van Beek
4ebe160f6c Restore tab selection after merging conflicts 2021-09-28 17:19:22 +02:00
Nick O'Leary
b427eca21f Merge pull request #3136 from node-red/tour-guide-2
Add Tour Guide component
2021-09-27 17:59:05 +01:00
Nick O'Leary
3eb438c8d2 Merge pull request #3116 from node-red-hitachi/dev-httpreqlog
Extend HTTP request node to log detailed timing information
2021-09-27 17:56:34 +01:00
Nick O'Leary
068f425833 Merge pull request #3139 from node-red/fs-promises
Fixes to fs promises so that an electron built version runs
2021-09-27 17:51:10 +01:00
Nick O'Leary
b3c84242dc Bump version for 2.1.0-beta.1 2021-09-27 17:50:09 +01:00
Nick O'Leary
24672d91d8 Fix linting error in tourGuide 2021-09-27 17:49:38 +01:00
Nick O'Leary
4422af26ec Try to handle smaller screen sizes in tourGuide 2021-09-27 17:35:49 +01:00
Nick O'Leary
5329e803e2 Add keyboard handling to tourGuide - escape/enter 2021-09-27 17:35:24 +01:00
Nick O'Leary
ad542b91fa Add i18n support to tours 2021-09-27 17:34:30 +01:00
Nick O'Leary
e9e03c945b Add core:show-welcome-tour action and logic to display on first-run 2021-09-27 16:42:51 +01:00
Nick O'Leary
e20cfb3dae Ignore dynamicImport warning from jshint 2021-09-26 20:46:43 +01:00
Nick O'Leary
48baac916c Add initial tour-guide feature 2021-09-26 20:46:38 +01:00
Nick O'Leary
adadf38b08 Allow menu items to be opened via css class 2021-09-26 20:46:33 +01:00
Nick O'Leary
d4e1469450 Allow default tab to be specified when editing flows/groups/subflows 2021-09-26 20:46:28 +01:00
Nick O'Leary
2c456f044f Allow popovers to be moved and styled 2021-09-26 20:46:23 +01:00
Nick O'Leary
228c15ace3 Fix icon position in dropdown menu 2021-09-26 20:38:55 +01:00
Nick O'Leary
a0d15e6e7b Fix menu error for workspace tab button 2021-09-26 20:08:15 +01:00
Nick O'Leary
5ec3544340 Merge pull request #3148 from node-red/login-fixes
Improve error reporting with oauth login strategies
2021-09-24 22:40:15 +01:00
Nick O'Leary
5443a17775 Merge pull request #3120 from node-red/hide-flows
Allow tabs to be hidden
2021-09-24 22:39:42 +01:00
Nick O'Leary
40d60e4eb3 Add allowUpdate to settings file 2021-09-24 22:23:50 +01:00
Nick O'Leary
f3312a6403 Merge pull request #3143 from node-red/upgrade-deny-list
Add allowUpdate feature to externalModules.palette
2021-09-24 22:20:58 +01:00
Nick O'Leary
e638b55b30 Merge pull request #3149 from hardillb/coreNodesDir-false
Allow coreNodesDir to be set to false
2021-09-24 22:20:11 +01:00
Nick O'Leary
5caa76a8b3 Widden default menu to handle shortcuts 2021-09-24 22:15:02 +01:00
Nick O'Leary
901a5ce9d2 Better fade effect when hiding tabs 2021-09-24 22:10:53 +01:00
Nick O'Leary
6ab74951f4 Fix menu shortcut display when menu label is long 2021-09-24 19:44:05 +01:00
Nick O'Leary
c2625d696d Merge branch 'dev' into hide-flows 2021-09-24 19:12:34 +01:00
Ben Hardill
77fb5ef2ab Allow coreNodesDir to be set to false
This will disable all core nodes
2021-09-22 10:21:23 +01:00
Steve-Mcl
c20ca3399e codeEditor.options should take precedence
- over plugins monacoOptions
2021-09-21 14:12:21 +01:00
Steve-Mcl
5825da9c76 Merge branch 'dev' into theme-monaco-theme 2021-09-21 14:06:54 +01:00
Nick O'Leary
e3853ae402 Improve error reporting with oauth login strategies 2021-09-20 11:48:51 +01:00
Renato Junior
bd142a9710 uncaughtException debug improvements
Changed error uncaughtException tracing
2021-09-17 22:02:48 -03:00
Dave Conway-Jones
4f23847546 Fix UDP node to not not use port if unassigned 2021-09-16 16:22:01 +01:00
Nick O'Leary
85820c571d Add unit tests for allowUpdate settings 2021-09-14 10:50:26 +01:00
Nick O'Leary
d9bed03025 Add allowUpdate feature to externalModules.palette 2021-09-13 21:25:12 +01:00
Nick O'Leary
d6e05962c9 Merge pull request #3140 from harmonic7/dev
Allow colouring of tab icon svg
2021-09-13 09:23:59 +01:00
Casey Wilkes
d32636ed6b Tweak theme tests for tabicon colour config 2021-09-10 23:16:42 +12:00
Casey Wilkes
a3d2f6592e Add support for colouring tab icon in settings.js
```
editorTheme: {
    page: {
       tabicon: {
           icon: "full/path/of/tabicon.svg",
           colour: "#008f00"
    }
}
```

The old way still works also (but doesn't allow the tabicon to
be coloured:
```
editorTheme: {
    page: {
       tabicon: "full/path/of/tabicon.svg"
    }
}
```
2021-09-10 13:10:01 +12:00
Nick O'Leary
87b6327c5e Merge branch 'dev' into hide-flows 2021-09-07 13:53:45 +01:00
Nick O'Leary
abaebb329d Merge branch 'dev' into edit-panes-2 2021-09-07 13:42:49 +01:00
Nick O'Leary
8970fe412d Merge pull request #3124 from node-red/raise-lower-nodes
Allow nodes to be raised/lowered in the workspace
2021-09-07 12:19:56 +01:00
Nick O'Leary
9dc5ae21c4 Add menu options for raise/lower actions 2021-09-07 12:04:58 +01:00
Nick O'Leary
4132fb79a6 Allow nodes to be raised/lowered in the workspace 2021-09-07 11:49:31 +01:00
Nick O'Leary
9a4dc30604 Merge pull request #3110 from node-red/view-tools
Add align actions to editor
2021-09-07 11:49:10 +01:00
Nick O'Leary
192b542fe4 Add menu options for align tools and show shortcuts on menu 2021-09-07 11:47:04 +01:00
Kunihiko Toumura
490547cd3d Use httpRequestTimingLog for enable detailed timing log 2021-09-05 15:22:13 +09:00
Nick O'Leary
234e77fd06 Rename registerEditPane function 2021-09-02 22:12:32 +01:00
Nick O'Leary
87ac831c8a Simplify edit pane api 2021-09-02 21:59:30 +01:00
Nick O'Leary
4e92492165 Edit panes should not need to create own tray content div 2021-09-02 21:44:06 +01:00
Nick O'Leary
c3d0b1114f Fix jshint error 2021-09-02 16:37:13 +01:00
Nick O'Leary
4463a7d4ba Move envVar list component to own file 2021-09-02 16:14:35 +01:00
Nick O'Leary
741fe3dd90 Move tab edit dialog into editor and use new edit panes 2021-09-02 14:29:58 +01:00
Nick O'Leary
e910f3915d Initial refactor of edit dialogs to separate panes 2021-09-02 10:33:43 +01:00
Nick O'Leary
39aafc5007 Ensure treeList row has suitable min-height when no content
Fixes #3109
2021-09-02 10:26:54 +01:00
Nick O'Leary
9b83afae42 Fix typo in ko editor.json
Fixes #3119
2021-09-02 10:26:49 +01:00
Mauricio Bonani
bdf54f6cff Change fade color when hovering an inactive tab 2021-09-02 10:26:44 +01:00
Mauricio Bonani
f2a9887a12 Place close tab link in front of fade 2021-09-02 10:26:39 +01:00
bartbutenaers
4f4d78bfab Key and certificate as string or buffer 2021-09-02 10:26:34 +01:00
Hiroyasu Nishiyama
67404a327d merge getFlowSetting to getSetting 2021-09-01 22:26:31 +09:00
Sam Machin
702dfa4b79 Update packages/node_modules/@node-red/nodes/locales/en-US/function/80-template.html
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2021-08-31 16:59:32 +01:00
Nick O'Leary
b36dd62c50 Remove console.log 2021-08-31 15:23:50 +01:00
Nick O'Leary
7026df7d96 Track hidden tabs in localStorage 2021-08-31 15:19:04 +01:00
Nick O'Leary
ed8e7afdf6 Add flow tab bar menu 2021-08-31 14:46:11 +01:00
Hiroyasu Nishiyama
d78e5932f9 update according to PR comments 2021-08-30 08:00:58 +09:00
Nick O'Leary
c880cc0987 Add core:hide-other-tabs and handle multiple tab selection 2021-08-27 11:46:30 +01:00
Nick O'Leary
0874ba7a03 Add core:show-last-hidden-tab and update keymap 2021-08-26 22:20:25 +01:00
Nick O'Leary
7962278475 Allow tabs to be hidden via x-button on tab 2021-08-26 12:06:35 +01:00
Nick O'Leary
c8949f5eeb Fix treeList gutter padding for outliner 2021-08-26 12:06:30 +01:00
Nick O'Leary
8108b93c5f Add core:toggle-tabs action 2021-08-26 12:06:25 +01:00
Nick O'Leary
9dbe531bf7 Remove duplicate hide-tab action 2021-08-26 12:06:20 +01:00
Nick O'Leary
46e2ff1001 Allow tabs to be hidden 2021-08-26 12:06:15 +01:00
Nick O'Leary
d2cdc67ec7 Add distribute-horizontally/vertically actions to editor 2021-08-26 12:05:56 +01:00
Nick O'Leary
56121203bf Rename align actions to match existing align-selection-to-grid 2021-08-26 12:05:51 +01:00
Nick O'Leary
e13133fd2b Add align actions to editor 2021-08-26 12:05:45 +01:00
Magnus Månsson
f20565fd16 Renamed resetTimeout to restartTimeout
Updated documentation differently
2021-08-25 21:53:37 +02:00
Magnus Månsson
cf2d5841f5 SPLIT Join node - support for payload.resetTimeout to restore original timeout 2021-08-25 12:52:10 +02:00
Kunihiko Toumura
401466d6c0 Add timing log 2021-08-23 11:54:05 +09:00
Hiroyasu Nishiyama
6aecc3915c add support of environtment variable for tab & group 2021-08-19 21:15:13 +09:00
Dave Conway-Jones
ef1b3aa7f5 Add comment to info docs re queue depth limit setting 2021-08-18 14:05:42 +01:00
Sam Machin
1aaab2a814 change template characters
Added note about changing template characters
2021-08-12 16:41:32 +01:00
Ben Hardill
711ec39327 Fix editor-client package.json
The main entry pointed to non-existant entry.

Also fixed error when loading nodes lazily
2021-08-06 21:16:34 +01:00
Steve-Mcl
08049252f2 permit plugin theme to change other monaco options 2021-07-31 10:24:48 +01:00
Steve-Mcl
8a1d81989b use codeEditor.options.theme 2021-07-26 21:02:11 +01:00
Steve-Mcl
d7a2fc2be4 use them plugin theme monacoTheme if present 2021-07-25 15:16:49 +01:00
Dave Conway-Jones
4d26b806dd delay - add test for push toFront and flush=1 2021-07-16 11:38:06 +01:00
Dave Conway-Jones
a2b95dbb39 delay node - change lifo property to toFront
add info to sidebar
add tests
2021-07-16 11:31:21 +01:00
Dave Conway-Jones
d820f55358 Add push to front of rate limit queue.
(moved random delay to top to group with other delay types.
Tests and docs to follow
2021-07-15 22:15:46 +01:00
315 changed files with 30778 additions and 8659 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -38,12 +38,9 @@ If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it may well get rejected if you haven't discussed it on
the [forum](https://discourse.nodered.org) first.
All contributors need to sign the JS Foundation's Contributor License Agreement.
It is an online process and quick to do. You can read the details of the agreement
here: https://cla.js.foundation/node-red/node-red.
If you raise a pull-request without having signed the CLA, you will be prompted
to do so automatically.
All contributors need to sign the OpenJS Foundation's Contributor License Agreement.
It is an online process and quick to do. If you raise a pull-request without
having signed the CLA, you will be prompted to do so automatically.
### Code Branches

View File

@@ -162,7 +162,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/colorPicker.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
@@ -182,6 +182,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editor.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/panes/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/*.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js",
@@ -199,7 +200,8 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js"
"packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tour/*.js"
],
dest: "packages/node_modules/@node-red/editor-client/public/red/red.js"
},
@@ -326,6 +328,12 @@ module.exports = function(grunt) {
],
tasks: ['jsonlint:keymaps','copy:build']
},
tours: {
files: [
'packages/node_modules/@node-red/editor-client/src/tours/**/*.js'
],
tasks: ['copy:build']
},
misc: {
files: [
'CHANGELOG.md'
@@ -423,6 +431,12 @@ module.exports = function(grunt) {
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/'
},
{
cwd: 'packages/node_modules/@node-red/editor-client/src/tours',
src: '**',
expand: true,
dest: 'packages/node_modules/@node-red/editor-client/public/red/tours/'
}
]
}
@@ -569,7 +583,7 @@ module.exports = function(grunt) {
grunt.registerMultiTask('attachCopyright', function() {
var files = this.data.src;
var copyright = "/**\n"+
" * Copyright JS Foundation and other contributors, http://js.foundation\n"+
" * Copyright OpenJS Foundation and other contributors, https://openjsf.org/\n"+
" *\n"+
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
" * you may not use this file except in compliance with the License.\n"+

View File

@@ -56,13 +56,13 @@ This project adheres to the [Contributor Covenant 1.4](http://contributor-covena
## Authors
Node-RED is a project of the [OpenJS Foundation](https://openjsf.org).
Node-RED is a project of the [OpenJS Foundation](http://openjsf.org).
It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
It is maintained by:
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
* And many others...
## Copyright and license

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "2.0.6",
"version": "2.2.3",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -26,66 +26,66 @@
}
],
"dependencies": {
"acorn": "8.4.1",
"acorn-walk": "8.1.1",
"ajv": "8.6.2",
"acorn": "8.7.0",
"acorn-walk": "8.2.0",
"ajv": "8.10.0",
"async-mutex": "0.3.2",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"body-parser": "1.19.1",
"cheerio": "1.0.0-rc.10",
"clone": "2.1.2",
"content-type": "1.0.4",
"cookie": "0.4.1",
"cookie-parser": "1.4.5",
"cookie": "0.4.2",
"cookie-parser": "1.4.6",
"cors": "2.8.5",
"cronosjs": "1.7.1",
"denque": "1.5.0",
"express": "4.17.1",
"denque": "2.0.1",
"express": "4.17.2",
"express-session": "1.17.2",
"form-data": "4.0.0",
"fs-extra": "10.0.0",
"fs.notify": "0.0.4",
"got": "11.8.2",
"got": "11.8.3",
"hash-sum": "2.0.0",
"hpagent": "^0.1.2",
"hpagent": "0.1.2",
"https-proxy-agent": "5.0.0",
"i18next": "20.3.2",
"i18next": "21.6.11",
"iconv-lite": "0.6.3",
"is-utf8": "0.2.1",
"js-yaml": "3.14.1",
"json-stringify-safe": "5.0.1",
"jsonata": "1.8.5",
"jsonata": "1.8.6",
"lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0",
"memorystore": "1.6.6",
"mime": "2.5.2",
"moment-timezone": "0.5.33",
"mqtt": "4.2.8",
"multer": "1.4.3",
"memorystore": "1.6.7",
"mime": "3.0.0",
"moment-timezone": "0.5.34",
"mqtt": "4.3.5",
"multer": "1.4.4",
"mustache": "4.2.0",
"node-red-admin": "^2.2.0",
"node-red-admin": "^2.2.3",
"nopt": "5.0.0",
"oauth2orize": "1.11.0",
"oauth2orize": "1.11.1",
"on-headers": "1.0.2",
"passport": "0.4.1",
"passport": "0.5.2",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"raw-body": "2.4.1",
"raw-body": "2.4.3",
"semver": "7.3.5",
"tar": "6.1.11",
"tough-cookie": "4.0.0",
"uglify-js": "3.14.1",
"uglify-js": "3.15.1",
"uuid": "8.3.2",
"ws": "7.5.1",
"ws": "7.5.6",
"xml2js": "0.4.23"
},
"optionalDependencies": {
"bcrypt": "5.0.1"
},
"devDependencies": {
"dompurify": "2.3.1",
"grunt": "1.4.1",
"dompurify": "2.3.6",
"grunt": "1.5.2",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.4.3",
"grunt-concurrent": "3.0.0",
@@ -93,7 +93,7 @@
"grunt-contrib-compress": "2.0.0",
"grunt-contrib-concat": "~1.0.1",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-jshint": "3.0.0",
"grunt-contrib-jshint": "3.1.1",
"grunt-contrib-uglify": "5.0.1",
"grunt-contrib-watch": "~1.1.0",
"grunt-jsdoc": "2.4.1",
@@ -104,20 +104,20 @@
"grunt-sass": "~3.1.0",
"grunt-simple-mocha": "~0.4.1",
"grunt-simple-nyc": "^3.0.1",
"i18next-http-backend": "1.2.6",
"i18next-http-backend": "1.3.2",
"jquery-i18next": "1.2.1",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "2.1.3",
"marked": "4.0.12",
"minami": "1.2.3",
"mocha": "9.1.1",
"mocha": "9.2.0",
"node-red-node-test-helper": "^0.2.7",
"nodemon": "2.0.12",
"nodemon": "2.0.15",
"proxy": "^1.0.2",
"sass": "1.39.0",
"sass": "1.49.7",
"should": "13.2.3",
"sinon": "11.1.2",
"stoppable": "^1.1.0",
"supertest": "6.1.6"
"supertest": "6.2.2"
},
"engines": {
"node": ">=12"

View File

@@ -1,4 +1,4 @@
Copyright JS Foundation and other contributors, http://js.foundation
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
Apache License
Version 2.0, January 2004

View File

@@ -141,7 +141,7 @@ function completeVerify(profile,done) {
Users.authenticate(profile).then(function(user) {
if (user) {
Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) {
log.audit({event: "auth.login",username:user.username,scope:user.permissions});
log.audit({event: "auth.login",user,username:user.username,scope:user.permissions});
user.tokens = tokens;
done(null,user);
});
@@ -199,8 +199,12 @@ function genericStrategy(adminApp,strategy) {
passport.use(new strategy.strategy(options, verify));
adminApp.get('/auth/strategy',
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
completeGenerateStrategyAuth
passport.authenticate(strategy.name, {session:false,
failureMessage: true,
failureRedirect: settings.httpAdminRoot
}),
completeGenerateStrategyAuth,
handleStrategyError
);
var callbackMethodFunc = adminApp.get;
@@ -208,8 +212,13 @@ function genericStrategy(adminApp,strategy) {
callbackMethodFunc = adminApp.post;
}
callbackMethodFunc.call(adminApp,'/auth/strategy/callback',
passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
completeGenerateStrategyAuth
passport.authenticate(strategy.name, {
session:false,
failureMessage: true,
failureRedirect: settings.httpAdminRoot
}),
completeGenerateStrategyAuth,
handleStrategyError
);
}
@@ -219,6 +228,13 @@ function completeGenerateStrategyAuth(req,res) {
// Successful authentication, redirect home.
res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken);
}
function handleStrategyError(err, req, res, next) {
if (res.headersSent) {
return next(err)
}
log.audit({event: "auth.login.fail.oauth",error:err.toString()});
res.redirect(settings.httpAdminRoot + '?session_message='+err.toString());
}
module.exports = {
init: init,

View File

@@ -93,7 +93,7 @@ var passwordTokenExchange = function(client, username, password, scope, done) {
return logEntry.user !== username;
});
Tokens.create(username,client.id,scope).then(function(tokens) {
log.audit({event: "auth.login",username:username,client:client.id,scope:scope});
log.audit({event: "auth.login",user,username:username,client:client.id,scope:scope});
done(null,tokens.accessToken,null,{expires_in:tokens.expires_in});
});
} else {
@@ -146,7 +146,7 @@ function authenticateUserToken(req) {
} else {
reject();
}
});
}).catch(reject);
} else {
reject();
}
@@ -163,6 +163,9 @@ TokensStrategy.prototype.authenticate = function(req) {
authenticateUserToken(req).then(user => {
this.success(user,{scope:user.permissions});
}).catch(err => {
if (err) {
log.trace("token authentication failure: "+err.stack?err.stack:err)
}
this.fail(401);
});
}

View File

@@ -48,9 +48,10 @@ module.exports = {
var prevLang = i18n.i.language;
// Trigger a load from disk of the language if it is not the default
i18n.i.changeLanguage(lang, function(){
var catalog = loadResource(lang, namespace);
res.json(catalog||{});
i18n.i.changeLanguage(prevLang, function() {
var catalog = loadResource(lang, namespace);
res.json(catalog||{});
});
});
i18n.i.changeLanguage(prevLang);
}
}

View File

@@ -122,6 +122,7 @@ module.exports = {
}
if (req.body.active) {
opts.clearContext = req.body.hasOwnProperty('clearContext')?req.body.clearContext:true
runtimeAPI.projects.setActiveProject(opts).then(function() {
listProjects(req,res);
}).catch(function(err) {

View File

@@ -18,14 +18,6 @@ var apiUtils = require("../util");
var express = require("express");
var runtimeAPI;
function getUsername(userObj) {
var username = '__default';
if ( userObj && userObj.name ) {
username = userObj.name;
}
return username;
}
module.exports = {
init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI;

View File

@@ -24,15 +24,19 @@ var defaultContext = {
page: {
title: "Node-RED",
favicon: "favicon.ico",
tabicon: "red/images/node-red-icon-black.svg"
tabicon: {
icon: "red/images/node-red-icon-black.svg",
colour: "#8f0000"
},
version: require(path.join(__dirname,"../../package.json")).version
},
header: {
title: "Node-RED",
image: "red/images/node-red.svg"
},
asset: {
red: (process.env.NODE_ENV == "development")? "red/red.js":"red/red.min.js",
main: (process.env.NODE_ENV == "development")? "red/main.js":"red/main.min.js",
red: "red/red.min.js",
main: "red/main.min.js",
vendorMonaco: ""
}
};
@@ -74,7 +78,7 @@ function serveFilesFromTheme(themeValue, themeApp, directory, baseDirectory) {
let fullPath = array[i];
if (baseDirectory) {
fullPath = path.resolve(baseDirectory,array[i]);
if (fullPath.indexOf(baseDirectory) !== 0) {
if (fullPath.indexOf(path.resolve(baseDirectory)) !== 0) {
continue;
}
}
@@ -91,6 +95,10 @@ module.exports = {
init: function(settings, _runtimeAPI) {
runtimeAPI = _runtimeAPI;
themeContext = clone(defaultContext);
if (process.env.NODE_ENV == "development") {
themeContext.asset.red = "red/red.js";
themeContext.asset.main = "red/main.js";
}
themeSettings = null;
theme = settings.editorTheme || {};
themeContext.asset.vendorMonaco = ((theme.codeEditor || {}).lib === "monaco") ? "vendor/monaco/monaco-bootstrap.js" : "";
@@ -123,9 +131,13 @@ module.exports = {
}
if (theme.page.tabicon) {
url = serveFile(themeApp,"/tabicon/",theme.page.tabicon)
let icon = theme.page.tabicon.icon || theme.page.tabicon
url = serveFile(themeApp,"/tabicon/", icon)
if (url) {
themeContext.page.tabicon = url;
themeContext.page.tabicon.icon = url;
}
if (theme.page.tabicon.colour) {
themeContext.page.tabicon.colour = theme.page.tabicon.colour
}
}
@@ -216,6 +228,11 @@ module.exports = {
if (theme.theme) {
themeSettings.theme = theme.theme;
}
if (theme.hasOwnProperty("tours")) {
themeSettings.tours = theme.tours;
}
return themeApp;
},
context: async function() {
@@ -246,6 +263,9 @@ module.exports = {
theme.page = theme.page || {_:{}}
theme.page._.scripts = scriptFiles.concat(theme.page._.scripts || [])
}
if(theme.codeEditor) {
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
}
}
activeThemeInitialised = true;
}

View File

@@ -91,7 +91,16 @@ module.exports = {
},
editor: async function(req,res) {
res.send(Mustache.render(editorTemplate,await theme.context()));
let sessionMessages;
if (req.session && req.session.messages) {
sessionMessages = JSON.stringify(req.session.messages);
delete req.session.messages
}
res.send(Mustache.render(editorTemplate,{
sessionMessages,
...await theme.context()
}));
},
editorResources: express.static(path.join(editorClientDir,'public'))
};

View File

@@ -90,6 +90,8 @@ function init(settings,_server,storage,runtimeAPI) {
auth.getToken,
auth.errorHandler
);
} else if (settings.adminAuth.tokens) {
adminApp.use(passport.initialize());
}
adminApp.post("/auth/revoke",auth.needsPermission(""),auth.revoke,apiUtil.errorHandler);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "2.0.6",
"version": "2.2.3",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,23 +16,23 @@
}
],
"dependencies": {
"@node-red/util": "2.0.6",
"@node-red/editor-client": "2.0.6",
"@node-red/util": "2.2.3",
"@node-red/editor-client": "2.2.3",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"body-parser": "1.19.1",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.17.2",
"express": "4.17.1",
"memorystore": "1.6.6",
"mime": "2.5.2",
"multer": "1.4.3",
"express": "4.17.2",
"memorystore": "1.6.7",
"mime": "3.0.0",
"multer": "1.4.4",
"mustache": "4.2.0",
"oauth2orize": "1.11.0",
"oauth2orize": "1.11.1",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"passport": "0.4.1",
"ws": "7.5.1"
"passport": "0.5.2",
"ws": "7.5.6"
},
"optionalDependencies": {
"bcrypt": "5.0.1"

View File

@@ -1,4 +1,4 @@
Copyright JS Foundation and other contributors, http://js.foundation
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
Apache License
Version 2.0, January 2004

View File

@@ -53,8 +53,17 @@
"confirmDelete": "Confirm delete",
"delete": "Are you sure you want to delete '__label__'?",
"dropFlowHere": "Drop the flow here",
"addFlow": "Add Flow",
"listFlows": "List Flows",
"addFlow": "Add flow",
"addFlowToRight": "Add flow to the right",
"hideFlow": "Hide flow",
"hideOtherFlows": "Hide other flows",
"showAllFlows": "Show all flows",
"hideAllFlows": "Hide all flows",
"hiddenFlows": "List __count__ hidden flow",
"hiddenFlows_plural": "List __count__ hidden flows",
"showLastHiddenFlow": "Show last hidden flow",
"listFlows": "List flows",
"listSubflows": "List subflows",
"status": "Status",
"enabled": "Enabled",
"disabled":"Disabled",
@@ -66,6 +75,8 @@
"view": {
"view": "View",
"grid": "Grid",
"storeZoom": "Restore zoom level on load",
"storePosition": "Restore scroll position on load",
"showGrid": "Show grid",
"snapGrid": "Snap to grid",
"gridSize": "Grid size",
@@ -83,6 +94,7 @@
"palette": {
"show": "Show palette"
},
"edit": "Edit",
"settings": "Settings",
"userSettings": "User Settings",
"nodes": "Nodes",
@@ -105,6 +117,7 @@
"editPalette":"Manage palette",
"other": "Other",
"showTips": "Show tips",
"showWelcomeTours": "Show guided tours for new versions",
"help": "Node-RED website",
"projects": "Projects",
"projects-new": "New",
@@ -116,7 +129,20 @@
"groupSelection": "Group selection",
"ungroupSelection": "Ungroup selection",
"groupMergeSelection": "Merge selection",
"groupRemoveSelection": "Remove from group"
"groupRemoveSelection": "Remove from group",
"arrange":"Arrange",
"alignLeft":"Align to left",
"alignCenter":"Align to center",
"alignRight":"Align to right",
"alignTop":"Align to top",
"alignMiddle":"Align to middle",
"alignBottom":"Align to bottom",
"distributeHorizontally":"Distribute horizontally",
"distributeVertically":"Distribute vertically",
"moveToBack":"Move to back",
"moveToFront":"Move to front",
"moveBackwards":"Move backwards",
"moveForwards":"Move forwards"
}
},
"actions": {
@@ -450,8 +476,9 @@
"unassigned": "Unassigned",
"global": "global",
"workspace": "workspace",
"selectAll": "Select all nodes",
"selectAllConnected": "Select all connected nodes",
"selectAll": "Select all",
"selectNone": "Select none",
"selectAllConnected": "Select connected",
"addRemoveNode": "Add/remove node from selection",
"editSelected": "Edit selected node",
"deleteSelected": "Delete selected nodes or link",
@@ -464,7 +491,10 @@
"copyNode": "Copy selected nodes",
"cutNode": "Cut selected nodes",
"pasteNode": "Paste nodes",
"undoChange": "Undo the last change performed",
"copyGroupStyle": "Copy group style",
"pasteGroupStyle": "Paste group style",
"undoChange": "Undo",
"redoChange": "Redo",
"searchBox": "Open search box",
"managePalette": "Manage palette",
"actionList":"Action list"
@@ -519,7 +549,8 @@
"nodeEnabled_plural": "Nodes enabled:",
"nodeDisabled": "Node disabled:",
"nodeDisabled_plural": "Nodes disabled:",
"nodeUpgraded": "Node module __module__ upgraded to version __version__"
"nodeUpgraded": "Node module __module__ upgraded to version __version__",
"unknownNodeRegistered": "Error loading node: <ul><li>__type__<br>__error__</li></ul>"
},
"editor": {
"title": "Manage palette",
@@ -642,7 +673,8 @@
"unusedConfigNodes": "Unused configuration nodes",
"invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows"
"unusedSubflows": "Unused subflows",
"hiddenFlows": "Hidden flows"
}
},
"help": {
@@ -864,6 +896,8 @@
"addTitle": "add an item"
},
"search": {
"history": "Search history",
"clear": "clear all",
"empty": "No matches found",
"addNode": "add a node..."
},
@@ -1061,7 +1095,8 @@
"not-git": "Not a git repository",
"no-resource": "Repository not found",
"cant-get-ssh-key-path": "Error! Can't get selected SSH key path.",
"unexpected_error": "unexpected_error"
"unexpected_error": "unexpected_error",
"clearContext": "Clear context when switching projects"
},
"delete": {
"confirm": "Are you sure you want to delete this project?"
@@ -1108,6 +1143,11 @@
"preview": "UI Preview",
"defaultValue": "Default value"
},
"tourGuide": {
"takeATour": "Take a tour",
"start": "Start",
"next": "Next"
},
"languages" : {
"de": "German",
"en-US": "English",

View File

@@ -54,7 +54,16 @@
"delete": "本当に '__label__' を削除しますか?",
"dropFlowHere": "ここにフローをドロップしてください",
"addFlow": "フローの追加",
"addFlowToRight": "右側にフローを追加",
"hideFlow": "フローを非表示",
"hideOtherFlows": "他のフローを非表示",
"showAllFlows": "全てのフローを表示",
"hideAllFlows": "全てのフローを非表示",
"hiddenFlows": "__count__ 個の非表示のフロー一覧",
"hiddenFlows_plural": "__count__ 個の非表示のフロー一覧",
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
"listFlows": "フロー一覧",
"listSubflows": "サブフロー一覧",
"status": "状態",
"enabled": "有効",
"disabled": "無効",
@@ -66,6 +75,8 @@
"view": {
"view": "表示",
"grid": "グリッド",
"storeZoom": "読み込み時に拡大/縮小のレベルを復元",
"storePosition": "読み込み時にスクロール位置を復元",
"showGrid": "グリッドを表示",
"snapGrid": "ノードの配置を補助",
"gridSize": "グリッドの大きさ",
@@ -83,6 +94,7 @@
"palette": {
"show": "パレットを表示"
},
"edit": "編集",
"settings": "設定",
"userSettings": "ユーザ設定",
"nodes": "ノード",
@@ -105,6 +117,7 @@
"editPalette": "パレットの管理",
"other": "その他",
"showTips": "ヒントを表示",
"showWelcomeTours": "新バージョンのガイドツアーを表示",
"help": "Node-REDウェブサイト",
"projects": "プロジェクト",
"projects-new": "新規",
@@ -116,7 +129,20 @@
"groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除"
"groupRemoveSelection": "グループから削除",
"arrange": "配置",
"alignLeft": "左揃え",
"alignCenter": "左右中央揃え",
"alignRight": "右揃え",
"alignTop": "上揃え",
"alignMiddle": "上下中央揃え",
"alignBottom": "下揃え",
"distributeHorizontally": "左右に整列",
"distributeVertically": "上下に整列",
"moveToBack": "最背面へ移動",
"moveToFront": "最前面へ移動",
"moveBackwards": "背面へ移動",
"moveForwards": "前面へ移動"
}
},
"actions": {
@@ -451,7 +477,8 @@
"global": "グローバル",
"workspace": "ワークスペース",
"selectAll": "全てのノードを選択",
"selectAllConnected": "接続された全てのノードを選択",
"selectNone": "選択を外す",
"selectAllConnected": "接続されたノードを選択",
"addRemoveNode": "ノードの選択、選択解除",
"editSelected": "選択したノードを編集",
"deleteSelected": "選択したノードや接続を削除",
@@ -461,10 +488,13 @@
"moveNode": "選択したノードを移動(移動量大)",
"toggleSidebar": "サイドバーの表示/非表示",
"togglePalette": "パレットの表示/非表示",
"copyNode": "選択したノードをコピー",
"cutNode": "選択したノードを切り取り",
"copyNode": "ノードをコピー",
"cutNode": "ノードを切り取り",
"pasteNode": "ノードを貼り付け",
"copyGroupStyle": "グループ様式をコピー",
"pasteGroupStyle": "グループ様式を貼り付け",
"undoChange": "変更操作を戻す",
"redoChange": "変更操作をやり直し",
"searchBox": "ノードを検索",
"managePalette": "パレットの管理",
"actionList": "動作一覧"
@@ -519,7 +549,8 @@
"nodeEnabled_plural": "ノードを有効化しました:",
"nodeDisabled": "ノードを無効化しました:",
"nodeDisabled_plural": "ノードを無効化しました:",
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました",
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
},
"editor": {
"title": "パレットの管理",
@@ -642,7 +673,8 @@
"unusedConfigNodes": "未使用の設定ノード",
"invalidNodes": "不正なノード",
"uknownNodes": "未知のノード",
"unusedSubflows": "未使用のサブフロー"
"unusedSubflows": "未使用のサブフロー",
"hiddenFlows": "非表示のフロー"
}
},
"help": {
@@ -813,7 +845,7 @@
"pushFailed": "リモートに新しいコミットがあるため、プッシュに失敗しました。プルしてマージしてから、再度プッシュしてください。",
"push": "プッシュ",
"pull": "プル",
"unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>",
"unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>",
"showUnstagedChanges": "ステージングされていない変更を表示",
"connectionFailed": "リモートリポジトリに接続できません: ",
"pullUnrelatedHistory": "<p>リモートに関連のないコミット履歴があります。</p><p>本当に変更をプルしてローカルリポジトリに反映しますか?</p>",
@@ -864,6 +896,8 @@
"addTitle": "要素を追加"
},
"search": {
"history": "検索履歴",
"clear": "全て削除",
"empty": "一致したものが見つかりませんでした",
"addNode": "ノードを追加..."
},
@@ -1061,7 +1095,8 @@
"not-git": "Gitリポジトリではありません",
"no-resource": "リポジトリが見つかりません",
"cant-get-ssh-key-path": "エラー! 選択したSSHキーのパスを取得できません。",
"unexpected_error": "予期しないエラー"
"unexpected_error": "予期しないエラー",
"clearContext": "プロジェクトを切り替る際にコンテキストを初期化"
},
"delete": {
"confirm": "プロジェクトを削除しても良いですか?"
@@ -1108,6 +1143,11 @@
"preview": "UIプレビュー",
"defaultValue": "デフォルト値"
},
"tourGuide": {
"takeATour": "ツアーを開始",
"start": "開始",
"next": "次へ"
},
"languages": {
"de": "ドイツ語",
"en-US": "英語",
@@ -1116,5 +1156,141 @@
"ru": "ロシア語",
"zh-CN": "中国語(簡体)",
"zh-TW": "中国語(繁体)"
},
"action-list": {
"toggle-show-tips": "ヒント表示切替",
"show-about": "Node-REDの説明を表示",
"show-welcome-tour": "ウェルカムツアー表示",
"show-next-tab": "次のタブを表示",
"show-previous-tab": "前のタブを表示",
"add-flow": "フローを追加",
"add-flow-to-right": "フローを右に追加",
"edit-flow": "フローを編集",
"remove-flow": "フローを削除",
"enable-flow": "フローを有効化",
"disable-flow": "フローを無効化",
"hide-flow": "フローを隠す",
"hide-other-flows": "他のフローを非表示",
"hide-all-flows": "全てのフローを非表示",
"show-all-flows": "全てのフローを表示",
"show-last-hidden-flow": "最後に非表示にしたフローを表示",
"list-hidden-flows": "非表示フローを表示",
"list-flows": "フロー一覧",
"list-subflows": "サブフロー一覧",
"go-to-previous-location": "前の位置に移動",
"go-to-next-location": "次の位置に移動",
"copy-selection-to-internal-clipboard": "選択をクリップボードにコピー",
"cut-selection-to-internal-clipboard": "選択をクリップボードに切り取り",
"paste-from-internal-clipboard": "クリップボードから貼り付け",
"detach-selected-nodes": "選択ノードを接続から外す",
"delete-selection": "選択を削除",
"delete-selection-and-reconnect": "選択を削除し再接続",
"edit-selected-node": "選択したノードを編集",
"go-to-selection": "選択に移動",
"undo": "変更操作を戻す",
"redo": "変更操作をやり直し",
"select-all-nodes": "全てのノードを選択",
"select-none": "ノードを選択",
"enable-selected-nodes": "選択ノードを有効化",
"disable-selected-nodes": "選択ノードを無効化",
"toggle-show-grid": "グリッド表示切替",
"toggle-snap-grid": "ノードの配置補助切替",
"toggle-status": "ステータス表示切替",
"show-selected-node-labels": "選択したノードのラベルを表示",
"hide-selected-node-labels": "選択したノードのラベルを非表示",
"scroll-view-up": "上スクロール",
"scroll-view-right": "右スクロール",
"scroll-view-down": "下スクロール",
"scroll-view-left": "左スクロール",
"step-view-up": "一単位上スクロール",
"step-view-right": "一単位右スクロール",
"step-view-down": "一単位下スクロール",
"step-view-left": "一単位左スクロール",
"move-selection-up": "選択を上移動",
"move-selection-right": "選択を右移動",
"move-selection-down": "選択を下移動",
"move-selection-left": "選択を左移動",
"move-selection-forwards": "選択を前面に移動",
"move-selection-backwards": "選択を背面に移動",
"move-selection-to-front": "選択を最前面に移動",
"move-selection-to-back": "選択を最背面に移動",
"step-selection-up": "選択を一単位上移動",
"step-selection-right": "選択を一単位右移動",
"step-selection-down": "選択を一単位下移動",
"step-selection-left": "選択を一単位左移動",
"select-connected-nodes": "接続されたノードを選択",
"select-downstream-nodes": "後方に接続されたノードを選択",
"select-upstream-nodes": "前方に接続されたノードを選択",
"go-to-next-node": "次のノードに移動",
"go-to-previous-node": "前のノードに移動",
"go-to-next-sibling": "次の兄弟ノードに移動",
"go-to-previous-sibling": "前の兄弟ノードに移動",
"go-to-nearest-node-on-left": "最も近い左側ノードに移動",
"go-to-nearest-node-on-right": "最も近い右側ノードに移動",
"go-to-nearest-node-above": "最も近い上側ノードに移動",
"go-to-nearest-node-below": "最も近い下側ノードに移動",
"align-selection-to-grid": "選択を整列",
"align-selection-to-left": "選択を左揃え",
"align-selection-to-right": "選択を右揃え",
"align-selection-to-top": "選択を上揃え",
"align-selection-to-bottom": "選択を下揃え",
"align-selection-to-middle": "選択を上下中央揃え",
"align-selection-to-center": "選択を左右中央揃え",
"distribute-selection-horizontally": "選択を左右に整列",
"distribute-selection-vertically": "選択を上下に整列",
"wire-series-of-nodes": "ノードを一続きに接続",
"wire-node-to-multiple": "ノードを複数に接続",
"show-user-settings": "ユーザ設定を表示",
"show-help": "ヘルプを表示",
"toggle-palette": "パレットの表示切替",
"show-event-log": "イベントログを表示",
"manage-palette": "パレットの管理",
"toggle-sidebar": "サイドバーの表示切替",
"show-info-tab": "ノード情報タブの表示",
"show-help-tab": "ノードヘルプタブの表示",
"show-config-tab": "設定ノードタブの表示",
"select-all-config-nodes": "全ての設定ノードを選択",
"delete-config-selection": "選択した設定ノードを削除",
"show-context-tab": "コンテキストデータタブを表示",
"create-subflow": "サブフローを作成",
"convert-to-subflow": "選択をサブフローに変換",
"group-selection": "選択をグループ化",
"ungroup-selection": "選択をグループ解除",
"merge-selection-to-group": "選択をグループにマージ",
"remove-selection-from-group": "選択をグループから削除",
"copy-group-style": "グループのスタイルをコピー",
"paste-group-style": "グループのスタイルを貼り付け",
"show-export-dialog": "書き出しダイアログを表示",
"show-import-dialog": "読み込みダイアログを表示",
"show-library-export-dialog": "ライブラリ書き出しダイアログを表示",
"show-library-import-dialog": "ライブラリ読み込みダイアログを表示",
"show-examples-import-dialog": "サンプル読み込みダイアログを表示",
"search": "検索",
"show-action-list": "アクション一覧を表示",
"confirm-edit-tray": "編集を完了",
"cancel-edit-tray": "編集をキャンセル",
"show-remote-diff": "リモートとの変更差分を表示",
"deploy-flows": "フローをデプロイ",
"restart-flows": "フローを再起動",
"set-deploy-type-to-full": "デプロイを「全て」に設定",
"set-deploy-type-to-modified-flows": "デプロイを「変更したフロー」に設定",
"set-deploy-type-to-modified-nodes": "デプロイを「変更したノード」に設定",
"show-debug-tab": "デバッグタブを表示",
"clear-debug-messages": "デバッグメッセージをクリア",
"clear-filtered-debug-messages": "フィルタしたデバッグメッセージをクリア",
"activate-selected-debug-nodes": "選択したデバッグノードを有効化",
"activate-all-debug-nodes": "全てのデバッグノードを有効化",
"activate-all-flow-debug-nodes": "フロー内の全デバッグノードを有効化",
"deactivate-selected-debug-nodes": "選択したデバッグノードを無効化",
"deactivate-all-debug-nodes": "全てのデバッグノードを無効化",
"deactivate-all-flow-debug-nodes": "フロー内の全デバッグノードを無効化",
"zoom-in": "ズームイン",
"zoom-out": "ズームアウト",
"zoom-reset": "ズームリセット",
"toggle-navigator": "ナビゲータ表示切替",
"new-project": "新しいプロジェクト",
"open-project": "プロジェクトを開く",
"show-project-settings": "プロジェクト設定を表示",
"show-version-control-tab": "バージョンコントロールタブを表示"
}
}

View File

@@ -17,7 +17,7 @@
"tip14": "[shift] を押しながらノードを [click] すると、接続された全てのノードを選択できます。",
"tip15": "[ctrl] を押しながらノードを [click] すると、選択/非選択を切り替えできます。",
"tip16": "{{core:show-previous-tab}} や {{core:show-next-tab}} で、タブの切り替えができます。",
"tip17": "ノードのプロティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
"tip17": "ノードのプロティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
"tip18": "ノードを選択し、 {{core:edit-selected-node}} を押すとプロパティ設定画面が表示されます。"
}
}

View File

@@ -225,7 +225,7 @@
"compact": "紧凑",
"formatted": "已格式化",
"copy": "导出到剪贴板",
"export": "到处到库",
"export": "导出到库",
"exportAs": "导出为",
"overwrite": "替换",
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "2.0.6",
"version": "2.2.3",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -14,5 +14,5 @@
"name": "Dave Conway-Jones"
}
],
"main": "./lib/index.js"
"main": "./index.js"
}

View File

@@ -98,7 +98,7 @@ oop.inherits(NRJavaScriptWorker, Mirror);
if (options) {
for (var opt in options) {
if (options.hasOwnProperty(opt)) {
this.options[opt] = options.opt;
this.options[opt] = options[opt];
}
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="512" width="512"><g transform="translate(0 -540.36)"><path fill="#8f0000" color="#000" d="M0 540.36h512v392H0z"/><rect ry="0" height="108.23" width="500.23" stroke="#fff" y="938.25" x="5.89" stroke-width="11.77" fill="#fff"/><path style="text-decoration-color:#000;isolation:auto;mix-blend-mode:normal;solid-color:#000;block-progression:tb;text-decoration-line:none;white-space:normal;text-indent:0;text-transform:none;text-decoration-style:solid" d="M122.88 305.82a4.46 4.46 0 0 0-4.38 4.42v.78c-2.23.1-4.04.54-5.33 1.43a10.5 10.5 0 0 0-3.18 3.87c-.71 1.3-1.3 2.41-2.15 3.2-.72.66-1.8 1.12-3.45 1.32a4.37 4.37 0 0 0-4.3-3.95H82.91a4.43 4.43 0 0 0-4.42 4.35v4.24a4.43 4.43 0 0 0 4.42 4.36h17.16a4.4 4.4 0 0 0 4.4-4.36v-1.6c9.72.14 12.46 2.6 15.59 5.33 3 2.62 6.66 5.38 15.43 5.5v.73a4.49 4.49 0 0 0 4.46 4.38h17.09c2.38 0 4.45-2 4.45-4.38v-4.24a4.49 4.49 0 0 0-4.45-4.38h-17.1c-2.38 0-4.45 2-4.45 4.38v.58c-8.1-.06-10.48-2.15-13.5-4.79-2.5-2.19-5.64-4.58-11.94-5.58 1.17-1.18 1.88-2.52 2.51-3.66.68-1.23 1.29-2.2 2.27-2.88.76-.52 1.98-.84 3.66-.94v.55c0 2.39 2 4.34 4.38 4.34h17.24a4.39 4.39 0 0 0 4.38-4.34v-4.24c0-2.38-2-4.42-4.38-4.42zm0 3h17.24c.8 0 1.38.62 1.38 1.42v4.24c0 .81-.57 1.34-1.38 1.34h-17.24c-.8 0-1.38-.53-1.38-1.34v-4.24c0-.8.57-1.42 1.38-1.42zm-39.96 11.02h17.16c.81 0 1.42.6 1.42 1.4v4.24c0 .81-.61 1.41-1.42 1.41H82.92c-.8 0-1.42-.6-1.42-1.4v-4.25c0-.8.61-1.4 1.42-1.4zm57.04 9.98h17.09c.8 0 1.45.57 1.45 1.38v4.17c0 .8-.65 1.45-1.45 1.45h-17.1c-.8 0-1.45-.65-1.45-1.45v-4.17c0-.8.65-1.38 1.46-1.38z" fill="#fff" color="#000" transform="matrix(4 0 0 4 -162 -450.91)"/><g fill="#8f0000"><path d="M91 954.34v8.45l-8 1.45v60.07H69.03l-28.53-47.1-.5.05v37.2l8 1.44v8.41H19v-8.4l7.45-1.45v-50.22L19 962.79v-8.46h21.48l28.37 47.1.15-.04v-37.15l-7-1.45v-8.45h29zM95 997.83q0-11.63 6.49-19.03 6.53-7.45 18.02-7.45 11.53 0 18.02 7.4 6.54 7.4 6.54 19.08v1q0 11.74-6.54 19.14-6.49 7.35-17.93 7.35-11.58 0-18.11-7.35-6.5-7.4-6.5-19.13v-1.01zm14.03 1q0 7.12 2.5 11.45 2.5 4.28 8.08 4.28 5.43 0 7.93-4.33 2.54-4.33 2.54-11.4v-1q0-6.92-2.54-11.3-2.55-4.37-8.03-4.37t-7.98 4.37-2.5 11.3v1zM184.48 1017.96a17.15 17.15 0 0 1-5.82 5.48 15.17 15.17 0 0 1-7.59 1.88c-6.4 0-11.4-2.35-14.95-7.03-3.52-4.67-5.13-10.86-5.13-18.55v-1c0-8.21 1.62-14.83 5.18-19.86 3.56-5.03 8.56-7.54 15-7.54 2.6 0 4.93.57 7.01 1.73a17.94 17.94 0 0 1 5.81 4.8v-18.64l-8-1.45v-8.46h22v65.13l6 1.44v8.43h-18.45l-1.06-6.36zm-19.49-18.22c0 4.55.63 8.14 2.14 10.77 1.54 2.6 4.04 3.9 7.5 3.9 2.05 0 3.83-.43 5.33-1.26 1.5-.83 3.07-2.03 4.03-3.6v-22.06a11.27 11.27 0 0 0-4.03-3.85 9.62 9.62 0 0 0-5.24-1.4c-3.43 0-5.92 1.53-7.5 4.57s-2.23 7.02-2.23 11.92v1.01zM233.7 1025.28c-7.5 0-13.5-2.4-17.98-7.21-4.48-4.81-6.73-10.91-6.73-18.32v-1.92c0-7.72 2.12-14.08 6.35-19.08 4.26-5 9.96-7.46 17.1-7.43 7.03 0 12.47 2.1 16.35 6.33a23.46 23.46 0 0 1 6.2 17.15v7.52h-31.43l-.1.41c.26 3.43 1.4 6.25 3.41 8.46 2.05 2.21 4.83 3.32 8.32 3.32 3.1 0 5.69-.3 7.74-.91 2.05-.64 4.29-1.64 6.73-2.98l3.8 8.65a27.59 27.59 0 0 1-8.37 4.28 35.28 35.28 0 0 1-11.4 1.73zm-1.25-43.16c-2.6 0-4.65.99-6.15 2.98s-2.44 4.6-2.8 7.83l.15.4H241v-1.41c0-2.98-.84-5.35-2.25-7.11-1.37-1.8-3.47-2.7-6.3-2.7zM291.99 1000.32h-27v-11h27zM331.88 954.34c7.95 0 14.18 1.82 18.7 5.47 4.52 3.63 6.4 8.64 6.4 15.05 0 3.52-.57 6.58-2.46 9.18-1.89 2.6-4.66 4.7-8.31 6.3 4.13 1.21 7.1 3.25 8.89 6.1a19.02 19.02 0 0 1 2.89 10.52v3.56c0 1.54.15 2.74.76 3.6.6.84 1.62 1.34 3.03 1.5l1.2.24v8.46h-6.73c-4.58 0-7.8-1.24-9.66-3.7s-2.6-5.66-2.6-9.57v-3.99c0-3.4-1.1-6.05-2.93-7.98-1.8-1.95-4.34-2.98-7.64-3.07H322v18.45l7 1.44v8.42h-29v-8.42l8-1.44v-50.22l-8-1.44v-8.46h31.89zm-9.95 30.85h9.71c3.91 0 6.84-.83 8.8-2.5s2.93-4.07 2.93-7.2c0-3.15-.98-5.65-2.93-7.5-1.92-1.9-4.78-2.84-8.56-2.84h-9.9v20.04zM412.99 993.32h-23v20h22.21l.63-8h10.2v18.99H368v-8.42l8-1.44v-50.22l-8-1.44v-8.47h54.95v19h-10.3l-.63-8H390v17h23v11zM462.48 954.36c8.55 0 15.6 2.71 21.14 8.19 5.55 5.45 8.36 12.42 8.36 20.98v11.58c0 8.59-2.81 15.63-8.36 21.08-5.54 5.41-12.59 8.12-21.14 8.12h-31.5v-8.41l7-1.52v-50.22l-7-1.37v-8.43l7.46-.08 24.04.08zm-10.5 10.76v48.4l9.77.02c5.03.02 8.98-1.7 11.83-5.1 2.85-3.39 4.4-7.8 4.4-13.28v-11.68c0-5.42-1.55-9.84-4.4-13.24-2.85-3.4-6.8-5.1-11.83-5.1l-9.77-.02z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -558,11 +558,22 @@ RED.history = (function() {
} else if (ev.t == "reorder") {
inverseEv = {
t: 'reorder',
order: RED.nodes.getWorkspaceOrder(),
dirty: RED.nodes.dirty()
};
if (ev.order) {
RED.workspaces.order(ev.order);
if (ev.workspaces) {
inverseEv.workspaces = {
from: ev.workspaces.to,
to: ev.workspaces.from
}
RED.workspaces.order(ev.workspaces.from);
}
if (ev.nodes) {
inverseEv.nodes = {
z: ev.nodes.z,
from: ev.nodes.to,
to: ev.nodes.from
}
RED.nodes.setNodeOrder(ev.nodes.z,ev.nodes.from);
}
} else if (ev.t == "createGroup") {
inverseEv = {
@@ -658,6 +669,8 @@ RED.history = (function() {
push: function(ev) {
undoHistory.push(ev);
redoHistory = [];
RED.menu.setDisabled("menu-item-edit-undo", false);
RED.menu.setDisabled("menu-item-edit-redo", true);
},
pop: function() {
var ev = undoHistory.pop();
@@ -665,13 +678,24 @@ RED.history = (function() {
if (rev) {
redoHistory.push(rev);
}
RED.menu.setDisabled("menu-item-edit-undo", undoHistory.length === 0);
RED.menu.setDisabled("menu-item-edit-redo", redoHistory.length === 0);
},
peek: function() {
return undoHistory[undoHistory.length-1];
},
replace: function(ev) {
if (undoHistory.length === 0) {
RED.history.push(ev);
} else {
undoHistory[undoHistory.length-1] = ev;
}
},
clear: function() {
undoHistory = [];
redoHistory = [];
RED.menu.setDisabled("menu-item-edit-undo", true);
RED.menu.setDisabled("menu-item-edit-redo", true);
},
redo: function() {
var ev = redoHistory.pop();
@@ -681,6 +705,8 @@ RED.history = (function() {
undoHistory.push(uev);
}
}
RED.menu.setDisabled("menu-item-edit-undo", undoHistory.length === 0);
RED.menu.setDisabled("menu-item-edit-redo", redoHistory.length === 0);
}
}

View File

@@ -27,6 +27,7 @@ RED.i18n = (function() {
apiRootUrl = options.apiRootUrl||"";
var preferredLanguage = localStorage.getItem("editor-language") || detectLanguage();
var opts = {
compatibilityJSON: 'v3',
backend: {
loadPath: apiRootUrl+'locales/__ns__?lng=__lng__',
},
@@ -37,6 +38,8 @@ RED.i18n = (function() {
defaultNS: "editor",
fallbackLng: ['en-US'],
returnObjects: true,
keySeparator: ".",
nsSeparator: ":",
interpolation: {
unescapeSuffix: 'HTML',
escapeValue: false,

View File

@@ -25,7 +25,9 @@
"ctrl-alt-o": "core:open-project",
"ctrl-g v": "core:show-version-control-tab",
"ctrl-shift-l": "core:show-event-log",
"ctrl-shift-p":"core:show-action-list"
"ctrl-shift-p":"core:show-action-list",
"alt-w": "core:hide-flow",
"alt-shift-w": "core:show-last-hidden-flow"
},
"red-ui-sidebar-node-config": {
"backspace": "core:delete-config-selection",
@@ -36,7 +38,9 @@
},
"red-ui-workspace": {
"backspace": "core:delete-selection",
"ctrl-backspace": "core:delete-selection-and-reconnect",
"delete": "core:delete-selection",
"ctrl-delete": "core:delete-selection-and-reconnect",
"enter": "core:edit-selected-node",
"ctrl-enter": "core:go-to-selection",
"ctrl-c": "core:copy-selection-to-internal-clipboard",
@@ -77,6 +81,15 @@
"right": "core:go-to-nearest-node-on-right",
"left": "core:go-to-nearest-node-on-left",
"up": "core:go-to-nearest-node-above",
"down": "core:go-to-nearest-node-below"
"down": "core:go-to-nearest-node-below",
"alt-a g": "core:align-selection-to-grid",
"alt-a l": "core:align-selection-to-left",
"alt-a r": "core:align-selection-to-right",
"alt-a t": "core:align-selection-to-top",
"alt-a b": "core:align-selection-to-bottom",
"alt-a m": "core:align-selection-to-middle",
"alt-a c": "core:align-selection-to-center",
"alt-a h": "core:distribute-selection-horizontally",
"alt-a v": "core:distribute-selection-vertically"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -201,6 +201,7 @@ var RED = (function() {
RED.projects.refresh(function(activeProject) {
loadFlows(function() {
RED.sidebar.info.refresh()
var showProjectWelcome = false;
if (!activeProject) {
// Projects enabled but no active project
RED.menu.setDisabled('menu-item-projects-open',true);
@@ -208,10 +209,10 @@ var RED = (function() {
if (activeProject === false) {
// User previously decline the migration to projects.
} else { // null/undefined
RED.projects.showStartup();
showProjectWelcome = true;
}
}
completeLoad();
completeLoad(showProjectWelcome);
});
});
} else {
@@ -251,6 +252,22 @@ var RED = (function() {
if (/^#flow\/.+$/.test(currentHash)) {
RED.workspaces.show(currentHash.substring(6),true);
}
if (RED.workspaces.count() > 0) {
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
const workspaces = RED.nodes.getWorkspaceOrder();
if (RED.workspaces.active() === 0) {
for (let index = 0; index < workspaces.length; index++) {
const ws = workspaces[index];
if (!hiddenTabs[ws]) {
RED.workspaces.show(ws);
break;
}
}
}
if (RED.workspaces.active() === 0) {
RED.workspaces.show(workspaces[0]);
}
}
} catch(err) {
console.warn(err);
RED.notify(
@@ -267,7 +284,7 @@ var RED = (function() {
});
}
function completeLoad() {
function completeLoad(showProjectWelcome) {
var persistentNotifications = {};
RED.comms.subscribe("notification/#",function(topic,msg) {
var parts = topic.split("/");
@@ -457,7 +474,7 @@ var RED = (function() {
var parts = topic.split("/");
var node = RED.nodes.node(parts[1]);
if (node) {
if (msg.hasOwnProperty("text") && msg.text !== null && /^[a-zA-Z]/.test(msg.text)) {
if (msg.hasOwnProperty("text") && msg.text !== null && /^[@a-zA-Z]/.test(msg.text)) {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
}
node.status = msg;
@@ -471,22 +488,33 @@ var RED = (function() {
var typeList;
var info;
if (topic == "notification/node/added") {
var addedTypes = [];
msg.forEach(function(m) {
var id = m.id;
RED.nodes.addNodeSet(m);
addedTypes = addedTypes.concat(m.types);
RED.i18n.loadNodeCatalog(id, function() {
$.get('nodes/'+id, function(data) {
appendNodeConfig(data);
RED.settings.refreshSettings(function(err, data) {
var addedTypes = [];
msg.forEach(function(m) {
var id = m.id;
RED.nodes.addNodeSet(m);
addedTypes = addedTypes.concat(m.types);
RED.i18n.loadNodeCatalog(id, function() {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+id,
success: function(data) {
appendNodeConfig(data);
}
});
});
});
});
if (addedTypes.length) {
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
loadIconList();
if (addedTypes.length) {
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
loadIconList();
})
} else if (topic == "notification/node/removed") {
for (i=0;i<msg.length;i++) {
m = msg[i];
@@ -499,18 +527,29 @@ var RED = (function() {
loadIconList();
} else if (topic == "notification/node/enabled") {
if (msg.types) {
info = RED.nodes.getNodeSet(msg.id);
if (info.added) {
RED.nodes.enableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
$.get('nodes/'+msg.id, function(data) {
appendNodeConfig(data);
RED.settings.refreshSettings(function(err, data) {
info = RED.nodes.getNodeSet(msg.id);
if (info.added) {
RED.nodes.enableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
});
}
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
$.ajax({
headers: {
"Accept":"text/html",
"Accept-Language": lang
},
cache: false,
url: 'nodes/'+msg.id,
success: function(data) {
appendNodeConfig(data);
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
}
});
}
});
}
} else if (topic == "notification/node/disabled") {
if (msg.types) {
@@ -530,24 +569,28 @@ var RED = (function() {
$(".red-ui-header-toolbar").show();
RED.sidebar.show(":first");
RED.sidebar.show(":first", true);
setTimeout(function() {
loader.end();
checkFirstRun(function() {
if (showProjectWelcome) {
RED.projects.showStartup();
}
});
},100);
}
function showAbout() {
$.get('red/about', function(data) {
// data will be strictly markdown. Any HTML should be escaped.
data = RED.utils.sanitize(data);
var aboutHeader = '<div style="text-align:center;">'+
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data));
});
function checkFirstRun(done) {
if (RED.settings.theme("tours") === false) {
done();
return;
}
if (!RED.settings.get("editor.view.view-show-welcome-tours", true)) {
done();
return;
}
RED.actions.invoke("core:show-welcome-tour", RED.settings.get("editor.tours.welcome"), done);
}
function buildMainMenu() {
@@ -559,6 +602,22 @@ var RED = (function() {
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
]});
}
menuOptions.push({id:"menu-item-edit-menu", label:RED._("menu.label.edit"), options: [
{id: "menu-item-edit-undo", label:RED._("keyboard.undoChange"), disabled: true, onselect: "core:undo"},
{id: "menu-item-edit-redo", label:RED._("keyboard.redoChange"), disabled: true, onselect: "core:redo"},
null,
{id: "menu-item-edit-cut", label:RED._("keyboard.cutNode"), onselect: "core:cut-selection-to-internal-clipboard"},
{id: "menu-item-edit-copy", label:RED._("keyboard.copyNode"), onselect: "core:copy-selection-to-internal-clipboard"},
{id: "menu-item-edit-paste", label:RED._("keyboard.pasteNode"), disabled: true, onselect: "core:paste-from-internal-clipboard"},
null,
{id: "menu-item-edit-copy-group-style", label:RED._("keyboard.copyGroupStyle"), onselect: "core:copy-group-style"},
{id: "menu-item-edit-paste-group-style", label:RED._("keyboard.pasteGroupStyle"), disabled: true, onselect: "core:paste-group-style"},
null,
{id: "menu-item-edit-select-all", label:RED._("keyboard.selectAll"), onselect: "core:select-all-nodes"},
{id: "menu-item-edit-select-connected", label:RED._("keyboard.selectAllConnected"), onselect: "core:select-connected-nodes"},
{id: "menu-item-edit-select-none", label:RED._("keyboard.selectNone"), onselect: "core:select-none"}
]});
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
{id:"menu-item-palette",label:RED._("menu.label.palette.show"),toggle:true,onselect:"core:toggle-palette", selected: true},
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true},
@@ -566,6 +625,25 @@ var RED = (function() {
{id:"menu-item-action-list",label:RED._("keyboard.actionList"),onselect:"core:show-action-list"},
null
]});
menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [
{id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"},
{id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"},
{id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"},
{id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"},
null,
{id: "menu-item-view-tools-align-left", label:RED._("menu.label.alignLeft"), disabled: true, onselect: "core:align-selection-to-left"},
{id: "menu-item-view-tools-align-center", label:RED._("menu.label.alignCenter"), disabled: true, onselect: "core:align-selection-to-center"},
{id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"},
null,
{id: "menu-item-view-tools-align-top", label:RED._("menu.label.alignTop"), disabled: true, onselect: "core:align-selection-to-top"},
{id: "menu-item-view-tools-align-middle", label:RED._("menu.label.alignMiddle"), disabled: true, onselect: "core:align-selection-to-middle"},
{id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"},
null,
{id: "menu-item-view-tools-distribute-horizontally", label:RED._("menu.label.distributeHorizontally"), disabled: true, onselect: "core:distribute-selection-horizontally"},
{id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"}
]});
menuOptions.push(null);
if (RED.settings.theme("menu.menu-item-import-library", true)) {
menuOptions.push({id: "menu-item-import", label: RED._("menu.label.import"), onselect: "core:show-import-dialog"});
@@ -626,7 +704,6 @@ var RED = (function() {
RED.user.init();
RED.notifications.init();
RED.library.init();
RED.keyboard.init();
RED.palette.init();
RED.eventLog.init();
@@ -655,16 +732,13 @@ var RED = (function() {
RED.deploy.init(RED.settings.theme("deployButton",null));
buildMainMenu();
RED.keyboard.init(buildMainMenu);
RED.nodes.init();
RED.comms.connect();
$("#red-ui-main-container").show();
RED.actions.add("core:show-about", showAbout);
loadPluginList();
}

View File

@@ -19,7 +19,6 @@ RED.settings = (function () {
var loadedSettings = {};
var userSettings = {};
var settingsDirty = false;
var pendingSave;
var hasLocalStorage = function () {
@@ -126,7 +125,7 @@ RED.settings = (function () {
load(done);
}
var load = function(done) {
var refreshSettings = function(done) {
$.ajax({
headers: {
"Accept": "application/json"
@@ -136,6 +135,23 @@ RED.settings = (function () {
url: 'settings',
success: function (data) {
setProperties(data);
done(null, data);
},
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status === 401) {
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
window.location.search = "";
}
RED.user.login(function() { refreshSettings(done); });
} else {
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
}
}
});
}
var load = function(done) {
refreshSettings(function(err, data) {
if (!err) {
if (!RED.settings.user || RED.settings.user.anonymous) {
RED.settings.remove("auth-tokens");
}
@@ -148,18 +164,8 @@ RED.settings = (function () {
console.log("D3",d3.version);
console.groupEnd();
loadUserSettings(done);
},
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status === 401) {
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
window.location.search = "";
}
RED.user.login(function() { load(done); });
} else {
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
}
}
});
})
};
function loadUserSettings(done) {
@@ -220,14 +226,28 @@ RED.settings = (function () {
return defaultValue;
}
}
function getLocal(key) {
return localStorage.getItem(key)
}
function setLocal(key, value) {
localStorage.setItem(key, value);
}
function removeLocal(key) {
localStorage.removeItem(key)
}
return {
init: init,
load: load,
loadUserSettings: loadUserSettings,
refreshSettings: refreshSettings,
set: set,
get: get,
remove: remove,
theme: theme
theme: theme,
setLocal: setLocal,
getLocal: getLocal,
removeLocal: removeLocal
}
})();

View File

@@ -160,18 +160,19 @@ RED.actionList = (function() {
createDialog();
}
dialog.slideDown(300);
searchInput.searchBox('value',v)
searchInput.searchBox('value',v);
searchResults.editableList('empty');
results = [];
var actions = RED.actions.list();
actions.sort(function(A,B) {
return A.id.localeCompare(B.id);
var Akey = A.label;
var Bkey = B.label;
return Akey.localeCompare(Bkey);
});
actions.forEach(function(action) {
action.label = action.id.replace(/:/,": ").replace(/-/g," ").replace(/(^| )./g,function() { return arguments[0].toUpperCase()});
action._label = action.label.toLowerCase();
searchResults.editableList('addItem',action)
})
searchResults.editableList('addItem',action);
});
RED.events.emit("actionList:open");
visible = true;
}

View File

@@ -1,25 +1,39 @@
RED.actions = (function() {
var actions = {
}
};
function addAction(name,handler) {
actions[name] = handler;
function addAction(name,handler,options) {
if (typeof handler !== 'function') {
throw new Error("Action handler not a function");
}
if (actions[name]) {
throw new Error("Cannot override existing action");
}
actions[name] = {
handler: handler,
options: options,
};
}
function removeAction(name) {
delete actions[name];
}
function getAction(name) {
return actions[name];
return actions[name].handler;
}
function invokeAction(name,args) {
function invokeAction() {
var args = Array.prototype.slice.call(arguments);
var name = args.shift();
if (actions.hasOwnProperty(name)) {
actions[name](args);
var handler = actions[name].handler;
handler.apply(null, args);
}
}
function listActions() {
var result = [];
var missing = [];
Object.keys(actions).forEach(function(action) {
var def = actions[action];
var shortcut = RED.keyboard.getShortcut(action);
var isUser = false;
if (shortcut) {
@@ -27,13 +41,38 @@ RED.actions = (function() {
} else {
isUser = !!RED.keyboard.getUserShortcut(action);
}
if (!def.label) {
var name = action;
var options = def.options;
var key = options ? options.label : undefined;
if (!key) {
key = "action-list." +name.replace(/^.*:/,"");
}
var label = RED._(key);
if (label === key) {
// no translation. convert `name` to description
label = name.replace(/(^.+:([a-z]))|(-([a-z]))/g, function() {
if (arguments[5] === 0) {
return arguments[2].toUpperCase();
} else {
return " "+arguments[4].toUpperCase();
}
});
missing.push(key);
}
def.label = label;
}
//console.log("; missing:", missing);
result.push({
id:action,
scope:shortcut?shortcut.scope:undefined,
key:shortcut?shortcut.key:undefined,
user:isUser
})
})
user:isUser,
label: def.label,
options: def.options,
});
});
return result;
}
return {

View File

@@ -71,6 +71,7 @@ RED.clipboard = (function() {
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
RED.view.focus();
}
},
{ // red-ui-clipboard-dialog-download
@@ -81,6 +82,7 @@ RED.clipboard = (function() {
var data = $("#red-ui-clipboard-dialog-export-text").val();
downloadData("flows.json", data);
$( this ).dialog( "close" );
RED.view.focus();
}
},
{ // red-ui-clipboard-dialog-export
@@ -95,6 +97,7 @@ RED.clipboard = (function() {
$( this ).dialog( "close" );
copyText(flowData);
RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"});
RED.view.focus();
} else {
var flowToExport = $("#red-ui-clipboard-dialog-export-text").val();
var selectedPath = activeLibraries[activeTab].getSelected();
@@ -110,6 +113,7 @@ RED.clipboard = (function() {
contentType: "application/json; charset=utf-8"
}).done(function() {
$(dialog).dialog( "close" );
RED.view.focus();
RED.notify(RED._("library.exportedToLibrary"),"success");
}).fail(function(xhr,textStatus,err) {
if (xhr.status === 401) {
@@ -171,6 +175,7 @@ RED.clipboard = (function() {
}
}
$( this ).dialog( "close" );
RED.view.focus();
}
},
{ // red-ui-clipboard-dialog-import-conflict
@@ -203,6 +208,7 @@ RED.clipboard = (function() {
// console.table(pendingImportConfig.importNodes.map(function(n) { return {id:n.id,type:n.type,result:importMap[n.id]}}))
RED.view.importNodes(newNodes, pendingImportConfig.importOptions);
$( this ).dialog( "close" );
RED.view.focus();
}
}
],
@@ -498,6 +504,13 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport);
$("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
if (RED.workspaces.active() === 0) {
$("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected");
$("#red-ui-clipboard-dialog-import-opt-new").addClass("selected");
} else {
$("#red-ui-clipboard-dialog-import-opt-current").removeClass('disabled').addClass("selected");
$("#red-ui-clipboard-dialog-import-opt-new").removeClass("selected");
}
$("#red-ui-clipboard-dialog-import-opt > a").on("click", function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
@@ -611,9 +624,6 @@ RED.clipboard = (function() {
activeLibraries[tabId] = browser;
})
$("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename);
$("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)});
$("#red-ui-clipboard-dialog-export").button("enable");
@@ -636,7 +646,6 @@ RED.clipboard = (function() {
label: RED._("editor.types.json")
});
var previewList = $("#red-ui-clipboard-dialog-export-tab-clipboard-preview-list").css({position:"absolute",top:0,right:0,bottom:0,left:0}).treeList({
data: []
})
@@ -738,16 +747,22 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-export").hide();
$("#red-ui-clipboard-dialog-import-conflict").hide();
var selection = RED.workspaces.selection();
if (selection.length > 0) {
$("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
if (RED.workspaces.active() === 0) {
$("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected');
$("#red-ui-clipboard-dialog-export-rng-flow").addClass('disabled').removeClass('selected');
$("#red-ui-clipboard-dialog-export-rng-full").trigger("click");
} else {
selection = RED.view.selection();
if (selection.nodes) {
var selection = RED.workspaces.selection();
if (selection.length > 0) {
$("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
} else {
$("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected');
$("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
selection = RED.view.selection();
if (selection.nodes) {
$("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
} else {
$("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected');
$("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
}
}
}
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
@@ -931,7 +946,8 @@ RED.clipboard = (function() {
if (truncated) {
msg += "_truncated";
}
$("#red-ui-clipboard-hidden").val(value).focus().select();
var clipboardHidden = $('<textarea type="text" id="red-ui-clipboard-hidden" tabIndex="-1">').appendTo(document.body);
clipboardHidden.val(value).focus().select();
var result = document.execCommand("copy");
if (result && element) {
var popover = RED.popover.create({
@@ -945,14 +961,13 @@ RED.clipboard = (function() {
},1000);
popover.open();
}
$("#red-ui-clipboard-hidden").val("");
clipboardHidden.remove();
if (currentFocus) {
$(currentFocus).focus();
}
return result;
}
function importNodes(nodesStr,addFlow) {
var newNodes = nodesStr;
if (typeof nodesStr === 'string') {
@@ -1227,8 +1242,6 @@ RED.clipboard = (function() {
init: function() {
setupDialogs();
$('<textarea type="text" id="red-ui-clipboard-hidden" tabIndex="-1">').appendTo("#red-ui-editor");
RED.actions.add("core:show-export-dialog",showExportNodes);
RED.actions.add("core:show-import-dialog",showImportNodes);

View File

@@ -0,0 +1,115 @@
(function($) {
/**
* Attach to an <input type="text"> to provide auto-complete
*
* $("#node-red-text").autoComplete({
* search: function(value) { return ['a','b','c'] }
* })
*
* options:
*
* search : function(value, [done])
* A function that is passed the current contents of the input whenever
* it changes.
* The function must either return auto-complete options, or pass them
* to the optional 'done' parameter.
* If the function signature includes 'done', it must be used
*
* The auto-complete options should be an array of objects in the form:
* {
* value: String : the value to insert if selected
* label: String|DOM Element : the label to display in the dropdown.
* }
*
*/
$.widget( "nodered.autoComplete", {
_create: function() {
var that = this;
this.completionMenuShown = false;
this.options.search = this.options.search || function() { return [] }
this.element.addClass("red-ui-autoComplete")
this.element.on("keydown.red-ui-autoComplete", function(evt) {
if ((evt.keyCode === 13 || evt.keyCode === 9) && that.completionMenuShown) {
var opts = that.menu.options();
that.element.val(opts[0].value);
that.menu.hide();
evt.preventDefault();
}
})
this.element.on("keyup.red-ui-autoComplete", function(evt) {
if (evt.keyCode === 13 || evt.keyCode === 9 || evt.keyCode === 27) {
// ENTER / TAB / ESCAPE
return
}
if (evt.keyCode === 8 || evt.keyCode === 46) {
// Delete/Backspace
if (!that.completionMenuShown) {
return;
}
}
that._updateCompletions(this.value);
});
},
_showCompletionMenu: function(completions) {
if (this.completionMenuShown) {
return;
}
this.menu = RED.popover.menu({
tabSelect: true,
width: 300,
maxHeight: 200,
class: "red-ui-autoComplete-container",
options: completions,
onselect: (opt) => { this.element.val(opt.value); this.element.focus(); this.element.trigger("change") },
onclose: () => { this.completionMenuShown = false; delete this.menu; this.element.focus()}
});
this.menu.show({
target: this.element
})
this.completionMenuShown = true;
},
_updateCompletions: function(val) {
var that = this;
if (val.trim() === "") {
if (this.completionMenuShown) {
this.menu.hide();
}
return;
}
function displayResults(completions,requestId) {
if (requestId && requestId !== that.pendingRequest) {
// This request has been superseded
return
}
if (!completions || completions.length === 0) {
if (that.completionMenuShown) {
that.menu.hide();
}
return
}
if (that.completionMenuShown) {
that.menu.options(completions);
} else {
that._showCompletionMenu(completions);
}
}
if (this.options.search.length === 2) {
var requestId = 1+Math.floor(Math.random()*10000);
this.pendingRequest = requestId;
this.options.search(val,function(completions) { displayResults(completions,requestId);})
} else {
displayResults(this.options.search(val))
}
},
_destroy: function() {
this.element.removeClass("red-ui-autoComplete")
this.element.off("keydown.red-ui-autoComplete")
this.element.off("keyup.red-ui-autoComplete")
if (this.completionMenuShown) {
this.menu.hide();
}
}
});
})(jQuery);

View File

@@ -82,12 +82,19 @@ RED.menu = (function() {
linkContent += '<span class="red-ui-menu-label-container"><span class="red-ui-menu-label">'+opt.label+'</span>'+
'<span class="red-ui-menu-sublabel">'+opt.sublabel+'</span></span>'
} else {
linkContent += '<span class="red-ui-menu-label">'+opt.label+'</span>'
linkContent += '<span class="red-ui-menu-label"><span>'+opt.label+'</span></span>'
}
linkContent += '</a>';
var link = $(linkContent).appendTo(item);
opt.link = link;
if (typeof opt.onselect === 'string') {
var shortcut = RED.keyboard.getShortcut(opt.onselect);
if (shortcut && shortcut.key) {
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(link.find(".red-ui-menu-label"));
}
}
menuItems[opt.id] = opt;
@@ -276,6 +283,22 @@ RED.menu = (function() {
}
}
function refreshShortcuts() {
for (var id in menuItems) {
if (menuItems.hasOwnProperty(id)) {
var opt = menuItems[id];
if (typeof opt.onselect === "string" && opt.shortcutSpan) {
opt.shortcutSpan.remove();
delete opt.shortcutSpan;
var shortcut = RED.keyboard.getShortcut(opt.onselect);
if (shortcut && shortcut.key) {
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(opt.link.find(".red-ui-menu-label"));
}
}
}
}
}
return {
init: createMenu,
setSelected: setSelected,
@@ -284,6 +307,7 @@ RED.menu = (function() {
setDisabled: setDisabled,
addItem: addItem,
removeItem: removeItem,
setAction: setAction
setAction: setAction,
refreshShortcuts: refreshShortcuts
}
})();

View File

@@ -13,24 +13,138 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/*
* RED.popover.create(options) - create a popover callout box
* RED.popover.tooltip(target,content, action) - add a tooltip to an element
* RED.popover.menu(options) - create a dropdown menu
* RED.popover.panel(content) - create a dropdown container element
*/
/*
* RED.popover.create(options)
*
* options
* - target : DOM element - the element to target with the popover
* - direction : string - position of the popover relative to target
* 'top', 'right'(default), 'bottom', 'left', 'inset-[top,right,bottom,left]'
* - trigger : string - what triggers the popover to be displayed
* 'hover' - display when hovering the target
* 'click' - display when target is clicked
* 'modal' - hmm not sure, need to find where we use that mode
* - content : string|function - contents of the popover. If a string, handled
* as raw HTML, so take care.
* If a function, can return a String to be added
* as text (not HTML), or a DOM element to append
* - delay : object - sets show/hide delays after mouseover/out events
* { show: 750, hide: 50 }
* - autoClose : number - delay before closing the popover in some cases
* if trigger is click - delay after mouseout
* else if trigger not hover/modal - delay after showing
* - width : number - width of popover, default 'auto'
* - maxWidth : number - max width of popover, default 'auto'
* - size : string - scale of popover. 'default', 'small'
* - offset : number - px offset from target
* - tooltip : boolean - if true, clicking on popover closes it
* - class : string - optional css class to apply to popover
* - interactive : if trigger is 'hover' and this is set to true, allow the mouse
* to move over the popover without hiding it.
*
* Returns the popover object with the following properties/functions:
* properties:
* - element : DOM element - the popover dom element
* functions:
* - setContent(content) - change the popover content. This only works if the
* popover is not currently displayed. It does not
* change the content of a visible popover.
* - open(instant) - show the popover. If 'instant' is true, don't fade in
* - close(instant) - hide the popover. If 'instant' is true, don't fade out
* - move(options) - move the popover. The options parameter can take many
* of the options detailed above including:
* target,direction,content,width,offset
* Other settings probably won't work because we haven't needed to change them
*/
/*
* RED.popover.tooltip(target,content, action)
*
* - target : DOM element - the element to apply the tooltip to
* - content : string - the text of the tooltip
* - action : string - *optional* the name of an Action this tooltip is tied to
* For example, it 'target' is a button that triggers a particular action.
* The tooltip will include the keyboard shortcut for the action
* if one is defined
*
*/
/*
* RED.popover.menu(options)
*
* options
* - options : array - list of menu options - see below for format
* - width : number - width of the menu. Default: 'auto'
* - class : string - class to apply to the menu container
* - maxHeight : number - maximum height of menu before scrolling items. Default: none
* - onselect : function(item) - called when a menu item is selected, if that item doesn't
* have its own onselect function
* - onclose : function(cancelled) - called when the menu is closed
* - disposeOnClose : boolean - by default, the menu is discarded when it closes
* and mustbe rebuilt to redisplay. Setting this to 'false'
* keeps the menu on the DOM so it can be shown again.
*
* Menu Options array:
* [
* label : string|DOM element - the label of the item. Can be custom DOM element
* onselect : function - called when the item is selected
* ]
*
* Returns the menu object with the following functions:
*
* - options([menuItems]) - if menuItems is undefined, returns the current items.
* otherwise, sets the current menu items
* - show(opts) - shows the menu. `opts` is an object of options. See RED.popover.panel.show(opts)
* for the full list of options. In most scenarios, this just needs:
* - target : DOM element - the element to display the menu below
* - hide(cancelled) - hide the menu
*/
/*
* RED.popover.panel(content)
* Create a UI panel that can be displayed relative to any target element.
* Handles auto-closing when mouse clicks outside the panel
*
* - 'content' - DOM element to display in the panel
*
* Returns the panel object with the following functions:
*
* properties:
* - container : DOM element - the panel element
*
* functions:
* - show(opts) - show the panel.
* opts:
* - onclose : function - called when the panel closes
* - closeButton : DOM element - if the panel is closeable by a click of a button,
* by providing a reference to it here, we can
* handle the events properly to hide the panel
* - target : DOM element - the element to display the panel relative to
* - align : string - should the panel align to the left or right edge of target
* default: 'right'
* - offset : Array - px offset to apply from the target. [width, height]
* - dispose : boolean - whether the panel should be removed from DOM when hidden
* default: true
* - hide(dispose) - hide the panel.
*/
RED.popover = (function() {
var deltaSizes = {
"default": {
top: 10,
topTop: 30,
leftRight: 17,
leftLeft: 25,
leftBottom: 8,
leftTop: 11
x: 12,
y: 12
},
"small": {
top: 6,
topTop: 20,
leftRight: 8,
leftLeft: 26,
leftBottom: 8,
leftTop: 9
x:8,
y:8
}
}
function createPopover(options) {
@@ -41,7 +155,9 @@ RED.popover = (function() {
var delay = options.delay || { show: 750, hide: 50 };
var autoClose = options.autoClose;
var width = options.width||"auto";
var maxWidth = options.maxWidth;
var size = options.size||"default";
var popupOffset = options.offset || 0;
if (!deltaSizes[size]) {
throw new Error("Invalid RED.popover size value:",size);
}
@@ -49,6 +165,8 @@ RED.popover = (function() {
var timer = null;
var active;
var div;
var contentDiv;
var currentStyle;
var openPopup = function(instant) {
if (active) {
@@ -58,6 +176,10 @@ RED.popover = (function() {
return;
}
div = $('<div class="red-ui-popover"></div>');
if (options.class) {
div.addClass(options.class);
}
contentDiv = $('<div class="red-ui-popover-content">').appendTo(div);
if (size !== "default") {
div.addClass("red-ui-popover-size-"+size);
}
@@ -67,71 +189,23 @@ RED.popover = (function() {
return;
}
if (typeof result === 'string') {
div.text(result);
contentDiv.text(result);
} else {
div.append(result);
contentDiv.append(result);
}
} else {
div.html(content);
}
if (width !== "auto") {
div.width(width);
contentDiv.html(content);
}
div.appendTo("body");
var targetPos = target.offset();
var targetWidth = target.outerWidth();
var targetHeight = target.outerHeight();
var divHeight = div.height();
var divWidth = div.width();
var paddingRight = 10;
movePopup({target,direction,width,maxWidth});
var viewportTop = $(window).scrollTop();
var viewportLeft = $(window).scrollLeft();
var viewportBottom = viewportTop + $(window).height();
var viewportRight = viewportLeft + $(window).width();
var top = 0;
var left = 0;
var d = direction;
if (d === 'right') {
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
left = targetPos.left+targetWidth+deltaSizes[size].leftRight;
} else if (d === 'left') {
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
left = targetPos.left-deltaSizes[size].leftLeft-divWidth;
} else if (d === 'bottom') {
top = targetPos.top+targetHeight+deltaSizes[size].top;
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom;
if (left < 0) {
d = "right";
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
left = targetPos.left+targetWidth+deltaSizes[size].leftRight;
} else if (left+divWidth+paddingRight > viewportRight) {
d = "left";
top = targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top;
left = targetPos.left-deltaSizes[size].leftLeft-divWidth;
if (top+divHeight+targetHeight/2 + 5 > viewportBottom) {
top -= (top+divHeight+targetHeight/2 - viewportBottom + 5)
}
} else if (top+divHeight > viewportBottom) {
d = 'top';
top = targetPos.top-deltaSizes[size].topTop-divHeight;
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftTop;
}
} else if (d === 'top') {
top = targetPos.top-deltaSizes[size].topTop-divHeight;
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftTop;
if (top < 0) {
d = 'bottom';
top = targetPos.top+targetHeight+deltaSizes[size].top;
left = targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom;
}
}
div.addClass('red-ui-popover-'+d).css({top: top, left: left});
if (existingPopover) {
existingPopover.close(true);
}
target.data("red-ui-popover",res)
if (options.trigger !== 'manual') {
target.data("red-ui-popover",res)
}
if (options.tooltip) {
div.on("mousedown", function(evt) {
closePopup(true);
@@ -161,6 +235,104 @@ RED.popover = (function() {
}
}
}
var movePopup = function(options) {
target = options.target || target;
direction = options.direction || direction || "right";
popupOffset = options.offset || popupOffset;
var transition = options.transition;
var width = options.width||"auto";
div.width(width);
if (options.maxWidth) {
div.css("max-width",options.maxWidth)
} else {
div.css("max-width", 'auto');
}
var targetPos = target[0].getBoundingClientRect();
var targetHeight = targetPos.height;
var targetWidth = targetPos.width;
var divHeight = div.outerHeight();
var divWidth = div.outerWidth();
var paddingRight = 10;
var viewportTop = $(window).scrollTop();
var viewportLeft = $(window).scrollLeft();
var viewportBottom = viewportTop + $(window).height();
var viewportRight = viewportLeft + $(window).width();
var top = 0;
var left = 0;
if (direction === 'right') {
top = targetPos.top+targetHeight/2-divHeight/2;
left = targetPos.left+targetWidth+deltaSizes[size].x+popupOffset;
} else if (direction === 'left') {
top = targetPos.top+targetHeight/2-divHeight/2;
left = targetPos.left-deltaSizes[size].x-divWidth-popupOffset;
} else if (direction === 'bottom') {
top = targetPos.top+targetHeight+deltaSizes[size].y+popupOffset;
left = targetPos.left+targetWidth/2-divWidth/2;
if (left < 0) {
direction = "right";
top = targetPos.top+targetHeight/2-divHeight/2;
left = targetPos.left+targetWidth+deltaSizes[size].x+popupOffset;
} else if (left+divWidth+paddingRight > viewportRight) {
direction = "left";
top = targetPos.top+targetHeight/2-divHeight/2;
left = targetPos.left-deltaSizes[size].x-divWidth-popupOffset;
if (top+divHeight+targetHeight/2 + 5 > viewportBottom) {
top -= (top+divHeight+targetHeight/2 - viewportBottom + 5)
}
} else if (top+divHeight > viewportBottom) {
direction = 'top';
top = targetPos.top-deltaSizes[size].y-divHeight-popupOffset;
left = targetPos.left+targetWidth/2-divWidth/2;
}
} else if (direction === 'top') {
top = targetPos.top-deltaSizes[size].y-divHeight-popupOffset;
left = targetPos.left+targetWidth/2-divWidth/2;
if (top < 0) {
direction = 'bottom';
top = targetPos.top+targetHeight+deltaSizes[size].y+popupOffset;
left = targetPos.left+targetWidth/2-divWidth/2;
}
} else if (/inset/.test(direction)) {
top = targetPos.top + targetHeight/2 - divHeight/2;
left = targetPos.left + targetWidth/2 - divWidth/2;
if (/bottom/.test(direction)) {
top = targetPos.top + targetHeight - divHeight-popupOffset;
}
if (/top/.test(direction)) {
top = targetPos.top+popupOffset;
}
if (/left/.test(direction)) {
left = targetPos.left+popupOffset;
}
if (/right/.test(direction)) {
left = targetPos.left + targetWidth - divWidth-popupOffset;
}
}
if (currentStyle) {
div.removeClass(currentStyle);
}
if (transition) {
div.css({
"transition": "0.6s ease",
"transition-property": "top,left,right,bottom"
})
}
currentStyle = 'red-ui-popover-'+direction;
div.addClass(currentStyle).css({top: top, left: left});
if (transition) {
setTimeout(function() {
div.css({
"transition": "none"
});
},600);
}
}
var closePopup = function(instant) {
$(document).off('mousedown.red-ui-popover');
if (!active) {
@@ -178,6 +350,15 @@ RED.popover = (function() {
}
}
target.on("remove", function (ev) {
if (timer) {
clearTimeout(timer);
}
if (active) {
active = false;
setTimeout(closePopup,delay.hide);
}
});
if (trigger === 'hover') {
target.on('mouseenter',function(e) {
clearTimeout(timer);
@@ -236,8 +417,10 @@ RED.popover = (function() {
},autoClose);
}
var res = {
get element() { return div },
setContent: function(_content) {
content = _content;
return res;
},
open: function (instant) {
@@ -249,6 +432,10 @@ RED.popover = (function() {
active = false;
closePopup(instant);
return res;
},
move: function(options) {
movePopup(options);
return
}
}
return res;
@@ -258,18 +445,17 @@ RED.popover = (function() {
return {
create: createPopover,
tooltip: function(target,content, action) {
var label = content;
if (action) {
label = function() {
var label = content;
var label = function() {
var label = content;
if (action) {
var shortcut = RED.keyboard.getShortcut(action);
if (shortcut && shortcut.key) {
label = $('<span>'+content+' <span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span></span>');
}
return label;
}
return label;
}
return RED.popover.create({
var popover = RED.popover.create({
tooltip: true,
target:target,
trigger: "hover",
@@ -278,6 +464,14 @@ RED.popover = (function() {
content: label,
delay: { show: 750, hide: 50 }
});
popover.setContent = function(newContent) {
content = newContent;
}
popover.setAction = function(newAction) {
action = newAction;
}
return popover;
},
menu: function(options) {
var list = $('<ul class="red-ui-menu"></ul>');
@@ -286,20 +480,47 @@ RED.popover = (function() {
}
var menuOptions = options.options || [];
var first;
menuOptions.forEach(function(opt) {
var item = $('<li>').appendTo(list);
var link = $('<a href="#"></a>').text(opt.label).appendTo(item);
link.on("click", function(evt) {
evt.preventDefault();
if (opt.onselect) {
opt.onselect();
}
menu.hide();
})
if (!first) { first = link}
})
var container = RED.popover.panel(list);
if (options.width) {
container.container.width(options.width);
}
if (options.class) {
container.container.addClass(options.class);
}
if (options.maxHeight) {
container.container.css({
"max-height": options.maxHeight,
"overflow-y": 'auto'
})
}
var menu = {
options: function(opts) {
if (opts === undefined) {
return menuOptions
}
menuOptions = opts || [];
list.empty();
menuOptions.forEach(function(opt) {
var item = $('<li>').appendTo(list);
var link = $('<a href="#"></a>').appendTo(item);
if (typeof opt.label == "string") {
link.text(opt.label)
} else if (opt.label){
opt.label.appendTo(link);
}
link.on("click", function(evt) {
evt.preventDefault();
if (opt.onselect) {
opt.onselect();
} else if (options.onselect) {
options.onselect(opt);
}
menu.hide();
})
if (!first) { first = link}
})
},
show: function(opts) {
$(document).on("keydown.red-ui-menu", function(evt) {
var currentItem = list.find(":focus").parent();
@@ -333,6 +554,11 @@ RED.popover = (function() {
// ESCAPE
evt.preventDefault();
menu.hide(true);
} else if (evt.keyCode === 9 && options.tabSelect) {
// TAB - with tabSelect enabled
evt.preventDefault();
currentItem.find("a").trigger("click");
}
evt.stopPropagation();
})
@@ -352,6 +578,7 @@ RED.popover = (function() {
}
}
}
menu.options(menuOptions);
return menu;
},
panel: function(content) {
@@ -380,12 +607,12 @@ RED.popover = (function() {
var pos = target.offset();
var targetWidth = target.width();
var targetHeight = target.height();
var targetHeight = target.outerHeight();
var panelHeight = panel.height();
var panelWidth = panel.width();
var top = (targetHeight+pos.top) + offset[1];
if (top+panelHeight > $(window).height()) {
if (top+panelHeight-$(document).scrollTop() > $(window).height()) {
top -= (top+panelHeight)-$(window).height() + 5;
}
if (top < 0) {

View File

@@ -38,6 +38,7 @@ RED.tabs = (function() {
if (options.vertical) {
wrapper.addClass("red-ui-tabs-vertical");
}
if (options.addButton) {
wrapper.addClass("red-ui-tabs-add");
var addButton = $('<div class="red-ui-tab-button red-ui-tabs-add"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
@@ -75,6 +76,8 @@ RED.tabs = (function() {
});
}
if (options.searchButton) {
// This is soft-deprecated as we don't use this in the core anymore
// We no use the `menu` option to provide a drop-down list of actions
wrapper.addClass("red-ui-tabs-search");
var searchButton = $('<div class="red-ui-tab-button red-ui-tabs-search"><a href="#"><i class="fa fa-list-ul"></i></a></div>').appendTo(wrapper);
searchButton.find('a').on("click", function(evt) {
@@ -94,6 +97,52 @@ RED.tabs = (function() {
}
}
if (options.menu) {
wrapper.addClass("red-ui-tabs-menu");
var menuButton = $('<div class="red-ui-tab-button red-ui-tabs-menu"><a href="#"><i class="fa fa-caret-down"></i></a></div>').appendTo(wrapper);
var menuButtonLink = menuButton.find('a')
var menuOpen = false;
var menu;
menuButtonLink.on("click", function(evt) {
evt.stopPropagation();
evt.preventDefault();
if (menuOpen) {
menu.remove();
menuOpen = false;
return;
}
menuOpen = true;
var menuOptions = [];
if (typeof options.searchButton === 'function') {
menuOptions = options.menu()
} else if (Array.isArray(options.menu)) {
menuOptions = options.menu;
} else if (typeof options.menu === 'function') {
menuOptions = options.menu();
}
menu = RED.menu.init({options: menuOptions});
menu.attr("id",options.id+"-menu");
menu.css({
position: "absolute"
})
menu.appendTo("body");
var elementPos = menuButton.offset();
menu.css({
top: (elementPos.top+menuButton.height()-2)+"px",
left: (elementPos.left - menu.width() + menuButton.width())+"px"
})
$(".red-ui-menu.red-ui-menu-dropdown").hide();
$(document).on("click.red-ui-tabmenu", function(evt) {
$(document).off("click.red-ui-tabmenu");
menuOpen = false;
menu.remove();
});
menu.show();
})
}
var scrollLeft;
var scrollRight;
@@ -117,9 +166,9 @@ RED.tabs = (function() {
}
})
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();});
scrollLeft.on('mousedown',function(evt) {scrollEventHandler(evt, evt.shiftKey?('-='+scrollContainer.scrollLeft()):'-=150') }).on('click',function(evt){ evt.preventDefault();});
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();});
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,evt.shiftKey?('+='+(scrollContainer[0].scrollWidth - scrollContainer.width()-scrollContainer.scrollLeft())):'+=150') }).on('click',function(evt){ evt.preventDefault();});
}
if (options.collapsible) {
@@ -337,6 +386,12 @@ RED.tabs = (function() {
if (link.length === 0) {
return;
}
if (link.parent().hasClass("hide-tab")) {
link.parent().removeClass("hide-tab").removeClass("hide");
if (options.onshow) {
options.onshow(tabs[link.attr('href').slice(1)])
}
}
if (!link.parent().hasClass("active")) {
ul.children().removeClass("active");
ul.children().css({"transition": "width 100ms"});
@@ -362,13 +417,13 @@ RED.tabs = (function() {
}
}
function activatePreviousTab() {
var previous = ul.find("li.active").prev();
var previous = findPreviousVisibleTab();
if (previous.length > 0) {
activateTab(previous.find("a"));
}
}
function activateNextTab() {
var next = ul.find("li.active").next();
var next = findNextVisibleTab();
if (next.length > 0) {
activateTab(next.find("a"));
}
@@ -378,7 +433,9 @@ RED.tabs = (function() {
if (options.vertical) {
return;
}
var tabs = ul.find("li.red-ui-tab");
var allTabs = ul.find("li.red-ui-tab");
var tabs = allTabs.filter(":not(.hide-tab)");
var hiddenTabs = allTabs.filter(".hide-tab");
var width = wrapper.width();
var tabCount = tabs.length;
var tabWidth;
@@ -446,6 +503,7 @@ RED.tabs = (function() {
// }
tabs.css({width:currentTabWidth});
hiddenTabs.css({width:"0px"});
if (tabWidth < 50) {
// ul.find(".red-ui-tab-close").hide();
ul.find(".red-ui-tab-icon").hide();
@@ -486,12 +544,19 @@ RED.tabs = (function() {
}
var li = ul.find("a[href='#"+id+"']").parent();
if (li.hasClass("active")) {
var tab = li.prev();
var tab = findPreviousVisibleTab(li);
if (tab.length === 0) {
tab = li.next();
tab = findNextVisibleTab(li);
}
if (tab.length > 0) {
activateTab(tab.find("a"));
} else {
if (options.onchange) {
options.onchange(null);
}
}
activateTab(tab.find("a"));
}
li.remove();
if (tabs[id].pinned) {
pinnedTabsCount--;
@@ -507,6 +572,75 @@ RED.tabs = (function() {
}
}
function findPreviousVisibleTab(li) {
if (!li) {
li = ul.find("li.active");
}
var previous = li.prev();
while(previous.length > 0 && previous.hasClass("hide-tab")) {
previous = previous.prev();
}
return previous;
}
function findNextVisibleTab(li) {
if (!li) {
li = ul.find("li.active");
}
var next = li.next();
while(next.length > 0 && next.hasClass("hide-tab")) {
next = next.next();
}
return next;
}
function showTab(id) {
if (tabs[id]) {
var li = ul.find("a[href='#"+id+"']").parent();
if (li.hasClass("hide-tab")) {
li.removeClass("hide-tab").removeClass("hide");
if (ul.find("li.red-ui-tab:not(.hide-tab)").length === 1) {
activateTab(li.find("a"))
}
updateTabWidths();
if (options.onshow) {
options.onshow(tabs[id])
}
}
}
}
function hideTab(id) {
if (tabs[id]) {
var li = ul.find("a[href='#"+id+"']").parent();
if (!li.hasClass("hide-tab")) {
if (li.hasClass("active")) {
var tab = findPreviousVisibleTab(li);
if (tab.length === 0) {
tab = findNextVisibleTab(li);
}
if (tab.length > 0) {
activateTab(tab.find("a"));
} else {
if (options.onchange) {
options.onchange(null);
}
}
}
li.removeClass("active");
li.one("transitionend", function(evt) {
li.addClass("hide");
updateTabWidths();
if (options.onhide) {
options.onhide(tabs[id])
}
setTimeout(function() {
updateScroll()
},200)
})
li.addClass("hide-tab");
li.css({width:0})
}
}
}
var tabAPI = {
addTab: function(tab,targetIndex) {
if (options.onselect) {
@@ -663,7 +797,6 @@ RED.tabs = (function() {
link.on("click", function(evt) { evt.preventDefault(); })
link.on("dblclick", function(evt) { evt.stopPropagation(); evt.preventDefault(); })
$('<span class="red-ui-tabs-fade"></span>').appendTo(li);
if (tab.closeable) {
@@ -674,6 +807,18 @@ RED.tabs = (function() {
event.preventDefault();
removeTab(tab.id);
});
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
}
if (tab.hideable) {
li.addClass("red-ui-tabs-closeable")
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
closeLink.append('<i class="fa fa-eye" />');
closeLink.append('<i class="fa fa-eye-slash" />');
closeLink.on("click",function(event) {
event.preventDefault();
hideTab(tab.id);
});
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
}
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
@@ -682,11 +827,12 @@ RED.tabs = (function() {
$('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges);
}
// link.attr("title",tab.label);
RED.popover.tooltip(link,function() { return RED.utils.sanitize(tab.label); });
if (options.onadd) {
options.onadd(tab);
}
link.attr("title",tab.label);
if (ul.find("li.red-ui-tab").length == 1) {
activateTab(link);
}
@@ -787,7 +933,7 @@ RED.tabs = (function() {
previousTab: activatePreviousTab,
resize: updateTabWidths,
count: function() {
return ul.find("li.red-ui-tab").length;
return ul.find("li.red-ui-tab:not(.hide)").length;
},
activeIndex: function() {
return ul.find("li.active").index()
@@ -795,14 +941,29 @@ RED.tabs = (function() {
contains: function(id) {
return ul.find("a[href='#"+id+"']").length > 0;
},
showTab: showTab,
hideTab: hideTab,
renameTab: function(id,label) {
tabs[id].label = label;
var tab = ul.find("a[href='#"+id+"']");
tab.attr("title",label);
tab.find("span.red-ui-text-bidi-aware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label));
updateTabWidths();
},
listTabs: function() {
return $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
},
selection: getSelection,
clearSelection: function() {
if (options.onselect) {
var selection = ul.find("li.red-ui-tab.selected");
if (selection.length > 0) {
selection.removeClass("selected");
selectionChanged();
}
}
},
order: function(order) {
preferredOrder = order;
var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));

View File

@@ -24,6 +24,9 @@
* - rootSortable: boolean - if 'sortable' is set, then setting this to
* false, prevents items being sorted to the
* top level of the tree
* - autoSelect: boolean - default true - triggers item selection when navigating
* list by keyboard. If the list has checkboxed items
* you probably want to set this to false
*
* methods:
* - data(items) - clears existing items and replaces with new data
@@ -41,6 +44,7 @@
* sublabel: 'Local', // a sub-label for the item
* icon: 'fa fa-rocket', // (optional) icon for the item
* checkbox: true/false, // (optional) if present, display checkbox accordingly
* radio: 'group-name', // (optional) if present, display radio box - using group-name to set radio group
* selected: true/false, // (optional) whether the item is selected or not
* children: [] | function(done,item) // (optional) an array of child items, or a function
* // that will call the `done` callback with an array
@@ -49,6 +53,7 @@
* deferBuild: true/false, // don't build any ui elements for the item's children
* until it is expanded by the user.
* element: // custom dom element to use for the item - ignored if `label` is set
* collapsible: true/false, // prevent a parent item from being collapsed. default true.
* }
* ]
*
@@ -89,77 +94,99 @@
$.widget( "nodered.treeList", {
_create: function() {
var that = this;
var autoSelect = true;
if (that.options.autoSelect === false) {
autoSelect = false;
}
this.element.addClass('red-ui-treeList');
this.element.attr("tabIndex",0);
var wrapper = $('<div>',{class:'red-ui-treeList-container'}).appendTo(this.element);
this.element.on('keydown', function(evt) {
var selected = that._topList.find(".selected").parent().data('data');
if (!selected && (evt.keyCode === 40 || evt.keyCode === 38)) {
that.select(that._data[0]);
var focussed = that._topList.find(".focus").parent().data('data');
if (!focussed && (evt.keyCode === 40 || evt.keyCode === 38)) {
if (that._data[0]) {
if (autoSelect) {
that.select(that._data[0]);
} else {
that._topList.find(".focus").removeClass("focus")
}
that._data[0].treeList.label.addClass('focus')
}
return;
}
var target;
switch(evt.keyCode) {
case 32: // SPACE
case 13: // ENTER
if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) {
return
}
evt.preventDefault();
evt.stopPropagation();
if (selected.children) {
if (selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse()
if (focussed.checkbox) {
focussed.treeList.checkbox.trigger("click");
} else if (focussed.radio) {
focussed.treeList.radio.trigger("click");
} else if (focussed.children) {
if (focussed.treeList.container.hasClass("expanded")) {
focussed.treeList.collapse()
} else {
selected.treeList.expand()
focussed.treeList.expand()
}
} else {
that._trigger("confirm",null,selected)
that._trigger("confirm",null,focussed)
}
break;
case 37: // LEFT
evt.preventDefault();
evt.stopPropagation();
if (selected.children&& selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse()
} else if (selected.parent) {
target = selected.parent;
if (focussed.children&& focussed.treeList.container.hasClass("expanded")) {
focussed.treeList.collapse()
} else if (focussed.parent) {
target = focussed.parent;
}
break;
case 38: // UP
evt.preventDefault();
evt.stopPropagation();
target = that._getPreviousSibling(selected);
target = that._getPreviousSibling(focussed);
if (target) {
target = that._getLastDescendant(target);
}
if (!target && selected.parent) {
target = selected.parent;
if (!target && focussed.parent) {
target = focussed.parent;
}
break;
case 39: // RIGHT
evt.preventDefault();
evt.stopPropagation();
if (selected.children) {
if (!selected.treeList.container.hasClass("expanded")) {
selected.treeList.expand()
if (focussed.children) {
if (!focussed.treeList.container.hasClass("expanded")) {
focussed.treeList.expand()
}
}
break
case 40: //DOWN
evt.preventDefault();
evt.stopPropagation();
if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) {
target = selected.children[0];
if (focussed.children && Array.isArray(focussed.children) && focussed.children.length > 0 && focussed.treeList.container.hasClass("expanded")) {
target = focussed.children[0];
} else {
target = that._getNextSibling(selected);
while (!target && selected.parent) {
selected = selected.parent;
target = that._getNextSibling(selected);
target = that._getNextSibling(focussed);
while (!target && focussed.parent) {
focussed = focussed.parent;
target = that._getNextSibling(focussed);
}
}
break
}
if (target) {
that.select(target);
if (autoSelect) {
that.select(target);
} else {
that._topList.find(".focus").removeClass("focus")
}
target.treeList.label.addClass('focus')
}
});
this._data = [];
@@ -313,7 +340,7 @@
if (child.depth !== parent.depth+1) {
child.depth = parent.depth+1;
// var labelPaddingWidth = ((child.gutter ? child.gutter[0].offsetWidth + 2 : 0) + (child.depth * 20));
var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20));
var labelPaddingWidth = (((child.gutter&&!child.gutter.hasClass("red-ui-treeList-gutter-float"))?child.gutter.width()+2:0)+(child.depth*20));
child.treeList.labelPadding.width(labelPaddingWidth+'px');
if (child.element) {
$(child.element).css({
@@ -462,6 +489,9 @@
container.addClass("expanded");
}
item.treeList.collapse = function() {
if (item.collapsible === false) {
return
}
if (!item.children) {
return;
}
@@ -532,10 +562,12 @@
}).appendTo(label)
}
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
// var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (depth * 20)
var labelPaddingWidth = ((item.gutter&&!item.gutter.hasClass("red-ui-treeList-gutter-float"))?item.gutter.width()+2:0)+(depth*20);
item.treeList.labelPadding = $('<span>').css({
display: "inline-block",
"flex-shrink": 0,
width: labelPaddingWidth+'px'
}).appendTo(label);
@@ -581,7 +613,7 @@
// Already a parent because we've got the angle-right icon
return;
}
$('<i class="fa fa-angle-right" />').appendTo(treeListIcon);
$('<i class="fa fa-angle-right" />').toggleClass("hide",item.collapsible === false).appendTo(treeListIcon);
treeListIcon.on("click.red-ui-treeList-expand", function(e) {
e.stopPropagation();
e.preventDefault();
@@ -632,6 +664,46 @@
label.on("click", function(e) {
e.stopPropagation();
cb.trigger("click");
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
})
}
item.treeList.select = function(v) {
if (v !== item.selected) {
cb.trigger("click");
}
}
item.treeList.checkbox = cb;
selectWrapper.appendTo(label)
} else if (item.radio) {
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>');
var cb = $('<input class="red-ui-treeList-radio" type="radio">').prop('name', item.radio).prop('checked',item.selected).appendTo(selectWrapper);
cb.on('click', function(e) {
e.stopPropagation();
});
cb.on('change', function(e) {
item.selected = this.checked;
that._selected.forEach(function(selectedItem) {
if (selectedItem.radio === item.radio) {
selectedItem.treeList.label.removeClass("selected");
selectedItem.selected = false;
that._selected.delete(selectedItem);
}
})
if (item.selected) {
that._selected.add(item);
} else {
that._selected.delete(item);
}
label.toggleClass("selected",this.checked);
that._trigger("select",e,item);
})
if (!item.children) {
label.on("click", function(e) {
e.stopPropagation();
cb.trigger("click");
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
})
}
item.treeList.select = function(v) {
@@ -640,6 +712,7 @@
}
}
selectWrapper.appendTo(label)
item.treeList.radio = cb;
} else {
label.on("click", function(e) {
if (!that.options.multi) {
@@ -647,10 +720,14 @@
}
label.addClass("selected");
that._selected.add(item);
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
that._trigger("select",e,item)
})
label.on("dblclick", function(e) {
that._topList.find(".focus").removeClass("focus")
label.addClass('focus')
if (!item.children) {
that._trigger("confirm",e,item);
}
@@ -798,6 +875,9 @@
if (item.treeList.label) {
item.treeList.label.addClass("selected");
}
that._topList.find(".focus").removeClass("focus");
if (triggerEvent !== false) {
this._trigger("select",null,item)
}
@@ -805,6 +885,9 @@
clearSelection: function() {
this._selected.forEach(function(item) {
item.selected = false;
if (item.treeList.checkbox) {
item.treeList.checkbox.prop('checked',false)
}
if (item.treeList.label) {
item.treeList.label.removeClass("selected")
}

View File

@@ -53,8 +53,88 @@
}
return icon;
}
var autoComplete = function(options) {
return function(val) {
var matches = [];
options.forEach(opt => {
let v = opt.value;
var i = v.toLowerCase().indexOf(val.toLowerCase());
if (i > -1) {
var pre = v.substring(0,i);
var matchedVal = v.substring(i,i+val.length);
var post = v.substring(i+val.length)
var el = $('<div/>',{style:"white-space:nowrap; overflow: hidden; flex-grow:1"});
$('<span/>').text(pre).appendTo(el);
$('<span/>',{style:"font-weight: bold"}).text(matchedVal).appendTo(el);
$('<span/>').text(post).appendTo(el);
var element = $('<div>',{style: "display: flex"});
el.appendTo(element);
if (opt.source) {
$('<div>').css({
"font-size": "0.8em"
}).text(opt.source.join(",")).appendTo(element);
}
matches.push({
value: v,
label: element,
i:i
})
}
})
matches.sort(function(A,B){return A.i-B.i})
return matches;
}
}
// This is a hand-generated list of completions for the core nodes (based on the node help html).
var msgCompletions = [
{ value: "payload" },
{ value: "req", source: ["http in"]},
{ value: "req.body", source: ["http in"]},
{ value: "req.headers", source: ["http in"]},
{ value: "req.query", source: ["http in"]},
{ value: "req.params", source: ["http in"]},
{ value: "req.cookies", source: ["http in"]},
{ value: "req.files", source: ["http in"]},
{ value: "complete", source: ["join"] },
{ value: "contentType", source: ["mqtt"] },
{ value: "cookies", source: ["http in","http request"] },
{ value: "correlationData", source: ["mqtt"] },
{ value: "delay", source: ["delay","trigger"] },
{ value: "encoding", source: ["file"] },
{ value: "error", source: ["catch"] },
{ value: "filename", source: ["file","file in"] },
{ value: "flush", source: ["delay"] },
{ value: "followRedirects", source: ["http request"] },
{ value: "headers", source: ["http in"," http request"] },
{ value: "kill", source: ["exec"] },
{ value: "messageExpiryInterval", source: ["mqtt"] },
{ value: "method", source: ["http-request"] },
{ value: "options", source: ["xml"] },
{ value: "parts", source: ["split","join"] },
{ value: "pid", source: ["exec"] },
{ value: "qos", source: ["mqtt"] },
{ value: "rate", source: ["delay"] },
{ value: "rejectUnauthorized", source: ["http request"] },
{ value: "requestTimeout", source: ["http request"] },
{ value: "reset", source: ["delay","trigger","join","rbe"] },
{ value: "responseTopic", source: ["mqtt"] },
{ value: "restartTimeout", source: ["join"] },
{ value: "retain", source: ["mqtt"] },
{ value: "select", source: ["html"] },
{ value: "statusCode", source: ["http in"] },
{ value: "template", source: ["template"] },
{ value: "toFront", source: ["delay"] },
{ value: "topic", source: ["inject","mqtt","rbe"] },
{ value: "url", source: ["http request"] },
{ value: "userProperties", source: ["mqtt"] }
]
var allOptions = {
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression},
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete: autoComplete(msgCompletions)},
flow: {value:"flow",label:"flow.",hasValue:true,
options:[],
validate:RED.utils.validatePropertyExpression,
@@ -265,6 +345,47 @@
}
}
};
// For a type with options, check value is a valid selection
// If !opt.multiple, returns the valid option object
// if opt.multiple, returns an array of valid option objects
// If not valid, returns null;
function isOptionValueValid(opt, currentVal) {
if (!opt.multiple) {
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
if (typeof op === "string" && op === currentVal) {
return {value:currentVal}
} else if (op.value === currentVal) {
return op;
}
}
} else {
// Check to see if value is a valid csv of
// options.
var currentValues = {};
var selected = [];
currentVal.split(",").forEach(function(v) {
if (v) {
currentValues[v] = true;
}
});
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
var val = typeof op === "string" ? op : op.value;
if (currentValues.hasOwnProperty(val)) {
delete currentValues[val];
selected.push(typeof op === "string" ? {value:op} : op.value)
}
}
if (!$.isEmptyObject(currentValues)) {
return null;
}
return selected
}
}
var nlsd = false;
$.widget( "nodered.typedInput", {
@@ -298,7 +419,8 @@
}
nlsd = true;
var that = this;
this.identifier = this.element.attr('id') || "TypedInput-"+Math.floor(Math.random()*100);
if (this.options.debug) { console.log(this.identifier,"Create",{defaultType:this.options.default, value:this.element.val()}) }
this.disarmClick = false;
this.input = $('<input class="red-ui-typedInput-input" type="text"></input>');
this.input.insertAfter(this.element);
@@ -328,6 +450,8 @@
});
this.defaultInputType = this.input.attr('type');
// Used to remember selections per-type to restore them when switching between types
this.oldValues = {};
this.uiSelect.addClass("red-ui-typedInput-container");
@@ -380,6 +504,9 @@
that.element.trigger('paste',evt);
});
this.input.on('keydown', function(evt) {
if (that.typeMap[that.propertyType].autoComplete) {
return
}
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
evt.stopPropagation();
}
@@ -407,9 +534,9 @@
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
RED.popover.tooltip(this.optionSelectLabel,function() {
return that.optionValue;
});
// RED.popover.tooltip(this.optionSelectLabel,function() {
// return that.optionValue;
// });
this.optionSelectTrigger.on("click", function(event) {
event.preventDefault();
event.stopPropagation();
@@ -428,7 +555,9 @@
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton);
this.type(this.options.default||this.typeList[0].value);
this.type(this.typeField.val() || this.options.default||this.typeList[0].value);
this.typeChanged = !!this.options.default;
}catch(err) {
console.log(err.stack);
}
@@ -579,7 +708,7 @@
var height = relativeTo.height();
var menuHeight = menu.height();
var top = (height+pos.top);
if (top+menuHeight > $(window).height()) {
if (top+menuHeight-$(document).scrollTop() > $(window).height()) {
top -= (top+menuHeight)-$(window).height()+5;
}
if (top < 0) {
@@ -676,6 +805,7 @@
var that = this;
var currentType = this.type();
this.typeMap = {};
var firstCall = (this.typeList === undefined);
this.typeList = types.map(function(opt) {
var result;
if (typeof opt === 'string') {
@@ -688,8 +818,10 @@
});
if (this.typeList.length < 2) {
this.selectTrigger.attr("tabindex", -1)
this.selectTrigger.on("mousedown.red-ui-typedInput-focus-block", function(evt) { evt.preventDefault(); })
} else {
this.selectTrigger.attr("tabindex", 0)
this.selectTrigger.off("mousedown.red-ui-typedInput-focus-block")
}
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
this.selectTrigger.find(".fa-caret-down").toggle(this.typeList.length > 1)
@@ -698,10 +830,19 @@
}
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
this.type(this.typeList[0].value);
if (!firstCall) {
this.type(this.typeList[0].value);
}
} else {
this.propertyType = null;
this.type(currentType);
if (!firstCall) {
this.type(currentType);
}
}
if (this.typeList.length === 1 && !this.typeList[0].icon && (!this.typeList[0].label || this.typeList[0].showLabel === false)) {
this.selectTrigger.hide()
} else {
this.selectTrigger.show()
}
},
width: function(desiredWidth) {
@@ -712,7 +853,10 @@
},
value: function(value) {
var that = this;
var opt = this.typeMap[this.propertyType];
// If the default type has been set to an invalid type, then on first
// creation, the current propertyType will not exist. Default to an
// empty object on the assumption the corrent type will be set shortly
var opt = this.typeMap[this.propertyType] || {};
if (!arguments.length) {
var v = this.input.val();
if (opt.export) {
@@ -720,27 +864,38 @@
}
return v;
} else {
if (this.options.debug) { console.log(this.identifier,"----- SET VALUE ------",value) }
var selectedOption = [];
var valueToCheck = value;
if (opt.options) {
var checkValues = [value];
if (opt.hasValue && opt.parse) {
var parts = opt.parse(value);
if (this.options.debug) { console.log(this.identifier,"new parse",parts) }
value = parts.value;
valueToCheck = parts.option || parts.value;
}
var checkValues = [valueToCheck];
if (opt.multiple) {
selectedOption = [];
checkValues = value.split(",");
checkValues = valueToCheck.split(",");
}
checkValues.forEach(function(value) {
checkValues.forEach(function(valueToCheck) {
for (var i=0;i<opt.options.length;i++) {
var op = opt.options[i];
if (typeof op === "string") {
if (op === value || op === ""+value) {
if (op === valueToCheck || op === ""+valueToCheck) {
selectedOption.push(that.activeOptions[op]);
break;
}
} else if (op.value === value) {
} else if (op.value === valueToCheck) {
selectedOption.push(op);
break;
}
}
})
if (this.options.debug) { console.log(this.identifier,"set value to",value) }
this.input.val(value);
if (!opt.multiple) {
if (selectedOption.length === 0) {
@@ -765,9 +920,64 @@
return this.propertyType;
} else {
var that = this;
if (this.options.debug) { console.log(this.identifier,"----- SET TYPE -----",type) }
var previousValue = null;
var opt = this.typeMap[type];
if (opt && this.propertyType !== type) {
// If previousType is !null, then this is a change of the type, rather than the initialisation
var previousType = this.typeMap[this.propertyType];
previousValue = this.input.val();
if (previousType && this.typeChanged) {
if (this.options.debug) { console.log(this.identifier,"typeChanged",{previousType,previousValue}) }
if (previousType.options && opt.hasValue !== true) {
this.oldValues[previousType.value] = previousValue;
} else if (previousType.hasValue === false) {
this.oldValues[previousType.value] = previousValue;
} else {
this.oldValues["_"] = previousValue;
}
if ((opt.options && opt.hasValue !== true) || opt.hasValue === false) {
if (this.oldValues.hasOwnProperty(opt.value)) {
if (this.options.debug) { console.log(this.identifier,"restored previous (1)",this.oldValues[opt.value]) }
this.input.val(this.oldValues[opt.value]);
} else if (opt.options) {
// No old value for the option type.
// It is possible code has called 'value' then 'type'
// to set the selected option. This is what the Inject/Switch/Change
// nodes did before 2.1.
// So we need to be careful to not reset the value if it is a valid option.
var validOptions = isOptionValueValid(opt,previousValue);
if (this.options.debug) { console.log(this.identifier,{previousValue,opt,validOptions}) }
if ((previousValue || previousValue === '') && validOptions) {
if (this.options.debug) { console.log(this.identifier,"restored previous (2)") }
this.input.val(previousValue);
} else {
if (typeof opt.default === "string") {
if (this.options.debug) { console.log(this.identifier,"restored previous (3)",opt.default) }
this.input.val(opt.default);
} else if (Array.isArray(opt.default)) {
if (this.options.debug) { console.log(this.identifier,"restored previous (4)",opt.default.join(",")) }
this.input.val(opt.default.join(","))
} else {
if (this.options.debug) { console.log(this.identifier,"restored previous (5)") }
this.input.val("");
}
}
} else {
if (this.options.debug) { console.log(this.identifier,"restored default/blank",opt.default||"") }
this.input.val(opt.default||"")
}
} else {
if (this.options.debug) { console.log(this.identifier,"restored old/default/blank") }
this.input.val(this.oldValues.hasOwnProperty("_")?this.oldValues["_"]:(opt.default||""))
}
if (previousType.autoComplete) {
this.input.autoComplete("destroy");
}
}
this.propertyType = type;
this.typeChanged = true;
if (this.typeField) {
this.typeField.val(type);
}
@@ -836,22 +1046,12 @@
var op;
if (!opt.hasValue) {
var validValue = false;
var currentVal = this.input.val();
// Check the value is valid for the available options
var validValues = isOptionValueValid(opt,this.input.val());
if (!opt.multiple) {
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
if (typeof op === "string" && op === currentVal) {
that._updateOptionSelectLabel({value:currentVal});
validValue = true;
break;
} else if (op.value === currentVal) {
that._updateOptionSelectLabel(op);
validValue = true;
break;
}
}
if (!validValue) {
if (validValues) {
that._updateOptionSelectLabel(validValues)
} else {
op = opt.options[0];
if (typeof op === "string") {
this.value(op);
@@ -862,27 +1062,19 @@
}
}
} else {
// Check to see if value is a valid csv of
// options.
var currentValues = {};
currentVal.split(",").forEach(function(v) {
if (v) {
currentValues[v] = true;
}
});
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
delete currentValues[op.value||op];
}
if (!$.isEmptyObject(currentValues)) {
// Invalid, set to default/empty
this.value((opt.default||[]).join(","));
if (!validValues) {
validValues = (opt.default || []).map(function(v) {
return typeof v === "string"?v:v.value
});
this.value(validValues.join(","));
}
that._updateOptionSelectLabel(validValues);
}
} else {
var selectedOption = this.optionValue||opt.options[0];
if (opt.parse) {
var parts = opt.parse(this.input.val(),selectedOption);
var selectedOptionObj = typeof selectedOption === "string"?{value:selectedOption}:selectedOption
var parts = opt.parse(this.input.val(),selectedOptionObj);
if (parts.option) {
selectedOption = parts.option;
if (!this.activeOptions.hasOwnProperty(selectedOption)) {
@@ -906,6 +1098,7 @@
this._updateOptionSelectLabel(this.activeOptions[selectedOption]);
}
} else if (selectedOption) {
if (this.options.debug) { console.log(this.identifier,"HERE",{optionValue:selectedOption.value}) }
this.optionValue = selectedOption.value;
this._updateOptionSelectLabel(selectedOption);
} else {
@@ -938,8 +1131,6 @@
this.input.attr('type',this.defaultInputType)
}
if (opt.hasValue === false) {
this.oldValue = this.input.val();
this.input.val("");
this.elementDiv.hide();
this.valueLabelContainer.hide();
} else if (opt.valueLabel) {
@@ -952,12 +1143,13 @@
this.elementDiv.hide();
opt.valueLabel.call(this,this.valueLabelContainer,this.input.val());
} else {
if (this.oldValue !== undefined) {
this.input.val(this.oldValue);
delete this.oldValue;
}
this.valueLabelContainer.hide();
this.elementDiv.show();
if (opt.autoComplete) {
this.input.autoComplete({
search: opt.autoComplete
})
}
}
if (this.optionExpandButton) {
if (opt.expand) {
@@ -1042,6 +1234,9 @@
},
disabled: function() {
return this.uiSelect.attr("disabled") === "disabled";
},
focus: function() {
this.input.focus();
}
});
})(jQuery);

View File

@@ -319,192 +319,208 @@ RED.deploy = (function() {
},delta);
});
}
function save(skipValidation,force) {
if (!$("#red-ui-header-button-deploy").hasClass("disabled")) {
if (!RED.user.hasPermission("flows.write")) {
RED.notify(RED._("user.errors.deploy"),"error");
function save(skipValidation, force) {
if ($("#red-ui-header-button-deploy").hasClass("disabled")) {
return; //deploy is disabled
}
if ($("#red-ui-header-shade").is(":visible")) {
return; //deploy is shaded
}
if (!RED.user.hasPermission("flows.write")) {
RED.notify(RED._("user.errors.deploy"), "error");
return;
}
let hasUnusedConfig = false;
if (!skipValidation) {
let hasUnknown = false;
let hasInvalid = false;
const unknownNodes = [];
const invalidNodes = [];
RED.nodes.eachConfig(function (node) {
if (node.valid === undefined) {
RED.editor.validateNode(node);
}
if (!node.valid && !node.d) {
invalidNodes.push(getNodeInfo(node));
}
if (node.type === "unknown") {
if (unknownNodes.indexOf(node.name) == -1) {
unknownNodes.push(node.name);
}
}
});
RED.nodes.eachNode(function (node) {
if (!node.valid && !node.d) {
invalidNodes.push(getNodeInfo(node));
}
if (node.type === "unknown") {
if (unknownNodes.indexOf(node.name) == -1) {
unknownNodes.push(node.name);
}
}
});
hasUnknown = unknownNodes.length > 0;
hasInvalid = invalidNodes.length > 0;
const unusedConfigNodes = [];
RED.nodes.eachConfig(function (node) {
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
unusedConfigNodes.push(getNodeInfo(node));
hasUnusedConfig = true;
}
});
let showWarning = false;
let notificationMessage;
let notificationButtons = [];
let notification;
if (hasUnknown && !ignoreDeployWarnings.unknown) {
showWarning = true;
notificationMessage = "<p>" + RED._('deploy.confirm.unknown') + "</p>" +
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(unknownNodes).map(function (n) { return sanitize(n) }).join("</li><li>") + "</li></ul><p>" +
RED._('deploy.confirm.confirm') +
"</p>";
notificationButtons = [
{
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
text: RED._("deploy.confirm.button.confirm"),
class: "primary",
click: function () {
save(true);
notification.close();
}
}
];
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
showWarning = true;
invalidNodes.sort(sortNodeInfo);
notificationMessage = "<p>" + RED._('deploy.confirm.improperlyConfigured') + "</p>" +
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(invalidNodes.map(function (A) { return sanitize((A.tab ? "[" + A.tab + "] " : "") + A.label + " (" + A.type + ")") })).join("</li><li>") + "</li></ul><p>" +
RED._('deploy.confirm.confirm') +
"</p>";
notificationButtons = [
{
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
text: RED._("deploy.confirm.button.confirm"),
class: "primary",
click: function () {
save(true);
notification.close();
}
}
];
}
if (showWarning) {
notificationButtons.unshift(
{
text: RED._("common.label.cancel"),
click: function () {
notification.close();
}
}
);
notification = RED.notify(notificationMessage, {
modal: true,
fixed: true,
buttons: notificationButtons
});
return;
}
if (!skipValidation) {
var hasUnknown = false;
var hasInvalid = false;
var hasUnusedConfig = false;
var unknownNodes = [];
var invalidNodes = [];
RED.nodes.eachNode(function(node) {
if (!node.valid && !node.d) {
invalidNodes.push(getNodeInfo(node));
}
if (node.type === "unknown") {
if (unknownNodes.indexOf(node.name) == -1) {
unknownNodes.push(node.name);
}
}
});
hasUnknown = unknownNodes.length > 0;
hasInvalid = invalidNodes.length > 0;
var unusedConfigNodes = [];
RED.nodes.eachConfig(function(node) {
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
unusedConfigNodes.push(getNodeInfo(node));
hasUnusedConfig = true;
}
});
var showWarning = false;
var notificationMessage;
var notificationButtons = [];
var notification;
if (hasUnknown && !ignoreDeployWarnings.unknown) {
showWarning = true;
notificationMessage = "<p>"+RED._('deploy.confirm.unknown')+"</p>"+
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(unknownNodes).map(function(n) { return sanitize(n) }).join("</li><li>")+"</li></ul><p>"+
RED._('deploy.confirm.confirm')+
"</p>";
notificationButtons= [
{
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
text: RED._("deploy.confirm.button.confirm"),
class: "primary",
click: function() {
save(true);
notification.close();
}
}
];
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
showWarning = true;
invalidNodes.sort(sortNodeInfo);
notificationMessage = "<p>"+RED._('deploy.confirm.improperlyConfigured')+"</p>"+
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(invalidNodes.map(function(A) { return sanitize( (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")")})).join("</li><li>")+"</li></ul><p>"+
RED._('deploy.confirm.confirm')+
"</p>";
notificationButtons= [
{
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
text: RED._("deploy.confirm.button.confirm"),
class: "primary",
click: function() {
save(true);
notification.close();
}
}
];
}
if (showWarning) {
notificationButtons.unshift(
{
text: RED._("common.label.cancel"),
click: function() {
notification.close();
}
}
);
notification = RED.notify(notificationMessage,{
modal: true,
fixed: true,
buttons:notificationButtons
});
return;
}
}
var nns = RED.nodes.createCompleteNodeSet();
var startTime = Date.now();
$(".red-ui-deploy-button-content").css('opacity',0);
$(".red-ui-deploy-button-spinner").show();
$("#red-ui-header-button-deploy").addClass("disabled");
var data = {flows:nns};
if (!force) {
data.rev = RED.nodes.version();
}
deployInflight = true;
$("#red-ui-header-shade").show();
$("#red-ui-editor-shade").show();
$("#red-ui-palette-shade").show();
$("#red-ui-sidebar-shade").show();
$.ajax({
url:"flows",
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
headers: {
"Node-RED-Deployment-Type":deploymentType
}
}).done(function(data,textStatus,xhr) {
RED.nodes.dirty(false);
RED.nodes.version(data.rev);
RED.nodes.originalFlow(nns);
if (hasUnusedConfig) {
RED.notify(
'<p>'+RED._("deploy.successfulDeploy")+'</p>'+
'<p>'+RED._("deploy.unusedConfigNodes")+' <a href="#" onclick="RED.sidebar.config.show(true); return false;">'+RED._("deploy.unusedConfigNodesLink")+'</a></p>',"success",false,6000);
} else {
RED.notify('<p>'+RED._("deploy.successfulDeploy")+'</p>',"success");
}
RED.nodes.eachNode(function(node) {
if (node.changed) {
node.dirty = true;
node.changed = false;
}
if (node.moved) {
node.dirty = true;
node.moved = false;
}
if(node.credentials) {
delete node.credentials;
}
});
RED.nodes.eachConfig(function (confNode) {
confNode.changed = false;
if (confNode.credentials) {
delete confNode.credentials;
}
});
RED.nodes.eachSubflow(function(subflow) {
subflow.changed = false;
});
RED.nodes.eachWorkspace(function(ws) {
ws.changed = false;
});
// Once deployed, cannot undo back to a clean state
RED.history.markAllDirty();
RED.view.redraw();
RED.events.emit("deploy");
}).fail(function(xhr,textStatus,err) {
RED.nodes.dirty(true);
$("#red-ui-header-button-deploy").removeClass("disabled");
if (xhr.status === 401) {
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
} else if (xhr.status === 409) {
resolveConflict(nns, true);
} else if (xhr.responseText) {
RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
} else {
RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
}
}).always(function() {
deployInflight = false;
var delta = Math.max(0,300-(Date.now()-startTime));
setTimeout(function() {
$(".red-ui-deploy-button-content").css('opacity',1);
$(".red-ui-deploy-button-spinner").hide();
$("#red-ui-header-shade").hide();
$("#red-ui-editor-shade").hide();
$("#red-ui-palette-shade").hide();
$("#red-ui-sidebar-shade").hide();
},delta);
});
}
const nns = RED.nodes.createCompleteNodeSet();
const startTime = Date.now();
$(".red-ui-deploy-button-content").css('opacity', 0);
$(".red-ui-deploy-button-spinner").show();
$("#red-ui-header-button-deploy").addClass("disabled");
const data = { flows: nns };
if (!force) {
data.rev = RED.nodes.version();
}
deployInflight = true;
$("#red-ui-header-shade").show();
$("#red-ui-editor-shade").show();
$("#red-ui-palette-shade").show();
$("#red-ui-sidebar-shade").show();
$.ajax({
url: "flows",
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
headers: {
"Node-RED-Deployment-Type": deploymentType
}
}).done(function (data, textStatus, xhr) {
RED.nodes.dirty(false);
RED.nodes.version(data.rev);
RED.nodes.originalFlow(nns);
if (hasUnusedConfig) {
RED.notify(
'<p>' + RED._("deploy.successfulDeploy") + '</p>' +
'<p>' + RED._("deploy.unusedConfigNodes") + ' <a href="#" onclick="RED.sidebar.config.show(true); return false;">' + RED._("deploy.unusedConfigNodesLink") + '</a></p>', "success", false, 6000);
} else {
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
}
RED.nodes.eachNode(function (node) {
if (node.changed) {
node.dirty = true;
node.changed = false;
}
if (node.moved) {
node.dirty = true;
node.moved = false;
}
if (node.credentials) {
delete node.credentials;
}
});
RED.nodes.eachConfig(function (confNode) {
confNode.changed = false;
if (confNode.credentials) {
delete confNode.credentials;
}
});
RED.nodes.eachSubflow(function (subflow) {
subflow.changed = false;
});
RED.nodes.eachWorkspace(function (ws) {
ws.changed = false;
});
// Once deployed, cannot undo back to a clean state
RED.history.markAllDirty();
RED.view.redraw();
RED.events.emit("deploy");
}).fail(function (xhr, textStatus, err) {
RED.nodes.dirty(true);
$("#red-ui-header-button-deploy").removeClass("disabled");
if (xhr.status === 401) {
RED.notify(RED._("deploy.deployFailed", { message: RED._("user.notAuthorized") }), "error");
} else if (xhr.status === 409) {
resolveConflict(nns, true);
} else if (xhr.responseText) {
RED.notify(RED._("deploy.deployFailed", { message: xhr.responseText }), "error");
} else {
RED.notify(RED._("deploy.deployFailed", { message: RED._("deploy.errors.noResponse") }), "error");
}
}).always(function () {
deployInflight = false;
const delta = Math.max(0, 300 - (Date.now() - startTime));
setTimeout(function () {
$(".red-ui-deploy-button-content").css('opacity', 1);
$(".red-ui-deploy-button-spinner").hide();
$("#red-ui-header-shade").hide();
$("#red-ui-editor-shade").hide();
$("#red-ui-palette-shade").hide();
$("#red-ui-sidebar-shade").hide();
}, delta);
});
}
return {
init: init,

View File

@@ -554,6 +554,8 @@ RED.diff = (function() {
color: "#DDAA99",
defaults:{name:{value:""}}
}
} else if (node.type === "group") {
def = RED.group.def;
} else {
def = {};
}
@@ -763,16 +765,15 @@ RED.diff = (function() {
}
}
if (node.hasOwnProperty('x')) {
if (localNode) {
if (localNode.x !== node.x || localNode.y !== node.y) {
if (localNode.x !== node.x || localNode.y !== node.y || localNode.w !== node.w || localNode.h !== node.h ) {
localChanged = true;
localChanges++;
}
}
if (remoteNode) {
if (remoteNode.x !== node.x || remoteNode.y !== node.y) {
if (remoteNode.x !== node.x || remoteNode.y !== node.y|| remoteNode.w !== node.w || remoteNode.h !== node.h) {
remoteChanged = true;
remoteChanges++;
}
@@ -790,7 +791,12 @@ RED.diff = (function() {
localCell.addClass("red-ui-diff-status-"+(localChanged?"changed":"unchanged"));
$('<span class="red-ui-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(localCell);
propertyElements['local.position'] = RED.utils.createObjectElement({x:localNode.x,y:localNode.y},
var localPosition = {x:localNode.x,y:localNode.y};
if (localNode.hasOwnProperty('w')) {
localPosition.w = localNode.w;
localPosition.h = localNode.h;
}
propertyElements['local.position'] = RED.utils.createObjectElement(localPosition,
{
path: "position",
exposeApi: true,
@@ -811,7 +817,12 @@ RED.diff = (function() {
if (remoteNode) {
$('<span class="red-ui-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(remoteCell);
propertyElements['remote.position'] = RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y},
var remotePosition = {x:remoteNode.x,y:remoteNode.y};
if (remoteNode.hasOwnProperty('w')) {
remotePosition.w = remoteNode.w;
remotePosition.h = remoteNode.h;
}
propertyElements['remote.position'] = RED.utils.createObjectElement(remotePosition,
{
path: "position",
exposeApi: true,
@@ -883,11 +894,11 @@ RED.diff = (function() {
}
}
}
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='w'&&p!=='h'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
if (def.defaults) {
properties = properties.concat(Object.keys(def.defaults));
}
if (node.type !== 'tab') {
if (node.type !== 'tab' && node.type !== "group") {
properties = properties.concat(['inputLabels','outputLabels']);
}
if ( ((localNode && localNode.hasOwnProperty('icon')) || (remoteNode && remoteNode.hasOwnProperty('icon'))) &&
@@ -1376,6 +1387,7 @@ RED.diff = (function() {
function mergeDiff(diff) {
//console.log(diff);
var selectedTab = RED.workspaces.active();
var appliedDiff = applyDiff(diff);
var newConfig = appliedDiff.config;
@@ -1426,6 +1438,7 @@ RED.diff = (function() {
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.workspaces.show(selectedTab, true);
RED.sidebar.config.refresh();
}

File diff suppressed because it is too large Load Diff

View File

@@ -54,6 +54,7 @@ RED.editor.codeEditor.monaco = (function() {
var initialised = false;
const type = "monaco";
const monacoThemes = ["vs","vs-dark","hc-black"]; //TODO: consider setting hc-black autmatically based on acessability?
let userSelectedTheme;
//TODO: get from externalModules.js For now this is enough for feature parity with ACE (and then some).
const knownModules = {
@@ -181,19 +182,35 @@ RED.editor.codeEditor.monaco = (function() {
var editorSettings = RED.editor.codeEditor.settings || {};
var editorOptions = editorSettings.options || {};
if (editorOptions.theme) {
if (!monacoThemes.includes(editorOptions.theme)) {
var customTheme = 'vendor/monaco/dist/theme/' + editorOptions.theme + '.json';
$.get(customTheme, function (theme) {
monacoThemes.push(editorOptions.theme);//add to list of loaded themes
if ((theme.rules && Array.isArray(theme.rules)) || theme.colors) {
monaco.editor.defineTheme(editorOptions.theme, theme);
monaco.editor.setTheme(editorOptions.theme);
//if editorOptions.theme is an object (set in theme.js context()), use the plugin theme name as the monaco theme name
//if editorOptions.theme is a string, it should be the name of a pre-set theme, load that
try {
const addTheme = function (themeThemeName, theme) {
if ((theme.rules && Array.isArray(theme.rules)) || theme.colors) {
monacoThemes.push(themeThemeName); //add to list of loaded themes
monaco.editor.defineTheme(themeThemeName, theme);
monaco.editor.setTheme(themeThemeName);
userSelectedTheme = themeThemeName;
}
};
if (editorOptions.theme) {
if (typeof editorOptions.theme == "object" && RED.settings.editorTheme.theme) {
let themeThemeName = editorOptions.theme.name || RED.settings.editorTheme.theme;
addTheme(themeThemeName, editorOptions.theme);
} else if (typeof editorOptions.theme == "string") {
let themeThemeName = editorOptions.theme;
if (!monacoThemes.includes(themeThemeName)) {
$.get('vendor/monaco/dist/theme/' + themeThemeName + '.json', function (theme) {
addTheme(themeThemeName, theme);
});
}
});
}
}
} catch (error) {
console.warn(error);
}
//Helper function to simplify snippet setup
function createMonacoCompletionItem(label, insertText, documentation, range, kind) {
if (Array.isArray(documentation)) { documentation = documentation.join("\n"); }
@@ -560,7 +577,7 @@ RED.editor.codeEditor.monaco = (function() {
createMonacoCompletionItem("set (flow context)", 'flow.set("${1:name}", ${1:value});','Set a value in flow context',range),
createMonacoCompletionItem("get (global context)", 'global.get("${1:name}");','Get a value from global context',range),
createMonacoCompletionItem("set (global context)", 'global.set("${1:name}", ${1:value});','Set a value in global context',range),
createMonacoCompletionItem("get (env)", 'env.get("${1:name}");','Get env variable value',range),
createMonacoCompletionItem("get (env)", 'env.get("${1|NR_NODE_ID,NR_NODE_NAME,NR_NODE_PATH,NR_GROUP_ID,NR_GROUP_NAME,NR_FLOW_ID,NR_FLOW_NAME|}");','Get env variable value',range),
createMonacoCompletionItem("cloneMessage (RED.util)", 'RED.util.cloneMessage(${1:msg});',
["```typescript",
"RED.util.cloneMessage<T extends registry.NodeMessage>(msg: T): T",
@@ -653,6 +670,8 @@ RED.editor.codeEditor.monaco = (function() {
noSyntaxValidation: false,
diagnosticCodesToIgnore: [
1108, //return not inside function
1375, //'await' expressions are only allowed at the top level of a file when that file is a module
1378, //Top-level 'await' expressions are only allowed when the 'module' option is set to 'esnext' or 'system', and the 'target' option is set to 'es2017' or higher
//2304, //Cannot find name - this one is heavy handed and prevents user seeing stupid errors. Would provide better ACE feature parity (i.e. no need for declaration of vars) but misses lots of errors. Lets be bold & leave it out!
2307, //Cannot find module 'xxx' or its corresponding type declarations
2322, //Type 'unknown' is not assignable to type 'string'
@@ -742,6 +761,10 @@ RED.editor.codeEditor.monaco = (function() {
var editorOptions = $.extend({}, editorSettings.options, options);
editorOptions.language = convertAceModeToMonacoLang(options.mode);
if(userSelectedTheme) {
editorOptions.theme = userSelectedTheme;//use user selected theme for this session
}
//by default, set javascript editors to text mode.
//when element becomes visible, it will be (re) set to javascript mode
//this is to ensure multiple editors sharing the model dont present its
@@ -1167,7 +1190,10 @@ RED.editor.codeEditor.monaco = (function() {
return { row: p.lineNumber-1, column: p.column-1 };
}
ed.setTheme = monaco.editor.setTheme;
ed.setTheme = function(theme) {
monaco.editor.setTheme(theme);
userSelectedTheme = theme;//remember users choice for this session
}
ed.on = function (name, cb) {
switch (name) {

View File

@@ -1,4 +1,4 @@
RED.colorPicker = (function() {
RED.editor.colorPicker = RED.colorPicker = (function() {
function create(options) {
var color = options.value;

View File

@@ -0,0 +1,625 @@
RED.editor.envVarList = (function() {
var currentLocale = 'en-US';
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
/**
* Create env var edit interface
* @param container - container
* @param node - subflow node
*/
function buildPropertiesList(envContainer, node) {
var isTemplateNode = (node.type === "subflow");
envContainer
.css({
'min-height':'150px',
'min-width':'450px'
})
.editableList({
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
addItem: function(container, i, opt) {
// If this is an instance node, these are properties unique to
// this instance - ie opt.parent will not be defined.
if (isTemplateNode) {
container.addClass("red-ui-editor-subflow-env-editable")
}
var envRow = $('<div/>').appendTo(container);
var nameField = null;
var valueField = null;
nameField = $('<input/>', {
class: "node-input-env-name",
type: "text",
placeholder: RED._("common.label.name")
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
valueField = $('<input/>',{
style: "width:100%",
class: "node-input-env-value",
type: "text",
}).attr("autocomplete","disable").appendTo(envRow);
var types = (opt.ui && opt.ui.opts && opt.ui.opts.types);
if (!types) {
types = isTemplateNode ? DEFAULT_ENV_TYPE_LIST : DEFAULT_ENV_TYPE_LIST_INC_CRED;
}
valueField.typedInput({default:'str',types:types});
valueField.typedInput('type', opt.type);
if (opt.type === "cred") {
if (opt.value) {
valueField.typedInput('value', opt.value);
} else if (node.credentials && node.credentials[opt.name]) {
valueField.typedInput('value', node.credentials[opt.name]);
} else if (node.credentials && node.credentials['has_'+opt.name]) {
valueField.typedInput('value', "__PWRD__");
} else {
valueField.typedInput('value', "");
}
} else {
valueField.typedInput('value', opt.value);
}
opt.nameField = nameField;
opt.valueField = valueField;
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
actionButton.on("click", function(evt) {
evt.preventDefault();
removeTip.close();
container.parent().addClass("red-ui-editableList-item-deleting")
container.fadeOut(300, function() {
envContainer.editableList('removeItem',opt);
});
});
if (isTemplateNode) {
// Add the UI customisation row
// if `opt.ui` does not exist, then apply defaults. If these
// defaults do not change then they will get stripped off
// before saving.
if (opt.type === 'cred') {
opt.ui = opt.ui || {
icon: "",
type: "cred"
}
opt.ui.type = "cred";
} else {
opt.ui = opt.ui || {
icon: "",
type: "input",
opts: {types:DEFAULT_ENV_TYPE_LIST}
}
}
opt.ui.label = opt.ui.label || {};
opt.ui.type = opt.ui.type || "input";
if ((opt.ui.type === "cred") &&
opt.ui.opts &&
opt.ui.opts.types) {
opt.ui.type = "input";
}
var uiRow = $('<div/>').appendTo(container).hide();
// save current info for reverting on cancel
// var copy = $.extend(true, {}, ui);
$('<a href="#"><i class="fa fa-angle-right"></a>').prependTo(envRow).on("click", function (evt) {
evt.preventDefault();
if ($(this).hasClass('expanded')) {
uiRow.slideUp();
$(this).removeClass('expanded');
} else {
uiRow.slideDown();
$(this).addClass('expanded');
}
});
buildEnvEditRow(uiRow, opt.ui, nameField, valueField);
nameField.trigger('change');
}
},
sortable: ".red-ui-editableList-item-handle",
removable: false
});
var parentEnv = {};
var envList = [];
if (/^subflow:/.test(node.type)) {
var subflowDef = RED.nodes.subflow(node.type.substring(8));
if (subflowDef.env) {
subflowDef.env.forEach(function(env) {
var item = {
name:env.name,
parent: {
type: env.type,
value: env.value,
ui: env.ui
}
}
envList.push(item);
parentEnv[env.name] = item;
})
}
}
if (node.env) {
for (var i = 0; i < node.env.length; i++) {
var env = node.env[i];
if (parentEnv.hasOwnProperty(env.name)) {
parentEnv[env.name].type = env.type;
parentEnv[env.name].value = env.value;
} else {
envList.push({
name: env.name,
type: env.type,
value: env.value,
ui: env.ui
});
}
}
}
envList.forEach(function(env) {
if (env.parent && env.parent.ui && env.parent.ui.type === 'hide') {
return;
}
if (!isTemplateNode && env.parent) {
return;
}
envContainer.editableList('addItem', JSON.parse(JSON.stringify(env)));
});
}
/**
* Create UI edit interface for environment variable
* @param container - container
* @param env - env var definition
* @param nameField - name field of env var
* @param valueField - value field of env var
*/
function buildEnvEditRow(container, ui, nameField, valueField) {
container.addClass("red-ui-editor-subflow-env-ui-row")
var topRow = $('<div></div>').appendTo(container);
$('<div></div>').appendTo(topRow);
$('<div>').text(RED._("editor.icon")).appendTo(topRow);
$('<div>').text(RED._("editor.label")).appendTo(topRow);
$('<div>').text(RED._("editor.inputType")).appendTo(topRow);
var row = $('<div></div>').appendTo(container);
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
var typeOptions = {
'input': {types:DEFAULT_ENV_TYPE_LIST},
'select': {opts:[]},
'spinner': {},
'cred': {}
};
if (ui.opts) {
typeOptions[ui.type] = ui.opts;
} else {
// Pick up the default values if not otherwise provided
ui.opts = typeOptions[ui.type];
}
var iconCell = $('<div></div>').appendTo(row);
var iconButton = $('<a href="#"></a>').appendTo(iconCell);
iconButton.on("click", function(evt) {
evt.preventDefault();
var icon = ui.icon || "";
var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
RED.editor.iconPicker.show(iconButton, null, iconPath, true, function (newIcon) {
iconButton.empty();
var path = newIcon || "";
var newPath = RED.utils.separateIconPath(path);
if (newPath) {
$('<i class="fa"></i>').addClass(newPath.file).appendTo(iconButton);
}
ui.icon = path;
});
})
if (ui.icon) {
var newPath = RED.utils.separateIconPath(ui.icon);
$('<i class="fa '+newPath.file+'"></i>').appendTo(iconButton);
}
var labelCell = $('<div></div>').appendTo(row);
var label = ui.label && ui.label[currentLocale] || "";
var labelInput = $('<input type="text">').val(label).appendTo(labelCell);
ui.labelField = labelInput;
labelInput.on('change', function(evt) {
ui.label = ui.label || {};
var val = $(this).val().trim();
if (val === "") {
delete ui.label[currentLocale];
} else {
ui.label[currentLocale] = val;
}
})
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelCell);
RED.popover.tooltip(labelIcon,function() {
var langs = Object.keys(ui.label);
var content = $("<div>");
if (langs.indexOf(currentLocale) === -1) {
langs.push(currentLocale);
langs.sort();
}
langs.forEach(function(l) {
var row = $('<div>').appendTo(content);
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
$('<span>').text(ui.label[l]||"").appendTo(row);
});
return content;
})
nameField.on('change',function(evt) {
labelInput.attr("placeholder",$(this).val())
});
var inputCell = $('<div></div>').appendTo(row);
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
if (ui.type === "input") {
inputCellInput.val(ui.opts.types.join(","));
}
var checkbox;
var selectBox;
inputCellInput.typedInput({
types: [
{
value:"input",
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"},
{value: "cred",label: RED._("editor.types.cred"),icon: "fa fa-lock"}
],
default: DEFAULT_ENV_TYPE_LIST,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
if (value.length) {
value.forEach(function(v) {
if (!/^fa /.test(v.icon)) {
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
} else {
var s = $('<span>',{style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
$("<i>",{class: v.icon}).appendTo(s);
}
})
} else {
$('<span class="red-ui-editor-subflow-env-input-type-placeholder"></span>').text(RED._("editor.selectType")).appendTo(input);
}
}
},
{
value: "cred",
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type">').css({
"border-top-right-radius": "4px",
"border-bottom-right-radius": "4px"
}).appendTo(container);
$('<div class="placeholder-input">').html("&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;").appendTo(innerContainer);
}
},
{
value:"select",
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
valueLabel: function(container,value) {
container.css("padding","0");
selectBox = $('<select></select>').appendTo(container);
if (ui.opts && Array.isArray(ui.opts.opts)) {
ui.opts.opts.forEach(function(o) {
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
$('<option>').val(o.v).text(label).appendTo(selectBox);
})
}
selectBox.on('change', function(evt) {
var v = selectBox.val();
// var parts = v.split(":");
// var t = parts.shift();
// v = parts.join(":");
//
// valueField.typedInput("type",'str')
valueField.typedInput("value",v)
});
selectBox.val(valueField.typedInput("value"));
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
},
expand: {
icon: "fa-caret-down",
minWidth: 400,
content: function(container) {
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
var optList = $('<ol>').appendTo(content).editableList({
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
addItem: function(row,index,itemData) {
var labelDiv = $('<div>').appendTo(row);
var label = lookupLabel(itemData.l, "", currentLocale);
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
itemData.label.on('keydown', function(evt) {
if (evt.keyCode === 13) {
itemData.input.focus();
evt.preventDefault();
}
});
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
RED.popover.tooltip(labelIcon,function() {
return currentLocale;
})
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
// Problem using a TI here:
// - this is in a popout panel
// - clicking the expand button in the TI will close the parent edit tray
// and open the type editor.
// - but it leaves the popout panel over the top.
// - there is no way to get back to the popout panel after closing the type editor
//.typedInput({default:itemData.t||'str', types:DEFAULT_ENV_TYPE_LIST});
itemData.input.on('keydown', function(evt) {
if (evt.keyCode === 13) {
// Enter or Tab
var index = optList.editableList('indexOf',itemData);
var length = optList.editableList('length');
if (index + 1 === length) {
var newItem = {};
optList.editableList('addItem',newItem);
setTimeout(function() {
if (newItem.label) {
newItem.label.focus();
}
},100)
} else {
var nextItem = optList.editableList('getItemAt',index+1);
if (nextItem.label) {
nextItem.label.focus()
}
}
evt.preventDefault();
}
});
},
sortable: true,
removable: true,
height: 160
})
if (ui.opts.opts.length > 0) {
ui.opts.opts.forEach(function(o) {
optList.editableList('addItem',$.extend(true,{},o))
})
} else {
optList.editableList('addItem',{})
}
return {
onclose: function() {
var items = optList.editableList('items');
var vals = [];
items.each(function (i,el) {
var data = el.data('data');
var l = data.label.val().trim();
var v = data.input.val();
// var t = data.input.typedInput('type');
// var v = data.input.typedInput('value');
if (l.length > 0) {
data.l = data.l || {};
data.l[currentLocale] = l;
}
data.v = v;
if (l.length > 0 || v.length > 0) {
var val = {l:data.l,v:data.v};
// if (t !== 'str') {
// val.t = t;
// }
vals.push(val);
}
});
ui.opts.opts = vals;
inputCellInput.typedInput('value',Date.now())
}
}
}
}
},
{
value:"checkbox",
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
valueLabel: function(container,value) {
container.css("padding",0);
checkbox = $('<input type="checkbox">').appendTo(container);
checkbox.on('change', function(evt) {
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
})
checkbox.prop('checked',valueField.typedInput('value')==="true");
}
},
{
value:"spinner",
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
var min = ui.opts && ui.opts.min;
var max = ui.opts && ui.opts.max;
var label = "";
if (min !== undefined && max !== undefined) {
label = Math.min(min,max)+" - "+Math.max(min,max);
} else if (min !== undefined) {
label = "> "+min;
} else if (max !== undefined) {
label = "< "+max;
}
$('<span>').css("margin-left","15px").text(label).appendTo(input);
},
expand: {
icon: "fa-caret-down",
content: function(container) {
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
content.css("padding","8px 5px")
var min = ui.opts.min;
var max = ui.opts.max;
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
minInput.val(min);
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
maxInput.val(max);
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
return {
onclose: function() {
var min = minInput.val().trim();
var max = maxInput.val().trim();
if (min !== "") {
ui.opts.min = parseInt(min);
} else {
delete ui.opts.min;
}
if (max !== "") {
ui.opts.max = parseInt(max);
} else {
delete ui.opts.max;
}
inputCellInput.typedInput('value',Date.now())
}
}
}
}
},
{
value:"none",
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
},
{
value:"hide",
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
}
],
default: 'none'
}).on("typedinputtypechange", function(evt,type) {
ui.type = $(this).typedInput("type");
ui.opts = typeOptions[ui.type];
if (ui.type === 'input') {
// In the case of 'input' type, the typedInput uses the multiple-option
// mode. Its value needs to be set to a comma-separately list of the
// selected options.
inputCellInput.typedInput('value',ui.opts.types.join(","))
} else {
// No other type cares about `value`, but doing this will
// force a refresh of the label now that `ui.opts` has
// been updated.
inputCellInput.typedInput('value',Date.now())
}
switch (ui.type) {
case 'input':
valueField.typedInput('types',ui.opts.types);
break;
case 'select':
valueField.typedInput('types',['str']);
break;
case 'checkbox':
valueField.typedInput('types',['bool']);
break;
case 'spinner':
valueField.typedInput('types',['num']);
break;
case 'cred':
valueField.typedInput('types',['cred']);
break;
default:
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
}
if (ui.type === 'checkbox') {
valueField.typedInput('type','bool');
} else if (ui.type === 'spinner') {
valueField.typedInput('type','num');
}
if (ui.type !== 'checkbox') {
checkbox = null;
}
}).on("change", function(evt,type) {
if (ui.type === 'input') {
var types = inputCellInput.typedInput('value');
ui.opts.types = (types === "") ? ["str"] : types.split(",");
valueField.typedInput('types',ui.opts.types);
}
});
valueField.on("change", function(evt) {
if (checkbox) {
checkbox.prop('checked',$(this).typedInput('value')==="true")
}
})
// Set the input to the right type. This will trigger the 'typedinputtypechange'
// event handler (just above ^^) to update the value if needed
inputCellInput.typedInput('type',ui.type)
}
function setLocale(l, list) {
currentLocale = l;
if (list) {
var items = list.editableList("items");
items.each(function (i, item) {
var entry = $(this).data('data');
var labelField = entry.ui.labelField;
labelField.val(lookupLabel(entry.ui.label, "", currentLocale));
if (labelField.timeout) {
clearTimeout(labelField.timeout);
delete labelField.timeout;
}
labelField.addClass("input-updated");
labelField.timeout = setTimeout(function() {
delete labelField.timeout
labelField.removeClass("input-updated");
},3000);
});
}
}
/**
* Lookup text for specific locale
* @param labels - dict of labels
* @param defaultLabel - fallback label if not found
* @param locale - target locale
* @returns {string} text for specified locale
*/
function lookupLabel(labels, defaultLabel, locale) {
if (labels) {
if (labels[locale]) {
return labels[locale];
}
if (locale) {
var lang = locale.substring(0, 2);
if (labels[lang]) {
return labels[lang];
}
}
}
return defaultLabel;
}
return {
create: buildPropertiesList,
setLocale: setLocale,
lookupLabel: lookupLabel,
DEFAULT_ENV_TYPE_LIST: DEFAULT_ENV_TYPE_LIST,
DEFAULT_ENV_TYPE_LIST_INC_CRED: DEFAULT_ENV_TYPE_LIST_INC_CRED
}
})();

View File

@@ -247,7 +247,7 @@
var currentExpression = expressionEditor.getValue();
var expr;
var usesContext = false;
var legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
var legacyMode = /(^|[^a-zA-Z0-9_'".])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
$(".red-ui-editor-type-expression-legacy").toggle(legacyMode);
try {
expr = jsonata(currentExpression);

View File

@@ -0,0 +1,99 @@
RED.editor.iconPicker = (function() {
function showIconPicker(container, backgroundColor, iconPath, faOnly, done) {
var picker = $('<div class="red-ui-icon-picker">');
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(picker);
searchInput = $('<input type="text">').attr("placeholder",RED._("editor.searchIcons")).appendTo(searchDiv).searchBox({
delay: 50,
change: function() {
var searchTerm = $(this).val().trim();
if (searchTerm === "") {
iconList.find(".red-ui-icon-list-module").show();
iconList.find(".red-ui-icon-list-icon").show();
} else {
iconList.find(".red-ui-icon-list-module").hide();
iconList.find(".red-ui-icon-list-icon").each(function(i,n) {
if ($(n).data('icon').indexOf(searchTerm) === -1) {
$(n).hide();
} else {
$(n).show();
}
});
}
}
});
var row = $('<div>').appendTo(picker);
var iconList = $('<div class="red-ui-icon-list">').appendTo(picker);
var metaRow = $('<div class="red-ui-icon-meta"></div>').appendTo(picker);
var summary = $('<span>').appendTo(metaRow);
var resetButton = $('<button type="button" class="red-ui-button red-ui-button-small">'+RED._("editor.useDefault")+'</button>').appendTo(metaRow).on("click", function(e) {
e.preventDefault();
iconPanel.hide();
done(null);
});
if (!backgroundColor && faOnly) {
iconList.addClass("red-ui-icon-list-dark");
}
setTimeout(function() {
var iconSets = RED.nodes.getIconSets();
Object.keys(iconSets).forEach(function(moduleName) {
if (faOnly && (moduleName !== "font-awesome")) {
return;
}
var icons = iconSets[moduleName];
if (icons.length > 0) {
// selectIconModule.append($("<option></option>").val(moduleName).text(moduleName));
var header = $('<div class="red-ui-icon-list-module"></div>').text(moduleName).appendTo(iconList);
$('<i class="fa fa-cube"></i>').prependTo(header);
icons.forEach(function(icon) {
var iconDiv = $('<div>',{class:"red-ui-icon-list-icon"}).appendTo(iconList);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconDiv);
var icon_url = RED.settings.apiRootUrl+"icons/"+moduleName+"/"+icon;
iconDiv.data('icon',icon_url);
if (backgroundColor) {
nodeDiv.css({
'backgroundColor': backgroundColor
});
var borderColor = RED.utils.getDarkerColor(backgroundColor);
if (borderColor !== backgroundColor) {
nodeDiv.css('border-color',borderColor)
}
}
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
if (iconPath.module === moduleName && iconPath.file === icon) {
iconDiv.addClass("selected");
}
iconDiv.on("mouseover", function() {
summary.text(icon);
})
iconDiv.on("mouseout", function() {
summary.html("&nbsp;");
})
iconDiv.on("click", function() {
iconPanel.hide();
done(moduleName+"/"+icon);
})
})
}
});
setTimeout(function() {
spinner.remove();
},50);
},300);
var spinner = RED.utils.addSpinnerOverlay(iconList,true);
var iconPanel = RED.popover.panel(picker);
iconPanel.show({
target: container
})
picker.slideDown(100);
searchInput.trigger("focus");
}
return {
show: showIconPicker
}
})();

View File

@@ -81,7 +81,8 @@
clearTimeout: true,
setInterval: true,
clearInterval: true
}
},
extraLibs: options.extraLibs
});
if (options.cursor) {
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);

View File

@@ -168,7 +168,7 @@
'b': { before:"**", after: "**", tooltip: RED._("markdownEditor.bold")},
'i': { before:"_", after: "_", tooltip: RED._("markdownEditor.italic")},
'code': { before:"`", after: "`", tooltip: RED._("markdownEditor.code")},
'ol': { before:" * ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
'ol': { before:" 1. ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
'ul': { before:" - ", newline: true, tooltip: RED._("markdownEditor.unordered-list")},
'bq': { before:"> ", newline: true, tooltip: RED._("markdownEditor.quote")},
'link': { before:"[", after: "]()", tooltip: RED._("markdownEditor.link")},

View File

@@ -0,0 +1,529 @@
;(function() {
RED.editor.registerEditPane("editor-tab-appearance", function(node) {
return {
label: RED._("editor-tab.appearance"),
name: RED._("editor-tab.appearance"),
iconClass: "fa fa-object-group",
create: function(container) {
this.content = container;
buildAppearanceForm(this.content,node);
if (node.type === 'subflow') {
this.defaultIcon = "node-red/subflow.svg";
} else {
var iconPath = RED.utils.getDefaultNodeIcon(node._def,node);
this.defaultIcon = iconPath.module+"/"+iconPath.file;
if (node.icon && node.icon !== this.defaultIcon) {
this.isDefaultIcon = false;
} else {
this.isDefaultIcon = true;
}
}
},
resize: function(size) {
},
close: function() {
},
show: function() {
refreshLabelForm(this.content, node);
},
apply: function(editState) {
if (updateLabels(node, editState.changes, editState.outputMap)) {
editState.changed = true;
}
if (!node._def.defaults || !node._def.defaults.hasOwnProperty("icon")) {
var icon = $("#red-ui-editor-node-icon").val()||"";
if (!this.isDefaultIcon) {
if ((node.icon && icon !== node.icon) || (!node.icon && icon !== "")) {
editState.changes.icon = node.icon;
node.icon = icon;
editState.changed = true;
}
} else {
if (icon !== "" && icon !== this.defaultIcon) {
editState.changes.icon = node.icon;
node.icon = icon;
editState.changed = true;
} else {
var iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
var currentDefaultIcon = iconPath.module+"/"+iconPath.file;
if (this.defaultIcon !== currentDefaultIcon) {
editState.changes.icon = node.icon;
node.icon = currentDefaultIcon;
editState.changed = true;
}
}
}
}
if (node.type === "subflow") {
var newCategory = $("#subflow-appearance-input-category").val().trim();
if (newCategory === "_custom_") {
newCategory = $("#subflow-appearance-input-custom-category").val().trim();
if (newCategory === "") {
newCategory = node.category;
}
}
if (newCategory === 'subflows') {
newCategory = '';
}
if (newCategory != node.category) {
editState.changes['category'] = node.category;
node.category = newCategory;
editState.changed = true;
}
var oldColor = node.color;
var newColor = $("#red-ui-editor-node-color").val();
if (oldColor !== newColor) {
editState.changes.color = node.color;
node.color = newColor;
editState.changed = true;
RED.utils.clearNodeColorCache();
if (node.type === "subflow") {
var nodeDefinition = RED.nodes.getType(
"subflow:" + node.id
);
nodeDefinition["color"] = newColor;
}
}
}
var showLabel = node._def.hasOwnProperty("showLabel")?node._def.showLabel:true;
if (!$("#node-input-show-label").prop('checked')) {
// Not checked - hide label
if (showLabel) {
// Default to show label
if (node.l !== false) {
editState.changes.l = node.l;
editState.changed = true;
}
node.l = false;
} else {
// Node has showLabel:false (eg link nodes)
if (node.hasOwnProperty('l') && node.l) {
editState.changes.l = node.l;
editState.changed = true;
}
delete node.l;
}
} else {
// Checked - show label
if (showLabel) {
// Default to show label
if (node.hasOwnProperty('l') && !node.l) {
editState.changes.l = node.l;
editState.changed = true;
}
delete node.l;
} else {
if (!node.l) {
editState.changes.l = node.l;
editState.changed = true;
}
node.l = true;
}
}
}
};
});
function buildAppearanceForm(container,node) {
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
var i,row;
if (node.type === "subflow") {
var categoryRow = $("<div/>", {
class: "form-row"
}).appendTo(dialogForm);
$("<label/>", {
for: "subflow-appearance-input-category",
"data-i18n": "editor:subflow.category"
}).appendTo(categoryRow);
var categorySelector = $("<select/>", {
id: "subflow-appearance-input-category"
}).css({
width: "250px"
}).appendTo(categoryRow);
$("<input/>", {
type: "text",
id: "subflow-appearance-input-custom-category"
}).css({
display: "none",
"margin-left": "10px",
width: "calc(100% - 250px)"
}).appendTo(categoryRow);
var categories = RED.palette.getCategories();
categories.sort(function(A,B) {
return A.label.localeCompare(B.label);
});
categories.forEach(function(cat) {
categorySelector.append($("<option/>").val(cat.id).text(cat.label));
});
categorySelector.append($("<option/>").attr('disabled',true).text("---"));
categorySelector.append($("<option/>").val("_custom_").text(RED._("palette.addCategory")));
$("#subflow-appearance-input-category").on("change", function() {
var val = $(this).val();
if (val === "_custom_") {
$("#subflow-appearance-input-category").width(120);
$("#subflow-appearance-input-custom-category").show();
} else {
$("#subflow-appearance-input-category").width(250);
$("#subflow-appearance-input-custom-category").hide();
}
});
$("#subflow-appearance-input-category").val(node.category||"subflows");
var userCount = 0;
var subflowType = "subflow:"+node.id;
// RED.nodes.eachNode(function(n) {
// if (n.type === subflowType) {
// userCount++;
// }
// });
$("#red-ui-editor-subflow-user-count")
.text(RED._("subflow.subflowInstances", {count:node.instances.length})).show();
}
$('<div class="form-row">'+
'<label for="node-input-show-label-btn" data-i18n="editor.label"></label>'+
'<span style="margin-right: 2px;"/>'+
'<input type="checkbox" id="node-input-show-label"/>'+
'</div>').appendTo(dialogForm);
$("#node-input-show-label").toggleButton({
enabledLabel: RED._("editor.show"),
disabledLabel: RED._("editor.hide")
});
if (!node.hasOwnProperty("l")) {
// Show label unless def.showLabel set to false
node.l = node._def.hasOwnProperty("showLabel")?node._def.showLabel:true;
}
$("#node-input-show-label").prop("checked",node.l).trigger("change");
if (node.type === "subflow") {
// subflow template can select its color
var color = node.color ? node.color : "#DDAA99";
var colorRow = $("<div/>", {
class: "form-row"
}).appendTo(dialogForm);
$("<label/>").text(RED._("editor.color")).appendTo(colorRow);
var recommendedColors = [
"#DDAA99",
"#3FADB5", "#87A980", "#A6BBCF",
"#AAAA66", "#C0C0C0", "#C0DEED",
"#C7E9C0", "#D7D7A0", "#D8BFD8",
"#DAC4B4", "#DEB887", "#DEBD5C",
"#E2D96E", "#E6E0F8", "#E7E7AE",
"#E9967A", "#F3B567", "#FDD0A2",
"#FDF0C2", "#FFAAAA", "#FFCC66",
"#FFF0F0", "#FFFFFF"
];
RED.editor.colorPicker.create({
id: "red-ui-editor-node-color",
value: color,
palette: recommendedColors,
sortPalette: function (a, b) {return a.l - b.l;}
}).appendTo(colorRow);
$("#red-ui-editor-node-color").on('change', function(ev) {
// Horribly out of scope...
var colour = $(this).val();
nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor);
}
});
}
// If a node has icon property in defaults, the icon of the node cannot be modified. (e.g, ui_button node in dashboard)
if ((!node._def.defaults || !node._def.defaults.hasOwnProperty("icon"))) {
var iconRow = $('<div class="form-row"></div>').appendTo(dialogForm);
$('<label data-i18n="editor.settingIcon">').appendTo(iconRow);
var iconButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(iconRow);
$('<i class="fa fa-caret-down"></i>').appendTo(iconButton);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconButton);
var colour = RED.utils.getNodeColor(node.type, node._def);
var icon_url = RED.utils.getNodeIcon(node._def,node);
nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor);
}
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
iconButton.on("click", function(e) {
e.preventDefault();
var iconPath;
var icon = $("#red-ui-editor-node-icon").val()||"";
if (icon) {
iconPath = RED.utils.separateIconPath(icon);
} else {
iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
}
var backgroundColor = RED.utils.getNodeColor(node.type, node._def);
if (node.type === "subflow") {
backgroundColor = $("#red-ui-editor-node-color").val();
}
RED.editor.iconPicker.show(iconButton,backgroundColor,iconPath,false,function(newIcon) {
$("#red-ui-editor-node-icon").val(newIcon||"");
var icon_url = RED.utils.getNodeIcon(node._def,{type:node.type,icon:newIcon});
RED.utils.createIconElement(icon_url, iconContainer, true);
});
});
RED.popover.tooltip(iconButton, function() {
return $("#red-ui-editor-node-icon").val() || RED._("editor.default");
});
$('<input type="hidden" id="red-ui-editor-node-icon">').val(node.icon).appendTo(iconRow);
}
$('<div class="form-row"><span data-i18n="editor.portLabels"></span></div>').appendTo(dialogForm);
var inputCount = node.inputs || node._def.inputs || 0;
var outputCount = node.outputs || node._def.outputs || 0;
if (node.type === 'subflow') {
inputCount = node.in.length;
outputCount = node.out.length;
}
var inputLabels = node.inputLabels || [];
var outputLabels = node.outputLabels || [];
var inputPlaceholder = node._def.inputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
var outputPlaceholder = node._def.outputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
$('<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelInputs"></span><div id="red-ui-editor-node-label-form-inputs"></div></div>').appendTo(dialogForm);
var inputsDiv = $("#red-ui-editor-node-label-form-inputs");
if (inputCount > 0) {
for (i=0;i<inputCount;i++) {
buildLabelRow("input",i,inputLabels[i],inputPlaceholder).appendTo(inputsDiv);
}
} else {
buildLabelRow().appendTo(inputsDiv);
}
$('<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelOutputs"></span><div id="red-ui-editor-node-label-form-outputs"></div></div>').appendTo(dialogForm);
var outputsDiv = $("#red-ui-editor-node-label-form-outputs");
if (outputCount > 0) {
for (i=0;i<outputCount;i++) {
buildLabelRow("output",i,outputLabels[i],outputPlaceholder).appendTo(outputsDiv);
}
} else {
buildLabelRow().appendTo(outputsDiv);
}
}
function refreshLabelForm(container,node) {
var inputPlaceholder = node._def.inputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
var outputPlaceholder = node._def.outputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
var inputsDiv = $("#red-ui-editor-node-label-form-inputs");
var outputsDiv = $("#red-ui-editor-node-label-form-outputs");
var inputCount;
var formInputs = $("#node-input-inputs").val();
if (formInputs === undefined) {
if (node.type === 'subflow') {
inputCount = node.in.length;
} else {
inputCount = node.inputs || node._def.inputs || 0;
}
} else {
inputCount = Math.min(1,Math.max(0,parseInt(formInputs)));
if (isNaN(inputCount)) {
inputCount = 0;
}
}
var children = inputsDiv.children();
var childCount = children.length;
if (childCount === 1 && $(children[0]).hasClass('red-ui-editor-node-label-form-none')) {
childCount--;
}
if (childCount < inputCount) {
if (childCount === 0) {
// remove the 'none' placeholder
$(children[0]).remove();
}
for (i = childCount;i<inputCount;i++) {
buildLabelRow("input",i,"",inputPlaceholder).appendTo(inputsDiv);
}
} else if (childCount > inputCount) {
for (i=inputCount;i<childCount;i++) {
$(children[i]).remove();
}
if (inputCount === 0) {
buildLabelRow().appendTo(inputsDiv);
}
}
var outputCount;
var i;
var formOutputs = $("#node-input-outputs").val();
if (formOutputs === undefined) {
if (node.type === 'subflow') {
outputCount = node.out.length;
} else {
inputCount = node.outputs || node._def.outputs || 0;
}
} else if (isNaN(formOutputs)) {
var outputMap = JSON.parse(formOutputs);
var keys = Object.keys(outputMap);
children = outputsDiv.children();
childCount = children.length;
if (childCount === 1 && $(children[0]).hasClass('red-ui-editor-node-label-form-none')) {
childCount--;
}
outputCount = 0;
var rows = [];
keys.forEach(function(p) {
var row = $("#red-ui-editor-node-label-form-output-"+p).parent();
if (row.length === 0 && outputMap[p] !== -1) {
if (childCount === 0) {
$(children[0]).remove();
childCount = -1;
}
row = buildLabelRow("output",p,"",outputPlaceholder);
} else {
row.detach();
}
if (outputMap[p] !== -1) {
outputCount++;
rows.push({i:parseInt(outputMap[p]),r:row});
}
});
rows.sort(function(A,B) {
return A.i-B.i;
});
rows.forEach(function(r,i) {
r.r.find("label").text((i+1)+".");
r.r.appendTo(outputsDiv);
});
if (rows.length === 0) {
buildLabelRow("output",i,"").appendTo(outputsDiv);
} else {
}
} else {
outputCount = Math.max(0,parseInt(formOutputs));
}
children = outputsDiv.children();
childCount = children.length;
if (childCount === 1 && $(children[0]).hasClass('red-ui-editor-node-label-form-none')) {
childCount--;
}
if (childCount < outputCount) {
if (childCount === 0) {
// remove the 'none' placeholder
$(children[0]).remove();
}
for (i = childCount;i<outputCount;i++) {
buildLabelRow("output",i,"").appendTo(outputsDiv);
}
} else if (childCount > outputCount) {
for (i=outputCount;i<childCount;i++) {
$(children[i]).remove();
}
if (outputCount === 0) {
buildLabelRow().appendTo(outputsDiv);
}
}
}
function buildLabelRow(type, index, value, placeHolder) {
var result = $('<div>',{class:"red-ui-editor-node-label-form-row"});
if (type === undefined) {
$('<span>').text(RED._("editor.noDefaultLabel")).appendTo(result);
result.addClass("red-ui-editor-node-label-form-none");
} else {
result.addClass("");
var id = "red-ui-editor-node-label-form-"+type+"-"+index;
$('<label>',{for:id}).text((index+1)+".").appendTo(result);
var input = $('<input>',{type:"text",id:id, placeholder: placeHolder}).val(value).appendTo(result);
var clear = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-times"></i></button>').appendTo(result);
clear.on("click", function(evt) {
evt.preventDefault();
input.val("");
});
}
return result;
}
function updateLabels(node, changes, outputMap) {
var inputLabels = $("#red-ui-editor-node-label-form-inputs").children().find("input");
var outputLabels = $("#red-ui-editor-node-label-form-outputs").children().find("input");
var hasNonBlankLabel = false;
var changed = false;
var newValue = inputLabels.map(function() {
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
return v;
}).toArray().slice(0,node.inputs);
if ((node.inputLabels === undefined && hasNonBlankLabel) ||
(node.inputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(node.inputLabels))) {
changes.inputLabels = node.inputLabels;
node.inputLabels = newValue;
changed = true;
}
hasNonBlankLabel = false;
newValue = new Array(node.outputs);
outputLabels.each(function() {
var index = $(this).attr('id').substring("red-ui-editor-node-label-form-output-".length);
if (outputMap && outputMap.hasOwnProperty(index)) {
index = parseInt(outputMap[index]);
if (index === -1) {
return;
}
}
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
// mark changed output port labels as dirty
if (node.type === "subflow" && (!node.outputLabels || node.outputLabels[index] !== v)) {
node.out[index].dirty = true;
}
newValue[index] = v;
});
if ((node.outputLabels === undefined && hasNonBlankLabel) ||
(node.outputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(node.outputLabels))) {
changes.outputLabels = node.outputLabels;
node.outputLabels = newValue;
changed = true;
// trigger redraw of dirty port labels
if (node.type === "subflow") {
RED.view.redraw();
}
}
return changed;
}
})();

View File

@@ -0,0 +1,70 @@
;(function() {
RED.editor.registerEditPane("editor-tab-description", function(node) {
return {
label: RED._("editor-tab.description"),
name: RED._("editor-tab.description"),
iconClass: "fa fa-file-text-o",
create: function(container) {
this.editor = buildDescriptionForm(container,node);
RED.e = this.editor;
},
resize: function(size) {
this.editor.resize();
},
close: function() {
this.editor.destroy();
this.editor = null;
},
show: function() {
this.editor.focus();
},
apply: function(editState) {
var oldInfo = node.info;
var newInfo = this.editor.getValue();
if (!!oldInfo) {
// Has existing info property
if (newInfo.trim() === "") {
// New value is blank - remove the property
editState.changed = true;
editState.changes.info = oldInfo;
delete node.info;
} else if (newInfo !== oldInfo) {
// New value is different
editState.changed = true;
editState.changes.info = oldInfo;
node.info = newInfo;
}
} else {
// No existing info
if (newInfo.trim() !== "") {
// New value is not blank
editState.changed = true;
editState.changes.info = undefined;
node.info = newInfo;
}
}
}
}
});
function buildDescriptionForm(container,node) {
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
var toolbarRow = $('<div></div>').appendTo(dialogForm);
var row = $('<div class="form-row node-text-editor-row" style="position:relative; padding-top: 4px; height: 100%"></div>').appendTo(dialogForm);
var editorId = "node-info-input-info-editor-"+Math.floor(1000*Math.random());
$('<div style="height: 100%" class="node-text-editor" id="'+editorId+'" ></div>').appendTo(row);
var nodeInfoEditor = RED.editor.createEditor({
id: editorId,
mode: 'ace/mode/markdown',
value: ""
});
if (node.info) {
nodeInfoEditor.getSession().setValue(node.info, -1);
}
node.infoEditor = nodeInfoEditor;
return nodeInfoEditor;
}
})();

View File

@@ -0,0 +1,75 @@
;(function() {
RED.editor.registerEditPane("editor-tab-envProperties", function(node) {
return {
label: RED._("editor-tab.envProperties"),
name: RED._("editor-tab.envProperties"),
iconClass: "fa fa-list",
create: function(container) {
var form = $('<form class="dialog-form form-horizontal"></form>').appendTo(container);
var listContainer = $('<div class="form-row node-input-env-container-row"></div>').appendTo(form);
this.list = $('<ol></ol>').appendTo(listContainer);
RED.editor.envVarList.create(this.list, node);
},
resize: function(size) {
this.list.editableList('height',size.height);
},
close: function() {
},
apply: function(editState) {
var old_env = node.env;
var new_env = [];
if (/^subflow:/.test(node.type)) {
new_env = RED.subflow.exportSubflowInstanceEnv(node);
}
// Get the values from the Properties table tab
var items = this.list.editableList('items');
items.each(function (i,el) {
var data = el.data('data');
var item;
if (data.nameField && data.valueField) {
item = {
name: data.nameField.val(),
value: data.valueField.typedInput("value"),
type: data.valueField.typedInput("type")
}
if (item.name.trim() !== "") {
new_env.push(item);
}
}
});
if (new_env && new_env.length > 0) {
new_env.forEach(function(prop) {
if (prop.type === "cred") {
node.credentials = node.credentials || {_:{}};
node.credentials[prop.name] = prop.value;
node.credentials['has_'+prop.name] = (prop.value !== "");
if (prop.value !== '__PWRD__') {
editState.changed = true;
}
delete prop.value;
}
});
}
if (!old_env && new_env.length === 0) {
delete node.env;
} else if (!isSameObj(old_env, new_env)) {
editState.changes.env = node.env;
if (new_env.length === 0) {
delete node.env;
} else {
node.env = new_env;
}
editState.changed = true;
}
}
}
});
function isSameObj(env0, env1) {
return (JSON.stringify(env0) === JSON.stringify(env1));
}
})();

View File

@@ -0,0 +1,60 @@
;(function() {
RED.editor.registerEditPane("editor-tab-flow-properties", function(node) {
return {
label: RED._("editor-tab.properties"),
name: RED._("editor-tab.properties"),
iconClass: "fa fa-cog",
create: function(container) {
var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(container);
$('<div class="form-row">'+
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
'<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+
'</div>').appendTo(dialogForm);
var row = $('<div class="form-row node-text-editor-row">'+
'<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+
'<div style="min-height:150px;" class="node-text-editor" id="node-input-info"></div>'+
'</div>').appendTo(dialogForm);
this.tabflowEditor = RED.editor.createEditor({
id: 'node-input-info',
mode: 'ace/mode/markdown',
value: ""
});
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
dialogForm.on("submit", function(e) { e.preventDefault();});
$("#node-input-name").val(node.label);
RED.text.bidi.prepareInput($("#node-input-name"));
this.tabflowEditor.getSession().setValue(node.info || "", -1);
},
resize: function(size) {
$("#node-input-info").css("height", (size.height-70)+"px");
this.tabflowEditor.resize();
},
close: function() {
this.tabflowEditor.destroy();
},
apply: function(editState) {
var label = $( "#node-input-name" ).val();
if (node.label != label) {
editState.changes.label = node.label;
editState.changed = true;
node.label = label;
}
var info = this.tabflowEditor.getValue();
if (node.info !== info) {
editState.changes.info = node.info;
editState.changed = true;
node.info = info;
}
$("#red-ui-tab-"+(node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!node.disabled);
}
}
});
})();

View File

@@ -0,0 +1,198 @@
;(function() {
RED.editor.registerEditPane("editor-tab-properties", function(node) {
return {
label: RED._("editor-tab.properties"),
name: RED._("editor-tab.properties"),
iconClass: "fa fa-cog",
create: function(container) {
var nodeType = node.type;
if (node.type === "subflow") {
nodeType = "subflow-template";
} else if (node.type.substring(0,8) == "subflow:") {
nodeType = "subflow";
}
var i18nNamespace;
if (node._def.set.module === "node-red") {
i18nNamespace = "node-red";
} else {
i18nNamespace = node._def.set.id;
}
var formStyle = "dialog-form";
this.inputClass = "node-input";
if (node._def.category === "config" && nodeType !== "group") {
this.inputClass = "node-config-input";
formStyle = "node-config-dialog-edit-form";
}
RED.editor.buildEditForm(container,formStyle,nodeType,i18nNamespace,node);
},
resize: function(size) {
if (node && node._def.oneditresize) {
try {
node._def.oneditresize.call(node,size);
} catch(err) {
console.log("oneditresize",node.id,node.type,err.toString());
}
}
},
close: function() {
},
apply: function(editState) {
var newValue;
var d;
if (node._def.defaults) {
for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) {
var input = $("#"+this.inputClass+"-"+d);
if (input.attr('type') === "checkbox") {
newValue = input.prop('checked');
} else if (input.prop("nodeName") === "select" && input.attr("multiple") === "multiple") {
// An empty select-multiple box returns null.
// Need to treat that as an empty array.
newValue = input.val();
if (newValue == null) {
newValue = [];
}
} else if ("format" in node._def.defaults[d] && node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") {
newValue = input.text();
} else {
newValue = input.val();
}
if (newValue != null) {
if (d === "outputs") {
if (newValue.trim() === "") {
continue;
}
if (isNaN(newValue)) {
editState.outputMap = JSON.parse(newValue);
var outputCount = 0;
var outputsChanged = false;
var keys = Object.keys(editState.outputMap);
keys.forEach(function(p) {
if (isNaN(p)) {
// New output;
outputCount ++;
delete editState.outputMap[p];
} else {
editState.outputMap[p] = editState.outputMap[p]+"";
if (editState.outputMap[p] !== "-1") {
outputCount++;
if (editState.outputMap[p] !== p) {
// Output moved
outputsChanged = true;
} else {
delete editState.outputMap[p];
}
} else {
// Output removed
outputsChanged = true;
}
}
});
newValue = outputCount;
if (outputsChanged) {
editState.changed = true;
}
} else {
newValue = parseInt(newValue);
}
}
if (node._def.defaults[d].type) {
if (newValue == "_ADD_") {
newValue = "";
}
}
if (!isEqual(node[d], newValue)) {
if (node._def.defaults[d].type) {
// Change to a related config node
var configNode = RED.nodes.node(node[d]);
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(node),1);
RED.events.emit("nodes:change",configNode);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(node);
RED.events.emit("nodes:change",configNode);
}
}
editState.changes[d] = node[d];
node[d] = newValue;
editState.changed = true;
}
}
}
}
}
if (node._def.credentials) {
var credDefinition = node._def.credentials;
var credsChanged = updateNodeCredentials(node,credDefinition,this.inputClass);
editState.changed = editState.changed || credsChanged;
}
}
}
});
/**
* Compares `newValue` with `originalValue` for equality.
* @param {*} originalValue Original value
* @param {*} newValue New value
* @returns {boolean} true if originalValue equals newValue, otherwise false
*/
function isEqual(originalValue, newValue) {
try {
if(originalValue == newValue) {
return true;
}
return JSON.stringify(originalValue) === JSON.stringify(newValue);
} catch (err) {
return false;
}
}
/**
* Update the node credentials from the edit form
* @param node - the node containing the credentials
* @param credDefinition - definition of the credentials
* @param prefix - prefix of the input fields
* @return {boolean} whether anything has changed
*/
function updateNodeCredentials(node, credDefinition, prefix) {
var changed = false;
if (!node.credentials) {
node.credentials = {_:{}};
} else if (!node.credentials._) {
node.credentials._ = {};
}
for (var cred in credDefinition) {
if (credDefinition.hasOwnProperty(cred)) {
var input = $("#" + prefix + '-' + cred);
if (input.length > 0) {
var value = input.val();
if (credDefinition[cred].type == 'password') {
node.credentials['has_' + cred] = (value !== "");
if (value == '__PWRD__') {
continue;
}
changed = true;
}
node.credentials[cred] = value;
if (value != node.credentials._[cred]) {
changed = true;
}
}
}
}
return changed;
}
})();

View File

@@ -0,0 +1,179 @@
(function() {
var _subflowModulePaneTemplate = '<form class="dialog-form form-horizontal" autocomplete="off">'+
'<div class="form-row">'+
'<label for="subflow-input-module-module" data-i18n="[append]editor:subflow.module"><i class="fa fa-cube"></i> </label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-module" data-i18n="[placeholder]common.label.name">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-type" data-i18n="[append]editor:subflow.type"> </label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-type">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-version" data-i18n="[append]editor:subflow.version"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-version" data-i18n="[placeholder]editor:subflow.versionPlaceholder">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-desc" data-i18n="[append]editor:subflow.desc"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-desc">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-license" data-i18n="[append]editor:subflow.license"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-license">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-author" data-i18n="[append]editor:subflow.author"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-author" data-i18n="[placeholder]editor:subflow.authorPlaceholder">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-keywords" data-i18n="[append]editor:subflow.keys"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-keywords" data-i18n="[placeholder]editor:subflow.keysPlaceholder">'+
'</div>'+
'</form>';
RED.editor.registerEditPane("editor-tab-subflow-module", function(node) {
return {
label: RED._("editor-tab.module"),
name: RED._("editor-tab.module"),
iconClass: "fa fa-cube",
create: function(container) {
buildModuleForm(container, node);
},
resize: function(size) {
},
close: function() {
},
apply: function(editState) {
var newMeta = exportSubflowModuleProperties(node);
if (!isSameObj(node.meta,newMeta)) {
editState.changes.meta = node.meta;
node.meta = newMeta;
editState.changed = true;
}
}
}
});
function isSameObj(env0, env1) {
return (JSON.stringify(env0) === JSON.stringify(env1));
}
function setupInputValidation(input,validator) {
var errorTip;
var validateTimeout;
var validateFunction = function() {
if (validateTimeout) {
return;
}
validateTimeout = setTimeout(function() {
var error = validator(input.val());
// if (!error && errorTip) {
// errorTip.close();
// errorTip = null;
// } else if (error && !errorTip) {
// errorTip = RED.popover.create({
// tooltip: true,
// target:input,
// size: "small",
// direction: "bottom",
// content: error,
// }).open();
// }
input.toggleClass("input-error",!!error);
validateTimeout = null;
})
}
input.on("change keyup paste", validateFunction);
}
function buildModuleForm(container, node) {
$(_subflowModulePaneTemplate).appendTo(container);
var moduleProps = node.meta || {};
[
'module',
'type',
'version',
'author',
'desc',
'keywords',
'license'
].forEach(function(property) {
$("#subflow-input-module-"+property).val(moduleProps[property]||"")
})
$("#subflow-input-module-type").attr("placeholder",node.id);
setupInputValidation($("#subflow-input-module-module"), function(newValue) {
newValue = newValue.trim();
var isValid = newValue.length < 215;
isValid = isValid && !/^[._]/.test(newValue);
isValid = isValid && !/[A-Z]/.test(newValue);
if (newValue !== encodeURIComponent(newValue)) {
var m = /^@([^\/]+)\/([^\/]+)$/.exec(newValue);
if (m) {
isValid = isValid && (m[1] === encodeURIComponent(m[1]) && m[2] === encodeURIComponent(m[2]))
} else {
isValid = false;
}
}
return isValid?"":"Invalid module name"
})
setupInputValidation($("#subflow-input-module-version"), function(newValue) {
newValue = newValue.trim();
var isValid = newValue === "" ||
/^(\d|[1-9]\d*)\.(\d|[1-9]\d*)\.(\d|[1-9]\d*)(-(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\.(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(newValue);
return isValid?"":"Invalid version number"
})
var licenses = ["none", "Apache-2.0", "BSD-3-Clause", "BSD-2-Clause", "GPL-2.0", "GPL-3.0", "MIT", "MPL-2.0", "CDDL-1.0", "EPL-2.0"];
var typedLicenses = {
types: licenses.map(function(l) {
return {
value: l,
label: l === "none" ? RED._("editor:subflow.licenseNone") : l,
hasValue: false
};
})
}
typedLicenses.types.push({
value:"_custom_", label:RED._("editor:subflow.licenseOther"), icon:"red/images/typedInput/az.svg"
})
if (!moduleProps.license) {
typedLicenses.default = "none";
} else if (licenses.indexOf(moduleProps.license) > -1) {
typedLicenses.default = moduleProps.license;
} else {
typedLicenses.default = "_custom_";
}
$("#subflow-input-module-license").typedInput(typedLicenses)
}
function exportSubflowModuleProperties(node) {
var value;
var moduleProps = {};
[
'module',
'type',
'version',
'author',
'desc',
'keywords'
].forEach(function(property) {
value = $("#subflow-input-module-"+property).val().trim();
if (value) {
moduleProps[property] = value;
}
})
var selectedLicenseType = $("#subflow-input-module-license").typedInput("type");
if (selectedLicenseType === '_custom_') {
value = $("#subflow-input-module-license").val();
if (value) {
moduleProps.license = value;
}
} else if (selectedLicenseType !== "none") {
moduleProps.license = selectedLicenseType;
}
return moduleProps;
}
})();

View File

@@ -87,16 +87,18 @@ RED.group = (function() {
"label-position": "nw"
};
var groupDef = {
defaults:{
name:{value:""},
style:{value:{label:true}},
nodes:{value:[]}
nodes:{value:[]},
env: {value:[]},
},
category: "config",
oneditprepare: function() {
var style = this.style || {};
RED.colorPicker.create({
RED.editor.colorPicker.create({
id:"node-input-style-stroke",
value: style.stroke || defaultGroupStyle.stroke || "#a4a4a4",
palette: colorPalette,
@@ -107,7 +109,7 @@ RED.group = (function() {
none: true,
opacity: style.hasOwnProperty('stroke-opacity')?style['stroke-opacity']:(defaultGroupStyle.hasOwnProperty('stroke-opacity')?defaultGroupStyle['stroke-opacity']:1.0)
}).appendTo("#node-input-row-style-stroke");
RED.colorPicker.create({
RED.editor.colorPicker.create({
id:"node-input-style-fill",
value: style.fill || defaultGroupStyle.fill ||"none",
palette: colorPalette,
@@ -124,7 +126,7 @@ RED.group = (function() {
value:style["label-position"] || "nw"
}).appendTo("#node-input-row-style-label-position");
RED.colorPicker.create({
RED.editor.colorPicker.create({
id:"node-input-style-color",
value: style.color || defaultGroupStyle.color ||"#a4a4a4",
palette: colorPalette,
@@ -144,7 +146,6 @@ RED.group = (function() {
})
$("#node-input-style-label").prop("checked", this.style.label)
$("#node-input-style-label").trigger("change");
},
oneditresize: function(size) {
},
@@ -183,7 +184,9 @@ RED.group = (function() {
var activateUngroup = false;
var activateMerge = false;
var activateRemove = false;
var singleGroupSelected = false;
if (activateGroup) {
singleGroupSelected = selection.nodes.length === 1 && selection.nodes[0].type === 'group';
selection.nodes.forEach(function (n) {
if (n.type === "group") {
activateUngroup = true;
@@ -200,6 +203,8 @@ RED.group = (function() {
RED.menu.setDisabled("menu-item-group-ungroup", !activateUngroup);
RED.menu.setDisabled("menu-item-group-merge", !activateMerge);
RED.menu.setDisabled("menu-item-group-remove", !activateRemove);
RED.menu.setDisabled("menu-item-edit-copy-group-style", !singleGroupSelected);
RED.menu.setDisabled("menu-item-edit-paste-group-style", !activateUngroup);
});
RED.actions.add("core:group-selection", function() { groupSelection() })
@@ -252,6 +257,7 @@ RED.group = (function() {
if (selection.nodes && selection.nodes.length === 1 && selection.nodes[0].type === 'group') {
groupStyleClipboard = JSON.parse(JSON.stringify(selection.nodes[0].style));
RED.notify(RED._("clipboard.groupStyleCopied"),{id:"clipboard"})
RED.menu.setDisabled("menu-item-edit-paste-group-style", false)
}
}
function pasteGroupStyle() {
@@ -317,9 +323,6 @@ RED.group = (function() {
groups: [ ],
dirty: RED.nodes.dirty()
}
RED.history.push(historyEvent);
groups.forEach(function(g) {
newSelection = newSelection.concat(ungroup(g))
historyEvent.groups.push(g);
@@ -584,12 +587,14 @@ RED.group = (function() {
markDirty(group);
}
function getNodes(group,recursive) {
function getNodes(group,recursive,excludeGroup) {
var nodes = [];
group.nodes.forEach(function(n) {
nodes.push(n);
if (n.type !== 'group' || !excludeGroup) {
nodes.push(n);
}
if (recursive && n.type === 'group') {
nodes = nodes.concat(getNodes(n,recursive))
nodes = nodes.concat(getNodes(n,recursive,excludeGroup))
}
})
return nodes;

View File

@@ -49,15 +49,15 @@ RED.keyboard = (function() {
"]": 221,
"{": 219,// <- QWERTY specific
"}": 221 // <- QWERTY specific
}
};
var metaKeyCodes = {
16: true,
17: true,
18: true,
91: true,
93: true
}
var actionToKeyMap = {}
};
var actionToKeyMap = {};
var defaultKeyMap = {};
// FF generates some different keycodes because reasons.
@@ -65,7 +65,7 @@ RED.keyboard = (function() {
59:186,
61:187,
173:189
}
};
function migrateOldKeymap() {
// pre-0.18
@@ -80,7 +80,7 @@ RED.keyboard = (function() {
}
function getUserKey(action) {
return RED.settings.get('editor.keymap',{})[action]
return RED.settings.get('editor.keymap',{})[action];
}
function mergeKeymaps(defaultKeymap, themeKeymap) {
@@ -105,7 +105,7 @@ RED.keyboard = (function() {
scope:scope,
key:key,
user:false
})
});
}
}
}
@@ -115,13 +115,13 @@ RED.keyboard = (function() {
if (themeKeymap.hasOwnProperty(action)) {
if (!themeKeymap[action].key) {
// No key for this action - default is no keybinding
delete mergedKeymap[action]
delete mergedKeymap[action];
} else {
mergedKeymap[action] = [{
scope: themeKeymap[action].scope || "*",
key: themeKeymap[action].key,
user: false
}]
}];
if (mergedKeymap[action][0].scope === "workspace") {
mergedKeymap[action][0].scope = "red-ui-workspace";
}
@@ -131,7 +131,7 @@ RED.keyboard = (function() {
return mergedKeymap;
}
function init() {
function init(done) {
// Migrate from pre-0.18
migrateOldKeymap();
@@ -164,6 +164,7 @@ RED.keyboard = (function() {
}
}
}
done();
});
RED.userSettings.add({
@@ -174,8 +175,11 @@ RED.keyboard = (function() {
setTimeout(function() {
$("#red-ui-settings-tab-keyboard-filter").trigger("focus");
},200);
},
close: function() {
RED.menu.refreshShortcuts();
}
})
});
}
function revertToDefault(action) {
@@ -239,7 +243,13 @@ RED.keyboard = (function() {
function resolveKeyEvent(evt) {
var slot = partialState||handlers;
if (evt.ctrlKey || evt.metaKey) {
// We cheat with MacOS CMD key and consider it the same as Ctrl.
// That means we don't have to have separate keymaps for different OS.
// It mostly works.
// One exception is shortcuts that include both Cmd and Ctrl. We don't
// support them - but we need to make sure we don't block browser-specific
// shortcuts (such as Cmd-Ctrl-F for fullscreen).
if ((evt.ctrlKey || evt.metaKey) && (evt.ctrlKey !== evt.metaKey)) {
slot = slot.ctrl;
}
if (slot && evt.shiftKey) {
@@ -317,7 +327,7 @@ RED.keyboard = (function() {
scope:scope,
key:key,
user:false
}
};
}
if (!ondown) {
var userAction = getUserKey(cbdown);
@@ -340,7 +350,7 @@ RED.keyboard = (function() {
}
}
} else {
keys.push([key,mod])
keys.push([key,mod]);
}
var slot = handlers;
for (i=0;i<keys.length;i++) {
@@ -363,7 +373,7 @@ RED.keyboard = (function() {
//slot[key] = {scope: scope, ondown:cbdown};
}
slot.handlers = slot.handlers || [];
slot.handlers.push({scope:scope,ondown:cbdown})
slot.handlers.push({scope:scope,ondown:cbdown});
slot.scope = scope;
slot.ondown = cbdown;
}
@@ -380,12 +390,12 @@ RED.keyboard = (function() {
if (parsedKey) {
keys.push(parsedKey);
} else {
console.log("Unrecognised key specifier:",key)
console.log("Unrecognised key specifier:",key);
return;
}
}
} else {
keys.push([key,mod])
keys.push([key,mod]);
}
var slot = handlers;
for (i=0;i<keys.length;i++) {
@@ -407,7 +417,7 @@ RED.keyboard = (function() {
}
if (typeof slot.ondown === "string") {
if (typeof modifiers === 'boolean' && modifiers) {
actionToKeyMap[slot.ondown] = {user: modifiers}
actionToKeyMap[slot.ondown] = {user: modifiers};
} else {
delete actionToKeyMap[slot.ondown];
}
@@ -423,11 +433,11 @@ RED.keyboard = (function() {
function formatKey(key,plain) {
var formattedKey = isMac?key.replace(/ctrl-?/,"&#8984;"):key;
formattedKey = isMac?formattedKey.replace(/alt-?/,"&#8997;"):key;
formattedKey = formattedKey.replace(/shift-?/,"&#8679;")
formattedKey = formattedKey.replace(/left/,"&#x2190;")
formattedKey = formattedKey.replace(/up/,"&#x2191;")
formattedKey = formattedKey.replace(/right/,"&#x2192;")
formattedKey = formattedKey.replace(/down/,"&#x2193;")
formattedKey = formattedKey.replace(/shift-?/,"&#8679;");
formattedKey = formattedKey.replace(/left/,"&#x2190;");
formattedKey = formattedKey.replace(/up/,"&#x2191;");
formattedKey = formattedKey.replace(/right/,"&#x2192;");
formattedKey = formattedKey.replace(/down/,"&#x2193;");
if (plain) {
return formattedKey;
}
@@ -451,7 +461,6 @@ RED.keyboard = (function() {
var container = $(this);
var object = container.data('data');
if (!container.hasClass('keyboard-shortcut-entry-expanded')) {
endEditShortcut();
@@ -475,7 +484,7 @@ RED.keyboard = (function() {
}
$(this).toggleClass("input-error",!valid);
okButton.attr("disabled",!valid);
})
});
var scopeSelect = $('<select><option value="*" data-i18n="keyboard.global"></option><option value="red-ui-workspace" data-i18n="keyboard.workspace"></option></select>').appendTo(scope);
scopeSelect.i18n();
@@ -485,7 +494,7 @@ RED.keyboard = (function() {
scopeSelect.val(object.scope||'*');
scopeSelect.on("change", function() {
keyInput.trigger("change");
})
});
var div = $('<div class="keyboard-shortcut-edit button-group-vertical"></div>').appendTo(scope);
var okButton = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-check"></i></button>').appendTo(div);
@@ -511,10 +520,13 @@ RED.keyboard = (function() {
id:object.id,
scope:shortcut?shortcut.scope:undefined,
key:shortcut?shortcut.key:undefined,
user:shortcut?shortcut.user:undefined
}
user:shortcut?shortcut.user:undefined,
label: object.label,
options: object.options,
};
buildShortcutRow(container,obj);
})
});
keyInput.trigger("focus");
}
@@ -549,7 +561,7 @@ RED.keyboard = (function() {
delete object.scope;
} else {
keyDiv.parent().removeClass("keyboard-shortcut-entry-unassigned");
keyDiv.append(RED.keyboard.formatKey(key))
keyDiv.append(RED.keyboard.formatKey(key));
$("<span>").text(scope).appendTo(scopeDiv);
object.key = key;
object.scope = scope;
@@ -562,7 +574,7 @@ RED.keyboard = (function() {
userKeymap[object.id] = {
scope:shortcut.scope,
key:shortcut.key
}
};
RED.settings.set('editor.keymap',userKeymap);
}
}
@@ -578,13 +590,7 @@ RED.keyboard = (function() {
var item = $('<div class="keyboard-shortcut-entry">').appendTo(container);
container.data('data',object);
var text = object.id.replace(/(^.+:([a-z]))|(-([a-z]))/g,function() {
if (arguments[5] === 0) {
return arguments[2].toUpperCase();
} else {
return " "+arguments[4].toUpperCase();
}
});
var text = object.label;
var label = $('<div>').addClass("keyboard-shortcut-entry-text").text(text).appendTo(item);
var user = $('<i class="fa fa-user"></i>').prependTo(label);
@@ -619,14 +625,15 @@ RED.keyboard = (function() {
pane.find("#red-ui-settings-tab-keyboard-filter").searchBox({
delay: 100,
change: function() {
var filterValue = $(this).val().trim();
var filterValue = $(this).val().trim().toLowerCase();
if (filterValue === "") {
shortcutList.editableList('filter', null);
} else {
filterValue = filterValue.replace(/\s/g,"");
shortcutList.editableList('filter', function(data) {
return data.id.toLowerCase().replace(/^.*:/,"").replace("-","").indexOf(filterValue) > -1;
})
var label = data.label.toLowerCase();
return label.indexOf(filterValue) > -1;
});
}
}
});
@@ -647,9 +654,9 @@ RED.keyboard = (function() {
});
var shortcuts = RED.actions.list();
shortcuts.sort(function(A,B) {
var Aid = A.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase();
var Bid = B.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase();
return Aid.localeCompare(Bid);
var Akey = A.label;
var Bkey = B.label;
return Akey.localeCompare(Bkey);
});
knownShortcuts = new Set();
shortcuts.forEach(function(s) {

View File

@@ -363,106 +363,112 @@ RED.library = (function() {
options.onconfirm(item);
}
});
var itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
.on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
var elementPos = menuButton.offset();
var menuOptionMenu = RED.menu.init({id:"red-ui-library-browser-menu",
options: [
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
var defaultFolderName = "new-folder";
var defaultFolderNameMatches = {};
var selected = dirList.treeList('selected');
if (!selected.children) {
selected = selected.parent;
}
var complete = function() {
selected.children.forEach(function(c) {
if (/^new-folder/.test(c.label)) {
defaultFolderNameMatches[c.label] = true
}
});
var folderIndex = 2;
while(defaultFolderNameMatches[defaultFolderName]) {
defaultFolderName = "new-folder-"+(folderIndex++)
}
selected.treeList.expand();
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
var newItem = {
icon: "fa fa-folder-o",
children:[],
path: selected.path,
element: input
}
var confirmAdd = function() {
var val = input.val().trim();
if (val === "") {
cancelAdd();
return;
} else {
for (var i=0;i<selected.children.length;i++) {
if (selected.children[i].label === val) {
cancelAdd();
return;
}
}
}
newItem.treeList.remove();
var finalItem = {
library: selected.library,
type: selected.type,
icon: "fa fa-folder",
children:[],
label: val,
path: newItem.path+val+"/"
}
selected.treeList.addChild(finalItem,true);
}
var cancelAdd = function() {
newItem.treeList.remove();
}
input.on('keydown', function(evt) {
evt.stopPropagation();
if (evt.keyCode === 13) {
confirmAdd();
} else if (evt.keyCode === 27) {
cancelAdd();
}
})
input.on("blur", function() {
confirmAdd();
})
selected.treeList.addChild(newItem);
setTimeout(function() {
input.trigger("focus");
input.select();
},400);
}
selected.treeList.expand(complete);
} },
// null,
// {id:"red-ui-library-browser-menu-rename",label:"Rename", onselect: function() {} },
// {id:"red-ui-library-browser-menu-delete",label:"Delete", onselect: function() {} }
]
}).on('mouseleave', function(){ $(this).remove(); dirList.focus() })
.on('mouseup', function() { var self = $(this);self.hide(); dirList.focus(); setTimeout(function() { self.remove() },100)})
.appendTo("body");
menuOptionMenu.css({
position: "absolute",
top: elementPos.top+"px",
left: (elementPos.left - menuOptionMenu.width() + 20)+"px"
}).show();
}).appendTo(itemTools);
var itemTools = null;
if (options.folderTools) {
dirList.on('treelistselect', function(event, item) {
if (item.writable !== false && item.treeList) {
if (itemTools) {
itemTools.remove();
}
itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
.on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
var elementPos = menuButton.offset();
var menuOptionMenu
= RED.menu.init({id:"red-ui-library-browser-menu",
options: [
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
var defaultFolderName = "new-folder";
var defaultFolderNameMatches = {};
var selected = dirList.treeList('selected');
if (!selected.children) {
selected = selected.parent;
}
var complete = function() {
selected.children.forEach(function(c) {
if (/^new-folder/.test(c.label)) {
defaultFolderNameMatches[c.label] = true
}
});
var folderIndex = 2;
while(defaultFolderNameMatches[defaultFolderName]) {
defaultFolderName = "new-folder-"+(folderIndex++)
}
selected.treeList.expand();
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
var newItem = {
icon: "fa fa-folder-o",
children:[],
path: selected.path,
element: input
}
var confirmAdd = function() {
var val = input.val().trim();
if (val === "") {
cancelAdd();
return;
} else {
for (var i=0;i<selected.children.length;i++) {
if (selected.children[i].label === val) {
cancelAdd();
return;
}
}
}
newItem.treeList.remove();
var finalItem = {
library: selected.library,
type: selected.type,
icon: "fa fa-folder",
children:[],
label: val,
path: newItem.path+val+"/"
}
selected.treeList.addChild(finalItem,true);
}
var cancelAdd = function() {
newItem.treeList.remove();
}
input.on('keydown', function(evt) {
evt.stopPropagation();
if (evt.keyCode === 13) {
confirmAdd();
} else if (evt.keyCode === 27) {
cancelAdd();
}
})
input.on("blur", function() {
confirmAdd();
})
selected.treeList.addChild(newItem);
setTimeout(function() {
input.trigger("focus");
input.select();
},400);
}
selected.treeList.expand(complete);
} },
// null,
// {id:"red-ui-library-browser-menu-rename",label:"Rename", onselect: function() {} },
// {id:"red-ui-library-browser-menu-delete",label:"Delete", onselect: function() {} }
]
}).on('mouseleave', function(){ $(this).remove(); dirList.focus() })
.on('mouseup', function() { var self = $(this);self.hide(); dirList.focus(); setTimeout(function() { self.remove() },100)})
.appendTo("body");
menuOptionMenu.css({
position: "absolute",
top: elementPos.top+"px",
left: (elementPos.left - menuOptionMenu.width() + 20)+"px"
}).show();
}).appendTo(itemTools);
itemTools.appendTo(item.treeList.label);
}
});
@@ -536,7 +542,7 @@ RED.library = (function() {
// evt.preventDefault();
// var icon = libraryFields['icon'].input.val() || "";
// var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
// RED.editor.showIconPicker(iconButton, null, iconPath, true, function (newIcon) {
// RED.editor.iconPicker.show(iconButton, null, iconPath, true, function (newIcon) {
// iconButton.empty();
// var path = newIcon || "";
// var newPath = RED.utils.separateIconPath(path);

View File

@@ -45,6 +45,22 @@ RED.notifications = (function() {
var persistentNotifications = {};
var shade = (function() {
var shadeUsers = 0;
return {
show: function() {
shadeUsers++;
$("#red-ui-full-shade").show();
},
hide: function() {
shadeUsers--;
if (shadeUsers === 0) {
$("#red-ui-full-shade").hide();
}
}
}
})();
var currentNotifications = [];
var c = 0;
function notify(msg,type,fixed,timeout) {
@@ -54,6 +70,10 @@ RED.notifications = (function() {
fixed = options.fixed;
timeout = options.timeout;
type = options.type;
} else {
options.type = type;
options.fixed = fixed;
options.timeout = options.timeout;
}
if (options.id && persistentNotifications.hasOwnProperty(options.id)) {
@@ -62,7 +82,7 @@ RED.notifications = (function() {
}
if (options.modal) {
$("#red-ui-full-shade").show();
shade.show();
}
if (currentNotifications.length > 4) {
@@ -79,6 +99,8 @@ RED.notifications = (function() {
var n = document.createElement("div");
n.id="red-ui-notification-"+c;
n.className = "red-ui-notification";
n.options = options;
n.fixed = fixed;
if (type) {
n.className = "red-ui-notification red-ui-notification-"+type;
@@ -115,7 +137,6 @@ RED.notifications = (function() {
})
}
$("#red-ui-notifications").append(n);
if (!RED.notifications.hide) {
$(n).slideDown(300);
@@ -141,8 +162,8 @@ RED.notifications = (function() {
} else {
nn.parentNode.removeChild(nn);
}
if (options.modal) {
$("#red-ui-full-shade").hide();
if (nn.options.modal) {
shade.hide();
}
};
})();
@@ -173,7 +194,7 @@ RED.notifications = (function() {
n.update = (function() {
var nn = n;
return function(msg,options) {
return function(msg,newOptions) {
if (typeof msg === "string") {
if (!/<p>/i.test(msg)) {
msg = "<p>"+msg+"</p>";
@@ -182,16 +203,31 @@ RED.notifications = (function() {
} else {
$(nn).empty().append(msg);
}
var timeout;
if (typeof options === 'number') {
timeout = options;
} else if (options !== undefined) {
if (!options.fixed) {
timeout = options.timeout || 5000;
var newTimeout;
if (typeof newOptions === 'number') {
newTimeout = newOptions;
nn.options.timeout = newTimeout;
} else if (newOptions !== undefined) {
if (!options.modal && newOptions.modal) {
nn.options.modal = true;
shade.show();
} else if (options.modal && newOptions.modal === false) {
nn.options.modal = false;
shade.hide();
}
if (options.buttons) {
var newType = newOptions.hasOwnProperty('type')?newOptions.type:type;
if (newType) {
n.className = "red-ui-notification red-ui-notification-"+newType;
}
if (!fixed || newOptions.fixed === false) {
newTimeout = (newOptions.hasOwnProperty('timeout')?newOptions.timeout:timeout)||5000;
}
if (newOptions.buttons) {
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(nn)
options.buttons.forEach(function(buttonDef) {
newOptions.buttons.forEach(function(buttonDef) {
var b = $('<button>').text(buttonDef.text).on("click", buttonDef.click).appendTo(buttonSet);
if (buttonDef.id) {
b.attr('id',buttonDef.id);
@@ -202,15 +238,22 @@ RED.notifications = (function() {
})
}
}
if (timeout !== undefined && timeout > 0) {
$(nn).off("click.red-ui-notification-close");
if (newTimeout !== undefined && newTimeout > 0) {
window.clearTimeout(nn.timeoutid);
nn.timeoutid = window.setTimeout(nn.close,timeout);
nn.timeoutid = window.setTimeout(nn.close,newTimeout);
setTimeout(function() {
$(nn).on("click.red-ui-notification-close", function() {
nn.close();
window.clearTimeout(nn.timeoutid);
});
},50);
} else {
window.clearTimeout(nn.timeoutid);
}
if (nn.hidden) {
nn.showNotification();
} else if (!options || !options.silent){
} else if (!newOptions || !newOptions.silent){
$(nn).addClass("red-ui-notification-shake-horizontal");
setTimeout(function() {
$(nn).removeClass("red-ui-notification-shake-horizontal");
@@ -221,7 +264,7 @@ RED.notifications = (function() {
})();
if (!fixed) {
$(n).on("click", (function() {
$(n).on("click.red-ui-notification-close", (function() {
var nn = n;
return function() {
nn.close();

View File

@@ -333,7 +333,10 @@ RED.palette.editor = (function() {
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
nodeEntry.updateButton.text(RED._('palette.editor.updated')).addClass('disabled').css('display', 'inline-block');
} else if (loadedIndex.hasOwnProperty(module)) {
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) > 0) {
if (updateAllowed &&
semVerCompare(loadedIndex[module].version,moduleInfo.version) > 0 &&
RED.utils.checkModuleAllowed(module,null,updateAllowList,updateDenyList)
) {
nodeEntry.updateButton.show();
nodeEntry.updateButton.text(RED._('palette.editor.update',{version:loadedIndex[module].version}));
} else {
@@ -484,6 +487,9 @@ RED.palette.editor = (function() {
var installAllowList = ['*'];
var installDenyList = [];
var updateAllowed = true;
var updateAllowList = ['*'];
var updateDenyList = [];
function init() {
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
@@ -498,6 +504,17 @@ RED.palette.editor = (function() {
installAllowList = RED.utils.parseModuleList(installAllowList);
installDenyList = RED.utils.parseModuleList(installDenyList);
var settingsUpdateAllowList = RED.settings.get("externalModules.palette.allowUpdateList")
var settingsUpdateDenyList = RED.settings.get("externalModules.palette.denyUpdateList")
if (settingsUpdateAllowList || settingsUpdateDenyList) {
updateAllowList = settingsUpdateAllowList;
updateDenyList = settingsUpdateDenyList;
}
updateAllowList = RED.utils.parseModuleList(updateAllowList);
updateDenyList = RED.utils.parseModuleList(updateDenyList);
updateAllowed = RED.settings.get("externalModules.palette.allowUpdate",true);
createSettingsPane();
RED.userSettings.add({

View File

@@ -208,7 +208,7 @@ RED.palette = (function() {
}
function escapeCategory(category) {
return category.replace(/[ /.]/g,"_");
return category.replace(/[\x00-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]/g,"_");
}
function addNodeType(nt,def) {
if (getPaletteNode(nt).length) {

View File

@@ -1212,6 +1212,9 @@ RED.projects = (function() {
}
}).appendTo(row);
row = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-open"></div>').hide().appendTo(container);
$('<span style="display: flex; align-items: center;"><input style="padding:0; margin: 0 5px 0 0" checked type="checkbox" id="red-ui-projects-dialog-screen-clear-context"> <label for="red-ui-projects-dialog-screen-clear-context" style="padding:0; margin: 0"> <span data-i18n="projects.create.clearContext"></span></label></span>').appendTo(row).i18n();
row = $('<div class="form-row red-ui-projects-dialog-screen-create-row red-ui-projects-dialog-screen-create-row-empty red-ui-projects-dialog-screen-create-row-clone"></div>').appendTo(container);
$('<label for="red-ui-projects-dialog-screen-create-project-name">'+RED._("projects.create.project-name")+'</label>').appendTo(row);
@@ -1501,7 +1504,8 @@ RED.projects = (function() {
};
}
} else if (projectType === 'open') {
return switchProject(selectedProject.name,function(err,data) {
var clearContext = $("#red-ui-projects-dialog-screen-clear-context").prop("checked")
return switchProject(selectedProject.name, clearContext, function(err,data) {
if (err) {
if (err.code !== 'credentials_load_failed') {
console.log(RED._("projects.create.unexpected_error"),err)
@@ -1595,7 +1599,7 @@ RED.projects = (function() {
}
}
function switchProject(name,done) {
function switchProject(name,clearContext,done) {
RED.deploy.setDeployInflight(true);
RED.projects.settings.switchProject(name);
sendRequest({
@@ -1614,7 +1618,7 @@ RED.projects = (function() {
'*': done
},
}
},{active:true}).then(function() {
},{active:true, clearContext:clearContext}).then(function() {
dialog.dialog( "close" );
RED.events.emit("project:change", {name:name});
}).always(function() {
@@ -1687,7 +1691,7 @@ RED.projects = (function() {
dialogHeight = 590 - (750 - winHeight);
}
$(".red-ui-projects-dialog-box").height(dialogHeight);
$(".red-ui-projects-dialog-project-list-inner-container").height(Math.max(500,dialogHeight) - 180);
$(".red-ui-projects-dialog-project-list-inner-container").height(Math.max(500,dialogHeight) - 210);
dialog.dialog('option','title',screen.title||"");
dialog.dialog("open");
}
@@ -2387,6 +2391,7 @@ RED.projects = (function() {
return {
init: init,
showStartup: function() {
console.warn("showStartup")
if (!RED.user.hasPermission("projects.write")) {
RED.notify(RED._("user.errors.notAuthorized"),"error");
return;

View File

@@ -22,6 +22,7 @@ RED.search = (function() {
var selected = -1;
var visible = false;
var searchHistory = [];
var index = {};
var currentResults = [];
var previousActiveElement;
@@ -52,10 +53,22 @@ RED.search = (function() {
}
l = l||n.label||n.name||n.id||"";
var properties = ['id','type','name','label','info'];
if (n._def && n._def.defaults) {
properties = properties.concat(Object.keys(n._def.defaults));
const node_def = n && n._def;
if (node_def) {
if (node_def.defaults) {
properties = properties.concat(Object.keys(node_def.defaults));
}
if (n.type !== "group" && node_def.paletteLabel && node_def.paletteLabel !== node_def.type) {
try {
const label = ("" + (typeof node_def.paletteLabel === "function" ? node_def.paletteLabel.call(node_def) : node_def.paletteLabel)).toLowerCase();
if(label && label !== (""+node_def.type).toLowerCase()) {
indexProperty(n, l, label);
}
} catch(err) {
console.warn(`error indexing ${l}`, err);
}
}
}
for (var i=0;i<properties.length;i++) {
if (n.hasOwnProperty(properties[i])) {
@@ -105,6 +118,7 @@ RED.search = (function() {
val = extractFlag(val,"unused",flags);
val = extractFlag(val,"config",flags);
val = extractFlag(val,"subflow",flags);
val = extractFlag(val,"hidden",flags);
// uses:<node-id>
val = extractValue(val,"uses",flags);
@@ -127,7 +141,7 @@ RED.search = (function() {
var key = keys[i];
var kpos = keys[i].indexOf(val);
if (kpos > -1) {
var ids = Object.keys(index[key]);
var ids = Object.keys(index[key]||{});
for (j=0;j<ids.length;j++) {
var node = index[key][ids[j]];
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
@@ -150,7 +164,15 @@ RED.search = (function() {
continue;
}
}
if (flags.hasOwnProperty("hidden")) {
// Only tabs can be hidden
if (node.node.type !== 'tab') {
continue
}
if (!RED.workspaces.isHidden(node.node.id)) {
continue
}
}
if (flags.hasOwnProperty("unused")) {
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0)
@@ -196,6 +218,20 @@ RED.search = (function() {
}
}
function populateSearchHistory() {
if (searchHistory.length > 0) {
searchResults.editableList('addItem',{
historyHeader: true
});
searchHistory.forEach(function(entry) {
searchResults.editableList('addItem',{
history: true,
value: entry
});
})
}
}
function createDialog() {
dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#red-ui-main-container");
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
@@ -204,9 +240,14 @@ RED.search = (function() {
change: function() {
searchResults.editableList('empty');
selected = -1;
currentResults = search($(this).val());
var value = $(this).val();
if (value === "") {
populateSearchHistory();
return;
}
currentResults = search(value);
if (currentResults.length > 0) {
for (i=0;i<Math.min(currentResults.length,25);i++) {
for (let i=0;i<Math.min(currentResults.length,25);i++) {
searchResults.editableList('addItem',currentResults[i])
}
if (currentResults.length > 25) {
@@ -276,7 +317,12 @@ RED.search = (function() {
})
}
}
} else {
} if ($(children[selected]).hasClass("red-ui-search-history")) {
var object = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
if (object) {
searchInput.searchBox('value',object.value)
}
} else if (!$(children[selected]).hasClass("red-ui-search-historyHeader")) {
if (currentResults.length > 0) {
reveal(currentResults[Math.max(0,selected)].node);
}
@@ -292,7 +338,32 @@ RED.search = (function() {
addItem: function(container,i,object) {
var node = object.node;
var div;
if (object.more) {
if (object.historyHeader) {
container.parent().addClass("red-ui-search-historyHeader")
$('<div>',{class:"red-ui-search-empty"}).text(RED._("search.history")).appendTo(container);
$('<button type="button" class="red-ui-button red-ui-button-small"></button>').text(RED._("search.clear")).appendTo(container).on("click", function(evt) {
evt.preventDefault();
searchHistory = [];
searchResults.editableList('empty');
});
} else if (object.history) {
container.parent().addClass("red-ui-search-history")
div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
div.text(object.value);
div.on("click", function(evt) {
evt.preventDefault();
searchInput.searchBox('value',object.value)
searchInput.focus();
})
$('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-remove"></i></button>').appendTo(container).on("click", function(evt) {
evt.preventDefault();
var index = searchHistory.indexOf(object.value);
searchHistory.splice(index,1);
searchResults.editableList('removeItem', object);
});
} else if (object.more) {
container.parent().addClass("red-ui-search-more")
div = $('<a>',{href:'#',class:"red-ui-search-result red-ui-search-empty"}).appendTo(container);
div.text(RED._("palette.editor.more",{count:object.more.results.length-object.more.start}));
@@ -347,6 +418,12 @@ RED.search = (function() {
}
function reveal(node) {
var searchVal = searchInput.val();
var existingIndex = searchHistory.indexOf(searchVal);
if (existingIndex > -1) {
searchHistory.splice(existingIndex,1);
}
searchHistory.unshift(searchInput.val());
hide();
RED.view.reveal(node.id);
}
@@ -365,9 +442,14 @@ RED.search = (function() {
if (dialog === null) {
createDialog();
} else {
searchResults.editableList('empty');
}
dialog.slideDown(300);
searchInput.searchBox('value',v)
if (!v || v === "") {
populateSearchHistory();
}
RED.events.emit("search:open");
visible = true;
}

View File

@@ -19,6 +19,15 @@ RED.sidebar = (function() {
var sidebar_tabs;
var knownTabs = {};
// We store the current sidebar tab id in localStorage as 'last-sidebar-tab'
// This is restored when the editor is reloaded.
// We use sidebar_tabs.onchange to update localStorage. However that will
// also get triggered when the first tab gets added to the tabs - typically
// the 'info' tab. So we use the following variable to store the retrieved
// value from localStorage before we start adding the actual tabs
var lastSessionSelectedTab = null;
function addTab(title,content,closeable,visible) {
var options;
if (typeof title === "string") {
@@ -194,16 +203,16 @@ RED.sidebar = (function() {
RED.events.emit("sidebar:resize");
}
function showSidebar(id) {
function showSidebar(id, skipShowSidebar) {
if (id === ":first") {
id = RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])[0]
id = lastSessionSelectedTab || RED.settings.get("editor.sidebar.order",["info", "help", "version-control", "debug"])[0]
}
if (id) {
if (!containsTab(id) && knownTabs[id]) {
sidebar_tabs.addTab(knownTabs[id]);
}
sidebar_tabs.activateTab(id);
if (!RED.menu.isSelected("menu-item-sidebar")) {
if (!skipShowSidebar && !RED.menu.isSelected("menu-item-sidebar")) {
RED.menu.setSelected("menu-item-sidebar",true);
}
}
@@ -227,6 +236,7 @@ RED.sidebar = (function() {
if (tab.toolbar) {
$(tab.toolbar).show();
}
RED.settings.setLocal("last-sidebar-tab", tab.id)
},
onremove: function(tab) {
$(tab.wrapper).hide();
@@ -255,7 +265,9 @@ RED.sidebar = (function() {
}
});
RED.popover.tooltip($("#red-ui-sidebar-separator").find(".red-ui-sidebar-control-right"),RED._("keyboard.toggleSidebar"),"core:toggle-sidebar");
showSidebar();
lastSessionSelectedTab = RED.settings.getLocal("last-sidebar-tab")
RED.sidebar.info.init();
RED.sidebar.help.init();
RED.sidebar.config.init();

View File

@@ -27,5 +27,7 @@ RED.state = {
PANNING: 10,
SELECTING_NODE: 11,
GROUP_DRAGGING: 12,
GROUP_RESIZE: 13
GROUP_RESIZE: 13,
DETACHED_DRAGGING: 14,
SLICING: 15
}

View File

@@ -16,8 +16,6 @@
RED.subflow = (function() {
var currentLocale = "en-US";
var _subflowEditTemplate = '<script type="text/x-red" data-template-name="subflow">'+
'<div class="form-row">'+
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
@@ -37,7 +35,7 @@ RED.subflow = (function() {
'<div id="subflow-env-tabs-content">'+
'<div id="subflow-env-tab-edit">'+
'<div class="form-row node-input-env-container-row" id="subflow-input-edit-ui">'+
'<ol class="red-ui-editor-subflow-env-list" id="node-input-env-container"></ol>'+
'<ol id="node-input-env-container"></ol>'+
'<div class="node-input-env-locales-row"><i class="fa fa-language"></i> <select id="subflow-input-env-locale"></select></div>'+
'</div>'+
'</div>'+
@@ -47,37 +45,6 @@ RED.subflow = (function() {
'</div>'+
'</script>';
var _subflowModulePaneTemplate = '<form class="dialog-form form-horizontal" autocomplete="off">'+
'<div class="form-row">'+
'<label for="subflow-input-module-module" data-i18n="[append]editor:subflow.module"><i class="fa fa-cube"></i> </label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-module" data-i18n="[placeholder]common.label.name">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-type" data-i18n="[append]editor:subflow.type"> </label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-type">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-version" data-i18n="[append]editor:subflow.version"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-version" data-i18n="[placeholder]editor:subflow.versionPlaceholder">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-desc" data-i18n="[append]editor:subflow.desc"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-desc">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-license" data-i18n="[append]editor:subflow.license"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-license">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-author" data-i18n="[append]editor:subflow.author"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-author" data-i18n="[placeholder]editor:subflow.authorPlaceholder">'+
'</div>'+
'<div class="form-row">'+
'<label for="subflow-input-module-keywords" data-i18n="[append]editor:subflow.keys"></label>'+
'<input style="width: calc(100% - 110px)" type="text" id="subflow-input-module-keywords" data-i18n="[placeholder]editor:subflow.keysPlaceholder">'+
'</div>'+
'</form>';
function findAvailableSubflowIOPosition(subflow,isInput) {
var pos = {x:50,y:30};
if (!isInput) {
@@ -909,7 +876,6 @@ RED.subflow = (function() {
* Create interface for controlling env var UI definition
*/
function buildEnvControl(envList,node) {
var tabs = RED.tabs.create({
id: "subflow-env-tabs",
onchange: function(tab) {
@@ -950,588 +916,11 @@ RED.subflow = (function() {
locales.val(locale);
locales.on("change", function() {
currentLocale = $(this).val();
var items = $("#node-input-env-container").editableList("items");
items.each(function (i, item) {
var entry = $(this).data('data');
var labelField = entry.ui.labelField;
labelField.val(lookupLabel(entry.ui.label, "", currentLocale));
if (labelField.timeout) {
clearTimeout(labelField.timeout);
delete labelField.timeout;
}
labelField.addClass("input-updated");
labelField.timeout = setTimeout(function() {
delete labelField.timeout
labelField.removeClass("input-updated");
},3000);
});
RED.editor.envVarList.setLocale($(this).val(), $("#node-input-env-container"));
});
RED.editor.envVarList.setLocale(locale);
}
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
/**
* Create env var edit interface
* @param container - container
* @param node - subflow node
*/
function buildPropertiesList(envContainer, node) {
var isTemplateNode = (node.type === "subflow");
if (isTemplateNode) {
buildEnvControl(envContainer, node);
}
envContainer
.css({
'min-height':'150px',
'min-width':'450px'
})
.editableList({
header: isTemplateNode?$('<div><div><div></div><div data-i18n="common.label.name"></div><div data-i18n="editor-tab.defaultValue"></div><div></div></div></div>'):undefined,
addItem: function(container, i, opt) {
// If this is an instance node, these are properties unique to
// this instance - ie opt.parent will not be defined.
if (isTemplateNode) {
container.addClass("red-ui-editor-subflow-env-editable")
}
var envRow = $('<div/>').appendTo(container);
var nameField = null;
var valueField = null;
nameField = $('<input/>', {
class: "node-input-env-name",
type: "text",
placeholder: RED._("common.label.name")
}).attr("autocomplete","disable").appendTo(envRow).val(opt.name);
valueField = $('<input/>',{
style: "width:100%",
class: "node-input-env-value",
type: "text",
}).attr("autocomplete","disable").appendTo(envRow)
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
valueField.typedInput('type', opt.type);
if (opt.type === "cred") {
if (opt.value) {
valueField.typedInput('value', opt.value);
} else if (node.credentials && node.credentials[opt.name]) {
valueField.typedInput('value', node.credentials[opt.name]);
} else if (node.credentials && node.credentials['has_'+opt.name]) {
valueField.typedInput('value', "__PWRD__");
} else {
valueField.typedInput('value', "");
}
} else {
valueField.typedInput('value', opt.value);
}
opt.nameField = nameField;
opt.valueField = valueField;
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(envRow);
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
actionButton.on("click", function(evt) {
evt.preventDefault();
removeTip.close();
container.parent().addClass("red-ui-editableList-item-deleting")
container.fadeOut(300, function() {
envContainer.editableList('removeItem',opt);
});
});
if (isTemplateNode) {
// Add the UI customisation row
// if `opt.ui` does not exist, then apply defaults. If these
// defaults do not change then they will get stripped off
// before saving.
if (opt.type === 'cred') {
opt.ui = opt.ui || {
icon: "",
type: "cred"
}
opt.ui.type = "cred";
} else {
opt.ui = opt.ui || {
icon: "",
type: "input",
opts: {types:DEFAULT_ENV_TYPE_LIST}
}
}
opt.ui.label = opt.ui.label || {};
opt.ui.type = opt.ui.type || "input";
var uiRow = $('<div/>').appendTo(container).hide();
// save current info for reverting on cancel
// var copy = $.extend(true, {}, ui);
$('<a href="#"><i class="fa fa-angle-right"></a>').prependTo(envRow).on("click", function (evt) {
evt.preventDefault();
if ($(this).hasClass('expanded')) {
uiRow.slideUp();
$(this).removeClass('expanded');
} else {
uiRow.slideDown();
$(this).addClass('expanded');
}
});
buildEnvEditRow(uiRow, opt.ui, nameField, valueField);
nameField.trigger('change');
}
},
sortable: ".red-ui-editableList-item-handle",
removable: false
});
var parentEnv = {};
var envList = [];
if (/^subflow:/.test(node.type)) {
var subflowDef = RED.nodes.subflow(node.type.substring(8));
if (subflowDef.env) {
subflowDef.env.forEach(function(env) {
var item = {
name:env.name,
parent: {
type: env.type,
value: env.value,
ui: env.ui
}
}
envList.push(item);
parentEnv[env.name] = item;
})
}
}
if (node.env) {
for (var i = 0; i < node.env.length; i++) {
var env = node.env[i];
if (parentEnv.hasOwnProperty(env.name)) {
parentEnv[env.name].type = env.type;
parentEnv[env.name].value = env.value;
} else {
envList.push({
name: env.name,
type: env.type,
value: env.value,
ui: env.ui
});
}
}
}
envList.forEach(function(env) {
if (env.parent && env.parent.ui && env.parent.ui.type === 'hide') {
return;
}
if (!isTemplateNode && env.parent) {
return;
}
envContainer.editableList('addItem', JSON.parse(JSON.stringify(env)));
});
}
/**
* Create UI edit interface for environment variable
* @param container - container
* @param env - env var definition
* @param nameField - name field of env var
* @param valueField - value field of env var
*/
function buildEnvEditRow(container, ui, nameField, valueField) {
container.addClass("red-ui-editor-subflow-env-ui-row")
var topRow = $('<div></div>').appendTo(container);
$('<div></div>').appendTo(topRow);
$('<div>').text(RED._("editor.icon")).appendTo(topRow);
$('<div>').text(RED._("editor.label")).appendTo(topRow);
$('<div>').text(RED._("editor.inputType")).appendTo(topRow);
var row = $('<div></div>').appendTo(container);
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
var typeOptions = {
'input': {types:DEFAULT_ENV_TYPE_LIST},
'select': {opts:[]},
'spinner': {},
'cred': {}
};
if (ui.opts) {
typeOptions[ui.type] = ui.opts;
} else {
// Pick up the default values if not otherwise provided
ui.opts = typeOptions[ui.type];
}
var iconCell = $('<div></div>').appendTo(row);
var iconButton = $('<a href="#"></a>').appendTo(iconCell);
iconButton.on("click", function(evt) {
evt.preventDefault();
var icon = ui.icon || "";
var iconPath = (icon ? RED.utils.separateIconPath(icon) : {});
RED.editor.showIconPicker(iconButton, null, iconPath, true, function (newIcon) {
iconButton.empty();
var path = newIcon || "";
var newPath = RED.utils.separateIconPath(path);
if (newPath) {
$('<i class="fa"></i>').addClass(newPath.file).appendTo(iconButton);
}
ui.icon = path;
});
})
if (ui.icon) {
var newPath = RED.utils.separateIconPath(ui.icon);
$('<i class="fa '+newPath.file+'"></i>').appendTo(iconButton);
}
var labelCell = $('<div></div>').appendTo(row);
var label = ui.label && ui.label[currentLocale] || "";
var labelInput = $('<input type="text">').val(label).appendTo(labelCell);
ui.labelField = labelInput;
labelInput.on('change', function(evt) {
ui.label = ui.label || {};
var val = $(this).val().trim();
if (val === "") {
delete ui.label[currentLocale];
} else {
ui.label[currentLocale] = val;
}
})
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelCell);
RED.popover.tooltip(labelIcon,function() {
var langs = Object.keys(ui.label);
var content = $("<div>");
if (langs.indexOf(currentLocale) === -1) {
langs.push(currentLocale);
langs.sort();
}
langs.forEach(function(l) {
var row = $('<div>').appendTo(content);
$('<span>').css({display:"inline-block",width:"120px"}).text(RED._("languages."+l)+(l===currentLocale?"*":"")).appendTo(row);
$('<span>').text(ui.label[l]||"").appendTo(row);
});
return content;
})
nameField.on('change',function(evt) {
labelInput.attr("placeholder",$(this).val())
});
var inputCell = $('<div></div>').appendTo(row);
var inputCellInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
if (ui.type === "input") {
inputCellInput.val(ui.opts.types.join(","));
}
var checkbox;
var selectBox;
inputCellInput.typedInput({
types: [
{
value:"input",
label:RED._("editor.inputs.input"), icon:"fa fa-i-cursor",showLabel:false,multiple:true,options:[
{value:"str",label:RED._("editor.types.str"),icon:"red/images/typedInput/az.svg"},
{value:"num",label:RED._("editor.types.num"),icon:"red/images/typedInput/09.svg"},
{value:"bool",label:RED._("editor.types.bool"),icon:"red/images/typedInput/bool.svg"},
{value:"json",label:RED._("editor.types.json"),icon:"red/images/typedInput/json.svg"},
{value: "bin",label: RED._("editor.types.bin"),icon: "red/images/typedInput/bin.svg"},
{value: "env",label: RED._("editor.types.env"),icon: "red/images/typedInput/env.svg"},
{value: "cred",label: RED._("editor.types.cred"),icon: "fa fa-lock"}
],
default: DEFAULT_ENV_TYPE_LIST,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
if (value.length) {
value.forEach(function(v) {
if (!/^fa /.test(v.icon)) {
$('<img>',{src:v.icon,style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
} else {
var s = $('<span>',{style:"max-width:14px; padding: 0 3px; margin-top:-4px; margin-left: 1px"}).appendTo(input);
$("<i>",{class: v.icon}).appendTo(s);
}
})
} else {
$('<span class="red-ui-editor-subflow-env-input-type-placeholder"></span>').text(RED._("editor.selectType")).appendTo(input);
}
}
},
{
value: "cred",
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type">').css({
"border-top-right-radius": "4px",
"border-bottom-right-radius": "4px"
}).appendTo(container);
$('<div class="placeholder-input">').html("&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;").appendTo(innerContainer);
}
},
{
value:"select",
label:RED._("editor.inputs.select"), icon:"fa fa-tasks",showLabel:false,
valueLabel: function(container,value) {
container.css("padding","0");
selectBox = $('<select></select>').appendTo(container);
if (ui.opts && Array.isArray(ui.opts.opts)) {
ui.opts.opts.forEach(function(o) {
var label = lookupLabel(o.l, o.l["en-US"]||o.v, currentLocale);
// $('<option>').val((o.t||'str')+":"+o.v).text(label).appendTo(selectBox);
$('<option>').val(o.v).text(label).appendTo(selectBox);
})
}
selectBox.on('change', function(evt) {
var v = selectBox.val();
// var parts = v.split(":");
// var t = parts.shift();
// v = parts.join(":");
//
// valueField.typedInput("type",'str')
valueField.typedInput("value",v)
});
selectBox.val(valueField.typedInput("value"));
// selectBox.val(valueField.typedInput('type')+":"+valueField.typedInput("value"));
},
expand: {
icon: "fa-caret-down",
minWidth: 400,
content: function(container) {
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
var optList = $('<ol>').appendTo(content).editableList({
header:$("<div><div>"+RED._("editor.select.label")+"</div><div>"+RED._("editor.select.value")+"</div></div>"),
addItem: function(row,index,itemData) {
var labelDiv = $('<div>').appendTo(row);
var label = lookupLabel(itemData.l, "", currentLocale);
itemData.label = $('<input type="text">').val(label).appendTo(labelDiv);
itemData.label.on('keydown', function(evt) {
if (evt.keyCode === 13) {
itemData.input.focus();
evt.preventDefault();
}
});
var labelIcon = $('<span class="red-ui-editor-subflow-env-lang-icon"><i class="fa fa-language"></i></span>').appendTo(labelDiv);
RED.popover.tooltip(labelIcon,function() {
return currentLocale;
})
itemData.input = $('<input type="text">').val(itemData.v).appendTo(row);
// Problem using a TI here:
// - this is in a popout panel
// - clicking the expand button in the TI will close the parent edit tray
// and open the type editor.
// - but it leaves the popout panel over the top.
// - there is no way to get back to the popout panel after closing the type editor
//.typedInput({default:itemData.t||'str', types:DEFAULT_ENV_TYPE_LIST});
itemData.input.on('keydown', function(evt) {
if (evt.keyCode === 13) {
// Enter or Tab
var index = optList.editableList('indexOf',itemData);
var length = optList.editableList('length');
if (index + 1 === length) {
var newItem = {};
optList.editableList('addItem',newItem);
setTimeout(function() {
if (newItem.label) {
newItem.label.focus();
}
},100)
} else {
var nextItem = optList.editableList('getItemAt',index+1);
if (nextItem.label) {
nextItem.label.focus()
}
}
evt.preventDefault();
}
});
},
sortable: true,
removable: true,
height: 160
})
if (ui.opts.opts.length > 0) {
ui.opts.opts.forEach(function(o) {
optList.editableList('addItem',$.extend(true,{},o))
})
} else {
optList.editableList('addItem',{})
}
return {
onclose: function() {
var items = optList.editableList('items');
var vals = [];
items.each(function (i,el) {
var data = el.data('data');
var l = data.label.val().trim();
var v = data.input.val();
// var t = data.input.typedInput('type');
// var v = data.input.typedInput('value');
if (l.length > 0) {
data.l = data.l || {};
data.l[currentLocale] = l;
}
data.v = v;
if (l.length > 0 || v.length > 0) {
var val = {l:data.l,v:data.v};
// if (t !== 'str') {
// val.t = t;
// }
vals.push(val);
}
});
ui.opts.opts = vals;
inputCellInput.typedInput('value',Date.now())
}
}
}
}
},
{
value:"checkbox",
label:RED._("editor.inputs.checkbox"), icon:"fa fa-check-square-o",showLabel:false,
valueLabel: function(container,value) {
container.css("padding",0);
checkbox = $('<input type="checkbox">').appendTo(container);
checkbox.on('change', function(evt) {
valueField.typedInput('value',$(this).prop('checked')?"true":"false");
})
checkbox.prop('checked',valueField.typedInput('value')==="true");
}
},
{
value:"spinner",
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
var min = ui.opts && ui.opts.min;
var max = ui.opts && ui.opts.max;
var label = "";
if (min !== undefined && max !== undefined) {
label = Math.min(min,max)+" - "+Math.max(min,max);
} else if (min !== undefined) {
label = "> "+min;
} else if (max !== undefined) {
label = "< "+max;
}
$('<span>').css("margin-left","15px").text(label).appendTo(input);
},
expand: {
icon: "fa-caret-down",
content: function(container) {
var content = $('<div class="red-ui-editor-subflow-ui-edit-panel">').appendTo(container);
content.css("padding","8px 5px")
var min = ui.opts.min;
var max = ui.opts.max;
var minInput = $('<input type="number" style="margin-bottom:0; width:60px">');
minInput.val(min);
var maxInput = $('<input type="number" style="margin-bottom:0; width:60px">');
maxInput.val(max);
$('<div class="form-row" style="margin-bottom:3px"><label>'+RED._("editor.spinner.min")+'</label></div>').append(minInput).appendTo(content);
$('<div class="form-row" style="margin-bottom:0"><label>'+RED._("editor.spinner.max")+'</label></div>').append(maxInput).appendTo(content);
return {
onclose: function() {
var min = minInput.val().trim();
var max = maxInput.val().trim();
if (min !== "") {
ui.opts.min = parseInt(min);
} else {
delete ui.opts.min;
}
if (max !== "") {
ui.opts.max = parseInt(max);
} else {
delete ui.opts.max;
}
inputCellInput.typedInput('value',Date.now())
}
}
}
}
},
{
value:"none",
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
},
{
value:"hide",
label:RED._("editor.inputs.hidden"), icon:"fa fa-ban",hasValue:false
}
],
default: 'none'
}).on("typedinputtypechange", function(evt,type) {
ui.type = $(this).typedInput("type");
ui.opts = typeOptions[ui.type];
if (ui.type === 'input') {
// In the case of 'input' type, the typedInput uses the multiple-option
// mode. Its value needs to be set to a comma-separately list of the
// selected options.
inputCellInput.typedInput('value',ui.opts.types.join(","))
} else {
// No other type cares about `value`, but doing this will
// force a refresh of the label now that `ui.opts` has
// been updated.
inputCellInput.typedInput('value',Date.now())
}
switch (ui.type) {
case 'input':
valueField.typedInput('types',ui.opts.types);
break;
case 'select':
valueField.typedInput('types',['str']);
break;
case 'checkbox':
valueField.typedInput('types',['bool']);
break;
case 'spinner':
valueField.typedInput('types',['num']);
break;
case 'cred':
valueField.typedInput('types',['cred']);
break;
default:
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
}
if (ui.type === 'checkbox') {
valueField.typedInput('type','bool');
} else if (ui.type === 'spinner') {
valueField.typedInput('type','num');
}
if (ui.type !== 'checkbox') {
checkbox = null;
}
}).on("change", function(evt,type) {
if (ui.type === 'input') {
var types = inputCellInput.typedInput('value');
ui.opts.types = (types === "") ? ["str"] : types.split(",");
valueField.typedInput('types',ui.opts.types);
}
});
valueField.on("change", function(evt) {
if (checkbox) {
checkbox.prop('checked',$(this).typedInput('value')==="true")
}
})
// Set the input to the right type. This will trigger the 'typedinputtypechange'
// event handler (just above ^^) to update the value if needed
inputCellInput.typedInput('type',ui.type)
}
function buildEnvUIRow(row, tenv, ui, node) {
ui.label = ui.label||{};
@@ -1540,7 +929,7 @@ RED.subflow = (function() {
ui.opts = {};
} else if (!ui.type) {
ui.type = "input";
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
ui.opts = { types: RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST }
} else {
if (!ui.opts) {
ui.opts = (ui.type === "select") ? {opts:[]} : {};
@@ -1549,7 +938,7 @@ RED.subflow = (function() {
var labels = ui.label || {};
var locale = RED.i18n.lang();
var labelText = lookupLabel(labels, labels["en-US"]||tenv.name, locale);
var labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"]||tenv.name, locale);
var label = $('<label>').appendTo(row);
$('<span>&nbsp;</span>').appendTo(row);
var labelContainer = $('<span></span>').appendTo(label);
@@ -1594,6 +983,17 @@ RED.subflow = (function() {
default: inputType
})
input.typedInput('value',val.value)
if (inputType === 'cred') {
if (node.credentials) {
if (node.credentials[tenv.name]) {
input.typedInput('value', node.credentials[tenv.name]);
} else if (node.credentials['has_'+tenv.name]) {
input.typedInput('value', "__PWRD__")
} else {
input.typedInput('value', "");
}
}
}
} else {
input.val(val.value)
}
@@ -1602,7 +1002,7 @@ RED.subflow = (function() {
input = $('<select>').css('width','70%').appendTo(row);
if (ui.opts.opts) {
ui.opts.opts.forEach(function(o) {
$('<option>').val(o.v).text(lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
$('<option>').val(o.v).text(RED.editor.envVarList.lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
})
}
input.val(val.value);
@@ -1668,9 +1068,8 @@ RED.subflow = (function() {
* @param uiContainer - container for UI
* @param envList - env var definitions of template
*/
function buildEnvUI(uiContainer, envList,node) {
function buildEnvUI(uiContainer, envList, node) {
uiContainer.empty();
var elementID = 0;
for (var i = 0; i < envList.length; i++) {
var tenv = envList[i];
if (tenv.ui && tenv.ui.type === 'hide') {
@@ -1678,8 +1077,6 @@ RED.subflow = (function() {
}
var row = $("<div/>", { class: "form-row" }).appendTo(uiContainer);
buildEnvUIRow(row,tenv, tenv.ui || {}, node);
// console.log(ui);
}
}
// buildEnvUI
@@ -1715,7 +1112,7 @@ RED.subflow = (function() {
// icon: "",
// label: {},
// type: "input",
// opts: {types:DEFAULT_ENV_TYPE_LIST}
// opts: {types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST}
// }
if (!ui.icon) {
delete ui.icon;
@@ -1725,7 +1122,7 @@ RED.subflow = (function() {
}
switch (ui.type) {
case "input":
if (JSON.stringify(ui.opts) === JSON.stringify({types:DEFAULT_ENV_TYPE_LIST})) {
if (JSON.stringify(ui.opts) === JSON.stringify({types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST})) {
// This is the default input config. Delete it as it will
// be applied automatically
delete ui.type;
@@ -1841,7 +1238,6 @@ RED.subflow = (function() {
function exportSubflowInstanceEnv(node) {
var env = [];
// First, get the values for the SubflowTemplate defined properties
// - these are the ones with custom UI elements
var parentEnv = getSubflowInstanceParentEnv(node);
@@ -1853,7 +1249,7 @@ RED.subflow = (function() {
ui.type = "cred";
} else {
ui.type = "input";
ui.opts = {types:DEFAULT_ENV_TYPE_LIST}
ui.opts = {types:RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST}
}
} else {
ui.opts = ui.opts || {};
@@ -1893,22 +1289,6 @@ RED.subflow = (function() {
}
}
})
// Second, get the values from the Properties table tab
var items = $('#red-ui-editor-subflow-env-list').editableList('items');
items.each(function (i,el) {
var data = el.data('data');
var item;
if (data.nameField && data.valueField) {
item = {
name: data.nameField.val(),
value: data.valueField.typedInput("value"),
type: data.valueField.typedInput("type")
}
if (item.name.trim() !== "") {
env.push(item);
}
}
});
return env;
}
@@ -1916,164 +1296,18 @@ RED.subflow = (function() {
return 'node-input-subflow-env-'+name.replace(/[^a-z0-9-_]/ig,"_");
}
/**
* Lookup text for specific locale
* @param labels - dict of labels
* @param defaultLabel - fallback label if not found
* @param locale - target locale
* @returns {string} text for specified locale
*/
function lookupLabel(labels, defaultLabel, locale) {
if (labels) {
if (labels[locale]) {
return labels[locale];
}
if (locale) {
var lang = locale.substring(0, 2);
if (labels[lang]) {
return labels[lang];
}
}
}
return defaultLabel;
}
// Called by subflow.oneditprepare for both instances and templates
function buildEditForm(type,node) {
if (type === "subflow-template") {
buildPropertiesList($('#node-input-env-container'), node);
// This is the tabbed UI that offers the env list - with UI options
// plus the preview tab
buildEnvControl($('#node-input-env-container'), node);
RED.editor.envVarList.create($('#node-input-env-container'), node);
} else if (type === "subflow") {
// This gets called by the subflow type `oneditprepare` function
// registered in nodes.js#addSubflow()
// This is the rendered version of the subflow env var list
buildEnvUI($("#subflow-input-ui"), getSubflowInstanceParentEnv(node), node);
}
}
function buildPropertiesForm(node) {
var container = $('#editor-subflow-envProperties-content');
var form = $('<form class="dialog-form form-horizontal"></form>').appendTo(container);
var listContainer = $('<div class="form-row node-input-env-container-row"></div>').appendTo(form);
var list = $('<ol id="red-ui-editor-subflow-env-list" class="red-ui-editor-subflow-env-list"></ol>').appendTo(listContainer);
buildPropertiesList(list, node);
}
function setupInputValidation(input,validator) {
var errorTip;
var validateTimeout;
var validateFunction = function() {
if (validateTimeout) {
return;
}
validateTimeout = setTimeout(function() {
var error = validator(input.val());
// if (!error && errorTip) {
// errorTip.close();
// errorTip = null;
// } else if (error && !errorTip) {
// errorTip = RED.popover.create({
// tooltip: true,
// target:input,
// size: "small",
// direction: "bottom",
// content: error,
// }).open();
// }
input.toggleClass("input-error",!!error);
validateTimeout = null;
})
}
input.on("change keyup paste", validateFunction);
}
function buildModuleForm(container, node) {
$(_subflowModulePaneTemplate).appendTo(container);
var moduleProps = node.meta || {};
[
'module',
'type',
'version',
'author',
'desc',
'keywords',
'license'
].forEach(function(property) {
$("#subflow-input-module-"+property).val(moduleProps[property]||"")
})
$("#subflow-input-module-type").attr("placeholder",node.id);
setupInputValidation($("#subflow-input-module-module"), function(newValue) {
newValue = newValue.trim();
var isValid = newValue.length < 215;
isValid = isValid && !/^[._]/.test(newValue);
isValid = isValid && !/[A-Z]/.test(newValue);
if (newValue !== encodeURIComponent(newValue)) {
var m = /^@([^\/]+)\/([^\/]+)$/.exec(newValue);
if (m) {
isValid = isValid && (m[1] === encodeURIComponent(m[1]) && m[2] === encodeURIComponent(m[2]))
} else {
isValid = false;
}
}
return isValid?"":"Invalid module name"
})
setupInputValidation($("#subflow-input-module-version"), function(newValue) {
newValue = newValue.trim();
var isValid = newValue === "" ||
/^(\d|[1-9]\d*)\.(\d|[1-9]\d*)\.(\d|[1-9]\d*)(-(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\.(0|[1-9A-Za-z-][0-9A-Za-z-]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(newValue);
return isValid?"":"Invalid version number"
})
var licenses = ["none", "Apache-2.0", "BSD-3-Clause", "BSD-2-Clause", "GPL-2.0", "GPL-3.0", "MIT", "MPL-2.0", "CDDL-1.0", "EPL-2.0"];
var typedLicenses = {
types: licenses.map(function(l) {
return {
value: l,
label: l === "none" ? RED._("editor:subflow.licenseNone") : l,
hasValue: false
};
})
}
typedLicenses.types.push({
value:"_custom_", label:RED._("editor:subflow.licenseOther"), icon:"red/images/typedInput/az.svg"
})
if (!moduleProps.license) {
typedLicenses.default = "none";
} else if (licenses.indexOf(moduleProps.license) > -1) {
typedLicenses.default = moduleProps.license;
} else {
typedLicenses.default = "_custom_";
}
$("#subflow-input-module-license").typedInput(typedLicenses)
}
function exportSubflowModuleProperties(node) {
var value;
var moduleProps = {};
[
'module',
'type',
'version',
'author',
'desc',
'keywords'
].forEach(function(property) {
value = $("#subflow-input-module-"+property).val().trim();
if (value) {
moduleProps[property] = value;
}
})
var selectedLicenseType = $("#subflow-input-module-license").typedInput("type");
if (selectedLicenseType === '_custom_') {
value = $("#subflow-input-module-license").val();
if (value) {
moduleProps.license = value;
}
} else if (selectedLicenseType !== "none") {
moduleProps.license = selectedLicenseType;
}
return moduleProps;
}
return {
init: init,
@@ -2085,14 +1319,9 @@ RED.subflow = (function() {
removeOutput: removeSubflowOutput,
removeStatus: removeSubflowStatus,
buildEditForm: buildEditForm,
buildPropertiesForm: buildPropertiesForm,
buildModuleForm: buildModuleForm,
exportSubflowTemplateEnv: exportEnvList,
exportSubflowInstanceEnv: exportSubflowInstanceEnv,
exportSubflowModuleProperties: exportSubflowModuleProperties
exportSubflowInstanceEnv: exportSubflowInstanceEnv
}
})();

View File

@@ -229,7 +229,7 @@ RED.sidebar.config = (function() {
var globalConfigNodes = [];
var configList = {};
RED.nodes.eachConfig(function(cn) {
if (cn.z) {//} == RED.workspaces.active()) {
if (cn.z) {
configList[cn.z.replace(/\./g,"-")] = configList[cn.z.replace(/\./g,"-")]||[];
configList[cn.z.replace(/\./g,"-")].push(cn);
} else if (!cn.z) {
@@ -346,7 +346,7 @@ RED.sidebar.config = (function() {
refreshConfigNodeList();
}
});
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllUnusedConfigNodes"));
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllConfigNodes"));
RED.popover.tooltip($('#red-ui-sidebar-config-filter-unused'), RED._("sidebar.config.showAllUnusedConfigNodes"));
}

View File

@@ -25,7 +25,6 @@ RED.sidebar.help = (function() {
var tocPanel;
var helpIndex = {};
function resizeStack() {
var h = $(content).parent().height() - toolbar.outerHeight();
panels.resize(h)
@@ -65,15 +64,17 @@ RED.sidebar.help = (function() {
style: "compact",
delay: 100,
change: function() {
var val = $(this).val().toLowerCase();
if (val) {
const searchFor = $(this).val().toLowerCase();
if (searchFor) {
showTOC();
var c = treeList.treeList('filter',function(item) {
treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return (item.nodeType && item.nodeType.indexOf(val) > -1) ||
(item.subflowLabel && item.subflowLabel.indexOf(val) > -1)
let found = item.nodeType && item.nodeType.toLowerCase().indexOf(searchFor) > -1;
found = found || item.subflowLabel && item.subflowLabel.toLowerCase().indexOf(searchFor) > -1;
found = found || item.palleteLabel && item.palleteLabel.toLowerCase().indexOf(searchFor) > -1;
return found;
},true)
} else {
treeList.treeList('filter',null);
@@ -93,9 +94,28 @@ RED.sidebar.help = (function() {
$('<span class="red-ui-help-info-none">'+RED._("sidebar.help.noHelp")+'</span>').appendTo(helpSection);
treeList = $("<div>").css({width: "100%"}).appendTo(tocPanel).treeList({data: []})
var pendingContentLoad;
treeList.on('treelistselect', function(e,item) {
pendingContentLoad = item;
if (item.nodeType) {
showHelp(item.nodeType);
showNodeTypeHelp(item.nodeType);
} else if (item.content) {
helpSection.empty();
if (typeof item.content === "string") {
setInfoText(item.label, item.content);
} else if (typeof item.content === "function") {
if (item.content.length === 0) {
setInfoText(item.label, item.content());
} else {
setInfoText(item.label, '<div class="red-ui-component-spinner red-ui-component-spinner-contain"><img src="red/images/spin.svg" /></div>',helpSection)
item.content(function(content) {
if (pendingContentLoad === item) {
helpSection.empty();
setInfoText(item.label, content);
}
})
}
}
}
})
@@ -174,21 +194,28 @@ RED.sidebar.help = (function() {
var moduleNames = Object.keys(modules);
moduleNames.sort();
var helpData = [{
var nodeHelp = {
label: RED._("sidebar.help.nodeHelp"),
children: [],
expanded: true
}]
}
var helpData = [
{
id: 'changelog',
label: "Node-RED v"+RED.settings.version,
content: getChangelog
},
nodeHelp
]
var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)});
if (subflows.length > 0) {
helpData[0].children.push({
nodeHelp.children.push({
label: RED._("menu.label.subflows"),
children: []
})
subflows.forEach(function(nodeType) {
var sf = RED.nodes.getType(nodeType);
helpData[0].children[0].children.push({
nodeHelp.children[0].children.push({
id:"node-type:"+nodeType,
nodeType: nodeType,
subflowLabel: sf.label().toLowerCase(),
@@ -199,17 +226,21 @@ RED.sidebar.help = (function() {
moduleNames.forEach(function(moduleName) {
var module = modules[moduleName];
var nodeTypes = [];
var setNames = Object.keys(module.sets);
const module = modules[moduleName];
const nodeTypes = [];
const moduleSets = module.sets;
const setNames = Object.keys(moduleSets);
setNames.forEach(function(setName) {
module.sets[setName].types.forEach(function(nodeType) {
const moduleSet = moduleSets[setName];
moduleSet.types.forEach(function(nodeType) {
if ($("script[data-help-name='"+nodeType+"']").length) {
const n = {_def:RED.nodes.getType(nodeType),type:nodeType}
n.name = getNodePaletteLabel(n);
nodeTypes.push({
id: "node-type:"+nodeType,
nodeType: nodeType,
element:getNodeLabel({_def:RED.nodes.getType(nodeType),type:nodeType})
palleteLabel: n.name,
element: getNodeLabel(n)
})
}
})
@@ -218,7 +249,7 @@ RED.sidebar.help = (function() {
nodeTypes.sort(function(A,B) {
return A.nodeType.localeCompare(B.nodeType)
})
helpData[0].children.push({
nodeHelp.children.push({
id: moduleName,
icon: "fa fa-cube",
label: moduleName,
@@ -229,22 +260,25 @@ RED.sidebar.help = (function() {
treeList.treeList("data",helpData);
}
function getNodeLabel(n) {
var div = $('<div>',{class:"red-ui-node-list-item"});
var icon = RED.utils.createNodeIcon(n).appendTo(div);
var label = n.name;
if (!label && n._def.paletteLabel) {
function getNodePaletteLabel(n) {
let label = n.name;
if (!label && n._def && n._def.paletteLabel) {
try {
label = (typeof n._def.paletteLabel === "function" ? n._def.paletteLabel.call(n._def) : n._def.paletteLabel)||"";
} catch (err) {
}
}
label = label || n.type;
$('<div>',{class:"red-ui-node-label"}).text(n.name||n.type).appendTo(icon);
return label || n.type;
}
function getNodeLabel(n) {
const div = $('<div>',{class:"red-ui-node-list-item"});
const icon = RED.utils.createNodeIcon(n).appendTo(div);
$('<div>',{class:"red-ui-node-label"}).text(getNodePaletteLabel(n)).appendTo(icon);
return div;
}
function showHelp(nodeType) {
function showNodeTypeHelp(nodeType) {
helpSection.empty();
var helpText;
var title;
@@ -265,7 +299,7 @@ RED.sidebar.help = (function() {
}
}
}
setInfoText(title, helpText, helpSection);
setInfoText(title, helpText);
var ratio = panels.ratio();
if (ratio > 0.7) {
@@ -282,7 +316,7 @@ RED.sidebar.help = (function() {
}
if (type) {
// hideTOC();
showHelp(type);
showNodeTypeHelp(type);
}
resizeStack();
}
@@ -298,11 +332,12 @@ RED.sidebar.help = (function() {
return el;
}
function setInfoText(title, infoText,target) {
function setInfoText(title, infoText) {
helpSection.empty();
if (title) {
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(target);
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(helpSection);
}
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(helpSection);
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
var foldingHeader = "H3";
info.find(foldingHeader).wrapInner('<a class="red-ui-help-info-header expanded" href="#"></a>')
@@ -316,12 +351,12 @@ RED.sidebar.help = (function() {
}
$(this).toggleClass('expanded',!isExpanded);
})
target.parent().scrollTop(0);
helpSection.parent().scrollTop(0);
}
function set(html,title) {
$(helpSection).empty();
setInfoText(title,html,helpSection);
setInfoText(title,html);
hideTOC();
show();
}
@@ -336,13 +371,91 @@ RED.sidebar.help = (function() {
if (node.type === "subflow" && node.direction) {
// ignore subflow virtual ports
} else if (node.type !== 'group'){
showHelp(node.type);
showNodeTypeHelp(node.type);
}
}
}
}
RED.events.on("view:selection-changed",refreshSelection);
function getChangelog(done) {
$.get('red/about', function(data) {
// data will be strictly markdown. Any HTML should be escaped.
data = RED.utils.sanitize(data);
RED.tourGuide.load("./tours/welcome.js", function(err, tour) {
var tourHeader = '<div><img width="50px" src="red/images/node-red-icon.svg" /></div>';
if (tour) {
var currentVersionParts = RED.settings.version.split(".");
var tourVersionParts = tour.version.split(".");
if (tourVersionParts[0] === currentVersionParts[0] && tourVersionParts[1] === currentVersionParts[1]) {
tourHeader = '<div><button type="button" onclick="RED.actions.invoke(\'core:show-welcome-tour\')" class="red-ui-button">' + RED._("tourGuide.takeATour") + '</button></div>';
}
}
var aboutHeader = '<div style="text-align:center;">'+tourHeader+'</div>'
done(aboutHeader+RED.utils.renderMarkdown(data))
});
});
}
function showAbout() {
treeList.treeList("show","changelog")
treeList.treeList("select","changelog");
show();
}
function showWelcomeTour(lastSeenVersion, done) {
done = done || function() {};
RED.tourGuide.load("./tours/welcome.js", function(err, tour) {
if (err) {
console.warn("Failed to load welcome tour",err);
done()
return;
}
var currentVersionParts = RED.settings.version.split(".");
var tourVersionParts = tour.version.split(".");
// Only display the tour if its MAJ.MIN versions the current version
// This means if we update MAJ/MIN without updating the tour, the old tour won't get shown
if (tourVersionParts[0] !== currentVersionParts[0] || tourVersionParts[1] !== currentVersionParts[1]) {
done()
return;
}
if (lastSeenVersion) {
// Previously displayed a welcome tour.
if (lastSeenVersion === RED.settings.version) {
// Exact match - don't show the tour
done()
return;
}
var lastSeenParts = lastSeenVersion.split(".");
if (currentVersionParts[0] < lastSeenParts[0] || (currentVersionParts[0] === lastSeenParts[0] && currentVersionParts[1] < lastSeenParts[1])) {
// Running an *older* version than last displayed tour.
done()
return;
}
if (currentVersionParts[0] === lastSeenParts[0] && currentVersionParts[1] === lastSeenParts[1]) {
if (lastSeenParts.length === 3 && currentVersionParts.length === 3) {
// Matching non-beta MAJ.MIN - don't repeat tour
done()
return;
}
if (currentVersionParts.length === 4 && (lastSeenParts.length === 3 || currentVersionParts[3] < lastSeenParts[3])) {
// Running an *older* beta than last displayed tour.
done()
return
}
}
}
RED.tourGuide.run("./tours/welcome.js", function(err) {
RED.settings.set("editor.tours.welcome", RED.settings.version)
done()
})
})
}
RED.actions.add("core:show-about", showAbout);
RED.actions.add("core:show-welcome-tour", showWelcomeTour);
return {
init: init,
show: show,

View File

@@ -122,11 +122,20 @@ RED.sidebar.info.outliner = (function() {
})
RED.popover.tooltip(triggerButton,RED._("sidebar.info.triggerAction"));
}
// $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-eye"></i></button>').appendTo(controls).on("click",function(evt) {
// evt.preventDefault();
// evt.stopPropagation();
// RED.view.reveal(n.id);
// })
if (n.type === "tab") {
var toggleVisibleButton = $('<button type="button" class="red-ui-info-outline-item-control-hide red-ui-button red-ui-button-small"><i class="fa fa-eye"></i><i class="fa fa-eye-slash"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
var isHidden = !div.hasClass("red-ui-info-outline-item-hidden");
div.toggleClass("red-ui-info-outline-item-hidden",isHidden);
if (isHidden) {
RED.workspaces.hide(n.id);
} else {
RED.workspaces.show(n.id, null, true);
}
});
}
if (n.type !== 'subflow') {
var toggleButton = $('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
@@ -166,6 +175,7 @@ RED.sidebar.info.outliner = (function() {
n.d = true;
}
n.dirty = true;
n.dirtyStatus = true;
n.changed = true;
RED.events.emit("nodes:change",n);
groupHistoryEvent.events.push(historyEvent);
@@ -194,6 +204,7 @@ RED.sidebar.info.outliner = (function() {
n.d = true;
}
n.dirty = true;
n.dirtyStatus = true;
n.changed = true;
RED.events.emit("nodes:change",n);
RED.history.push(historyEvent);
@@ -263,6 +274,7 @@ RED.sidebar.info.outliner = (function() {
{label:RED._("sidebar.info.search.invalidNodes"), value: "is:invalid"},
{label:RED._("sidebar.info.search.uknownNodes"), value: "type:unknown"},
{label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"},
{label:RED._("sidebar.info.search.hiddenFlows"), value:"is:hidden"},
]
});
@@ -278,11 +290,11 @@ RED.sidebar.info.outliner = (function() {
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
if (node) {
if (node.type === 'group' || node._def.category !== "config") {
RED.view.select({nodes:[node]})
// RED.view.select({nodes:[node]})
} else if (node._def.category === "config") {
RED.sidebar.info.refresh(node);
} else {
RED.view.select({nodes:[]})
// RED.view.select({nodes:[]})
}
}
})
@@ -311,18 +323,33 @@ RED.sidebar.info.outliner = (function() {
RED.events.on("nodes:add",onNodeAdd);
RED.events.on("nodes:remove",onObjectRemove);
RED.events.on("nodes:change",onNodeChange);
// RED.events.on("nodes:reorder",onNodesReorder);
RED.events.on("groups:add",onNodeAdd);
RED.events.on("groups:remove",onObjectRemove);
RED.events.on("groups:change",onNodeChange);
RED.events.on("workspace:clear", onWorkspaceClear)
RED.events.on("workspace:show", onWorkspaceShow);
RED.events.on("workspace:hide", onWorkspaceHide);
RED.events.on("workspace:clear", onWorkspaceClear);
return container;
}
function onWorkspaceClear() {
treeList.treeList('data',getFlowData());
}
function onWorkspaceShow(event) {
var existingObject = objects[event.workspace];
if (existingObject) {
existingObject.element.removeClass("red-ui-info-outline-item-hidden")
}
}
function onWorkspaceHide(event) {
var existingObject = objects[event.workspace];
if (existingObject) {
existingObject.element.addClass("red-ui-info-outline-item-hidden")
}
}
function onFlowAdd(ws) {
objects[ws.id] = {
id: ws.id,
@@ -369,6 +396,21 @@ RED.sidebar.info.outliner = (function() {
return indexMap[A.id] - indexMap[B.id]
})
}
// function onNodesReorder(event) {
// //
// var nodes = RED.nodes.getNodeOrder(event.z);
// var indexMap = {};
// nodes.forEach(function(id,index) {
// indexMap[id] = index;
// })
// var existingObject = objects[event.z];
// existingObject.treeList.sortChildren(function(A,B) {
// if (A.children && !B.children) { return -1 }
// if (!A.children && B.children) { return 1 }
// if (A.children && B.children) { return -1 }
// return indexMap[A.id] - indexMap[B.id]
// })
// }
function onSubflowAdd(sf) {
objects[sf.id] = {
id: sf.id,
@@ -524,7 +566,7 @@ RED.sidebar.info.outliner = (function() {
}
}
function getGutter(n) {
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
var span = $("<span>",{class:"red-ui-info-outline-gutter red-ui-treeList-gutter-float"});
var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();

View File

@@ -180,6 +180,10 @@ RED.sidebar.info = (function() {
if (node === null) {
RED.sidebar.info.outliner.select(null);
propertiesPanelHeaderIcon.empty();
propertiesPanelHeaderLabel.text("");
propertiesPanelHeaderReveal.hide();
propertiesPanelHeaderHelp.hide();
return;
} else if (Array.isArray(node)) {
// Multiple things selected

View File

@@ -0,0 +1,445 @@
RED.tourGuide = (function() {
var activeListeners = [];
var shade;
var focus;
var popover;
var stepContent;
var targetElement;
var fullscreen;
var tourCache = {};
function run(tourPath, done) {
done = done || function(err) {
if (err) {
console.error(err);
}
};
loadTour(tourPath, function(err, tour) {
if (err) {
console.warn("Error loading tour:",err);
return;
}
runTour(tour, done);
})
}
function loadTour(tourPath, done) {
if (tourCache[tourPath]) {
done(null, tourCache[tourPath]);
} else {
/* jshint ignore:start */
// jshint<2.13 doesn't support dynamic imports. Once grunt-contrib-jshint
// has been updated with the new jshint, we can stop ignoring this block
import(tourPath).then(function(module) {
tourCache[tourPath] = module.default;
done(null, tourCache[tourPath]);
}).catch(function(err) {
done(err);
})
/* jshint ignore:end */
}
}
function repositionFocus() {
if (targetElement) {
if (!fullscreen) {
var pos = targetElement[0].getBoundingClientRect();
var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
focus.css({
left: (pos.left+pos.width/2)+"px",
top: (pos.top+pos.height/2)+"px",
width: (2*dimension)+"px",
height: (2*dimension)+"px"
})
var flush = focus[0].offsetHeight; // Flush CSS changes
focus.addClass("transition");
focus.css({
width: dimension+"px",
height: dimension+"px"
})
} else {
focus.css({
left: ($(window).width()/2)+"px",
top: ($(window).height()/2)+"px",
width: "0px",
height: "0px"
})
}
if (popover) {
popover.move({
target: targetElement,
})
}
}
}
function runTour(tour, done) {
shade = $('<div class="red-ui-tourGuide-shade"></div>').appendTo(document.body);
focus = $('<div class="red-ui-tourGuide-shade-focus"></div>').appendTo(shade);
// var resizeTimer;
//
$(window).on("resize.red-ui-tourGuide", function() {
repositionFocus();
})
var i = 0;
var state = {
index: 0,
count: tour.steps.length
};
function endTour(err) {
$(window).off("resize.red-ui-tourGuide");
$(document).off('keydown.red-ui-tourGuide');
if (popover) {
popover.close();
}
stepContent = null;
popover = null;
shade.remove();
shade = null;
done(err);
}
function runStep(carryOn) {
if (carryOn === false) {
endTour(false);
return;
}
if (i === tour.steps.length) {
endTour();
return
}
state.index = i;
// console.log("TOUR STEP",i+1,"OF",tour.steps.length)
try {
runTourStep(tour.steps[i++], state, runStep)
} catch(err) {
endTour(err);
return;
}
}
runStep();
}
function clearListeners() {
activeListeners.forEach(function(listener) {
if (listener.type === "dom-event") {
listener.target[0].removeEventListener(listener.event,listener.listener,listener.opts);
} else if (listener.type === "nr-event") {
RED.events.off(listener.event, listener.listener)
}
})
activeListeners = [];
}
function prepareStep(step, state, done) {
if (step.prepare) {
if (step.prepare.length === 0) {
step.prepare.call(state);
} else {
if (popover) {
popover.element.hide();
if (!fullscreen) {
fullscreen = true;
repositionFocus()
}
}
step.prepare.call(state, function() {
if (popover) {
popover.element.show();
}
done();
})
return;
}
}
done();
}
function completeStep(step, state, done) {
function finish() {
clearListeners();
setTimeout(function() {
done();
},0)
}
if (step.complete) {
if (step.complete.length === 0) {
step.complete.call(state);
} else {
if (popover) {
popover.element.hide();
if (!fullscreen) {
fullscreen = true;
repositionFocus()
}
}
step.complete.call(state, function() {
if (popover) {
popover.element.show();
}
finish();
})
return;
}
}
finish();
}
function getLocaleText(property) {
if (typeof property === 'string') {
return property;
}
var currentLang = RED.i18n.lang() || 'en-US';
var availableLangs = Object.keys(property);
return property[currentLang]||property['en-US']||property[availableLangs[0]]
}
function runTourStep(step, state, done) {
shade.fadeIn();
prepareStep(step, state, function() {
var zIndex;
var direction = step.direction || "bottom";
fullscreen = false;
if (typeof step.element === "string") {
targetElement = $(step.element)
} else if (typeof step.element === "function") {
targetElement = step.element.call(state);
} else if (!step.element) {
targetElement = $(".red-ui-editor")
fullscreen = true;
direction = "inset";
} else {
targetElement = step.element;
}
if (targetElement.length === 0) {
targetElement = null;
shade.hide();
throw new Error("Element not found")
}
if ($(window).width() < 400) {
targetElement = $(".red-ui-editor");
fullscreen = true;
direction = "inset";
}
zIndex = targetElement.css("z-index");
if (!fullscreen && (step.interactive || step.wait)) {
targetElement.css("z-index",2002);
}
repositionFocus();
if (!stepContent) {
stepContent = $('<div style="position:relative"></div>');
} else {
stepContent.empty();
}
$('<button type="button" class="red-ui-button red-ui-button-small" style="float: right; margin-top: -4px; margin-right: -4px;"><i class="fa fa-times"></i></button>').appendTo(stepContent).click(function(evt) {
evt.preventDefault();
completeStep(step, state, function() {
done(false);
});
})
var stepDescription = $('<div class="red-ui-tourGuide-popover-description"></div>').appendTo(stepContent);
if (step.titleIcon) {
$('<h2><i class="'+step.titleIcon+'"></i></h2>').appendTo(stepDescription);
}
if (step.title) {
$('<h2>').text(getLocaleText(step.title)).appendTo(stepDescription);
}
$('<div>').css("text-align","left").html(getLocaleText(step.description)).appendTo(stepDescription);
if (step.image) {
$(`<img src="red/tours/${step.image}" />`).appendTo(stepDescription)
}
var stepToolbar = $('<div>',{class:"red-ui-tourGuide-toolbar"}).appendTo(stepContent);
// var breadcrumbs = $('<div>',{class:"red-ui-tourGuide-breadcrumbs"}).appendTo(stepToolbar);
// var bcStart = Math.max(0,state.index - 3);
// var bcEnd = Math.min(state.count, bcStart + 7);
// if (bcEnd === state.count) {
// bcStart = Math.max(0,bcEnd - 7);
// }
// for (var i = bcStart; i < bcEnd; i++) {
// var bullet = $('<i class="fa"></i>').addClass(i===state.index ? "fa-circle":"fa-circle-o").appendTo(breadcrumbs);
// if (i === bcStart) {
// if (i > 1) {
// bullet.css("font-size", "3px");
// } else if (i === 1) {
// bullet.css("font-size", "4px");
// }
// } else if (i === bcStart + 1) {
// if (i > 2) {
// bullet.css("font-size", "4px");
// }
// }
// if (i === bcEnd - 1) {
// if (i < state.count - 2) {
// bullet.css("font-size", "3px");
// } else if (i === state.count - 2) {
// bullet.css("font-size", "4px");
// }
// } else if (i === bcEnd - 2) {
// if (i < state.count - 3) {
// bullet.css("font-size", "4px");
// }
// }
// // if (i === bcEnd - 1) {
// // if (i < state.count - 2) {
// // bullet.css("font-size", "3px");
// // } else if (i === state.count - 2) {
// // bullet.css("font-size", "4px");
// // }
// // }
// }
$('<small>').text((state.index+1)+"/"+state.count).appendTo(stepToolbar)
var nextButton;
if (fullscreen || !step.wait) {
nextButton = $('<button type="button" class="red-ui-button" style="position: absolute; right:0;bottom:0;"></button>').appendTo(stepToolbar).one('click',function(evt) {
evt.preventDefault();
stepEventListener();
});
if (state.index === state.count - 1) {
$('<span></span>').text(RED._("common.label.close")).appendTo(nextButton);
} else if (state.index === 0) {
$('<span>start</span>').text(RED._("tourGuide.start")).appendTo(nextButton);
$('<span style="margin-left: 6px"><i class="fa fa-chevron-right"></i></span>').appendTo(nextButton);
} else if (state.index < state.count-1) {
$('<span></span>').text(RED._("tourGuide.next")).appendTo(nextButton);
$('<span style="margin-left: 6px"><i class="fa fa-chevron-right"></i></span>').appendTo(nextButton);
}
}
var width = step.width;
if (fullscreen) {
width = 500;
}
var maxWidth = Math.min($(window).width()-10,Math.max(width || 0, 300));
if (!popover) {
popover = RED.popover.create({
target: targetElement,
width: width || "auto",
maxWidth: maxWidth+"px",
direction: direction,
class: "red-ui-tourGuide-popover"+(fullscreen?" ":""),
trigger: "manual",
content: stepContent
}).open();
}
$(document).off('keydown.red-ui-tourGuide');
$(document).on('keydown.red-ui-tourGuide', function(evt) {
if (evt.key === "Escape" || evt.key === "Esc") {
evt.preventDefault();
evt.stopPropagation();
completeStep(step, state, function() {
done(false);
});
}
})
popover.element.toggleClass("red-ui-tourGuide-popover-full",!!fullscreen);
popover.move({
target: targetElement,
width: width || "auto",
maxWidth: maxWidth+"px",
direction: direction,
})
setTimeout(function() {
var pos = popover.element.position()
if (pos.left < 0) {
popover.element.css({left: 0});
}
},100);
if (nextButton) {
setTimeout(function() {
nextButton.focus();
},100);
}
var isSVG = targetElement[0] instanceof SVGElement;
if (step.fallback) {
focus.one("mouseenter", function(evt) {
setTimeout(function() {
var pos = targetElement[0].getBoundingClientRect();
var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
focus.css({
width: (4*dimension)+"px",
height: (4*dimension)+"px"
})
shade.fadeOut();
popover.move({
target: $(".red-ui-editor"),
direction: step.fallback,
offset: 10,
transition: true
})
// popover.element.addClass('red-ui-tourGuide-popover-bounce');
},isSVG?0:500);
})
}
var stepEventListener = function() {
focus.removeClass("transition");
targetElement.css("z-index",zIndex);
completeStep(step, state, done);
}
if (step.wait) {
if (step.wait.type === "dom-event") {
var eventTarget = targetElement;
if (step.wait.element) {
if (typeof step.wait.element === "string") {
eventTarget = $(step.wait.element);
} else if (typeof step.wait.element === "function") {
eventTarget = step.wait.element.call(state);
}
}
var listener = {
type: step.wait.type,
target: eventTarget,
event: step.wait.event,
listener: function() {
stepEventListener();
},
opts: { once: true }
}
activeListeners.push(listener)
eventTarget[0].addEventListener(listener.event,listener.listener,listener.opts)
} else if (step.wait.type === "nr-event") {
var listener = {
type: step.wait.type,
event: step.wait.event,
listener: function() {
if (step.wait.filter) {
if (!step.wait.filter.apply(state,arguments)) {
return;
}
}
stepEventListener();
}
}
activeListeners.push(listener);
RED.events.on(listener.event,listener.listener);
}
}
})
}
return {
load: loadTour,
run: run,
reset: function() {
RED.settings.set("editor.tours.welcome",'');
}
}
})();

View File

@@ -121,6 +121,13 @@ RED.userSettings = (function() {
// {setting:"theme", label:"Theme",options:function(done){ done([{val:'',text:'default'}].concat(RED.settings.theme("themes"))) }},
// ]
// },
{
title: "menu.label.view.view",
options: [
{setting:"view-store-zoom",label:"menu.label.view.storeZoom", default: false, toggle:true, onchange: function(val) { if (!val) { RED.settings.removeLocal("zoom-level")}}},
{setting:"view-store-position",label:"menu.label.view.storePosition", default: false, toggle:true, onchange: function(val) { if (!val) { RED.settings.removeLocal("scroll-positions")}}},
]
},
{
title: "menu.label.view.grid",
options: [
@@ -139,7 +146,8 @@ RED.userSettings = (function() {
{
title: "menu.label.other",
options: [
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"}
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"},
{setting:"view-show-welcome-tours",label:"menu.label.showWelcomeTours",toggle:true,default:true}
]
}
];

View File

@@ -22,8 +22,82 @@ RED.utils = (function() {
return renderMarkdown(txt);
}
_marked.setOptions({
renderer: new _marked.Renderer(),
const descriptionList = {
name: 'descriptionList',
level: 'block', // Is this a block-level or inline-level tokenizer?
start(src) {
if (!src) { return null; }
let m = src.match(/:[^:\n]/g);
return m && m.index; // Hint to Marked.js to stop and check for a match
},
tokenizer(src, tokens) {
if (!src) { return null; }
const rule = /^(?::[^:\n]+:[^:\n]*(?:\n|$))+/; // Regex for the complete token
const match = rule.exec(src);
if (match) {
return { // Token to generate
type: 'descriptionList', // Should match "name" above
raw: match[0], // Text to consume from the source
text: match[0].trim(), // Additional custom properties
tokens: this.lexer.inlineTokens(match[0].trim()) // inlineTokens to process **bold**, *italics*, etc.
};
}
},
renderer(token) {
return `<dl class="message-properties">${this.parser.parseInline(token.tokens)}\n</dl>`; // parseInline to turn child tokens into HTML
}
};
const description = {
name: 'description',
level: 'inline', // Is this a block-level or inline-level tokenizer?
start(src) {
if (!src) { return null; }
let m = src.match(/:/g);
return m && m.index; // Hint to Marked.js to stop and check for a match
},
tokenizer(src, tokens) {
if (!src) { return null; }
const rule = /^:([^:\n]+)\(([^:\n]+)\).*?:([^:\n]*)(?:\n|$)/; // Regex for the complete token
const match = rule.exec(src);
if (match) {
return { // Token to generate
type: 'description', // Should match "name" above
raw: match[0], // Text to consume from the source
dt: this.lexer.inlineTokens(match[1].trim()), // Additional custom properties
types: this.lexer.inlineTokens(match[2].trim()),
dd: this.lexer.inlineTokens(match[3].trim()),
};
}
},
renderer(token) {
return `\n<dt>${this.parser.parseInline(token.dt)}<span class="property-type">${this.parser.parseInline(token.types)}</span></dt><dd>${this.parser.parseInline(token.dd)}</dd>`;
},
childTokens: ['dt', 'dd'], // Any child tokens to be visited by walkTokens
walkTokens(token) { // Post-processing on the completed token tree
if (token.type === 'strong') {
token.text += ' walked';
}
}
};
const renderer = new window._marked.Renderer();
//override list creation - add node-ports to order lists
renderer.list = function (body, ordered, start) {
let addClass = /dl.*?class.*?message-properties.*/.test(body);
if (addClass && ordered) {
return '<ol class="node-ports">' + body + '</ol>';
} else if (ordered) {
return '<ol>' + body + '</ol>';
} else {
return '<ul>' + body + '</ul>'
}
}
window._marked.setOptions({
renderer: renderer,
gfm: true,
tables: true,
breaks: false,
@@ -32,8 +106,10 @@ RED.utils = (function() {
smartypants: false
});
window._marked.use({extensions: [descriptionList, description] } );
function renderMarkdown(txt) {
var rendered = _marked(txt);
var rendered = _marked.parse(txt);
var cleaned = DOMPurify.sanitize(rendered, {SAFE_FOR_JQUERY: true})
return cleaned;
}
@@ -66,6 +142,8 @@ RED.utils = (function() {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('function');
} else if (value.hasOwnProperty('type') && (value.type === 'number' || value.type === 'bigint')) {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data);
} else if (value.hasOwnProperty('type') && value.type === 'regexp') {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-string"></span>').text(value.data);
} else {
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>');
}
@@ -364,6 +442,8 @@ RED.utils = (function() {
$('<span class="red-ui-debug-msg-type-null">undefined</span>').appendTo(entryObj);
} else if (obj.__enc__ && (obj.type === 'number' || obj.type === 'bigint')) {
e = $('<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>').text(obj.data).appendTo(entryObj);
} else if (typeHint === "regexp" || (obj.__enc__ && obj.type === 'regexp')) {
e = $('<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>').text((typeof obj === "string")?obj:obj.data).appendTo(entryObj);
} else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) {
e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("function").appendTo(entryObj);
} else if (typeHint === "internal" || (obj.__enc__ && obj.type === 'internal')) {
@@ -487,7 +567,8 @@ RED.utils = (function() {
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi,
tools: tools
// tools: tools // Do not pass tools down as we
// keep them attached to the top-level header
}
).appendTo(row);
}
@@ -516,7 +597,8 @@ RED.utils = (function() {
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi,
tools: tools
// tools: tools // Do not pass tools down as we
// keep them attached to the top-level header
}
).appendTo(row);
}
@@ -571,7 +653,8 @@ RED.utils = (function() {
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi,
tools: tools
// tools: tools // Do not pass tools down as we
// keep them attached to the top-level header
}
).appendTo(row);
}

View File

@@ -159,15 +159,15 @@ RED.view.tools = (function() {
nodes.forEach(function(n) {
var modified = false;
var oldValue = n.l === undefined?true:n.l;
var isLink = /^link (in|out)$/.test(n._def.type);
var showLabel = n._def.hasOwnProperty("showLabel")?n._def.showLabel:true;
if (labelShown) {
if (n.l === false || (isLink && !n.hasOwnProperty('l'))) {
if (n.l === false || (!showLabel && !n.hasOwnProperty('l'))) {
n.l = true;
modified = true;
}
} else {
if ((!isLink && (!n.hasOwnProperty('l') || n.l === true)) || (isLink && n.l === true) ) {
if ((showLabel && (!n.hasOwnProperty('l') || n.l === true)) || (!showLabel && n.l === true) ) {
n.l = false;
modified = true;
}
@@ -427,18 +427,393 @@ RED.view.tools = (function() {
}
}
}
}
function alignSelectionToEdge(direction) {
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length > 1) {
var changedNodes = [];
var bounds = {
minX: Number.MAX_SAFE_INTEGER,
minY: Number.MAX_SAFE_INTEGER,
maxX: Number.MIN_SAFE_INTEGER,
maxY: Number.MIN_SAFE_INTEGER
}
selection.nodes.forEach(function(n) {
if (n.type === "group") {
bounds.minX = Math.min(bounds.minX, n.x);
bounds.minY = Math.min(bounds.minY, n.y);
bounds.maxX = Math.max(bounds.maxX, n.x + n.w);
bounds.maxY = Math.max(bounds.maxY, n.y + n.h);
} else {
bounds.minX = Math.min(bounds.minX, n.x - n.w/2);
bounds.minY = Math.min(bounds.minY, n.y - n.h/2);
bounds.maxX = Math.max(bounds.maxX, n.x + n.w/2);
bounds.maxY = Math.max(bounds.maxY, n.y + n.h/2);
}
});
bounds.midX = bounds.minX + (bounds.maxX - bounds.minX)/2;
bounds.midY = bounds.minY + (bounds.maxY - bounds.minY)/2;
selection.nodes.forEach(function(n) {
var targetX;
var targetY;
var isGroup = n.type==="group";
switch(direction) {
case 'top':
targetX = n.x;
targetY = bounds.minY + (isGroup?0:(n.h/2));
break;
case 'bottom':
targetX = n.x;
targetY = bounds.maxY - (isGroup?n.h:(n.h/2));
break;
case 'left':
targetX = bounds.minX + (isGroup?0:(n.w/2));
targetY = n.y;
break;
case 'right':
targetX = bounds.maxX - (isGroup?n.w:(n.w/2));
targetY = n.y;
break;
case 'middle':
targetX = n.x;
targetY = bounds.midY - (isGroup?n.h/2:0)
break;
case 'center':
targetX = bounds.midX - (isGroup?n.w/2:0)
targetY = n.y;
break;
}
if (n.x !== targetX || n.y !== targetY) {
if (!isGroup) {
changedNodes.push({
n:n,
ox: n.x,
oy: n.y,
moved: n.moved
});
n.x = targetX;
n.y = targetY;
n.dirty = true;
n.moved = true;
} else {
var groupNodes = RED.group.getNodes(n, true);
var deltaX = n.x - targetX;
var deltaY = n.y - targetY;
groupNodes.forEach(function(gn) {
if (gn.type !== "group" ) {
changedNodes.push({
n:gn,
ox: gn.x,
oy: gn.y,
moved: gn.moved
});
gn.x = gn.x - deltaX;
gn.y = gn.y - deltaY;
gn.dirty = true;
gn.moved = true;
}
})
}
}
});
if (changedNodes.length > 0) {
RED.history.push({t:"move",nodes:changedNodes,dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
RED.view.redraw(true);
}
}
}
function distributeSelection(direction) {
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length > 2) {
var changedNodes = [];
var bounds = {
minX: Number.MAX_SAFE_INTEGER,
minY: Number.MAX_SAFE_INTEGER,
maxX: Number.MIN_SAFE_INTEGER,
maxY: Number.MIN_SAFE_INTEGER
}
var startAnchors = [];
var endAnchors = [];
selection.nodes.forEach(function(n) {
var nx,ny;
if (n.type === "group") {
nx = n.x + n.w/2;
ny = n.y + n.h/2;
} else {
nx = n.x;
ny = n.y;
}
if (direction === "h") {
if (nx < bounds.minX) {
startAnchors = [];
bounds.minX = nx;
}
if (nx === bounds.minX) {
startAnchors.push(n);
}
if (nx > bounds.maxX) {
endAnchors = [];
bounds.maxX = nx;
}
if (nx === bounds.maxX) {
endAnchors.push(n);
}
} else {
if (ny < bounds.minY) {
startAnchors = [];
bounds.minY = ny;
}
if (ny === bounds.minY) {
startAnchors.push(n);
}
if (ny > bounds.maxY) {
endAnchors = [];
bounds.maxY = ny;
}
if (ny === bounds.maxY) {
endAnchors.push(n);
}
}
});
var startAnchor = startAnchors[0];
var endAnchor = endAnchors[0];
var nodeSpace = 0;
var nodesToMove = selection.nodes.filter(function(n) {
if (n.id !== startAnchor.id && n.id !== endAnchor.id) {
nodeSpace += direction === 'h'?n.w:n.h;
return true;
}
return false;
}).sort(function(A,B) {
if (direction === 'h') {
return A.x - B.x
} else {
return A.y - B.y
}
})
var saX = startAnchor.x + startAnchor.w/2;
var saY = startAnchor.y + startAnchor.h/2;
if (startAnchor.type === "group") {
saX = startAnchor.x + startAnchor.w;
saY = startAnchor.y + startAnchor.h;
}
var eaX = endAnchor.x;
var eaY = endAnchor.y;
if (endAnchor.type !== "group") {
eaX -= endAnchor.w/2;
eaY -= endAnchor.h/2;
}
var spaceToFill = direction === 'h'?(eaX - saX - nodeSpace): (eaY - saY - nodeSpace);
var spaceBetweenNodes = spaceToFill / (nodesToMove.length + 1);
var tx = saX;
var ty = saY;
while(nodesToMove.length > 0) {
if (direction === 'h') {
tx += spaceBetweenNodes;
} else {
ty += spaceBetweenNodes;
}
var nextNode = nodesToMove.shift();
var isGroup = nextNode.type==="group";
var nx = nextNode.x;
var ny = nextNode.y;
if (!isGroup) {
tx += nextNode.w/2;
ty += nextNode.h/2;
}
if ((direction === 'h' && nx !== tx) || (direction === 'v' && ny !== ty)) {
if (!isGroup) {
changedNodes.push({
n:nextNode,
ox: nextNode.x,
oy: nextNode.y,
moved: nextNode.moved
});
if (direction === 'h') {
nextNode.x = tx;
} else {
nextNode.y = ty;
}
nextNode.dirty = true;
nextNode.moved = true;
} else {
var groupNodes = RED.group.getNodes(nextNode, true);
var deltaX = direction === 'h'? nx - tx : 0;
var deltaY = direction === 'v'? ny - ty : 0;
groupNodes.forEach(function(gn) {
if (gn.type !== "group" ) {
changedNodes.push({
n:gn,
ox: gn.x,
oy: gn.y,
moved: gn.moved
});
gn.x = gn.x - deltaX;
gn.y = gn.y - deltaY;
gn.dirty = true;
gn.moved = true;
}
})
}
}
if (isGroup) {
tx += nextNode.w;
ty += nextNode.h;
} else {
tx += nextNode.w/2;
ty += nextNode.h/2;
}
}
if (changedNodes.length > 0) {
RED.history.push({t:"move",nodes:changedNodes,dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
RED.view.redraw(true);
}
}
}
function reorderSelection(dir) {
var selection = RED.view.selection();
if (selection.nodes) {
var nodesToMove = [];
selection.nodes.forEach(function(n) {
if (n.type === "group") {
nodesToMove = nodesToMove.concat(RED.group.getNodes(n, true).filter(function(n) {
return n.type !== "group";
}))
} else if (n.type !== "subflow"){
nodesToMove.push(n);
}
})
if (nodesToMove.length > 0) {
var z = nodesToMove[0].z;
var existingOrder = RED.nodes.getNodeOrder(z);
var movedNodes;
if (dir === "forwards") {
movedNodes = RED.nodes.moveNodesForwards(nodesToMove);
} else if (dir === "backwards") {
movedNodes = RED.nodes.moveNodesBackwards(nodesToMove);
} else if (dir === "front") {
movedNodes = RED.nodes.moveNodesToFront(nodesToMove);
} else if (dir === "back") {
movedNodes = RED.nodes.moveNodesToBack(nodesToMove);
}
if (movedNodes.length > 0) {
var newOrder = RED.nodes.getNodeOrder(z);
RED.history.push({t:"reorder",nodes:{z:z,from:existingOrder,to:newOrder},dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
RED.view.redraw(true);
}
}
}
}
function wireSeriesOfNodes() {
var selection = RED.view.selection();
if (selection.nodes) {
if (selection.nodes.length > 1) {
var i = 0;
var newLinks = [];
while (i < selection.nodes.length - 1) {
var nodeA = selection.nodes[i];
var nodeB = selection.nodes[i+1];
if (nodeA.outputs > 0 && nodeB.inputs > 0) {
var existingLinks = RED.nodes.filterLinks({
source: nodeA,
target: nodeB,
sourcePort: 0
})
if (existingLinks.length === 0) {
var newLink = {
source: nodeA,
target: nodeB,
sourcePort: 0
}
RED.nodes.addLink(newLink);
newLinks.push(newLink);
}
}
i++;
}
if (newLinks.length > 0) {
RED.history.push({
t: 'add',
links: newLinks,
dirty: RED.nodes.dirty()
})
RED.nodes.dirty(true);
RED.view.redraw(true);
}
}
}
}
function wireNodeToMultiple() {
var selection = RED.view.selection();
if (selection.nodes) {
if (selection.nodes.length > 1) {
var sourceNode = selection.nodes[0];
if (sourceNode.outputs === 0) {
return;
}
var i = 1;
var newLinks = [];
while (i < selection.nodes.length) {
var targetNode = selection.nodes[i];
if (targetNode.inputs > 0) {
var existingLinks = RED.nodes.filterLinks({
source: sourceNode,
target: targetNode,
sourcePort: Math.min(sourceNode.outputs-1,i-1)
})
if (existingLinks.length === 0) {
var newLink = {
source: sourceNode,
target: targetNode,
sourcePort: Math.min(sourceNode.outputs-1,i-1)
}
RED.nodes.addLink(newLink);
newLinks.push(newLink);
}
}
i++;
}
if (newLinks.length > 0) {
RED.history.push({
t: 'add',
links: newLinks,
dirty: RED.nodes.dirty()
})
RED.nodes.dirty(true);
RED.view.redraw(true);
}
}
}
}
return {
init: function() {
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
RED.actions.add("core:hide-selected-node-labels", function() { setSelectedNodeLabelState(false); })
RED.actions.add("core:align-selection-to-grid", alignToGrid);
RED.actions.add("core:scroll-view-up", function() { RED.view.scroll(0,-RED.view.gridSize());});
RED.actions.add("core:scroll-view-right", function() { RED.view.scroll(RED.view.gridSize(),0);});
RED.actions.add("core:scroll-view-down", function() { RED.view.scroll(0,RED.view.gridSize());});
@@ -454,6 +829,12 @@ RED.view.tools = (function() {
RED.actions.add("core:move-selection-down", function() { moveSelection(0,1);});
RED.actions.add("core:move-selection-left", function() { moveSelection(-1,0);});
RED.actions.add("core:move-selection-forwards", function() { reorderSelection('forwards') })
RED.actions.add("core:move-selection-backwards", function() { reorderSelection('backwards') })
RED.actions.add("core:move-selection-to-front", function() { reorderSelection('front') })
RED.actions.add("core:move-selection-to-back", function() { reorderSelection('back') })
RED.actions.add("core:step-selection-up", function() { moveSelection(0,-RED.view.gridSize());});
RED.actions.add("core:step-selection-right", function() { moveSelection(RED.view.gridSize(),0);});
RED.actions.add("core:step-selection-down", function() { moveSelection(0,RED.view.gridSize());});
@@ -474,6 +855,21 @@ RED.view.tools = (function() {
RED.actions.add("core:go-to-nearest-node-on-right", function() { gotoNearestNode('right')})
RED.actions.add("core:go-to-nearest-node-above", function() { gotoNearestNode('up') })
RED.actions.add("core:go-to-nearest-node-below", function() { gotoNearestNode('down') })
RED.actions.add("core:align-selection-to-grid", alignToGrid);
RED.actions.add("core:align-selection-to-left", function() { alignSelectionToEdge('left') })
RED.actions.add("core:align-selection-to-right", function() { alignSelectionToEdge('right') })
RED.actions.add("core:align-selection-to-top", function() { alignSelectionToEdge('top') })
RED.actions.add("core:align-selection-to-bottom", function() { alignSelectionToEdge('bottom') })
RED.actions.add("core:align-selection-to-middle", function() { alignSelectionToEdge('middle') })
RED.actions.add("core:align-selection-to-center", function() { alignSelectionToEdge('center') })
RED.actions.add("core:distribute-selection-horizontally", function() { distributeSelection('h') })
RED.actions.add("core:distribute-selection-vertically", function() { distributeSelection('v') })
RED.actions.add("core:wire-series-of-nodes", function() { wireSeriesOfNodes() })
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
// RED.actions.add("core:add-node", function() { addNode() })
},
/**

File diff suppressed because it is too large Load Diff

View File

@@ -21,40 +21,77 @@ RED.workspaces = (function() {
var workspaceIndex = 0;
var viewStack = [];
var hideStack = [];
var viewStackPos = 0;
function addToViewStack(id) {
if (viewStackPos !== viewStack.length) {
viewStack.splice(viewStackPos);
}
viewStack.push(id);
viewStackPos = viewStack.length;
// console.warn("addToViewStack",id,viewStack);
}
function removeFromHideStack(id) {
hideStack = hideStack.filter(function(v) {
if (v === id) {
return false;
} else if (Array.isArray(v)) {
var i = v.indexOf(id);
if (i > -1) {
v.splice(i,1);
}
if (v.length === 0) {
return false;
}
return true
}
return true;
})
}
function addWorkspace(ws,skipHistoryEntry,targetIndex) {
if (ws) {
if (!ws.closeable) {
ws.hideable = true;
}
workspace_tabs.addTab(ws,targetIndex);
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
if (hiddenTabs[ws.id]) {
workspace_tabs.hideTab(ws.id);
}
workspace_tabs.resize();
} else {
var tabId = RED.nodes.id();
do {
workspaceIndex += 1;
} while ($("#red-ui-workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
} while ($("#red-ui-workspace-tabs li[flowname='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
ws = {type:"tab",id:tabId,disabled: false,info:"",label:RED._('workspace.defaultName',{number:workspaceIndex})};
ws = {
type: "tab",
id: tabId,
disabled: false,
info: "",
label: RED._('workspace.defaultName',{number:workspaceIndex}),
env: [],
hideable: true
};
RED.nodes.addWorkspace(ws,targetIndex);
workspace_tabs.addTab(ws,targetIndex);
workspace_tabs.activateTab(tabId);
if (!skipHistoryEntry) {
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
}
}
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
RED.view.focus();
return ws;
}
function deleteWorkspace(ws) {
if (workspaceTabCount === 1) {
return;
@@ -78,165 +115,9 @@ RED.workspaces = (function() {
if (subflow) {
RED.editor.editSubflow(subflow);
}
return;
} else {
RED.editor.editFlow(workspace);
}
RED.view.state(RED.state.EDITING);
var tabflowEditor;
var trayOptions = {
title: RED._("workspace.editFlow",{name:RED.utils.sanitize(workspace.label)}),
buttons: [
{
id: "node-dialog-delete",
class: 'leftButton'+((workspaceTabCount === 1)?" disabled":""),
text: RED._("common.label.delete"), //'<i class="fa fa-trash"></i>',
click: function() {
deleteWorkspace(workspace);
RED.tray.close();
}
},
{
id: "node-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
RED.tray.close();
}
},
{
id: "node-dialog-ok",
class: "primary",
text: RED._("common.label.done"),
click: function() {
var label = $( "#node-input-name" ).val();
var changed = false;
var changes = {};
if (workspace.label != label) {
changes.label = workspace.label;
changed = true;
workspace.label = label;
workspace_tabs.renameTab(workspace.id,label);
}
var disabled = $("#node-input-disabled").prop("checked");
if (workspace.disabled !== disabled) {
changes.disabled = workspace.disabled;
changed = true;
workspace.disabled = disabled;
}
var info = tabflowEditor.getValue();
if (workspace.info !== info) {
changes.info = workspace.info;
changed = true;
workspace.info = info;
}
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
if (changed) {
var historyEvent = {
t: "edit",
changes:changes,
node: workspace,
dirty: RED.nodes.dirty()
}
workspace.changed = true;
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
if (changes.hasOwnProperty('disabled')) {
RED.nodes.eachNode(function(n) {
if (n.z === workspace.id) {
n.dirty = true;
}
});
RED.view.redraw();
}
RED.events.emit("flows:change",workspace);
}
RED.tray.close();
}
}
],
resize: function(dimensions) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var editorRow = $("#dialog-form>div.node-text-editor-row");
var height = $("#dialog-form").height();
for (var i=0; i<rows.size(); i++) {
height -= $(rows[i]).outerHeight(true);
}
height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
tabflowEditor.resize();
},
open: function(tray) {
var trayFooter = tray.find(".red-ui-tray-footer");
var trayBody = tray.find('.red-ui-tray-body');
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(trayBody);
$('<div class="form-row">'+
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
'<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">'+
'</div>').appendTo(dialogForm);
if (!workspace.hasOwnProperty("disabled")) {
workspace.disabled = false;
}
$('<input id="node-input-disabled" type="checkbox">').prop("checked",workspace.disabled).appendTo(trayFooterLeft).toggleButton({
enabledIcon: "fa-circle-thin",
disabledIcon: "fa-ban",
invertState: true
})
var row = $('<div class="form-row node-text-editor-row">'+
'<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+
'<div style="min-height:250px;" class="node-text-editor" id="node-input-info"></div>'+
'</div>').appendTo(dialogForm);
tabflowEditor = RED.editor.createEditor({
id: 'node-input-info',
mode: 'ace/mode/markdown',
value: ""
});
$('#node-info-input-info-expand').on("click", function(e) {
e.preventDefault();
var value = tabflowEditor.getValue();
RED.editor.editMarkdown({
value: value,
width: "Infinity",
cursor: tabflowEditor.getCursorPosition(),
complete: function(v,cursor) {
tabflowEditor.setValue(v, -1);
tabflowEditor.gotoLine(cursor.row+1,cursor.column,false);
setTimeout(function() {
tabflowEditor.focus();
},300);
}
})
});
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
dialogForm.on("submit", function(e) { e.preventDefault();});
$("#node-input-name").val(workspace.label);
RED.text.bidi.prepareInput($("#node-input-name"));
tabflowEditor.getSession().setValue(workspace.info || "", -1);
dialogForm.i18n();
},
close: function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
var selection = RED.view.selection();
if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
RED.sidebar.info.refresh(workspace);
}
tabflowEditor.destroy();
}
}
RED.tray.show(trayOptions);
}
@@ -249,11 +130,18 @@ RED.workspaces = (function() {
var event = {
old: activeWorkspace
}
activeWorkspace = tab.id;
if (tab) {
$("#red-ui-workspace-chart").show();
activeWorkspace = tab.id;
window.location.hash = 'flow/'+tab.id;
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!tab.disabled);
} else {
$("#red-ui-workspace-chart").hide();
activeWorkspace = 0;
window.location.hash = '';
}
event.workspace = activeWorkspace;
RED.events.emit("workspace:change",event);
window.location.hash = 'flow/'+tab.id;
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!tab.disabled);
RED.sidebar.config.refresh();
RED.view.focus();
},
@@ -278,7 +166,7 @@ RED.workspaces = (function() {
if (tab.disabled) {
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-disabled');
}
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
if (workspaceTabCount === 1) {
showWorkspace();
}
@@ -286,14 +174,23 @@ RED.workspaces = (function() {
onremove: function(tab) {
if (tab.type === "tab") {
workspaceTabCount--;
} else {
hideStack.push(tab.id);
}
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
if (workspaceTabCount === 0) {
hideWorkspace();
}
},
onreorder: function(oldOrder, newOrder) {
RED.history.push({t:'reorder',order:oldOrder,dirty:RED.nodes.dirty()});
RED.history.push({
t:'reorder',
workspaces: {
from:oldOrder,
to:newOrder
},
dirty:RED.nodes.dirty()
});
RED.nodes.dirty(true);
setWorkspaceOrder(newOrder);
},
@@ -312,12 +209,99 @@ RED.workspaces = (function() {
$(".red-ui-sidebar-shade").show();
}
},
onhide: function(tab) {
hideStack.push(tab.id);
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
hiddenTabs[tab.id] = true;
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
RED.events.emit("workspace:hide",{workspace: tab.id})
},
onshow: function(tab) {
removeFromHideStack(tab.id);
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
delete hiddenTabs[tab.id];
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
RED.events.emit("workspace:show",{workspace: tab.id})
},
minimumActiveTabWidth: 150,
scrollable: true,
addButton: "core:add-flow",
addButtonCaption: RED._("workspace.addFlow"),
searchButton: "core:list-flows",
searchButtonCaption: RED._("workspace.listFlows")
menu: function() {
var menuItems = [
{
id:"red-ui-tabs-menu-option-search-flows",
label: RED._("workspace.listFlows"),
onselect: "core:list-flows"
},
{
id:"red-ui-tabs-menu-option-search-subflows",
label: RED._("workspace.listSubflows"),
onselect: "core:list-subflows"
},
null,
{
id:"red-ui-tabs-menu-option-add-flow",
label: RED._("workspace.addFlow"),
onselect: "core:add-flow"
},
{
id:"red-ui-tabs-menu-option-add-flow-right",
label: RED._("workspace.addFlowToRight"),
onselect: "core:add-flow-to-right"
},
null,
{
id:"red-ui-tabs-menu-option-add-hide-flows",
label: RED._("workspace.hideFlow"),
onselect: "core:hide-flow"
},
{
id:"red-ui-tabs-menu-option-add-hide-other-flows",
label: RED._("workspace.hideOtherFlows"),
onselect: "core:hide-other-flows"
},
{
id:"red-ui-tabs-menu-option-add-show-all-flows",
label: RED._("workspace.showAllFlows"),
onselect: "core:show-all-flows"
},
{
id:"red-ui-tabs-menu-option-add-hide-all-flows",
label: RED._("workspace.hideAllFlows"),
onselect: "core:hide-all-flows"
},
{
id:"red-ui-tabs-menu-option-add-show-last-flow",
label: RED._("workspace.showLastHiddenFlow"),
onselect: "core:show-last-hidden-flow"
}
]
let hiddenFlows = new Set()
for (let i = 0; i < hideStack.length; i++) {
let ids = hideStack[i]
if (!Array.isArray(ids)) {
ids = [ids]
}
ids.forEach(id => {
if (RED.nodes.workspace(id)) {
hiddenFlows.add(id)
}
})
}
const flowCount = hiddenFlows.size;
if (flowCount > 0) {
menuItems.unshift({
label: RED._("workspace.hiddenFlows",{count: flowCount}),
onselect: "core:list-hidden-flows"
})
}
return menuItems;
}
});
workspaceTabCount = 0;
}
@@ -368,15 +352,104 @@ RED.workspaces = (function() {
});
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
RED.actions.add("core:add-flow-to-right",function(opts) { addWorkspace(undefined,undefined,workspace_tabs.activeIndex()+1)});
RED.actions.add("core:edit-flow",editWorkspace);
RED.actions.add("core:remove-flow",removeWorkspace);
RED.actions.add("core:enable-flow",enableWorkspace);
RED.actions.add("core:disable-flow",disableWorkspace);
RED.actions.add("core:hide-flow", function() {
var selection = workspace_tabs.selection();
if (selection.length === 0) {
selection = [{id:activeWorkspace}]
}
var hiddenTabs = [];
selection.forEach(function(ws) {
RED.workspaces.hide(ws.id);
hideStack.pop();
hiddenTabs.push(ws.id);
})
if (hiddenTabs.length > 0) {
hideStack.push(hiddenTabs);
}
workspace_tabs.clearSelection();
})
RED.actions.add("core:hide-other-flows", function() {
var selection = workspace_tabs.selection();
if (selection.length === 0) {
selection = [{id:activeWorkspace}]
}
var selected = new Set(selection.map(function(ws) { return ws.id }))
var currentTabs = workspace_tabs.listTabs();
var hiddenTabs = [];
currentTabs.forEach(function(id) {
if (!selected.has(id)) {
RED.workspaces.hide(id);
hideStack.pop();
hiddenTabs.push(id);
}
})
if (hiddenTabs.length > 0) {
hideStack.push(hiddenTabs);
}
})
RED.actions.add("core:hide-all-flows", function() {
var currentTabs = workspace_tabs.listTabs();
currentTabs.forEach(function(id) {
RED.workspaces.hide(id);
hideStack.pop();
})
if (currentTabs.length > 0) {
hideStack.push(currentTabs);
}
workspace_tabs.clearSelection();
})
RED.actions.add("core:show-all-flows", function() {
var currentTabs = workspace_tabs.listTabs();
currentTabs.forEach(function(id) {
RED.workspaces.show(id, null, true)
})
})
// RED.actions.add("core:toggle-flows", function() {
// var currentTabs = workspace_tabs.listTabs();
// var visibleCount = workspace_tabs.count();
// currentTabs.forEach(function(id) {
// if (visibleCount === 0) {
// RED.workspaces.show(id)
// } else {
// RED.workspaces.hide(id)
// }
// })
// })
RED.actions.add("core:show-last-hidden-flow", function() {
var id = hideStack.pop();
if (id) {
if (typeof id === 'string') {
RED.workspaces.show(id);
} else {
var last = id.pop();
id.forEach(function(i) {
RED.workspaces.show(i, null, true);
})
setTimeout(function() {
RED.workspaces.show(last);
},150)
}
}
})
RED.actions.add("core:list-hidden-flows",function() {
RED.actions.invoke("core:search","is:hidden ");
})
RED.actions.add("core:list-flows",function() {
RED.actions.invoke("core:search","type:tab ");
})
RED.actions.add("core:list-subflows",function() {
RED.actions.invoke("core:search","type:subflow ");
})
RED.actions.add("core:go-to-previous-location", function() {
if (viewStackPos > 0) {
if (viewStackPos === viewStack.length) {
@@ -392,8 +465,6 @@ RED.workspaces = (function() {
RED.workspaces.show(viewStack[++viewStackPos],true);
}
})
hideWorkspace();
}
@@ -416,7 +487,7 @@ RED.workspaces = (function() {
var changes = { disabled: workspace.disabled };
workspace.disabled = disabled;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
if (id === activeWorkspace) {
if (!id || (id === activeWorkspace)) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
}
var historyEvent = {
@@ -445,7 +516,6 @@ RED.workspaces = (function() {
}
}
function removeWorkspace(ws) {
if (!ws) {
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
@@ -474,7 +544,10 @@ RED.workspaces = (function() {
return {
init: init,
add: addWorkspace,
// remove: remove workspace without editor history etc
remove: removeWorkspace,
// delete: remove workspace and update editor history
delete: deleteWorkspace,
order: setWorkspaceOrder,
edit: editWorkspace,
contains: function(id) {
@@ -489,7 +562,18 @@ RED.workspaces = (function() {
selection: function() {
return workspace_tabs.selection();
},
show: function(id,skipStack) {
hide: function(id) {
if (!id) {
id = activeWorkspace;
}
if (workspace_tabs.contains(id)) {
workspace_tabs.hideTab(id);
}
},
isHidden: function(id) {
return hideStack.includes(id)
},
show: function(id,skipStack,unhideOnly) {
if (!workspace_tabs.contains(id)) {
var sf = RED.nodes.subflow(id);
if (sf) {
@@ -498,19 +582,24 @@ RED.workspaces = (function() {
null,
workspace_tabs.activeIndex()+1
);
removeFromHideStack(id);
} else {
return;
}
}
if (!skipStack && activeWorkspace !== id) {
addToViewStack(activeWorkspace)
if (unhideOnly) {
workspace_tabs.showTab(id);
} else {
if (!skipStack && activeWorkspace !== id) {
addToViewStack(activeWorkspace)
}
workspace_tabs.activateTab(id);
}
workspace_tabs.activateTab(id);
},
refresh: function() {
RED.nodes.eachWorkspace(function(ws) {
workspace_tabs.renameTab(ws.id,ws.label);
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
})
RED.nodes.eachSubflow(function(sf) {
if (workspace_tabs.contains(sf.id)) {

View File

@@ -21,10 +21,10 @@ RED.user = (function() {
opts = {};
}
var dialog = $('<div id="node-dialog-login" class="hide">'+
'<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img id="node-dialog-login-image" src=""/></div>'+
'<div style="display: inline-block; width: 250px; vertical-align: bottom; margin-left: 10px; margin-bottom: 20px;">'+
'<form id="node-dialog-login-fields" class="form-horizontal" style="margin-bottom: 0px;"></form>'+
var dialog = $('<div id="node-dialog-login" class="hide" style="display: flex; align-items: flex-end;">'+
'<div style="width: 250px; flex-grow: 0;"><img id="node-dialog-login-image" src=""/></div>'+
'<div style="flex-grow: 1;">'+
'<form id="node-dialog-login-fields" class="form-horizontal" style="margin-bottom: 0px; margin-left:20px;"></form>'+
'</div>'+
'</div>');
@@ -76,7 +76,7 @@ RED.user = (function() {
}
row.appendTo("#node-dialog-login-fields");
}
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">'+RED._("user.loginFailed")+'</span><img src="red/images/spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;color:var(--red-ui-text-color-error);" class="hide">'+RED._("user.loginFailed")+'</span><img src="red/images/spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
(opts.cancelable?'<a href="#" id="node-dialog-login-cancel" class="red-ui-button" style="margin-right: 20px;" tabIndex="'+(i+1)+'">'+RED._("common.label.cancel")+'</a>':'')+
'<input type="submit" id="node-dialog-login-submit" class="red-ui-button" style="width: auto;" tabIndex="'+(i+2)+'" value="'+RED._("user.login")+'"></div>').appendTo("#node-dialog-login-fields");
@@ -121,6 +121,24 @@ RED.user = (function() {
i = 0;
for (;i<data.prompts.length;i++) {
var field = data.prompts[i];
var sessionMessage = /[?&]session_message=(.*?)(?:$|&)/.exec(window.location.search);
if (sessionMessage) {
RED.sessionMessages = RED.sessionMessages || [];
RED.sessionMessages.push(sessionMessage[1]);
if (history.pushState) {
var newurl = window.location.protocol+"//"+window.location.host+window.location.pathname
window.history.replaceState({ path: newurl }, "", newurl);
} else {
window.location.search = "";
}
}
if (RED.sessionMessages) {
var sessionMessages = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
RED.sessionMessages.forEach(function (msg) {
$('<div>').css("color","var(--red-ui-text-color-error)").text(msg).appendTo(sessionMessages);
});
delete RED.sessionMessages;
}
var row = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
var loginButton = $('<a href="#" class="red-ui-button"></a>',{style: "padding: 10px"}).appendTo(row).on("click", function() {
@@ -152,7 +170,7 @@ RED.user = (function() {
});
}
var loginImageSrc = data.image || "red/images/node-red-256.png";
var loginImageSrc = data.image || "red/images/node-red-256.svg";
$("#node-dialog-login-image").load(function() {
dialog.dialog("open");

View File

@@ -140,8 +140,8 @@ $workspace-button-color-focus-outline: $form-input-focus-color;
$shade-color: rgba(160,160,160,0.5);
$popover-background: #333;
$popover-border: $popover-background;
$popover-color: #eee;
$popover-button-border-color: #bbb;
$popover-button-border-color-hover: #666;
@@ -150,7 +150,8 @@ $popover-button-border-color-hover: #666;
$diff-text-header-color: $secondary-text-color;
$diff-text-header-background: #ffd;
$diff-text-header-background-hover: #ffc;
$diff-state-color: $primary-text-color;
$diff-state-prefix-color: $secondary-text-color;
$diff-state-added: #009900;
$diff-state-deleted: #f80000;
$diff-state-changed: #f89406;
@@ -193,10 +194,10 @@ $view-lasso-stroke: #ff7f0e;
$view-lasso-fill: rgba(20,125,255,0.1);
$view-background: $secondary-background;
$view-select-mode-background: $secondary-background-selected;
$view-grid-color: #eee;
$node-label-color: #333;
$node-port-label-color: #888;
$node-border: #999;
$node-border-unknown: #f33;
$node-border-placeholder: #aaa;
@@ -211,6 +212,7 @@ $node-icon-background-color-opacity: 0.05;
$node-icon-border-color: #000;
$node-icon-border-color-opacity: 0.1;
$node-config-background: #f3f3f3;
$node-link-port-background: #eee;
@@ -295,6 +297,9 @@ $group-default-stroke: #999;
$group-default-stroke-opacity: 1;
$group-default-label-color: #a4a4a4;
$tourGuide-border: #c56c6c;
$tourGuide-heading-color: #c56c6c;
// Deprecated
$text-color-green: $text-color-success;
$info-text-code-color: $text-color-code;

View File

@@ -43,12 +43,24 @@
border-bottom: 1px solid $secondary-border-color;
box-shadow: 0 2px 6px $shadow;
}
.red-ui-debug-filter-row {
.red-ui-nodeList {
margin: 10px 0;
#red-ui-sidebar-debug-filter-node-list-row {
.red-ui-treeList-label.disabled {
font-style: italic;
color: $secondary-text-color-disabled;
}
.red-ui-treeList-label {
&.selected, &.selected .red-ui-treeList-sublabel-text {
background: inherit;
}
&.selected, &.selected .red-ui-treeList-sublabel-text {
background: inherit;
}
&.focus, &.focus .red-ui-treeList-sublabel-text {
background: $list-item-background-hover !important;
}
}
}
.red-ui-debug-msg {
position: relative;
border-bottom: 1px solid $debug-message-border;

View File

@@ -562,7 +562,7 @@ ul.red-ui-deploy-dialog-confirm-list {
width: 30px;
display: inline-block;
text-align: center;
color: $secondary-text-color;
color: $diff-state-prefix-color;
}
&.added {
@@ -577,9 +577,11 @@ ul.red-ui-deploy-dialog-confirm-list {
}
td.added {
background: $diff-state-added-background;
color: $diff-state-color;
}
td.removed {
background: $diff-state-deleted-background;
color: $diff-state-color;
}
tr.mergeHeader td {
color: $diff-merge-header-color;
@@ -652,7 +654,7 @@ ul.red-ui-deploy-dialog-confirm-list {
font-family: $monospace-font;
padding: 5px 10px;
text-align: left;
color: $secondary-text-color;
color: $diff-text-header-color;
background: $diff-text-header-background;
height: 30px;
vertical-align: middle;

View File

@@ -19,7 +19,7 @@
font-size: $primary-font-size;
position: absolute;
top: 100%;
width: 200px;
width: 230px;
left: 0;
z-index: 1000;
display: none;
@@ -46,7 +46,7 @@
& > li > a,
& > li > a:focus {
display: block;
padding: 4px 0 4px 32px;
padding: 4px 12px 4px 32px;
clear: both;
font-weight: normal;
line-height: 20px;
@@ -68,6 +68,10 @@
& > .disabled > a:hover,
& > .disabled > a:focus {
color: $menuDisabledColor;
.red-ui-popover-key {
color: $menuDisabledColor;
border-color: $menuDisabledColor;
}
}
& > .disabled > a:hover,
@@ -83,6 +87,7 @@
max-width: 14px;
}
.fa {
float: left;
width: 20px;
margin-left: -25px;
margin-top: 3px;
@@ -102,6 +107,20 @@
display: none;
}
}
.red-ui-menu-label {
display: flex;
& > :first-child {
flex-grow: 1
}
}
.red-ui-popover-key {
border: none;
padding: 0;
font-size: 13px;
// float: right;
color: $menuColor;
border-color: $menuColor;
}
}
}
@@ -113,6 +132,7 @@
.red-ui-menu-dropdown > li > a:hover,
.red-ui-menu-dropdown > li.open > a,
.red-ui-menu-dropdown > li > a:focus,
.red-ui-menu-dropdown-submenu:hover > a,
.red-ui-menu-dropdown-submenu:focus > a {
@@ -129,6 +149,7 @@
margin-top: -6px;
margin-left: -1px;
}
&.open > .red-ui-menu-dropdown,
&:hover > .red-ui-menu-dropdown {
display: block;
}
@@ -209,4 +230,4 @@ ul.red-ui-menu:not(.red-ui-menu-dropdown) {
}
}
}
}

View File

@@ -360,6 +360,7 @@ button.red-ui-button-small
position: absolute;
top: -3000px;
}
.form-row .red-ui-editor-node-label-form-row {
margin: 5px 0 0 50px;
label {

View File

@@ -21,6 +21,13 @@
stroke-dasharray: 10 5;
}
.nr-ui-view-slice {
stroke-width: 1px;
stroke: $view-lasso-stroke;
fill: none;
stroke-dasharray: 10 5;
}
.node_label_italic, // deprecated: use red-ui-flow-node-label-italic
.red-ui-flow-node-label-italic {
font-style: italic;
@@ -47,7 +54,7 @@
.red-ui-flow-port-label {
stroke-width: 0;
fill: $secondary-text-color;
fill: $node-port-label-color;
font-size: 16px;
dominant-baseline: middle;
text-anchor: middle;

View File

@@ -187,18 +187,21 @@
ul.red-ui-menu-dropdown {
background: $header-menu-background;
border: 1px solid $header-menu-background;
width: 250px !important;
width: 260px !important;
margin-top: 0;
li a {
color: $header-menu-color;
padding: 3px 40px;
padding: 3px 10px 3px 40px;
img {
max-width: 100%;
margin-right: 10px;
padding: 4px;
border: 3px solid transparent;
}
.red-ui-popover-key {
color: $header-menu-color-disabled !important;
border-color: $header-menu-color-disabled !important;
}
&.active img {
border: 3px solid $header-menu-item-border-active;
}
@@ -211,7 +214,6 @@
}
span.red-ui-menu-label {
font-size: 14px;
display: inline-block;
text-indent: 0px;
}
span.red-ui-menu-sublabel {
@@ -222,6 +224,7 @@
}
}
> li > a:hover,
> li.open > a,
> li > a:focus,
> li:hover > a,
> li:focus > a {

View File

@@ -26,6 +26,13 @@
box-shadow: none;
}
.ui-widget.ui-widget-content {
border: 1px solid $tertiary-border-color;
}
.ui-widget-content {
border: 1px solid $secondary-border-color;
}
.ui-widget-header {
color: $header-text-color;
}

View File

@@ -254,7 +254,7 @@ button.red-ui-palette-editor-upload-button {
padding: 2px 8px;
}
form {
width: 0;
width: 0;
}
}
.red-ui-palette-editor-upload {

View File

@@ -19,19 +19,23 @@
display: none;
position: absolute;
width: auto;
padding: 10px;
padding: 2px;
height: auto;
background: $popover-background;
color: $popover-color;
background: var(--red-ui-popover-border);
color: var(--red-ui-popover-color);
border-radius: 4px;
z-index: 1000;
font-family: $primary-font;
font-size: 14px;
line-height: 1.4em;
@include component-shadow;
border-color: $popover-background;
border-color: var(--red-ui-popover-border);
}
.red-ui-popover-content {
padding: 8px;
border-radius: 2px;
background: var(--red-ui-popover-background);
}
.red-ui-popover:after, .red-ui-popover:before {
border: solid transparent;
content: " ";
@@ -61,26 +65,26 @@
.red-ui-popover.red-ui-popover-right:after {
border-color: transparent;
border-right-color: $popover-background;
border-right-color: var(--red-ui-popover-border);
border-width: 10px;
margin-top: -10px;
}
.red-ui-popover.red-ui-popover-right:before {
border-color: transparent;
border-right-color: $popover-background;
border-right-color: var(--red-ui-popover-border);
border-width: 11px;
margin-top: -11px;
}
.red-ui-popover.red-ui-popover-left:after {
border-color: transparent;
border-left-color: $popover-background;
border-left-color: var(--red-ui-popover-border);
border-width: 10px;
margin-top: -10px;
}
.red-ui-popover.red-ui-popover-left:before {
border-color: transparent;
border-left-color: $popover-background;
border-left-color: var(--red-ui-popover-border);
border-width: 11px;
margin-top: -11px;
}
@@ -88,26 +92,26 @@
.red-ui-popover.red-ui-popover-bottom:after {
border-color: transparent;
border-bottom-color: $popover-background;
border-bottom-color: var(--red-ui-popover-border);
border-width: 10px;
margin-left: -10px;
}
.red-ui-popover.red-ui-popover-bottom:before {
border-color: transparent;
border-bottom-color: $popover-background;
border-bottom-color: var(--red-ui-popover-border);
border-width: 11px;
margin-left: -11px;
}
.red-ui-popover.red-ui-popover-top:after {
border-color: transparent;
border-top-color: $popover-background;
border-top-color: var(--red-ui-popover-border);
border-width: 10px;
margin-left: -10px;
}
.red-ui-popover.red-ui-popover-top:before {
border-color: transparent;
border-top-color: $popover-background;
border-top-color: var(--red-ui-popover-border);
border-width: 11px;
margin-left: -11px;
}
@@ -116,9 +120,10 @@
.red-ui-popover-size-small {
font-size: 12px;
padding: 5px 7px;
line-height: 1.8em;
.red-ui-popover-content {
padding: 1px 4px;
}
&.red-ui-popover-right:after, &.red-ui-popover-left:after {
border-width: 7px;
margin-top: -7px;
@@ -143,7 +148,7 @@
font-size: 11px;
font-family: $monospace-font;
margin-left: 3px;
border: 1px solid $popover-color;
border: 1px solid var(--red-ui-popover-color);
border-radius:3px;
padding: 1px 2px;
}
@@ -152,8 +157,8 @@
.red-ui-popover button.red-ui-button {
&:not(.primary) {
border-color: $popover-button-border-color;
background: $popover-background;
color: $popover-color !important;
background: var(--red-ui-popover-background);
color: var(--red-ui-popover-color) !important;
}
&:not(.primary):not(.disabled):not(.ui-button-disabled):hover {
border-color: $popover-button-border-color-hover;

View File

@@ -73,13 +73,13 @@
.red-ui-projects-dialog-screen-start {
.red-ui-projects-dialog-screen-start-hero {
text-align: center;
font-size: 2em;
font-size: 1.4em;
padding: 10px;
min-height: 60px;
min-height: 40px;
color: $primary-text-color;
}
.red-ui-projects-dialog-screen-start-body {
min-height: 400px;
min-height: 300px;
line-height: 1.6em;
p {
font-size: 1.1em;
@@ -92,7 +92,7 @@
}
button.red-ui-button.red-ui-projects-dialog-button {
width: calc(50% - 80px);
margin: 20px;
margin: 10px 20px;
height: auto;
line-height: 2em;
padding: 10px;

View File

@@ -204,6 +204,28 @@
font-style: italic;
color: $form-placeholder-color;
}
.red-ui-search-history {
button {
display: none;
position: absolute;
top: 8px;
right: 7px;
}
&:hover button {
display: inline;
}
}
.red-ui-search-historyHeader {
button {
position: absolute;
top: 10px;
right: 7px;
}
}
.red-ui-search-history-result {
}
.red-ui-search-result-action {
color: $primary-text-color;

View File

@@ -61,6 +61,7 @@
@import "ui/common/checkboxSet";
@import "ui/common/stack";
@import "ui/common/treeList";
@import "ui/common/autoComplete";
@import "dragdrop";
@@ -69,3 +70,5 @@
@import "debug";
@import "radialMenu";
@import "tourGuide";

View File

@@ -54,7 +54,7 @@ ul.red-ui-sidebar-node-config-list {
.red-ui-palette-icon-container {
font-size: 12px;
line-height: 30px;
background-color: $secondary-background-selected;
background-color: $node-icon-background-color;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
a {
@@ -63,10 +63,10 @@ ul.red-ui-sidebar-node-config-list {
bottom: 0;
left: 0;
right: 0;
color: $secondary-text-color;
color: $node-port-label-color;
&:hover {
text-decoration: none;
background: $secondary-background-hover;
background: $node-port-background-hover;
}
}
}
@@ -74,7 +74,7 @@ ul.red-ui-sidebar-node-config-list {
.red-ui-palette-node-config {
width: 160px;
height: 30px;
background: $primary-background;
background: $node-config-background;
color: $primary-text-color;
cursor: pointer;
}

View File

@@ -16,6 +16,7 @@
.red-ui-sidebar-info {
height: 100%;
overflow: hidden;
}
.red-ui-sidebar-info hr {
margin: 10px 0;
@@ -212,6 +213,9 @@ div.red-ui-info-table {
border: none;
}
}
p {
display: inline;
}
}
.red-ui-help-info-header {
i {
@@ -230,7 +234,26 @@ div.red-ui-info-table {
}
}
}
table {
border-collapse: collapse;
border: 1px solid var(--red-ui-secondary-border-color);
margin : 8px 0 8px 0;
min-width : 300px;
overflow : hidden;
}
table thead tr {
background-color: var(--red-ui-primary-background); //$primary-text-color;
border-bottom: 1px solid var(--red-ui-secondary-border-color);
color: var(--red-ui-header-text-color);
text-align: left;
}
table th,
table td {
padding: 6px 8px;
}
table tbody tr:nth-of-type(even) {
background-color: var(--red-ui-tertiary-background); //$primary-background;
}
}
.red-ui-sidebar-info-stack {
height: 100%;
@@ -411,16 +434,19 @@ div.red-ui-info-table {
}
.red-ui-info-outline-item-controls {
position: absolute;
top:0;
bottom: 0;
right: 0px;
padding: 2px 3px 0 1px;
top:1px;
bottom: 1px;
right: 1px;
padding: 1px 2px 0 1px;
text-align: right;
background: $list-item-background;
.red-ui-treeList-label:hover & {
background: $list-item-background-hover;
}
.red-ui-treeList-label.focus & {
background: $list-item-background-hover;
}
.red-ui-treeList-label.selected & {
background: $list-item-background-selected;
}
@@ -435,6 +461,12 @@ div.red-ui-info-table {
border: none;
background: none;
}
.fa-circle-thin {
display: none;
}
.fa-eye {
display: none;
}
}
.red-ui-info-outline-item-control-reveal,
.red-ui-info-outline-item-control-action {
@@ -446,7 +478,17 @@ div.red-ui-info-table {
display: inline-block;
}
}
.fa-eye-slash {
display: none;
}
.red-ui-info-outline-item.red-ui-info-outline-item-hidden & {
.fa-eye-slash {
display: inline-block;
}
.fa-eye {
display: none;
}
}
.fa-ban {
display: none;
}

View File

@@ -21,6 +21,9 @@
height: 35px;
box-sizing: border-box;
.hide-tab {
transition: width 0.1s ease-in;
}
.red-ui-tabs-scroll-container {
height: 60px;
overflow-x: scroll;
@@ -142,13 +145,18 @@
padding-right: 21px;
}
&.red-ui-tabs-add {
padding-right: 35px;
padding-right: 29px;
}
&.red-ui-tabs-add.red-ui-tabs-scrollable {
padding-right: 59px;
padding-right: 53px;
}
&.red-ui-tabs-add.red-ui-tabs-menu.red-ui-tabs-scrollable,
&.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-scrollable {
padding-right: 95px;
padding-right: 83px;
}
&.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-menu.red-ui-tabs-scrollable {
padding-right: 113px;
}
&.red-ui-tabs-collapsible {
@@ -232,13 +240,14 @@
a {
@include workspace-button;
line-height: 32px;
height: 32px;
width: 32px;
line-height: 30px;
height: 28px;
width: 28px;
margin-left: 2px;
margin-right: 2px;
margin-top: 3px;
margin-right:3px;
margin-left:3px;
border: 1px solid $primary-border-color;
margin-bottom: 3px;
border: none;
z-index: 2;
}
}
@@ -280,6 +289,8 @@
border-left: none;
border-right: none;
border-top: none;
border-bottom: 1px solid $primary-border-color;
line-height: 34px;
}
}
.red-ui-tab-scroll-left {
@@ -296,15 +307,30 @@
}
.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right {
right: 38px;
right: 32px;
}
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-menu .red-ui-tab-scroll-right,
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search .red-ui-tab-scroll-right {
right: 76px;
right: 64px;
}
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-menu .red-ui-tabs-add,
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search .red-ui-tabs-add {
right: 38px;
right: 32px;
}
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-menu {
.red-ui-tab-scroll-right {
right: 96px;
}
.red-ui-tabs-add {
right: 64px;
}
.red-ui-tabs-search {
right: 32px;
}
}
.red-ui-tabs-fade {
position: absolute;
bottom: 0;
@@ -363,7 +389,19 @@ i.red-ui-tab-icon {
vertical-align: top;
}
.red-ui-tab-hide {
.fa-eye-slash {
display: none;
}
&:hover {
.fa-eye-slash {
display: inline
}
.fa-eye {
display: none
}
}
}
.red-ui-tab-close {
display: none;
background: $tab-background-inactive;

View File

@@ -0,0 +1,124 @@
.red-ui-tourGuide-shade {
position: absolute;
top:0;
left:0;
bottom:0;
right:0;
z-index: 2000;
overflow: hidden;
}
.red-ui-tourGuide-shade-focus {
display: block;
width: 100px;
height: 100px;
position: absolute;
z-index: 2001;
transform: translate(-50%, -50%);
border-radius: 50%;
border: 2px solid var(--red-ui-tourGuide-border);
&.transition {
transition: 0.4s ease;
transition-property: width,height;
}
&::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
border: solid 6000px var(--red-ui-shade-color);
margin-left: -6000px;
margin-top: -6000px;
pointer-events: none;
}
}
.red-ui-popover.red-ui-tourGuide-popover {
z-index: 2003;
--red-ui-popover-background: var(--red-ui-secondary-background);
--red-ui-popover-border: var(--red-ui-tourGuide-border);
--red-ui-popover-color: var(--red-ui-primary-text-color);
.red-ui-popover-content {
h2 {
text-align: center;
margin-top: 0px;
line-height: 1.2em;
color: var(--red-ui-tourGuide-heading-color);
i.fa {
font-size: 1.5em
}
}
}
}
.red-ui-tourGuide-toolbar {
min-height: 36px;
position: relative;
display: flex;
align-items: flex-end;
}
.red-ui-tourGuide-breadcrumbs {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 6px;
& > div {
display: inline-block;
}
i {
line-height: 16px;
margin: 0 3px;
}
}
.red-ui-tourGuide-popover-description {
padding: 10px 20px 5px;
img {
max-height: 150px;
border: 1px solid var(--red-ui-tourGuide-border);
border-radius: 2px;
}
}
.red-ui-tourGuide-popover-full {
.red-ui-tourGuide-popover-description {
padding: 20px 40px 10px;
text-align: center;
}
}
.red-ui-popover.red-ui-tourGuide-popover button.red-ui-button {
&:not(.primary) {
background: var(--red-ui-secondary-background);
color: var(--red-ui-primary-text-color) !important;
}
&:not(.primary):not(.disabled):not(.ui-button-disabled):hover {
border-color: $popover-button-border-color-hover;
}
}
// .red-ui-tourGuide-popover-bounce {
// animation: 10s ease-in 5s infinite both red-ui-tourGuide-popover-bounce;
// }
// // @keyframes *must* be on multiple lines so build-custom-theme can filter them out
// @keyframes red-ui-tourGuide-popover-bounce {
// 0%,
// 10%,
// 100% {
// -webkit-transform: translateY(0);
// transform: translateY(0);
// }
// 2%,8% {
// -webkit-transform: translateY(-5px);
// transform: translateY(-5px);
// }
// 5% {
// -webkit-transform: translateY(5px);
// transform: translateY(5px);
// }
// }

View File

@@ -0,0 +1,5 @@
.red-ui-autoComplete-container {
&.red-ui-popover-panel {
border-top: none;
}
}

View File

@@ -89,18 +89,27 @@
color: $list-item-color;
text-decoration: none;
}
&.focus, &.focus .red-ui-treeList-sublabel-text {
background: $list-item-background-hover;
outline: 1px solid $form-input-focus-color !important;
outline-offset: -1px;
color: $list-item-color;
}
&.selected, &.selected .red-ui-treeList-sublabel-text {
background: $list-item-background-selected;
outline: none;
color: $list-item-color;
}
input.red-ui-treeList-checkbox {
input.red-ui-treeList-checkbox,
input.red-ui-treeList-radio {
margin: 0;
}
}
.red-ui-treeList-label-text {
margin-left: 4px;
overflow: hidden;
text-overflow: ellipsis;
&:empty {
min-height: 20px;
}
@@ -120,6 +129,7 @@
.red-ui-treeList-icon {
display: inline-block;
flex-shrink: 0;
width: 20px;
text-align: center;
}

View File

@@ -16,7 +16,7 @@
.red-ui-typedInput-container {
border: 1px solid $form-input-border-color;
border-radius: 4px;
border-radius: 5px;
height: 34px;
line-height: 14px;
display: inline-flex;
@@ -81,7 +81,8 @@
z-index: 2000;
a {
padding: 6px 18px 6px 6px;
display: block;
display: flex;
align-items: center;
border-bottom: 1px solid $secondary-border-color;
color: $form-text-color;
&:hover {
@@ -98,7 +99,7 @@
background: $workspace-button-background-active;
}
input[type="checkbox"] {
margin-right: 6px;
margin: 0 6px 0 0;
}
}
.red-ui-typedInput-icon {

View File

@@ -81,12 +81,18 @@
--red-ui-node-status-changed-border: #{$node-status-changed-border};
--red-ui-node-status-changed-background: #{$node-status-changed-background};
--red-ui-node-border: #{$node-border};
--red-ui-node-port-background:#{$node-port-background};
--red-ui-node-label-color: #{$node-label-color};
--red-ui-node-selected-color: #{$node-selected-color};
--red-ui-port-selected-color: #{$port-selected-color};
--red-ui-popover-background: #{$popover-background};
--red-ui-popover-border: #{$popover-border};
--red-ui-popover-color: #{$popover-color};
--red-ui-tourGuide-border: #{$tourGuide-border};
--red-ui-tourGuide-heading-color: #{$tourGuide-heading-color};
}

View File

@@ -58,7 +58,6 @@
.red-ui-workspace-select-mode {
.red-ui-workspace-chart-background {
opacity: 0.7;
// fill: $view-select-mode-background;
}
.red-ui-workspace-chart-grid line {
opacity: 0.8;

View File

@@ -0,0 +1,101 @@
export default {
steps: [
{
title: {
'en-US': 'Create your first flow',
'ja': 'はじめてのフローを作成'
},
width: 400,
description: {
'en-US': 'This tutorial will guide you through creating your first flow',
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。'
},
nextButton: 'start'
},
{
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
description: {
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。'
},
wait: {
type: "dom-event",
event: "click",
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add a"
},
},
{
element: '.red-ui-palette-node[data-palette-type="inject"]',
direction: 'right',
description: {
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
'ja': 'パレットには、利用できる全てのードが一覧表示されます。injectードをワークスペースにドラッグします。'
},
fallback: 'inset-bottom-right',
wait: {
type: "nr-event",
event: "nodes:add",
filter: function(event) {
if (event.type === "inject") {
this.injectNode = event;
return true;
}
return false
}
},
complete: function() {
$('.red-ui-palette-node[data-palette-type="inject"]').css("z-index","auto");
}
},
{
element: '.red-ui-palette-node[data-palette-type="debug"]',
direction: 'right',
description: {
'en-US': 'Next, drag a new Debug node into the workspace.',
'ja': '次に、debugードをワークスペースにドラッグします。'
},
fallback: 'inset-bottom-right',
wait: {
type: "nr-event",
event: "nodes:add",
filter: function(event) {
if (event.type === "debug") {
this.debugNode = event;
return true;
}
return false
}
},
complete: function() {
$('.red-ui-palette-node[data-palette-type="debug"]').css("z-index","auto");
},
},
{
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
description: {
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
'ja': 'injectードの出力から、debugードの入力へワイヤーで接続します。'
},
fallback: 'inset-bottom-right',
wait: {
type: "nr-event",
event: "links:add",
filter: function(event) {
return event.source.id === this.injectNode.id && event.target.id === this.debugNode.id;
}
},
},
{
element: "#red-ui-header-button-deploy",
description: {
'en-US': 'Deploy your changes so the flow is active in the runtime',
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。'
},
width: 200,
wait: {
type: "dom-event",
event: "click"
},
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Some files were not shown because too many files have changed in this diff Show More