mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
41 Commits
pr_3744
...
phase-out-
Author | SHA1 | Date | |
---|---|---|---|
|
2350540a98 | ||
|
c021c4020e | ||
|
11a6925ae4 | ||
|
24ff5262d9 | ||
|
c24d7fafa9 | ||
|
30ea300f65 | ||
|
04f4d5274d | ||
|
1f9695abd7 | ||
|
1b94cc3ac0 | ||
|
4698d5d2fc | ||
|
92bc9d81c5 | ||
|
952cfaec14 | ||
|
637c44aa59 | ||
|
6e5fc29dca | ||
|
8bd02d0c36 | ||
|
c6cfbb8755 | ||
|
75d3444391 | ||
|
c648e1e8d6 | ||
|
e2f42fddb5 | ||
|
f93fe684c0 | ||
|
ee378ea0c4 | ||
|
613d34e6e6 | ||
|
4c784af55d | ||
|
b28595c814 | ||
|
fca7beec01 | ||
|
f813f03a46 | ||
|
6ff2232df3 | ||
|
e3b1f058cd | ||
|
542e9cacc2 | ||
|
0a0a7ca39b | ||
|
cee287da99 | ||
|
c8e4df94f9 | ||
|
c86e4f52a0 | ||
|
44216310ca | ||
|
5c69599e78 | ||
|
e4098d3991 | ||
|
55a94d659b | ||
|
7a048d5b32 | ||
|
e14dd06a94 | ||
|
62332a2b56 | ||
|
639030924f |
560
CHANGELOG.md
560
CHANGELOG.md
@@ -1,3 +1,41 @@
|
||||
#### 3.0.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Use theme page and header values if settings.js values are not present (#3767) @Steve-Mcl
|
||||
- Focus editor for undo after some actions in menu (#3759) @kazuhitoyokoi
|
||||
- Ensure node icon shade has properly rounded corners (#3763) @knolleary
|
||||
- Fix storing subflow credential type when input has multiple types (#3762) @knolleary
|
||||
- Ensure global-config and flow-config have info in the hierarchy popover (#3752) @Steve-Mcl
|
||||
- Include dirty state in history event (#3748) @Steve-Mcl
|
||||
- Fix display direction of context sub-menu (#3746) @knolleary
|
||||
- Fix clear pinned paths of debug sidebar menu (#3745) @HiroyasuNishiyama
|
||||
- prevent exception generating tooltip for deleted nodes (#3742) @Steve-Mcl
|
||||
- Fix context menu issues ready for v3 beta.5 (#3741) @Steve-Mcl
|
||||
- Do not generate new node-ids when pasting a cut flow (#3729) @knolleary
|
||||
- Fix to prevent node from moving out of workspace (#3731) @HiroyasuNishiyama
|
||||
- Don't let themes change disabled config node background color (#3736) @bonanitech
|
||||
- Move colors left behind in #3692 to CSS variables (#3737) @bonanitech
|
||||
- Fix handling of global debug message (#3733) @HiroyasuNishiyama
|
||||
- Fix label overflow @ config-node palette (#3730) @ralphwetzel
|
||||
- Fix defaulting to monaco if settings does not contain codeEditor (#3732) @knolleary
|
||||
- Disable keyboard shortcut mapping when showing Edit[..]Dialog (#3700) @ralphwetzel
|
||||
- Update add-junction menu to work in more cases (#3727) @knolleary
|
||||
- Ensure importMap is not null when using import UI (#3723) @Steve-Mcl
|
||||
- Add Japanese translations for v3.0-beta.4 (#3724) @kazuhitoyokoi
|
||||
- Fix "split with" on virtual links (#3766) @Steve-Mcl
|
||||
|
||||
Runtime
|
||||
|
||||
- Do not remove unknown credentials of Subflow Modules (#3728) @knolleary
|
||||
- Add missing entries from beta.4 changelog (#3721) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Fix change node, not handling from field properly when using context (#3754) @Fadoli
|
||||
- Link Call: Fix linkcall registry bugs (#3751) @Steve-Mcl
|
||||
- WebSocket: Fix close timeout of websocket node (#3734) @HiroyasuNishiyama
|
||||
|
||||
#### 3.0.0-beta.4: Beta Release
|
||||
|
||||
Editor
|
||||
@@ -185,528 +223,6 @@ Nodes
|
||||
- Watch: Update Watch node to use node-watch module (#3559 #3569) @knolleary
|
||||
- WebSocket: call done after ws disconnects (#3531) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.2: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- Fix "close timed out" error when performing full deploy or modifying broker node. (#3451) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Handle mixed-cased filter terms in keyboard shortcut dialog (#3444) @knolleary
|
||||
- Prevent duplicate links being added between nodes (#3442) @knolleary
|
||||
- Fix to hide tooltip after removing subflow tab (#3391) @HiroyasuNishiyama
|
||||
- Fix node validation to be applied to config node (#3397) @HiroyasuNishiyama
|
||||
- Fix: Dont add wires to undo buffer twice (#3437) @Steve-Mcl
|
||||
|
||||
Runtime
|
||||
|
||||
- Improve module location parsing (of stack info) when adding hook (#3447) @Steve-Mcl
|
||||
- Fix substitution of NR_NODE_PATH (#3445) @HiroyasuNishiyama
|
||||
- Remove console.log when ignoring disabled module (#3439) @knolleary
|
||||
- Improve "Unexpected Node Error" logging (#3446) @Steve-Mcl
|
||||
|
||||
Nodes
|
||||
|
||||
- Debug: Fix no-prototype-builtins bug in debug node and utils (#3394) @Alkarex
|
||||
- Delay: Fix Japanese message of delay node (#3434)
|
||||
- Allow nbRateUnits to be undefined when validating (#3443) @knolleary
|
||||
- Coding help for recently added node-red Predefined Environment Variables (#3440) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add editorTheme.tours property to default settings file (#3375) @knolleary
|
||||
- Remember Zoom level and Sidebar tab selection between sessions (#3361) @knolleary
|
||||
- Fix timing issue when merging background changes fixes #3364 (#3373) @Steve-Mcl
|
||||
- Use a nodes palette label in help tree (#3372) @Steve-Mcl
|
||||
- Subflow: Add labels to OUTPUT nodes (#3352) @ralphwetzel
|
||||
- Fix vertical align subflow port (#3370) @knolleary
|
||||
- Make actions list i18n ready and Japanese translation (#3359) @HiroyasuNishiyama
|
||||
- Update tour for 2.2.0 (#3378) @knolleary
|
||||
- Include paletteLabel when building search index (#3380) @Steve-Mcl
|
||||
- Fix opening/closing subflow template not to make subflow changed (#3382) @HiroyasuNishiyama
|
||||
- Add Japanese translations for v2.2.0 (#3353, #3381) @kazuhitoyokoi
|
||||
|
||||
Runtime
|
||||
|
||||
- Add support for accessing node id & name as environment variable (#3356) @HiroyasuNishiyama
|
||||
- Clear context contents when switching projects (#3243) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- MQTT: reject invalid topics (#3374) @Steve-Mcl
|
||||
- Function: Expose node.path property (#3371) @knolleary
|
||||
- Function: Update `node` declarations in func.d.ts (#3377) @Steve-Mcl
|
||||
|
||||
#### 2.2.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add search history to main search box (#3262) @knolleary
|
||||
- Check availability of type of config node on deploy (#3304) @k-toumura
|
||||
- Add wire-slice mode to delete wires with Ctrl-RHClick-Drag (#3340) @knolleary
|
||||
- Wiring keyboard shortcuts (#3288) @knolleary
|
||||
- Snap nodes on grid using either edge as reference (#3289) @knolleary
|
||||
- Detach node action (#3338) @knolleary
|
||||
- Highlight links when selecting nodes (#3323) @knolleary
|
||||
- Allow multiple links to be selected by ctrl-click (#3294) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- JSON: Let JSON node attempt to parse buffer if it contains a valid string (#3296) @dceejay
|
||||
- Remove use of verbose flag in core nodes - and use node.debug level instead (#3300) @dceejay
|
||||
- TCP: Add TLS option to tcp client nodes (#3307) @dceejay
|
||||
- WebSocket: Implemented support for Websocket Subprotocols in WS Client Node. (#3333) @tobiasoort
|
||||
|
||||
#### 2.1.6: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Revert copy-text change and apply alternative fix (#3363) @knolleary
|
||||
- Update marked to latest (#3362) @knolleary
|
||||
- fix to make start of property error tooltip messages aligned (#3358) @HiroyasuNishiyama
|
||||
|
||||
Nodes
|
||||
|
||||
- Inject: fix JSON propety validation of inject node (#3349) @HiroyasuNishiyama
|
||||
- Delay: fix unit value validation of delay node (#3351) @HiroyasuNishiyama
|
||||
|
||||
#### 2.1.5: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Handle reporting error location when stack is truncated (#3346) @knolleary
|
||||
- Initialize passport when only adminAuth.tokens is set (#3343) @knolleary
|
||||
- Add log logging (#3342) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Fix copy buttons on the debug window (another method) (#3331) @kazuhitoyokoi
|
||||
- Add Japanese translations for hidden flow (#3302) @kazuhitoyokoi
|
||||
- Improve jsonata legacy mode detection regex (#3345) @knolleary
|
||||
- Fix generating flow name with incrementing number (#3347) @knolleary
|
||||
- resume focus after import/export dialog close (#3337) @HiroyasuNishiyama
|
||||
- Fix findPreviousVisibleTab action (#3321) @knolleary
|
||||
- Fix storing hidden tab state when not hidden via action (#3312) @knolleary
|
||||
- Avoid adding empty env properties to tabs/groups (#3311) @knolleary
|
||||
- Fix hide icon in tour guide (#3301) @kazuhitoyokoi
|
||||
|
||||
Nodes
|
||||
|
||||
- File: Update file node examples according to node name change (#3335) @HiroyasuNishiyama
|
||||
- Filter (RBE): Fix for filter node narrrowbandEq mode start condition failure (#3339) @dceejay
|
||||
- Function: Prevent function scrollbar from obscuring expand button (#3348) @knolleary
|
||||
- Function: load extralibs when expanding monaco. fixes #3319 (#3334) @Steve-Mcl
|
||||
- Function: Update Function to use correct api to access env vars (#3310) @knolleary
|
||||
- HTTP Request: Fix basic auth with empty username or password (#3325) @hardillb
|
||||
- Inject: Fix incorrect clearing of blank payload property in Inject node (#3322) @knolleary
|
||||
- Link Call: add link call example (#3336) @HiroyasuNishiyama
|
||||
- WebSocket: Only setup ws client heartbeat once it is connected (#3344) @knolleary
|
||||
- Update Japanese translations in node help (#3332) @kazuhitoyokoi
|
||||
|
||||
#### 2.1.4: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- fix env var access using $parent for groups (#3278) @HiroyasuNishiyama
|
||||
- Add proper error handling for 404 errors when serving debug files (#3277) @knolleary
|
||||
- Add Japanese translations for Node-RED v2.1.0-beta.1 (#3179) @kazuhitoyokoi
|
||||
- Include full user object on login audit events (#3269) @knolleary
|
||||
- Remove styling from de locale files (#3237) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Change tab hide button icon to an eye and add search option (#3282) @knolleary
|
||||
- Fix i18n handling of namespaces with spaces in (#3281) @knolleary
|
||||
- Trigger change event when autoComplete fills in input (#3280) @knolleary
|
||||
- Apply CN i18n fix (#3279) @knolleary
|
||||
- fix select menu label of config node to use paletteLabel (#3273) @HiroyasuNishiyama
|
||||
- fix removed tab not to cause node conflict (#3275) @HiroyasuNishiyama
|
||||
- Group diff fix (#3239) @knolleary
|
||||
- Only toggle disabled workspace flag if on activeWorkspace (#3252) @knolleary
|
||||
- Do not show status for disabled nodes (#3253) @knolleary
|
||||
- Set dimension value for tour guide (#3265) @kazuhitoyokoi
|
||||
- Avoid redundant initialisation of TypedInput type (#3263) @knolleary
|
||||
- Don't let themes change flow port label color (#3270) @bonanitech
|
||||
- Fix treeList gutter calculation to handle floating gutters (#3238) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Debug: Handle RegExp types in Debug sidebar (#3251) @knolleary
|
||||
- Delay: fix 2nd output when in rate limit per topic modes (#3261) @dceejay
|
||||
- Link: fix to show link target when selected (#3267) @HiroyasuNishiyama
|
||||
- Inject: Do not modify inject node props in oneditprepare (#3242) @knolleary
|
||||
- HTTP Request: HTTP Basic Auth should always add : between username and password even if empty (#3236) @hardillb
|
||||
|
||||
#### 2.1.3: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Update gen-publish script to update 'next' tag for main releases
|
||||
- Add environment variable to enable/disable tours (#3221) @hardillb
|
||||
- Fix loading non-default language files leaving runtime in wrong locale (#3225) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Refresh editor settings whenever a node is added or enabled (#3227) @knolleary
|
||||
- Revert spinner css change that made it shrink in some cases (#3229) @knolleary
|
||||
- Fix import notification message when importing config nodes (#3224) @knolleary
|
||||
- Handle changing types of TypedInput repeatedly (#3223) @knolleary
|
||||
|
||||
|
||||
#### 2.1.2: Maintenance Release
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- node-red-pi: Remove bash dependency (#3216) @a16bitsysop
|
||||
|
||||
Editor
|
||||
|
||||
- Improved regex for markdown renderer (#3213) @GerwinvBeek
|
||||
- Fix TypedInput initialisation (#3220) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- MQTT: fix datatype in node config not used. fixes #3215 (#3219) @Steve-Mcl
|
||||
|
||||
#### 2.1.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Ensure tourGuide popover doesn't fall offscreen (#3212) @knolleary
|
||||
- Fix issue with old inject nodes that migrated topic to 'string' type (#3210) @knolleary
|
||||
- Add cache-busting query params to index.mst (#3211) @knolleary
|
||||
- Fix TypedInput validation of type without options (#3207) @knolleary
|
||||
|
||||
#### 2.1.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Position popover properly on a scrolled page
|
||||
- Fixes from 2.1.0-beta.2 (#3202) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Link Out: Fix saving link out node links (#3201) @knolleary
|
||||
- Switch: Refix #3170 - copy switch rule type when adding new rule
|
||||
- TCP Request: Add string option to TCP request node output (#3204) @dceejay
|
||||
|
||||
#### 2.1.0-beta.2: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix switching projects (#3199) @knolleary
|
||||
- Use locale setting when installing/enabling node (#3198) @knolleary
|
||||
- Do not show projects-wecome dialog until welcome tour completes (#3197) @knolleary
|
||||
- Fix converting selection to subflow (#3196) @knolleary
|
||||
- Avoid conflicts with native browser cmd-ctrl type shortcuts (#3195) @knolleary
|
||||
- Ensure message tools stay attached to top-level entry in Debug/Context (#3186) @knolleary
|
||||
- Ensure tab state updates properly when toggling enable state (#3175) @knolleary
|
||||
- Improve handling of long labels in TreeList (#3176) @knolleary
|
||||
- Shift-click tab scroll arrows to jump to start/end (#3177) @knolleary
|
||||
|
||||
Runtime
|
||||
|
||||
- Update package dependencies
|
||||
- Update to latest node-red-admin
|
||||
|
||||
Nodes
|
||||
|
||||
- Dynamic MQTT connections (#3189)
|
||||
- Link: Filter out Link Out Return nodes in Link In edit dialog Fixes #3187
|
||||
- Link: Fix link call label (#3200) @knolleary
|
||||
- Debug: Redesign debug filter options and make them persistant (#3183) @knolleary
|
||||
- Inject: Widen Inject interval box for >1 digit (#3184) @knolleary
|
||||
- Switch: Fix rule focus when switch 'otherwise' rule is used (#3185) @knolleary
|
||||
|
||||
#### 2.1.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add Tour Guide component (#3136) @knolleary
|
||||
- Allow tabs to be hidden (#3120) @knolleary
|
||||
- Add align actions to editor (#3110) @knolleary
|
||||
- Add support of environment variable for tab & group (#3112) @HiroyasuNishiyama
|
||||
- Add autoComplete widget and add to TypedInput for msg. props (#3171) @knolleary
|
||||
- Render node documentation to node-red style guide when written in markdown. (#3169) @Steve-Mcl
|
||||
- Allow colouring of tab icon svg (#3140) @harmonic7
|
||||
- Restore tab selection after merging conflicts (#3151) @GerwinvBeek
|
||||
- Fix serving of theme files on Windows (#3154) @knolleary
|
||||
- Ensure config-node select inherits width properly from input (#3155) @knolleary
|
||||
- Do better remembering TypedInput values whilst switching types (#3159) @knolleary
|
||||
- Update monaco to 0.28.1 (#3153) @knolleary
|
||||
- Improve themeing of tourGuide (#3161) @knolleary
|
||||
- Allow a node to specify a filter for the config nodes it can pick from (#3160) @knolleary
|
||||
- Allow RED.notify.update to modify any notification setting (#3163) @knolleary
|
||||
- Fix typo in ko editor.json Fixes #3119
|
||||
- Improve RED.actions api to ensure actions cannot be overridden
|
||||
- Ensure treeList row has suitable min-height when no content Fixes #3109
|
||||
- Refactor edit dialogs to use separate edit panes
|
||||
- Ensure type select button is not focussable when TypedInput only has one type
|
||||
- Place close tab link in front of fade
|
||||
|
||||
Runtime
|
||||
|
||||
- Improve error reporting with oauth login strategies (#3148) @knolleary
|
||||
- Add allowUpdate feature to externalModules.palette (#3143) @knolleary
|
||||
- Improve node install error reporting (#3158) @knolleary
|
||||
- Improve unit test coverage (#3168) @knolleary
|
||||
- Allow coreNodesDir to be set to false (#3149) @hardillb
|
||||
- Update package dependencies
|
||||
- uncaughtException debug improvements (#3146) @renatojuniorrs
|
||||
|
||||
Nodes
|
||||
|
||||
- Change: Add option to deep-clone properties in Change node (#3156) @knolleary
|
||||
- Delay: Add push to front of rate limit queue. (#3069) @dceejay
|
||||
- File: Add paletteLabel to file nodes to make read/write more obvious (#3157) @knolleary
|
||||
- HTTP Request: Extend HTTP request node to log detailed timing information (#3116) @k-toumura
|
||||
- HTTP Response: Fix sizing of HTTP Response header fields (#3164) @knolleary
|
||||
- Join: Support for msg.restartTimeout (#3121) @magma1447
|
||||
- Link Call: Add Link Call node (#3152) @knolleary
|
||||
- Switch: Copy previous rule type when adding rule to switch node (#3170) @knolleary
|
||||
- Delay node: add option to send intermediate messages on separate output (#3166) @knolleary
|
||||
- Typo in http request set method translation (#3173) @mailsvb
|
||||
|
||||
#### 2.0.6: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix typo in ko editor.json Fixes #3119
|
||||
- Change fade color when hovering an inactive tab (#3106) @bonanitech
|
||||
- Ensure treeList row has suitable min-height when no content Fixes #3109
|
||||
|
||||
Runtime
|
||||
|
||||
- Update tar to latest (#3128) @aksswami
|
||||
- Give passport verify callback the same arity as the original callback (#3117) @dschmidt
|
||||
- Handle HTTPS Key and certificate as string or buffer (#3115) @bartbutenaers
|
||||
|
||||
#### 2.0.5: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Remove default ctrl-enter keybinding from monaco editor Fixes #3093
|
||||
|
||||
Runtime
|
||||
|
||||
- Update tar dependency
|
||||
- Add support for maintenance streams in generate-publish-script
|
||||
|
||||
|
||||
Nodes
|
||||
|
||||
- Fix regression in Join node when manual joining array with msg.parts present Fixes #3096
|
||||
|
||||
#### 2.0.4: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix tab fade CSS for when using themes (#3085) @bonanitech
|
||||
- Handle just-copied-but-not-deployed node with credentials in editor Fixes #3090
|
||||
|
||||
Nodes
|
||||
|
||||
- Filter: Fix RBE node handling of default topi property Fixes #3087
|
||||
- HTTP Request: Handle partially encoded url query strings in request node
|
||||
- HTTP Request: Fix support for supplied CA certs (#3089) @hardillb
|
||||
- HTTP Request: Ensure TLS Cert is used (#3092) @hardillb
|
||||
- Inject: Fix inject now button unable to send empty props
|
||||
- Inject: Inject now button success notification should use label with updated props
|
||||
|
||||
#### 2.0.3: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- HTML: Fix HTML parsing when body is included in the select tag Fixes #3079
|
||||
- HTTP Request: Preserve case of user-provided http headers in request node Fixes #3081
|
||||
- HTTP Request: Set decompress to false for HTTP Request to keep 1.x compatibility Fixes #3083
|
||||
- HTTP Request: Add unit tests for HTTP Request encodeURI and error response
|
||||
- HTTP Request: Do not throw HTTP errors in request node Fixes #3082
|
||||
- HTTP Request: Ensure uri is properly encoded before passing to got module Fixes #3080
|
||||
|
||||
#### 2.0.2: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Use file:// url with dynamic import
|
||||
- Detect if agent-base has patched https.request and undo it Fixes #3072
|
||||
|
||||
Editor
|
||||
|
||||
- Fix tab fade css because Safari Fixes #3073
|
||||
- Fix error closing library dialog with monaco
|
||||
- Handle other error types in Manage Palette view
|
||||
|
||||
|
||||
Nodes
|
||||
|
||||
- HTTP Request node - ignore invalid cookies rather than fail request Fixes #3075
|
||||
- Fix msg.reset handling in Delay node Fixes #3074
|
||||
|
||||
#### 2.0.1: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- Function: Ensure default module export is exposed in Function node
|
||||
|
||||
#### 2.0.0: Milestone Release
|
||||
|
||||
**Migration from 1.x**
|
||||
|
||||
- Node-RED now requires Node.js 12.x or later.
|
||||
|
||||
- The following nodes have had significant dependency updates. Unless stated,
|
||||
they should be fully backward compatible.
|
||||
|
||||
- RBE: Relabelled as 'filter' to make it more discoverable and made part of
|
||||
the core palette, rather than as a separate module.
|
||||
- Tail: This node has been removed from the default palette. You can reinstall it
|
||||
from node-red-node-tail
|
||||
- HTTP Request: Reimplemented with a different underlying module. We have
|
||||
tried to maintain 100% functional compatibility, but it is possible
|
||||
some edge cases remain.
|
||||
- JSON: The schema validation option no longer supports JSON-Schema draft-04
|
||||
- HTML: Its underlying module has had a major version update. Should be fully
|
||||
backward compatible.
|
||||
|
||||
- `functionExternalModules` is now enabled by default for new installs.
|
||||
If you have an existing settings file that contains this setting, you will
|
||||
need to set it to `true` yourself.
|
||||
|
||||
The external modules will now get installed in your Node-RED user directory,
|
||||
(`~/.node-red`) rather than in a subdirectory. This means all dependencies will
|
||||
be listed in your top-level `package.json`. If you have existing external modules,
|
||||
they will get reinstalled to the new location when you first run Node-RED 2.0.
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- Fix missing dependencies (#3052, #2057) @kazuhitoyokoi
|
||||
- Ensure node.types is defined if node html file missing
|
||||
- Fix reporting of type_already_registered error
|
||||
- Move install location of external modules (#3064) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Update translations (#3063) @kazuhitoyokoi
|
||||
- Add a slight fade to tab labels that overflow
|
||||
- Show config node details when selected in outliner
|
||||
- Fix layout of info outliner for subflow entries
|
||||
|
||||
Nodes
|
||||
|
||||
- Delay: let `msg.flush` specify how many messages to flush from node (#3059) @dceejay
|
||||
- Function: external modules is now enabled by default (#3065) @knolleary
|
||||
- Function: external modules now supports both ES6 and CJS modules (#3065) @knolleary
|
||||
- WebSocket: add option for client node to send automatic pings (#3056) @knolleary
|
||||
|
||||
|
||||
##### 2.0.0-beta.2: Beta Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Add `node-red admin init` (via `node-red-admin@2.1.0`)
|
||||
- Move to GH Actions rather than Travis for build (#3042) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Include hasUser=false config nodes when exporting whole flow (#3048)
|
||||
- Emit nodes:change for any updated config node when node deleted/added
|
||||
- Fix padding of compact notification Closes #3045
|
||||
- Ensure any html in changelog is escaped before displaying
|
||||
- Add support for Map/Set property types on Debug (#3040) @knolleary
|
||||
- Add 'theme' to default settings file
|
||||
- Add RED.view.annotations api (#3032) @knolleary
|
||||
- Update monaco editor to V0.25.2 (#3031) @Steve-Mcl
|
||||
- Lower tray zIndex when overlay tray being opened Fixes #3019
|
||||
- Reduce z-Index of Function expand buttons to prevent overlap Part of #3019
|
||||
- Ensure RED.clipboard.import displays the right library Fixes #3021
|
||||
- Batch messages sent over comms to prevent flooding (#3025) @knolleary
|
||||
- Allow RED.popover.panel to specify a closeButton to ignore click events on
|
||||
- Use browser default language for initial page load
|
||||
- Add css var for node font color
|
||||
- Fix label padding of toggleButton
|
||||
- Give sidebar open tab a bit more room for its label
|
||||
- Various Monaco updates (#3015) @Steve-Mcl
|
||||
- Log readOnly on startup (#3024) @sammachin
|
||||
- Translation updates (#3020 #3022) @HiroyasuNishiyama @kazuhitoyokoi
|
||||
|
||||
Nodes
|
||||
|
||||
- HTTP Request: Fix proxy handling (#3044) @hardillb
|
||||
- HTTP Request: Handle basic auth with @ in username (#3017) @hardillb
|
||||
- Add Japanese translation for file-in node (#3037 #3039) @kazuhitoyokoi
|
||||
- File In: Add option for file-in node to include all properties (default off) (#3035) @dceejay
|
||||
- Exec: add windowsHide option to hide windows under Windows (#3026) @natcl
|
||||
- Support loading external module sub path Fixes #3023
|
||||
|
||||
##### 2.0.0-beta.1: Beta Release
|
||||
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- [MAJOR] Set minimum node version to 12.
|
||||
- [MAJOR] Fix flowfile name to flows.json in settings (#2951) @dceejay
|
||||
- [MAJOR] Update to latest i18n in editor and runtime (#2940) @knolleary
|
||||
- [MAJOR] Deprecate usage of httpRoot (#2953) @knolleary
|
||||
- Add pre/postInstall hooks to npm install handling (#2936) @knolleary
|
||||
- Add engine-strict flag to npm install args (#2965) @nileio
|
||||
- Restructure default settings.js to be more organised (#3012) @knolleary
|
||||
- Ensure httpServerOptions gets applied to ALL the express apps
|
||||
- Allow RED.settings.set to replace string property with object property
|
||||
- Update debug tests to handle compact comms format
|
||||
- Updates to encode/decode message when passed over debug comms link
|
||||
- Remove all input event listeners on a node once it is closed
|
||||
- Move hooks to util package
|
||||
- Rework hooks structure to be a linkedlist
|
||||
- Update dependencies (#2922) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- [MAJOR] Change node id generation to give fixed length values without '.' (#2987) @knolleary
|
||||
- [MAJOR] Add Monaco code editor (#2971) @Steve-Mcl
|
||||
- Update to latest Monaco (#3007) @Steve-Mcl
|
||||
- Update Node-RED Function typings in Monaco (#3008) @Steve-Mcl
|
||||
- Add css named variables for certain key colours (#2994) @knolleary
|
||||
- Improve contrast of export dialog JSON font color
|
||||
- Switch editableList buttons from <a> to <button> elements
|
||||
- Add option to RED.nodes.createCompleteNodeSet to include node dimensions
|
||||
- Fix css of node help table of contents elements
|
||||
- Improve red-ui-node-icon css and add red-ui-node-icon-small modifier class
|
||||
- Add RED.hooks to editor
|
||||
- Add viewAddPort viewRemovePort viewAddNode viewRemoveNode hooks to view
|
||||
- Use paletteLabel if set in help sidebar
|
||||
- Add missing args from JSONata $now signature
|
||||
|
||||
Nodes
|
||||
|
||||
- [MAJOR] Relabel RBE node as 'filter' and move into core. Also remove tail (#2944) @dceejay
|
||||
- [MAJOR] HTTP Request: migrate to 'got' module (#2952) @knolleary
|
||||
- [MAJOR] Move Inject node to CronosJS module (#2959) @knolleary
|
||||
- [MAJOR] JSON: Update ajv to 8.2.0 - drop support for JSON-Schema draft-04 (#2969) @knolleary
|
||||
- [MAJOR] HTML node: cheerio update to 1.x (#3011) @knolleary
|
||||
- Join: change default manual mode to object (#2931) @knolleary
|
||||
- File node: Add fileWorkingDirectory (#2932) @knolleary
|
||||
- Delay node enhancements (#2294) @kazuhitoyokoi (#2949) @dceejay
|
||||
- Add Japanese translations for delay node enhancements (#2958) @kazuhitoyokoi
|
||||
- Inject node: reorder TypedInput options (#2961) @dceejay
|
||||
- HTTP Request: update to work with proxies (#2983) @hardillb (#3009) @hardillb
|
||||
- HTTP Request: fix msg.responseUrl (#2986) @hardillb
|
||||
- TLS: Add ALPN support to TLS node (#2988) @hardillb
|
||||
- Inject: add "Inject now" button to edit dialog (#2990) @Steve-Mcl
|
||||
|
||||
|
||||
|
||||
#### Older Releases
|
||||
|
||||
Change logs for older releases are available on GitHub: https://github.com/node-red/node-red/releases
|
||||
|
@@ -152,6 +152,7 @@ module.exports = function(grunt) {
|
||||
"packages/node_modules/@node-red/editor-client/src/js/history.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/validators.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/utils.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/utils-domselection.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js",
|
||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js",
|
||||
|
22
package.json
22
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -49,7 +49,7 @@
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "1.0.0",
|
||||
"https-proxy-agent": "5.0.1",
|
||||
"i18next": "21.8.10",
|
||||
"i18next": "21.8.14",
|
||||
"iconv-lite": "0.6.3",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "4.1.0",
|
||||
@@ -59,7 +59,7 @@
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.7",
|
||||
"mime": "3.0.0",
|
||||
"moment": "2.29.3",
|
||||
"moment": "2.29.4",
|
||||
"moment-timezone": "0.5.34",
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
@@ -69,14 +69,14 @@
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.5.2",
|
||||
"passport": "0.6.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.5.1",
|
||||
"semver": "7.3.7",
|
||||
"tar": "6.1.11",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uglify-js": "3.16.0",
|
||||
"uglify-js": "3.16.2",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.6",
|
||||
"xml2js": "0.4.23"
|
||||
@@ -85,7 +85,7 @@
|
||||
"bcrypt": "5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dompurify": "2.3.8",
|
||||
"dompurify": "2.3.9",
|
||||
"grunt": "1.5.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.4.3",
|
||||
@@ -95,7 +95,7 @@
|
||||
"grunt-contrib-concat": "2.1.0",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-contrib-jshint": "3.2.0",
|
||||
"grunt-contrib-uglify": "5.2.1",
|
||||
"grunt-contrib-uglify": "5.2.2",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"grunt-jsdoc": "2.4.1",
|
||||
"grunt-jsdoc-to-markdown": "6.0.0",
|
||||
@@ -108,17 +108,17 @@
|
||||
"i18next-http-backend": "1.4.1",
|
||||
"jquery-i18next": "1.2.1",
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "4.0.17",
|
||||
"marked": "4.0.18",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "9.2.2",
|
||||
"node-red-node-test-helper": "^0.3.0",
|
||||
"nodemon": "2.0.16",
|
||||
"nodemon": "2.0.19",
|
||||
"proxy": "^1.0.2",
|
||||
"sass": "1.52.3",
|
||||
"sass": "1.53.0",
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.2",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "6.2.3"
|
||||
"supertest": "6.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
@@ -266,6 +266,67 @@ module.exports = {
|
||||
theme.page = theme.page || {_:{}}
|
||||
theme.page._.scripts = scriptFiles.concat(theme.page._.scripts || [])
|
||||
}
|
||||
// check and load page settings from theme
|
||||
if (themePlugin.page) {
|
||||
if (themePlugin.page.favicon && !theme.page.favicon) {
|
||||
const result = serveFilesFromTheme(
|
||||
[themePlugin.page.favicon],
|
||||
themeApp,
|
||||
"/",
|
||||
themePlugin.path
|
||||
)
|
||||
if(result && result.length > 0) {
|
||||
// update themeContext page favicon
|
||||
themeContext.page.favicon = result[0]
|
||||
theme.page = theme.page || {_:{}}
|
||||
theme.page._.favicon = result[0]
|
||||
}
|
||||
}
|
||||
if (themePlugin.page.tabicon && themePlugin.page.tabicon.icon && !theme.page.tabicon) {
|
||||
const result = serveFilesFromTheme(
|
||||
[themePlugin.page.tabicon.icon],
|
||||
themeApp,
|
||||
"/page/",
|
||||
themePlugin.path
|
||||
)
|
||||
if(result && result.length > 0) {
|
||||
// update themeContext page tabicon
|
||||
themeContext.page.tabicon.icon = result[0]
|
||||
themeContext.page.tabicon.colour = themeContext.page.tabicon.colour || themeContext.page.tabicon.colour
|
||||
theme.page = theme.page || {_:{}}
|
||||
theme.page._.tabicon = theme.page._.tabicon || {}
|
||||
theme.page._.tabicon.icon = themeContext.page.tabicon.icon
|
||||
theme.page._.tabicon.colour = themeContext.page.tabicon.colour
|
||||
}
|
||||
}
|
||||
// if the plugin has a title AND the users settings.js does NOT
|
||||
if (themePlugin.page.title && !theme.page.title) {
|
||||
themeContext.page.title = themePlugin.page.title || themeContext.page.title
|
||||
}
|
||||
}
|
||||
// check and load header settings from theme
|
||||
if (themePlugin.header) {
|
||||
if (themePlugin.header.image && !theme.header.image) {
|
||||
const result = serveFilesFromTheme(
|
||||
[themePlugin.header.image],
|
||||
themeApp,
|
||||
"/header/",
|
||||
themePlugin.path
|
||||
)
|
||||
if(result && result.length > 0) {
|
||||
// update themeContext header image
|
||||
themeContext.header.image = result[0]
|
||||
}
|
||||
}
|
||||
// if the plugin has a title AND the users settings.js does NOT have a title
|
||||
if (themePlugin.header.title && !theme.header.title) {
|
||||
themeContext.header.title = themePlugin.header.title || themeContext.header.title
|
||||
}
|
||||
// if the plugin has a header url AND the users settings.js does NOT
|
||||
if (themePlugin.header.url && !theme.header.url) {
|
||||
themeContext.header.url = themePlugin.header.url || themeContext.header.url
|
||||
}
|
||||
}
|
||||
if(theme.codeEditor) {
|
||||
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.0.0-beta.4",
|
||||
"@node-red/editor-client": "3.0.0-beta.4",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"@node-red/editor-client": "3.1.0-beta.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.20.0",
|
||||
"clone": "2.1.2",
|
||||
@@ -31,7 +31,7 @@
|
||||
"oauth2orize": "1.11.1",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.5.2",
|
||||
"passport": "0.6.0",
|
||||
"ws": "7.5.6"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -30,11 +30,14 @@ RED.contextMenu = (function () {
|
||||
}
|
||||
|
||||
const selection = RED.view.selection()
|
||||
const noSelection = !selection || Object.keys(selection).length === 0
|
||||
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||
const hasLinks = selection.links && selection.links.length > 0;
|
||||
const isSingleLink = !hasSelection && hasLinks && selection.links.length === 1
|
||||
const isMultipleLinks = !hasSelection && hasLinks && selection.links.length > 1
|
||||
const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || [];
|
||||
const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || [];
|
||||
const hasLinks = wireLinks.length > 0;
|
||||
const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1
|
||||
const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1
|
||||
const canDelete = hasSelection || hasLinks
|
||||
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
|
||||
|
||||
@@ -66,7 +69,7 @@ RED.contextMenu = (function () {
|
||||
})
|
||||
}
|
||||
},
|
||||
(hasSelection || hasLinks) ? {
|
||||
(hasLinks) ? { // has least 1 wire selected
|
||||
label: RED._("contextMenu.junction"),
|
||||
onselect: 'core:split-wires-with-junctions',
|
||||
disabled: !hasLinks
|
||||
@@ -93,6 +96,7 @@ RED.contextMenu = (function () {
|
||||
RED.nodes.addJunction(nn);
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.select({nodes: [nn] });
|
||||
RED.view.redraw(true)
|
||||
}
|
||||
},
|
||||
|
@@ -308,6 +308,7 @@ RED.group = (function() {
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:[group]});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,6 +331,7 @@ RED.group = (function() {
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:newSelection})
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,6 +426,7 @@ RED.group = (function() {
|
||||
});
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +454,7 @@ RED.group = (function() {
|
||||
}
|
||||
}
|
||||
RED.view.select({nodes:selection.nodes})
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
function createGroup(nodes) {
|
||||
|
@@ -267,7 +267,7 @@ RED.keyboard = (function() {
|
||||
return resolveKeyEvent(evt);
|
||||
}
|
||||
if (Object.keys(handler).length > 0) {
|
||||
// check if there's a potential combined handler initiated by this keyCode
|
||||
// check if there's a potential combined handler initiated by this keyCode
|
||||
for (let h in handler) {
|
||||
if (matchHandlerToEvent(evt,handler[h]) > -1) {
|
||||
partialState = handler;
|
||||
@@ -298,21 +298,21 @@ RED.keyboard = (function() {
|
||||
return resolveKeyEvent(evt);
|
||||
}
|
||||
}
|
||||
d3.select(window).on("keydown",function() {
|
||||
document.addEventListener("keydown", function(event) {
|
||||
if (!handlersActive) {
|
||||
return;
|
||||
}
|
||||
if (metaKeyCodes[d3.event.keyCode]) {
|
||||
if (metaKeyCodes[event.keyCode]) {
|
||||
return;
|
||||
}
|
||||
var handler = resolveKeyEvent(d3.event);
|
||||
var handler = resolveKeyEvent(event);
|
||||
if (handler && handler.ondown) {
|
||||
if (typeof handler.ondown === "string") {
|
||||
RED.actions.invoke(handler.ondown);
|
||||
} else {
|
||||
handler.ondown();
|
||||
}
|
||||
d3.event.preventDefault();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -299,7 +299,7 @@ RED.palette = (function() {
|
||||
RED.view.focus();
|
||||
},
|
||||
stop: function() {
|
||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||
document.querySelectorAll(".red-ui-flow-link-splice").forEach(n => { n.classList.remove("red-ui-flow-link-splice") })
|
||||
if (hoverGroup) {
|
||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||
}
|
||||
@@ -358,26 +358,26 @@ RED.palette = (function() {
|
||||
var mx = mouseX / RED.view.scale();
|
||||
var my = mouseY / RED.view.scale();
|
||||
for (var i=0;i<nodes.length;i++) {
|
||||
var node = d3.select(nodes[i]);
|
||||
if (node.classed('red-ui-flow-link-background') && !node.classed('red-ui-flow-link-link')) {
|
||||
var length = nodes[i].getTotalLength();
|
||||
var node = nodes[i];
|
||||
if (node.classList.contains('red-ui-flow-link-background') && !node.classList.contains('red-ui-flow-link-link')) {
|
||||
var length = node.getTotalLength();
|
||||
for (var j=0;j<length;j+=10) {
|
||||
var p = nodes[i].getPointAtLength(j);
|
||||
var p = node.getPointAtLength(j);
|
||||
var d2 = ((p.x-mx)*(p.x-mx))+((p.y-my)*(p.y-my));
|
||||
if (d2 < 200 && d2 < bestDistance) {
|
||||
bestDistance = d2;
|
||||
bestLink = nodes[i];
|
||||
bestLink = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activeSpliceLink && activeSpliceLink !== bestLink) {
|
||||
d3.select(activeSpliceLink.parentNode).classed('red-ui-flow-link-splice',false);
|
||||
activeSpliceLink.parentNode.classList.remove('red-ui-flow-link-splice');
|
||||
}
|
||||
if (bestLink) {
|
||||
d3.select(bestLink.parentNode).classed('red-ui-flow-link-splice',true)
|
||||
bestLink.parentNode.classList.add('red-ui-flow-link-splice');
|
||||
} else {
|
||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||
document.querySelectorAll(".red-ui-flow-link-splice").forEach(n => { n.classList.remove("red-ui-flow-link-splice") })
|
||||
}
|
||||
if (activeSpliceLink !== bestLink) {
|
||||
if (bestLink) {
|
||||
|
@@ -877,6 +877,7 @@ RED.subflow = (function() {
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.updateActive();
|
||||
RED.view.select(null);
|
||||
RED.view.focus();
|
||||
}
|
||||
|
||||
|
||||
@@ -931,6 +932,7 @@ RED.subflow = (function() {
|
||||
|
||||
|
||||
function buildEnvUIRow(row, tenv, ui, node) {
|
||||
console.log(tenv, ui)
|
||||
ui.label = ui.label||{};
|
||||
if ((tenv.type === "cred" || (tenv.parent && tenv.parent.type === "cred")) && !ui.type) {
|
||||
ui.type = "cred";
|
||||
@@ -991,6 +993,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)
|
||||
}
|
||||
|
@@ -27,26 +27,24 @@ RED.touch.radialMenu = (function() {
|
||||
function createRadial(obj,pos,options) {
|
||||
isActive = true;
|
||||
try {
|
||||
touchMenu = d3.select("body").append("div").classed("red-ui-editor-radial-menu",true)
|
||||
.on('touchstart',function() {
|
||||
touchMenu = $('<div>', {class: 'red-ui-editor-radial-menu'}).appendTo('body')
|
||||
.on('touchstart',function(evt) {
|
||||
hide();
|
||||
d3.event.preventDefault();
|
||||
evt.preventDefault();
|
||||
});
|
||||
|
||||
var menu = touchMenu.append("div")
|
||||
.style({
|
||||
var menu = $('<div>').appendTo(touchMenu).css({
|
||||
top: (pos[1]-80)+"px",
|
||||
left:(pos[0]-80)+"px",
|
||||
});
|
||||
|
||||
var menuOpts = [];
|
||||
var createMenuOpt = function(x,y,opt) {
|
||||
opt.el = menu.append("div").classed("red-ui-editor-radial-menu-opt",true)
|
||||
.style({
|
||||
opt.el = $('<div>', {class: 'red-ui-editor-radial-menu-opt'}).appendTo(menu)
|
||||
.css({
|
||||
top: (y+80-25)+"px",
|
||||
left:(x+80-25)+"px"
|
||||
})
|
||||
.classed("red-ui-editor-radial-menu-opt-disabled",!!opt.disabled)
|
||||
.toggleClass("red-ui-editor-radial-menu-opt-disabled",!!opt.disabled)
|
||||
|
||||
opt.el.html(opt.name);
|
||||
|
||||
@@ -54,16 +52,16 @@ RED.touch.radialMenu = (function() {
|
||||
opt.y = y;
|
||||
menuOpts.push(opt);
|
||||
|
||||
opt.el.on('touchstart',function() {
|
||||
opt.el.classed("red-ui-editor-radial-menu-opt-active",true)
|
||||
d3.event.preventDefault();
|
||||
d3.event.stopPropagation();
|
||||
opt.el.on('touchstart',function(evt) {
|
||||
opt.el.toggleClass("red-ui-editor-radial-menu-opt-active",true)
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
});
|
||||
opt.el.on('touchend',function() {
|
||||
opt.el.on('touchend',function(evt) {
|
||||
hide();
|
||||
opt.onselect();
|
||||
d3.event.preventDefault();
|
||||
d3.event.stopPropagation();
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -88,8 +86,8 @@ RED.touch.radialMenu = (function() {
|
||||
}
|
||||
|
||||
obj.on('touchend.radial',function() {
|
||||
obj.on('touchend.radial',null);
|
||||
obj.on('touchmenu.radial',null);
|
||||
obj.off('touchend.radial');
|
||||
obj.off('touchmenu.radial');
|
||||
|
||||
if (activeOption) {
|
||||
try {
|
||||
@@ -103,9 +101,9 @@ RED.touch.radialMenu = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
obj.on('touchmove.radial',function() {
|
||||
obj.on('touchmove.radial',function(evt) {
|
||||
try {
|
||||
var touch0 = d3.event.touches.item(0);
|
||||
var touch0 = evt.touches.item(0);
|
||||
var p = [touch0.pageX - pos[0],touch0.pageY-pos[1]];
|
||||
for (var i=0;i<menuOpts.length;i++) {
|
||||
var opt = menuOpts[i];
|
||||
@@ -119,7 +117,7 @@ RED.touch.radialMenu = (function() {
|
||||
if (opt === activeOption) {
|
||||
activeOption = null;
|
||||
}
|
||||
opt.el.classed("selected",false);
|
||||
opt.el.toggleClass("selected",false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -437,17 +437,17 @@ RED.tourGuide = (function() {
|
||||
return [
|
||||
{
|
||||
id: "3_0",
|
||||
label: "3.0.0-beta.4",
|
||||
label: "3.0",
|
||||
path: "./tours/welcome.js"
|
||||
},
|
||||
{
|
||||
id: "2_2",
|
||||
label: "2.2.0",
|
||||
label: "2.2",
|
||||
path: "./tours/2.2/welcome.js"
|
||||
},
|
||||
{
|
||||
id: "2_1",
|
||||
label: "2.1.0",
|
||||
label: "2.1",
|
||||
path: "./tours/2.1/welcome.js"
|
||||
}
|
||||
];
|
||||
|
61
packages/node_modules/@node-red/editor-client/src/js/ui/utils-domselection.js
vendored
Normal file
61
packages/node_modules/@node-red/editor-client/src/js/ui/utils-domselection.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Modelled after `d3.selection` this provides a way to keep a mapping of
|
||||
* DOM Nodes with a data collection.
|
||||
*
|
||||
* The goal here is not to reproduce d3 functionality as-is, but to provide an
|
||||
* api that is specific to what we need to do
|
||||
*
|
||||
* const domSelection = RED.utils.domSelection(container, selector, createNode, eachNode)
|
||||
*
|
||||
* - container - a DOM Node that is the container of the DOM Nodes to track
|
||||
* - selector - CSS selector to get the DOM nodes to track
|
||||
* - createNode - function called when a DOM node must be created for a piece of data.
|
||||
* `this` is the data item. Should return the DOM Node. It will
|
||||
* get added to the container.
|
||||
* - eachNode - function called for each DOM node/data item in the selection
|
||||
*
|
||||
* DomSelection.refresh(data) - called whenever the selection should be refreshed.
|
||||
* Data is expected to be an array of objects that contain an 'id' property
|
||||
*
|
||||
*/
|
||||
RED.utils.domSelection = (function() {
|
||||
|
||||
class DomSelection {
|
||||
constructor(container, selector, createNode, eachNode) {
|
||||
this.container = container
|
||||
this.selector = selector
|
||||
this.createNode = createNode
|
||||
this.eachNode = eachNode
|
||||
this.data = []
|
||||
}
|
||||
|
||||
refresh(data) {
|
||||
const domNodes = this.container.querySelectorAll(this.selector)
|
||||
const domItems = new Map()
|
||||
const dataLength = data.length
|
||||
const domLength = domNodes.length
|
||||
for (let i = 0; i < domLength; i++) {
|
||||
const domNode = domNodes[i]
|
||||
if (domNode.__data__) {
|
||||
domItems.set(domNode.__data__.id, domNode)
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < dataLength; i++) {
|
||||
const datum = data[i]
|
||||
let domNode = domItems.get(datum.id)
|
||||
if (!domNode) {
|
||||
domNode = this.createNode.call(datum)
|
||||
this.container.appendChild(domNode)
|
||||
domNode.__data__ = datum
|
||||
} else {
|
||||
domItems.delete(datum.id)
|
||||
}
|
||||
this.eachNode.call(datum, domNode)
|
||||
}
|
||||
for (const remainingDomNodes of domItems) {
|
||||
remainingDomNodes[1].remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
return (container, selector, createNode, eachNode) => new DomSelection(container, selector, createNode, eachNode)
|
||||
})()
|
@@ -1397,6 +1397,17 @@ RED.utils = (function() {
|
||||
return r;
|
||||
}
|
||||
|
||||
function createSVGElement(tag, attrs = {}, parent) {
|
||||
const element = document.createElementNS('http://www.w3.org/2000/svg', tag)
|
||||
for (const k in attrs) {
|
||||
element.setAttribute(k, attrs[k])
|
||||
}
|
||||
if (parent) {
|
||||
parent.appendChild(element)
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
return {
|
||||
createObjectElement: createObjectElement,
|
||||
getMessageProperty: getMessageProperty,
|
||||
@@ -1420,6 +1431,7 @@ RED.utils = (function() {
|
||||
getDarkerColor: getDarkerColor,
|
||||
parseModuleList: parseModuleList,
|
||||
checkModuleAllowed: checkModuleAllowed,
|
||||
getBrowserInfo: getBrowserInfo
|
||||
getBrowserInfo: getBrowserInfo,
|
||||
createSVGElement: createSVGElement
|
||||
}
|
||||
})();
|
||||
|
@@ -91,8 +91,7 @@ RED.view.annotations = (function() {
|
||||
function addAnnotation(id,evt) {
|
||||
var opts = annotations[id];
|
||||
evt.el.__annotations__ = evt.el.__annotations__ || [];
|
||||
var annotationGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
annotationGroup.setAttribute("class",opts.class || "");
|
||||
var annotationGroup = RED.utils.createSVGElement("g", { class: opts.class || '' })
|
||||
evt.el.__annotations__.push({
|
||||
id:id,
|
||||
element: annotationGroup
|
||||
|
@@ -15,133 +15,128 @@
|
||||
**/
|
||||
|
||||
|
||||
RED.view.navigator = (function() {
|
||||
RED.view.navigator = (function() {
|
||||
var nav_scale = 25;
|
||||
var nav_width = 5000/nav_scale;
|
||||
var nav_height = 5000/nav_scale;
|
||||
|
||||
var nav_scale = 25;
|
||||
var nav_width = 5000/nav_scale;
|
||||
var nav_height = 5000/nav_scale;
|
||||
var navContainer;
|
||||
var navBox;
|
||||
var navBorder;
|
||||
var scrollPos;
|
||||
var scaleFactor;
|
||||
var chartSize;
|
||||
var dimensions;
|
||||
var isDragging;
|
||||
var isShowing = false;
|
||||
|
||||
var navContainer;
|
||||
var navBox;
|
||||
var navBorder;
|
||||
var navVis;
|
||||
var scrollPos;
|
||||
var scaleFactor;
|
||||
var chartSize;
|
||||
var dimensions;
|
||||
var isDragging;
|
||||
var isShowing = false;
|
||||
var domSelection
|
||||
|
||||
function refreshNodes() {
|
||||
if (!isShowing) {
|
||||
return;
|
||||
}
|
||||
var navNode = navVis.selectAll(".red-ui-navigator-node").data(RED.view.getActiveNodes(),function(d){return d.id});
|
||||
navNode.exit().remove();
|
||||
navNode.enter().insert("rect")
|
||||
.attr('class','red-ui-navigator-node')
|
||||
.attr("pointer-events", "none");
|
||||
navNode.each(function(d) {
|
||||
d3.select(this).attr("x",function(d) { return (d.x-d.w/2)/nav_scale })
|
||||
.attr("y",function(d) { return (d.y-d.h/2)/nav_scale })
|
||||
.attr("width",function(d) { return Math.max(9,d.w/nav_scale) })
|
||||
.attr("height",function(d) { return Math.max(3,d.h/nav_scale) })
|
||||
.attr("fill",function(d) { return RED.utils.getNodeColor(d.type,d._def);})
|
||||
});
|
||||
}
|
||||
function onScroll() {
|
||||
if (!isDragging) {
|
||||
resizeNavBorder();
|
||||
}
|
||||
}
|
||||
function resizeNavBorder() {
|
||||
if (navBorder) {
|
||||
scaleFactor = RED.view.scale();
|
||||
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
|
||||
scrollPos = [$("#red-ui-workspace-chart").scrollLeft(),$("#red-ui-workspace-chart").scrollTop()];
|
||||
navBorder.attr('x',scrollPos[0]/nav_scale)
|
||||
.attr('y',scrollPos[1]/nav_scale)
|
||||
.attr('width',chartSize[0]/nav_scale/scaleFactor)
|
||||
.attr('height',chartSize[1]/nav_scale/scaleFactor)
|
||||
}
|
||||
}
|
||||
function toggle() {
|
||||
if (!isShowing) {
|
||||
isShowing = true;
|
||||
$("#red-ui-view-navigate").addClass("selected");
|
||||
resizeNavBorder();
|
||||
refreshNodes();
|
||||
$("#red-ui-workspace-chart").on("scroll",onScroll);
|
||||
navContainer.fadeIn(200);
|
||||
} else {
|
||||
isShowing = false;
|
||||
navContainer.fadeOut(100);
|
||||
$("#red-ui-workspace-chart").off("scroll",onScroll);
|
||||
$("#red-ui-view-navigate").removeClass("selected");
|
||||
}
|
||||
}
|
||||
function refreshNodes() {
|
||||
if (!isShowing) {
|
||||
return;
|
||||
}
|
||||
domSelection.refresh(RED.view.getActiveNodes())
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
function onScroll() {
|
||||
if (!isDragging) {
|
||||
resizeNavBorder();
|
||||
}
|
||||
}
|
||||
function resizeNavBorder() {
|
||||
if (navBorder) {
|
||||
scaleFactor = RED.view.scale();
|
||||
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
|
||||
scrollPos = [$("#red-ui-workspace-chart").scrollLeft(),$("#red-ui-workspace-chart").scrollTop()];
|
||||
|
||||
$(window).on("resize", resizeNavBorder);
|
||||
RED.events.on("sidebar:resize",resizeNavBorder);
|
||||
RED.actions.add("core:toggle-navigator",toggle);
|
||||
var hideTimeout;
|
||||
navBorder.attr('x', scrollPos[0]/nav_scale)
|
||||
navBorder.attr('y', scrollPos[1]/nav_scale)
|
||||
navBorder.attr('width',chartSize[0]/nav_scale/scaleFactor)
|
||||
navBorder.attr('height',chartSize[1]/nav_scale/scaleFactor)
|
||||
}
|
||||
}
|
||||
function toggle() {
|
||||
if (!isShowing) {
|
||||
isShowing = true;
|
||||
$("#red-ui-view-navigate").addClass("selected");
|
||||
resizeNavBorder();
|
||||
refreshNodes();
|
||||
$("#red-ui-workspace-chart").on("scroll",onScroll);
|
||||
navContainer.fadeIn(200);
|
||||
} else {
|
||||
isShowing = false;
|
||||
navContainer.fadeOut(100);
|
||||
$("#red-ui-workspace-chart").off("scroll",onScroll);
|
||||
$("#red-ui-view-navigate").removeClass("selected");
|
||||
}
|
||||
}
|
||||
|
||||
navContainer = $('<div>').css({
|
||||
"position":"absolute",
|
||||
"bottom":$("#red-ui-workspace-footer").height(),
|
||||
"right":0,
|
||||
zIndex: 1
|
||||
}).appendTo("#red-ui-workspace").hide();
|
||||
return {
|
||||
init: function() {
|
||||
|
||||
navBox = d3.select(navContainer[0])
|
||||
.append("svg:svg")
|
||||
.attr("width", nav_width)
|
||||
.attr("height", nav_height)
|
||||
.attr("pointer-events", "all")
|
||||
.attr("id","red-ui-navigator-canvas")
|
||||
$(window).on("resize", resizeNavBorder);
|
||||
RED.events.on("sidebar:resize",resizeNavBorder);
|
||||
RED.actions.add("core:toggle-navigator",toggle);
|
||||
|
||||
navBox.append("rect").attr("x",0).attr("y",0).attr("width",nav_width).attr("height",nav_height).style({
|
||||
fill:"none",
|
||||
stroke:"none",
|
||||
pointerEvents:"all"
|
||||
}).on("mousedown", function() {
|
||||
// Update these in case they have changed
|
||||
scaleFactor = RED.view.scale();
|
||||
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
|
||||
dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor];
|
||||
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||
navBorder.attr('x',newX).attr('y',newY);
|
||||
isDragging = true;
|
||||
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||
}).on("mousemove", function() {
|
||||
if (!isDragging) { return }
|
||||
if (d3.event.buttons === 0) {
|
||||
isDragging = false;
|
||||
return;
|
||||
}
|
||||
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||
navBorder.attr('x',newX).attr('y',newY);
|
||||
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||
}).on("mouseup", function() {
|
||||
isDragging = false;
|
||||
})
|
||||
navContainer = $('<div>').css({
|
||||
"position":"absolute",
|
||||
"bottom":$("#red-ui-workspace-footer").height(),
|
||||
"right":0,
|
||||
zIndex: 1
|
||||
}).appendTo("#red-ui-workspace").hide();
|
||||
|
||||
navBorder = navBox.append("rect").attr("class","red-ui-navigator-border")
|
||||
navBox = $(RED.utils.createSVGElement('svg', {id: "red-ui-navigator-canvas", width: nav_width, height: nav_height, 'pointer-events': 'all'})).appendTo(navContainer)
|
||||
|
||||
navVis = navBox.append("svg:g")
|
||||
const navBoxBody = $(RED.utils.createSVGElement("rect", { x: 0, y: 0, width: nav_width, height: nav_height, fill: 'none', stroke: 'none', 'pointer-events': 'all'}))
|
||||
.css({'cursor': 'pointer'})
|
||||
navBoxBody.on('mousedown',function(event) {
|
||||
// Update these in case they have changed
|
||||
scaleFactor = RED.view.scale();
|
||||
chartSize = [ $("#red-ui-workspace-chart").width(), $("#red-ui-workspace-chart").height()];
|
||||
dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor];
|
||||
var newX = Math.max(0,Math.min(event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||
var newY = Math.max(0,Math.min(event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||
navBorder.attr('x',newX)
|
||||
navBorder.attr('y',newY);
|
||||
isDragging = true;
|
||||
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||
}).on('mousemove', function(event) {
|
||||
if (!isDragging) { return }
|
||||
if (event.buttons === 0) {
|
||||
isDragging = false;
|
||||
return;
|
||||
}
|
||||
var newX = Math.max(0,Math.min(event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||
var newY = Math.max(0,Math.min(event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||
navBorder.attr('x',newX)
|
||||
navBorder.attr('y',newY);
|
||||
$("#red-ui-workspace-chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||
$("#red-ui-workspace-chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||
}).on('mouseup', function() {
|
||||
isDragging = false;
|
||||
}).appendTo(navBox)
|
||||
|
||||
RED.statusBar.add({
|
||||
id: "view-navigator",
|
||||
align: "right",
|
||||
element: $('<button class="red-ui-footer-button-toggle single" id="red-ui-view-navigate"><i class="fa fa-map-o"></i></button>')
|
||||
})
|
||||
navBorder = $(RED.utils.createSVGElement("rect", { "class": "red-ui-navigator-border" })).appendTo(navBox)
|
||||
|
||||
const navVis = $(RED.utils.createSVGElement('g')).appendTo(navBox)
|
||||
|
||||
domSelection = RED.utils.domSelection(navVis[0], '.red-ui-navigator-node', function() {
|
||||
return RED.utils.createSVGElement('rect', { class: 'red-ui-navigator-node', 'pointer-events': 'none' })
|
||||
}, function(node) {
|
||||
node.setAttribute('x', (this.x-this.w/2)/nav_scale)
|
||||
node.setAttribute('y', (this.y-this.h/2)/nav_scale)
|
||||
node.setAttribute('width', Math.max(9,this.w/nav_scale))
|
||||
node.setAttribute('height', Math.max(3,this.h/nav_scale))
|
||||
node.setAttribute('fill', RED.utils.getNodeColor(this.type,this._def))
|
||||
})
|
||||
|
||||
RED.statusBar.add({
|
||||
id: "view-navigator",
|
||||
align: "right",
|
||||
element: $('<button class="red-ui-footer-button-toggle single" id="red-ui-view-navigate"><i class="fa fa-map-o"></i></button>')
|
||||
})
|
||||
|
||||
$("#red-ui-view-navigate").on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
|
@@ -823,7 +823,7 @@ RED.view.tools = (function() {
|
||||
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
|
||||
*/
|
||||
function splitWiresWithLinkNodes(wires) {
|
||||
let wiresToSplit = wires || RED.view.selection().links;
|
||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
}
|
||||
@@ -1061,7 +1061,7 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function addJunctionsToWires(wires) {
|
||||
let wiresToSplit = wires || RED.view.selection().links;
|
||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
}
|
||||
@@ -1089,6 +1089,7 @@ RED.view.tools = (function() {
|
||||
linkGroups.sort(function(A,B) {
|
||||
return groupedLinks[B].length - groupedLinks[A].length
|
||||
})
|
||||
const wasDirty = RED.nodes.dirty()
|
||||
linkGroups.forEach(function(gid) {
|
||||
var links = groupedLinks[gid]
|
||||
var junction = {
|
||||
@@ -1179,12 +1180,14 @@ RED.view.tools = (function() {
|
||||
})
|
||||
if (addedJunctions.length > 0) {
|
||||
RED.history.push({
|
||||
dirty: wasDirty,
|
||||
t: 'add',
|
||||
links: addedLinks,
|
||||
junctions: addedJunctions,
|
||||
removedLinks: Array.from(removedLinks)
|
||||
})
|
||||
RED.nodes.dirty(true)
|
||||
RED.view.select({nodes: addedJunctions });
|
||||
}
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
@@ -294,25 +294,13 @@ RED.view = (function() {
|
||||
]
|
||||
startTouchDistance = Math.sqrt((a*a)+(b*b));
|
||||
} else {
|
||||
var obj = d3.select(document.body);
|
||||
touch0 = d3.event.touches.item(0);
|
||||
var pos = [touch0.pageX,touch0.pageY];
|
||||
startTouchCenter = [touch0.pageX,touch0.pageY];
|
||||
startTouchDistance = 0;
|
||||
var point = d3.touches(this)[0];
|
||||
touchStartTime = setTimeout(function() {
|
||||
touchStartTime = null;
|
||||
showTouchMenu(obj,pos);
|
||||
//lasso = eventLayer.append("rect")
|
||||
// .attr("ox",point[0])
|
||||
// .attr("oy",point[1])
|
||||
// .attr("rx",2)
|
||||
// .attr("ry",2)
|
||||
// .attr("x",point[0])
|
||||
// .attr("y",point[1])
|
||||
// .attr("width",0)
|
||||
// .attr("height",0)
|
||||
// .attr("class","nr-ui-view-lasso");
|
||||
showTouchMenu(document.body,pos);
|
||||
},touchLongPressTimeout);
|
||||
}
|
||||
d3.event.preventDefault();
|
||||
@@ -712,11 +700,11 @@ RED.view = (function() {
|
||||
type: "badge",
|
||||
class: "red-ui-flow-node-changed",
|
||||
element: function() {
|
||||
var changeBadge = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||
changeBadge.setAttribute("cx",5);
|
||||
changeBadge.setAttribute("cy",5);
|
||||
changeBadge.setAttribute("r",5);
|
||||
return changeBadge;
|
||||
return RED.utils.createSVGElement("circle", {
|
||||
cx: 5,
|
||||
cy: 5,
|
||||
r: 5
|
||||
})
|
||||
},
|
||||
show: function(n) { return n.changed||n.moved }
|
||||
})
|
||||
@@ -725,9 +713,9 @@ RED.view = (function() {
|
||||
type: "badge",
|
||||
class: "red-ui-flow-node-error",
|
||||
element: function(d) {
|
||||
var errorBadge = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
errorBadge.setAttribute("d","M 0,9 l 10,0 -5,-8 z");
|
||||
return errorBadge
|
||||
return RED.utils.createSVGElement("path", {
|
||||
d: "M 0,9 l 10,0 -5,-8 z"
|
||||
})
|
||||
},
|
||||
tooltip: function(d) {
|
||||
if (d.validationErrors && d.validationErrors.length > 0) {
|
||||
@@ -3703,13 +3691,12 @@ RED.view = (function() {
|
||||
}
|
||||
function nodeTouchStart(d) {
|
||||
if (RED.view.DEBUG) { console.warn("nodeTouchStart", mouse_mode,d); }
|
||||
var obj = d3.select(this);
|
||||
var touch0 = d3.event.touches.item(0);
|
||||
var pos = [touch0.pageX,touch0.pageY];
|
||||
startTouchCenter = [touch0.pageX,touch0.pageY];
|
||||
startTouchDistance = 0;
|
||||
touchStartTime = setTimeout(function() {
|
||||
showTouchMenu(obj,pos);
|
||||
showTouchMenu(this,pos);
|
||||
},touchLongPressTimeout);
|
||||
nodeMouseDown.call(this,d)
|
||||
d3.event.preventDefault();
|
||||
@@ -3868,12 +3855,11 @@ RED.view = (function() {
|
||||
focusView();
|
||||
d3.event.stopPropagation();
|
||||
|
||||
var obj = d3.select(document.body);
|
||||
var touch0 = d3.event.touches.item(0);
|
||||
var pos = [touch0.pageX,touch0.pageY];
|
||||
touchStartTime = setTimeout(function() {
|
||||
touchStartTime = null;
|
||||
showTouchMenu(obj,pos);
|
||||
showTouchMenu(document.body,pos);
|
||||
},touchLongPressTimeout);
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
@@ -4247,13 +4233,14 @@ RED.view = (function() {
|
||||
d.resize = true;
|
||||
d.dirty = true;
|
||||
|
||||
var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
var mainRect = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-subflow-port",
|
||||
rx: 8,
|
||||
ry: 8,
|
||||
width: 40,
|
||||
height: 40,
|
||||
})
|
||||
mainRect.__data__ = d;
|
||||
mainRect.setAttribute("class", "red-ui-flow-subflow-port");
|
||||
mainRect.setAttribute("rx", 8);
|
||||
mainRect.setAttribute("ry", 8);
|
||||
mainRect.setAttribute("width", 40);
|
||||
mainRect.setAttribute("height", 40);
|
||||
node[0][0].__mainRect__ = mainRect;
|
||||
d3.select(mainRect)
|
||||
.on("mouseup",nodeMouseUp)
|
||||
@@ -4262,50 +4249,50 @@ RED.view = (function() {
|
||||
.on("touchend",nodeTouchEnd)
|
||||
nodeContents.appendChild(mainRect);
|
||||
|
||||
var output_groupEl = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
output_groupEl.setAttribute("x",0);
|
||||
output_groupEl.setAttribute("y",0);
|
||||
var output_groupEl = RED.utils.createSVGElement("g", { x: 0, y: 0 })
|
||||
node[0][0].__outputLabelGroup__ = output_groupEl;
|
||||
|
||||
var output_output = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
output_output.setAttribute("class","red-ui-flow-port-label");
|
||||
var output_output = RED.utils.createSVGElement("text", { class: "red-ui-flow-port-label" })
|
||||
output_output.style["font-size"] = "10px";
|
||||
output_output.textContent = "output";
|
||||
output_groupEl.appendChild(output_output);
|
||||
node[0][0].__outputOutput__ = output_output;
|
||||
|
||||
var output_number = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
output_number.setAttribute("class","red-ui-flow-port-label red-ui-flow-port-index");
|
||||
output_number.setAttribute("x",0);
|
||||
output_number.setAttribute("y",0);
|
||||
var output_number = RED.utils.createSVGElement("text", {
|
||||
class: "red-ui-flow-port-label red-ui-flow-port-index",
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
output_number.textContent = d.i+1;
|
||||
output_groupEl.appendChild(output_number);
|
||||
node[0][0].__outputNumber__ = output_number;
|
||||
|
||||
var output_border = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
output_border.setAttribute("d","M 40 1 l 0 38")
|
||||
output_border.setAttribute("class", "red-ui-flow-node-icon-shade-border")
|
||||
var output_border = RED.utils.createSVGElement("path", {
|
||||
d: "M 40 1 l 0 38",
|
||||
class: "red-ui-flow-node-icon-shade-border"
|
||||
})
|
||||
output_groupEl.appendChild(output_border);
|
||||
node[0][0].__outputBorder__ = output_border;
|
||||
|
||||
nodeContents.appendChild(output_groupEl);
|
||||
|
||||
var text = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
text.setAttribute("class","red-ui-flow-port-label");
|
||||
text.setAttribute("transform","translate(38,0)");
|
||||
text.setAttribute('style', 'fill : #888'); // hard coded here!
|
||||
var text = RED.utils.createSVGElement("g", {
|
||||
class: "red-ui-flow-port-label",
|
||||
transform: "translate(38,0)",
|
||||
style: 'fill : #888' // hard coded here!
|
||||
})
|
||||
node[0][0].__textGroup__ = text;
|
||||
nodeContents.append(text);
|
||||
|
||||
var portEl = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
portEl.setAttribute('transform','translate(-5,15)')
|
||||
var portEl = RED.utils.createSVGElement("g", { transform: 'translate(-5,15)'})
|
||||
|
||||
var port = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
port.setAttribute("class","red-ui-flow-port");
|
||||
port.setAttribute("rx",3);
|
||||
port.setAttribute("ry",3);
|
||||
port.setAttribute("width",10);
|
||||
port.setAttribute("height",10);
|
||||
var port = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-port",
|
||||
rx: 3,
|
||||
ry: 3,
|
||||
width: 10,
|
||||
height: 10
|
||||
})
|
||||
portEl.appendChild(port);
|
||||
port.__data__ = d;
|
||||
|
||||
@@ -4434,10 +4421,11 @@ RED.view = (function() {
|
||||
}
|
||||
for (var i=0; i<sn; i++) {
|
||||
if (i===textLines.length) {
|
||||
var line = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
line.setAttribute("class","red-ui-flow-node-label-text");
|
||||
line.setAttribute("x",0);
|
||||
line.setAttribute("y",i*24);
|
||||
var line = RED.utils.createSVGElement("text", {
|
||||
class: "red-ui-flow-node-label-text",
|
||||
x: 0,
|
||||
y: i*24
|
||||
});
|
||||
this.__textGroup__.appendChild(line);
|
||||
}
|
||||
textLines[i].textContent = sa[i];
|
||||
@@ -4507,32 +4495,35 @@ RED.view = (function() {
|
||||
d.resize = true;
|
||||
|
||||
if (d._def.button) {
|
||||
var buttonGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
var buttonGroup = RED.utils.createSVGElement("g", {
|
||||
class: "red-ui-flow-node-button",
|
||||
transform: "translate("+((d._def.align == "right") ? 94 : -25)+",2)"
|
||||
})
|
||||
buttonGroup.__data__ = d;
|
||||
buttonGroup.setAttribute("transform", "translate("+((d._def.align == "right") ? 94 : -25)+",2)");
|
||||
buttonGroup.setAttribute("class","red-ui-flow-node-button");
|
||||
node[0][0].__buttonGroup__ = buttonGroup;
|
||||
|
||||
var bgBackground = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
var bgBackground = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-node-button-background",
|
||||
rx: 5,
|
||||
ry: 5,
|
||||
width: 32,
|
||||
height: node_height-4
|
||||
})
|
||||
bgBackground.__data__ = d;
|
||||
bgBackground.setAttribute("class","red-ui-flow-node-button-background");
|
||||
bgBackground.setAttribute("rx",5);
|
||||
bgBackground.setAttribute("ry",5);
|
||||
bgBackground.setAttribute("width",32);
|
||||
bgBackground.setAttribute("height",node_height-4);
|
||||
buttonGroup.appendChild(bgBackground);
|
||||
node[0][0].__buttonGroupBackground__ = bgBackground;
|
||||
|
||||
var bgButton = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
var bgButton = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-node-button-button",
|
||||
x: d._def.align == "right"? 11:5,
|
||||
y: 4,
|
||||
rx: 4,
|
||||
ry: 4,
|
||||
width: 16,
|
||||
height: node_height-12,
|
||||
fill: RED.utils.getNodeColor(d.type,d._def)
|
||||
})
|
||||
bgButton.__data__ = d;
|
||||
bgButton.setAttribute("class","red-ui-flow-node-button-button");
|
||||
bgButton.setAttribute("x", d._def.align == "right"? 11:5);
|
||||
bgButton.setAttribute("y",4);
|
||||
bgButton.setAttribute("rx",4);
|
||||
bgButton.setAttribute("ry",4);
|
||||
bgButton.setAttribute("width",16);
|
||||
bgButton.setAttribute("height",node_height-12);
|
||||
bgButton.setAttribute("fill", RED.utils.getNodeColor(d.type,d._def));
|
||||
d3.select(bgButton)
|
||||
.on("mousedown",function(d) {if (!lasso && isButtonEnabled(d)) {focusView();d3.select(this).attr("fill-opacity",0.2);d3.event.preventDefault(); d3.event.stopPropagation();}})
|
||||
.on("mouseup",function(d) {if (!lasso && isButtonEnabled(d)) { d3.select(this).attr("fill-opacity",0.4);d3.event.preventDefault();d3.event.stopPropagation();}})
|
||||
@@ -4553,12 +4544,13 @@ RED.view = (function() {
|
||||
|
||||
}
|
||||
|
||||
var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
var mainRect = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-node "+(d.type == "unknown"?"red-ui-flow-node-unknown":""),
|
||||
rx: 5,
|
||||
ry: 5,
|
||||
fill: RED.utils.getNodeColor(d.type,d._def)
|
||||
})
|
||||
mainRect.__data__ = d;
|
||||
mainRect.setAttribute("class", "red-ui-flow-node "+(d.type == "unknown"?"red-ui-flow-node-unknown":""));
|
||||
mainRect.setAttribute("rx", 5);
|
||||
mainRect.setAttribute("ry", 5);
|
||||
mainRect.setAttribute("fill", RED.utils.getNodeColor(d.type,d._def));
|
||||
node[0][0].__mainRect__ = mainRect;
|
||||
d3.select(mainRect)
|
||||
.on("mouseup",nodeMouseUp)
|
||||
@@ -4573,63 +4565,65 @@ RED.view = (function() {
|
||||
|
||||
if (d._def.icon) {
|
||||
var icon_url = RED.utils.getNodeIcon(d._def,d);
|
||||
var icon_groupEl = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
icon_groupEl.__data__ = d;
|
||||
icon_groupEl.setAttribute("class","red-ui-flow-node-icon-group"+("right" == d._def.align?" red-ui-flow-node-icon-group-right":""));
|
||||
icon_groupEl.setAttribute("x",0);
|
||||
icon_groupEl.setAttribute("y",0);
|
||||
var icon_groupEl = RED.utils.createSVGElement("g", {
|
||||
class: "red-ui-flow-node-icon-group"+("right" == d._def.align?" red-ui-flow-node-icon-group-right":""),
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
icon_groupEl.style["pointer-events"] = "none";
|
||||
icon_groupEl.__data__ = d;
|
||||
node[0][0].__iconGroup__ = icon_groupEl;
|
||||
var icon_shade = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
icon_shade.setAttribute("x",0);
|
||||
icon_shade.setAttribute("y",0);
|
||||
icon_shade.setAttribute("class","red-ui-flow-node-icon-shade")
|
||||
icon_shade.setAttribute("width",30);
|
||||
icon_shade.setAttribute("height",Math.min(50,d.h-4));
|
||||
var icon_shade = RED.utils.createSVGElement("path", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
class: "red-ui-flow-node-icon-shade"
|
||||
})
|
||||
icon_groupEl.appendChild(icon_shade);
|
||||
node[0][0].__iconShade__ = icon_shade;
|
||||
|
||||
var icon_group = d3.select(icon_groupEl)
|
||||
createIconAttributes(icon_url, icon_group, d);
|
||||
|
||||
var icon_shade_border = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
icon_shade_border.setAttribute("d","right" != d._def.align ? "M 30 1 l 0 "+(d.h-2) : "M 0 1 l 0 "+(d.h-2) )
|
||||
icon_shade_border.setAttribute("class", "red-ui-flow-node-icon-shade-border")
|
||||
var icon_shade_border = RED.utils.createSVGElement("path", {
|
||||
d: "right" != d._def.align ? "M 30 1 l 0 "+(d.h-2) : "M 0 1 l 0 "+(d.h-2),
|
||||
class: "red-ui-flow-node-icon-shade-border"
|
||||
})
|
||||
icon_groupEl.appendChild(icon_shade_border);
|
||||
node[0][0].__iconShadeBorder__ = icon_shade_border;
|
||||
|
||||
nodeContents.appendChild(icon_groupEl);
|
||||
}
|
||||
var text = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
text.setAttribute("class","red-ui-flow-node-label"+(hideLabel?" hide":"")+(d._def.align?" red-ui-flow-node-label-"+d._def.align:""));
|
||||
text.setAttribute("transform","translate(38,0)");
|
||||
// text.setAttribute("dy", ".3px");
|
||||
// text.setAttribute("text-anchor",d._def.align !== "right" ? "start":"end");
|
||||
var text = RED.utils.createSVGElement("g", {
|
||||
class: "red-ui-flow-node-label"+(hideLabel?" hide":"")+(d._def.align?" red-ui-flow-node-label-"+d._def.align:""),
|
||||
transform: "translate(38,0)"
|
||||
// dy: ".3px",
|
||||
// "text-anchor": d._def.align !== "right" ? "start":"end"
|
||||
})
|
||||
nodeContents.appendChild(text);
|
||||
node[0][0].__textGroup__ = text;
|
||||
|
||||
var statusEl = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
// statusEl.__data__ = d;
|
||||
statusEl.setAttribute("class","red-ui-flow-node-status-group");
|
||||
var statusEl = RED.utils.createSVGElement("g", { class: "red-ui-flow-node-status-group" })
|
||||
statusEl.style.display = "none";
|
||||
node[0][0].__statusGroup__ = statusEl;
|
||||
|
||||
var statusRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
statusRect.setAttribute("class","red-ui-flow-node-status");
|
||||
statusRect.setAttribute("x",6);
|
||||
statusRect.setAttribute("y",1);
|
||||
statusRect.setAttribute("width",9);
|
||||
statusRect.setAttribute("height",9);
|
||||
statusRect.setAttribute("rx",2);
|
||||
statusRect.setAttribute("ry",2);
|
||||
statusRect.setAttribute("stroke-width","3");
|
||||
var statusRect = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-node-status",
|
||||
x: 6,
|
||||
y: 1,
|
||||
width: 9,
|
||||
height: 9,
|
||||
rx: 2,
|
||||
ry: 2,
|
||||
"stroke-width": 3
|
||||
})
|
||||
statusEl.appendChild(statusRect);
|
||||
node[0][0].__statusShape__ = statusRect;
|
||||
|
||||
var statusLabel = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
statusLabel.setAttribute("class","red-ui-flow-node-status-label");
|
||||
statusLabel.setAttribute("x",20);
|
||||
statusLabel.setAttribute("y",10);
|
||||
var statusLabel = RED.utils.createSVGElement("text", {
|
||||
class: "red-ui-flow-node-status-label",
|
||||
x: 20,
|
||||
y: 10
|
||||
})
|
||||
statusEl.appendChild(statusLabel);
|
||||
node[0][0].__statusLabel__ = statusLabel;
|
||||
|
||||
@@ -4714,10 +4708,11 @@ RED.view = (function() {
|
||||
}
|
||||
for (var i=0; i<sn; i++) {
|
||||
if (i===textLines.length) {
|
||||
var line = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
line.setAttribute("class","red-ui-flow-node-label-text");
|
||||
line.setAttribute("x",0);
|
||||
line.setAttribute("y",i*24);
|
||||
var line = RED.utils.createSVGElement("text", {
|
||||
class: "red-ui-flow-node-label-text",
|
||||
x: 0,
|
||||
y: i*24
|
||||
})
|
||||
this.__textGroup__.appendChild(line);
|
||||
}
|
||||
textLines[i].textContent = sa[i];
|
||||
@@ -4816,22 +4811,23 @@ RED.view = (function() {
|
||||
for(var portIndex = 0; portIndex < numOutputs; portIndex++ ) {
|
||||
var portGroup;
|
||||
if (portIndex === this.__outputs__.length) {
|
||||
portGroup = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
portGroup.setAttribute("class","red-ui-flow-port-output");
|
||||
portGroup = RED.utils.createSVGElement("g", { class: "red-ui-flow-port-output" })
|
||||
var portPort;
|
||||
if (d.type === "link out") {
|
||||
portPort = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||
portPort.setAttribute("cx",11);
|
||||
portPort.setAttribute("cy",5);
|
||||
portPort.setAttribute("r",5);
|
||||
portPort.setAttribute("class","red-ui-flow-port red-ui-flow-link-port");
|
||||
portPort = RED.utils.createSVGElement("circle", {
|
||||
cx: 11,
|
||||
cy: 5,
|
||||
r: 5,
|
||||
class: "red-ui-flow-port red-ui-flow-link-port"
|
||||
})
|
||||
} else {
|
||||
portPort = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
portPort.setAttribute("rx",3);
|
||||
portPort.setAttribute("ry",3);
|
||||
portPort.setAttribute("width",10);
|
||||
portPort.setAttribute("height",10);
|
||||
portPort.setAttribute("class","red-ui-flow-port");
|
||||
portPort = RED.utils.createSVGElement("rect", {
|
||||
rx: 3,
|
||||
ry: 3,
|
||||
width: 10,
|
||||
height: 10,
|
||||
class: "red-ui-flow-port"
|
||||
})
|
||||
}
|
||||
portGroup.appendChild(portPort);
|
||||
portGroup.__port__ = portPort;
|
||||
@@ -4878,9 +4874,20 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
icon.attr("y",function(){return (d.h-d3.select(this).attr("height"))/2;});
|
||||
this.__iconShade__.setAttribute("height", d.h );
|
||||
|
||||
|
||||
const iconShadeHeight = d.h
|
||||
const iconShadeWidth = 30
|
||||
this.__iconShade__.setAttribute("d", hideLabel ?
|
||||
`M5 0 h${iconShadeWidth-10} a 5 5 0 0 1 5 5 v${iconShadeHeight-10} a 5 5 0 0 1 -5 5 h-${iconShadeWidth-10} a 5 5 0 0 1 -5 -5 v-${iconShadeHeight-10} a 5 5 0 0 1 5 -5` : (
|
||||
"right" === d._def.align ?
|
||||
`M 0 0 h${iconShadeWidth-5} a 5 5 0 0 1 5 5 v${iconShadeHeight-10} a 5 5 0 0 1 -5 5 h-${iconShadeWidth-5} v-${iconShadeHeight}` :
|
||||
`M5 0 h${iconShadeWidth-5} v${iconShadeHeight} h-${iconShadeWidth-5} a 5 5 0 0 1 -5 -5 v-${iconShadeHeight-10} a 5 5 0 0 1 5 -5`
|
||||
)
|
||||
)
|
||||
this.__iconShadeBorder__.style.display = hideLabel?'none':''
|
||||
this.__iconShadeBorder__.setAttribute("d",
|
||||
"M " + (((!d._def.align && d.inputs !== 0 && d.outputs === 0) || "right" === d._def.align) ? 0 : 30) + " 1 l 0 " + (d.h - 2)
|
||||
"M " + (((!d._def.align && d.inputs !== 0 && d.outputs === 0) || "right" === d._def.align) ? 0.5 : 29.5) + " "+(d.selected?1:0.5)+" l 0 " + (d.h - (d.selected?2:1))
|
||||
);
|
||||
faIcon.attr("y",(d.h+13)/2);
|
||||
}
|
||||
@@ -4972,26 +4979,28 @@ RED.view = (function() {
|
||||
var junction = d3.select(this);
|
||||
var contents = document.createDocumentFragment();
|
||||
// d.added = true;
|
||||
var junctionBack = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
junctionBack.setAttribute("class","red-ui-flow-junction-background");
|
||||
junctionBack.setAttribute("x",-5);
|
||||
junctionBack.setAttribute("y",-5);
|
||||
junctionBack.setAttribute("width",10);
|
||||
junctionBack.setAttribute("height",10);
|
||||
junctionBack.setAttribute("rx",3);
|
||||
junctionBack.setAttribute("ry",3);
|
||||
var junctionBack = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-junction-background",
|
||||
x: -5,
|
||||
y: -5,
|
||||
width: 10,
|
||||
height: 10,
|
||||
rx: 3,
|
||||
ry: 3
|
||||
})
|
||||
junctionBack.__data__ = d;
|
||||
this.__junctionBack__ = junctionBack;
|
||||
contents.appendChild(junctionBack);
|
||||
|
||||
var junctionInput = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
junctionInput.setAttribute("class","red-ui-flow-junction-port red-ui-flow-junction-port-input");
|
||||
junctionInput.setAttribute("x",-5);
|
||||
junctionInput.setAttribute("y",-5);
|
||||
junctionInput.setAttribute("width",10);
|
||||
junctionInput.setAttribute("height",10);
|
||||
junctionInput.setAttribute("rx",3);
|
||||
junctionInput.setAttribute("ry",3);
|
||||
var junctionInput = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-junction-port red-ui-flow-junction-port-input",
|
||||
x: -5,
|
||||
y: -5,
|
||||
width: 10,
|
||||
height: 10,
|
||||
rx: 3,
|
||||
ry: 3
|
||||
})
|
||||
junctionInput.__data__ = d;
|
||||
junctionInput.__portType__ = PORT_TYPE_INPUT;
|
||||
junctionInput.__portIndex__ = 0;
|
||||
@@ -5003,14 +5012,15 @@ RED.view = (function() {
|
||||
|
||||
this.__junctionInput__ = junctionInput;
|
||||
contents.appendChild(junctionInput);
|
||||
var junctionOutput = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
junctionOutput.setAttribute("class","red-ui-flow-junction-port red-ui-flow-junction-port-output");
|
||||
junctionOutput.setAttribute("x",-5);
|
||||
junctionOutput.setAttribute("y",-5);
|
||||
junctionOutput.setAttribute("width",10);
|
||||
junctionOutput.setAttribute("height",10);
|
||||
junctionOutput.setAttribute("rx",3);
|
||||
junctionOutput.setAttribute("ry",3);
|
||||
var junctionOutput = RED.utils.createSVGElement("rect", {
|
||||
class: "red-ui-flow-junction-port red-ui-flow-junction-port-output",
|
||||
x: -5,
|
||||
y: -5,
|
||||
width: 10,
|
||||
height: 10,
|
||||
rx: 3,
|
||||
ry: 3,
|
||||
})
|
||||
junctionOutput.__data__ = d;
|
||||
junctionOutput.__portType__ = PORT_TYPE_OUTPUT;
|
||||
junctionOutput.__portIndex__ = 0;
|
||||
@@ -5067,9 +5077,8 @@ RED.view = (function() {
|
||||
var pathContents = document.createDocumentFragment();
|
||||
|
||||
d.added = true;
|
||||
var pathBack = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
var pathBack = RED.utils.createSVGElement("path", { class: "red-ui-flow-link-background red-ui-flow-link-path"+(d.link?" red-ui-flow-link-link":"")})
|
||||
pathBack.__data__ = d;
|
||||
pathBack.setAttribute("class","red-ui-flow-link-background red-ui-flow-link-path"+(d.link?" red-ui-flow-link-link":""));
|
||||
this.__pathBack__ = pathBack;
|
||||
pathContents.appendChild(pathBack);
|
||||
d3.select(pathBack)
|
||||
@@ -5105,16 +5114,17 @@ RED.view = (function() {
|
||||
}
|
||||
})
|
||||
|
||||
var pathOutline = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
var pathOutline = RED.utils.createSVGElement("path", {
|
||||
class: "red-ui-flow-link-outline red-ui-flow-link-path"
|
||||
})
|
||||
pathOutline.__data__ = d;
|
||||
pathOutline.setAttribute("class","red-ui-flow-link-outline red-ui-flow-link-path");
|
||||
this.__pathOutline__ = pathOutline;
|
||||
pathContents.appendChild(pathOutline);
|
||||
|
||||
var pathLine = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
var pathLine = RED.utils.createSVGElement("path", {
|
||||
class: "red-ui-flow-link-line red-ui-flow-link-path"+(d.link?" red-ui-flow-link-link":(activeSubflow?" red-ui-flow-subflow-link":""))
|
||||
})
|
||||
pathLine.__data__ = d;
|
||||
pathLine.setAttribute("class","red-ui-flow-link-line red-ui-flow-link-path"+
|
||||
(d.link?" red-ui-flow-link-link":(activeSubflow?" red-ui-flow-subflow-link":"")));
|
||||
this.__pathLine__ = pathLine;
|
||||
pathContents.appendChild(pathLine);
|
||||
|
||||
|
@@ -171,6 +171,7 @@
|
||||
left:0;
|
||||
width: 30px;
|
||||
border-right: 1px solid var(--red-ui-node-icon-background-color);
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
background-color: var(--red-ui-node-icon-background-color);
|
||||
}
|
||||
.red-ui-palette-icon-container-right {
|
||||
@@ -178,6 +179,7 @@
|
||||
right: 0;
|
||||
border-right: none;
|
||||
border-left: 1px solid var(--red-ui-node-icon-background-color);
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
}
|
||||
.red-ui-palette-icon {
|
||||
display: inline-block;
|
||||
|
@@ -1,15 +1,15 @@
|
||||
export default {
|
||||
version: "3.0.0-beta.4",
|
||||
version: "3.0.0",
|
||||
steps: [
|
||||
{
|
||||
titleIcon: "fa fa-map-o",
|
||||
title: {
|
||||
"en-US": "Welcome to Node-RED 3.0 Beta 4!",
|
||||
"ja": "Node-RED 3.0 ベータ4へようこそ!"
|
||||
"en-US": "Welcome to Node-RED 3.0!",
|
||||
"ja": "Node-RED 3.0へようこそ!"
|
||||
},
|
||||
description: {
|
||||
"en-US": "<p>This is another final beta release of Node-RED 3.0.</p><p>Let's take a moment to discover the new features in this release.</p>",
|
||||
"ja": "<p>これはNode-RED 3.0のもう一つの最後のベータリリースです。</p><p>本リリースの新機能を見つけてみましょう。</p>"
|
||||
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
|
||||
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@@ -245,47 +245,37 @@
|
||||
// complete parentage of the node that generated this message.
|
||||
// flow-id/subflow-A-instance/subflow-B-instance
|
||||
|
||||
// If it has one id, that is a top level flow
|
||||
// If it has one id, that is a top level flow or config node/global
|
||||
// each subsequent id is the instance id of a subflow node
|
||||
//
|
||||
pathParts = o.path.split("/");
|
||||
if (pathParts.length === 1) {
|
||||
// The source node is on a flow - so can use its id to find
|
||||
// The source node is on a flow or is a global/config - so can use its id to find
|
||||
sourceNode = RED.nodes.node(o.id);
|
||||
if (pathParts[0] === "global") {
|
||||
pathParts = [];
|
||||
}
|
||||
} else if (pathParts.length > 1) {
|
||||
// Highlight the subflow instance node.
|
||||
sourceNode = RED.nodes.node(pathParts[1]);
|
||||
}
|
||||
const getNodeLabel = (n) => n.name || (typeof n.label === "function" && n.label()) || (typeof n.label === "string" && n.label) || (n.type + ":" + n.id);
|
||||
pathHierarchy = pathParts.map((id,index) => {
|
||||
if (index === 0) {
|
||||
return {
|
||||
id: id,
|
||||
label: RED.nodes.workspace(id).label
|
||||
}
|
||||
if (id === "global") {
|
||||
return { id: sourceNode.id, label: getNodeLabel(sourceNode) }
|
||||
}
|
||||
return { id: id, label: RED.nodes.workspace(id).label } //flow id + name
|
||||
} else {
|
||||
var instanceNode = RED.nodes.node(id)
|
||||
return {
|
||||
id: id,
|
||||
label: (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
|
||||
}
|
||||
const instanceNode = RED.nodes.node(id)
|
||||
const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
|
||||
return { id: id, label: pathLabel }
|
||||
}
|
||||
})
|
||||
if (pathParts.length === 1) {
|
||||
pathHierarchy.push({
|
||||
id: o.id,
|
||||
label: sourceNode.name || sourceNode.type+":"+sourceNode.id
|
||||
})
|
||||
if (pathParts.length === 1 && pathParts[0] !== "global") {
|
||||
pathHierarchy.push({ id: o.id, label: getNodeLabel(sourceNode) })
|
||||
}
|
||||
if (o._alias) {
|
||||
let aliasNode = RED.nodes.node(o._alias)
|
||||
if (aliasNode) {
|
||||
pathHierarchy.push({
|
||||
id: o._alias,
|
||||
label: aliasNode.name || aliasNode.type+":"+aliasNode.id
|
||||
})
|
||||
pathHierarchy.push({ id: o._alias, label: getNodeLabel(aliasNode) })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@@ -29,23 +29,23 @@ module.exports = function(RED) {
|
||||
"use strict";
|
||||
const crypto = require("crypto");
|
||||
const targetCache = (function () {
|
||||
const registry = { id: {}, name: {} };
|
||||
function getIndex(/** @type {[LinkTarget]}*/ targets, id) {
|
||||
let registry = { id: {}, name: {} }
|
||||
function getIndex (/** @type {[LinkTarget]} */ targets, id) {
|
||||
for (let index = 0; index < (targets || []).length; index++) {
|
||||
const element = targets[index];
|
||||
const element = targets[index]
|
||||
if (element.id === id) {
|
||||
return index;
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return -1
|
||||
}
|
||||
/**
|
||||
* Generate a target object from a node
|
||||
* @param {LinkInNode} node
|
||||
* @param {LinkInNode} node
|
||||
* @returns {LinkTarget} a link target object
|
||||
*/
|
||||
function generateTarget(node) {
|
||||
const isSubFlow = node._flow.TYPE === "subflow";
|
||||
function generateTarget (node) {
|
||||
const isSubFlow = node._flow.TYPE === 'subflow'
|
||||
return {
|
||||
id: node.id,
|
||||
name: node.name || node.id,
|
||||
@@ -58,72 +58,72 @@ module.exports = function(RED) {
|
||||
/**
|
||||
* Get a list of targets registerd to this name
|
||||
* @param {string} name Name of the target
|
||||
* @param {boolean} [excludeSubflows] set `true` to exclude
|
||||
* @param {boolean} [excludeSubflows] set `true` to exclude
|
||||
* @returns {[LinkTarget]} Targets registerd to this name.
|
||||
*/
|
||||
getTargets(name, excludeSubflows) {
|
||||
const targets = registry.name[name] || [];
|
||||
getTargets (name, excludeSubflows) {
|
||||
const targets = registry.name[name] || []
|
||||
if (excludeSubflows) {
|
||||
return targets.filter(e => e.isSubFlow != true);
|
||||
return targets.filter(e => e.isSubFlow !== true)
|
||||
}
|
||||
return targets;
|
||||
return targets
|
||||
},
|
||||
/**
|
||||
* Get a single target by registered name.
|
||||
* To restrict to a single flow, include the `flowId`
|
||||
* If there is no targets OR more than one target, null is returned
|
||||
* @param {string} name Name of the node
|
||||
* @param {string} [flowId]
|
||||
* @param {string} [flowId]
|
||||
* @returns {LinkTarget} target
|
||||
*/
|
||||
getTarget(name, flowId) {
|
||||
/** @type {[LinkTarget]}*/
|
||||
let possibleTargets = this.getTargets(name);
|
||||
/** @type {LinkTarget}*/
|
||||
let target;
|
||||
getTarget (name, flowId) {
|
||||
/** @type {[LinkTarget]} */
|
||||
let possibleTargets = this.getTargets(name)
|
||||
/** @type {LinkTarget} */
|
||||
let target
|
||||
if (possibleTargets.length && flowId) {
|
||||
possibleTargets = possibleTargets.filter(e => e.flowId == flowId);
|
||||
possibleTargets = possibleTargets.filter(e => e.flowId === flowId)
|
||||
}
|
||||
if (possibleTargets.length === 1) {
|
||||
target = possibleTargets[0];
|
||||
target = possibleTargets[0]
|
||||
}
|
||||
return target;
|
||||
return target
|
||||
},
|
||||
/**
|
||||
* Get a target by node ID
|
||||
* @param {string} nodeId ID of the node
|
||||
* @returns {LinkTarget} target
|
||||
*/
|
||||
getTargetById(nodeId) {
|
||||
return registry.id[nodeId];
|
||||
getTargetById (nodeId) {
|
||||
return registry.id[nodeId]
|
||||
},
|
||||
register(/** @type {LinkInNode} */ node) {
|
||||
const target = generateTarget(node);
|
||||
const tByName = this.getTarget(target.name, target.flowId);
|
||||
register (/** @type {LinkInNode} */ node) {
|
||||
const target = generateTarget(node)
|
||||
const tByName = this.getTarget(target.name, target.flowId)
|
||||
if (!tByName || tByName.id !== target.id) {
|
||||
registry.name[target.name] = registry.name[target.name] || [];
|
||||
registry.name[target.name] = registry.name[target.name] || []
|
||||
registry.name[target.name].push(target)
|
||||
}
|
||||
registry.id[target.id] = target;
|
||||
return target;
|
||||
registry.id[target.id] = target
|
||||
return target
|
||||
},
|
||||
remove(node) {
|
||||
const target = generateTarget(node);
|
||||
const targs = this.getTargets(target.name);
|
||||
const idx = getIndex(targs, target.id);
|
||||
remove (node) {
|
||||
const target = generateTarget(node)
|
||||
const targs = this.getTargets(target.name)
|
||||
const idx = getIndex(targs, target.id)
|
||||
if (idx > -1) {
|
||||
targs.splice(idx, 1);
|
||||
targs.splice(idx, 1)
|
||||
}
|
||||
if (targs.length === 0) {
|
||||
delete registry.name[tn.name];
|
||||
delete registry.name[target.name]
|
||||
}
|
||||
delete registry.id[target.id];
|
||||
delete registry.id[target.id]
|
||||
},
|
||||
clear() {
|
||||
registry = { id: {}, name: {} };
|
||||
clear () {
|
||||
registry = { id: {}, name: {} }
|
||||
}
|
||||
}
|
||||
})();
|
||||
})()
|
||||
|
||||
function LinkInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
@@ -168,9 +168,9 @@ module.exports = function(RED) {
|
||||
return getFromValueType(RED.util.getMessageProperty(msg,rule.from),done);
|
||||
} else if (rule.fromt === 'flow' || rule.fromt === 'global') {
|
||||
var contextKey = RED.util.parseContextStore(rule.from);
|
||||
if (/\[msg\./.test(context.key)) {
|
||||
if (/\[msg\./.test(contextKey.key)) {
|
||||
// The key has a nest msg. reference to evaluate first
|
||||
context.key = RED.util.normalisePropertyExpression(contextKey.key,msg,true);
|
||||
contextKey.key = RED.util.normalisePropertyExpression(contextKey.key,msg,true);
|
||||
}
|
||||
node.context()[rule.fromt].get(contextKey.key, contextKey.store, (err,fromValue) => {
|
||||
if (err) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,11 +16,11 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.0.0-beta.4",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "10.1.0",
|
||||
"semver": "7.3.7",
|
||||
"tar": "6.1.11",
|
||||
"uglify-js": "3.16.0"
|
||||
"uglify-js": "3.16.2"
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "3.0.0-beta.4",
|
||||
"@node-red/util": "3.0.0-beta.4",
|
||||
"@node-red/registry": "3.1.0-beta.0",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"async-mutex": "0.3.2",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.18.1",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -16,11 +16,11 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"fs-extra": "10.1.0",
|
||||
"i18next": "21.8.10",
|
||||
"i18next": "21.8.14",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.6",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"moment": "2.29.3",
|
||||
"moment": "2.29.4",
|
||||
"moment-timezone": "0.5.34"
|
||||
}
|
||||
}
|
||||
|
10
packages/node_modules/node-red/package.json
vendored
10
packages/node_modules/node-red/package.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.0.0-beta.4",
|
||||
"version": "3.1.0-beta.0",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "3.0.0-beta.4",
|
||||
"@node-red/runtime": "3.0.0-beta.4",
|
||||
"@node-red/util": "3.0.0-beta.4",
|
||||
"@node-red/nodes": "3.0.0-beta.4",
|
||||
"@node-red/editor-api": "3.1.0-beta.0",
|
||||
"@node-red/runtime": "3.1.0-beta.0",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"@node-red/nodes": "3.1.0-beta.0",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.18.1",
|
||||
|
Reference in New Issue
Block a user