Compare commits

...

438 Commits

Author SHA1 Message Date
Nick O'Leary
43db1824be Bump for 1.1.2 2020-07-10 20:13:05 +01:00
Nick O'Leary
7f671c9f3f Ensure unknown nodes removed from outliner when node registers
Fixes #2646
2020-07-10 20:00:18 +01:00
Nick O'Leary
580cc00967 Fix all the touch screen issues 2020-07-10 16:00:38 +01:00
Nick O'Leary
612c565cfd Add RED.view.redrawStatus to avoid full redraw on update 2020-07-10 16:00:18 +01:00
Nick O'Leary
979c5351a8 Ensure node/group xrefs are consistent on import 2020-07-10 15:59:28 +01:00
Nick O'Leary
97b7479081 Disable keyboard handler when dialogs are open 2020-07-09 20:41:55 +01:00
Nick O'Leary
1df2f5e96a Allow Comms websocket auth to be done via token header
Fixes #2642
2020-07-09 19:07:51 +01:00
Nick O'Leary
32163d5f21 Update changelog 2020-07-08 13:26:48 +01:00
Nick O'Leary
1c337f6817 Fix connecting wires to subflow status or io ports on touchscreen 2020-07-08 13:22:26 +01:00
Nick O'Leary
6df26f2400 Bump for 1.1.1 2020-07-08 10:30:20 +01:00
Nick O'Leary
a9431a5aee Merge pull request #2645 from kazuhitoyokoi/master-addjpn
Update Japanese message for debug node
2020-07-08 10:08:49 +01:00
Kazuhito Yokoi
5a3c832a98 Update Japanese message for debug node 2020-07-08 16:20:02 +09:00
Nick O'Leary
c4b5bb22db Tidy up commit msg on docker update action 2020-07-08 01:13:14 +01:00
Nick O'Leary
2b5a976f35 Add github action to auto-update docker repo version on release publish 2020-07-08 01:02:18 +01:00
Nick O'Leary
ae1ca85924 Update Debug status label 2020-07-07 22:10:47 +01:00
Nick O'Leary
c9acfdb1d7 Set apiRootUrl for debug pop-out to load locales properly
Fixes #2629, #2630
2020-07-07 21:14:44 +01:00
Nick O'Leary
11ac8fbf13 Ensure groups are removed when deleting subflows 2020-07-07 18:23:42 +01:00
Nick O'Leary
dc541444ba Merge pull request #2638 from node-red/Clean-up-debug-status-/-remove-loops
fix debug status to not loop, make migration more seamless, detect status type objects
2020-07-07 13:37:05 +01:00
Nick O'Leary
8ea25bcd1c Update build-custom-theme to handle keyframes properly
Fixes #2636

Also adds a header to the generated CSS identifing the version
of NR and date/time it was generated.
2020-07-07 11:38:07 +01:00
Nick O'Leary
f5e46a663a Remove hardcoded css and allow group to default from theme
Fixes #2633
2020-07-07 11:01:05 +01:00
Nick O'Leary
64ec415a54 Add RED.view.DEBUG_SYNC_REDRAW to disable requestAnimationFrame
References #2631
2020-07-06 21:01:14 +01:00
Nick O'Leary
57154b2853 Authenticate websocket comms using user-provided token if present
Fixes #2642
2020-07-06 20:45:07 +01:00
Nick O'Leary
0243a902b2 Fix up subflow port wiring 2020-07-06 18:11:47 +01:00
Nick O'Leary
6c04402a98 Prevent wiring to node with no corresponding port
Fixes #2641
2020-07-06 17:32:44 +01:00
Nick O'Leary
ef7c9b5c2a Get group order right in history events to ensure proper handling 2020-07-06 16:00:15 +01:00
Nick O'Leary
73448a6039 Avoid copying duplicate nodes to internal clipboard 2020-07-06 16:00:15 +01:00
Dave Conway-Jones
176a0ff99b add words avout indepedence of messages being delayed. 2020-07-06 10:33:26 +01:00
Dave Conway-Jones
b96d562700 fix debug status to not loop, make migration more seamless, detect status type objects 2020-07-04 15:26:02 +01:00
Nick O'Leary
7a3ead8f3b Merge branch 'dev' 2020-06-30 17:46:43 +01:00
Nick O'Leary
f72903ccc2 Update changelog 2020-06-29 21:12:12 +01:00
Nick O'Leary
668678b2c4 Bump version to 1.1.0 2020-06-29 21:08:34 +01:00
Nick O'Leary
e2802175a5 Clear outline focus on config node sidebar panel 2020-06-29 21:07:21 +01:00
Nick O'Leary
71c5b1be86 Merge pull request #2628 from Steve-Mcl/dev
Add developer options
2020-06-29 20:51:11 +01:00
Nick O'Leary
44da085e0b Tweak group margin to fit node status and look better 2020-06-29 20:43:25 +01:00
Nick O'Leary
362554ad3b Switch JSONata expr does not require msg.parts.count 2020-06-29 09:32:52 +01:00
Dave Conway-Jones
f01866d76f Fix backwards migration of inject without topic 2020-06-28 15:09:07 +01:00
Steve-Mcl
53490cd368 Add developer options
- permits npm run build-dev.  skips minification & doesnt launch nodemon
- permits npm run dev for those without grunt installed globally
2020-06-27 11:24:06 +01:00
Nick O'Leary
c171088838 Fix reparenting nodes in outliner when they change 2020-06-26 17:21:20 +01:00
Nick O'Leary
0cc944dc5a Update changelog 2020-06-26 16:02:19 +01:00
Nick O'Leary
8bd8834237 Add default shortcut for core:show-help-tab 2020-06-26 15:58:02 +01:00
Nick O'Leary
84fc739c8d Merge pull request #2626 from node-red-hitachi/dev-zhcn
Update both zh-CN and zh-TW translation for release 1.1.0
2020-06-26 15:54:47 +01:00
JIYE YU
a7fa2cf0c9 update zh-TW translation for release-1.1.0 2020-06-26 10:40:17 +09:00
JIYE YU
1137cd5ca5 update zh-CN translation for nodes information 2020-06-26 10:38:41 +09:00
Nick O'Leary
d47906b525 Simplify example https settings 2020-06-25 20:10:26 +01:00
JIYE YU
13a59a882e update zh-CN translation for editor-client 2020-06-25 18:31:36 +09:00
Nick O'Leary
3b7348f862 Update changelog 2020-06-24 14:51:18 +01:00
Nick O'Leary
07585f01e3 Ensure all examples are consistently named 2020-06-24 14:43:27 +01:00
Nick O'Leary
5042137006 Merge branch 'pr_2585' into examples 2020-06-24 13:50:50 +01:00
Nick O'Leary
a2ea79130c Merge branch 'pr_2550' into examples 2020-06-24 13:49:56 +01:00
Nick O'Leary
979401f3ac Merge branch 'pr_2549' into examples 2020-06-24 13:49:33 +01:00
Nick O'Leary
4c98db2269 Outliner - add empty item when last config node moved 2020-06-24 13:18:46 +01:00
Nick O'Leary
209c5f337c Join node - clear timeout when msg.reset received
Fixes #2471
2020-06-24 10:02:42 +01:00
Nick O'Leary
8080ed4787 Merge pull request #2623 from node-red-hitachi/update-subflow-message-jp
Update subflow message jp
2020-06-23 16:18:36 +01:00
Nick O'Leary
f3be5f0e67 Merge pull request #2624 from node-red-hitachi/fix-subflow-input
Fix error on empty subflow input types
2020-06-23 16:18:02 +01:00
Hiroyasu Nishiyama
fb2d185c5f fix typedInput error on empty subflow input types 2020-06-23 09:24:29 +09:00
Hiroyasu Nishiyama
f2d696b48e update JP message catalogue for subflow input type 2020-06-23 08:39:44 +09:00
Dave Conway-Jones
5596d2df8e catch tiny possible escape for "\n " in exec command node label. 2020-06-22 22:41:22 +01:00
Dave Conway-Jones
b72ca439e2 Fix tcp in node finishing packets when in streaming base64 receive mode. 2020-06-22 22:40:15 +01:00
Nick O'Leary
432ed264c2 Remove hardcoded css
Fixes #2603
2020-06-22 20:39:41 +01:00
Nick O'Leary
0a411cbe4f Fix node button mouse pointer css 2020-06-22 14:37:52 +01:00
Nick O'Leary
581f71911a Change node linebreak handling to use "\n " 2020-06-22 13:08:35 +01:00
Nick O'Leary
e548bf8bc2 Handle import of node with non-default number of outputs 2020-06-22 10:43:09 +01:00
Nick O'Leary
1d944bab51 Improve display of focussed form element 2020-06-18 22:25:19 +01:00
Nick O'Leary
6f407750f5 Fix clearing group label 2020-06-18 22:25:00 +01:00
Nick O'Leary
19ffe8f308 Default group label to be shown and improve toggle button 2020-06-18 22:24:44 +01:00
Nick O'Leary
c9069d472f Make color/icon/label-pos pickers keyboard navigable 2020-06-18 22:23:50 +01:00
Nick O'Leary
68d3cc7507 Fix node toggle button initial opacity 2020-06-18 10:18:35 +01:00
Nick O'Leary
0c90376752 Align node labels on FF
FF doesn't seems to use alignment-baseline CSS class in the same
way Chrome does. Switched to domintant-baseline.
2020-06-18 10:11:22 +01:00
Hiroyasu Nishiyama
f5eb832cd2 merge template node example #1 and #4 2020-06-18 14:03:33 +09:00
Hiroyasu Nishiyama
c3a058a479 fixed switch node example#8 imported as flow 2020-06-18 13:56:01 +09:00
Hiroyasu Nishiyama
bc87210ce3 change scale and limit to limit and fixed typo 2020-06-18 13:35:09 +09:00
Hiroyasu Nishiyama
d595eb2614 change exec node example to use echo command and merge two examples 2020-06-18 13:12:58 +09:00
Hiroyasu Nishiyama
cb4d118ccc remove delay node example#6 from cookbook 2020-06-18 11:25:05 +09:00
Hiroyasu Nishiyama
62c723866a fix typos 2020-06-18 10:41:36 +09:00
Nick O'Leary
c9e54f2ba9 Bump for 1.1.0-beta.3 2020-06-17 10:54:15 +01:00
Nick O'Leary
e2c86c4b96 Fix wiring nodes from input back to output 2020-06-17 10:52:41 +01:00
Nick O'Leary
4469a334fd Fix sometimes unable to keyboard-move group to left/up 2020-06-17 09:57:25 +01:00
Nick O'Leary
aca379db6e Fix group position in outliner 2020-06-16 20:48:28 +01:00
Nick O'Leary
9ce5210c33 Handle unknown nodes with no icon 2020-06-16 20:34:45 +01:00
Nick O'Leary
4dd68452b4 Prevent node creep when switching tabs 2020-06-16 20:23:18 +01:00
Nick O'Leary
714b3d3fe0 Bump version to 1.1.0-beta.2 2020-06-16 15:21:03 +01:00
Nick O'Leary
2378e0d961 Fix up linting in search.js 2020-06-16 15:08:30 +01:00
Nick O'Leary
f78bbdc29f Update CHANGELOG for 1.1.0-beta.2 2020-06-16 15:03:56 +01:00
Nick O'Leary
708620f929 Merge pull request #2605 from johanneskropf/patch-1
use bash as shell for exec command if on linux
2020-06-16 14:45:34 +01:00
Nick O'Leary
9f0490fc12 Merge pull request #2619 from kazuhitoyokoi/dev-fixuitest3
Fix page object of inject node
2020-06-16 14:38:15 +01:00
Nick O'Leary
d37eebd8ed Merge pull request #2618 from kazuhitoyokoi/dev-addjpntranslations
Fix i18n bug in outliner
2020-06-16 14:22:55 +01:00
Kazuhito Yokoi
bfeda23ce5 Fix page object of inject node 2020-06-16 21:58:08 +09:00
Kazuhito Yokoi
52eb158231 Add Japanese translations for outliner, jsonata and runtime 2020-06-16 21:32:10 +09:00
Nick O'Leary
afb782410d Merge pull request #2617 from kazuhitoyokoi/dev-fixuitest2
Fix page object of debug node
2020-06-16 10:57:16 +01:00
Nick O'Leary
aebb7da3c7 Fix deleting node in group after changing selection 2020-06-16 10:54:50 +01:00
Kazuhito Yokoi
b90710945a Fix page object of debug node 2020-06-16 11:45:27 +09:00
Nick O'Leary
56efd51c06 Fixup padding of quick-add search box 2020-06-15 22:31:47 +01:00
Nick O'Leary
76728d1783 Move config nodes under type-level hierarchy in outline
Also adds user-count label and button to open search
2020-06-15 22:31:47 +01:00
Nick O'Leary
5b1fe9aa0a Emit nodes:change event for config node users list modified 2020-06-15 22:31:47 +01:00
Nick O'Leary
e3c8466819 Merge pull request #2616 from kazuhitoyokoi/dev-fixuitest
Fix page object of inject node
2020-06-15 22:27:30 +01:00
Kazuhito Yokoi
6a70cd1975 Fix page object of inject node 2020-06-15 20:36:41 +09:00
Nick O'Leary
2c45771024 Merge pull request #2593 from kazuhitoyokoi/master-adduitest4travis
Enable automated UI testing on Travis CI
2020-06-15 11:14:14 +01:00
Nick O'Leary
ebca8c0217 Increase group margin to avoid clash with status text 2020-06-14 23:44:26 +01:00
Nick O'Leary
752a080876 Fix event order when quick-adding node to group 2020-06-14 23:44:01 +01:00
Nick O'Leary
0541d9189d Switch RED.events.DEBUG messages to warn to get stacktraces 2020-06-14 23:43:15 +01:00
Nick O'Leary
0e454b08c8 Fix empty item handling for subflows/config in outliner 2020-06-14 22:46:59 +01:00
Nick O'Leary
2d0ca20a03 Fix search indexing of group nodes 2020-06-14 22:46:46 +01:00
Nick O'Leary
61d9ccf263 Avoid regenerating every node label on redraw 2020-06-13 23:02:10 +01:00
Hiroyasu Nishiyama
1c30584153 fix code indentation 2020-06-13 23:33:45 +09:00
Hiroyasu Nishiyama
5c5bebd689 fix handling of multi-line node label 2020-06-13 23:28:10 +09:00
johanneskropf
d9548a2891 moved check for shell 2020-06-12 17:14:11 +02:00
johanneskropf
d25e027201 moved building of execOpt object to line 36 2020-06-12 17:10:31 +02:00
Nick O'Leary
93211470d1 Merge pull request #2611 from node-red-hitachi/fix-group-merge-activation
Disable group merge for single item or non-group items
2020-06-12 08:50:12 +01:00
Nick O'Leary
b5800205c4 Merge pull request #2610 from node-red-hitachi/fix-charAt-error-on-undefined
Fix char at error on undefined when opening websocket-listner
2020-06-12 08:49:34 +01:00
Nick O'Leary
eeebf04509 Merge pull request #2609 from node-red-hitachi/fix-remove-from-group
fix empty placeholder not shown on remove from group
2020-06-12 08:49:09 +01:00
Nick O'Leary
f4f99f594d Merge pull request #2612 from node-red-hitachi/fix-group-position
Fix group position of empty group with multi-line label
2020-06-12 08:48:33 +01:00
Hiroyasu Nishiyama
5e8e739f78 fix position of empty group with multi-line label 2020-06-12 16:07:46 +09:00
Hiroyasu Nishiyama
a15adc43af merge code for checking menu activation 2020-06-12 09:54:11 +09:00
Hiroyasu Nishiyama
07556592c1 disable merge group menu for single item or non-group item 2020-06-12 08:42:15 +09:00
Hiroyasu Nishiyama
7694349078 prevent charAt call on websocket listener 2020-06-11 23:00:56 +09:00
Hiroyasu Nishiyama
4f3cb3103e make treelist of subflow/config nodes initialy has empty placeholder 2020-06-11 22:18:31 +09:00
Hiroyasu Nishiyama
842cd1ecf0 fix empty placeholder not shown on remove from group 2020-06-11 09:57:43 +09:00
Nick O'Leary
81a4f42673 Merge pull request #2607 from node-red-hitachi/fix-stringify-error
prevent conversion of circular structure
2020-06-10 13:38:32 +01:00
Hiroyasu Nishiyama
152e695f4c prevent conversion of circular structure 2020-06-10 19:56:16 +09:00
Nick O'Leary
5a0c10b80e Handle null status text in the editor
Fixes #2606
2020-06-10 10:58:44 +01:00
johanneskropf
06adf3d346 use bash as shell for exec command if on linux
This relates to:
https://github.com/node-red/node-red/issues/2604
and
https://discourse.nodered.org/t/exec-node-timeout-not-working-in-exec-mode/28040
and is a possible workaround for most issues related to kill described there.
This has only been tested on linux where this change applies so it would most definitely need more testing on windows/mac and maybe linux distributions where there is no bash(?).
2020-06-10 11:24:56 +02:00
Nick O'Leary
7be824640c Fix snapToGrid 2020-06-10 01:02:48 +01:00
Nick O'Leary
c061487a16 Massively reduce our dependency on d3 to render the view
This is a slightly scary set of changes to be making. It overhauls
how the view is rendered.

Rather than use d3 for every single part of generating the view,
we new use native DOM functions as much as possible.

d3 is still used for the basic heavy lifting of working out what
nodes/links etc need to be added/removed from the view. But once
it comes to rendering them, d3 is side-lined as much as possible.

There's room for further improvement. This change focusses on Nodes
and Links. It has not touched groups, subflow-ports and link-nodes.
2020-06-10 00:45:20 +01:00
Nick O'Leary
97fd34150f EditableList/TreeList - defer adding elements to DOM
Whenever a DOM element is modified, it causes the browser to re-examine
the whole hierarchy around the element to see if anything needs to change.

This can cause a lot of extra work if an element is added to the DOM and
then a lot of updates are applied to the element.

It is much better to get the element as close to its final state as
possible *before* adding it to the DOM.
2020-06-10 00:42:11 +01:00
Nick O'Leary
6d294a0c74 Prevent RED.stop being called multiple times if >1 signal received 2020-06-09 08:23:12 +01:00
Nick O'Leary
fe4ef354ac Flag a node as removed when it is disabled 2020-06-08 20:59:00 +01:00
Nick O'Leary
d28b8b5e8d Some performance improvements for TreeList 2020-06-08 17:13:05 +01:00
Nick O'Leary
f2b30d9a3f Resize info/help sidebars whenever sidebar is opened 2020-06-08 13:17:06 +01:00
Nick O'Leary
0a614f2741 Add search defaults to outliner searchBox 2020-06-08 12:02:21 +01:00
Nick O'Leary
a9fb50787b Add search presets option to searchBox widget 2020-06-08 12:01:29 +01:00
Nick O'Leary
ce7d7a8e01 Add RED.popover.menu as a new type of menu widget 2020-06-08 12:01:05 +01:00
Nick O'Leary
7006c00233 Add support for is:XYZ search flags
- is:unused
 - is:config
 - is:subflow
 - is:invalid
2020-06-08 11:55:24 +01:00
Nick O'Leary
21866634b3 Track subflow instances on the subflow node itself 2020-06-08 11:49:43 +01:00
Nick O'Leary
34dfd50702 Bump node-red-admin 0.2.6 2020-06-06 10:35:07 +01:00
Nick O'Leary
d9502a6c00 Refresh outline filter whenever something changes
Fixes #2601
2020-06-05 22:19:46 +01:00
Nick O'Leary
95f7b9205a Fix Help tab search box appearance 2020-06-05 17:14:25 +01:00
Nick O'Leary
d14d4944a0 Rename Node Information to Information in sidebar 2020-06-05 17:14:08 +01:00
Nick O'Leary
b4b2729e96 Do a sync-redraw after clearing to ensure clean state 2020-06-05 16:56:12 +01:00
Nick O'Leary
299b81f51b Fix Link node filter
Fixes #2600
2020-06-05 16:20:40 +01:00
Nick O'Leary
ad6b18e66f Make catch/status/complete/link filter case-insensitive 2020-06-05 16:00:02 +01:00
Nick O'Leary
091a462a42 Add 'add' option to touch radialMenu for quick-add dialog 2020-06-05 15:48:45 +01:00
Dave Conway-Jones
cb218a57f1 Merge branch 'dev' of https://github.com/node-red/node-red into dev 2020-06-05 11:22:42 +01:00
Dave Conway-Jones
ba8649117d ensure trigger node detects changes to number of outputs 2020-06-05 11:22:38 +01:00
Nick O'Leary
20daebd965 Ignore whitespace when checking function setup/close code 2020-06-05 10:36:49 +01:00
Nick O'Leary
7c2786969a Preserve event handlers when moving outliner items 2020-06-05 09:55:36 +01:00
Nick O'Leary
565aae5967 Add tooltips to outliner buttons 2020-06-05 09:55:36 +01:00
Dave Conway-Jones
16a634063a Fix debug node status to migrate old nodes to correct default mode. 2020-06-05 09:48:12 +01:00
Nick O'Leary
4c28b5b227 Only validate nodes once they have all been imported
This ensures any checks for dependent config nodes will pass
2020-06-04 17:06:29 +01:00
Nick O'Leary
a7a949377b Ensure configNode.users is updated properly on import 2020-06-04 17:06:11 +01:00
Nick O'Leary
c048b1a25b Exit with non-0 rc if admin command fails 2020-06-04 11:02:48 +01:00
Nick O'Leary
f7e7f7ed01 Add $moment docs 2020-06-04 09:46:17 +01:00
Nick O'Leary
5dfcb80de8 Fixing typos in the changelog 2020-06-04 00:05:12 +01:00
Nick O'Leary
c8f6100a6a Assume -d params are strings if they don't otherwise parse 2020-06-04 00:04:41 +01:00
Nick O'Leary
c0f4e07e10 Bump dependencies 2020-06-03 21:26:31 +01:00
Nick O'Leary
3c259b2c22 Update changelog 2020-06-03 21:10:28 +01:00
Nick O'Leary
3b3a2d4edc Merge pull request #2592 from node-red/admin-cli
Add node-red admin support
2020-06-03 20:59:19 +01:00
Nick O'Leary
e930098b51 Merge pull request #2447 from node-red/catch-more-signals
catch more signals to allow clean context flush on shutdown
2020-06-03 19:28:16 +01:00
Nick O'Leary
43d5df4a12 Merge branch 'dev' into catch-more-signals 2020-06-03 19:26:50 +01:00
Nick O'Leary
914cfdbc55 Merge pull request #2595 from jeancarl/dev
Filter list of nodes on node type
2020-06-03 18:59:57 +01:00
JeanCarl Bisson
aa8f4af339 Filter list of nodes on node type 2020-06-03 10:33:35 -07:00
Nick O'Leary
b6fbe7d07d Merge pull request #2588 from node-red/status-filter-nodes
Add compact searchBox to status/catch/complete nodes
2020-06-03 17:29:05 +01:00
Nick O'Leary
bf9d6c7ac4 Bump to node-red-admin 0.2.4 2020-06-03 16:53:45 +01:00
Nick O'Leary
139ae547c6 Add filter to link node 2020-06-03 15:54:51 +01:00
Nick O'Leary
8b252b458c Merge pull request #2590 from kazuhitoyokoi/dev-addjpnmsg
Add Japanese transaltions for http-request node, change node and https refresh logic
2020-06-03 14:31:52 +01:00
Nick O'Leary
efecfa328b Fix up event handling when deleting groups and tabs 2020-06-03 14:23:26 +01:00
Nick O'Leary
5651e7107f Bump to 0.2.3 node-red-admin 2020-06-03 10:48:52 +01:00
Nick O'Leary
b6b3ceef4d Add some proper validation of module/url properties in install api 2020-06-03 10:45:28 +01:00
Kazuhito Yokoi
e44d89c2af Enable automated UI testing on Travis CI 2020-06-03 17:22:25 +09:00
Nick O'Leary
3e74d75f28 Add node-red admin support 2020-06-02 23:39:36 +01:00
Nick O'Leary
6d737b9e4c Remove unneeded code on object delete in outliner
See https://github.com/node-red/node-red/pull/2578#discussion_r434163293
2020-06-02 22:53:34 +01:00
Nick O'Leary
dec82589d1 Handle missing projects runtime setting 2020-06-02 22:53:05 +01:00
Nick O'Leary
f0193b0f67 Add better messages for 404 errors on admin api 2020-06-02 22:52:22 +01:00
Kazuhito Yokoi
fdf8eb0657 Add japanese transaltions for http-request node and https refresh logic 2020-06-02 14:55:53 +09:00
Nick O'Leary
2ce424b567 Add compact searchBox to status/catch/complete nodes 2020-06-01 21:09:58 +01:00
Nick O'Leary
8995fa9ed1 Update changelog for 1.1.0-beta.1 2020-06-01 14:57:37 +01:00
Nick O'Leary
dc412b305c Tidy up unhandledRejection warning from context unit tests 2020-06-01 13:48:12 +01:00
Nick O'Leary
d7505da997 Merge pull request #2586 from Steve-Mcl/dev
Support setting title on typedInput option/ check
2020-06-01 13:29:01 +01:00
Nick O'Leary
4b54a81dfd Add test cases for setMessageProperty with non-object properties 2020-06-01 13:13:14 +01:00
Nick O'Leary
132254b3a5 Merge branch 'dev' into pr_2439 2020-06-01 11:56:19 +01:00
Steve-Mcl
9128b12960 Support setting title on typedInput option/ check 2020-06-01 11:25:42 +01:00
Nick O'Leary
e9104df047 Merge branch 'dev' into pr_2583 2020-06-01 10:20:40 +01:00
Nick O'Leary
bae52613ab Merge branch 'master' into dev 2020-06-01 09:38:39 +01:00
Nick O'Leary
18af906fd3 Merge branch 'dev' of github.com:node-red/node-red into dev 2020-06-01 09:37:14 +01:00
Nick O'Leary
d45415ab22 Merge branch 'master' into dev 2020-06-01 09:36:20 +01:00
Nick O'Leary
c6c42740c5 Merge pull request #2584 from sammachin/sammachin-settings_set_fix
fix for settings.set subsequent updates
2020-06-01 09:30:41 +01:00
Hiroyasu Nishiyama
b4c033ca50 add missing inject node examples 2020-06-01 15:20:53 +09:00
Hiroyasu Nishiyama
b67f2d874b add examples for function category nodes 2020-06-01 14:44:18 +09:00
Sam Machin
a8d8540346 fix for settings.set subsequent updates
By cloning the value the assert.deepEqual will now fail even for subsequent updates of the value without restarting Node-RED
2020-05-31 13:44:31 +01:00
Dave Conway-Jones
cbf1afc9fe turn off installer funding messages 2020-05-31 11:21:53 +01:00
Dave Conway-Jones
8a798e620a Ensure delay node rate limit timer is cleared on reset 2020-05-30 15:18:15 +01:00
Nick O'Leary
774751a25c Tweak HTTP Request GET payload handling labels 2020-05-29 17:35:18 +01:00
Nick O'Leary
13718032f6 Merge branch 'dev' into pr_2478 2020-05-29 17:04:54 +01:00
Nick O'Leary
1b497b340b Merge branch 'pr_2551' into dev 2020-05-29 16:52:19 +01:00
Nick O'Leary
bb41ab482c Rework the https refresh logic
- puts the node version check first
 - validates the refresh interval and keeps it in valid range
 - simplifies the error messages
 - uses parseFloat not parseInt so we can use fractions of hour
2020-05-29 16:50:53 +01:00
Nick O'Leary
215aab0fe4 Modify format of -D settings file 2020-05-29 11:44:13 +01:00
Nick O'Leary
666822cf51 Merge branch 'dev' into pr_2463 2020-05-29 11:04:38 +01:00
bartbutenaers
40101df6ec Refresh interval in hours 2020-05-29 00:11:14 +02:00
bartbutenaers
4adcb9c439 Refresh interval in hours 2020-05-29 00:08:07 +02:00
dxdc
a6cd0bf7e9 Add moment-timezone dependencies 2020-05-28 06:08:40 -05:00
Nick O'Leary
8158744829 Merge pull request #2578 from node-red-hitachi/fix-group-delete
fix deletion of group
2020-05-28 11:18:08 +01:00
Nick O'Leary
70c0c7bc14 Merge pull request #2582 from node-red-hitachi/fix-IE11-support
remove JSONata Array.from check for IE11
2020-05-28 11:04:15 +01:00
dxdc
fdda29f048 Support for moment-timezone 2020-05-28 01:20:10 -05:00
dxdc
95cc8ea80d Add missing unit test for accesses undefined environment variable from an expression 2020-05-28 00:48:11 -05:00
dxdc
18f8dde712 Add test for $moment jsonata expression 2020-05-27 23:47:04 -05:00
dxdc
effff3405b Add support for moment in jsonata expressions, based on elasticio/jsonata-moment 2020-05-27 23:26:57 -05:00
Hiroyasu Nishiyama
9d8cbcb993 remove JSONata Arra.from check for IE11 2020-05-28 13:22:14 +09:00
Hiroyasu Nishiyama
3345f2f3b8 simplify code structure 2020-05-28 10:23:50 +09:00
Nick O'Leary
bcf1d986a4 Merge branch 'master' of github.com:node-red/node-red 2020-05-27 17:15:45 +01:00
Nick O'Leary
a51e74bfa1 Bump jquery/migrate to latest versions 2020-05-27 17:15:33 +01:00
Nick O'Leary
cf00acac04 Bump jquery/migrate to latest versions 2020-05-27 17:13:33 +01:00
Nick O'Leary
876a7a4646 Add bulk-activate actions for debug node
Adds the actions:

 - core:activate-all-debug-nodes
 - core:activate-all-flow-debug-nodes

to match the deactivate* actions.

Also adds:

 - core:activate-selected-debug-nodes
 - core:deactivate-selected-debug-nodes

Adds a new httpAdmin route - /debug/(enable/disable) - that can be
use to bulk enable/disable nodes via HTTP Post.
2020-05-27 12:20:23 +01:00
Nick O'Leary
95d1b7bc36 Merge branch 'dev' into pr_2570 2020-05-27 11:52:37 +01:00
Nick O'Leary
d4ae0b0a2e Merge pull request #2576 from kazuhitoyokoi/dev-addjapanesetranslations
Update Japanese translations for trigger, tcp request, debug nodes
2020-05-27 10:26:42 +01:00
Nick O'Leary
36739fb444 Merge pull request #2577 from node-red-hitachi/update-function-message-jp
Update Japanese message catalogue for function node
2020-05-27 10:26:25 +01:00
Nick O'Leary
7906c28abb Merge pull request #2579 from ristomatti/bug/editor-underscore-hidden
Fix editor underscore visibility on Linux systems
2020-05-27 10:26:01 +01:00
Kazuhito Yokoi
f87b40941f Update Japanese translations for trigger, tcp request, debug nodes 2020-05-27 10:44:17 +09:00
Hiroyasu Nishiyama
05f816fc5d not emit change event on group delete 2020-05-25 08:46:35 +09:00
Ristomatti Airo
f9a157fe18 Fix editor underscore visibility on Linux systems
- seems to relate to DejaVu Sans font rendering
- fixes #2104
2020-05-23 18:41:44 +03:00
Hiroyasu Nishiyama
ca213589ac update Japanese message catalogue for function node 2020-05-23 21:39:52 +09:00
Hiroyasu Nishiyama
c5ca9fafee fix deletion of group 2020-05-23 21:20:23 +09:00
Nick O'Leary
82b3a97d99 Remove _info/type tests for subflow node tests 2020-05-22 21:23:55 +01:00
Nick O'Leary
1c94064c57 Remove unused _info/_type subflow env var magic values 2020-05-22 20:54:06 +01:00
Nick O'Leary
7969dd431f [function] Make the function node top-level async
This allows you to use 'await' in a function node without
having to wrap it in another promise/async function.
2020-05-22 20:49:18 +01:00
Nick O'Leary
22e7ddcb1d Merge branch 'dev' into pr_2490 2020-05-22 15:43:17 +01:00
Nick O'Leary
b1eafac67a Fixup IE11 Array.from polyfill 2020-05-22 15:31:38 +01:00
Nick O'Leary
5d81cec00c Merge branch 'pr_2498' into dev 2020-05-22 15:22:12 +01:00
Nick O'Leary
9512450d7c Reduce duplicated code in Function node html 2020-05-22 14:57:28 +01:00
Nick O'Leary
ed1998162f Fix gutter button position in outline tree 2020-05-21 23:05:29 +01:00
Nick O'Leary
ac2a21f992 Fixup positioning of create-project icons in startup dialog 2020-05-21 17:46:29 +01:00
Nick O'Leary
ad78ce0eb6 [projects] Allow remote branch dialog to create non-default remote branches 2020-05-21 17:26:27 +01:00
Nick O'Leary
8ce49c25d4 Ensure auth failure on project fetch identifies the remote
Fixes #2545
2020-05-21 17:25:51 +01:00
Nick O'Leary
4c24bd4ab9 [projects] Allow remote branch dialog to create non-default remote branches 2020-05-21 17:19:54 +01:00
Nick O'Leary
0de49e2a75 Ensure auth failure on project fetch identifies the remote
Fixes #2545
2020-05-21 17:18:46 +01:00
Nick O'Leary
05c3f459ad Add #! lines to project shell scripts
Fixes #2548
2020-05-21 15:33:10 +01:00
Nick O'Leary
50aaef5103 Make all dialogs handle smaller height screens better
Covers library, clipboard and project dialogs
2020-05-21 15:14:39 +01:00
Nick O'Leary
38872049fd Fix checkbox appearance on status/complete/catch/link nodes 2020-05-21 10:39:49 +01:00
Nick O'Leary
5dc1cc54d5 Add basic Array.from polyfill for IE11 2020-05-21 10:26:24 +01:00
Nick O'Leary
57f0fbbb98 Add some more trap form elements to workaround Chrome autofill 2020-05-21 10:21:18 +01:00
Nick O'Leary
977fef03b0 Merge pull request #2572 from jeancarl/dev
Moved options property from Outputs to Inputs section
2020-05-20 13:47:54 +01:00
Nick O'Leary
7d67e6a276 [outliner] handle items being added out-of-order
Closes #2573
2020-05-20 12:37:19 +01:00
Nick O'Leary
0832be5970 Merge pull request #2574 from node-red-hitachi/fix-grunt-error
add variable declaration to prohibit jshint error
2020-05-20 11:38:56 +01:00
Hiroyasu Nishiyama
2343fbd86a add variable declaration to prohibit jshint error 2020-05-20 13:47:56 +09:00
JeanCarl Bisson
367ebc1dd4 Moved options property from Outputs to Inputs section 2020-05-19 20:31:02 -07:00
Nick O'Leary
15cc88de6c [info-sidebar] Handle node/group/flows with \\n in their name 2020-05-19 17:53:20 +01:00
cinhcet
64b3c11682 debug nodes in subflows are ignored and changed name of callback to callback 2020-05-19 18:00:03 +02:00
Nick O'Leary
b8784185e8 Merge pull request #2568 from node-red-hitachi/fix-line-break-of-group-name
fix line break of group label
2020-05-19 15:09:06 +01:00
Nick O'Leary
fdc721baa1 Merge pull request #2569 from node-red/node-labels
Add action to toggle node label visiblity
2020-05-19 14:43:54 +01:00
Nick O'Leary
03b64bc493 Merge pull request #2564 from node-red/debugStatus
Let debug node show status indpendent of main output
2020-05-19 14:41:52 +01:00
cinhcet
a6a781f67c fix debug undo/redo by introducing a sideEffectCallback in history object 2020-05-19 13:51:08 +02:00
Nick O'Leary
fe1f8ca0a8 Delay when nodes are added to internal model on import
Closes #2567

This ensures when the node:added event fires, all possible
changes have already been applied such as remapping node ids.

This avoids the need to emit a separate node:changed event.
2020-05-19 11:28:38 +01:00
Dave Conway-Jones
a600feb5de Move debug status text length check to just before dsiplay. 2020-05-19 10:57:33 +01:00
Nick O'Leary
1f2c0a78c2 Only refresh sidebar on tab edit if nothing else selected 2020-05-19 10:13:35 +01:00
Nick O'Leary
e4b9c6a2ee Merge pull request #2571 from node-red-hitachi/fix-delete-tab
Fix error on deleting tab
2020-05-19 10:06:49 +01:00
cinhcet
a69db4d572 move to debug.html, rename to "deactivate" instead of "disable" 2020-05-19 11:03:15 +02:00
Hiroyasu Nishiyama
12c92072d0 not update sidebar for deleted tab 2020-05-19 09:27:50 +09:00
Nick O'Leary
e674d9246b [treeList] Ensure removed item is also removed from selected set 2020-05-19 00:15:51 +01:00
cinhcet
b71f81af57 added editor action to disable all debug nodes on a global/current workspace level 2020-05-18 22:49:10 +02:00
Nick O'Leary
b3535281ef Add action to toggle node label visiblity 2020-05-18 21:08:01 +01:00
Hiroyasu Nishiyama
5f5e6ea845 fix error on empty label 2020-05-17 11:44:23 +09:00
Dave Conway-Jones
64d2e80690 Merge branch 'dev' of https://github.com/node-red/node-red into dev 2020-05-16 22:24:38 +01:00
Dave Conway-Jones
b6e0568e76 Trigger node - hide second outpiut option when not appropriate
Update status to better reflect multiple streams in flight
2020-05-16 22:24:29 +01:00
Nick O'Leary
dca5b3b2a0 Merge pull request #2566 from node-red-hitachi/fix-outliner-subflow
Fix outliner display of newly created subflow
2020-05-16 21:17:56 +01:00
Hiroyasu Nishiyama
243915516e fix line break of group label 2020-05-16 20:56:21 +09:00
Hiroyasu Nishiyama
bc3683d8f6 fix outliner for subflow addition 2020-05-16 11:25:55 +09:00
Dave Conway-Jones
1d36ce0fdf debug node: add auto handling of error and status msgs if set to show status 2020-05-15 23:32:27 +01:00
Dave Conway-Jones
88d4d306f3 Add some colour smarts to debug status 2020-05-15 16:06:34 +01:00
Dave Conway-Jones
184d928cf7 ensure debug status in sync with main option 2020-05-14 23:01:26 +01:00
Nick O'Leary
fbd911ed27 [outliner] Keep outliner selection in sync with workspace 2020-05-14 22:08:25 +01:00
bartbutenaers
dec3762b7a Remove debugger statement 2020-05-14 22:43:50 +02:00
Dave Conway-Jones
a849872c21 ensure old config work with new fields 2020-05-14 16:28:38 +01:00
Dave Conway-Jones
1d71fb3554 Let debug node show status indpendent of main output 2020-05-14 15:38:48 +01:00
bartbutenaers
0d3bf0cd00 Https refresh settings 2020-05-13 23:49:30 +02:00
bartbutenaers
6c766eba86 Logs internationalisation 2020-05-13 23:46:33 +02:00
bartbutenaers
cc760acb62 Update packages/node_modules/node-red/red.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2020-05-13 23:24:57 +02:00
bartbutenaers
f4d4bf8779 Update packages/node_modules/node-red/red.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2020-05-13 23:24:40 +02:00
bartbutenaers
90f62e5e4a Update packages/node_modules/node-red/red.js
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2020-05-13 23:23:29 +02:00
Nick O'Leary
f1bd3e1711 Merge pull request #2562 from kazuhitoyokoi/dev-addjapanesetranslations
Add Japanese translations for Outliner, help sidebar and loading progress bar
2020-05-13 09:18:50 +01:00
Nick O'Leary
01dde8bea5 Merge pull request #2563 from kazuhitoyokoi/dev-fixgroping
Fix description of grouping nodes
2020-05-13 08:54:19 +01:00
Kazuhito Yokoi
341c66a199 Fix description of grouping nodes 2020-05-13 12:32:02 +09:00
Nick O'Leary
bc1fb2770b [groups] Change style of disabled groups 2020-05-12 13:53:20 +01:00
Nick O'Leary
9f1373945b [help-sidebar] Tidy up some errors 2020-05-12 13:42:01 +01:00
Kazuhito Yokoi
266ee2ca81 Add Japanese translations for Outliner 2020-05-12 20:06:07 +09:00
Kazuhito Yokoi
35738cc1a3 Update Japanese translations for CSV node 2020-05-12 20:03:00 +09:00
Nick O'Leary
ff310f89bd [groups] Support RED.view.reveal(group-id) 2020-05-12 10:59:41 +01:00
Hiroyasu Nishiyama
2dd004f6cd rename example name of complete node 2020-05-12 15:56:35 +09:00
Hiroyasu Nishiyama
964b7e0e23 rename example name of status node 2020-05-12 15:53:59 +09:00
Hiroyasu Nishiyama
bc039bde81 rename example name of catch node 2020-05-12 15:52:01 +09:00
Hiroyasu Nishiyama
9505f82d9b split debug node examples 2020-05-12 15:43:28 +09:00
Kazuhito Yokoi
9189db5531 Add Japanese translations for Outliner, help sidebar and loading progress bar 2020-05-12 11:06:29 +09:00
bartbutenaers
bfa5f39b6d Asynchronous https support 2020-05-11 23:33:54 +02:00
bartbutenaers
15f97bbf26 Asynchronous https support 2020-05-11 23:29:38 +02:00
Nick O'Leary
90ba761325 Merge pull request #2555 from node-red/authMiddleware
Add httpAdminMiddleware to allow custom headers on admin routes
2020-05-11 16:28:07 +01:00
Nick O'Leary
ddd428f76e Merge pull request #2558 from node-red/progress-bar
Add a loading progress bar
2020-05-11 16:27:40 +01:00
Nick O'Leary
0c83fa7060 Add loading progress bar 2020-05-11 16:27:22 +01:00
Nick O'Leary
f2e2c7e4d0 Merge pull request #2556 from node-red/outliner
Add Outliner to Info sidebar and add help sidebar
2020-05-11 16:26:41 +01:00
Nick O'Leary
717bfffa63 [Inject] Use legacy properies by preference 2020-05-11 16:07:26 +01:00
Hiroyasu Nishiyama
a764a4a44b update initial contents for setup & close code 2020-05-11 22:55:07 +09:00
Dave Conway-Jones
247fa0ce7c Fix inject so more backwards compatible
reuse old payload property and copy over topic if a string.
2020-05-11 14:37:19 +01:00
Nick O'Leary
13932b2cfb Merge pull request #2553 from node-red-hitachi/add-reset-to-batch-node
Add reset feature to batch node
2020-05-11 09:39:09 +01:00
Nick O'Leary
0bd0540d2f Merge pull request #2559 from kazuhitoyokoi/dev-addjapanesetranslations
Add Japanese translations for grouping nodes
2020-05-11 09:38:14 +01:00
Nick O'Leary
9a17cc503c Merge pull request #2561 from node-red-hitachi/inject-node-error-handling
Update inject node error handling
2020-05-11 09:37:43 +01:00
Dave Conway-Jones
89a048e5fa add docker to environment list 2020-05-11 09:01:35 +01:00
Nick O'Leary
88bc022e2a [help-sidebar] hide toc when directly setting content 2020-05-11 09:00:12 +01:00
Hiroyasu Nishiyama
00e080459e update handling of invalid jsonata expression 2020-05-11 14:51:47 +09:00
Hiroyasu Nishiyama
5b197adf33 update according to comments 2020-05-11 14:37:14 +09:00
Kazuhito Yokoi
9019c31f91 Add Japanese translations for core nodes 2020-05-08 15:12:47 +09:00
Kazuhito Yokoi
2e14703b16 Add Japanese translations for grouping nodes 2020-05-08 15:01:39 +09:00
Nick O'Leary
f87698438d [outliner] Handle switching projects properly 2020-05-07 21:48:47 +01:00
Nick O'Leary
4af1cf1d1f [help-sidebar] Refresh help on node selection 2020-05-07 15:19:56 +01:00
Nick O'Leary
d6ad7dc6eb Add show-examples-import-dialog action 2020-05-07 13:46:18 +01:00
Nick O'Leary
f25e4ea520 [help-sidebar] Include subflow help in sidebar 2020-05-07 12:34:15 +01:00
Nick O'Leary
17891d373b [outliner] Fix positioning of tips box 2020-05-07 10:32:25 +01:00
Nick O'Leary
9f29149d87 [help-sidebar] Add help sidebar 2020-05-06 16:15:12 +01:00
Nick O'Leary
010e20989a [popover] Allow hover-type popovers to contain buttons 2020-05-06 16:12:07 +01:00
Hiroyasu Nishiyama
c885f2edaa add example of link node across tabs 2020-05-06 12:36:28 +09:00
Hiroyasu Nishiyama
ae5a7176ba change comment of debug node example 2020-05-06 12:36:05 +09:00
Hiroyasu Nishiyama
ee13cd10fe add checks for interval value 2020-05-06 11:21:58 +09:00
Nick O'Leary
b0f9bf2c62 Add httpAdminMiddleware for admin routes 2020-05-05 18:13:21 +01:00
Nick O'Leary
9fbfc3d677 Merge branch 'dev' into outliner 2020-05-05 17:47:59 +01:00
Nick O'Leary
189389f96a [inject] Tidy up node label 2020-05-05 17:35:30 +01:00
Nick O'Leary
2af7066512 Merge branch 'dev' into outliner 2020-05-05 15:11:35 +01:00
Hiroyasu Nishiyama
9cbc40a229 fix message catalogue for CSV ndoe & update japanese message catalogue (#2554) 2020-05-05 14:43:08 +01:00
Nick O'Leary
18bf220ca4 Merge pull request #2413 from dvv/patch-1
Allow to know particular session from status node
2020-05-05 14:42:26 +01:00
Hiroyasu Nishiyama
8750c4b121 add reset feature to batch node 2020-05-05 21:07:55 +09:00
Dave Conway-Jones
417d2cb40a Add nodejs14 to Travis test matrix 2020-05-04 21:48:34 +01:00
Dave Conway-Jones
36b0698432 Trigger - redo second output code update 2020-05-04 17:11:09 +01:00
Nick O'Leary
0edc57f0e3 Merge pull request #2547 from node-red-hitachi/fix-project-menu-item-activation
Activate project menu after initial clone
2020-05-04 16:14:42 +01:00
Nick O'Leary
3d76137247 [inject] Modify output labels for multi-value inject 2020-05-04 15:37:09 +01:00
Dave Conway-Jones
df9d231389 Merge branch 'dev' of https://github.com/node-red/node-red into dev 2020-05-04 14:17:17 +01:00
Dave Conway-Jones
e2aebaf0e7 CSV : add warn when unpaired quotes detected on input.
helps handling now that we allow line breaks within fields (as per spec).
2020-05-04 14:17:11 +01:00
Nick O'Leary
20e84a847a Merge pull request #2435 from PaulWieland/dev
Adding user definable properties to inject node
2020-05-04 14:02:10 +01:00
Nick O'Leary
ad4779e32f Merge pull request #2436 from node-red/add-trigger-second-output
Add second output to trigger node
2020-05-04 12:48:25 +01:00
Nick O'Leary
90537e42ba Merge branch 'dev' into add-trigger-second-output 2020-05-04 12:45:01 +01:00
Nick O'Leary
4615465599 Merge pull request #2527 from node-red/enhance-csv
Enhance csv to allow output of column headers once only
2020-05-04 12:43:16 +01:00
Nick O'Leary
95418724fa Merge pull request #2540 from vladimir-kazan/fix-deprecation-warning
Fix: Remove nodejs deprecation warning in 21-httpin node
2020-05-04 12:42:30 +01:00
Nick O'Leary
989cb05257 Merge pull request #2544 from kazuhitoyokoi/master-fixuitest
Fix test cases for UI testing
2020-05-04 12:41:30 +01:00
Nick O'Leary
d7df20413d Merge branch 'master' into dev 2020-05-04 11:41:44 +01:00
bartbutenaers
f7e0f55c13 httpsRefreshInterval in seconds 2020-05-02 22:24:04 +02:00
bartbutenaers
e16f48c9fd httpsRefreshInterval in seconds 2020-05-02 22:22:36 +02:00
bartbutenaers
4694644043 Refresh interval in milliseconds 2020-05-02 14:41:46 +02:00
bartbutenaers
f468d6e947 Rename fix 2020-05-02 14:40:01 +02:00
bartbutenaers
9a19477796 Refresh https settings 2020-05-02 07:54:58 +02:00
bartbutenaers
00d41c6de2 Refresh https settings 2020-05-02 07:52:20 +02:00
Nick O'Leary
fc2a9a85ff [outline] Reveal selected item after clearing outline filter 2020-05-01 17:51:44 +01:00
Nick O'Leary
78c86880e4 [outline] Update information section of info sidebar 2020-05-01 17:39:54 +01:00
Nick O'Leary
aca61c0354 Modify RED.panels to use flexbox position 2020-05-01 17:38:23 +01:00
Nick O'Leary
73dde4de51 Allow node edit dialog to be opened on a non-default tab 2020-05-01 17:37:42 +01:00
Nick O'Leary
597c4a2e4f Add createNodeIcon and getDarkerColor to RED.utils 2020-05-01 17:37:15 +01:00
Hiroyasu Nishiyama
62ec7f4d37 add examples of common category nodes 2020-05-02 00:18:24 +09:00
Hiroyasu Nishiyama
319c7e9e9f add join node example 2020-05-01 16:49:17 +09:00
Hiroyasu Nishiyama
580492b0c8 create sequence category 2020-05-01 10:39:52 +09:00
Hiroyasu Nishiyama
655ce7b87a add split node example 2020-05-01 10:37:47 +09:00
Hiroyasu Nishiyama
4e09b404a2 fix comment description of sort sequence example 2020-05-01 09:55:38 +09:00
Hiroyasu Nishiyama
748f831495 rename examples & correct sequence size 2020-05-01 09:48:31 +09:00
Hiroyasu Nishiyama
bb3b87814c add sort node examples 2020-05-01 09:24:29 +09:00
Hiroyasu Nishiyama
0bfe20182f rename batch examples 2020-04-30 23:55:22 +09:00
Hiroyasu Nishiyama
4245c0a0ad activate project menu after initial clone 2020-04-30 12:59:10 +09:00
Paul Wieland
25aadc690a Added i18n and legacy output label support 2020-04-27 12:16:20 -04:00
Nick O'Leary
12dc4ab1fa [outline] Connect search dialog to outline filter box 2020-04-27 15:23:39 +01:00
Nick O'Leary
55a5917282 [search] Refactor search to use editor events to generate index 2020-04-27 14:43:22 +01:00
Nick O'Leary
a5b33d11fc [outline] Add outline section to info sidebar 2020-04-27 11:17:19 +01:00
Nick O'Leary
d2d872f51c TreeList updates for the outliner sidebar
All data items now get their `item.treeList` api added even if deferBuild is set.
This means the apis can be used regardless of whether the tree has built their
ui pieces.

Also adds a number of new api calls

Top-level methods:

 - clearSelection - clears selection from the list
 - filter(filterFunc) - filters the tree using the provided function

Data item functions:

 - item.treeList.sortChildren(sortFunction)
 - item.treeList.replaceElement(element)
2020-04-27 11:14:47 +01:00
Nick O'Leary
5c0b500f48 Reorder group creation so groups:add is fired before nodes:change 2020-04-27 11:06:28 +01:00
Nick O'Leary
28418288e3 Allow RED.notify.popover to have a position offset 2020-04-27 11:05:32 +01:00
Nick O'Leary
0150769c17 EditableList api calls must not return nested list items 2020-04-27 11:04:41 +01:00
Nick O'Leary
2eaea02489 Make selected list item more distinct 2020-04-27 11:04:04 +01:00
Nick O'Leary
1a9c4b7714 All node button to be clicked via api call 2020-04-27 11:03:43 +01:00
Nick O'Leary
d9f710aa52 Only update disabled workspace css if it is the active ws 2020-04-27 11:03:02 +01:00
Nick O'Leary
2069cc4392 Add flows:reorder event 2020-04-27 10:49:54 +01:00
Nick O'Leary
f78be9050a Reorder inital load so projects:load event emits before any nodes:add 2020-04-27 10:49:14 +01:00
Nick O'Leary
feb5d13e1c Bump for 1.0.6 2020-04-24 13:55:34 +01:00
Nick O'Leary
a3b0448f53 Handle clone of null in utils
Fixes #2536
2020-04-24 13:54:49 +01:00
Nick O'Leary
3dfbefb9f5 Handle error objects when reporting in palette manager 2020-04-24 13:54:49 +01:00
Nick O'Leary
9f6bac1b1b Revert to cron 1.7.2
See https://github.com/kelektiv/node-cron/issues/478
2020-04-24 13:54:49 +01:00
Nick O'Leary
0f2ed14d16 Update to JSONata 1.8.3 2020-04-24 13:54:49 +01:00
Paul Wieland
3e898c487a Corrected output label logic 2020-04-22 15:13:11 -04:00
Nick O'Leary
efb9dce92f Merge pull request #2543 from node-red/editor-events
Add more consistent events in the editor
2020-04-22 13:51:36 +01:00
Kazuhito Yokoi
f024e0bbed Fix test cases for UI testing 2020-04-21 21:58:18 +09:00
Dave Conway-Jones
3f1bb6771a Dont try and clone properties of a null object 2020-04-21 11:14:11 +01:00
Dave Conway-Jones
0b3ced5203 add test for cr lf in input and enhance odd quotes tests 2020-04-21 10:58:36 +01:00
Nick O'Leary
373267c53b Add more consistent events in the editor
This introduces a much more consistent set of events within the editor
for whenever a element is added, removed or modified.

The events emited on the `RED.events` event system. The event names
take the form: `"<thing>:<action>"`.

`<thing>` can be one of:
 - nodes
 - flows
 - subflows
 - groups
 - links

`<action>` can be one of:
 - add
 - remove
 - change

The payload of the events is the object in question.

There is also:
 - flows:reorder    - when tabs are reordered. Payload is array of flow ids.
 - workspace:clear  - when the workspace is emptied - part of switching projects

The `nodes:change` event was already used by RED.nodes.dirty() to cause
the Deploy button to become active. This renames that event to:
 - workspace:dirty  - Payload is boolean flag for the dirty state

This commit also updates the Palette to use the subflows:change event to
only redraw subflows that have actually changed rather than refresh them
all whenever one of them *might* have changed. This removes a noticable
flicker of the icon which was needlessly being redrawn.
2020-04-20 22:23:34 +01:00
Nick O'Leary
ae3e250269 Merge branch 'dev' of github.com:node-red/node-red into dev 2020-04-20 21:57:46 +01:00
Vladimir Kuznetsov
33200b2d08 Fix: Remove nodejs deprecation warning in 21-httpin node 2020-04-15 15:39:59 +02:00
Nick O'Leary
b032e00d01 [groups] increase group border radius 2020-04-14 22:39:42 +01:00
Dave Conway-Jones
bc96f2d0cb udp node: when reusing input socket honour the broadcast mode. 2020-04-11 22:33:11 +01:00
Hiroyasu Nishiyama
c649e1b4a2 update promise & message handling 2020-04-10 23:06:43 +09:00
Nick O'Leary
f54ed8ebd1 Prevent button label wrapping in typedInput 2020-04-09 20:20:52 +01:00
Nick O'Leary
b82167fefa Bump for 1.0.5 2020-04-09 14:15:46 +01:00
Paul Wieland
2efc2bc186 Update 20-inject.html
Scroll the div down automatically when the user changes the repeat drop down.
2020-04-08 13:37:51 -04:00
Nick O'Leary
f572c11912 Bump dependencies 2020-04-08 17:43:32 +01:00
Paul Wieland
4595a77c41 tip removed from inject node, cleanup i18n 2020-04-08 12:30:13 -04:00
Paul Wieland
7c1853431a Update 20-inject.html
Cleanup old payload, topic & type.
Move name and remove tip.
2020-04-08 12:29:55 -04:00
Nick O'Leary
e26eb85718 Fine tune typedInput flexbox handling on option-button 2020-04-08 17:06:11 +01:00
Nick O'Leary
821b5686f2 Merge branch 'master' into pr_2492 2020-04-08 12:42:33 +01:00
Nick O'Leary
c989f466ed Update changelog 2020-04-08 12:38:49 +01:00
Nick O'Leary
97c771f93a Ensure file context does not write 'undefined' to store
Fixes #2522
2020-04-08 11:32:39 +01:00
Nick O'Leary
54dbdde9cb Merge pull request #2532 from martinLim45/master
Set flow.disabled when disabled property is false
2020-04-07 10:05:36 +01:00
martinLim45
513957eea1 Set flow.disabled when disabled property is false 2020-04-07 16:41:49 +09:00
Dave Conway-Jones
5eed4672ed rtrigger node - reapply - passing topic through to output fix that seemed to only half merge 2020-04-06 22:58:00 +01:00
Nick O'Leary
aafa4fe0b9 Bump dev branch to 1.1.0 2020-04-06 20:29:22 +01:00
Nick O'Leary
572c03631d Do not collapse whitespace in Debug string messages 2020-04-06 15:40:06 +01:00
Nick O'Leary
2f869a55e2 Handle nodes with no wires array 2020-04-06 15:39:48 +01:00
Hiroyasu Nishiyama
161f6090c1 update initialize & finalize processing of function node 2020-04-06 16:34:41 +09:00
Nick O'Leary
efad7270b7 Add polyfills for IE11 2020-04-03 16:57:15 +01:00
tmdoit
4f31632863 Fix: Allow CR and LF control chars to be a part of the value (#2526)
To properly parse CSV data.
2020-04-03 15:10:33 +01:00
Dave Conway-Jones
1d417c07cd TCP out - tidy up select of which rows to display
to help address #2525
2020-04-03 11:14:23 +01:00
Nick O'Leary
344c9fe57e Merge branch 'master' into dev 2020-04-02 23:24:42 +01:00
Nick O'Leary
9d4400349b Fix timer reference in node close handling 2020-04-02 23:24:18 +01:00
Nick O'Leary
24f7000918 [groups] Remove padStart because IE11 2020-04-02 23:23:41 +01:00
Nick O'Leary
6ff3286d78 Merge branch 'master' into dev 2020-04-02 16:52:55 +01:00
Nick O'Leary
f058de8bcd Update TypedInput to use flexbox and remove resizing code 2020-04-02 16:49:58 +01:00
Nick O'Leary
a6ecb54cc4 Clear node.close timeout to avoid unnecessary work on restart 2020-03-31 19:25:20 +01:00
Kazuhito Yokoi
08ef9ee682 Add backslash handling to library 2020-03-16 21:58:28 +09:00
Hiroyasu Nishiyama
134c68c98e merge origin 2020-03-07 19:22:12 +09:00
Hiroyasu Nishiyama
82539fc420 update for merging settings object & better error handling 2020-03-07 19:19:48 +09:00
Hiroyasu Nishiyama
7a5604697f Update packages/node_modules/node-red/red.js
Co-Authored-By: Nick O'Leary <nick.oleary@gmail.com>
2020-03-07 16:38:24 +09:00
Hiroyasu Nishiyama
84d2b8ad6d add support of initialization & finalization to function node 2020-03-07 01:55:45 +09:00
Thierry Le Gal
dea47a6e3d Improve performance in change node panel 2020-03-03 18:43:44 +01:00
Thierry Le Gal
7621cf3377 Merge pull request #1 from node-red/master
Refresh on node-red github
2020-03-03 18:36:23 +01:00
Kazuhito Yokoi
6675fdf3c2 Saving the node description property to the library 2020-03-02 05:50:32 +00:00
Ben Hardill
7723ff461b Remove console.logs 2020-02-26 19:46:54 +00:00
Ben Hardill
0ca36a89e3 Updates to match Nick's suggestions 2020-02-26 19:45:01 +00:00
Ben Hardill
37bcd5c603 First pass at adding support for GET requests
with a body
2020-02-25 21:28:15 +00:00
Hiroyasu Nishiyama
c0d007ffa9 add option support for overwriting settiings.js 2020-02-16 23:07:05 +09:00
Dave Conway-Jones
127b361979 change PR to only use a single property for the 2nd output 2020-02-14 20:13:37 -05:00
Dave Conway-Jones
b2f53a183e rename BreakingExit call
(undo Brexit :-)
2020-02-05 13:58:45 +00:00
Dave Conway-Jones
0622be843b Add catcher for PM2 graceful shutdown 2020-02-04 13:42:34 +00:00
Dave Conway-Jones
fcf757f715 catch mode signals to allow clean context flush on shutdown
(yes the name is intentionally ironic)
Code pattern copied from https://nodejs.org/api/process.html#process_signal_events
2020-01-31 18:11:58 +00:00
Dave Conway-Jones
88e729664a complete tidy up of trigger node
remove unnecessary console.log
2020-01-31 17:56:06 +00:00
Dave Conway-Jones
87aacb4270 change property name to leave space if we want to also do main payload property 2020-01-30 22:20:55 +00:00
Dave Conway-Jones
3f756aac21 Allow trigger node to use other than msg.topic to separate streams
and add test
2020-01-30 21:39:34 +00:00
Dave Conway-Jones
d5d9ac5c76 let setMessageProperty return success flag
so calling node can warn if operation tries to overwrite primitive type
2020-01-26 18:20:25 +00:00
Dave Conway-Jones
bb12ec702a Add second output to trigger node
and add tests
2020-01-24 18:20:14 +00:00
Paul Wieland
82490b0a58 Implemented RED.util.setMessageProperty 2020-01-23 11:23:02 -05:00
Paul Wieland
2cbf625483 Removing form-row label. 2020-01-23 10:56:31 -05:00
Paul Wieland
44f2a986a2 Update messages.json
This label is used for the user definable properties form-row. The word properties is duplicated with the tab description, but it best descrbies the form-rows content. If another name is chosen, this entry can be deleted.
2020-01-23 08:56:55 -05:00
Paul Wieland
c3df1c6cde Add support for user definable properties to inject node 2020-01-23 08:55:50 -05:00
Vladimir Dronnikov
fe0d4f08f3 Allow to know particular session from status node
The rationale is to keep own list of active sessions.
As a workaround for https://discourse.nodered.org/t/tcp-connection-pool-better-separation/19432
TIA
2019-12-25 06:21:55 +03:00
251 changed files with 8104 additions and 3924 deletions

View File

@@ -32,3 +32,4 @@ To help us understand the issue, please fill-in as much of the following informa
- [ ] npm version:
- [ ] Platform/OS:
- [ ] Browser:
- [ ] running in Docker:

View File

@@ -0,0 +1,29 @@
const fs = require("fs");
const newVersion = require("../../package.json").version;
if (process.env.GITHUB_REF !== "refs/tags/"+newVersion) {
console.log(`GITHUB_REF doesn't match the package.json version: ${process.env.GITHUB_REF} !== ${newVersion}`);
process.exit(0);
}
if (!/^\d+\.\d+\.\d+$/.test(newVersion)) {
console.log(`Not updating for a non-stable release - ${newVersion}`);
process.exit(0);
}
const currentVersion = require("../../../node-red-docker/package.json").version;
console.log(`Update from ${currentVersion} to ${newVersion}`)
updateFile(__dirname+"/../../../node-red-docker/package.json", currentVersion, newVersion);
updateFile(__dirname+"/../../../node-red-docker/docker-custom/package.json", currentVersion, newVersion);
updateFile(__dirname+"/../../../node-red-docker/README.md", currentVersion, newVersion);
console.log(`::set-env name=newVersion::${newVersion}`);
function updateFile(path,from,to) {
let contents = fs.readFileSync(path,"utf8");
contents = contents.replace(new RegExp(from.replace(/\./g,"\\."),"g"), to);
fs.writeFileSync(path, contents);
}

40
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: PublishDockerImage
on:
release:
types: [published]
jobs:
generate:
name: 'Update node-red-docker image'
runs-on: ubuntu-latest
steps:
- name: Check out node-red repository
uses: actions/checkout@v2
with:
path: 'node-red'
- name: Check out node-red-docker repository
uses: actions/checkout@v2
with:
repository: 'node-red/node-red-docker'
path: 'node-red-docker'
- uses: actions/setup-node@v1
with:
node-version: '12'
- run: node ./node-red/.github/scripts/update-node-red-docker.js
id: updateFiles
- name: Create Pull Request
uses: peter-evans/create-pull-request@v2
with:
token: ${{ secrets.NR_REPO_TOKEN }}
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
path: 'node-red-docker'
commit-message: 'Bump to ${{ env.newVersion }}'
title: '🚀 Update to Node-RED ${{ env.newVersion }} release'
body: |
Updates the Node-RED Docker repo for the ${{ env.newVersion }} release.
Once this is merged, you will need to create a new release with the tag `v${{ env.newVersion }}`.
This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary

View File

@@ -1,11 +1,15 @@
sudo: false
addons:
chrome: stable
language: node_js
matrix:
include:
- node_js: "14"
- node_js: "12"
- node_js: "10"
script:
- ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
- scripts/install-ui-test-dependencies.sh && grunt test-ui
before_script:
- npm install -g istanbul coveralls
- node_js: "8"

View File

@@ -1,3 +1,290 @@
### 1.1.2: Maintenance Release
Editor
- Fix all the touch screen issues Fixes #2647
- Add RED.view.redrawStatus to avoid full redraw on update
- Ensure node/group xrefs are consistent on import
- Disable keyboard handler when dialogs are open
- Ensure unknown nodes removed from outliner when node registers Fixes #2646
Runtime
- Allow Comms websocket auth to be done via token header Fixes #2642
### 1.1.1: Maintenance Release
Editor
- Set apiRootUrl for debug pop-out to load locales properly Fixes #2629, #2630
- Update build-custom-theme to handle keyframes properly Fixes #2636
- Remove hardcoded css and allow group to default from theme Fixes #2633
- Add RED.view.DEBUG_SYNC_REDRAW to disable requestAnimationFrame References #2631
- Fix up subflow port wiring
- Ensure groups are removed when deleting subflows
- Get group order right in history events to ensure proper handling
- Prevent wiring to node with no corresponding port Fixes #2641
- Avoid copying duplicate nodes to internal clipboard
- Fix connecting wires to subflow status or io ports on touchscreen Fixes #2637
Runtime
- Authenticate websocket comms using user-provided token if present Fixes #2642
Nodes
- Delay: add words about independence of messages being delayed.
- Debug: fix debug status to not loop, make migration more seamless, detect status type objects #2638
- Debug: Update Japanese message for debug node #2645 (@kazuhitoyokoi)
### 1.1.0: Milestone Release
Editor
- Align node labels on FF
- Fix node toggle button initial opacity
- Make color/icon/label-pos pickers keyboard navigable
- Default group label to be shown and improve toggle button
- Fix clearing group label
- Remove hardcoded css Fixes #2603
- Fix node button mouse pointer css
- Change node linebreak handling to use "\n "
- Handle import of node with non-default number of outputs
- Improve display of focussed form element
- Fix typedInput error on empty subflow input types #2624 (@HiroyasuNishiyama)
- Update JP message catalogue for subflow input type #2471 (@HiroyasuNishiyama)
- Outliner - add empty item when last config node moved
- Update zh-CN/zh-TW translations #2626 (@JiyeYu)
- Add default shortcut for `core:show-help-tab`
- Clear outline focus on config node sidebar panel
- Tweak group margin to fit node status and look better
- Fix reparenting nodes in outliner when they change
Runtime
- Add developer options - permits npm run build-dev #2628 (@Steve-Mcl)
Nodes
- Add example flows for lots of core nodes #2585 #2550 #2549 (@HiroyasuNishiyama)
- TCP: Fix tcp in node finishing packets when in streaming base64 receive mode.
- Join: Clear timeout when msg.reset received Fixes #2471
- Switch: JSONata expr does not require msg.parts.count
- Inject: fix backwards migration of inject without topic
#### 1.1.0-beta.3: Beta Release
Editor
- Fix wiring nodes from input back to output
- Fix sometimes unable to keyboard-move group to left/up
- Fix group position in outliner
- Handle unknown nodes with no icon
- Prevent node creep when switching tabs
#### 1.1.0-beta.2: Beta Release
Editor
- Add UI tests to travis build #2593 #2616 #2617 #2619 (@kazuhitoyokoi)
- Add Japanese translations for outliner, jsonata and runtime #2618 (@kazuhitoyokoi)
- Fix deleting node in group after changing selection
- Fixup padding of quick-add search box
- Move config nodes under type-level hierarchy in outline
- Emit nodes:change event for config node users list modified
- Increase group margin to avoid clash with status text
- Fix event order when quick-adding node to group
- Switch RED.events.DEBUG messages to warn to get stacktraces
- Fix empty item handling for subflows/config in outliner
- Fix search indexing of group nodes
- Avoid regenerating every node label on redraw
- Fix handling of multi-line node label
- Disable merge group menu for single item or non-group item #2611 (@HiroyasuNishiyama)
- Merge pull request #2609 from node-red-hitachi/fix-remove-from-group
- Fix position of empty group with multi-line label #2612 (@HiroyasuNishiyama)
- Make treelist of subflow/config nodes initially have empty placeholder
- Fix empty placeholder not shown on remove from group #2609 (@HiroyasuNishiyama)
- Prevent conversion of circular structure #2607 (@HiroyasuNishiyama)
- Handle null status text in the editor Fixes #2606
- Massively reduce our dependency on d3 to render the view
- EditableList/TreeList - defer adding elements to DOM
- Prevent RED.stop being called multiple times if >1 signal received
- Flag a node as removed when it is disabled
- Some performance improvements for TreeList
- Resize info/help sidebars whenever sidebar is opened
- Add search defaults to outliner searchBox
- Add search presets option to searchBox widget
- Add RED.popover.menu as a new type of menu widget
- Add support for is:XYZ search flags
- Track subflow instances on the subflow node itself
- Refresh outline filter whenever something changes Fixes #2601
- Fix Help tab search box appearance
- Rename Node Information to Information in sidebar
- Do a sync-redraw after clearing to ensure clean state
- Make catch/status/complete/link filter case-insensitive
- Add 'add' option to touch radialMenu for quick-add dialog
- Merge branch 'dev' of https://github.com/node-red/node-red into dev
- ensure trigger node detects changes to number of outputs
- Ignore whitespace when checking function setup/close code
- Preserve event handlers when moving outliner items
- Add tooltips to outliner buttons
- Only validate nodes once they have all been imported
- Ensure configNode.users is updated properly on import
Runtime
- Bump node-red-admin 0.2.6
Nodes
- WebSocket: Prevent charAt call on websocket listener #2610 ()
- Debug: fix status to migrate old nodes to correct default mode.
- Link: Fix Link node filter Fixes #2600
#### 1.1.0-beta.1: Beta Release
Runtime
- Allow HTTPS settings to be refreshed #2551 (@bartbutenaers)
- Add support for moment in JSONata expressions #2583 (@dxdc)
- Add httpAdminMiddleware for admin routes #2555
- Add admin api authentication function #2479 (@KazuhiroItoh)
- Add option support for overwriting settings.js #2463 (@HiroyasuNishiyama)
- Add support for credential-stored env var in subflow #2368
- Add node installation from other than public site #2378 (@KazuhiroItoh)
- Catch more signals to allow clean context flush on shutdown #2447
- Add `node-red admin` command #2592
- Move to `lodash.clonedeep` #2396 (@amodelbello)
- Tidy up unhandledRejection warning from context unit tests
- Add test cases for setMessageProperty with non-object properties
- Fix for settings.set subsequent updates #2584 (@sammachin)
- Turn off installer funding messages
- Remove unused \_info/\_type subflow env var magic values
- Add #! lines to project shell scripts #2548
- Add nodejs14 to Travis test matrix
- Remove duplicate NLS message #2516 (@alexk111)
- Let setMessageProperty return success flag #2439
Editor
- Add ability to group nodes #2493
- Add loading progress bar #2558
- Add Outliner to Info sidebar and add help sidebar #2556
- Add action to toggle node label visibility #2569
- Add show-examples-import-dialog action
- Add more consistent events in the editor #2543
- Save the node description property to the library #2490 (@kazuhitoyokoi)
- Add credential type to TypedInput #2367
- Scroll the view with WASD/Cursor keys when nothing selected #2381
- Bump jquery/migrate to latest versions
- Fix editor underscore visibility on Linux systems #2579 (@ristomatti)
- Support setting title on typedInput multi-option #2586 (@Steve-Mcl)
- Projects: Allow remote branch dialog to create non-default remote branches
- Ensure auth failure on project fetch identifies the remote #2545
- Make all dialogs handle smaller height screens better
- Add basic Array.from polyfill for IE11
- Add some more trap form elements to workaround Chrome autofill
- [info-sidebar] Handle node/group/flows with \n in their name
- [popover] Allow hover-type popovers to contain buttons
- Modify RED.panels to use flexbox position
- Allow node edit dialog to be opened on a non-default tab
- Add createNodeIcon and getDarkerColor to RED.utils
- [search] Refactor search to use editor events to generate index
- Allow RED.notify.popover to have a position offset
- Make selected list item more distinct
- Allow node button to be clicked via api call
- Reorder initial load so projects:load event emits before any nodes:add
- Add polyfills for IE11
- Activate project menu after initial clone #2547 (@HiroyasuNishiyama)
- Fix replacement of unknown node in workspace when module installed #2524 (@HiroyasuNishiyama)
- Fix appearance of subflow template panel #2506 (@HiroyasuNishiyama)
- Fix workspace CSS properties syntax #2487 (@bonanitech)
- Consolidate duplicate selectors #2488 (@bonanitech)
- Update message catalogue for subflow UI #2466 (@HiroyasuNishiyama)
Nodes
- Batch: Add reset feature to batch node #2553 (@HiroyasuNishiyama)
- Catch/Complete/Link/Status: #2588 Add compact searchBox to filter node lists
- Catch/Complete/Link/Status: Allow searchBox filter to filter on node type #2595 (@jeancarl)
- CSV: Add warn when unpaired quotes detected on input.
- CSV: allow node to only send headers once
- CSV: Allow CR and LF control chars to be a part of the value #2526 (@tmdoit)
- CSV: Add support for parsing empty strings and null values #2510 (@tmdoit)
- CSV: Update Japanese translations for CSV node #2562 (@kazuhitoyokoi)
- Debug: Add bulk-activate/deactive actions for debug node #2570 (@cinhcet)
- Debug: Show status independently of main output #2564
- Delay: Ensure delay node rate limit timer is cleared on reset
- Function: Make the function node top-level async
- Function: Add support of initialization & finalization to function node #2498 (@HiroyasuNishiyama)
- HTTP In: Remove nodejs deprecation warning #2540 (@vladimir-kazan)
- HTTP Request: Support sending body in GET requests #2478 (@hardillb)
- Inject: Adding user definable properties to inject node #2435 (@PaulWieland)
- TCP: Allow to know particular session from status node #2413 (@dvv)
- Trigger: Add optional second output
- Trigger: Ensure trigger sends complete 2nd msg if set to send latest msg
- Trigger: Allow trigger node to use other than msg.topic to separate streams
- XML: Moved XML options documentation property from Outputs to Inputs section #2572 (@jeancarl)
- Add some core node example flows #2455 (@HiroyasuNishiyama)
- Change types from text/x-red to text/html in node html files #2425 (@kazuhitoyokoi)
#### 1.0.6: Maintenance Release
Runtime
- Update to JSONata 1.8.3
- #2536 Handle clone of null in utils
Editor
- Prevent button label wrapping in typedInput
- Handle error objects when reporting in palette manager
Nodes
- Inject: Revert to cron 1.7.2
- UDP: when reusing input socket honour the broadcast mode.
#### 1.0.5: Maintenance Release
Runtime
- #2500 Support for context stores using JSONata and evaluateNodeProperty()
- Add better handling of host-key-verify error with projects
- #2517 Handle false values in $env() properly
- #2514 Ensure complete node scope is remapped in subflows
- #2513 Flows/subflows must preinitialise their context objects
- Clear node.close timeout to avoid unnecessary work on restart
- #2532 Set flow.disabled when disabled property is false
- #2522 Ensure file context does not write 'undefined' to store
Editor
- #2489 Fix XPath in UI tests
- #2504 Fix paletteCategories order
- #2501 Add page objects for UI testing
- #2494 Check node props when deciding if pasted node can splice links
- #2521 Don't double-sanitize node name in debug sidebar
- #2519 German i18n updates
- #2523 Update nodeTabMap when replacing unknown nodes
- Update TypedInput to use flexbox and remove resizing code
- Handle nodes with no wires array
- Do not collapse whitespace in Debug string messages
Nodes
- File: Remove old legacy wording from file node info to stop confusing users.
- Join: Ensure join node handles missing buffer joiner when not in string mode
- Exec: make exec node logging consistent with itself. (only be verbose when in verbose mode)
- Trigger: reset default timeout value when switching away from wait for reset
- Join: Fix join to not crash on appending invalid types to buffer.
- MQTT out: Add warning if topic contains + or #
- #2502 WebSocket i18n update
- #2508 Add Japanese translation for join node
- TCP out: tidy up select of which rows to display
#### 1.0.4: Maintenance Release
Runtime
@@ -63,7 +350,7 @@ Runtime
- #2332 Fix error handling of nodes with multiple input handlers
- Add script to generate npm publish script
- #2371 Ensure folder is present before write (e.g. flows file not in user folder)
- #2371 Handle windows UNC '\\' paths
- #2371 Handle windows UNC '\' paths
- #2366 Handle logging of non-JSON encodable objects
Editor

View File

@@ -125,6 +125,7 @@ module.exports = function(grunt) {
src: [
// Ensure editor source files are concatenated in
// the right order
"packages/node_modules/@node-red/editor-client/src/js/polyfills.js",
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
"packages/node_modules/@node-red/editor-client/src/js/red.js",
"packages/node_modules/@node-red/editor-client/src/js/events.js",
@@ -164,6 +165,8 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",
@@ -191,8 +194,8 @@ module.exports = function(grunt) {
vendor: {
files: {
"packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.4.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.0.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"node_modules/marked/marked.min.js",
@@ -620,6 +623,10 @@ module.exports = function(grunt) {
grunt.registerTask('build',
'Builds editor content',
['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']);
grunt.registerTask('build-dev',
'Developer mode: build dev version',
['clean:build','concat:build','concat:vendor','copy:build','sass:build','setDevEnv']);
grunt.registerTask('dev',
'Developer mode: run node-red, watch for source changes and build/restart',

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "1.0.4",
"version": "1.1.2",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -13,6 +13,8 @@
"start": "node packages/node_modules/node-red/red.js",
"test": "grunt",
"build": "grunt build",
"dev": "grunt dev",
"build-dev": "grunt build-dev",
"docs": "grunt docs"
},
"contributors": [
@@ -24,41 +26,43 @@
}
],
"dependencies": {
"ajv": "6.12.0",
"ajv": "6.12.3",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"cheerio": "0.22.0",
"clone": "2.1.2",
"content-type": "1.0.4",
"cookie": "0.4.0",
"cookie-parser": "1.4.4",
"cookie": "0.4.1",
"cookie-parser": "1.4.5",
"cors": "2.8.5",
"cron": "1.8.2",
"cron": "1.7.2",
"denque": "1.4.1",
"express": "4.17.1",
"express-session": "1.17.0",
"express-session": "1.17.1",
"fs-extra": "8.1.0",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
"https-proxy-agent": "5.0.0",
"i18next": "15.1.2",
"iconv-lite": "0.5.1",
"iconv-lite": "0.6.2",
"is-utf8": "0.2.1",
"js-yaml": "3.13.1",
"js-yaml": "3.14.0",
"json-stringify-safe": "5.0.1",
"jsonata": "1.8.1",
"jsonata": "1.8.3",
"lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0",
"memorystore": "1.6.2",
"mime": "2.4.4",
"mime": "2.4.6",
"moment-timezone": "^0.5.31",
"mqtt": "2.18.8",
"multer": "1.4.2",
"mustache": "4.0.0",
"node-red-node-rbe": "^0.2.6",
"mustache": "4.0.1",
"node-red-admin": "^0.2.6",
"node-red-node-rbe": "^0.2.9",
"node-red-node-sentiment": "^0.1.6",
"node-red-node-tail": "^0.1.0",
"nopt": "4.0.1",
"nopt": "4.0.3",
"oauth2orize": "1.11.0",
"on-headers": "1.0.2",
"passport": "0.4.1",
@@ -67,17 +71,17 @@
"raw-body": "2.4.1",
"request": "2.88.0",
"semver": "6.3.0",
"uglify-js": "3.8.0",
"uglify-js": "3.10.0",
"when": "3.7.8",
"ws": "6.2.1",
"xml2js": "0.4.23"
},
"optionalDependencies": {
"bcrypt": "3.0.6"
"bcrypt": "3.0.8"
},
"devDependencies": {
"marked": "0.8.0",
"dompurify": "2.0.8",
"marked": "0.8.2",
"dompurify": "2.0.12",
"grunt": "~1.0.4",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.3.2",
@@ -98,14 +102,14 @@
"grunt-npm-command": "~0.1.2",
"grunt-sass": "~3.1.0",
"grunt-simple-mocha": "~0.4.1",
"http-proxy": "1.18.0",
"http-proxy": "1.18.1",
"istanbul": "0.4.5",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"minami": "1.2.3",
"mocha": "^5.2.0",
"mosca": "^2.8.3",
"node-red-node-test-helper": "^0.2.3",
"node-sass": "^4.13.1",
"node-red-node-test-helper": "^0.2.5",
"node-sass": "^4.14.1",
"should": "^8.4.0",
"sinon": "1.17.7",
"stoppable": "^1.1.0",

View File

@@ -123,38 +123,57 @@ AnonymousStrategy.prototype.authenticate = function(req) {
});
}
function authenticateUserToken(req) {
return new Promise( (resolve,reject) => {
var token = null;
var tokenHeader = Users.tokenHeader();
if (Users.tokenHeader() === null) {
// No custom user token provided. Fail the request
reject();
return;
} else if (Users.tokenHeader() === 'authorization') {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
token = req.headers.authorization.split(' ')[1];
}
} else {
token = req.headers[Users.tokenHeader()];
}
if (token) {
Users.tokens(token).then(function(user) {
if (user) {
resolve(user);
} else {
reject();
}
});
} else {
reject();
}
});
}
function TokensStrategy() {
passport.Strategy.call(this);
this.name = 'tokens';
}
util.inherits(TokensStrategy, passport.Strategy);
TokensStrategy.prototype.authenticate = function(req) {
var self = this;
var token = null;
if (Users.tokenHeader() === 'authorization') {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
token = req.headers.authorization.split(' ')[1];
}
} else {
token = req.headers[Users.tokenHeader()];
}
if (token) {
Users.tokens(token).then(function(admin) {
if (admin) {
self.success(admin,{scope:admin.permissions});
} else {
self.fail(401);
}
});
} else {
self.fail(401);
}
authenticateUserToken(req).then(user => {
this.success(user,{scope:user.permissions});
}).catch(err => {
this.fail(401);
});
}
module.exports = {
bearerStrategy: bearerStrategy,
clientPasswordStrategy: clientPasswordStrategy,
passwordTokenExchange: passwordTokenExchange,
anonymousStrategy: new AnonymousStrategy(),
tokensStrategy: new TokensStrategy()
tokensStrategy: new TokensStrategy(),
authenticateUserToken: authenticateUserToken
}

View File

@@ -61,7 +61,7 @@ var api = {
authenticate: authenticate,
default: getDefaultUser,
tokens: getDefaultUser,
tokenHeader: "authorization"
tokenHeader: null
}
function init(config) {
@@ -111,6 +111,8 @@ function init(config) {
api.tokens = config.tokens;
if (config.tokenHeader && typeof config.tokenHeader === "string") {
api.tokenHeader = config.tokenHeader.toLowerCase();
} else {
api.tokenHeader = "authorization";
}
}
}

View File

@@ -21,6 +21,7 @@ var log = require("@node-red/util").log; // TODO: separate module
var Tokens;
var Users;
var Permissions;
var Strategies;
var server;
var settings;
@@ -44,6 +45,7 @@ function init(_server,_settings,_runtimeAPI) {
Tokens.onSessionExpiry(handleSessionExpiry);
Users = require("../auth/users");
Permissions = require("../auth/permissions");
Strategies = require("../auth/strategies");
}
function handleSessionExpiry(session) {
@@ -63,17 +65,18 @@ function generateSession(length) {
return token.join("");
}
function CommsConnection(ws) {
function CommsConnection(ws, user) {
this.session = generateSession(32);
this.ws = ws;
this.stack = [];
this.user = null;
this.user = user;
this.lastSentTime = 0;
var self = this;
log.audit({event: "comms.open"});
log.trace("comms.open "+self.session);
var pendingAuth = (settings.adminAuth != null);
var preAuthed = !!user;
var pendingAuth = !this.user && (settings.adminAuth != null);
if (!pendingAuth) {
addActiveConnection(self);
@@ -130,8 +133,16 @@ function CommsConnection(ws) {
}
});
} else {
log.audit({event: "comms.auth.fail"});
completeConnection(null,null,false);
Users.tokens(msg.auth).then(function(user) {
if (user) {
self.user = user;
log.audit({event: "comms.auth",user:self.user});
completeConnection(user.permissions,msg.auth,true);
} else {
log.audit({event: "comms.auth.fail"});
completeConnection(null,null,false);
}
});
}
});
} else {
@@ -191,8 +202,8 @@ function start() {
var commsPath = settings.httpAdminRoot || "/";
commsPath = (commsPath.slice(0,1) != "/" ? "/":"") + commsPath + (commsPath.slice(-1) == "/" ? "":"/") + "comms";
wsServer = new ws.Server({ noServer: true });
wsServer.on('connection',function(ws) {
var commsConnection = new CommsConnection(ws);
wsServer.on('connection',function(ws, request, user) {
var commsConnection = new CommsConnection(ws, user);
});
wsServer.on('error', function(err) {
log.warn(log._("comms.error-server",{message:err.toString()}));
@@ -201,8 +212,26 @@ function start() {
server.on('upgrade', function upgrade(request, socket, head) {
const pathname = url.parse(request.url).pathname;
if (pathname === commsPath) {
if (Users.tokenHeader() !== null && request.headers[Users.tokenHeader()]) {
// The user has provided custom token handling. For the websocket,
// the token could be provided in two ways:
// - as an http header (only possible with a reverse proxy setup)
// - passed over the connected websock in an auth packet
// If the header is present, verify the token. If not, use the auth
// packet over the connected socket
//
Strategies.authenticateUserToken(request).then(user => {
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit('connection', ws, request, user);
});
}).catch(err => {
log.audit({event: "comms.auth.fail"});
socket.destroy();
})
return
}
wsServer.handleUpgrade(request, socket, head, function done(ws) {
wsServer.emit('connection', ws, request);
wsServer.emit('connection', ws, request, null);
});
}
// Don't destroy the socket as other listeners may want to handle the

View File

@@ -59,6 +59,12 @@ function init(settings,_server,storage,runtimeAPI) {
});
adminApp.use(corsHandler);
if (settings.httpAdminMiddleware) {
if (typeof settings.httpAdminMiddleware === "function") {
adminApp.use(settings.httpAdminMiddleware)
}
}
auth.init(settings,storage);
var maxApiRequestSize = settings.apiMaxLength || '5mb';

View File

@@ -43,10 +43,16 @@ module.exports = {
rejectHandler: function(req,res,err) {
//TODO: why this when errorHandler also?!
log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.message||err.toString()},req);
res.status(err.status||400).json({
var response = {
code: err.code||"unexpected_error",
message: err.message||err.toString()
});
};
// Handle auth failures on a specific remote
// TODO: don't hardcode this here - allow users of rejectHandler to identify extra props to send
if (err.remote) {
response.remote = err.remote;
}
res.status(err.status||400).json(response);
},
getRequestLogObject: function(req) {
return {

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "1.0.4",
"version": "1.1.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,17 +16,17 @@
}
],
"dependencies": {
"@node-red/util": "1.0.4",
"@node-red/editor-client": "1.0.4",
"@node-red/util": "1.1.2",
"@node-red/editor-client": "1.1.2",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.17.0",
"express-session": "1.17.1",
"express": "4.17.1",
"memorystore": "1.6.2",
"mime": "2.4.4",
"mustache": "4.0.0",
"mime": "2.4.6",
"mustache": "4.0.1",
"oauth2orize": "1.11.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",

View File

@@ -15,10 +15,14 @@
"next": "Next",
"clone": "Clone project",
"cont": "Continue",
"style": "Style",
"line": "Outline",
"fill": "Fill",
"label": "Label",
"color": "Color",
"position": "Position"
"position": "Position",
"enable": "Enable",
"disable": "Disable"
},
"type": {
"string": "string",
@@ -32,6 +36,13 @@
"null": "null"
}
},
"event": {
"loadPalette": "Loading Palette",
"loadNodeCatalogs": "Loading Node catalogs",
"loadNodes": "Loading Nodes __count__",
"loadFlows": "Loading Flows",
"importFlows": "Adding Flows to workspace"
},
"workspace": {
"defaultName": "Flow __number__",
"editFlow": "Edit flow: __name__",
@@ -358,6 +369,7 @@
"locale": "Select UI Language",
"icon": "Icon",
"inputType": "Input type",
"selectType": "select types...",
"inputs" : {
"input": "input",
"select": "select",
@@ -555,7 +567,7 @@
},
"sidebar": {
"info": {
"name": "Node information",
"name": "Information",
"tabName": "Name",
"label": "info",
"node": "Node",
@@ -583,7 +595,29 @@
"nodeHelp": "Node Help",
"none":"None",
"arrayItems": "__count__ items",
"showTips":"You can open the tips from the settings panel"
"showTips":"You can open the tips from the settings panel",
"outline": "Outline",
"empty": "empty",
"globalConfig": "Global Configuration Nodes",
"triggerAction": "Trigger action",
"find": "Find in workspace",
"search": {
"configNodes": "Configuration nodes",
"unusedConfigNodes": "Unused configuration nodes",
"invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows"
}
},
"help": {
"name": "Help",
"label": "help",
"search": "Search help",
"nodeHelp": "Node Help",
"showHelp": "Show help",
"showInOutline": "Show in outline",
"showTopics": "Show topics",
"noHelp": "No help topic selected"
},
"config": {
"name": "Configuration nodes",
@@ -827,9 +861,9 @@
"expandItems": "Expand items",
"collapseItems": "Collapse items",
"duplicate": "Duplicate",
"error": {
"invalidJSON": "Invalid JSON: "
}
"error": {
"invalidJSON": "Invalid JSON: "
}
},
"markdownEditor": {
"title": "Markdown editor",
@@ -1001,7 +1035,7 @@
"retry": "Retry",
"update-failed": "Failed to update auth",
"unhandled": "Unhandled error response",
"host-key-verify-failed": "<p>Host key verification failed.</p><p>The repository host key could not be verified. Please update your <code>known_hosts</code> file and try again."
"host-key-verify-failed": "<p>Host key verification failed.</p><p>The repository host key could not be verified. Please update your <code>known_hosts</code> file and try again.</p>"
},
"create-branch-list": {
"invalid": "Invalid branch",

View File

@@ -266,5 +266,9 @@
"$type": {
"args": "value",
"desc": "Returns the type of `value` as a string. If `value` is undefined, this will return `undefined`"
},
"$moment": {
"args": "[str]",
"desc": "Gets a date object using the Moment library."
}
}

72
packages/node_modules/@node-red/editor-client/locales/ja/editor.json vendored Executable file → Normal file
View File

@@ -14,7 +14,15 @@
"back": "戻る",
"next": "進む",
"clone": "プロジェクトをクローン",
"cont": "続ける"
"cont": "続ける",
"style": "形式",
"line": "線",
"fill": "塗りつぶし",
"label": "ラベル",
"color": "色",
"position": "配置",
"enable": "有効",
"disable": "無効"
},
"type": {
"string": "文字列",
@@ -28,6 +36,13 @@
"null": "null"
}
},
"event": {
"loadPalette": "パレットを読み込み中",
"loadNodeCatalogs": "ノードカタログを読み込み中",
"loadNodes": "ノードを読み込み中 __count__",
"loadFlows": "フローを読み込み中",
"importFlows": "ワークスペースにフローを追加中"
},
"workspace": {
"defaultName": "フロー __number__",
"editFlow": "フローを編集: __name__",
@@ -67,7 +82,7 @@
"settings": "設定",
"userSettings": "ユーザ設定",
"nodes": "ノード",
"displayStatus": "ノードの状態を表示",
"displayStatus": "ノードのステータスを表示",
"displayConfig": "ノードの設定",
"import": "読み込み",
"export": "書き出し",
@@ -91,7 +106,12 @@
"projects-new": "新規",
"projects-open": "開く",
"projects-settings": "設定",
"showNodeLabelDefault": "追加したノードのラベルを表示"
"showNodeLabelDefault": "追加したノードのラベルを表示",
"groups": "グループ",
"groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除"
}
},
"actions": {
@@ -171,6 +191,8 @@
"node_plural": "__count__ 個のノード",
"configNode": "__count__ 個の設定ノード",
"configNode_plural": "__count__ 個の設定ノード",
"group": "__count__ 個のグループ",
"group_plural": "__count__ 個のグループ",
"flow": "__count__ 個のフロー",
"flow_plural": "__count__ 個のフロー",
"subflow": "__count__ 個のサブフロー",
@@ -186,6 +208,9 @@
"nodesImported": "読み込みました:",
"nodeCopied": "__count__ 個のノードをコピーしました",
"nodeCopied_plural": "__count__ 個のノードをコピーしました",
"groupCopied": "__count__ 個のグループをコピーしました",
"groupCopied_plural": "__count__ 個のグループをコピーしました",
"groupStyleCopied": "グループの形式をコピーしました",
"invalidFlow": "不正なフロー: __message__",
"export": {
"selected": "選択したフロー",
@@ -308,6 +333,13 @@
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"
}
},
"group": {
"editGroup": "__name__ グループを編集",
"errors": {
"cannotCreateDiffGroups": "異なるグループのノードを使用してグループを作成することはできません",
"cannotAddSubflowPorts": "グループにサブフローの端子を追加できません"
}
},
"editor": {
"configEdit": "編集",
"configAdd": "追加",
@@ -337,6 +369,7 @@
"locale": "UI言語の選択",
"icon": "記号",
"inputType": "入力形式",
"selectType": "形式選択...",
"inputs": {
"input": "入力",
"select": "メニュー",
@@ -539,6 +572,7 @@
"label": "情報",
"node": "ノード",
"type": "型",
"group": "グループ",
"module": "モジュール",
"id": "ID",
"status": "状態",
@@ -561,7 +595,29 @@
"nodeHelp": "ノードのヘルプ",
"none": "なし",
"arrayItems": "__count__ 要素",
"showTips": "設定からヒントを表示できます"
"showTips": "設定からヒントを表示できます",
"outline": "アウトライン",
"empty": "空",
"globalConfig": "グローバル設定ノード",
"triggerAction": "アクションを実行",
"find": "ワークスペース内を検索",
"search": {
"configNodes": "設定ノード",
"unusedConfigNodes": "未使用の設定ノード",
"invalidNodes": "不正なノード",
"uknownNodes": "未知のノード",
"unusedSubflows": "未使用のサブフロー"
}
},
"help": {
"name": "ヘルプ",
"label": "ヘルプ",
"search": "ヘルプを検索",
"nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示",
"showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択"
},
"config": {
"name": "ノードの設定を表示",
@@ -614,9 +670,9 @@
"removeFromProject": "プロジェクトから削除",
"addToProject": "プロジェクトへ追加",
"files": "ファイル",
"package": "パッケージ",
"flow": "フロー",
"credentials": "認証情報",
"package": "パッケージ",
"packageCreate": "変更が保存された時にファイルが作成されます",
"fileNotExist": "ファイルが存在しません",
"selectFile": "ファイルを選択",
@@ -757,7 +813,8 @@
"bin": "バッファ",
"date": "日時",
"jsonata": "JSONata式",
"env": "環境変数"
"env": "環境変数",
"cred": "認証情報"
}
},
"editableList": {
@@ -977,7 +1034,8 @@
"passphrase": "パスフレーズ",
"retry": "リトライ",
"update-failed": "認証の更新に失敗しました",
"unhandled": "エラー応答が処理されませんでした"
"unhandled": "エラー応答が処理されませんでした",
"host-key-verify-failed": "<p>ホストキーの検証に失敗</p><p>リポジトリのホストキーを検証できませんでした。<code>known_hosts</code>ファイルを更新して、もう一度試してください。</p>"
},
"create-branch-list": {
"invalid": "不正なブランチ",

View File

@@ -266,5 +266,9 @@
"$type": {
"args": "value",
"desc": "`value` の型を文字列として返します。もし `value` が未定義の場合、 `undefined` が返されます。"
},
"$moment": {
"args": "[str]",
"desc": "Momentライブラリを使用して日付オブジェクトを取得します。"
}
}

View File

@@ -14,7 +14,15 @@
"back": "后退",
"next": "下一个",
"clone": "克隆项目",
"cont": "继续"
"cont": "继续",
"style": "风格",
"line": "大纲",
"fill": "填充",
"label": "标签",
"color": "颜色",
"position": "位置",
"enable": "启用",
"disable": "禁用"
},
"type": {
"string": "字符串",
@@ -28,11 +36,18 @@
"null": "空"
}
},
"event": {
"loadPalette": "加载控制板",
"loadNodeCatalogs": "加载节点目录",
"loadNodes": "加载 __count__ 个节点",
"loadFlows": "加载流程",
"importFlows": "往工作区中加载流程"
},
"workspace": {
"defaultName": "流程__number__",
"defaultName": "流程 __number__",
"editFlow": "编辑流程: __name__",
"confirmDelete": "确认删除",
"delete": "你确定删除 '__label__'?",
"delete": "你确定删除 __label__ ?",
"dropFlowHere": "把流程放到这里",
"addFlow": "添加流程",
"listFlows": "流程一览",
@@ -91,7 +106,12 @@
"projects-new": "新建",
"projects-open": "打开",
"projects-settings": "项目设定",
"showNodeLabelDefault": "显示新添加的节点的标签"
"showNodeLabelDefault": "显示新添加的节点的标签",
"groups": "组",
"groupSelection": "选择组",
"ungroupSelection": "取消选择组",
"groupMergeSelection": "合并选择",
"groupRemoveSelection": "从组中移除"
}
},
"actions": {
@@ -101,7 +121,7 @@
"zoom-in": "放大"
},
"user": {
"loggedInAs": "作为__name__登陆",
"loggedInAs": "作为 __name__ 登陆",
"username": "账号",
"password": "密码",
"login": "登陆",
@@ -127,13 +147,13 @@
"missing_flow_file": "<p>找不到项目流程文件。</p><p>该项目未配置流程文件。</p>",
"missing_package_file": "<p>找不到项目包文件。</p><p>项目缺少package.json文件。</p>",
"project_empty": "<p>该项目为空。</p><p>是否要创建一组默认的项目文件?<br/>否则,您将必须在编辑器外部手动将文件添加到项目中。</p>",
"project_not_found": "<p>未找到项目'__project__'。</p>",
"project_not_found": "<p>未找到项目 __project__ 。</p>",
"git_merge_conflict": "<p>自动合并更改失败。</p><p>修复未合并的冲突,然后提交结果。</p>"
},
"error": "<strong>错误</strong>: __message__",
"errors": {
"lostConnection": "丢失与服务器的连接,重新连接...",
"lostConnectionReconnect": "丢失与服务器的连接__time__秒后重新连接",
"lostConnectionReconnect": "丢失与服务器的连接, __time__ 秒后重新连接",
"lostConnectionTry": "现在尝试",
"cannotAddSubflowToItself": "无法向其自身添加子流程",
"cannotAddCircularReference": "无法添加子流程 - 循环引用",
@@ -167,14 +187,16 @@
"clipboard": {
"clipboard": "剪贴板",
"nodes": "节点",
"node": "__count__节点",
"node_plural": "__count__节点",
"configNode": "__count__配置节点",
"configNode_plural": "__count__配置节点",
"flow": "__count__流程",
"flow_plural": "__count__流程",
"subflow": "__count__流程",
"subflow_plural": "__count__流程",
"node": "__count__节点",
"node_plural": "__count__节点",
"configNode": "__count__配置节点",
"configNode_plural": "__count__配置节点",
"group": "__count__ 个组",
"group_plural": "__count__ 个组",
"flow": "__count__流程",
"flow_plural": "__count__流程",
"subflow": "__count__ 个子流程",
"subflow_plural": "__count__ 子流程",
"pasteNodes": "在这里粘贴节点",
"selectFile": "选择要导入的文件",
"importNodes": "导入节点",
@@ -184,8 +206,11 @@
"importUnrecognised_plural": "导入了无法识别的类型:",
"nodesExported": "节点导出到了剪贴板",
"nodesImported": "导入:",
"nodeCopied": "已复制__count__个节点",
"nodeCopied_plural": "已复制__count__个节点",
"nodeCopied": "已复制 __count__ 个节点",
"nodeCopied_plural": "已复制 __count__ 个节点",
"groupCopied": "复制 __count__ 个组",
"groupCopied_plural": "已复制 __count__ 个groups",
"groupStyleCopied": "已复制组风格",
"invalidFlow": "无效的流程: __message__",
"export": {
"selected": "已选择的节点",
@@ -204,9 +229,9 @@
"newFlow": "新流程",
"errors": {
"notArray": "输入的不是JSON数组",
"itemNotObject": "输入的流无效 - 项目__index__不是节点对象",
"itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象",
"missingId": "输入的流无效-项 __index__ 缺少'id'属性",
"missingType": "输入的流程无效-项__index__缺少'类型'属性"
"missingType": "输入的流程无效-项 __index__ 缺少'类型'属性"
}
},
"copyMessagePath": "已复制路径",
@@ -250,7 +275,7 @@
"conflictChecking": "检查是否可以自动合并更改",
"conflictAutoMerge": "此更改不包括冲突,可以自动合并",
"conflictManualMerge": "这些更改包括了在部署之前必须解决的冲突。",
"plusNMore": "+ __count__更多"
"plusNMore": "+ __count__ 更多"
}
},
"eventLog": {
@@ -287,11 +312,11 @@
"newVersionError": "新版本不包含有效的JSON"
},
"subflow": {
"editSubflowInstance": "编辑子流实例__name__",
"editSubflow": "编辑流程模板: __name__",
"editSubflowInstance": "编辑子流实例: __name__",
"editSubflow": "编辑流程模板 __name__",
"edit": "编辑流程模板",
"subflowInstances": "这个子流程模板有__count__个实例",
"subflowInstances_plural": "这个子流程模板有__count__个实例",
"subflowInstances": "这个子流程模板有 __count__ 个实例",
"subflowInstances_plural": "这个子流程模板有 __count__ 个实例",
"editSubflowProperties": "编辑属性",
"input": "输入:",
"output": "输出:",
@@ -308,17 +333,24 @@
"multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择"
}
},
"group": {
"editGroup": "编辑组: __name__",
"errors": {
"cannotCreateDiffGroups": "无法使用来自不同组的节点创建组",
"cannotAddSubflowPorts": "无法将子流程的端口添加到组"
}
},
"editor": {
"configEdit": "编辑",
"configAdd": "添加",
"configUpdate": "更新",
"configDelete": "删除",
"nodesUse": "__count__个节点使用此配置",
"nodesUse_plural": "__count__个节点使用此配置",
"addNewConfig": "添加新的__type__配置",
"editNode": "编辑__type__节点",
"editConfig": "编辑__type__配置",
"addNewType": "添加新的__type__节点",
"nodesUse": "__count__ 个节点使用此配置",
"nodesUse_plural": "__count__ 个节点使用此配置",
"addNewConfig": "添加新的 __type__ 配置",
"editNode": "编辑 __type__ 节点",
"editConfig": "编辑 __type__ 配置",
"addNewType": "添加新的 __type__ 节点",
"nodeProperties": "节点属性",
"label": "标签",
"color": "颜色",
@@ -337,6 +369,7 @@
"locale": "选择界面语言",
"icon": "图标",
"inputType": "输入类型",
"selectType": "选择类型...",
"inputs": {
"input": "输入",
"select": "选择",
@@ -351,7 +384,8 @@
"bool": "布尔",
"json": "JSON",
"bin": "buffer",
"env": "环境变量"
"env": "环境变量",
"cred": "证书"
},
"menu": {
"input": "输入",
@@ -381,7 +415,7 @@
"scope": "范围",
"unassigned": "未分配",
"global": "全局",
"workspace": "工作",
"workspace": "工作",
"selectAll": "选择所有节点",
"selectAllConnected": "选择所有连接的节点",
"addRemoveNode": "从选择中添加/删除节点",
@@ -460,33 +494,33 @@
"times": {
"seconds": "秒前",
"minutes": "分前",
"minutesV": "__count__分前",
"hoursV": "__count__小时前",
"hoursV_plural": "__count__小时前",
"daysV": "__count__天前",
"daysV_plural": "__count__天前",
"weeksV": "__count__周前",
"weeksV_plural": "__count__周前",
"monthsV": "__count__月前",
"monthsV_plural": "__count__月前",
"yearsV": "__count__年前",
"yearsV_plural": "__count__年前",
"yearMonthsV": "__y__年, __count__月前",
"yearMonthsV_plural": "__y__年, __count__月前",
"yearsMonthsV": "__y__年, __count__月前",
"yearsMonthsV_plural": "__y__年, __count__月前"
"minutesV": "__count__ 分前",
"hoursV": "__count__ 小时前",
"hoursV_plural": "__count__ 小时前",
"daysV": "__count__ 天前",
"daysV_plural": "__count__ 天前",
"weeksV": "__count__ 周前",
"weeksV_plural": "__count__ 周前",
"monthsV": "__count__ 月前",
"monthsV_plural": "__count__ 月前",
"yearsV": "__count__ 年前",
"yearsV_plural": "__count__ 年前",
"yearMonthsV": "__y__ 年, __count__ 月前",
"yearMonthsV_plural": "__y__ 年, __count__ 月前",
"yearsMonthsV": "__y__ 年, __count__ 月前",
"yearsMonthsV_plural": "__y__ 年, __count__ 月前"
},
"nodeCount": "__label__个节点",
"nodeCount_plural": "__label__个节点",
"moduleCount": "__count__个可用模块",
"moduleCount_plural": "__count__个可用模块",
"nodeCount": "__label__ 个节点",
"nodeCount_plural": "__label__ 个节点",
"moduleCount": "__count__ 个可用模块",
"moduleCount_plural": "__count__ 个可用模块",
"inuse": "使用中",
"enableall": "全部启用",
"disableall": "全部禁用",
"enable": "启用",
"disable": "禁用",
"remove": "移除",
"update": "更新至__version__版本",
"update": "更新至 __version__ 版本",
"updated": "已更新",
"install": "安装",
"installed": "已安装",
@@ -498,7 +532,7 @@
"sort": "排序:",
"sortAZ": "a-z顺序",
"sortRecent": "日期顺序",
"more": "增加__count__个",
"more": "增加 __count__ 个",
"errors": {
"catalogLoadFailed": "无法加载节点目录。<br>查看浏览器控制台了解更多信息",
"installFailed": "无法安装: __module__<br>__message__<br>查看日志了解更多信息",
@@ -539,6 +573,7 @@
"label": "信息",
"node": "节点",
"type": "类型",
"group": "组",
"module": "模组",
"id": "ID",
"status": "状态",
@@ -560,8 +595,30 @@
"subflowDesc": "子流程描述",
"nodeHelp": "节点帮助",
"none": "无",
"arrayItems": "__count__个项目",
"showTips": "您可以从设置面板启用提示信息"
"arrayItems": "__count__ 个项目",
"showTips": "您可以从设置面板启用提示信息",
"outline": "大纲",
"empty": "空的",
"globalConfig": "全局配置节点",
"triggerAction": "触发动作",
"find": "在工作区中查找",
"search": {
"configNodes": "配置节点",
"unusedConfigNodes": "未使用的配置节点",
"invalidNodes": "无效的节点",
"uknownNodes": "未知的节点",
"unusedSubflows": "未使用的子流程"
}
},
"help": {
"name": "帮助",
"label": "帮助",
"search": "搜索帮助",
"nodeHelp": "节点帮助",
"showHelp": "显示帮助",
"showInOutline": "在大纲中显示",
"showTopics": "显示主题",
"noHelp": "未选择帮助主题"
},
"config": {
"name": "配置节点",
@@ -614,9 +671,9 @@
"removeFromProject": "从项目中删除",
"addToProject": "添加到项目",
"files": "文件",
"package": "包",
"flow": "流程",
"credentials": "证书",
"package": "包",
"packageCreate": "保存更改后将创建文件",
"fileNotExist": "文件不存在",
"selectFile": "选择文件",
@@ -628,7 +685,7 @@
"changeTheEncryptionKey": "更改加密密钥",
"currentKey": "当前密钥",
"newKey": "新密钥",
"credentialsAlert": "这将删除所有现有证",
"credentialsAlert": "这将删除所有现有证",
"versionControl": "版本控制",
"branches": "分支",
"noBranches": "没有分支",
@@ -668,7 +725,7 @@
"copyPublicKey": "将公钥复制到剪贴板",
"delete": "删除密钥",
"gitConfig": "Git配置",
"deleteConfirm": "您确定要删除SSH密钥__name__吗这不能被撤消。"
"deleteConfirm": "您确定要删除SSH密钥 __name__ 吗?这不能被撤消。"
},
"versionControl": {
"unstagedChanges": "未暂存的变更",
@@ -722,24 +779,24 @@
"pullChanges": "拉取更改",
"history": "历史",
"projectHistory": "项目历史",
"daysAgo": "__count__天前",
"daysAgo_plural": "__count__天前",
"hoursAgo": "__count__小时前",
"hoursAgo_plural": "__count__小时前",
"minsAgo": "__count__分钟前",
"minsAgo_plural": "__count__分钟前",
"daysAgo": "__count__ 天前",
"daysAgo_plural": "__count__ 天前",
"hoursAgo": "__count__ 小时前",
"hoursAgo_plural": "__count__ 小时前",
"minsAgo": "__count__ 分钟前",
"minsAgo_plural": "__count__ 分钟前",
"secondsAgo": "秒前",
"notTracking": "您的本地分支当前未跟踪一个远程分支。",
"statusUnmergedChanged": "您的仓库中有未合并的更改。您需要解决冲突并提交结果。",
"repositoryUpToDate": "您的仓库是最新的。",
"commitsAhead": "您的存储库领先远程仓库__count__次提交。您现在可以推送这些提交。",
"commitsAhead_plural": "您的存储库领先远程仓库__count__次提交。您现在可以推送这些提交。",
"commitsBehind": "您的存储库落后远程仓库__count__次提交。您现在可以拉取这些提交。",
"commitsBehind_plural": "您的存储库落后远程仓库__count__次提交。您现在可以拉取这些提交。",
"commitsAheadAndBehind1": "您的存储库落后远程仓库__count__次提交",
"commitsAheadAndBehind1_plural": "您的存储库落后远程仓库__count__次提交",
"commitsAheadAndBehind2": "领先远程仓库__count__次提交。",
"commitsAheadAndBehind2_plural": "领先远程仓库__count__次提交。",
"commitsAhead": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。",
"commitsAhead_plural": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。",
"commitsBehind": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。",
"commitsBehind_plural": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。",
"commitsAheadAndBehind1": "您的存储库落后远程仓库 __count__ 次提交",
"commitsAheadAndBehind1_plural": "您的存储库落后远程仓库 __count__ 次提交",
"commitsAheadAndBehind2": "领先远程仓库 __count__ 次提交。",
"commitsAheadAndBehind2_plural": "领先远程仓库 __count__ 次提交。",
"commitsAheadAndBehind3": "您必须先拉取远程提交,然后才能进行推送。",
"commitsAheadAndBehind3_plural": "您必须先拉取远程提交,然后才能进行推送。",
"refreshCommitHistory": "刷新提交历史",
@@ -757,7 +814,8 @@
"bin": "二进制流",
"date": "时间戳",
"jsonata": "表达式",
"env": "环境变量"
"env": "环境变量",
"cred": "证书"
}
},
"editableList": {
@@ -977,7 +1035,8 @@
"passphrase": "密码短语",
"retry": "重试",
"update-failed": "无法更新身份验证",
"unhandled": "未处理的错误响应"
"unhandled": "未处理的错误响应",
"host-key-verify-failed": "<p>主机密钥验证失败。</p><p>无法验证存储库主机密钥。请更新您的<code>known_hosts</code>文件,然后重试。</p>"
},
"create-branch-list": {
"invalid": "无效的分支",

View File

@@ -1,15 +1,15 @@
{
"$string": {
"args": "arg",
"desc": "通过以下的类型转换规则将参数*arg*转换成字符串:\n\n - 字符串不转换。\n -函数转换成空的字符串。\n - JSON的值无法用数字表示所以用无限大或者NaN非数表示。\n - 用JSON.stringify函数将其他值转换成JSON字符串。"
"desc": "通过以下的类型转换规则将参数 *arg* 转换成字符串:\n\n - 字符串不转换。\n -函数转换成空的字符串。\n - JSON的值无法用数字表示所以用无限大或者NaN非数表示。\n - 用 `JSON.stringify` 函数将其他值转换成JSON字符串。"
},
"$length": {
"args": "str",
"desc": "输出字符串str的字数。如果str不是字符串,抛出错误。"
"desc": "输出字符串 `str` 的字数。如果 `str` 不是字符串,抛出错误。"
},
"$substring": {
"args": "str, start[, length]",
"desc": "输出`start`位置后的的首次出现的包括`str`的子字符串。 如果`length`被指定,那么的字符串中将只包括前`length`个文字。如果`start`是负数则输出从`str`末尾开始的`length`个文字"
"desc": "输出 `start` 位置后的的首次出现的包括 `str` 的子字符串。 如果 `length` 被指定,那么的字符串中将只包括前 `length` 个文字。如果 `start` 是负数则输出从 `str` 末尾开始的 `length` 个文字"
},
"$substringBefore": {
"args": "str, chars",
@@ -17,11 +17,11 @@
},
"$substringAfter": {
"args": "str, chars",
"desc": "输出str中首次出现的chars之后的子字符串,如果str中不包括chars则输出str。"
"desc": "输出 `str` 中首次出现的 `chars` 之后的子字符串,如果 `str` 中不包括 `chars` 则输出 `str` 。"
},
"$uppercase": {
"args": "str",
"desc": "`将’str中的所有字母变为大写后输出。"
"desc": "将 `str` 中的所有字母变为大写后输出。"
},
"$lowercase": {
"args": "str",
@@ -29,27 +29,27 @@
},
"$trim": {
"args": "str",
"desc": "将以下步骤应用于`str`来去除所有空白文字并实现标准化。\n\n 将全部tab制表符、回车键、换行字符用空白代替。\n- 将连续的空白文字变成一个空白文字。\n- 消除开头和末尾的空白文字。\n\n如果`str`没有被指定(即在无输入参数的情况下调用本函数),将上下文的值作为`str`来使用。 如果`str` 不是字符串则抛出错误。"
"desc": "将以下步骤应用于 `str` 来去除所有空白文字并实现标准化。\n\n 将全部tab制表符、回车键、换行字符用空白代替。\n- 将连续的空白文字变成一个空白文字。\n- 消除开头和末尾的空白文字。\n\n如果 `str` 没有被指定(即在无输入参数的情况下调用本函数),将上下文的值作为 `str` 来使用。 如果 `str` 不是字符串则抛出错误。"
},
"$contains": {
"args": "str, pattern",
"desc": "字符串`str` 和 `pattern`匹配的话输出`true`,不匹配的情况下输出 `false`。 不指定`str`的情况下(比如用一个参数调用本函数时)、将上下文的值作为`str`来使用。参数 `pattern`可以为字符串或正则表达。"
"desc": "字符串 `str` 和 `pattern` 匹配的话输出 `true` ,不匹配的情况下输出 `false` 。 不指定 `str` 的情况下(比如用一个参数调用本函数时)、将上下文的值作为 `str` 来使用。参数 `pattern` 可以为字符串或正则表达。"
},
"$split": {
"args": "str[, separator][, limit]",
"desc": "将参数`str`分解成由子字符串组成的数组。 如果`str`不是字符串抛出错误。可以省略的参数 `separator`中指定字符串`str`的分隔符。分隔符可以是文字或正则表达式。在不指定`separator`的情况下、将分隔符看作空的字符串并把`str`拆分成由单个字母组成的数组。如果`separator`不是字符串则抛出错误。在可省略的参数`limit`中指定分割后的子字符串的最大个数。超出个数的子字符串将被舍弃。如果`limit`没有被指定,`str` 将不考虑子字符串的个数而将字符串完全分隔。如果`limit`是负数则抛出错误。"
"desc": "将参数 `str` 分解成由子字符串组成的数组。 如果 `str` 不是字符串抛出错误。可以省略的参数 `separator` 中指定字符串 `str` 的分隔符。分隔符可以是文字或正则表达式。在不指定 `separator` 的情况下、将分隔符看作空的字符串并把 `str` 拆分成由单个字母组成的数组。如果 `separator` 不是字符串则抛出错误。在可省略的参数 `limit` 中指定分割后的子字符串的最大个数。超出个数的子字符串将被舍弃。如果 `limit` 没有被指定,`str` 将不考虑子字符串的个数而将字符串完全分隔。如果 `limit` 是负数则抛出错误。"
},
"$join": {
"args": "array[, separator]",
"desc": "用可以省略的参数 `separator`来把多个字符串连接。如果`array`不是字符串则抛出错误。 如果没有指定`separator`,则用空字符串来连接字符(即字符串之间没有`separator`)。 如果`separator`不是字符则抛出错误。"
"desc": "用可以省略的参数 `separator` 来把多个字符串连接。如果 `array` 不是字符串则抛出错误。 如果没有指定 `separator` ,则用空字符串来连接字符(即字符串之间没有 `separator` )。 如果 `separator` 不是字符则抛出错误。"
},
"$match": {
"args": "str, pattern [, limit]",
"desc": "对字符串`str`使用正则表达式`pattern`并输出与`str`相匹配的部分信息。"
"desc": "对字符串 `str` 使用正则表达式 `pattern` 并输出与 `str` 相匹配的部分信息。"
},
"$replace": {
"args": "str, pattern, replacement [, limit]",
"desc": "在字符串`str`中搜索`pattern`并用`replacement`来替换。\n\n可选参数`limit`用来指定替换次数的上限。"
"desc": "在字符串 `str` 中搜索 `pattern` 并用 `replacement` 来替换。\n\n可选参数 `limit` 用来指定替换次数的上限。"
},
"$now": {
"args": "",
@@ -65,31 +65,31 @@
},
"$number": {
"args": "arg",
"desc": "用下述的规则将参数 `arg`转换为数值。:\n\n 数值不做转换。\n 将字符串中合法的JSON数値表示转换成数値。\n 其他形式的值则抛出错误。"
"desc": "用下述的规则将参数 `arg` 转换为数值。:\n\n 数值不做转换。\n 将字符串中合法的JSON数値表示转换成数値。\n 其他形式的值则抛出错误。"
},
"$abs": {
"args": "number",
"desc": "输出参数`number`的绝对值。"
"desc": "输出参数 `number` 的绝对值。"
},
"$floor": {
"args": "number",
"desc": "输出比`number`的值小的最大整数。"
"desc": "输出比 `number` 的值小的最大整数。"
},
"$ceil": {
"args": "number",
"desc": "输出比`number`的值大的最小整数。"
"desc": "输出比 `number` 的值大的最小整数。"
},
"$round": {
"args": "number [, precision]",
"desc": "输出四舍五入后的参数`number`。可省略的参数 `precision`指定四舍五入后小数点下的位数。"
"desc": "输出四舍五入后的参数 `number` 。可省略的参数 `precision` 指定四舍五入后小数点下的位数。"
},
"$power": {
"args": "base, exponent",
"desc": "输出底数`base``exponent`次幂。"
"desc": "输出底数 `base``exponent` 次幂。"
},
"$sqrt": {
"args": "number",
"desc": "输出参数 `number`的平方根。"
"desc": "输出参数 `number` 的平方根。"
},
"$random": {
"args": "",
@@ -97,35 +97,35 @@
},
"$millis": {
"args": "",
"desc": "返回从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。在同一个表达式的测试中所有对`$millis()`的调用将会返回相同的值。"
"desc": "返回从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。在同一个表达式的测试中所有对 `$millis()` 的调用将会返回相同的值。"
},
"$sum": {
"args": "array",
"desc": "输出数组`array`的总和。如果`array`不是数值则抛出错误。"
"desc": "输出数组 `array` 的总和。如果 `array` 不是数值则抛出错误。"
},
"$max": {
"args": "array",
"desc": "输出数组`array`的最大值。如果`array`不是数值则抛出错误。"
"desc": "输出数组 `array` 的最大值。如果 `array` 不是数值则抛出错误。"
},
"$min": {
"args": "array",
"desc": "输出数组`array`的最小值。如果`array`不是数值则抛出错误。。"
"desc": "输出数组 `array` 的最小值。如果 `array` 不是数值则抛出错误。。"
},
"$average": {
"args": "array",
"desc": "输出数组`array`的平均数。如果`array`不是数值则抛出错误。。"
"desc": "输出数组 `array` 的平均数。如果 `array` 不是数值则抛出错误。。"
},
"$boolean": {
"args": "arg",
"desc": "用下述规则将数据转换成布尔值。:\n\n - 不转换布尔值`Boolean`。\n 将空的字符串`string`转换为`false`\n 将不为空的字符串`string`转换为`true`\n 将为0的数字`number`转换成`false`\n 将不为0的数字`number`转换成`true`\n –将`null`转换成`false`\n –将空的数组`array`转换成`false`\n –如果数组`array`中含有可以转换成`true`的要素则转换成`true`\n –如果`array`中没有可转换成`true`的要素则转换成`false`\n 空的对象`object`转换成`false`\n 非空的对象`object`转换成`true`\n –将函数`function`转换成`false`"
"desc": "用下述规则将数据转换成布尔值。:\n\n - 不转换布尔值 `Boolean` 。\n 将空的字符串 `string` 转换为 `false` \n 将不为空的字符串 `string` 转换为 `true` \n 将为0的数字 `number` 转换成 `false` \n 将不为0的数字 `number` 转换成 `true` \n –将 `null` 转换成 `false` \n –将空的数组 `array` 转换成 `false` \n –如果数组 `array` 中含有可以转换成 `true` 的要素则转换成 `true` \n –如果 `array` 中没有可转换成 `true` 的要素则转换成 `false` \n 空的对象 `object` 转换成 `false` \n 非空的对象 `object` 转换成 `true` \n –将函数 `function` 转换成 `false` "
},
"$not": {
"args": "arg",
"desc": "输出做取反运算后的布尔值。首先将`arg`转换为布尔值。"
"desc": "输出做取反运算后的布尔值。首先将 `arg` 转换为布尔值。"
},
"$exists": {
"args": "arg",
"desc": "如果算式`arg`的值存在则输出`true`。如果算式的值不存在(比如指向不存在区域的引用)则输出`false`。"
"desc": "如果算式 `arg` 的值存在则输出 `true` 。如果算式的值不存在(比如指向不存在区域的引用)则输出 `false` 。"
},
"$count": {
"args": "array",
@@ -137,15 +137,15 @@
},
"$sort": {
"args": "array [, function]",
"desc": "输出排序后的数组`array`。\n\n如果使用了比较函数`function`,则下述两个参数需要被指定。\n\n`function(left, right)`\n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后那么该函数必须输出布尔值`true`来表示位置交换。而在不需要位置交换时函数必须输出`false`。"
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)` \n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
},
"$reverse": {
"args": "array",
"desc": "输出倒序后的数组`array`。"
"desc": "输出倒序后的数组 `array` 。"
},
"$shuffle": {
"args": "array",
"desc": "输出随机排序后的数组 `array`。"
"desc": "输出随机排序后的数组 `array` 。"
},
"$zip": {
"args": "array, ...",
@@ -157,35 +157,35 @@
},
"$lookup": {
"args": "object, key",
"desc": "输出对象中与参数`key`对应的值。如果第一个参数`object`是数组,那么数组中所有的对象都将被搜索并输出这些对象中与参数`key`对应的值。"
"desc": "输出对象中与参数 `key` 对应的值。如果第一个参数 `object` 是数组,那么数组中所有的对象都将被搜索并输出这些对象中与参数 `key` 对应的值。"
},
"$spread": {
"args": "object",
"desc": "将对象中的键值对分隔成每个要素中只含有一个键值对的数组。如果参数`object`是数组,那么返回值的数组中包含所有对象中的键值对。"
"desc": "将对象中的键值对分隔成每个要素中只含有一个键值对的数组。如果参数 `object` 是数组,那么返回值的数组中包含所有对象中的键值对。"
},
"$merge": {
"args": "array&lt;object&gt;",
"desc": "将输入数组`objects`中所有的键值对合并到一个`object`中并返回。如果输入数组的要素中含有重复的键,则返回的`object`中将只包含数组中最后出现要素的值。如果输入数组中包括对象以外的元素,则抛出错误。"
"desc": "将输入数组 `objects` 中所有的键值对合并到一个 `object` 中并返回。如果输入数组的要素中含有重复的键,则返回的 `object` 中将只包含数组中最后出现要素的值。如果输入数组中包括对象以外的元素,则抛出错误。"
},
"$sift": {
"args": "object, function",
"desc": "输出参数`object`中符合`function`的键值对。\n\n`function`必须含有下述参数。\n\n`function(value [, key [, object]])`"
"desc": "输出参数 `object` 中符合 `function` 的键值对。\n\n `function` 必须含有下述参数。\n\n `function(value [, key [, object]])` "
},
"$each": {
"args": "object, function",
"desc": "将函数`function`应用于`object`中的所有键值对并输出由所有返回值组成的数组。"
"desc": "将函数 `function` 应用于 `object` 中的所有键值对并输出由所有返回值组成的数组。"
},
"$map": {
"args": "array, function",
"desc": "将函数`function`应用于数组`array`中所有的值并输出由返回值组成的数组。\n\n`function`中必须含有下述参数。\n\n`function(value [, index [, array]])`"
"desc": "将函数 `function` 应用于数组 `array` 中所有的值并输出由返回值组成的数组。\n\n `function` 中必须含有下述参数。\n\n`function(value [, index [, array]])` "
},
"$filter": {
"args": "array, function",
"desc": "输出数组`array`中符合函数`function`条件的值组成的数组。\n\n`function`必须包括下述参数。\n\n`function(value [, index [, array]])`"
"desc": "输出数组 `array` 中符合函数 `function` 条件的值组成的数组。\n\n `function` 必须包括下述参数。\n\n `function(value [, index [, array]])`"
},
"$reduce": {
"args": "array, function [, init]",
"desc": "将`function`依次应用于数组中的各要素值。 其中,前一个要素值的计算结果将参与到下一次的函数运算中。。\n\n函数`function`接受两个参数并作为中缀表示法中的操作符。\n\n可省略的参数`init`将作为运算的初始值。"
"desc": "将 `function` 依次应用于数组中的各要素值。 其中,前一个要素值的计算结果将参与到下一次的函数运算中。。\n\n函数 `function` 接受两个参数并作为中缀表示法中的操作符。\n\n可省略的参数 `init` 将作为运算的初始值。"
},
"$flowContext": {
"args": "string",
@@ -197,7 +197,7 @@
},
"$pad": {
"args": "string, width [, char]",
"desc": "根据需要,向字符串`string`的副本中填充文字使该字符串的字数达到`width`的绝对值并返回填充文字后的字符串。\n\n如果`width`的值为正,则向字符串`string`的右侧填充文字,如果`width`为负,则向字符串`string`的左侧填充文字。\n\n可选参数`char`用来指定填充的文字。如果未指定该参数,则填充空白文字。"
"desc": "根据需要,向字符串 `string` 的副本中填充文字使该字符串的字数达到 `width` 的绝对值并返回填充文字后的字符串。\n\n如果 `width` 的值为正,则向字符串 `string` 的右侧填充文字,如果 `width` 为负,则向字符串 `string` 的左侧填充文字。\n\n可选参数 `char` 用来指定填充的文字。如果未指定该参数,则填充空白文字。"
},
"$fromMillis": {
"args": "number",
@@ -205,15 +205,15 @@
},
"$formatNumber": {
"args": "number, picture [, options]",
"desc": "将`number`转换成具有`picture`所指定的数值格式的字符串。\n\n此函数的功能与XPath F&O 3.1规格中定义的XPath/XQuery函数的fn:format-number功能相一致。参数`picture`用于指定数值的转换格式其语法与fn:format-number中的定义一致。\n\n可选的第三参数`options`用来覆盖默认的局部环境格式如小数点分隔符。如果指定该参数那么该参数必须是包含name/value对的对象并且name/value对必须符合XPath F&O 3.1规格中记述的数值格式。"
"desc": "将 `number` 转换成具有 `picture` 所指定的数值格式的字符串。\n\n此函数的功能与XPath F&O 3.1规格中定义的XPath/XQuery函数的fn:format-number功能相一致。参数 `picture` 用于指定数值的转换格式其语法与fn:format-number中的定义一致。\n\n可选的第三参数 `options` 用来覆盖默认的局部环境格式如小数点分隔符。如果指定该参数那么该参数必须是包含name/value对的对象并且name/value对必须符合XPath F&O 3.1规格中记述的数值格式。"
},
"$formatBase": {
"args": "number [, radix]",
"desc": "将`number`变换为以参数`radix`的值为基数形式的字符串。如果不指定`radix`的值则默认基数为10。指定的`radix`值必须在236之间否则抛出错误。"
"desc": "将 `number` 变换为以参数 `radix` 的值为基数形式的字符串。如果不指定 `radix` 的值则默认基数为10。指定的 `radix` 值必须在236之间否则抛出错误。"
},
"$toMillis": {
"args": "timestamp",
"desc": "将ISO 8601格式的字符串`timestamp`转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。如果该字符串的格式不正确则抛出错误。"
"desc": "将ISO 8601格式的字符串 `timestamp` 转换为从UNIX时间 (1970年1月1日 UTC/GMT的午夜开始到现在的毫秒数。如果该字符串的格式不正确则抛出错误。"
},
"$env": {
"args": "arg",
@@ -221,7 +221,7 @@
},
"$eval": {
"args": "expr [, context]",
"desc": "使用当前上下文来作为评估依据,分析并评估字符串`expr`其中包含文字JSON或JSONata表达式。"
"desc": "使用当前上下文来作为评估依据,分析并评估字符串 `expr` 其中包含文字JSON或JSONata表达式。"
},
"$formatInteger": {
"args": "number, picture",
@@ -233,19 +233,19 @@
},
"$error": {
"args": "[str]",
"desc": "引发错误并显示一条消息。 可选的`str`将替代$error()函数评估的默认消息。"
"desc": "引发错误并显示一条消息。 可选的 `str` 将替代$error()函数评估的默认消息。"
},
"$assert": {
"args": "arg, str",
"desc": "如果`arg`为真,则该函数返回。 如果arg为假则抛出带有str的异常作为异常消息。"
"desc": "如果 `arg` 为真,则该函数返回。 如果arg为假则抛出带有str的异常作为异常消息。"
},
"$single": {
"args": "array, function",
"desc": "返回满足参数function谓语的array参数中的唯一值 (比如传递值时函数返回布尔值“true”)。如果匹配值的数量不唯一时,则抛出异常。\n\n应在以下签名中提供函数`functionvalue [index [array []]]`其中value是数组的每个输入index是该值的位置整个数组作为第三个参数传递。"
"desc": "返回满足参数function谓语的array参数中的唯一值 (比如传递值时函数返回布尔值“true”)。如果匹配值的数量不唯一时,则抛出异常。\n\n应在以下签名中提供函数 `functionvalue [index [array []]]` 其中value是数组的每个输入index是该值的位置整个数组作为第三个参数传递。"
},
"$encodeUrl": {
"args": "str",
"desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL组件进行编码。\n\n示例`$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
"desc": "通过用表示字符的UTF-8编码的一个两个三个或四个转义序列替换某些字符的每个实例对统一资源定位符URL组件进行编码。\n\n示例 `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`"
},
"$encodeUrlComponent": {
"args": "str",
@@ -261,10 +261,14 @@
},
"$distinct": {
"args": "array",
"desc": "返回一个数组,其中重复的值已从`数组`中删除"
"desc": "返回一个数组,其中重复的值已从 `数组` 中删除"
},
"$type": {
"args": "value",
"desc": "以字符串形式返回`值`的类型。 如果该`值`未定义,则将返回`未定义`"
"desc": "以字符串形式返回 `值` 的类型。 如果该 `值` 未定义,则将返回 `未定义` "
},
"$moment": {
"args": "[str]",
"desc": "使用Moment库获取日期对象。"
}
}

View File

@@ -14,7 +14,15 @@
"back": "返回",
"next": "下一步",
"clone": "複製專案",
"cont": "Continue"
"cont": "繼續",
"style": "風格",
"line": "大綱",
"fill": "填充",
"label": "標籤",
"color": "顏色",
"position": "位置",
"enable": "啟用",
"disable": "禁用"
},
"type": {
"string": "字符串",
@@ -28,6 +36,13 @@
"null": "空"
}
},
"event": {
"loadPalette": "加載控制板",
"loadNodeCatalogs": "加載節點目錄",
"loadNodes": "加載 __count__ 個節點",
"loadFlows": "加載流程",
"importFlows": "往工作區中加載流程"
},
"workspace": {
"defaultName": "流程__number__",
"editFlow": "編輯流程: __name__",
@@ -91,7 +106,12 @@
"projects-new": "新專案",
"projects-open": "開啟專案",
"projects-settings": "專案設定",
"showNodeLabelDefault": "顯示新添加節點的標籤"
"showNodeLabelDefault": "顯示新添加節點的標籤",
"groups": "組",
"groupSelection": "選擇組",
"ungroupSelection": "取消選擇組",
"groupMergeSelection": "合并選擇",
"groupRemoveSelection": "從組中移除"
}
},
"actions": {
@@ -101,7 +121,7 @@
"zoom-in": "放大"
},
"user": {
"loggedInAs": "作為__name__登入",
"loggedInAs": "作為 __name__ 登入",
"username": "帳號",
"password": "密碼",
"login": "登入",
@@ -133,7 +153,7 @@
"error": "<strong>Error</strong>: __message__",
"errors": {
"lostConnection": "丟失與伺服器的連接,重新連接...",
"lostConnectionReconnect": "丟失與伺服器的連接__time__秒後重新連接",
"lostConnectionReconnect": "丟失與伺服器的連接__time__ 秒後重新連接",
"lostConnectionTry": "現在嘗試",
"cannotAddSubflowToItself": "無法向其自身添加子流程",
"cannotAddCircularReference": "無法添加子流程 - 迴圈引用",
@@ -146,7 +166,7 @@
"loaded": "已加載項目'__project__'",
"updated": "已更新項目'__project__'",
"pull": "已重新加載項目'__project__'",
"revert": "項目__project__已還原",
"revert": "項目'__project__'已還原",
"merge-complete": "Git合併完成",
"setupCredentials": "設定證書",
"setupProjectFiles": "設置項目文件",
@@ -171,6 +191,8 @@
"node_plural": "__count__ 多個節點",
"configNode": "__count__ 節點組態",
"configNode_plural": "__count__ 多節點組態",
"group": "__count__ 個組",
"group_plural": "__count__ 個組",
"flow": "__count__ 流程",
"flow_plural": "__count__ 多流程",
"subflow": "__count__ 子流程",
@@ -184,8 +206,11 @@
"importUnrecognised_plural": "匯入了無法識別的類型:",
"nodesExported": "節點匯出到了剪貼簿",
"nodesImported": "已匯入:",
"nodeCopied": "已複製__count__個節點",
"nodeCopied_plural": "已複製__count__個節點",
"nodeCopied": "已複製 __count__ 個節點",
"nodeCopied_plural": "已複製 __count__ 個節點",
"groupCopied": "複製 __count__ 個組",
"groupCopied_plural": "已複製 __count__ 個groups",
"groupStyleCopied": "已複製組風格",
"invalidFlow": "無效的流程: __message__",
"export": {
"selected": "已選擇的節點",
@@ -204,9 +229,9 @@
"newFlow": "新流程",
"errors": {
"notArray": "輸入的不是JSON數組",
"itemNotObject": "輸入的流程無效-項目__index__不是節點對象",
"missingId": "輸入的流程無效-項__index__缺少“ id”屬性",
"missingType": "輸入的流程無效-項__index__缺少“類型”屬性"
"itemNotObject": "輸入的流程無效-項目 __index__ 不是節點對象",
"missingId": "輸入的流程無效-項 __index__ 缺少“ id”屬性",
"missingType": "輸入的流程無效-項 __index__ 缺少“類型”屬性"
}
},
"copyMessagePath": "已複製路徑",
@@ -250,7 +275,7 @@
"conflictChecking": "檢查是否可以自動合併更改",
"conflictAutoMerge": "此更改不包括衝突,可以自動合併",
"conflictManualMerge": "這些更改包括了在部署之前必須解決的衝突。",
"plusNMore": "+更多的__count__"
"plusNMore": "+更多的 __count__"
}
},
"eventLog": {
@@ -258,8 +283,8 @@
"view": "查看日誌"
},
"diff": {
"unresolvedCount": "__count__個未解決的衝突",
"unresolvedCount_plural": "__count__個未解決的衝突",
"unresolvedCount": "__count__ 個未解決的衝突",
"unresolvedCount_plural": "__count__ 個未解決的衝突",
"globalNodes": "全局節點",
"flowProperties": "流程屬性",
"type": {
@@ -269,11 +294,11 @@
"deleted": "已刪除",
"flowDeleted": "已刪除流程",
"flowAdded": "已添加流程",
"movedTo": "移動至__id__",
"movedFrom": "從__id__移動"
"movedTo": "移動至 __id__",
"movedFrom": "從 __id__ 移動"
},
"nodeCount": "__count__個節點",
"nodeCount_plural": "__count__個節點",
"nodeCount": "__count__ 個節點",
"nodeCount_plural": "__count__ 個節點",
"local": "本地",
"remote": "遠端",
"reviewChanges": "查看變更",
@@ -287,11 +312,11 @@
"newVersionError": "新版本不包含有效的JSON"
},
"subflow": {
"editSubflowInstance": "編輯子流程實例__name__",
"editSubflow": "編輯流程範本: __name__",
"editSubflowInstance": "編輯子流程實例: __name__",
"editSubflow": "編輯流程範本 __name__",
"edit": "編輯流程範本",
"subflowInstances": "這個子流程範本有__count__個實例",
"subflowInstances_plural": "這個子流程範本有__count__個實例",
"subflowInstances": "這個子流程範本有 __count__ 個實例",
"subflowInstances_plural": "這個子流程範本有 __count__ 個實例",
"editSubflowProperties": "編輯屬性",
"input": "輸入:",
"output": "輸出:",
@@ -308,17 +333,24 @@
"multipleInputsToSelection": "<strong>無法創建子流程</strong>: 多個輸入到了選擇"
}
},
"group": {
"editGroup": "編輯組: __name__",
"errors": {
"cannotCreateDiffGroups": "無法使用來自不同組的節點創建組",
"cannotAddSubflowPorts": "無法將子流程的端口添加到組"
}
},
"editor": {
"configEdit": "編輯",
"configAdd": "添加",
"configUpdate": "更新",
"configDelete": "刪除",
"nodesUse": "__count__個節點使用此配置",
"nodesUse_plural": "__count__個節點使用此配置",
"addNewConfig": "添加新的__type__配置",
"editNode": "編輯__type__節點",
"editConfig": "編輯__type__配置",
"addNewType": "添加新的__type__節點",
"nodesUse": "__count__ 個節點使用此配置",
"nodesUse_plural": "__count__ 個節點使用此配置",
"addNewConfig": "添加新的 __type__ 配置",
"editNode": "編輯 __type__ 節點",
"editConfig": "編輯 __type__ 配置",
"addNewType": "添加新的 __type__ 節點",
"nodeProperties": "節點屬性",
"label": "Label",
"color": "顏色",
@@ -337,6 +369,7 @@
"locale": "選擇界面語言",
"icon": "圖標",
"inputType": "輸入類型",
"selectType": "選擇類型...",
"inputs": {
"input": "輸入",
"select": "選擇",
@@ -351,7 +384,8 @@
"bool": "布爾",
"json": "JSON",
"bin": "buffer",
"env": "環境變量"
"env": "環境變量",
"cred": "證書"
},
"menu": {
"input": "輸入",
@@ -405,13 +439,13 @@
"library": "庫",
"openLibrary": "打開庫...",
"saveToLibrary": "保存到庫...",
"typeLibrary": "__type__型別程式庫",
"unnamedType": "無名__type__",
"typeLibrary": "__type__ 型別程式庫",
"unnamedType": "無名 __type__",
"exportedToLibrary": "節點導出到庫",
"dialogSaveOverwrite": "一個叫做__libraryName____libraryType__已經存在您需要覆蓋麼",
"dialogSaveOverwrite": "一個叫做 __libraryName____libraryType__ 已經存在,您需要覆蓋麼?",
"invalidFilename": "無效的檔案名",
"savedNodes": "保存的節點",
"savedType": "已保存__type__",
"savedType": "已保存 __type__",
"saveFailed": "保存失敗: __message__",
"newFolder": "新文件夾",
"types": {
@@ -460,33 +494,33 @@
"times": {
"seconds": "秒前",
"minutes": "分前",
"minutesV": "__count__分前",
"hoursV": "__count__小時前",
"hoursV_plural": "__count__小時前",
"daysV": "__count__天前",
"daysV_plural": "__count__天前",
"weeksV": "__count__周前",
"weeksV_plural": "__count__周前",
"monthsV": "__count__月前",
"monthsV_plural": "__count__月前",
"yearsV": "__count__年前",
"yearsV_plural": "__count__年前",
"yearMonthsV": "__y__年, __count__月前",
"yearMonthsV_plural": "__y__年, __count__月前",
"yearsMonthsV": "__y__年, __count__月前",
"yearsMonthsV_plural": "__y__年, __count__月前"
"minutesV": "__count__ 分前",
"hoursV": "__count__ 小時前",
"hoursV_plural": "__count__ 小時前",
"daysV": "__count__ 天前",
"daysV_plural": "__count__ 天前",
"weeksV": "__count__ 周前",
"weeksV_plural": "__count__ 周前",
"monthsV": "__count__ 月前",
"monthsV_plural": "__count__ 月前",
"yearsV": "__count__ 年前",
"yearsV_plural": "__count__ 年前",
"yearMonthsV": "__y__ 年, __count__ 月前",
"yearMonthsV_plural": "__y__ 年, __count__ 月前",
"yearsMonthsV": "__y__ 年, __count__ 月前",
"yearsMonthsV_plural": "__y__ 年, __count__ 月前"
},
"nodeCount": "__label__個節點",
"nodeCount_plural": "__label__個節點",
"moduleCount": "__count__個可用模組",
"moduleCount_plural": "__count__個可用模組",
"nodeCount": "__label__ 個節點",
"nodeCount_plural": "__label__ 個節點",
"moduleCount": "__count__ 個可用模組",
"moduleCount_plural": "__count__ 個可用模組",
"inuse": "使用中",
"enableall": "全部啟用",
"disableall": "全部禁用",
"enable": "啟用",
"disable": "禁用",
"remove": "移除",
"update": "更新至__version__版本",
"update": "更新至 __version__ 版本",
"updated": "已更新",
"install": "安裝",
"installed": "已安裝",
@@ -498,7 +532,7 @@
"sort": "排序:",
"sortAZ": "a-z順序",
"sortRecent": "日期順序",
"more": "增加__count__個",
"more": "增加 __count__ 個",
"errors": {
"catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制臺瞭解更多資訊",
"installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊",
@@ -539,6 +573,7 @@
"label": "信息",
"node": "節點",
"type": "類型",
"group": "組",
"module": "Module",
"id": "ID",
"status": "狀態",
@@ -560,8 +595,30 @@
"subflowDesc": "子流程描述",
"nodeHelp": "節點幫助",
"none": "無",
"arrayItems": "__count__個項目",
"showTips": "您可以從設置面板啟用提示資訊"
"arrayItems": "__count__ 個項目",
"showTips": "您可以從設置面板啟用提示資訊",
"outline": "大綱",
"empty": "空的",
"globalConfig": "全局配置節點",
"triggerAction": "觸發動作",
"find": "在工作區中查找",
"search": {
"configNodes": "配置節點",
"unusedConfigNodes": "未使用的配置節點",
"invalidNodes": "無效的節點",
"uknownNodes": "未知的節點",
"unusedSubflows": "未使用的子流程"
}
},
"help": {
"name": "幫助",
"label": "幫助",
"search": "搜索幫助",
"nodeHelp": "節點幫助",
"showHelp": "顯示幫助",
"showInOutline": "在大綱中顯示",
"showTopics": "顯示主題",
"noHelp": "未選擇幫助主題"
},
"config": {
"name": "配置節點",
@@ -614,9 +671,9 @@
"removeFromProject": "從項目中刪除",
"addToProject": "添加到項目",
"files": "文件",
"package": "包",
"flow": "流程",
"credentials": "證書",
"package": "包",
"packageCreate": "保存更改後將創建文件",
"fileNotExist": "文件不存在",
"selectFile": "選擇文件",
@@ -668,7 +725,7 @@
"copyPublicKey": "將公鑰複製到剪貼板",
"delete": "刪除密鑰",
"gitConfig": "Git配置",
"deleteConfirm": "您確定要刪除SSH密鑰__name__嗎 這不能被撤消。"
"deleteConfirm": "您確定要刪除SSH密鑰 __name__ 嗎? 這不能被撤消。"
},
"versionControl": {
"unstagedChanges": "未暫存的更改",
@@ -722,24 +779,24 @@
"pullChanges": "Pull變更",
"history": "歷史",
"projectHistory": "項目歷史",
"daysAgo": "__count__天前",
"daysAgo_plural": "__count__天前",
"hoursAgo": "__count__小時前",
"hoursAgo_plural": "__count__小時前",
"minsAgo": "__count__分鐘前",
"minsAgo_plural": "__count__分鐘前",
"daysAgo": "__count__ 天前",
"daysAgo_plural": "__count__ 天前",
"hoursAgo": "__count__ 小時前",
"hoursAgo_plural": "__count__ 小時前",
"minsAgo": "__count__ 分鐘前",
"minsAgo_plural": "__count__ 分鐘前",
"secondsAgo": "秒前",
"notTracking": "您的本地分支當前未跟蹤遠程分支。",
"statusUnmergedChanged": "您的存儲庫中有未合併的更改。您需要解決衝突並提交結果。",
"repositoryUpToDate": "您的存儲庫是最新的。",
"commitsAhead": "您的倉庫領先遠程倉庫__count__次提交。您現在可以push這些提交。",
"commitsAhead_plural": "您的倉庫領先遠程倉庫__count__次提交。您現在可以push這些提交。",
"commitsBehind": "您的倉庫落後遠程倉庫__count__次提交。您現在可以pull這些提交。",
"commitsBehind_plural": "您的倉庫落後遠程倉庫__count__次提交。您現在可以pull這些提交。",
"commitsAheadAndBehind1": "您的倉庫落後遠程倉庫__count__次提交",
"commitsAheadAndBehind1_plural": "您的倉庫落後遠程倉庫__count__次提交",
"commitsAheadAndBehind2": "領先遠程倉庫__count__次提交。",
"commitsAheadAndBehind2_plural": "領先遠程倉庫__count__次提交。",
"commitsAhead": "您的倉庫領先遠程倉庫 __count__ 次提交。您現在可以push這些提交。",
"commitsAhead_plural": "您的倉庫領先遠程倉庫 __count__ 次提交。您現在可以push這些提交。",
"commitsBehind": "您的倉庫落後遠程倉庫 __count__ 次提交。您現在可以pull這些提交。",
"commitsBehind_plural": "您的倉庫落後遠程倉庫 __count__ 次提交。您現在可以pull這些提交。",
"commitsAheadAndBehind1": "您的倉庫落後遠程倉庫 __count__ 次提交",
"commitsAheadAndBehind1_plural": "您的倉庫落後遠程倉庫 __count__ 次提交",
"commitsAheadAndBehind2": "領先遠程倉庫 __count__ 次提交。",
"commitsAheadAndBehind2_plural": "領先遠程倉庫 __count__ 次提交。",
"commitsAheadAndBehind3": "您必須先pull遠程提交然後再進行push。",
"commitsAheadAndBehind3_plural": "您必須先pull遠程提交然後再進行push。",
"refreshCommitHistory": "刷新提交歷史",
@@ -757,7 +814,8 @@
"bin": "二進位流",
"date": "時間戳記",
"jsonata": "expression",
"env": "env variable"
"env": "env variable",
"cred": "證書"
}
},
"editableList": {
@@ -977,7 +1035,8 @@
"passphrase": "密碼短語",
"retry": "重試",
"update-failed": "無法更新身份驗證",
"unhandled": "未處理的錯誤響應"
"unhandled": "未處理的錯誤響應",
"host-key-verify-failed": "<p>主機密鑰驗證失敗。</p><p>無法驗證存儲庫主機密鑰。請更新您的<code>known_hosts</code>文件,然後重試。</p>"
},
"create-branch-list": {
"invalid": "無效的分支",

View File

@@ -266,5 +266,9 @@
"$type": {
"args": "value",
"desc": "以字符串形式返回`值`的類型。 如果該`值`未定義,則將返回`未定義`"
},
"$moment": {
"args": "[str]",
"desc": "使用Moment庫獲取日期對象。"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "1.0.4",
"version": "1.1.2",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -32,14 +32,19 @@
}
}
}
function emit(evt,arg) {
function emit() {
var evt = arguments[0]
var args = Array.prototype.slice.call(arguments,1);
if (RED.events.DEBUG) {
console.warn(evt,args);
}
if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) {
try {
handlers[evt][i](arg);
handlers[evt][i].apply(null, args);
} catch(err) {
console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.log(err);
console.warn("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.warn(err);
}
}

View File

@@ -66,6 +66,14 @@ RED.history = (function() {
}
inverseEv.nodes.push(node);
RED.nodes.remove(ev.nodes[i]);
if (node.g) {
var group = RED.nodes.group(node.g);
var index = group.nodes.indexOf(node);
if (index !== -1) {
group.nodes.splice(index,1);
RED.group.markDirty(group);
}
}
}
}
if (ev.links) {
@@ -77,10 +85,12 @@ RED.history = (function() {
}
if (ev.groups) {
inverseEv.groups = [];
for (i=0;i<ev.groups.length;i++) {
for (i = ev.groups.length - 1;i>=0;i--) {
group = ev.groups[i];
modifiedTabs[group.z] = true;
inverseEv.groups.push(group);
// The order of groups is important
// - to invert the action, the order is reversed
inverseEv.groups.unshift(group);
RED.nodes.removeGroup(group);
}
}
@@ -196,22 +206,26 @@ RED.history = (function() {
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
n.inputs = subflow.in.length;
n.outputs = subflow.out.length;
while (n.outputs > n.ports.length) {
n.ports.push(n.ports.length);
}
n.resize = true;
n.dirty = true;
});
}
if (ev.groups) {
inverseEv.groups = [];
var groupsToAdd = new Set(ev.groups.map(function(g) { return g.id }));
for (i=0;i<ev.groups.length;i++) {
var groupsToAdd = {};
ev.groups.forEach(function(g) { groupsToAdd[g.id] = g; });
for (i = ev.groups.length - 1;i>=0;i--) {
RED.nodes.addGroup(ev.groups[i])
modifiedTabs[ev.groups[i].z] = true;
inverseEv.groups.push(ev.groups[i]);
if (ev.groups[i].g && !groupsToAdd.has(ev.groups[i].g)) {
group = RED.nodes.group(ev.groups[i].g);
// The order of groups is important
// - to invert the action, the order is reversed
inverseEv.groups.unshift(ev.groups[i]);
if (ev.groups[i].g) {
if (!groupsToAdd[ev.groups[i].g]) {
group = RED.nodes.group(ev.groups[i].g);
} else {
group = groupsToAdd[ev.groups[i].g];
}
if (group.nodes.indexOf(ev.groups[i]) === -1) {
group.nodes.push(ev.groups[i]);
}
@@ -260,9 +274,12 @@ RED.history = (function() {
}
node.dirty = true;
}
RED.events.emit("nodes:change",node);
}
}
}
if (subflow) {
RED.events.emit("subflows:change", subflow);
}
} else if (ev.t == "move") {
inverseEv = {
@@ -294,7 +311,7 @@ RED.history = (function() {
}
}
if (ev.addToGroup) {
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),true);
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false);
inverseEv.removeFromGroup = ev.addToGroup;
} else if (ev.removeFromGroup) {
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
@@ -314,15 +331,28 @@ RED.history = (function() {
var currentConfigNode = RED.nodes.node(ev.node[i]);
if (currentConfigNode) {
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
RED.events.emit("nodes:change",currentConfigNode);
}
var newConfigNode = RED.nodes.node(ev.changes[i]);
if (newConfigNode) {
newConfigNode.users.push(ev.node);
RED.events.emit("nodes:change",newConfigNode);
}
}
ev.node[i] = ev.changes[i];
}
}
var eventType;
switch(ev.node.type) {
case 'tab': eventType = "flows"; break;
case 'group': eventType = "groups"; break;
case 'subflow': eventType = "subflows"; break;
default: eventType = "nodes"; break;
}
eventType += ":change";
RED.events.emit(eventType,ev.node);
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
@@ -382,6 +412,7 @@ RED.history = (function() {
}
}
}
ev.node.__outputs = inverseEv.changes.outputs;
RED.editor.updateNodeProperties(ev.node,outputMap);
RED.editor.validateNode(ev.node);
}
@@ -549,6 +580,11 @@ RED.history = (function() {
}
}
if(ev.callback && typeof ev.callback === 'function') {
inverseEv.callback = ev.callback;
ev.callback(ev);
}
Object.keys(modifiedTabs).forEach(function(id) {
var subflow = RED.nodes.subflow(id);
if (subflow) {
@@ -559,7 +595,6 @@ RED.history = (function() {
RED.nodes.dirty(ev.dirty);
RED.view.updateActive();
RED.view.select(null);
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
RED.subflow.refresh();

View File

@@ -10,6 +10,7 @@
"ctrl-escape": "core:cancel-edit-tray",
"ctrl-d": "core:deploy-flows",
"ctrl-g i": "core:show-info-tab",
"ctrl-g h": "core:show-help-tab",
"ctrl-g d": "core:show-debug-tab",
"ctrl-g c": "core:show-config-tab",
"ctrl-g x": "core:show-context-tab",

View File

@@ -36,7 +36,7 @@ RED.nodes = (function() {
function setDirty(d) {
dirty = d;
RED.events.emit("nodes:change",{dirty:dirty});
RED.events.emit("workspace:dirty",{dirty:dirty});
}
var registry = (function() {
@@ -196,18 +196,17 @@ RED.nodes = (function() {
if (n.type.indexOf("subflow") !== 0) {
n["_"] = n._def._;
} else {
var subflowId = n.type.substring(8);
var sf = RED.nodes.subflow(subflowId);
if (sf) {
sf.instances.push(sf);
}
n["_"] = RED._;
}
if (n._def.category == "config") {
configNodes[n.id] = n;
} else {
n.ports = [];
if (n.wires && (n.wires.length > n.outputs)) { n.outputs = n.wires.length; }
if (n.outputs) {
for (var i=0;i<n.outputs;i++) {
n.ports.push(i);
}
}
n.dirty = true;
updateConfigNodeUsers(n);
if (n._def.category == "subflows" && typeof n.i === "undefined") {
@@ -228,6 +227,7 @@ RED.nodes = (function() {
}
function addLink(l) {
links.push(l);
RED.events.emit("links:add",l);
}
function getNode(id) {
@@ -260,7 +260,7 @@ RED.nodes = (function() {
delete nodeTabMap[node.z][node.id];
}
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
removedLinks.forEach(function(l) {links.splice(links.indexOf(l), 1); });
removedLinks.forEach(removeLink);
var updatedConfigNode = false;
for (var d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) {
@@ -283,6 +283,15 @@ RED.nodes = (function() {
}
}
}
if (node.type.indexOf("subflow:") === 0) {
var subflowId = node.type.substring(8);
var sf = RED.nodes.subflow(subflowId);
if (sf) {
sf.instances.splice(sf.instances.indexOf(node),1);
}
}
if (updatedConfigNode) {
RED.workspaces.refresh();
}
@@ -296,6 +305,9 @@ RED.nodes = (function() {
RED.events.emit('nodes:remove',node);
}
}
if (node && node._def.onremove) {
// Deprecated: never documented but used by some early nodes
console.log("Deprecated API warning: node type ",node.type," has an onremove function - should be oneditremove - please report");
@@ -317,6 +329,7 @@ RED.nodes = (function() {
}
nodeTabMap[z][node.id] = node;
node.z = z;
RED.events.emit("nodes:change",node);
}
function moveGroupToTab(group, z) {
var index = groupsByZ[group.z].indexOf(group);
@@ -324,6 +337,7 @@ RED.nodes = (function() {
groupsByZ[z] = groupsByZ[z] || [];
groupsByZ[z].push(group);
group.z = z;
RED.events.emit("groups:change",group);
}
function removeLink(l) {
@@ -331,6 +345,7 @@ RED.nodes = (function() {
if (index != -1) {
links.splice(index,1);
}
RED.events.emit("links:remove",l);
}
function addWorkspace(ws,targetIndex) {
@@ -343,43 +358,61 @@ RED.nodes = (function() {
} else {
workspacesOrder.splice(targetIndex,0,ws.id);
}
RED.events.emit('flows:add',ws);
if (targetIndex !== undefined) {
RED.events.emit('flows:reorder',workspacesOrder)
}
}
function getWorkspace(id) {
return workspaces[id];
}
function removeWorkspace(id) {
delete workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var ws = workspaces[id];
var removedNodes = [];
var removedLinks = [];
var removedGroups = [];
var n;
var node;
for (n=0;n<nodes.length;n++) {
node = nodes[n];
if (node.z == id) {
removedNodes.push(node);
}
}
for(n in configNodes) {
if (configNodes.hasOwnProperty(n)) {
node = configNodes[n];
if (ws) {
delete workspaces[id];
delete nodeTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var i;
var node;
for (i=0;i<nodes.length;i++) {
node = nodes[i];
if (node.z == id) {
removedNodes.push(node);
}
}
}
removedGroups = groupsByZ[id] || [];
removedGroups.forEach(function(g) {
delete groups[g.id]
})
delete groupsByZ[id];
for(i in configNodes) {
if (configNodes.hasOwnProperty(i)) {
node = configNodes[i];
if (node.z == id) {
removedNodes.push(node);
}
}
}
for (n=0;n<removedNodes.length;n++) {
var result = removeNode(removedNodes[n].id);
removedLinks = removedLinks.concat(result.links);
for (i=0;i<removedNodes.length;i++) {
var result = removeNode(removedNodes[i].id);
removedLinks = removedLinks.concat(result.links);
}
// Must get 'removedGroups' in the right order.
// - start with the top-most groups
// - then recurse into them
removedGroups = (groupsByZ[id] || []).filter(function(g) { return !g.g; });
for (i=0;i<removedGroups.length;i++) {
removedGroups[i].nodes.forEach(function(n) {
if (n.type === "group") {
removedGroups.push(n);
}
});
}
// Now remove them in the reverse order
for (i=removedGroups.length-1; i>=0; i--) {
removeGroup(removedGroups[i]);
}
RED.events.emit('flows:remove',ws);
}
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
}
@@ -437,15 +470,20 @@ RED.nodes = (function() {
module: "node-red"
}
});
sf.instances = [];
sf._def = RED.nodes.getType("subflow:"+sf.id);
RED.events.emit("subflows:add",sf);
}
function getSubflow(id) {
return subflows[id];
}
function removeSubflow(sf) {
delete subflows[sf.id];
delete nodeTabMap[sf.id];
registry.removeNodeType("subflow:"+sf.id);
if (subflows[sf.id]) {
delete subflows[sf.id];
delete nodeTabMap[sf.id];
registry.removeNodeType("subflow:"+sf.id);
RED.events.emit("subflows:remove",sf);
}
}
function subflowContains(sfid,nodeid) {
@@ -573,7 +611,9 @@ RED.nodes = (function() {
node.y = n.y;
node.w = n.w;
node.h = n.h;
node.nodes = node.nodes.map(function(n) { return n.id });
// In 1.1.0, we have seen an instance of this array containing `undefined`
// Until we know how that can happen, add a filter here to remove them
node.nodes = node.nodes.filter(function(n) { return !!n }).map(function(n) { return n.id });
}
if (n._def.category != "config") {
node.x = n.x;
@@ -953,7 +993,7 @@ RED.nodes = (function() {
var workspace_map = {};
var new_subflows = [];
var subflow_map = {};
var subflow_blacklist = {};
var subflow_denylist = {};
var node_map = {};
var new_nodes = [];
var new_links = [];
@@ -986,7 +1026,7 @@ RED.nodes = (function() {
} else if (n.type === "subflow") {
var matchingSubflow = checkForMatchingSubflow(n,nodeZmap[n.id]);
if (matchingSubflow) {
subflow_blacklist[n.id] = matchingSubflow;
subflow_denylist[n.id] = matchingSubflow;
} else {
subflow_map[n.id] = n;
if (createNewIds) {
@@ -1037,7 +1077,7 @@ RED.nodes = (function() {
var existingConfigNode = null;
if (createNewIds) {
if (n.z) {
if (subflow_blacklist[n.z]) {
if (subflow_denylist[n.z]) {
continue;
} else if (subflow_map[n.z]) {
n.z = subflow_map[n.z].id;
@@ -1108,7 +1148,6 @@ RED.nodes = (function() {
}
node_map[n.id] = configNode;
new_nodes.push(configNode);
RED.nodes.add(configNode);
}
}
}
@@ -1145,7 +1184,7 @@ RED.nodes = (function() {
node.g = n.g;
}
if (createNewIds) {
if (subflow_blacklist[n.z]) {
if (subflow_denylist[n.z]) {
continue;
} else if (subflow_map[node.z]) {
node.z = subflow_map[node.z].id;
@@ -1192,7 +1231,7 @@ RED.nodes = (function() {
node._config.y = node.y;
} else if (n.type.substring(0,7) === "subflow") {
var parentId = n.type.split(":")[1];
var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
var subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId);
if (createNewIds) {
parentId = subflow.id;
node.type = "subflow:"+parentId;
@@ -1211,7 +1250,7 @@ RED.nodes = (function() {
defaults: {},
label: "unknown: "+n.type,
labelStyle: "red-ui-flow-node-label-italic",
outputs: n.outputs||n.wires.length,
outputs: n.outputs|| (n.wires && n.wires.length) || 0,
set: registry.getNodeSet("node-red/unknown")
}
} else {
@@ -1280,12 +1319,6 @@ RED.nodes = (function() {
}
}
}
if (node.type !== "group") {
addNode(node);
RED.editor.validateNode(node);
} else {
addGroup(node);
}
node_map[n.id] = node;
// If an 'unknown' config node, it will not have been caught by the
// proper config node handling, so needs adding to new_nodes here
@@ -1335,9 +1368,9 @@ RED.nodes = (function() {
for (var d3 in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d3)) {
if (n._def.defaults[d3].type && node_map[n[d3]]) {
n[d3] = node_map[n[d3]].id;
configNode = RED.nodes.node(n[d3]);
if (configNode && configNode.users.indexOf(n) === -1) {
configNode = node_map[n[d3]];
n[d3] = configNode.id;
if (configNode.users.indexOf(n) === -1) {
configNode.users.push(n);
}
} else if (nodeTypeArrayReferences.hasOwnProperty(n.type) && nodeTypeArrayReferences[n.type] === d3 && n[d3] !== undefined && n[d3] !== null) {
@@ -1358,10 +1391,6 @@ RED.nodes = (function() {
return (otherNode && otherNode.z === activeWorkspace)
});
}
// With all properties now remapped to point at valid nodes,
// we can validate the node
RED.editor.validateNode(n);
}
for (i=0;i<new_subflows.length;i++) {
n = new_subflows[i];
@@ -1400,6 +1429,8 @@ RED.nodes = (function() {
delete n.status.wires;
}
}
// Order the groups to ensure they are outer-most to inner-most
var groupDepthMap = {};
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
if (n.g && node_map[n.g]) {
@@ -1410,6 +1441,53 @@ RED.nodes = (function() {
n.nodes = n.nodes.map(function(id) {
return node_map[id];
})
// Just in case the group references a node that doesn't exist for some reason
n.nodes = n.nodes.filter(function(v) {
if (v) {
// Repair any nodes that have forgotten they are in this group
if (v.g !== n.id) {
v.g = n.id;
}
}
return !!v
});
if (!n.g) {
groupDepthMap[n.id] = 0;
}
}
var changedDepth;
do {
changedDepth = false;
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
if (n.g) {
if (groupDepthMap[n.id] !== groupDepthMap[n.g] + 1) {
groupDepthMap[n.id] = groupDepthMap[n.g] + 1;
changedDepth = true;
}
}
}
} while(changedDepth);
new_groups.sort(function(A,B) {
return groupDepthMap[A.id] - groupDepthMap[B.id];
});
for (i=0;i<new_groups.length;i++) {
n = new_groups[i];
addGroup(n);
}
// Now the nodes have been fully updated, add them.
for (i=0;i<new_nodes.length;i++) {
var node = new_nodes[i];
addNode(node);
}
// Finally validate them all.
// This has to be done after everything is added so that any checks for
// dependent config nodes will pass
for (i=0;i<new_nodes.length;i++) {
var node = new_nodes[i];
RED.editor.validateNode(node);
}
RED.workspaces.refresh();
@@ -1518,12 +1596,14 @@ RED.nodes = (function() {
defaultWorkspace = null;
initialLoad = null;
RED.nodes.dirty(false);
RED.view.redraw(true);
RED.view.redraw(true, true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
RED.sidebar.info.refresh();
RED.events.emit("workspace:clear");
// var node_defs = {};
// var nodes = [];
// var configNodes = {};
@@ -1539,11 +1619,14 @@ RED.nodes = (function() {
groupsByZ[group.z] = groupsByZ[group.z] || [];
groupsByZ[group.z].push(group);
groups[group.id] = group;
RED.events.emit("groups:add",group);
}
function removeGroup(group) {
var i = groupsByZ[group.z].indexOf(group);
groupsByZ[group.z].splice(i,1);
if (groupsByZ[group.z].length === 0) {
delete groupsByZ[group.z];
}
if (group.g) {
if (groups[group.g]) {
var index = groups[group.g].nodes.indexOf(group);
@@ -1553,6 +1636,7 @@ RED.nodes = (function() {
RED.group.markDirty(group);
delete groups[group.id];
RED.events.emit("groups:remove",group);
}
@@ -1587,6 +1671,7 @@ RED.nodes = (function() {
}
}
reimportList.push(convertNode(n));
RED.events.emit('nodes:remove',n);
});
// Remove any links between nodes that are going to be reimported.

View File

@@ -0,0 +1,41 @@
(function() {
var isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
if (isIE11) {
// IE11 DOMTokenList.toggle does not support the two-argument variety
window.DOMTokenList.prototype.toggle = function(cl,bo) {
if (arguments.length === 1) {
bo = !this.contains(cl);
}
this[!!bo?"add":"remove"](cl);
}
// IE11 does not provide classList on SVGElements
if (! ("classList" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'classList', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'classList'));
}
// IE11 does not provide children on SVGElements
if (! ("children" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'children', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children'));
}
Array.from = function() {
if (arguments.length > 1) {
throw new Error("Node-RED's IE11 Array.from polyfill doesn't support multiple arguments");
}
var arrayLike = arguments[0]
var result = [];
if (arrayLike.forEach) {
arrayLike.forEach(function(i) {
result.push(i);
})
} else {
for (var i=0;i<arrayLike.length;i++) {
result.push(arrayList[i]);
}
}
return result;
}
}
})();

View File

@@ -75,6 +75,7 @@ var RED = (function() {
}
function loadNodeList() {
loader.reportProgress(RED._("event.loadPalette"), 20)
$.ajax({
headers: {
"Accept":"application/json"
@@ -83,6 +84,7 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
RED.nodes.setNodeList(data);
loader.reportProgress(RED._("event.loadNodeCatalogs"), 25)
RED.i18n.loadNodeCatalogs(function() {
loadIconList(loadNodes);
});
@@ -107,6 +109,7 @@ var RED = (function() {
}
function loadNodes() {
loader.reportProgress(RED._("event.loadNodes",{count:""}), 30)
var lang = localStorage.getItem("editor-language")||i18n.detectLanguage();
$.ajax({
@@ -118,15 +121,19 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
var totalCount = configs.length;
var stepConfig = function() {
loader.reportProgress(RED._("event.loadNodes",{count:(totalCount-configs.length)+"/"+totalCount}), 30 + ((totalCount-configs.length)/totalCount)*40 )
if (configs.length === 0) {
$("#red-ui-editor").i18n();
$("#red-ui-palette > .red-ui-palette-spinner").hide();
$(".red-ui-palette-scroll").removeClass("hide");
$("#red-ui-palette-search").removeClass("hide");
loadFlows(function() {
if (RED.settings.theme("projects.enabled",false)) {
RED.projects.refresh(function(activeProject) {
if (RED.settings.theme("projects.enabled",false)) {
RED.projects.refresh(function(activeProject) {
loadFlows(function() {
RED.sidebar.info.refresh()
if (!activeProject) {
// Projects enabled but no active project
@@ -140,12 +147,14 @@ var RED = (function() {
}
completeLoad();
});
} else {
});
} else {
loadFlows(function() {
// Projects disabled by the user
RED.sidebar.info.refresh()
completeLoad();
}
});
});
}
} else {
var config = configs.shift();
appendNodeConfig(config,stepConfig);
@@ -157,6 +166,7 @@ var RED = (function() {
}
function loadFlows(done) {
loader.reportProgress(RED._("event.loadFlows"),80 )
$.ajax({
headers: {
"Accept":"application/json",
@@ -167,6 +177,7 @@ var RED = (function() {
if (nodes) {
var currentHash = window.location.hash;
RED.nodes.version(nodes.rev);
loader.reportProgress(RED._("event.importFlows"),90 )
RED.nodes.import(nodes.flows);
RED.nodes.dirty(false);
RED.view.redraw(true);
@@ -193,6 +204,7 @@ var RED = (function() {
return;
}
if (notificationId === "project-update") {
loader.start("Loading project",0)
RED.nodes.clear();
RED.history.clear();
RED.view.redraw(true);
@@ -208,6 +220,7 @@ var RED = (function() {
"revert": RED._("notification.project.revert", {project: msg.project}),
"merge-complete": RED._("notification.project.merge-complete")
}[msg.action];
loader.end()
RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh()
});
@@ -353,13 +366,13 @@ var RED = (function() {
var parts = topic.split("/");
var node = RED.nodes.node(parts[1]);
if (node) {
if (msg.hasOwnProperty("text") && /^[a-zA-Z]/.test(msg.text)) {
if (msg.hasOwnProperty("text") && msg.text !== null && /^[a-zA-Z]/.test(msg.text)) {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
}
node.status = msg;
node.dirtyStatus = true;
node.dirty = true;
RED.view.redraw();
RED.view.redrawStatus(node);
}
});
RED.comms.subscribe("notification/node/#",function(topic,msg) {
@@ -423,6 +436,12 @@ var RED = (function() {
var id = topic.substring(9);
RED.eventLog.log(id,payload);
});
$(".red-ui-header-toolbar").show();
setTimeout(function() {
loader.end();
},100);
}
function showAbout() {
@@ -431,8 +450,7 @@ var RED = (function() {
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
RED.sidebar.info.set(aboutHeader+RED.utils.renderMarkdown(data));
RED.sidebar.info.show();
RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data));
});
}
@@ -505,7 +523,6 @@ var RED = (function() {
}
function loadEditor() {
RED.workspaces.init();
RED.statusBar.init();
RED.view.init();
@@ -548,13 +565,14 @@ var RED = (function() {
RED.comms.connect();
$("#red-ui-main-container").show();
$(".red-ui-header-toolbar").show();
RED.actions.add("core:show-about", showAbout);
loadNodeList();
}
function buildEditor(options) {
var header = $('<div id="red-ui-header"></div>').appendTo(options.target);
var logo = $('<span class="red-ui-header-logo"></span>').appendTo(header);
@@ -569,6 +587,10 @@ var RED = (function() {
'</div>').appendTo(options.target);
$('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target);
$('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target);
loader.init().appendTo("#red-ui-main-container");
loader.start("...",0);
$.getJSON(options.apiRootUrl+"theme", function(theme) {
if (theme.header) {
if (theme.header.url) {
@@ -601,12 +623,39 @@ var RED = (function() {
options.target.addClass("red-ui-editor");
buildEditor(options);
RED.i18n.init(options, function() {
RED.settings.init(options, loadEditor);
})
}
var loader = {
init: function() {
var wrapper = $('<div id="red-ui-loading-progress"></div>').hide();
var container = $('<div>').appendTo(wrapper);
var label = $('<div>',{class:"red-ui-loading-bar-label"}).appendTo(container);
var bar = $('<div>',{class:"red-ui-loading-bar"}).appendTo(container);
var fill =$('<span>').appendTo(bar);
return wrapper;
},
start: function(text, prcnt) {
if (text) {
loader.reportProgress(text,prcnt)
}
$("#red-ui-loading-progress").show();
},
reportProgress: function(text, prcnt) {
$(".red-ui-loading-bar-label").text(text);
$(".red-ui-loading-bar span").width(prcnt+"%")
},
end: function() {
$("#red-ui-loading-progress").hide();
loader.reportProgress("",0);
}
}
return {
init: init
init: init,
loader: loader
}
})();

View File

@@ -159,7 +159,11 @@ RED.clipboard = (function() {
}
}
],
open: function( event, ui ) {
RED.keyboard.disable();
},
close: function(e) {
RED.keyboard.enable();
if (popover) {
popover.close(true);
currentPopoverError = null;
@@ -184,7 +188,7 @@ RED.clipboard = (function() {
'</div>'+
'<div id="red-ui-clipboard-dialog-export-tabs-content" class="red-ui-clipboard-dialog-tabs-content">'+
'<div id="red-ui-clipboard-dialog-export-tab-clipboard" class="red-ui-clipboard-dialog-tab-clipboard">'+
'<div class="form-row">'+
'<div class="form-row" style="height:calc(100% - 30px)">'+
'<textarea readonly id="red-ui-clipboard-dialog-export-text"></textarea>'+
'</div>'+
'<div class="form-row" style="text-align: right;">'+
@@ -216,7 +220,7 @@ RED.clipboard = (function() {
' <a class="red-ui-button" id="red-ui-clipboard-dialog-import-file-upload-btn"><i class="fa fa-upload"></i> <span data-i18n="clipboard.selectFile"></span></a>'+
'<input type="file" id="red-ui-clipboard-dialog-import-file-upload" accept=".json" style="display:none">'+
'</div>'+
'<div class="form-row">'+
'<div class="form-row" style="height:calc(100% - 47px)">'+
'<textarea id="red-ui-clipboard-dialog-import-text"></textarea>'+
'</div>'+
'</div>'+
@@ -474,6 +478,12 @@ RED.clipboard = (function() {
},100)
}
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 600) {
dialogHeight = 400 - (600 - winHeight);
}
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
popover = RED.popover.create({
@@ -639,6 +649,14 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
}
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 600) {
dialogHeight = 400 - (600 - winHeight);
}
$(".red-ui-clipboard-dialog-box").height(dialogHeight);
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
@@ -740,6 +758,8 @@ RED.clipboard = (function() {
RED.actions.add("core:show-library-export-dialog",function() { exportNodes('library') });
RED.actions.add("core:show-library-import-dialog",function() { importNodes('library') });
RED.actions.add("core:show-examples-import-dialog",function() { importNodes('examples') });
RED.events.on("editor:open",function() { disabled = true; });
RED.events.on("editor:close",function() { disabled = false; });
RED.events.on("search:open",function() { disabled = true; });

View File

@@ -1,25 +1,5 @@
RED.colorPicker = (function() {
function getDarkerColor(c) {
var r,g,b;
if (/^#[a-f0-9]{6}$/i.test(c)) {
r = parseInt(c.substring(1, 3), 16);
g = parseInt(c.substring(3, 5), 16);
b = parseInt(c.substring(5, 7), 16);
} else if (/^#[a-f0-9]{3}$/i.test(c)) {
r = parseInt(c.substring(1, 2)+c.substring(1, 2), 16);
g = parseInt(c.substring(2, 3)+c.substring(2, 3), 16);
b = parseInt(c.substring(3, 4)+c.substring(3, 4), 16);
} else {
return c;
}
var l = 0.3 * r/255 + 0.59 * g/255 + 0.11 * b/255 ;
r = Math.max(0,r-50);
g = Math.max(0,g-50);
b = Math.max(0,b-50);
return '#'+((r<<16) + (g<<8) + b).toString(16).padStart(6,'0')
}
function create(options) {
var color = options.value;
var id = options.id;
@@ -56,7 +36,7 @@ RED.colorPicker = (function() {
"background-color": color,
"opacity": opacity
});
var border = getDarkerColor(color);
var border = RED.utils.getDarkerColor(color);
if (border[0] === '#') {
border += Math.round(255*Math.floor(opacity*100)/100).toString(16);
} else {
@@ -93,7 +73,7 @@ RED.colorPicker = (function() {
type:"text",
value:colorHiddenInput.val()
}).appendTo(row);
var focusTarget = colorInput;
colorInput.on("change", function (e) {
var color = colorInput.val();
colorHiddenInput.val(color).trigger('change');
@@ -131,7 +111,7 @@ RED.colorPicker = (function() {
height: height+"px",
margin: margin+"px",
backgroundColor: col,
"border-color": getDarkerColor(col)
"border-color": RED.utils.getDarkerColor(col)
}).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
@@ -208,8 +188,14 @@ RED.colorPicker = (function() {
refreshDisplay(colorHiddenInput.val())
},50);
colorPanel.show({
target: colorButton
target: colorButton,
onclose: function() {
colorButton.focus();
}
})
if (focusTarget) {
focusTarget.focus();
}
});
setTimeout(function() {
refreshDisplay(colorHiddenInput.val())

View File

@@ -33,7 +33,7 @@
* methods:
* - addItem(itemData)
* - insertItemAt : function(data,index) - add an item at the specified index
* - removeItem(itemData)
* - removeItem(itemData, detach) - remove the item. Optionally detach to preserve any event handlers on the item's label
* - getItemAt(index)
* - indexOf(itemData)
* - width(width)
@@ -183,7 +183,7 @@
if (this.options.resizeItem) {
var that = this;
this.element.children().each(function(i) {
that.options.resizeItem($(this).find(".red-ui-editableList-item-content"),i);
that.options.resizeItem($(this).children(".red-ui-editableList-item-content"),i);
});
}
},
@@ -223,7 +223,7 @@
var items = this.element.children();
var that = this;
items.sort(function(A,B) {
return that.activeSort($(A).find(".red-ui-editableList-item-content").data('data'),$(B).find(".red-ui-editableList-item-content").data('data'));
return that.activeSort($(A).children(".red-ui-editableList-item-content").data('data'),$(B).children(".red-ui-editableList-item-content").data('data'));
});
$.each(items,function(idx,li) {
that.element.append(li);
@@ -259,28 +259,6 @@
var that = this;
data = data || {};
var li = $('<li>');
var added = false;
if (this.activeSort) {
var items = this.items();
var skip = false;
items.each(function(i,el) {
if (added) { return }
var itemData = el.data('data');
if (that.activeSort(data,itemData) < 0) {
li.insertBefore(el.closest("li"));
added = true;
}
});
}
if (!added) {
if (index <= 0) {
li.prependTo(this.element);
} else if (index > that.element.children().length-1) {
li.appendTo(this.element);
} else {
li.insertBefore(this.element.children().eq(index));
}
}
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
row.data('data',data);
if (this.options.sortable === true) {
@@ -303,9 +281,31 @@
});
});
}
var added = false;
if (this.activeSort) {
var items = this.items();
var skip = false;
items.each(function(i,el) {
if (added) { return }
var itemData = el.data('data');
if (that.activeSort(data,itemData) < 0) {
li.insertBefore(el.closest("li"));
added = true;
}
});
}
if (!added) {
if (index <= 0) {
li.prependTo(this.element);
} else if (index > that.element.children().length-1) {
li.appendTo(this.element);
} else {
li.insertBefore(this.element.children().eq(index));
}
}
if (this.options.addItem) {
var index = that.element.children().length-1;
setTimeout(function() {
// setTimeout(function() {
that.options.addItem(row,index,data);
if (that.activeFilter) {
try {
@@ -321,7 +321,7 @@
that.uiContainer.scrollTop(that.element.height());
},0);
}
},0);
// },0);
}
},
addItem: function(data) {
@@ -332,17 +332,21 @@
this.addItem(items[i]);
}
},
removeItem: function(data) {
removeItem: function(data,detach) {
var items = this.element.children().filter(function(f) {
return data === $(this).find(".red-ui-editableList-item-content").data('data');
return data === $(this).children(".red-ui-editableList-item-content").data('data');
});
items.remove();
if (detach) {
items.detach();
} else {
items.remove();
}
if (this.options.removeItem) {
this.options.removeItem(data);
}
},
items: function() {
return this.element.children().map(function(i) { return $(this).find(".red-ui-editableList-item-content"); });
return this.element.children().map(function(i) { return $(this).children(".red-ui-editableList-item-content"); });
},
empty: function() {
this.element.empty();
@@ -365,14 +369,14 @@
},
show: function(item) {
var items = this.element.children().filter(function(f) {
return item === $(this).find(".red-ui-editableList-item-content").data('data');
return item === $(this).children(".red-ui-editableList-item-content").data('data');
});
if (items.length > 0) {
this.uiContainer.scrollTop(this.uiContainer.scrollTop()+items.position().top)
}
},
getItem: function(li) {
var el = li.find(".red-ui-editableList-item-content");
var el = li.children(".red-ui-editableList-item-content");
if (el.length) {
return el.data('data');
} else {

View File

@@ -158,7 +158,7 @@ RED.menu = (function() {
activeMenu = null;
topMenu.hide();
});
$(".red-ui-menu").hide();
$(".red-ui-menu.red-ui-menu-dropdown").hide();
topMenu.show();
}
})

View File

@@ -29,6 +29,10 @@ RED.panels = (function() {
if (!vertical) {
container.addClass("red-ui-panels-horizontal");
}
$(children[0]).addClass("red-ui-panel");
$(children[1]).addClass("red-ui-panel");
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
var startPosition;
var panelSizes = [];
@@ -52,11 +56,11 @@ RED.panels = (function() {
var newSizes = [panelSizes[0]+delta,panelSizes[1]-delta];
if (vertical) {
$(children[0]).height(newSizes[0]);
$(children[1]).height(newSizes[1]);
// $(children[1]).height(newSizes[1]);
ui.position.top -= delta;
} else {
$(children[0]).width(newSizes[0]);
$(children[1]).width(newSizes[1]);
// $(children[1]).width(newSizes[1]);
ui.position.left -= delta;
}
if (options.resize) {
@@ -71,6 +75,9 @@ RED.panels = (function() {
var panel = {
ratio: function(ratio) {
if (ratio === undefined) {
return panelRatio;
}
panelRatio = ratio;
modifiedSizes = true;
if (ratio === 0 || ratio === 1) {
@@ -99,10 +106,10 @@ RED.panels = (function() {
panelSizes = [topPanelSize,bottomPanelSize];
if (vertical) {
$(children[0]).outerHeight(panelSizes[0]);
$(children[1]).outerHeight(panelSizes[1]);
// $(children[1]).outerHeight(panelSizes[1]);
} else {
$(children[0]).outerWidth(panelSizes[0]);
$(children[1]).outerWidth(panelSizes[1]);
// $(children[1]).outerWidth(panelSizes[1]);
}
}
if (options.resize) {

View File

@@ -136,6 +136,23 @@ RED.popover = (function() {
closePopup(true);
});
}
if (trigger === 'hover' && options.interactive) {
div.on('mouseenter', function(e) {
clearTimeout(timer);
active = true;
})
div.on('mouseleave', function(e) {
if (timer) {
clearTimeout(timer);
}
if (active) {
timer = setTimeout(function() {
active = false;
closePopup();
},delay.hide);
}
})
}
if (instant) {
div.show();
} else {
@@ -163,8 +180,10 @@ RED.popover = (function() {
if (trigger === 'hover') {
target.on('mouseenter',function(e) {
clearTimeout(timer);
active = true;
timer = setTimeout(openPopup,delay.show);
if (!active) {
active = true;
timer = setTimeout(openPopup,delay.show);
}
});
target.on('mouseleave disabled', function(e) {
if (timer) {
@@ -259,6 +278,85 @@ RED.popover = (function() {
delay: { show: 750, hide: 50 }
});
},
menu: function(options) {
var list = $('<ul class="red-ui-menu"></ul>');
if (options.style === 'compact') {
list.addClass("red-ui-menu-compact");
}
var menuOptions = options.options || [];
var first;
menuOptions.forEach(function(opt) {
var item = $('<li>').appendTo(list);
var link = $('<a href="#"></a>').text(opt.label).appendTo(item);
link.on("click", function(evt) {
evt.preventDefault();
if (opt.onselect) {
opt.onselect();
}
menu.hide();
})
if (!first) { first = link}
})
var container = RED.popover.panel(list);
var menu = {
show: function(opts) {
$(document).on("keydown.red-ui-menu", function(evt) {
var currentItem = list.find(":focus").parent();
if (evt.keyCode === 40) {
evt.preventDefault();
// DOWN
if (currentItem.length > 0) {
if (currentItem.index() === menuOptions.length-1) {
console.log("WARP TO TOP")
// Wrap to top of list
list.children().first().children().first().focus();
} else {
console.log("GO DOWN ONE")
currentItem.next().children().first().focus();
}
} else {
list.children().first().children().first().focus();
}
} else if (evt.keyCode === 38) {
evt.preventDefault();
// UP
if (currentItem.length > 0) {
if (currentItem.index() === 0) {
console.log("WARP TO BOTTOM")
// Wrap to bottom of list
list.children().last().children().first().focus();
} else {
console.log("GO UP ONE")
currentItem.prev().children().first().focus();
}
} else {
list.children().last().children().first().focus();
}
} else if (evt.keyCode === 27) {
// ESCAPE
evt.preventDefault();
menu.hide(true);
}
evt.stopPropagation();
})
opts.onclose = function() {
$(document).off("keydown.red-ui-menu");
if (options.onclose) {
options.onclose(true);
}
}
container.show(opts);
},
hide: function(cancelled) {
$(document).off("keydown.red-ui-menu");
container.hide(options.disposeOnClose);
if (options.onclose) {
options.onclose(cancelled);
}
}
}
return menu;
},
panel: function(content) {
var panel = $('<div class="red-ui-editor-dialog red-ui-popover-panel"></div>');
panel.css({ display: "none" });
@@ -266,18 +364,22 @@ RED.popover = (function() {
content.appendTo(panel);
var closeCallback;
function hide() {
function hide(dispose) {
$(document).off("mousedown.red-ui-popover-panel-close");
$(document).off("keydown.red-ui-popover-panel-close");
panel.hide();
panel.css({
height: "auto"
});
panel.remove();
if (dispose !== false) {
panel.remove();
}
}
function show(options) {
var closeCallback = options.onclose;
var target = options.target;
var align = options.align || "left";
var align = options.align || "right";
var offset = options.offset || [0,0];
var pos = target.offset();
var targetWidth = target.width();
@@ -285,7 +387,7 @@ RED.popover = (function() {
var panelHeight = panel.height();
var panelWidth = panel.width();
var top = (targetHeight+pos.top);
var top = (targetHeight+pos.top) + offset[1];
if (top+panelHeight > $(window).height()) {
top -= (top+panelHeight)-$(window).height() + 5;
}
@@ -293,25 +395,35 @@ RED.popover = (function() {
panelHeight.height(panelHeight+top)
top = 0;
}
if (align === "left") {
if (align === "right") {
panel.css({
top: top+"px",
left: (pos.left)+"px",
left: (pos.left+offset[0])+"px",
});
} else if(align === "right") {
} else if (align === "left") {
panel.css({
top: top+"px",
left: (pos.left-panelWidth)+"px",
left: (pos.left-panelWidth+offset[0])+"px",
});
}
panel.slideDown(100);
$(document).on("keydown.red-ui-popover-panel-close", function(event) {
if (event.keyCode === 27) {
// ESCAPE
if (closeCallback) {
closeCallback();
}
hide(options.dispose);
}
});
$(document).on("mousedown.red-ui-popover-panel-close", function(event) {
if(!$(event.target).closest(panel).length && !$(event.target).closest(".red-ui-editor-dialog").length) {
if (closeCallback) {
closeCallback();
}
hide();
hide(options.dispose);
}
// if ($(event.target).closest(target).length) {
// event.preventDefault();

View File

@@ -38,12 +38,17 @@
this.element.addClass("red-ui-searchBox-input");
this.uiContainer = this.element.wrap("<div>").parent();
this.uiContainer.addClass("red-ui-searchBox-container");
if (this.options.style === "compact") {
this.uiContainer.addClass("red-ui-searchBox-compact");
}
if (this.element.parents("form").length === 0) {
var form = this.element.wrap("<form>").parent();
form.addClass("red-ui-searchBox-form");
}
$('<i class="fa fa-search"></i>').prependTo(this.uiContainer);
this.clearButton = $('<a href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer);
this.clearButton = $('<a class="red-ui-searchBox-clear" href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer);
this.clearButton.on("click",function(e) {
e.preventDefault();
that.element.val("");
@@ -51,6 +56,62 @@
that.element.trigger("focus");
});
if (this.options.options) {
this.uiContainer.addClass("red-ui-searchBox-has-options");
this.optsButton = $('<a class="red-ui-searchBox-opts" href="#"><i class="fa fa-caret-down"></i></a>').appendTo(this.uiContainer);
var menuShown = false;
this.optsMenu = RED.popover.menu({
style: this.options.style,
options: this.options.options.map(function(opt) {
return {
label: opt.label,
onselect: function() {
that.element.val(opt.value+" ");
that._change(opt.value,true);
}
}
}),
onclose: function(cancelled) {
menuShown = false;
that.element.trigger("focus");
},
disposeOnClose: false
});
var showMenu = function() {
menuShown = true;
that.optsMenu.show({
target: that.optsButton,
align: "left",
offset: [that.optsButton.width()-2,-1],
dispose: false
})
}
this.optsButton.on("click",function(e) {
e.preventDefault();
if (!menuShown) {
showMenu();
} else {
// TODO: This doesn't quite work because the panel's own
// mousedown handler triggers a close before this click
// handler fires.
that.optsMenu.hide(true);
}
});
this.optsButton.on("keydown",function(e) {
if (!menuShown && e.keyCode === 40) {
//DOWN
showMenu();
}
});
this.element.on("keydown",function(e) {
if (!menuShown && e.keyCode === 40) {
//DOWN
showMenu();
}
});
}
this.resultCount = $('<span>',{class:"red-ui-searchBox-resultCount hide"}).appendTo(this.uiContainer);
this.element.val("");

View File

@@ -153,7 +153,7 @@ RED.tabs = (function() {
if (collapsibleMenu.is(":visible")) {
$(document).off("click.red-ui-tabmenu");
} else {
$(".red-ui-menu").hide();
$(".red-ui-menu.red-ui-menu-dropdown").hide();
$(document).on("click.red-ui-tabmenu", function(evt) {
$(document).off("click.red-ui-tabmenu");
collapsibleMenu.hide();

View File

@@ -27,7 +27,8 @@
*
* methods:
* - data(items) - clears existing items and replaces with new data
*
* - clearSelection - clears the selected items
* - filter(filterFunc) - filters the tree using the provided function
* events:
* - treelistselect : function(event, item) {}
* - treelistconfirm : function(event,item) {}
@@ -39,7 +40,8 @@
* label: 'Local', // label for the item
* sublabel: 'Local', // a sub-label for the item
* icon: 'fa fa-rocket', // (optional) icon for the item
* selected: true/false, // (optional) if present, display checkbox accordingly
* checkbox: true/false, // (optional) if present, display checkbox accordingly
* selected: true/false, // (optional) whether the item is selected or not
* children: [] | function(done,item) // (optional) an array of child items, or a function
* // that will call the `done` callback with an array
* // of child items
@@ -59,11 +61,11 @@
* properties and functions:
*
* item.parent - set to the parent item
* item.depth - the depth in the tree (0 == root)
* item.treeList.container
* item.treeList.label - the label element for the item
* item.treeList.depth - the depth in the tree (0 == root)
* item.treeList.parentList - the editableList instance this item is in
* item.treeList.remove() - removes the item from the tree
* item.treeList.remove(detach) - removes the item from the tree. Optionally detach to preserve any event handlers on the item's label
* item.treeList.makeLeaf(detachChildElements) - turns an element with children into a leaf node,
* removing the UI decoration etc.
* detachChildElements - any children with custom
@@ -78,8 +80,8 @@
* Optionally selects the item after adding.
* item.treeList.expand(done) - expands the parent item to show children. Optional 'done' callback.
* item.treeList.collapse() - collapse the parent item to hide children.
*
*
* item.treeList.sortChildren(sortFunction) - does a one-time sort of the children using sortFunction
* item.treeList.replaceElement(element) - replace the custom element for the item
*
*
*/
@@ -100,6 +102,8 @@
var target;
switch(evt.keyCode) {
case 13: // ENTER
evt.preventDefault();
evt.stopPropagation();
if (selected.children) {
if (selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse()
@@ -112,6 +116,8 @@
break;
case 37: // LEFT
evt.preventDefault();
evt.stopPropagation();
if (selected.children&& selected.treeList.container.hasClass("expanded")) {
selected.treeList.collapse()
} else if (selected.parent) {
@@ -119,6 +125,8 @@
}
break;
case 38: // UP
evt.preventDefault();
evt.stopPropagation();
target = that._getPreviousSibling(selected);
if (target) {
target = that._getLastDescendant(target);
@@ -128,6 +136,8 @@
}
break;
case 39: // RIGHT
evt.preventDefault();
evt.stopPropagation();
if (selected.children) {
if (!selected.treeList.container.hasClass("expanded")) {
selected.treeList.expand()
@@ -135,6 +145,8 @@
}
break
case 40: //DOWN
evt.preventDefault();
evt.stopPropagation();
if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) {
target = selected.children[0];
} else {
@@ -151,7 +163,8 @@
}
});
this._data = [];
this._items = {};
this._selected = new Set();
this._topList = $('<ol class="red-ui-treeList-list">').css({
position:'absolute',
top: 0,
@@ -215,7 +228,7 @@
return candidates[index+1];
}
},
_addChildren: function(container,parent,children,depth) {
_addChildren: function(container,parent,children,depth,onCompleteChildren) {
var that = this;
var subtree = $('<ol class="red-ui-treeList-list">').appendTo(container).editableList({
connectWith: ".red-ui-treeList-sortable",
@@ -244,15 +257,38 @@
that._trigger("changeparent",null,evt);
});
that._trigger("sort",null,parent);
}
},
filter: parent.treeList.childFilter
});
if (!!that.options.sortable) {
subtree.addClass('red-ui-treeList-sortable');
}
for (var i=0;i<children.length;i++) {
children[i].parent = parent;
subtree.editableList('addItem',children[i])
var sliceSize = 30;
var index = 0;
var addSlice = function() {
var start = index;
for (var i=0;i<sliceSize;i++) {
index = start+i;
if (index === children.length) {
setTimeout(function() {
if (onCompleteChildren) {
onCompleteChildren();
}
},10);
return;
}
children[index].parent = parent;
subtree.editableList('addItem',children[index])
}
index++;
if (index < children.length) {
setTimeout(function() {
addSlice();
},10);
}
}
addSlice();
subtree.hide()
return subtree;
},
_fixDepths: function(parent,child) {
@@ -289,23 +325,184 @@
}
return reparentedEvent;
},
_addSubtree: function(parentList, container, item, depth) {
_initItem: function(item,depth) {
if (item.treeList) {
return;
}
var that = this;
this._items[item.id] = item;
item.treeList = {};
item.treeList.depth = depth;
item.treeList.container = container;
item.treeList.parentList = parentList;
item.treeList.remove = function() {
parentList.editableList('removeItem',item);
item.depth = depth;
item.treeList.remove = function(detach) {
if (item.treeList.parentList) {
item.treeList.parentList.editableList('removeItem',item,detach);
}
if (item.parent) {
var index = item.parent.children.indexOf(item);
item.parent.children.splice(index,1)
that._trigger("sort",null,item.parent);
}
that._selected.delete(item);
delete item.treeList;
delete that._items[item.id];
}
item.treeList.insertChildAt = function(newItem,position,select) {
newItem.parent = item;
item.children.splice(position,0,newItem);
var processChildren = function(parent,i) {
that._initItem(i,parent.depth+1)
i.parent = parent;
if (i.children && typeof i.children !== 'function') {
i.children.forEach(function(item) {
processChildren(i, item, parent.depth+2)
});
}
}
processChildren(item,newItem);
if (!item.deferBuild && item.treeList.childList) {
item.treeList.childList.editableList('insertItemAt',newItem,position)
if (select) {
setTimeout(function() {
that.select(newItem)
},100);
}
that._trigger("sort",null,item);
if (that.activeFilter) {
that.filter(that.activeFilter);
}
}
}
item.treeList.addChild = function(newItem,select) {
item.treeList.insertChildAt(newItem,item.children.length,select);
}
item.treeList.expand = function(done) {
if (!item.children) {
if (done) { done(false) }
return;
}
if (!item.treeList.container) {
item.expanded = true;
if (done) { done(false) }
return;
}
var container = item.treeList.container;
if (container.hasClass("expanded")) {
if (done) { done(false) }
return;
}
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
container.addClass('built');
var childrenAdded = false;
var spinner;
var startTime = 0;
var started = Date.now();
var completeBuild = function(children) {
childrenAdded = true;
item.treeList.childList = that._addChildren(container,item,children,depth, function() {
if (done) { done(true) }
that._trigger("childrenloaded",null,item)
});
var delta = Date.now() - startTime;
if (delta < 400) {
setTimeout(function() {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
},400-delta);
} else {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
}
item.expanded = true;
}
if (typeof item.children === 'function') {
item.children(completeBuild,item);
} else {
delete item.deferBuild;
completeBuild(item.children);
}
if (!childrenAdded) {
startTime = Date.now();
spinner = $('<div class="red-ui-treeList-spinner">').css({
"background-position": (35+depth*20)+'px 50%'
}).appendTo(container);
}
} else {
if (that._loadingData || item.children.length > 20) {
item.treeList.childList.show();
} else {
item.treeList.childList.slideDown('fast');
}
item.expanded = true;
if (done) { done(!that._loadingData) }
}
container.addClass("expanded");
}
item.treeList.collapse = function() {
if (!item.children) {
return;
}
item.expanded = false;
if (item.treeList.container) {
if (item.children.length < 20) {
item.treeList.childList.slideUp('fast');
} else {
item.treeList.childList.hide();
}
item.treeList.container.removeClass("expanded");
}
}
item.treeList.sortChildren = function(sortFunc) {
if (!item.children) {
return;
}
item.children.sort(sortFunc);
if (item.treeList.childList) {
// Do a one-off sort of the list, which means calling sort twice:
// 1. first with the desired sort function
item.treeList.childList.editableList('sort',sortFunc);
// 2. and then with null to remove it
item.treeList.childList.editableList('sort',null);
}
}
item.treeList.replaceElement = function (element) {
if (item.element) {
if (item.treeList.container) {
$(item.element).remove();
$(element).appendTo(item.treeList.label);
var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(item.depth*20);
$(element).css({
width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
})
}
item.element = element;
}
}
var label = $("<div>",{class:"red-ui-treeList-label"}).appendTo(container);
if (item.children && typeof item.children !== "function") {
item.children.forEach(function(i) {
that._initItem(i,depth+1);
})
}
},
_addSubtree: function(parentList, container, item, depth) {
var that = this;
this._initItem(item,depth);
// item.treeList = {};
// item.treeList.depth = depth;
item.treeList.container = container;
item.treeList.parentList = parentList;
var label = $("<div>",{class:"red-ui-treeList-label"});
label.appendTo(container);
item.treeList.label = label;
if (item.class) {
label.addClass(item.class);
@@ -357,6 +554,7 @@
treeListIcon.off("click.red-ui-treeList-expand");
delete item.children;
container.removeClass("expanded");
delete item.expanded;
}
item.treeList.makeParent = function(children) {
if (treeListIcon.children().length) {
@@ -385,104 +583,28 @@
})
if (!item.children) {
item.children = children||[];
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
item.treeList.childList = that._addChildren(container,item,item.children,depth);
}
}
item.treeList.insertChildAt = function(newItem,position,select) {
newItem.parent = item;
item.children.splice(position,0,newItem);
if (!item.deferBuild) {
item.treeList.childList.editableList('insertItemAt',newItem,position)
if (select) {
setTimeout(function() {
that.select(newItem)
},100);
}
that._trigger("sort",null,item);
}
}
item.treeList.addChild = function(newItem,select) {
item.treeList.insertChildAt(newItem,item.children.length,select);
}
item.treeList.expand = function(done) {
if (!item.children) {
return;
}
if (container.hasClass("expanded")) {
if (done) { done() }
return;
}
if (!container.hasClass("built") && (item.deferBuild || typeof item.children === 'function')) {
container.addClass('built');
var childrenAdded = false;
var spinner;
var startTime = 0;
var completeBuild = function(children) {
childrenAdded = true;
item.treeList.childList = that._addChildren(container,item,children,depth).hide();
var delta = Date.now() - startTime;
if (delta < 400) {
setTimeout(function() {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
},400-delta);
} else {
item.treeList.childList.slideDown('fast');
if (spinner) {
spinner.remove();
}
}
if (done) { done() }
that._trigger("childrenloaded",null,item)
}
if (typeof item.children === 'function') {
item.children(completeBuild,item);
} else {
delete item.deferBuild;
completeBuild(item.children);
}
if (!childrenAdded) {
startTime = Date.now();
spinner = $('<div class="red-ui-treeList-spinner">').css({
"background-position": (35+depth*20)+'px 50%'
}).appendTo(container);
}
} else {
if (that._loadingData) {
item.treeList.childList.show();
} else {
item.treeList.childList.slideDown('fast');
}
if (done) { done() }
}
container.addClass("expanded");
}
item.treeList.collapse = function() {
if (!item.children) {
return;
}
item.treeList.childList.slideUp('fast');
container.removeClass("expanded");
}
var treeListIcon = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
if (item.children) {
item.treeList.makeParent();
}
if (item.hasOwnProperty('selected')) {
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>').appendTo(label);
if (item.checkbox) {
var selectWrapper = $('<span class="red-ui-treeList-icon"></span>');
var cb = $('<input class="red-ui-treeList-checkbox" type="checkbox">').prop('checked',item.selected).appendTo(selectWrapper);
label.toggleClass("selected",item.selected);
cb.on('click', function(e) {
e.stopPropagation();
});
cb.on('change', function(e) {
item.selected = this.checked;
if (item.selected) {
that._selected.add(item);
} else {
that._selected.delete(item);
}
label.toggleClass("selected",this.checked);
that._trigger("select",e,item);
})
@@ -497,10 +619,15 @@
cb.trigger("click");
}
}
selectWrapper.appendTo(label)
} else {
label.on("click", function(e) {
that._topList.find(".selected").removeClass("selected");
if (!that.options.multi) {
that.clearSelection();
}
label.addClass("selected");
that._selected.add(item);
that._trigger("select",e,item)
})
label.on("dblclick", function(e) {
@@ -508,9 +635,30 @@
that._trigger("confirm",e,item);
}
})
item.treeList.select = function(v) {
if (!that.options.multi) {
that.clearSelection();
}
label.toggleClass("selected",v);
if (v) {
that._selected.add(item);
that._trigger("select",null,item)
} else {
that._selected.delete(item);
}
that.reveal(item);
}
}
label.toggleClass("selected",!!item.selected);
if (item.selected) {
that._selected.add(item);
}
if (item.icon) {
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
if (typeof item.icon === "string") {
$('<span class="red-ui-treeList-icon"><i class="'+item.icon+'" /></span>').appendTo(label);
} else {
$('<span class="red-ui-treeList-icon">').appendTo(label).append(item.icon);
}
}
if (item.hasOwnProperty('label') || item.hasOwnProperty('sublabel')) {
if (item.hasOwnProperty('label')) {
@@ -528,12 +676,13 @@
}
if (item.children) {
if (Array.isArray(item.children) && !item.deferBuild) {
item.treeList.childList = that._addChildren(container,item,item.children,depth).hide();
item.treeList.childList = that._addChildren(container,item,item.children,depth);
}
if (item.expanded) {
item.treeList.expand();
}
}
// label.appendTo(container);
},
empty: function() {
this._topList.editableList('empty');
@@ -542,6 +691,7 @@
var that = this;
if (items !== undefined) {
this._data = items;
this._items = {};
this._topList.editableList('empty');
this._loadingData = true;
for (var i=0; i<items.length;i++) {
@@ -556,33 +706,149 @@
return this._data;
}
},
show: function(id) {
for (var i=0;i<this._data.length;i++) {
if (this._data[i].id === id) {
this._topList.editableList('show',this._data[i]);
show: function(item, done) {
if (typeof item === "string") {
item = this._items[item]
}
if (!item) {
return;
}
var that = this;
var stack = [];
var i = item;
while(i) {
stack.unshift(i);
i = i.parent;
}
var isOpening = false;
var handleStack = function(opening) {
isOpening = isOpening ||opening
var item = stack.shift();
if (stack.length === 0) {
setTimeout(function() {
that.reveal(item);
if (done) { done(); }
},isOpening?200:0);
} else {
item.treeList.expand(handleStack)
}
}
handleStack();
},
select: function(item) {
this._topList.find(".selected").removeClass("selected");
item.treeList.label.addClass("selected");
this._trigger("select",null,item)
reveal: function(item) {
if (typeof item === "string") {
item = this._items[item]
}
if (!item) {
return;
}
var listOffset = this._topList.offset().top;
var itemOffset = item.treeList.label.offset().top;
var scrollTop = this._topList.parent().scrollTop();
itemOffset -= listOffset+scrollTop;
var treeHeight = this._topList.parent().height();
var itemHeight = item.treeList.label.outerHeight();
if (itemOffset < itemHeight/2) {
this._topList.parent().scrollTop(scrollTop+itemOffset-itemHeight/2-itemHeight)
} else if (itemOffset+itemHeight > treeHeight) {
this._topList.parent().scrollTop(scrollTop+((itemOffset+2.5*itemHeight)-treeHeight));
}
},
select: function(item, triggerEvent, deselectExisting) {
var that = this;
if (!this.options.multi && deselectExisting !== false) {
this.clearSelection();
}
if (Array.isArray(item)) {
item.forEach(function(i) {
that.select(i,triggerEvent,false);
})
return;
}
if (typeof item === "string") {
item = this._items[item]
}
if (!item) {
return;
}
// this.show(item.id);
item.selected = true;
this._selected.add(item);
if (item.treeList.label) {
item.treeList.label.addClass("selected");
}
if (triggerEvent !== false) {
this._trigger("select",null,item)
}
},
clearSelection: function() {
this._selected.forEach(function(item) {
item.selected = false;
if (item.treeList.label) {
item.treeList.label.removeClass("selected")
}
});
this._selected.clear();
},
selected: function() {
var s = this._topList.find(".selected");
var selected = [];
this._selected.forEach(function(item) {
selected.push(item);
})
if (this.options.multi) {
var res = [];
s.each(function() {
res.push($(this).parent().data('data'));
})
return res;
return selected;
}
if (s.length) {
return s.parent().data('data');
if (selected.length) {
return selected[0]
} else {
// TODO: This may be a bug.. it causes the call to return itself
// not undefined.
return undefined;
}
},
filter: function(filterFunc) {
this.activeFilter = filterFunc;
var totalCount = 0;
var filter = function(item) {
var matchCount = 0;
if (filterFunc && filterFunc(item)) {
matchCount++;
totalCount++;
}
var childCount = 0;
if (item.children && typeof item.children !== "function") {
if (item.treeList.childList) {
childCount = item.treeList.childList.editableList('filter', filter);
} else {
item.treeList.childFilter = filter;
if (filterFunc) {
item.children.forEach(function(i) {
if (filter(i)) {
childCount++;
}
})
}
}
matchCount += childCount;
if (filterFunc && childCount > 0) {
setTimeout(function() {
item.treeList.expand();
},10);
}
}
if (!filterFunc) {
totalCount++;
return true
}
return matchCount > 0
}
this._topList.editableList('filter', filter);
return totalCount;
},
get: function(id) {
return this._items[id] || null;
}
});

View File

@@ -449,6 +449,9 @@
if (opt.label) {
op.text(opt.label);
}
if (opt.title) {
op.prop('title', opt.title)
}
if (opt.icon) {
if (opt.icon.indexOf("<") === 0) {
$(opt.icon).prependTo(op);
@@ -568,56 +571,6 @@
done(labelWidth);
}
},
_resize: function() {
var that = this;
if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
var type = this.typeMap[this.propertyType];
if (type && type.hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
this._getLabelWidth(this.selectTrigger, function(labelWidth) {
that.elementDiv.css('left',labelWidth+"px");
that.valueLabelContainer.css('left',labelWidth+"px");
if (that.optionExpandButton.shown) {
that.elementDiv.css('right',"22px");
that.valueLabelContainer.css('right',"22px");
} else {
that.elementDiv.css('right','0');
that.valueLabelContainer.css('right','0');
that.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
if (that.optionSelectTrigger) {
if (type && type.options && type.hasValue === true) {
that.optionSelectLabel.css({'left':'auto'})
that._getLabelWidth(that.optionSelectLabel, function(lw) {
that.optionSelectTrigger.css({'width':(23+lw)+"px"});
that.elementDiv.css('right',(23+lw)+"px");
that.input.css({
'border-top-right-radius': 0,
'border-bottom-right-radius': 0
});
});
} else {
that.optionSelectLabel.css({'left':'0'})
that.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'});
if (!that.optionExpandButton.shown) {
that.elementDiv.css({'right':0});
that.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
}
}
});
}
},
_updateOptionSelectLabel: function(o) {
var opt = this.typeMap[this.propertyType];
this.optionSelectLabel.empty();
@@ -645,7 +598,6 @@
}
if (opt.hasValue) {
this.optionValue = o.value;
this._resize();
this.input.trigger('change',this.propertyType,this.value());
}
} else {
@@ -685,11 +637,12 @@
this.propertyType = null;
this.type(currentType);
}
setTimeout(function() {that._resize();},0);
},
width: function(desiredWidth) {
this.uiWidth = desiredWidth;
this._resize();
if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
},
value: function(value) {
var that = this;
@@ -760,8 +713,6 @@
}
else if (opt.icon.indexOf("/") !== -1) {
image = new Image();
image.onload = function() { that._resize(); }
image.onerror = function() { that._resize(); }
image.name = opt.icon;
image.src = mapDeprecatedIcon(opt.icon);
$('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
@@ -773,6 +724,12 @@
if (opt.hasValue === false || (opt.showLabel !== false && !opt.icon)) {
this.selectLabel.text(opt.label);
}
if (opt.hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
}
if (this.optionMenu) {
this.optionMenu.remove();
this.optionMenu = null;
@@ -783,11 +740,13 @@
this.optionExpandButton.shown = false;
}
if (this.optionSelectTrigger) {
this.optionSelectTrigger.show();
this.optionSelectTrigger.css({"display":"inline-flex"});
if (!opt.hasValue) {
this.optionSelectTrigger.css({"flex-grow":1})
this.elementDiv.hide();
this.valueLabelContainer.hide();
} else {
this.optionSelectTrigger.css({"flex-grow":0})
this.elementDiv.show();
this.valueLabelContainer.hide();
}
@@ -954,7 +913,7 @@
panel.show({
target:that.optionExpandButton,
onclose:content.onclose,
align: "right"
align: "left"
});
}
})
@@ -966,9 +925,6 @@
this._trigger("typechange",null,this.propertyType);
this.input.trigger('change',this.propertyType,this.value());
}
if (!image) {
this._resize();
}
}
}
},
@@ -995,7 +951,6 @@
},
show: function() {
this.uiSelect.show();
this._resize();
},
hide: function() {
this.uiSelect.hide();

View File

@@ -108,7 +108,7 @@ RED.deploy = (function() {
RED.events.on('nodes:change',function(state) {
RED.events.on('workspace:dirty',function(state) {
if (state.dirty) {
window.onbeforeunload = function() {
return RED._("deploy.confirm.undeployedChanges");

View File

@@ -204,32 +204,28 @@ RED.editor = (function() {
node.dirty = true;
node.dirtyStatus = true;
var removedLinks = [];
if (node.ports) {
if (outputMap) {
RED.nodes.eachLink(function(l) {
if (l.source === node && outputMap.hasOwnProperty(l.sourcePort)) {
if (outputMap) {
RED.nodes.eachLink(function(l) {
if (l.source === node) {
if (outputMap.hasOwnProperty(l.sourcePort)) {
if (outputMap[l.sourcePort] === "-1") {
removedLinks.push(l);
} else {
l.sourcePort = outputMap[l.sourcePort];
}
}
});
}
if (node.outputs < node.ports.length) {
while (node.outputs < node.ports.length) {
node.ports.pop();
}
});
}
if (node.hasOwnProperty("__outputs")) {
if (node.outputs < node.__outputs) {
RED.nodes.eachLink(function(l) {
if (l.source === node && l.sourcePort >= node.outputs && removedLinks.indexOf(l) === -1) {
removedLinks.push(l);
}
});
} else if (node.outputs > node.ports.length) {
while (node.outputs > node.ports.length) {
node.ports.push(node.ports.length);
}
}
delete node.__outputs;
}
node.inputs = Math.min(1,Math.max(0,parseInt(node.inputs)));
if (isNaN(node.inputs)) {
@@ -592,6 +588,7 @@ RED.editor = (function() {
// - the elements need to have id's that imply password/username
$('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-password" type="password"/></span>').prependTo(dialogForm);
$('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-username" type="text"/></span>').prependTo(dialogForm);
$('<span style="position: absolute; top: -2000px;"><input id="red-ui-trap-user" type="text"/></span>').prependTo(dialogForm);
dialogForm.on("submit", function(e) { e.preventDefault();});
dialogForm.find('input').attr("autocomplete","off");
return dialogForm;
@@ -790,6 +787,11 @@ RED.editor = (function() {
nodeDiv.css({
'backgroundColor': backgroundColor
});
var borderColor = RED.utils.getDarkerColor(backgroundColor);
if (borderColor !== backgroundColor) {
nodeDiv.css('border-color',borderColor)
}
}
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
@@ -877,13 +879,13 @@ RED.editor = (function() {
var userCount = 0;
var subflowType = "subflow:"+node.id;
RED.nodes.eachNode(function(n) {
if (n.type === subflowType) {
userCount++;
}
});
// RED.nodes.eachNode(function(n) {
// if (n.type === subflowType) {
// userCount++;
// }
// });
$("#red-ui-editor-subflow-user-count")
.text(RED._("subflow.subflowInstances", {count:userCount})).show();
.text(RED._("subflow.subflowInstances", {count:node.instances.length})).show();
}
$('<div class="form-row">'+
@@ -932,7 +934,12 @@ RED.editor = (function() {
$("#red-ui-editor-node-color").on('change', function(ev) {
// Horribly out of scope...
nodeDiv.css('backgroundColor',$(this).val());
var colour = $(this).val();
nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
})
}
@@ -948,6 +955,11 @@ RED.editor = (function() {
var colour = RED.utils.getNodeColor(node.type, node._def);
var icon_url = RED.utils.getNodeIcon(node._def,node);
nodeDiv.css('backgroundColor',colour);
var borderColor = RED.utils.getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
@@ -1068,15 +1080,17 @@ RED.editor = (function() {
if (node.info) {
nodeInfoEditor.getSession().setValue(node.info, -1);
}
node.infoEditor = nodeInfoEditor;
return nodeInfoEditor;
}
function showEditDialog(node) {
function showEditDialog(node, defaultTab) {
var editing_node = node;
var isDefaultIcon;
var defaultIcon;
var nodeInfoEditor;
var finishedBuilding = false;
var skipInfoRefreshOnClose = false;
editStack.push(node);
RED.view.state(RED.state.EDITING);
@@ -1269,10 +1283,12 @@ RED.editor = (function() {
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(editing_node),1);
RED.events.emit("nodes:change",configNode);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(editing_node);
RED.events.emit("nodes:change",configNode);
}
}
changes[d] = editing_node[d];
@@ -1469,6 +1485,7 @@ RED.editor = (function() {
editing_node.dirty = true;
validateNode(editing_node);
RED.events.emit("editor:save",editing_node);
RED.events.emit("nodes:change",editing_node);
RED.tray.close();
}
}
@@ -1486,6 +1503,10 @@ RED.editor = (function() {
}
},
open: function(tray, done) {
if (editing_node.hasOwnProperty('outputs')) {
editing_node.__outputs = editing_node.outputs;
}
var trayFooter = tray.find(".red-ui-tray-footer");
var trayBody = tray.find('.red-ui-tray-body');
trayBody.parent().css('overflow','hidden');
@@ -1516,9 +1537,6 @@ RED.editor = (function() {
collapsible: true,
menu: false
});
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
}
var ns;
if (node._def.set.module === "node-red") {
ns = "node-red";
@@ -1588,6 +1606,9 @@ RED.editor = (function() {
prepareEditDialog(node,node._def,"node-input", function() {
trayBody.i18n();
finishedBuilding = true;
if (defaultTab) {
editorTabs.activateTab(defaultTab);
}
done();
});
},
@@ -1595,7 +1616,7 @@ RED.editor = (function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
if (editing_node) {
if (editing_node && !skipInfoRefreshOnClose) {
RED.sidebar.info.refresh(editing_node);
}
RED.workspaces.refresh();
@@ -1623,6 +1644,7 @@ RED.editor = (function() {
text: RED._("subflow.edit"),
click: function() {
RED.workspaces.show(id);
skipInfoRefreshOnClose = true;
$("#node-dialog-ok").trigger("click");
}
});
@@ -1891,10 +1913,12 @@ RED.editor = (function() {
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(editing_config_node),1);
RED.events.emit("nodes:change",configNode);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(editing_config_node);
RED.events.emit("nodes:change",configNode);
}
}
editing_config_node[d] = newValue;
@@ -1989,6 +2013,7 @@ RED.editor = (function() {
RED.view.redraw(true);
if (!configAdding) {
RED.events.emit("editor:save",editing_config_node);
RED.events.emit("nodes:change",editing_config_node);
}
RED.tray.close(function() {
updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix);
@@ -2222,7 +2247,6 @@ RED.editor = (function() {
changes.env = editing_node.env;
changed = true;
}
RED.palette.refresh();
if (changed) {
var wasChanged = editing_node.changed;
@@ -2242,6 +2266,7 @@ RED.editor = (function() {
validateNode(n);
}
});
RED.events.emit("subflows:change",editing_node);
RED.nodes.dirty(true);
var historyEvent = {
t:'edit',
@@ -2440,7 +2465,7 @@ RED.editor = (function() {
changes[d] = oldValues[d];
changed = true;
}
} else {
} else if (d !== "nodes") {
if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
changes[d] = oldValues[d];
changed = true;
@@ -2482,10 +2507,12 @@ RED.editor = (function() {
if (configNode) {
var users = configNode.users;
users.splice(users.indexOf(editing_node),1);
RED.events.emit("nodes:change",configNode);
}
configNode = RED.nodes.node(newValue);
if (configNode) {
configNode.users.push(editing_node);
RED.events.emit("nodes:change",configNode);
}
}
changes[d] = editing_node[d];
@@ -2535,6 +2562,7 @@ RED.editor = (function() {
changed:wasChanged
};
RED.history.push(historyEvent);
RED.events.emit("groups:change",editing_node);
}
editing_node.dirty = true;
RED.tray.close();
@@ -2614,6 +2642,7 @@ RED.editor = (function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
RED.sidebar.info.refresh(editing_node);
nodeInfoEditor.destroy();
nodeInfoEditor = null;
editStack.pop();

View File

@@ -15,7 +15,7 @@
**/
(function() {
var template = '<script type="text/x-red" data-template-name="_buffer"><div id="red-ui-editor-type-buffer-panels"><div id="red-ui-editor-type-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button class="red-ui-editor-type-buffer-type red-ui-button red-ui-button-small"><i class="fa fa-exclamation-circle"></i> <span id="red-ui-editor-type-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="red-ui-editor-type-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="red-ui-editor-type-buffer-str"></div></div></div><div id="red-ui-editor-type-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px"><div class="node-text-editor" id="red-ui-editor-type-buffer-bin"></div></div></div></div></script>';
var template = '<script type="text/x-red" data-template-name="_buffer"><div id="red-ui-editor-type-buffer-panels"><div id="red-ui-editor-type-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button class="red-ui-editor-type-buffer-type red-ui-button red-ui-button-small"><i class="fa fa-exclamation-circle"></i> <span id="red-ui-editor-type-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="red-ui-editor-type-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="red-ui-editor-type-buffer-str"></div></div></div><div id="red-ui-editor-type-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px; margin-bottom:0;"><div class="node-text-editor" id="red-ui-editor-type-buffer-bin"></div></div></div></div></script>';
function stringToUTF8Array(str) {
var data = [];
@@ -187,8 +187,7 @@
$(".red-ui-editor-type-buffer-type").on("click", function(e) {
e.preventDefault();
RED.sidebar.info.set(RED._("bufferEditor.modeDesc"));
RED.sidebar.info.show();
RED.sidebar.help.set(RED._("bufferEditor.modeDesc"));
})

View File

@@ -237,8 +237,7 @@
var changeTimer;
$(".red-ui-editor-type-expression-legacy").on("click", function(e) {
e.preventDefault();
RED.sidebar.info.set(RED._("expressionEditor.compatModeDesc"));
RED.sidebar.info.show();
RED.sidebar.help.set(RED._("expressionEditor.compatModeDesc"));
})
var testExpression = function() {
var value = testDataEditor.getValue();
@@ -318,9 +317,9 @@
var p2 = $("#red-ui-editor-type-expression-panel-info > .form-row > div:first-child");
p2Height -= p2.outerHeight(true) + 20;
$(".red-ui-editor-type-expression-tab-content").height(p2Height);
$("#red-ui-editor-type-expression-test-data").css("height",(p2Height-5)+"px");
$("#red-ui-editor-type-expression-test-data").css("height",(p2Height-25)+"px");
testDataEditor.resize();
$("#red-ui-editor-type-expression-test-result").css("height",(p2Height-5)+"px");
$("#red-ui-editor-type-expression-test-result").css("height",(p2Height-25)+"px");
testResultEditor.resize();
}
});

View File

@@ -87,6 +87,9 @@
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
}
dialogForm.i18n();
setTimeout(function() {
expressionEditor.focus();
},300);
},
close: function() {
expressionEditor.destroy();

View File

@@ -25,14 +25,14 @@ RED.group = (function() {
// '<div class="node-input-group-style-tools"><span class="button-group"><button class="red-ui-button red-ui-button-small">Use default style</button><button class="red-ui-button red-ui-button-small">Set as default style</button></span></div>'+
'<div class="form-row" id="node-input-row-style-stroke">'+
'<label>Style</label>'+
'<label data-i18n="editor:common.label.style"></label>'+
'<label style="width: 70px;margin-right:10px" for="node-input-style-stroke" data-i18n="editor:common.label.line"></label>'+
'</div>'+
'<div class="form-row" style="padding-left: 100px;" id="node-input-row-style-fill">'+
'<label style="width: 70px;margin-right: 10px " for="node-input-style-fill" data-i18n="editor:common.label.fill"></label>'+
'</div>'+
'<div class="form-row">'+
'<label for="node-input-style-label">Label</label>'+
'<label for="node-input-style-label" data-i18n="editor:common.label.label"></label>'+
'<input type="checkbox" id="node-input-style-label"/>'+
'</div>'+
'<div class="form-row" id="node-input-row-style-label-options">'+
@@ -78,15 +78,19 @@ RED.group = (function() {
r = Math.min(255,Math.floor(r+j*dr));
g = Math.min(255,Math.floor(g+j*dg));
b = Math.min(255,Math.floor(b+j*db));
colorPalette.push('#'+((r<<16) + (g<<8) + b).toString(16).padStart(6,'0'));
var s = ((r<<16) + (g<<8) + b).toString(16);
colorPalette.push('#'+'000000'.slice(0, 6-s.length)+s);
}
var defaultGroupStyle = {};
var defaultGroupStyle = {
label: true,
"label-position": "nw"
};
var groupDef = {
defaults:{
name:{value:""},
style:{value:{}},
style:{value:{label:true}},
nodes:{value:[]}
},
category: "config",
@@ -94,7 +98,7 @@ RED.group = (function() {
var style = this.style || {};
RED.colorPicker.create({
id:"node-input-style-stroke",
value: style.stroke || "#a4a4a4",
value: style.stroke || defaultGroupStyle.stroke || "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
@@ -122,7 +126,7 @@ RED.group = (function() {
RED.colorPicker.create({
id:"node-input-style-color",
value: style.color || "#a4a4a4",
value: style.color || defaultGroupStyle.color ||"#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
@@ -132,10 +136,9 @@ RED.group = (function() {
$("#node-input-style-label").toggleButton({
enabledLabel: RED._("editor.show"),
disabledLabel: RED._("editor.hide")
disabledLabel: RED._("editor.show"),
})
$("#node-input-style-label").on("change", function(evt) {
$("#node-input-row-style-label-options").toggle($(this).prop("checked"));
})
@@ -165,6 +168,13 @@ RED.group = (function() {
if (this.style["fill-opacity"] === "1") {
delete this.style["fill-opacity"]
}
var node = this;
['stroke','fill','stroke-opacity','fill-opacity','color','label-position'].forEach(function(prop) {
if (node.style[prop] === defaultGroupStyle[prop]) {
delete node.style[prop]
}
})
this.resize = true;
},
set:{
@@ -175,10 +185,27 @@ RED.group = (function() {
function init() {
RED.events.on("view:selection-changed",function(selection) {
RED.menu.setDisabled("menu-item-group-group",!!!selection.nodes);
RED.menu.setDisabled("menu-item-group-ungroup",!!!selection.nodes || selection.nodes.filter(function(n) { return n.type==='group'}).length === 0);
RED.menu.setDisabled("menu-item-group-merge",!!!selection.nodes);
RED.menu.setDisabled("menu-item-group-remove",!!!selection.nodes || selection.nodes.filter(function(n) { return !!n.g }).length === 0);
var activateGroup = !!selection.nodes;
var activateUngroup = false;
var activateMerge = false;
var activateRemove = false;
if (activateGroup) {
selection.nodes.forEach(function (n) {
if (n.type === "group") {
activateUngroup = true;
}
if (!!n.g) {
activateRemove = true;
}
});
if (activateUngroup) {
activateMerge = (selection.nodes.length > 1);
}
}
RED.menu.setDisabled("menu-item-group-group", !activateGroup);
RED.menu.setDisabled("menu-item-group-ungroup", !activateUngroup);
RED.menu.setDisabled("menu-item-group-merge", !activateMerge);
RED.menu.setDisabled("menu-item-group-remove", !activateRemove);
});
RED.actions.add("core:group-selection", function() { groupSelection() })
@@ -199,15 +226,25 @@ RED.group = (function() {
stroke: convertColorToHex(groupStyle.stroke),
"stroke-opacity": groupStyle.strokeOpacity,
fill: convertColorToHex(groupStyle.fill),
"fill-opacity": groupStyle.fillOpacity
"fill-opacity": groupStyle.fillOpacity,
label: true,
"label-position": "nw"
}
groupStyleDiv.remove();
groupStyleDiv = $("<div>",{
class:"red-ui-flow-group-label",
style: "position: absolute; top: -1000px;"
}).appendTo(document.body);
groupStyle = getComputedStyle(groupStyleDiv[0]);
defaultGroupStyle.color = convertColorToHex(groupStyle.fill);
groupStyleDiv.remove();
}
function convertColorToHex(c) {
var m = /^rgb\((\d+), (\d+), (\d+)\)$/.exec(c);
if (m) {
return "#"+(((parseInt(m[1])<<16) + (parseInt(m[2])<<8) + parseInt(m[3])).toString(16).padStart(6,'0'))
var s = ((parseInt(m[1])<<16) + (parseInt(m[2])<<8) + parseInt(m[3])).toString(16)
return '#'+'000000'.slice(0, 6-s.length)+s;
}
return c;
}
@@ -309,6 +346,11 @@ RED.group = (function() {
} else {
delete n.g;
}
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
})
RED.nodes.removeGroup(g);
return nodes;
@@ -420,15 +462,16 @@ RED.group = (function() {
h: 0,
_def: RED.group.def
}
group.z = nodes[0].z;
RED.nodes.addGroup(group);
try {
addToGroup(group,nodes);
} catch(err) {
RED.notify(err,"error");
return;
}
group.z = nodes[0].z;
RED.nodes.addGroup(group);
return group;
}
function addToGroup(group,nodes) {
@@ -489,9 +532,16 @@ RED.group = (function() {
group.y = Math.min(group.y,n.y-n.h/2-25);
group.w = Math.max(group.w,n.x+n.w/2+25+((n._def.button && n._def.align=="right")?20:0) - group.x);
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
}
}
if (g) {
RED.events.emit("groups:change",group)
}
markDirty(group);
}
function removeFromGroup(group, nodes, reparent) {
@@ -518,6 +568,11 @@ RED.group = (function() {
} else {
delete n.g;
}
if (n.type === 'group') {
RED.events.emit("groups:change",n)
} else {
RED.events.emit("nodes:change",n)
}
}
markDirty(group);
}
@@ -578,14 +633,14 @@ RED.group = (function() {
var row = null;
row = $("<div/>").appendTo(picker);
var currentButton;
for (var y=0;y<2;y++) { //red-ui-group-layout-text-pos
var yComponent= "ns"[y];
row = $("<div/>").appendTo(picker);
for (var x=0;x<3;x++) {
var xComponent = ["w","","e"][x];
var val = yComponent+xComponent;
var button = $("<button/>", { class:"red-ui-search-result-node","data-pos":val }).appendTo(row);
var button = $("<button/>", { class:"red-ui-search-result-node red-ui-button","data-pos":val }).appendTo(row);
button.on("click", function (e) {
e.preventDefault();
layoutHiddenInput.val($(this).data("pos"));
@@ -593,15 +648,22 @@ RED.group = (function() {
refreshDisplay();
});
$('<div>',{class:"red-ui-group-layout-picker-cell-text red-ui-group-layout-text-pos-"+val}).appendTo(button);
if (val === layoutHiddenInput.val()) {
currentButton = button;
}
}
}
refreshDisplay();
var layoutPanel = RED.popover.panel(picker);
layoutPanel.show({
target: layoutButton
})
target: layoutButton,
onclose: function() {
layoutButton.focus();
}
});
if (currentButton) {
currentButton.focus();
}
})
refreshDisplay();

View File

@@ -17,6 +17,8 @@ RED.keyboard = (function() {
var isMac = /Mac/i.test(window.navigator.platform);
var handlersActive = true;
var handlers = {};
var partialState;
@@ -225,6 +227,9 @@ RED.keyboard = (function() {
}
}
d3.select(window).on("keydown",function() {
if (!handlersActive) {
return;
}
if (metaKeyCodes[d3.event.keyCode]) {
return;
}
@@ -570,6 +575,13 @@ RED.keyboard = (function() {
return pane;
}
function enable() {
handlersActive = true;
}
function disable() {
handlersActive = false;
}
return {
init: init,
add: addHandler,
@@ -579,7 +591,9 @@ RED.keyboard = (function() {
},
revertToDefault: revertToDefault,
formatKey: formatKey,
validateKey: validateKey
validateKey: validateKey,
disable: disable,
enable: enable
}
})();

View File

@@ -22,7 +22,7 @@ RED.library = (function() {
var _libraryLookup = '<div id="red-ui-library-dialog-load" class="hide">'+
'<form class="form-horizontal">'+
'<div style="height: 400px; position:relative; ">'+
'<div class="red-ui-library-dialog-box" style="height: 400px; position:relative; ">'+
'<div id="red-ui-library-dialog-load-panes">'+
'<div class="red-ui-panel" id="red-ui-library-dialog-load-browser"></div>'+
'<div class="red-ui-panel">'+
@@ -41,7 +41,7 @@ RED.library = (function() {
var _librarySave = '<div id="red-ui-library-dialog-save" class="hide">'+
'<form class="form-horizontal">'+
'<div style="height: 400px; position:relative; ">'+
'<div class="red-ui-library-dialog-box" style="height: 400px; position:relative; ">'+
'<div id="red-ui-library-dialog-save-browser"></div>'+
'<div class="form-row">'+
'<label data-i18n="clipboard.export.exportAs"></label><input id="red-ui-library-dialog-save-filename" type="text">'+
@@ -64,12 +64,14 @@ RED.library = (function() {
var queryArgs = [];
var data = {};
for (var i=0; i<activeLibrary.fields.length; i++) {
for (var i=0; i < activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i];
if (field == "name") {
if (field === "name") {
data.name = name;
} else if (typeof(field) === 'object') {
data[field.name] = field.get();
} else {
data[field] = $("#"+elementPrefix+field).val();
data[field] = $("#" + elementPrefix + field).val();
}
}
data.text = activeLibrary.editor.getValue();
@@ -254,6 +256,13 @@ RED.library = (function() {
libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
libraryEditor.$blockScrolling = Infinity;
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 570) {
dialogHeight = 400 - (570 - winHeight);
}
$("#red-ui-library-dialog-load .red-ui-library-dialog-box").height(dialogHeight);
$( "#red-ui-library-dialog-load" ).dialog("option","title",RED._("library.typeLibrary", {type:options.type})).dialog( "open" );
}
},
@@ -293,6 +302,15 @@ RED.library = (function() {
saveLibraryBrowser.select(listing[0].children[0]);
},200);
});
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 570) {
dialogHeight = 400 - (570 - winHeight);
}
$("#red-ui-library-dialog-save .red-ui-library-dialog-box").height(dialogHeight);
$( "#red-ui-library-dialog-save" ).dialog( "open" );
}
}
@@ -454,6 +472,8 @@ RED.library = (function() {
autoOpen: false,
width: 800,
resizable: false,
open: function( event, ui ) { RED.keyboard.disable() },
close: function( event, ui ) { RED.keyboard.enable() },
classes: {
"ui-dialog": "red-ui-editor-dialog",
"ui-dialog-titlebar-close": "hide",
@@ -518,23 +538,31 @@ RED.library = (function() {
{
text: RED._("common.label.load"),
class: "primary",
click: function() {
click: function () {
if (selectedLibraryItem) {
var elementPrefix = activeLibrary.elementPrefix || "node-input-";
for (var i=0; i<activeLibrary.fields.length; i++) {
for (var i = 0; i < activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i];
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
if (typeof(field) === 'object') {
var val = selectedLibraryItem[field.name];
field.set(val);
}
else {
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
}
}
activeLibrary.editor.setValue(libraryEditor.getValue(),-1);
activeLibrary.editor.setValue(libraryEditor.getValue(), -1);
}
$( this ).dialog( "close" );
}
}
],
open: function(e) {
RED.keyboard.disable();
$(this).parent().find(".ui-dialog-titlebar-close").hide();
},
close: function(e) {
RED.keyboard.enable();
if (libraryEditor) {
libraryEditor.destroy();
libraryEditor = null;

View File

@@ -223,7 +223,11 @@ RED.palette.editor = (function() {
var setElements = nodeEntry.sets[setName];
if (set.err) {
errorCount++;
$("<li>").text(set.err).appendTo(nodeEntry.errorList);
var errMessage = set.err;
if (set.err.message) {
errMessage = set.err.message;
}
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
}
if (set.enabled) {
activeTypeCount += set.types.length;

View File

@@ -105,7 +105,7 @@ RED.palette = (function() {
for (var i=0;i<words.length;i++) {
var word = words[i];
var sep = (i == 0) ? "" : " ";
var newWidth = RED.view.calculateTextWidth(currentLine+sep+word, "red-ui-palette-label", 0);
var newWidth = RED.view.calculateTextWidth(currentLine+sep+word, "red-ui-palette-label");
if (newWidth < nodeWidth) {
currentLine += sep +word;
} else {
@@ -113,12 +113,12 @@ RED.palette = (function() {
displayLines.push(currentLine);
}
while (true) {
var wordWidth = RED.view.calculateTextWidth(word, "red-ui-palette-label", 0);
var wordWidth = RED.view.calculateTextWidth(word, "red-ui-palette-label");
if (wordWidth >= nodeWidth) {
// break word if too wide
for(var j = word.length; j > 0; j--) {
var s = word.substring(0, j);
var width = RED.view.calculateTextWidth(s, "red-ui-palette-label", 0);
var width = RED.view.calculateTextWidth(s, "red-ui-palette-label");
if (width < nodeWidth) {
displayLines.push(s);
word = word.substring(j);
@@ -165,6 +165,7 @@ RED.palette = (function() {
metaData = typeInfo.set.module+" : ";
}
metaData += type;
$('<button type="button" onclick="RED.sidebar.help.show(\''+type+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
}
} catch(err) {
@@ -181,7 +182,11 @@ RED.palette = (function() {
function setIcon(element,sf) {
var icon_url = RED.utils.getNodeIcon(sf._def);
var iconContainer = element.find(".red-ui-palette-icon-container");
RED.utils.createIconElement(icon_url, iconContainer, true);
var currentIcon = iconContainer.attr("data-palette-icon");
if (currentIcon !== icon_url) {
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true);
}
}
function getPaletteNode(type) {
@@ -224,6 +229,7 @@ RED.palette = (function() {
var iconContainer = $('<div/>', {
class: "red-ui-palette-icon-container"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-icon-container-right" : "")
}).appendTo(d);
iconContainer.attr("data-palette-icon", icon_url);
RED.utils.createIconElement(icon_url, iconContainer, true);
}
@@ -250,6 +256,7 @@ RED.palette = (function() {
var popover = RED.popover.create({
target:d,
trigger: "hover",
interactive: true,
width: "300px",
content: "hi",
delay: { show: 750, hide: 50 }
@@ -265,19 +272,19 @@ RED.palette = (function() {
// html: true,
// container:'body'
// });
d.on("click", function() {
RED.view.focus();
var helpText;
if (nt.indexOf("subflow:") === 0) {
helpText = RED.utils.renderMarkdown(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
} else {
helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
}
// Don't look too closely. RED.sidebar.info.set will set the 'Description'
// section of the sidebar. Pass in the title of the Help section so it looks
// right.
RED.sidebar.info.set(helpText,RED._("sidebar.info.nodeHelp"));
});
// d.on("click", function() {
// RED.view.focus();
// var helpText;
// if (nt.indexOf("subflow:") === 0) {
// helpText = RED.utils.renderMarkdown(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// } else {
// helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// }
// // Don't look too closely. RED.sidebar.info.set will set the 'Description'
// // section of the sidebar. Pass in the title of the Help section so it looks
// // right.
// RED.sidebar.type.show(helpText,RED._("sidebar.info.nodeHelp"));
// });
var chart = $("#red-ui-workspace-chart");
var chartSVG = $("#red-ui-workspace-chart>svg").get(0);
var activeSpliceLink;
@@ -452,61 +459,67 @@ RED.palette = (function() {
categoryNode.show();
paletteNode.show();
}
function refreshNodeTypes() {
RED.nodes.eachSubflow(function(sf) {
var paletteNode = getPaletteNode('subflow:'+sf.id);
var portInput = paletteNode.find(".red-ui-palette-port-input");
var portOutput = paletteNode.find(".red-ui-palette-port-output");
RED.nodes.eachSubflow(refreshSubflow)
}
function refreshSubflow(sf) {
var paletteNode = getPaletteNode('subflow:'+sf.id);
var portInput = paletteNode.find(".red-ui-palette-port-input");
var portOutput = paletteNode.find(".red-ui-palette-port-output");
var paletteLabel = paletteNode.find(".red-ui-palette-label");
paletteLabel.attr("class","red-ui-palette-label" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-label-right" : ""));
var paletteLabel = paletteNode.find(".red-ui-palette-label");
paletteLabel.attr("class","red-ui-palette-label" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-label-right" : ""));
var paletteIconContainer = paletteNode.find(".red-ui-palette-icon-container");
paletteIconContainer.attr("class","red-ui-palette-icon-container" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-icon-container-right" : ""));
var paletteIconContainer = paletteNode.find(".red-ui-palette-icon-container");
paletteIconContainer.attr("class","red-ui-palette-icon-container" + (((!sf._def.align && sf.in.length !== 0 && sf.out.length === 0) || "right" === sf._def.align) ? " red-ui-palette-icon-container-right" : ""));
if (portInput.length === 0 && sf.in.length > 0) {
var portIn = document.createElement("div");
portIn.className = "red-ui-palette-port red-ui-palette-port-input";
paletteNode.append(portIn);
} else if (portInput.length !== 0 && sf.in.length === 0) {
portInput.remove();
}
if (portInput.length === 0 && sf.in.length > 0) {
var portIn = document.createElement("div");
portIn.className = "red-ui-palette-port red-ui-palette-port-input";
paletteNode.append(portIn);
} else if (portInput.length !== 0 && sf.in.length === 0) {
portInput.remove();
}
if (portOutput.length === 0 && sf.out.length > 0) {
var portOut = document.createElement("div");
portOut.className = "red-ui-palette-port red-ui-palette-port-output";
paletteNode.append(portOut);
} else if (portOutput.length !== 0 && sf.out.length === 0) {
portOutput.remove();
}
if (portOutput.length === 0 && sf.out.length > 0) {
var portOut = document.createElement("div");
portOut.className = "red-ui-palette-port red-ui-palette-port-output";
paletteNode.append(portOut);
} else if (portOutput.length !== 0 && sf.out.length === 0) {
portOutput.remove();
}
var currentLabel = paletteNode.attr("data-palette-label");
var currentInfo = paletteNode.attr("data-palette-info");
if (currentLabel !== sf.name || currentInfo !== sf.info) {
paletteNode.attr("data-palette-info",sf.info);
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,RED.utils.renderMarkdown(sf.info||""));
setIcon(paletteNode,sf);
}
setIcon(paletteNode,sf);
var currentCategory = paletteNode.data('category');
var newCategory = (sf.category||"subflows");
if (currentCategory !== newCategory) {
var category = escapeCategory(newCategory);
createCategory(newCategory,category,category,"node-red");
var currentCategory = paletteNode.data('category');
var newCategory = (sf.category||"subflows");
if (currentCategory !== newCategory) {
var category = escapeCategory(newCategory);
createCategory(newCategory,category,category,"node-red");
var currentCategoryNode = paletteNode.closest(".red-ui-palette-category");
var newCategoryNode = $("#red-ui-palette-"+category);
newCategoryNode.append(paletteNode);
if (newCategoryNode.find(".red-ui-palette-node").length === 1) {
categoryContainers[category].open();
}
paletteNode.data('category',newCategory);
if (currentCategoryNode.find(".red-ui-palette-node").length === 0) {
if (currentCategoryNode.find("i").hasClass("expanded")) {
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
}
}
var currentCategoryNode = paletteNode.closest(".red-ui-palette-category");
var newCategoryNode = $("#red-ui-palette-"+category);
newCategoryNode.append(paletteNode);
if (newCategoryNode.find(".red-ui-palette-node").length === 1) {
categoryContainers[category].open();
}
paletteNode.css("backgroundColor", sf.color);
});
paletteNode.data('category',newCategory);
if (currentCategoryNode.find(".red-ui-palette-node").length === 0) {
if (currentCategoryNode.find("i").hasClass("expanded")) {
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
}
}
}
paletteNode.css("backgroundColor", sf.color);
}
function filterChange(val) {
@@ -544,6 +557,8 @@ RED.palette = (function() {
$('<div class="red-ui-component-footer"></div>').appendTo("#red-ui-palette");
$('<div id="red-ui-palette-shade" class="hide"></div>').appendTo("#red-ui-palette");
$("#red-ui-palette > .red-ui-palette-spinner").show();
RED.events.on('registry:node-type-added', function(nodeType) {
var def = RED.nodes.getType(nodeType);
@@ -585,7 +600,8 @@ RED.palette = (function() {
}
});
$("#red-ui-palette > .red-ui-palette-spinner").show();
RED.events.on("subflows:change",refreshSubflow);
$("#red-ui-palette-search input").searchBox({

View File

@@ -685,6 +685,8 @@ RED.projects = (function() {
}
}
},projectData).then(function() {
RED.menu.setDisabled('menu-item-projects-open',false);
RED.menu.setDisabled('menu-item-projects-settings',false);
RED.events.emit("project:change", {name:name});
}).always(function() {
setTimeout(function() {
@@ -1495,7 +1497,6 @@ RED.projects = (function() {
}
} else if (projectType === 'open') {
return switchProject(selectedProject.name,function(err,data) {
dialog.dialog( "close" );
if (err) {
if (err.code !== 'credentials_load_failed') {
console.log(RED._("projects.create.unexpected_error"),err)
@@ -1604,6 +1605,7 @@ RED.projects = (function() {
},
}
},{active:true}).then(function() {
dialog.dialog( "close" );
RED.events.emit("project:change", {name:name});
}).always(function() {
setTimeout(function() {
@@ -1613,25 +1615,16 @@ RED.projects = (function() {
}
function deleteProject(row,name,done) {
var cover = $('<div>').css({
background:"white",
position:"absolute",
top:0,right:0,bottom:0,left:"100%",
overflow:"hidden",
padding: "5px 20px",
transition: "left 0.4s",
whitespace: "nowrap",
width:"1000px"
}).on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
$('<span>').css({"lineHeight":"40px"}).text(RED._("projects.delete.confirm")).appendTo(cover);
$('<button style="margin-left:20px" class="red-ui-button">'+RED._("common.label.cancel")+'</button>')
var cover = $('<div class="red-ui-projects-dialog-project-list-entry-delete-confirm"></div>').on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
$('<span>').text(RED._("projects.delete.confirm")).appendTo(cover);
$('<button class="red-ui-button">'+RED._("common.label.cancel")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
cover.remove();
done(true);
});
$('<button style="margin-left:20px" class="red-ui-button primary">'+RED._("common.label.delete")+'</button>')
$('<button class="red-ui-button primary">'+RED._("common.label.delete")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
@@ -1671,16 +1664,27 @@ RED.projects = (function() {
if (typeof buttons === 'function') {
buttons = buttons(options||{});
}
dialog.dialog('option','buttons',buttons);
dialogBody.append(container);
var dialogHeight = 590;
var winHeight = $(window).height();
if (winHeight < 750) {
dialogHeight = 590 - (750 - winHeight);
}
$(".red-ui-projects-dialog-box").height(dialogHeight);
$(".red-ui-projects-dialog-project-list-inner-container").height(Math.max(500,dialogHeight) - 180);
dialog.dialog('option','title',screen.title||"");
dialog.dialog("open");
dialog.dialog({position: { 'my': 'center top', 'at': 'center top+20', 'of': window }});
}
function createProjectList(options) {
options = options||{};
var height = options.height || "300px";
var height = options.height || "200px";
var container = $('<div></div>',{class:"red-ui-projects-dialog-project-list-container" });
var filterTerm = "";
@@ -2087,6 +2091,8 @@ RED.projects = (function() {
var branchFilterTerm = "";
var branchFilterCreateItem;
var branches = [];
var branchNames = new Set();
var remotes = [];
var branchPrefix = "";
var container = $('<div class="red-ui-projects-branch-list">').appendTo(options.container);
@@ -2094,18 +2100,30 @@ RED.projects = (function() {
delay: 200,
change: function() {
branchFilterTerm = $(this).val();
if (/(\.\.|\/\.|[?*[~^: \\]|\/\/|\/.$|\/$)/.test(branchFilterTerm)) {
// if there is a / then
// - check what preceeds it is a known remote
var valid = false;
var hasRemote = false;
var m = /^([^/]+)\/[^/.~*?\[]/.exec(branchFilterTerm);
if (m && remotes.indexOf(m[1]) > -1) {
valid = true;
hasRemote = true;
}
if (!valid && /(\.\.|\/\.|[?*[~^: \\]|\/\/|\/.$|\/$)/.test(branchFilterTerm)) {
if (!branchFilterCreateItem.hasClass("input-error")) {
branchFilterCreateItem.addClass("input-error");
branchFilterCreateItem.find("i").addClass("fa-warning").removeClass("fa-code-fork");
}
branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.invalid")+": "+branchPrefix+branchFilterTerm);
branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.invalid")+": "+(hasRemote?"":branchPrefix)+branchFilterTerm);
} else {
if (branchFilterCreateItem.hasClass("input-error")) {
branchFilterCreateItem.removeClass("input-error");
branchFilterCreateItem.find("i").removeClass("fa-warning").addClass("fa-code-fork");
}
branchFilterCreateItem.find(".red-ui-sidebar-vc-branch-list-entry-create-name").text(branchPrefix+branchFilterTerm);
branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.create")+":");
branchFilterCreateItem.find(".red-ui-sidebar-vc-branch-list-entry-create-name").text((hasRemote?"":branchPrefix)+branchFilterTerm);
}
branchList.editableList("filter");
}
@@ -2138,8 +2156,12 @@ RED.projects = (function() {
if (!entry.hasOwnProperty('commit')) {
body.name = branchFilter.val();
body.create = true;
if (options.remote) {
body.name = options.remote()+"/"+body.name;
if (options.remotes) {
var m = /^([^/]+)\/[^/.~*?\[]/.exec(body.name);
if (!m || remotes.indexOf(m[1]) === -1) {
body.name = remotes[0]+"/"+body.name;
}
}
} else {
if ($(this).hasClass('selected')) {
@@ -2154,11 +2176,17 @@ RED.projects = (function() {
},
filter: function(data) {
var isCreateEntry = (!data.hasOwnProperty('commit'));
var filterTerm = branchFilterTerm;
if (remotes.length > 0) {
var m = /^([^/]+)\/[^/.~*?\[]/.exec(filterTerm);
if (filterTerm !== "" && (!m || remotes.indexOf(m[1]) == -1)) {
filterTerm = remotes[0]+"/"+filterTerm;
}
}
return (
isCreateEntry &&
(
branchFilterTerm !== "" &&
branches.indexOf(branchPrefix+branchFilterTerm) === -1
filterTerm !== "" && !branchNames.has(filterTerm)
)
) ||
(
@@ -2173,12 +2201,14 @@ RED.projects = (function() {
branchList.editableList('empty');
var start = Date.now();
var spinner = addSpinnerOverlay(container).addClass("red-ui-component-spinner-contain");
if (options.remote) {
branchPrefix = options.remote()+"/";
if (options.remotes) {
remotes = options.remotes();
branchPrefix = remotes[0]+"/";
} else {
branchPrefix = "";
remotes = [];
}
branchNames = new Set();
sendRequest({
url: url,
type: "GET",
@@ -2190,6 +2220,7 @@ RED.projects = (function() {
branches = result.branches;
result.branches.forEach(function(b) {
branchList.editableList('addItem',b);
branchNames.add(b.name);
});
branchList.editableList('addItem',{});
setTimeout(function() {
@@ -2225,13 +2256,19 @@ RED.projects = (function() {
}
function init() {
dialog = $('<div id="red-ui-projects-dialog" class="hide red-ui-projects-edit-form"><form class="form-horizontal"></form><div class="red-ui-component-spinner hide"><img src="red/images/spin.svg"/></div></div>')
dialog = $('<div id="red-ui-projects-dialog" class="hide red-ui-projects-edit-form"><div class="red-ui-projects-dialog-box"><form class="form-horizontal"></form><div class="red-ui-component-spinner hide"><img src="red/images/spin.svg"/></div></div></div>')
.appendTo("#red-ui-editor")
.dialog({
modal: true,
autoOpen: false,
width: 600,
resizable: false,
open: function(e) {
RED.keyboard.disable();
},
close: function(e) {
RED.keyboard.enable();
},
classes: {
"ui-dialog": "red-ui-editor-dialog",
"ui-dialog-titlebar-close": "hide",
@@ -2312,6 +2349,7 @@ RED.projects = (function() {
if (data.active) {
$.getJSON("projects/"+data.active, function(project) {
activeProject = project;
RED.events.emit("projects:load",activeProject);
RED.sidebar.versionControl.refresh(true);
if (done) {
done(activeProject);

View File

@@ -830,10 +830,9 @@ RED.sidebar.versionControl = (function() {
var remoteBranchList = utils.createBranchList({
placeholder: RED._("sidebar.project.versionControl.createRemoteBranchPlaceholder"),
currentLabel: RED._("sidebar.project.versionControl.upstream"),
remote: function() {
remotes: function() {
var project = RED.projects.getActiveProject();
var remotes = Object.keys(project.git.remotes);
return remotes[0];
return Object.keys(project.git.remotes);
},
container: remoteBranchSubRow,
onselect: function(body) {

View File

@@ -23,11 +23,9 @@ RED.search = (function() {
var visible = false;
var index = {};
var keys = [];
var results = [];
var currentResults = [];
var previousActiveElement;
function indexProperty(node,label,property) {
if (typeof property === 'string' || typeof property === 'number') {
property = (""+property).toLowerCase();
@@ -61,53 +59,110 @@ RED.search = (function() {
}
for (var i=0;i<properties.length;i++) {
if (n.hasOwnProperty(properties[i])) {
if (n.type === "group" && properties[i] === "nodes") {
continue;
}
indexProperty(n, l, n[properties[i]]);
}
}
}
function indexWorkspace() {
index = {};
RED.nodes.eachWorkspace(indexNode);
RED.nodes.eachSubflow(indexNode);
RED.nodes.eachConfig(indexNode);
RED.nodes.eachNode(indexNode);
keys = Object.keys(index);
keys.sort();
keys.forEach(function(key) {
index[key] = Object.keys(index[key]).map(function(id) {
return index[key][id];
})
})
function extractFlag(val, flagName, flags) {
// is:XYZ
var regEx = new RegExp("(?:^| )is:"+flagName+"(?: |$)");
var m = regEx.exec(val);
if (m) {
val = val.replace(regEx," ").trim();
flags[flagName] = true;
}
return val;
}
function extractValue(val, flagName, flags) {
// flagName:XYZ
var regEx = new RegExp("(?:^| )"+flagName+":([^ ]+)(?: |$)");
var m
while(!!(m = regEx.exec(val))) {
val = val.replace(regEx," ").trim();
flags[flagName] = flags[flagName] || [];
flags[flagName].push(m[1]);
}
return val;
}
function search(val) {
searchResults.editableList('empty');
var results = [];
var keys = [];
var typeFilter;
var m = /(?:^| )type:([^ ]+)/.exec(val);
if (m) {
val = val.replace(/(?:^| )type:[^ ]+/,"");
typeFilter = m[1];
}
var flags = {};
val = extractFlag(val,"invalid",flags);
val = extractFlag(val,"unused",flags);
val = extractFlag(val,"config",flags);
val = extractFlag(val,"subflow",flags);
// uses:<node-id>
val = extractValue(val,"uses",flags);
var hasFlags = Object.keys(flags).length > 0;
val = val.trim();
selected = -1;
results = [];
if (val.length > 0 || typeFilter) {
if (val.length > 0 || typeFilter || hasFlags) {
val = val.toLowerCase();
var i;
var j;
var list = [];
var nodes = {};
if (flags.uses) {
keys = flags.uses;
} else {
keys = Object.keys(index);
}
for (i=0;i<keys.length;i++) {
var key = keys[i];
var kpos = keys[i].indexOf(val);
if (kpos > -1) {
for (j=0;j<index[key].length;j++) {
var node = index[key][j];
var ids = Object.keys(index[key]);
for (j=0;j<ids.length;j++) {
var node = index[key][ids[j]];
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
if (flags.uses && key === node.node.id) {
continue;
}
if (flags.hasOwnProperty("invalid")) {
var nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
if (flags.invalid === nodeIsValid) {
continue;
}
}
if (flags.hasOwnProperty("config")) {
if (flags.config !== isConfigNode) {
continue;
}
}
if (flags.hasOwnProperty("subflow")) {
if (flags.subflow !== (node.node.type === 'subflow')) {
continue;
}
}
if (flags.hasOwnProperty("unused")) {
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0)
if (flags.unused !== isUnused) {
continue;
}
}
if (!typeFilter || node.node.type === typeFilter) {
nodes[node.node.id] = nodes[node.node.id] = node;
nodes[node.node.id] = nodes[node.node.id] = {
node: node.node,
label: node.label
};
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
}
}
@@ -121,22 +176,8 @@ RED.search = (function() {
for (i=0;i<list.length;i++) {
results.push(nodes[list[i]]);
}
if (results.length > 0) {
for (i=0;i<Math.min(results.length,25);i++) {
searchResults.editableList('addItem',results[i])
}
if (results.length > 25) {
searchResults.editableList('addItem', {
more: {
results: results,
start: 25
}
})
}
} else {
searchResults.editableList('addItem',{});
}
}
return results;
}
function ensureSelectedIsVisible() {
@@ -161,13 +202,37 @@ RED.search = (function() {
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.searchInput">').appendTo(searchDiv).searchBox({
delay: 200,
change: function() {
search($(this).val());
searchResults.editableList('empty');
selected = -1;
currentResults = search($(this).val());
if (currentResults.length > 0) {
for (i=0;i<Math.min(currentResults.length,25);i++) {
searchResults.editableList('addItem',currentResults[i])
}
if (currentResults.length > 25) {
searchResults.editableList('addItem', {
more: {
results: currentResults,
start: 25
}
})
}
} else {
searchResults.editableList('addItem',{});
}
}
});
var copySearchContainer = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-caret-right"></button>').appendTo(searchDiv).on('click', function(evt) {
evt.preventDefault();
RED.sidebar.info.outliner.search(searchInput.val())
hide();
});
searchInput.on('keydown',function(evt) {
var children;
if (results.length > 0) {
if (currentResults.length > 0) {
if (evt.keyCode === 40) {
// Down
children = searchResults.children();
@@ -199,21 +264,21 @@ RED.search = (function() {
var object = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
if (object) {
searchResults.editableList('removeItem',object);
for (i=object.more.start;i<Math.min(results.length,object.more.start+25);i++) {
searchResults.editableList('addItem',results[i])
for (i=object.more.start;i<Math.min(currentResults.length,object.more.start+25);i++) {
searchResults.editableList('addItem',currentResults[i])
}
if (results.length > object.more.start+25) {
if (currentResults.length > object.more.start+25) {
searchResults.editableList('addItem', {
more: {
results: results,
results: currentResults,
start: object.more.start+25
}
})
}
}
} else {
if (results.length > 0) {
reveal(results[Math.max(0,selected)].node);
if (currentResults.length > 0) {
reveal(currentResults[Math.max(0,selected)].node);
}
}
}
@@ -234,13 +299,13 @@ RED.search = (function() {
div.on("click", function(evt) {
evt.preventDefault();
searchResults.editableList('removeItem',object);
for (i=object.more.start;i<Math.min(results.length,object.more.start+25);i++) {
searchResults.editableList('addItem',results[i])
for (i=object.more.start;i<Math.min(currentResults.length,object.more.start+25);i++) {
searchResults.editableList('addItem',currentResults[i])
}
if (results.length > object.more.start+25) {
if (currentResults.length > object.more.start+25) {
searchResults.editableList('addItem', {
more: {
results: results,
results: currentResults,
start: object.more.start+25
}
})
@@ -253,17 +318,7 @@ RED.search = (function() {
var def = node._def;
div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
var colour = RED.utils.getNodeColor(node.type,def);
var icon_url = RED.utils.getNodeIcon(def,node);
if (node.type === 'tab') {
colour = "#C0DEED";
}
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
RED.utils.createNodeIcon(node).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-node-description"}).appendTo(div);
if (node.z) {
var workspace = RED.nodes.workspace(node.z);
@@ -308,7 +363,7 @@ RED.search = (function() {
$("#red-ui-palette-shade").show();
$("#red-ui-sidebar-shade").show();
$("#red-ui-sidebar-separator").hide();
indexWorkspace();
if (dialog === null) {
createDialog();
}
@@ -342,6 +397,28 @@ RED.search = (function() {
}
}
function clearIndex() {
index = {};
}
function addItemToIndex(item) {
indexNode(item);
}
function removeItemFromIndex(item) {
var keys = Object.keys(index);
for (var i=0,l=keys.length;i<l;i++) {
delete index[keys[i]][item.id];
if (Object.keys(index[keys[i]]).length === 0) {
delete index[keys[i]];
}
}
}
function updateItemOnIndex(item) {
removeItemFromIndex(item);
addItemToIndex(item);
}
function init() {
RED.actions.add("core:search",show);
@@ -358,12 +435,33 @@ RED.search = (function() {
$("#red-ui-editor-shade").on('mousedown',hide);
$("#red-ui-palette-shade").on('mousedown',hide);
$("#red-ui-sidebar-shade").on('mousedown',hide);
RED.events.on("workspace:clear", clearIndex);
RED.events.on("flows:add", addItemToIndex);
RED.events.on("flows:remove", removeItemFromIndex);
RED.events.on("flows:change", updateItemOnIndex);
RED.events.on("subflows:add", addItemToIndex);
RED.events.on("subflows:remove", removeItemFromIndex);
RED.events.on("subflows:change", updateItemOnIndex);
RED.events.on("nodes:add",addItemToIndex);
RED.events.on("nodes:remove",removeItemFromIndex);
RED.events.on("nodes:change",updateItemOnIndex);
RED.events.on("groups:add",addItemToIndex);
RED.events.on("groups:remove",removeItemFromIndex);
RED.events.on("groups:change",updateItemOnIndex);
}
return {
init: init,
show: show,
hide: hide
hide: hide,
search: search
};
})();

View File

@@ -250,6 +250,7 @@ RED.sidebar = (function() {
RED.popover.tooltip($("#red-ui-sidebar-separator").find(".red-ui-sidebar-control-right"),RED._("keyboard.toggleSidebar"),"core:toggle-sidebar");
showSidebar();
RED.sidebar.info.init();
RED.sidebar.help.init();
RED.sidebar.config.init();
RED.sidebar.context.init();
// hide info bar at start if screen rather narrow...

View File

@@ -106,7 +106,7 @@ RED.subflow = (function() {
RED.view.redraw();
$("#red-ui-subflow-input-add").addClass("active");
$("#red-ui-subflow-input-remove").removeClass("active");
RED.palette.refresh();
RED.events.emit("subflows:change",subflow);
}
function removeSubflowInput() {
@@ -128,7 +128,7 @@ RED.subflow = (function() {
$("#red-ui-subflow-input-add").removeClass("active");
$("#red-ui-subflow-input-remove").addClass("active");
activeSubflow.changed = true;
RED.palette.refresh();
RED.events.emit("subflows:change",activeSubflow);
return {subflowInputs: [ removedInput ], links:removedInputLinks};
}
@@ -169,7 +169,7 @@ RED.subflow = (function() {
RED.nodes.dirty(true);
RED.view.redraw();
$("#red-ui-subflow-output .spinner-value").text(subflow.out.length);
RED.palette.refresh();
RED.events.emit("subflows:change",subflow);
}
function removeSubflowOutput(removedSubflowOutputs) {
@@ -209,7 +209,7 @@ RED.subflow = (function() {
}
}
activeSubflow.changed = true;
RED.palette.refresh();
RED.events.emit("subflows:change",activeSubflow);
return {subflowOutputs: removedSubflowOutputs, links: removedLinks}
}
@@ -244,6 +244,7 @@ RED.subflow = (function() {
RED.view.select();
RED.nodes.dirty(true);
RED.view.redraw();
RED.events.emit("subflows:change",subflow);
$("#red-ui-subflow-status").prop("checked",!!subflow.status);
$("#red-ui-subflow-status").parent().parent().toggleClass("active",!!subflow.status);
}
@@ -283,9 +284,6 @@ RED.subflow = (function() {
}
n.inputs = activeSubflow.in.length;
n.outputs = activeSubflow.out.length;
while (n.outputs < n.ports.length) {
n.ports.pop();
}
n.resize = true;
n.dirty = true;
RED.editor.updateNodeProperties(n);
@@ -456,25 +454,29 @@ RED.subflow = (function() {
}
function removeSubflow(id) {
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
var removedNodes = [];
var removedLinks = [];
var removedGroups = [];
var activeSubflow = RED.nodes.subflow(id);
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+activeSubflow.id) {
if (n.type == "subflow:"+id) {
removedNodes.push(n);
}
if (n.z == activeSubflow.id) {
if (n.z == id) {
removedNodes.push(n);
}
});
RED.nodes.eachConfig(function(n) {
if (n.z == activeSubflow.id) {
if (n.z == id) {
removedNodes.push(n);
}
});
RED.nodes.groups(id).forEach(function(n) {
removedGroups.push(n);
})
var removedConfigNodes = [];
for (var i=0;i<removedNodes.length;i++) {
var removedEntities = RED.nodes.remove(removedNodes[i].id);
@@ -484,6 +486,18 @@ RED.subflow = (function() {
// TODO: this whole delete logic should be in RED.nodes.removeSubflow..
removedNodes = removedNodes.concat(removedConfigNodes);
removedGroups = RED.nodes.groups(id).filter(function(g) { return !g.g; });
for (i=0;i<removedGroups.length;i++) {
removedGroups[i].nodes.forEach(function(n) {
if (n.type === "group") {
removedGroups.push(n);
}
});
}
// Now remove them in the reverse order
for (i=removedGroups.length-1; i>=0; i--) {
RED.nodes.removeGroup(removedGroups[i]);
}
RED.nodes.removeSubflow(activeSubflow);
RED.workspaces.remove(activeSubflow);
RED.nodes.dirty(true);
@@ -492,6 +506,7 @@ RED.subflow = (function() {
return {
nodes:removedNodes,
links:removedLinks,
groups: removedGroups,
subflows: [activeSubflow]
}
}
@@ -1167,11 +1182,7 @@ RED.subflow = (function() {
default: DEFAULT_ENV_TYPE_LIST,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div>').css({
"background":"white",
"height":"100%",
"box-sizing": "border-box"
}).appendTo(container);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
$('<span><i class="fa fa-i-cursor"></i></span>').appendTo(input);
@@ -1185,10 +1196,7 @@ RED.subflow = (function() {
}
})
} else {
$("<span>").css({
"color":"#aaa",
"padding-left": "4px"
}).text("select types...").appendTo(input);
$('<span class="red-ui-editor-subflow-env-input-type-placeholder"></span>').text(RED._("editor.selectType")).appendTo(input);
}
}
},
@@ -1197,10 +1205,7 @@ RED.subflow = (function() {
label: RED._("typedInput.type.cred"), icon:"fa fa-lock", showLabel: false,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div>').css({
"background":"white",
"height":"100%",
"box-sizing": "border-box",
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type">').css({
"border-top-right-radius": "4px",
"border-bottom-right-radius": "4px"
}).appendTo(container);
@@ -1345,11 +1350,7 @@ RED.subflow = (function() {
label:RED._("editor.inputs.spinner"), icon:"fa fa-sort-numeric-asc", showLabel:false,
valueLabel: function(container,value) {
container.css("padding",0);
var innerContainer = $('<div>').css({
"background":"white",
"height":"100%",
"box-sizing": "border-box"
}).appendTo(container);
var innerContainer = $('<div class="red-ui-editor-subflow-env-input-type"></div>').appendTo(container);
var input = $('<div class="placeholder-input">').appendTo(innerContainer);
$('<span><i class="fa fa-sort-numeric-asc"></i></span>').appendTo(input);
@@ -1454,7 +1455,8 @@ RED.subflow = (function() {
}).on("change", function(evt,type) {
if (ui.type === 'input') {
ui.opts.types = inputCellInput.typedInput('value').split(",");
var types = inputCellInput.typedInput('value');
ui.opts.types = (types === "") ? ["str"] : types.split(",");
valueField.typedInput('types',ui.opts.types);
}
});

View File

@@ -0,0 +1,334 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.sidebar.help = (function() {
var content;
var toolbar;
var helpSection;
var panels;
var panelRatio;
var helpTopics = [];
var treeList;
var tocPanel;
var helpIndex = {};
function resizeStack() {
var h = $(content).parent().height() - toolbar.outerHeight();
panels.resize(h)
}
function init() {
content = document.createElement("div");
content.className = "red-ui-sidebar-info"
toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content);
$('<span class="button-group"><a id="red-ui-sidebar-help-show-toc" class="red-ui-button red-ui-button-small selected" href="#"><i class="fa fa-list-ul"></i></a></span>').appendTo(toolbar)
var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc')
RED.popover.tooltip(showTOCButton,RED._("sidebar.help.showTopics"));
showTOCButton.on("click",function(e) {
e.preventDefault();
if ($(this).hasClass('selected')) {
hideTOC();
} else {
showTOC();
}
});
var stackContainer = $("<div>",{class:"red-ui-sidebar-help-stack"}).appendTo(content);
tocPanel = $("<div>", {class: "red-ui-sidebar-help-toc"}).appendTo(stackContainer);
var helpPanel = $("<div>").css({
"overflow-y": "scroll"
}).appendTo(stackContainer);
panels = RED.panels.create({
container: stackContainer
})
panels.ratio(0.3);
helpSearch = $('<input type="text" data-i18n="[placeholder]sidebar.help.search">').appendTo(toolbar).searchBox({
style: "compact",
delay: 100,
change: function() {
var val = $(this).val().toLowerCase();
if (val) {
showTOC();
var c = treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return (item.nodeType && item.nodeType.indexOf(val) > -1) ||
(item.subflowLabel && item.subflowLabel.indexOf(val) > -1)
},true)
} else {
treeList.treeList('filter',null);
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected.id);
}
}
}
})
helpSection = $("<div>",{class:"red-ui-help"}).css({
"padding":"6px",
}).appendTo(helpPanel)
$('<span class="red-ui-help-info-none">'+RED._("sidebar.help.noHelp")+'</span>').appendTo(helpSection);
treeList = $("<div>").css({width: "100%"}).appendTo(tocPanel).treeList({data: []})
treeList.on('treelistselect', function(e,item) {
if (item.nodeType) {
showHelp(item.nodeType);
}
})
RED.sidebar.addTab({
id: "help",
label: RED._("sidebar.help.label"),
name: RED._("sidebar.help.name"),
iconClass: "fa fa-book",
action:"core:show-help-tab",
content: content,
pinned: true,
enableOnEdit: true,
onchange: function() {
resizeStack()
}
});
$(window).on("resize", resizeStack);
$(window).on("focus", resizeStack);
RED.events.on('registry:node-type-added', queueRefresh);
RED.events.on('registry:node-type-removed', queueRefresh);
RED.events.on('subflows:change', refreshSubflow);
RED.actions.add("core:show-help-tab",show);
}
var refreshTimer;
function queueRefresh() {
if (!refreshTimer) {
refreshTimer = setTimeout(function() {
refreshTimer = null;
refreshHelpIndex();
},500);
}
}
function refreshSubflow(sf) {
var item = treeList.treeList('get',"node-type:subflow:"+sf.id);
item.subflowLabel = sf._def.label().toLowerCase();
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
}
function hideTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (tocButton.hasClass('selected')) {
tocButton.removeClass('selected');
panelRatio = panels.ratio();
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(0)
setTimeout(function() {
tocPanel.css({"transition":""})
},250);
}
}
function showTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (!tocButton.hasClass('selected')) {
tocButton.addClass('selected');
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(Math.max(0.3,Math.min(panelRatio,0.7)));
setTimeout(function() {
tocPanel.css({"transition":""})
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected);
}
},250);
}
}
function refreshHelpIndex() {
helpTopics = [];
var modules = RED.nodes.registry.getModuleList();
var moduleNames = Object.keys(modules);
moduleNames.sort();
var helpData = [{
label: RED._("sidebar.help.nodeHelp"),
children: [],
expanded: true
}]
var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)});
if (subflows.length > 0) {
helpData[0].children.push({
label: RED._("menu.label.subflows"),
children: []
})
subflows.forEach(function(nodeType) {
var sf = RED.nodes.getType(nodeType);
helpData[0].children[0].children.push({
id:"node-type:"+nodeType,
nodeType: nodeType,
subflowLabel: sf.label().toLowerCase(),
element: getNodeLabel({_def:sf,type:sf.label()})
})
})
}
moduleNames.forEach(function(moduleName) {
var module = modules[moduleName];
var nodeTypes = [];
var setNames = Object.keys(module.sets);
setNames.forEach(function(setName) {
module.sets[setName].types.forEach(function(nodeType) {
if ($("script[data-help-name='"+nodeType+"']").length) {
nodeTypes.push({
id: "node-type:"+nodeType,
nodeType: nodeType,
element:getNodeLabel({_def:RED.nodes.getType(nodeType),type:nodeType})
})
}
})
})
if (nodeTypes.length > 0) {
nodeTypes.sort(function(A,B) {
return A.nodeType.localeCompare(B.nodeType)
})
helpData[0].children.push({
id: moduleName,
icon: "fa fa-cube",
label: moduleName,
children: nodeTypes
})
}
});
treeList.treeList("data",helpData);
}
function getNodeLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
$('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).text(n.name||n.type).appendTo(contentDiv);
return div;
}
function showHelp(nodeType) {
helpSection.empty();
var helpText;
var title;
var m = /^subflow(:(.+))?$/.exec(nodeType);
if (m && m[2]) {
var subflowNode = RED.nodes.subflow(m[2]);
helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
title = subflowNode.name || nodeType;
} else {
helpText = $("script[data-help-name='"+nodeType+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
title = nodeType;
}
setInfoText(title, helpText, helpSection);
var ratio = panels.ratio();
if (ratio > 0.7) {
panels.ratio(0.7)
}
treeList.treeList("show","node-type:"+nodeType)
treeList.treeList("select","node-type:"+nodeType, false);
}
function show(type) {
RED.sidebar.show("help");
if (type) {
hideTOC();
showHelp(type);
}
resizeStack();
}
// TODO: DRY - projects.js
function addTargetToExternalLinks(el) {
$(el).find("a").each(function(el) {
var href = $(this).attr('href');
if (/^https?:/.test(href)) {
$(this).attr('target','_blank');
}
});
return el;
}
function setInfoText(title, infoText,target) {
if (title) {
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(target);
}
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
var foldingHeader = "H3";
info.find(foldingHeader).wrapInner('<a class="red-ui-help-info-header expanded" href="#"></a>')
.find("a").prepend('<i class="fa fa-angle-right">').on("click", function(e) {
e.preventDefault();
var isExpanded = $(this).hasClass('expanded');
var el = $(this).parent().next();
while(el.length === 1 && el[0].nodeName !== foldingHeader) {
el.toggle(!isExpanded);
el = el.next();
}
$(this).toggleClass('expanded',!isExpanded);
})
target.parent().scrollTop(0);
}
function set(html,title) {
$(helpSection).empty();
setInfoText(title,html,helpSection);
hideTOC();
show();
}
function refreshSelection(selection) {
if (selection === undefined) {
selection = RED.view.selection();
}
if (selection.nodes) {
if (selection.nodes.length == 1) {
var node = selection.nodes[0];
if (node.type === "subflow" && node.direction) {
// ignore subflow virtual ports
} else if (node.type !== 'group'){
showHelp(node.type);
}
}
}
}
RED.events.on("view:selection-changed",refreshSelection);
return {
init: init,
show: show,
set: set
}
})();

View File

@@ -0,0 +1,629 @@
RED.sidebar.info.outliner = (function() {
var treeList;
var searchInput;
var activeSearch;
var projectInfo;
var projectInfoLabel;
var flowList;
var subflowList;
var globalConfigNodes;
var objects = {};
var missingParents = {};
var configNodeTypes;
function getFlowData() {
var flowData = [
{
label: RED._("menu.label.flows"),
expanded: true,
children: []
},
{
id: "__subflow__",
label: RED._("menu.label.subflows"),
children: [
getEmptyItem("__subflow__")
]
},
{
id: "__global__",
flow: "__global__",
label: RED._("sidebar.info.globalConfig"),
types: {},
children: [
getEmptyItem("__global__")
]
}
]
flowList = flowData[0];
subflowList = flowData[1];
globalConfigNodes = flowData[2];
configNodeTypes = { __global__: globalConfigNodes};
return flowData;
}
function getProjectLabel(p) {
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
div.css("width", "calc(100% - 40px)");
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
contentDiv.text(p.name);
var controls = $('<div>',{class:"red-ui-info-outline-item-controls"}).appendTo(div);
var editProjectButton = $('<button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;top: 3px;"><i class="fa fa-ellipsis-h"></i></button>')
.appendTo(controls)
.on("click", function(evt) {
evt.preventDefault();
RED.projects.editProject();
});
RED.popover.tooltip(editProjectButton,RED._('sidebar.project.showProjectSettings'));
return div;
}
var empties = {};
function getEmptyItem(id) {
var item = {
empty: true,
element: $('<div class="red-ui-info-outline-item red-ui-info-outline-item-empty">').text(RED._("sidebar.info.empty")),
}
empties[id] = item;
return item;
}
function getNodeLabelText(n) {
var label = n.name || n.type+": "+n.id;
if (n._def.label) {
try {
label = (typeof n._def.label === "function" ? n._def.label.call(n) : n._def.label)||"";
} catch(err) {
console.log("Definition error: "+type+".label",err);
}
}
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
return label;
}
function getNodeLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
var labelText = getNodeLabelText(n);
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
if (labelText) {
label.text(labelText)
} else {
label.html("&nbsp;")
}
addControls(n, div);
return div;
}
function getFlowLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
var label = (typeof n === "string")? n : n.label;
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
contentDiv.text(label);
addControls(n, div);
return div;
}
function getSubflowLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
var labelText = getNodeLabelText(n);
var label = $('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).appendTo(contentDiv);
if (labelText) {
label.text(labelText)
} else {
label.html("&nbsp;")
}
addControls(n, div);
return div;
// var div = $('<div>',{class:"red-ui-info-outline-item red-ui-info-outline-item-flow"});
// var contentDiv = $('<div>',{class:"red-ui-search-result-description red-ui-info-outline-item-label"}).appendTo(div);
// contentDiv.text(n.name || n.id);
// addControls(n, div);
// return div;
}
function addControls(n,div) {
var controls = $('<div>',{class:"red-ui-info-outline-item-controls red-ui-info-outline-item-hover-controls"}).appendTo(div);
if (n._def.category === "config" && n.type !== "group") {
var userCountBadge = $('<button type="button" class="red-ui-info-outline-item-control-users red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').text(n.users.length).appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.search.show("uses:"+n.id);
})
RED.popover.tooltip(userCountBadge,function() { return RED._('editor.nodesUse',{count:n.users.length})});
}
if (n._def.button) {
var triggerButton = $('<button type="button" class="red-ui-info-outline-item-control-action red-ui-button red-ui-button-small"><i class="fa fa-toggle-right"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.view.clickNodeButton(n);
})
RED.popover.tooltip(triggerButton,RED._("sidebar.info.triggerAction"));
}
// $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-eye"></i></button>').appendTo(controls).on("click",function(evt) {
// evt.preventDefault();
// evt.stopPropagation();
// RED.view.reveal(n.id);
// })
if (n.type !== 'group' && n.type !== 'subflow') {
var toggleButton = $('<button type="button" class="red-ui-info-outline-item-control-disable red-ui-button red-ui-button-small"><i class="fa fa-circle-thin"></i><i class="fa fa-ban"></i></button>').appendTo(controls).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (n.type === 'tab') {
if (n.disabled) {
RED.workspaces.enable(n.id)
} else {
RED.workspaces.disable(n.id)
}
} else {
// TODO: this ought to be a utility function in RED.nodes
var historyEvent = {
t: "edit",
node: n,
changed: n.changed,
changes: {
d: n.d
},
dirty:RED.nodes.dirty()
}
if (n.d) {
delete n.d;
} else {
n.d = true;
}
n.dirty = true;
n.changed = true;
RED.events.emit("nodes:change",n);
RED.nodes.dirty(true)
RED.view.redraw();
}
});
RED.popover.tooltip(toggleButton,function() {
return RED._("common.label."+(((n.type==='tab' && n.disabled) || (n.type!=='tab' && n.d))?"enable":"disable"));
});
} else {
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
}
controls.find("button").on("dblclick", function(evt) {
evt.preventDefault();
evt.stopPropagation();
})
}
function onProjectLoad(activeProject) {
objects = {};
var newFlowData = getFlowData();
projectInfoLabel.empty();
getProjectLabel(activeProject).appendTo(projectInfoLabel);
projectInfo.show();
treeList.treeList('data',newFlowData);
}
function build() {
var container = $("<div>", {class:"red-ui-info-outline"}).css({'height': '100%'});
var toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(container);
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.search">').appendTo(toolbar).searchBox({
style: "compact",
delay: 500,
change: function() {
var val = $(this).val();
var searchResults = RED.search.search(val);
if (val) {
activeSearch = val;
var resultMap = {};
for (var i=0,l=searchResults.length;i<l;i++) {
resultMap[searchResults[i].node.id] = true;
}
var c = treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return item.id && objects[item.id] && resultMap[item.id]
},true)
} else {
activeSearch = null;
treeList.treeList('filter',null);
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected.id);
}
}
},
options: [
{label:RED._("sidebar.info.search.configNodes"), value:"is:config"},
{label:RED._("sidebar.info.search.unusedConfigNodes"), value:"is:config is:unused"},
{label:RED._("sidebar.info.search.invalidNodes"), value: "is:invalid"},
{label:RED._("sidebar.info.search.uknownNodes"), value: "type:unknown"},
{label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"},
]
});
projectInfo = $('<div class="red-ui-treeList-label red-ui-info-outline-project"><span class="red-ui-treeList-icon"><i class="fa fa-archive"></i></span></div>').hide().appendTo(container)
projectInfoLabel = $('<span>').appendTo(projectInfo);
// <div class="red-ui-info-outline-item red-ui-info-outline-item-flow" style=";"><div class="red-ui-search-result-description red-ui-info-outline-item-label">Space Monkey</div><div class="red-ui-info-outline-item-controls"><button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;"><i class="fa fa-ellipsis-h"></i></button></div></div></div>').appendTo(container)
treeList = $("<div>").css({width: "100%"}).appendTo(container).treeList({
data:getFlowData()
})
treeList.on('treelistselect', function(e,item) {
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
if (node) {
if (node.type === 'group' || node._def.category !== "config") {
RED.view.select({nodes:[node]})
} else {
RED.view.select({nodes:[]})
}
}
})
treeList.on('treelistconfirm', function(e,item) {
var node = RED.nodes.node(item.id);
if (node) {
if (node._def.category === "config") {
RED.editor.editConfig("", node.type, node.id);
} else {
RED.editor.edit(node);
}
}
})
RED.events.on("projects:load", onProjectLoad)
RED.events.on("flows:add", onFlowAdd)
RED.events.on("flows:remove", onObjectRemove)
RED.events.on("flows:change", onFlowChange)
RED.events.on("flows:reorder", onFlowsReorder)
RED.events.on("subflows:add", onSubflowAdd)
RED.events.on("subflows:remove", onObjectRemove)
RED.events.on("subflows:change", onSubflowChange)
RED.events.on("nodes:add",onNodeAdd);
RED.events.on("nodes:remove",onObjectRemove);
RED.events.on("nodes:change",onNodeChange);
RED.events.on("groups:add",onNodeAdd);
RED.events.on("groups:remove",onObjectRemove);
RED.events.on("groups:change",onNodeChange);
RED.events.on("workspace:clear", onWorkspaceClear)
return container;
}
function onWorkspaceClear() {
treeList.treeList('data',getFlowData());
}
function onFlowAdd(ws) {
objects[ws.id] = {
id: ws.id,
element: getFlowLabel(ws),
children:[],
deferBuild: true,
icon: "red-ui-icons red-ui-icons-flow",
gutter: getGutter(ws)
}
if (missingParents[ws.id]) {
objects[ws.id].children = missingParents[ws.id];
delete missingParents[ws.id]
} else {
objects[ws.id].children.push(getEmptyItem(ws.id));
}
flowList.treeList.addChild(objects[ws.id])
objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
updateSearch();
}
function onFlowChange(n) {
var existingObject = objects[n.id];
var label = n.label || n.id;
var newlineIndex = label.indexOf("\\n");
if (newlineIndex > -1) {
label = label.substring(0,newlineIndex)+"...";
}
existingObject.element.find(".red-ui-info-outline-item-label").text(label);
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
updateSearch();
}
function onFlowsReorder(order) {
var indexMap = {};
order.forEach(function(id,index) {
indexMap[id] = index;
})
flowList.treeList.sortChildren(function(A,B) {
if (A.id === "__global__") { return -1 }
if (B.id === "__global__") { return 1 }
return indexMap[A.id] - indexMap[B.id]
})
}
function onSubflowAdd(sf) {
objects[sf.id] = {
id: sf.id,
element: getNodeLabel(sf),
children:[],
deferBuild: true,
gutter: getGutter(sf)
}
if (missingParents[sf.id]) {
objects[sf.id].children = missingParents[sf.id];
delete missingParents[sf.id]
} else {
objects[sf.id].children.push(getEmptyItem(sf.id));
}
if (empties["__subflow__"]) {
empties["__subflow__"].treeList.remove();
delete empties["__subflow__"];
}
subflowList.treeList.addChild(objects[sf.id])
updateSearch();
}
function onSubflowChange(sf) {
var existingObject = objects[sf.id];
existingObject.treeList.replaceElement(getNodeLabel(sf));
// existingObject.element.find(".red-ui-info-outline-item-label").text(n.name || n.id);
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+sf.id) {
var sfInstance = objects[n.id];
sfInstance.treeList.replaceElement(getNodeLabel(n));
}
});
updateSearch();
}
function onNodeChange(n) {
var existingObject = objects[n.id];
var parent = n.g||n.z||"__global__";
var nodeLabelText = getNodeLabelText(n);
if (nodeLabelText) {
existingObject.element.find(".red-ui-info-outline-item-label").text(nodeLabelText);
} else {
existingObject.element.find(".red-ui-info-outline-item-label").html("&nbsp;");
}
var existingParent = existingObject.parent.id;
if (!existingParent) {
existingParent = existingObject.parent.parent.flow
}
if (parent !== existingParent) {
var parentItem = existingObject.parent;
existingObject.treeList.remove(true);
if (parentItem.children.length === 0) {
if (parentItem.config) {
// this is a config
parentItem.treeList.remove();
// console.log("Removing",n.type,"from",parentItem.parent.id||parentItem.parent.parent.id)
delete configNodeTypes[parentItem.parent.id||parentItem.parent.parent.id].types[n.type];
if (parentItem.parent.children.length === 0) {
if (parentItem.parent.id === "__global__") {
parentItem.parent.treeList.addChild(getEmptyItem(parentItem.parent.id));
} else {
delete configNodeTypes[parentItem.parent.parent.id];
parentItem.parent.treeList.remove();
if (parentItem.parent.parent.children.length === 0) {
parentItem.parent.parent.treeList.addChild(getEmptyItem(parentItem.parent.parent.id));
}
}
}
} else {
parentItem.treeList.addChild(getEmptyItem(parentItem.id));
}
}
if (n._def.category === 'config' && n.type !== 'group') {
// This must be a config node that has been rescoped
createFlowConfigNode(parent,n.type);
configNodeTypes[parent].types[n.type].treeList.addChild(objects[n.id]);
} else {
// This is a node that has moved groups
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
objects[parent].treeList.addChild(existingObject)
}
// if (parent === "__global__") {
// // Global always exists here
// if (!configNodeTypes[parent][n.type]) {
// configNodeTypes[parent][n.type] = {
// config: true,
// label: n.type,
// children: []
// }
// globalConfigNodes.treeList.addChild(configNodeTypes[parent][n.type])
// }
// configNodeTypes[parent][n.type].treeList.addChild(existingObject);
// } else {
// if (empties[parent]) {
// empties[parent].treeList.remove();
// delete empties[parent];
// }
// objects[parent].treeList.addChild(existingObject)
// }
}
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
if (n._def.category === "config" && n.type !== 'group') {
existingObject.element.find(".red-ui-info-outline-item-control-users").text(n.users.length);
}
updateSearch();
}
function onObjectRemove(n) {
var existingObject = objects[n.id];
existingObject.treeList.remove();
delete objects[n.id]
// If this is a group being removed, it may have an empty item
if (empties[n.id]) {
delete empties[n.id];
}
var parent = existingObject.parent;
if (parent.children.length === 0) {
if (parent.config) {
// this is a config
parent.treeList.remove();
delete configNodeTypes[parent.parent.id||n.z].types[n.type];
if (parent.parent.children.length === 0) {
if (parent.parent.id === "__global__") {
parent.parent.treeList.addChild(getEmptyItem(parent.parent.id));
} else {
delete configNodeTypes[n.z];
parent.parent.treeList.remove();
if (parent.parent.parent.children.length === 0) {
parent.parent.parent.treeList.addChild(getEmptyItem(parent.parent.parent.id));
}
}
}
} else {
parent.treeList.addChild(getEmptyItem(parent.id));
}
}
}
function getGutter(n) {
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
evt.preventDefault();
evt.stopPropagation();
RED.view.reveal(n.id);
})
RED.popover.tooltip(revealButton,RED._("sidebar.info.find"));
return span;
}
function createFlowConfigNode(parent,type) {
// console.log("createFlowConfig",parent,type,configNodeTypes[parent]);
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
if (!configNodeTypes[parent]) {
// There is no 'config nodes' item in the parent flow
configNodeTypes[parent] = {
config: true,
flow: parent,
types: {},
label: RED._("menu.label.displayConfig"),
children: []
}
objects[parent].treeList.insertChildAt(configNodeTypes[parent],0);
// console.log("CREATED", parent)
}
if (!configNodeTypes[parent].types[type]) {
configNodeTypes[parent].types[type] = {
config: true,
label: type,
children: []
}
configNodeTypes[parent].treeList.addChild(configNodeTypes[parent].types[type]);
// console.log("CREATED", parent,type)
}
}
function onNodeAdd(n) {
objects[n.id] = {
id: n.id,
element: getNodeLabel(n),
gutter: getGutter(n)
}
if (n.type === "group") {
objects[n.id].children = [];
objects[n.id].deferBuild = true;
if (missingParents[n.id]) {
objects[n.id].children = missingParents[n.id];
delete missingParents[n.id]
}
}
var parent = n.g||n.z||"__global__";
if (n._def.category !== "config" || n.type === 'group') {
if (objects[parent]) {
if (empties[parent]) {
empties[parent].treeList.remove();
delete empties[parent];
}
if (objects[parent].treeList) {
objects[parent].treeList.addChild(objects[n.id]);
} else {
objects[parent].children.push(objects[n.id])
}
} else {
missingParents[parent] = missingParents[parent]||[];
missingParents[parent].push(objects[n.id])
}
} else {
createFlowConfigNode(parent,n.type);
configNodeTypes[parent].types[n.type].treeList.addChild(objects[n.id]);
}
objects[n.id].element.toggleClass("red-ui-info-outline-item-disabled", !!n.d)
updateSearch();
}
var updateSearchTimer;
function updateSearch() {
if (updateSearchTimer) {
clearTimeout(updateSearchTimer)
}
if (activeSearch) {
updateSearchTimer = setTimeout(function() {
searchInput.searchBox("change");
},100);
}
}
function onSelectionChanged(selection) {
// treeList.treeList('clearSelection');
}
return {
build: build,
search: function(val) {
searchInput.searchBox('value',val)
},
select: function(node) {
if (node) {
if (Array.isArray(node)) {
treeList.treeList('select', node.map(function(n) { return objects[n.id] }), false)
} else {
treeList.treeList('select', objects[node.id], false)
}
} else {
treeList.treeList('clearSelection')
}
},
reveal: function(node) {
treeList.treeList('show', objects[node.id])
}
}
})();

View File

@@ -16,16 +16,32 @@
RED.sidebar.info = (function() {
var content;
var sections;
var propertiesSection;
var panels;
var infoSection;
var helpSection;
var propertiesPanelContent;
var propertiesPanelHeader;
var propertiesPanelHeaderIcon;
var propertiesPanelHeaderLabel;
var propertiesPanelHeaderReveal;
var propertiesPanelHeaderHelp;
var selectedObject;
var tipContainer;
var tipBox;
// TODO: remove this
var expandedSections = {
"property": false
};
function resizeStack() {
if (panels) {
var h = $(content).parent().height() - tipContainer.outerHeight();
panels.resize(h)
}
}
function init() {
content = document.createElement("div");
@@ -35,31 +51,81 @@ RED.sidebar.info = (function() {
var stackContainer = $("<div>",{class:"red-ui-sidebar-info-stack"}).appendTo(content);
sections = RED.stack.create({
container: stackContainer
}).hide();
var outlinerPanel = $("<div>").css({
"overflow": "hidden",
"height": "calc(70%)"
}).appendTo(stackContainer);
var propertiesPanel = $("<div>").css({
"overflow":"hidden",
"height":"100%",
"display": "flex",
"flex-direction": "column"
}).appendTo(stackContainer);
propertiesPanelHeader = $("<div>", {class:"red-ui-palette-header red-ui-info-header"}).css({
"flex":"0 0 auto"
}).appendTo(propertiesPanel);
propertiesSection = sections.add({
title: RED._("sidebar.info.info"),
collapsible: true
propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderLabel = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderHelp = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
position: 'absolute',
top: '12px',
right: '32px'
}).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (selectedObject) {
RED.sidebar.help.show(selectedObject.type);
}
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
propertiesPanelHeaderReveal = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
position: 'absolute',
top: '12px',
right: '8px'
}).on("click", function(evt) {
evt.preventDefault();
evt.stopPropagation();
if (selectedObject) {
RED.sidebar.info.outliner.reveal(selectedObject);
RED.view.reveal(selectedObject.id);
}
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderReveal,RED._("sidebar.help.showInOutline"));
propertiesPanelContent = $("<div>").css({
"flex":"1 1 auto",
"overflow-y":"scroll",
}).appendTo(propertiesPanel);
panels = RED.panels.create({container: stackContainer})
panels.ratio(0.6);
RED.sidebar.info.outliner.build().appendTo(outlinerPanel);
RED.sidebar.addTab({
id: "info",
label: RED._("sidebar.info.label"),
name: RED._("sidebar.info.name"),
iconClass: "fa fa-info",
action:"core:show-info-tab",
content: content,
pinned: true,
enableOnEdit: true
});
propertiesSection.expand();
infoSection = sections.add({
title: RED._("sidebar.info.desc"),
collapsible: true
});
infoSection.expand();
infoSection.content.css("padding","6px");
RED.events.on("sidebar:resize", resizeStack);
helpSection = sections.add({
title: RED._("sidebar.info.nodeHelp"),
collapsible: true
});
helpSection.expand();
helpSection.content.css("padding","6px");
$(window).on("resize", resizeStack);
$(window).on("focus", resizeStack);
var tipContainer = $('<div class="red-ui-help-tips"></div>').appendTo(content);
// Tip Box
tipContainer = $('<div class="red-ui-help-tips"></div>').appendTo(content);
tipBox = $('<div class="red-ui-help-tip"></div>').appendTo(tipContainer);
var tipButtons = $('<div class="red-ui-help-tips-buttons"></div>').appendTo(tipContainer);
@@ -75,17 +141,6 @@ RED.sidebar.info = (function() {
RED.actions.invoke("core:toggle-show-tips");
RED.notify(RED._("sidebar.info.showTips"));
});
RED.sidebar.addTab({
id: "info",
label: RED._("sidebar.info.label"),
name: RED._("sidebar.info.name"),
iconClass: "fa fa-info",
action:"core:show-info-tab",
content: content,
pinned: true,
enableOnEdit: true
});
if (tips.enabled()) {
tips.start();
} else {
@@ -113,41 +168,30 @@ RED.sidebar.info = (function() {
refreshSelection();
return;
}
sections.show();
$(propertiesSection.content).empty();
$(infoSection.content).empty();
$(helpSection.content).empty();
infoSection.title.text(RED._("sidebar.info.desc"));
$(propertiesPanelContent).empty();
var propRow;
var table = $('<table class="red-ui-info-table"></table>').appendTo(propertiesSection.content);
var table = $('<table class="red-ui-info-table"></table>').appendTo(propertiesPanelContent);
var tableBody = $('<tbody>').appendTo(table);
var subflowNode;
var subflowUserCount;
var activeProject = RED.projects.getActiveProject();
if (activeProject) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+ RED._("sidebar.project.name") + '</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).text(activeProject.name||"");
$('<tr class="red-ui-help-property-expand blank"><td colspan="2"></td></tr>').appendTo(tableBody);
var editProjectButton = $('<button class="red-ui-button red-ui-button-small" style="position:absolute;right:2px;"><i class="fa fa-ellipsis-h"></i></button>')
.appendTo(propRow.children()[1])
.on("click", function(evt) {
evt.preventDefault();
RED.projects.editProject();
});
RED.popover.tooltip(editProjectButton,RED._('sidebar.project.showProjectSettings'));
}
propertiesSection.container.show();
infoSection.container.show();
helpSection.container.show();
if (node === null) {
RED.sidebar.info.outliner.select(null);
return;
} else if (Array.isArray(node)) {
// Multiple things selected
// - hide help and info sections
RED.sidebar.info.outliner.select(node);
propertiesPanelHeaderIcon.empty();
RED.utils.createNodeIcon({type:"_selection_"}).appendTo(propertiesPanelHeaderIcon);
propertiesPanelHeaderLabel.text("Selection");
propertiesPanelHeaderReveal.hide();
propertiesPanelHeaderHelp.hide();
selectedObject = null;
var types = {
nodes:0,
@@ -167,8 +211,7 @@ RED.sidebar.info = (function() {
types.nodes++;
}
});
helpSection.container.hide();
infoSection.container.hide();
// infoSection.container.hide();
// - show the count of selected nodes
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.selection")+"</td><td></td></tr>").appendTo(tableBody);
@@ -188,42 +231,53 @@ RED.sidebar.info = (function() {
} else {
// A single 'thing' selected.
RED.sidebar.info.outliner.select(node);
// Check to see if this is a subflow or subflow instance
var m = /^subflow(:(.+))?$/.exec(node.type);
if (m) {
if (m[2]) {
subflowNode = RED.nodes.subflow(m[2]);
var subflowRegex = /^subflow(:(.+))?$/.exec(node.type);
if (subflowRegex) {
if (subflowRegex[2]) {
subflowNode = RED.nodes.subflow(subflowRegex[2]);
} else {
subflowNode = node;
}
subflowUserCount = 0;
var subflowType = "subflow:"+subflowNode.id;
RED.nodes.eachNode(function(n) {
if (n.type === subflowType) {
subflowUserCount++;
}
});
subflowUserCount = subflowNode.instances.length;
}
propertiesPanelHeaderIcon.empty();
RED.utils.createNodeIcon(node).appendTo(propertiesPanelHeaderIcon);
var objectLabel = RED.utils.getNodeLabel(node, node.type+": "+node.id)
var newlineIndex = objectLabel.indexOf("\\n");
if (newlineIndex > -1) {
objectLabel = objectLabel.substring(0,newlineIndex)+"...";
}
propertiesPanelHeaderLabel.text(objectLabel);
propertiesPanelHeaderReveal.show();
selectedObject = node;
propRow = $('<tr class="red-ui-help-info-row"><td></td><td></td></tr>').appendTo(tableBody);
var objectType = "node";
if (node.type === "subflow" || subflowRegex) {
objectType = "subflow";
} else if (node.type === "tab") {
objectType = "flow";
}else if (node.type === "group") {
objectType = "group";
}
$(propRow.children()[0]).text(RED._("sidebar.info."+objectType))
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
if (node.type === "tab" || node.type === "subflow") {
// If nothing is selected, but we're on a flow or subflow tab.
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info."+(node.type==='tab'?'flow':'subflow'))+'</td><td></td></tr>').appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.tabName")+"</td><td></td></tr>").appendTo(tableBody);
$(propRow.children()[1]).text(node.label||node.name||"");
if (node.type === "tab") {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
}
propertiesPanelHeaderHelp.hide();
} else if (node.type === "group") {
// An actual node is selected in the editor - build up its properties table
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.group")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
if (node.name) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
$('<span class="red-ui-text-bidi-aware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
}
propertiesPanelHeaderHelp.hide();
propRow = $('<tr class="red-ui-help-info-row"><td>&nbsp;</td><td></td></tr>').appendTo(tableBody);
var typeCounts = {
nodes:0,
groups: 0
@@ -246,22 +300,21 @@ RED.sidebar.info = (function() {
} else {
// An actual node is selected in the editor - build up its properties table
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
if (node.type !== "subflow" && node.type !== "unknown" && node.name) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
$('<span class="red-ui-text-bidi-aware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
}
if (!m) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+"</td><td></td></tr>").appendTo(tableBody);
propertiesPanelHeaderHelp.show();
if (!subflowRegex) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).text((node.type === "unknown")?node._orig.type:node.type);
if (node.type === "unknown") {
$('<span style="float: right; font-size: 0.8em"><i class="fa fa-warning"></i></span>').prependTo($(propRow.children()[1]))
}
}
var count = 0;
if (!m && node.type != "subflow" && node.type != "group") {
if (!subflowRegex && node.type != "subflow" && node.type != "group") {
var blankRow = $('<tr class="red-ui-help-property-expand blank"><td colspan="2"></td></tr>').appendTo(tableBody);
var defaults;
if (node.type === 'unknown') {
defaults = {};
@@ -276,7 +329,6 @@ RED.sidebar.info = (function() {
$(propRow.children()[1]).text(RED.nodes.getType(node.type).set.module);
count++;
}
$('<tr class="red-ui-help-property-expand red-ui-help-info-property-row blank'+(expandedSections.property?"":" hide")+'"><td colspan="2"></td></tr>').appendTo(tableBody);
if (defaults) {
for (var n in defaults) {
@@ -284,7 +336,8 @@ RED.sidebar.info = (function() {
var val = node[n];
var type = typeof val;
count++;
propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td>'+n+"</td><td></td></tr>").appendTo(tableBody);
propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td></td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[0]).text(n);
if (defaults[n].type) {
var configNode = RED.nodes.node(val);
if (!configNode) {
@@ -314,37 +367,35 @@ RED.sidebar.info = (function() {
}
}
if (count > 0) {
$('<tr class="red-ui-help-property-expand blank"><td colspan="2"><a href="#" class="node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="red-ui-help-property-more">'+RED._("sidebar.info.showMore")+'</span><span class="red-ui-help-property-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a></td></tr>').appendTo(tableBody);
$('<a href="#" class="node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="red-ui-help-property-more">'+RED._("sidebar.info.showMore")+'</span><span class="red-ui-help-property-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a>').appendTo(blankRow.children()[0]);
}
}
if (node.type !== 'tab') {
if (m) {
if (subflowRegex) {
$('<tr class="blank"><th colspan="2">'+RED._("sidebar.info.subflow")+'</th></tr>').appendTo(tableBody);
$('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+RED.utils.sanitize(subflowNode.name)+'</span></td></tr>').appendTo(tableBody);
}
}
}
if (m) {
if (subflowRegex) {
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody);
var category = subflowNode.category||"subflows";
$(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category}))
$('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+subflowUserCount+'</td></tr>').appendTo(tableBody);
}
var helpText = "";
if (node.type === "tab" || node.type === "subflow") {
$(helpSection.container).hide();
} else {
$(helpSection.container).show();
if (subflowNode && node.type !== "subflow") {
// Selected a subflow instance node.
// - The subflow template info goes into help
helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
} else {
helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
}
setInfoText(helpText, helpSection.content);
}
// var helpText = "";
// if (node.type === "tab" || node.type === "subflow") {
// } else {
// if (subflowNode && node.type !== "subflow") {
// // Selected a subflow instance node.
// // - The subflow template info goes into help
// helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
// } else {
// helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// }
// setInfoText(helpText, helpSection.content);
// }
var infoText = "";
@@ -356,7 +407,26 @@ RED.sidebar.info = (function() {
if (node.info) {
infoText = infoText + RED.utils.renderMarkdown(node.info || "")
}
setInfoText(infoText, infoSection.content);
var infoSectionContainer = $("<div>").css("padding","0 6px 6px").appendTo(propertiesPanelContent)
// var editInfo = $('<button class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-file-text-o"></button>').appendTo(infoSectionContainer).on("click", function(evt) {
// //.text(RED._("sidebar.info.editDescription"))
// evt.preventDefault();
// evt.stopPropagation();
// if (node.type === 'tab') {
//
// } else if (node.type === 'subflow') {
//
// } else if (node.type === 'group') {
//
// } else if (node._def.category !== 'config') {
// RED.editor.edit(node,"editor-tab-description");
// } else {
//
// }
// })
setInfoText(infoText, infoSectionContainer);
$(".red-ui-sidebar-info-stack").scrollTop(0);
$(".node-info-property-header").on("click", function(e) {
@@ -372,7 +442,7 @@ RED.sidebar.info = (function() {
// propRow = $('<tr class="red-ui-help-info-row"><td>Actions</td><td></td></tr>').appendTo(tableBody);
// var actionBar = $(propRow.children()[1]);
//
// // var actionBar = $('<div>',{style:"background: #fefefe; padding: 3px;"}).appendTo(propertiesSection.content);
// // var actionBar = $('<div>',{style:"background: #fefefe; padding: 3px;"}).appendTo(propertiesPanel);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
// $('<button type="button" class="red-ui-button"><i class="fa fa-code"></i></button>').appendTo(actionBar);
@@ -447,6 +517,7 @@ RED.sidebar.info = (function() {
}
function startTips() {
$(".red-ui-sidebar-info").addClass('show-tips');
resizeStack();
if (enabled) {
if (!startTimeout && !refreshTimeout) {
if (tipCount === -1) {
@@ -460,6 +531,7 @@ RED.sidebar.info = (function() {
}
function stopTips() {
$(".red-ui-sidebar-info").removeClass('show-tips');
resizeStack();
clearInterval(refreshTimeout);
clearTimeout(startTimeout);
refreshTimeout = null;
@@ -484,15 +556,8 @@ RED.sidebar.info = (function() {
}
function set(html,title) {
// tips.stop();
// sections.show();
refresh(null);
propertiesSection.container.hide();
helpSection.container.hide();
infoSection.container.show();
infoSection.title.text(title||RED._("sidebar.info.desc"));
setInfoText(html,infoSection.content);
$(".red-ui-sidebar-info-stack").scrollTop(0);
console.warn("Deprecated use of RED.sidebar.info.set - use RED.sidebar.help.set instead")
RED.sidebar.help.set(html,title);
}
function refreshSelection(selection) {

View File

@@ -112,14 +112,14 @@ RED.touch.radialMenu = (function() {
if (!opt.disabled) {
if (p[0]>opt.x-30 && p[0]<opt.x+30 && p[1]>opt.y-30 && p[1]<opt.y+30) {
if (opt !== activeOption) {
opt.el.style("background","#999");
opt.el.classed("selected",true);
activeOption = opt;
}
} else if (opt === activeOption) {
opt.el.style("background","#fff");
activeOption = null;
} else {
opt.el.style("background","#fff");
if (opt === activeOption) {
activeOption = null;
}
opt.el.classed("selected",false);
}
}
}

View File

@@ -241,10 +241,13 @@ RED.typeSearch = (function() {
$(document).off('mousedown.red-ui-type-search');
$(document).off('mouseup.red-ui-type-search');
$(document).off('click.red-ui-type-search');
$(document).off('touchstart.red-ui-type-search');
$(document).off('mousedown.red-ui-type-search');
setTimeout(function() {
$(document).on('mousedown.red-ui-type-search',handleMouseActivity);
$(document).on('mouseup.red-ui-type-search',handleMouseActivity);
$(document).on('click.red-ui-type-search',handleMouseActivity);
$(document).on('touchstart.red-ui-type-search',handleMouseActivity);
},200);
refreshTypeList(opts);
@@ -260,7 +263,9 @@ RED.typeSearch = (function() {
searchResultsDiv.slideDown(300);
setTimeout(function() {
searchResultsDiv.find(".red-ui-editableList-container").scrollTop(0);
searchInput.trigger("focus");
if (!opts.disableFocus) {
searchInput.trigger("focus");
}
},100);
}
function hide(fast) {
@@ -279,6 +284,7 @@ RED.typeSearch = (function() {
$(document).off('mousedown.red-ui-type-search');
$(document).off('mouseup.red-ui-type-search');
$(document).off('click.red-ui-type-search');
$(document).off('touchstart.red-ui-type-search');
}
}
function getTypeLabel(type, def) {

View File

@@ -806,9 +806,9 @@ RED.utils = (function() {
function separateIconPath(icon) {
var result = {module: "", file: ""};
if (icon) {
var index = icon.indexOf('icons/');
if (index !== -1) {
icon = icon.substring(index+6);
var index = icon.indexOf(RED.settings.apiRootUrl+'icons/');
if (index === 0) {
icon = icon.substring((RED.settings.apiRootUrl+'icons/').length);
}
index = icon.indexOf('/');
if (index !== -1) {
@@ -859,10 +859,15 @@ RED.utils = (function() {
}
function getNodeIcon(def,node) {
if (def.category === 'config') {
if (node && node.type === '_selection_') {
return "font-awesome/fa-object-ungroup";
} else if (node && node.type === 'group') {
return "font-awesome/fa-object-group"
} else if (def.category === 'config') {
return RED.settings.apiRootUrl+"icons/node-red/cog.svg"
} else if (node && node.type === 'tab') {
return RED.settings.apiRootUrl+"icons/node-red/subflow.svg"
return "red-ui-icons/red-ui-icons-flow"
// return RED.settings.apiRootUrl+"images/subflow_tab.svg"
} else if (node && node.type === 'unknown') {
return RED.settings.apiRootUrl+"icons/node-red/alert.svg"
} else if (node && node.icon) {
@@ -921,6 +926,8 @@ RED.utils = (function() {
var l;
if (node.type === 'tab') {
l = node.label || defaultLabel
} else if (node.type === 'group') {
l = node.name || defaultLabel
} else {
l = node._def.label;
try {
@@ -1054,11 +1061,63 @@ RED.utils = (function() {
}
// If the specified name is not defined in font-awesome, show arrow-in icon.
iconUrl = RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg"
} else if (iconPath.module === "red-ui-icons") {
var redIconElement = $('<i/>').appendTo(iconContainer);
redIconElement.addClass("red-ui-palette-icon red-ui-icons " + iconPath.file);
return;
}
var imageIconElement = $('<div/>',{class:"red-ui-palette-icon"}).appendTo(iconContainer);
imageIconElement.css("backgroundImage", "url("+iconUrl+")");
}
function createNodeIcon(node) {
var def = node._def;
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"})
if (node.type === "_selection_") {
nodeDiv.addClass("red-ui-palette-icon-selection");
} else if (node.type === "group") {
nodeDiv.addClass("red-ui-palette-icon-group");
} else if (node.type === 'tab') {
nodeDiv.addClass("red-ui-palette-icon-flow");
} else {
var colour = RED.utils.getNodeColor(node.type,def);
// if (node.type === 'tab') {
// colour = "#C0DEED";
// }
nodeDiv.css('backgroundColor',colour);
var borderColor = getDarkerColor(colour);
if (borderColor !== colour) {
nodeDiv.css('border-color',borderColor)
}
}
var icon_url = RED.utils.getNodeIcon(def,node);
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, true);
return nodeDiv;
}
function getDarkerColor(c) {
var r,g,b;
if (/^#[a-f0-9]{6}$/i.test(c)) {
r = parseInt(c.substring(1, 3), 16);
g = parseInt(c.substring(3, 5), 16);
b = parseInt(c.substring(5, 7), 16);
} else if (/^#[a-f0-9]{3}$/i.test(c)) {
r = parseInt(c.substring(1, 2)+c.substring(1, 2), 16);
g = parseInt(c.substring(2, 3)+c.substring(2, 3), 16);
b = parseInt(c.substring(3, 4)+c.substring(3, 4), 16);
} else {
return c;
}
var l = 0.3 * r/255 + 0.59 * g/255 + 0.11 * b/255 ;
r = Math.max(0,r-50);
g = Math.max(0,g-50);
b = Math.max(0,b-50);
var s = ((r<<16) + (g<<8) + b).toString(16);
return '#'+'000000'.slice(0, 6-s.length)+s;
}
return {
createObjectElement: buildMessageElement,
getMessageProperty: getMessageProperty,
@@ -1076,6 +1135,8 @@ RED.utils = (function() {
parseContextKey: parseContextKey,
createIconElement: createIconElement,
sanitize: sanitize,
renderMarkdown: renderMarkdown
renderMarkdown: renderMarkdown,
createNodeIcon: createNodeIcon,
getDarkerColor: getDarkerColor
}
})();

View File

@@ -102,11 +102,13 @@ RED.view.tools = (function() {
node.n.dirty = true;
if (node.n.type === "group") {
RED.group.markDirty(node.n);
minX = Math.min(node.n.x - 5,minX);
minY = Math.min(node.n.y - 5,minY);
} else {
minX = Math.min(node.n.x-node.n.w/2-5,minX);
minY = Math.min(node.n.y-node.n.h/2-5,minY);
}
minX = Math.min(node.n.x-node.n.w/2-5,minX);
minY = Math.min(node.n.y-node.n.h/2-5,minY);
}
if (minX !== 0 || minY !== 0) {
for (var n = 0; n<moving_set.length; n++) {
node = moving_set[n];
@@ -120,8 +122,69 @@ RED.view.tools = (function() {
}
}
function setSelectedNodeLabelState(labelShown) {
var selection = RED.view.selection();
var historyEvents = [];
var nodes = [];
if (selection.nodes) {
selection.nodes.forEach(function(n) {
if (n.type !== 'subflow' && n.type !== 'group') {
nodes.push(n);
} else if (n.type === 'group') {
nodes = nodes.concat( RED.group.getNodes(n,true));
}
});
}
nodes.forEach(function(n) {
var modified = false;
var oldValue = n.l === undefined?true:n.l;
var isLink = /^link (in|out)$/.test(n._def.type);
if (labelShown) {
if (n.l === false || (isLink && !n.hasOwnProperty('l'))) {
n.l = true;
modified = true;
}
} else {
if ((!isLink && (!n.hasOwnProperty('l') || n.l === true)) || (isLink && n.l === true) ) {
n.l = false;
modified = true;
}
}
if (modified) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
l: oldValue
}
})
n.changed = true;
n.dirty = true;
n.resize = true;
}
})
if (historyEvents.length > 0) {
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty()
})
RED.nodes.dirty(true);
}
RED.view.redraw();
}
return {
init: function() {
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
RED.actions.add("core:hide-selected-node-labels", function() { setSelectedNodeLabelState(false); })
RED.actions.add("core:align-selection-to-grid", alignToGrid);
RED.actions.add("core:scroll-view-up", function() { RED.view.scroll(0,-RED.view.gridSize());});

File diff suppressed because it is too large Load Diff

View File

@@ -128,10 +128,6 @@ RED.workspaces = (function() {
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
var selection = RED.view.selection();
if (!selection.nodes && !selection.links) {
RED.sidebar.info.refresh(workspace);
}
if (changes.hasOwnProperty('disabled')) {
RED.nodes.eachNode(function(n) {
if (n.z === workspace.id) {
@@ -140,6 +136,7 @@ RED.workspaces = (function() {
});
RED.view.redraw();
}
RED.events.emit("flows:change",workspace);
}
RED.tray.close();
}
@@ -219,7 +216,10 @@ RED.workspaces = (function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
RED.sidebar.info.refresh(workspace);
var selection = RED.view.selection();
if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
RED.sidebar.info.refresh(workspace);
}
tabflowEditor.destroy();
}
}
@@ -371,7 +371,9 @@ RED.workspaces = (function() {
var changes = { disabled: workspace.disabled };
workspace.disabled = disabled;
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
if (id === activeWorkspace) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
}
var historyEvent = {
t: "edit",
changes:changes,
@@ -380,10 +382,11 @@ RED.workspaces = (function() {
}
workspace.changed = true;
RED.history.push(historyEvent);
RED.events.emit("flows:change",workspace);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
var selection = RED.view.selection();
if (!selection.nodes && !selection.links) {
if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
RED.sidebar.info.refresh(workspace);
}
if (changes.hasOwnProperty('disabled')) {
@@ -412,9 +415,14 @@ RED.workspaces = (function() {
}
function setWorkspaceOrder(order) {
RED.nodes.setWorkspaceOrder(order.filter(function(id) {
var newOrder = order.filter(function(id) {
return RED.nodes.workspace(id) !== undefined;
}));
})
var currentOrder = RED.nodes.getWorkspaceOrder();
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
RED.nodes.setWorkspaceOrder(newOrder);
RED.events.emit("flows:reorder",newOrder);
}
workspace_tabs.order(order);
}

View File

@@ -39,7 +39,11 @@ RED.user = (function() {
closeOnEscape: !!opts.cancelable,
width: 600,
resizable: false,
draggable: false
draggable: false,
close: function( event, ui ) {
$("#node-dialog-login").dialog('destroy').remove();
RED.keyboard.enable()
}
});
$("#node-dialog-login-fields").empty();
@@ -98,10 +102,10 @@ RED.user = (function() {
data: body
}).done(function(data,textStatus,xhr) {
RED.settings.set("auth-tokens",data);
$("#node-dialog-login").dialog('destroy').remove();
if (opts.updateMenu) {
updateUserMenu();
}
$("#node-dialog-login").dialog("close");
done();
}).fail(function(jqXHR,textStatus,errorThrown) {
RED.settings.remove("auth-tokens");
@@ -143,7 +147,8 @@ RED.user = (function() {
}
if (opts.cancelable) {
$("#node-dialog-login-cancel").button().on("click", function( event ) {
$("#node-dialog-login").dialog('destroy').remove();
$("#node-dialog-login").dialog('close');
});
}
@@ -152,8 +157,7 @@ RED.user = (function() {
$("#node-dialog-login-image").load(function() {
dialog.dialog("open");
}).attr("src",loginImageSrc);
RED.keyboard.disable();
}
});
}

View File

@@ -45,6 +45,9 @@
@include component-shadow;
border-color: $popover-background;
}
.ace_content {
line-height: 1;
}
textarea.ace_text-input {
overflow: hidden;
padding: 0px 1px !important;

View File

@@ -67,6 +67,9 @@
text-decoration: none;
color: $primary-text-color;
}
a:focus {
outline: 1px solid $form-input-focus-color;
}
p {
margin: 0 0 10px;

View File

@@ -23,7 +23,7 @@ $primary-background: #f3f3f3;//#0ff;
$secondary-background: #fff;//#ff0;
$secondary-background-selected: #efefef;//#e9e900;
$secondary-background-inactive: #f0f0f0;//#f0f000;
$secondary-background-hover: #ddd;//#dd0;
$secondary-background-hover: #e6e6e6;//#dd0;
$secondary-background-disabled: #f9f9f9;//#fafa0;
$tertiary-background: #f7f7f7;//#f0f;
@@ -94,7 +94,7 @@ $list-item-secondary-color: $secondary-text-color;
$list-item-background: $secondary-background;
$list-item-background-disabled: $secondary-background-inactive;
$list-item-background-hover: $secondary-background-hover;
$list-item-background-selected: $secondary-background-selected;
$list-item-background-selected: #ffebc7; // #fff1e5;
$list-item-border-selected: $secondary-text-color-selected;
$tab-text-color-active: $header-text-color;
@@ -129,7 +129,7 @@ $workspace-button-color-primary: #eee;
$workspace-button-background-primary: #AD1625;
$workspace-button-background-primary-hover: #6E0A1E;
$workspace-button-color-focus-outline: $form-input-border-color;
$workspace-button-color-focus-outline: $form-input-focus-color;
$shade-color: rgba(160,160,160,0.5);
@@ -289,3 +289,4 @@ $group-default-fill: none;
$group-default-fill-opacity: 1;
$group-default-stroke: #999;
$group-default-stroke-opacity: 1;
$group-default-label-color: #a4a4a4;

View File

@@ -217,6 +217,10 @@
.red-ui-debug-msg-type-number { color: $debug-message-text-color-msg-type-number; };
.red-ui-debug-msg-type-number-toggle { cursor: pointer;}
.red-ui-debug-msg-type-string {
white-space: pre-wrap;
}
.red-ui-debug-msg-row {
display: block;
padding: 4px 2px 2px;

View File

@@ -175,3 +175,38 @@
.red-ui-menu-dropdown-submenu.disabled > a:before {
border-right-color: $menuCaret;
}
// Menu NG
ul.red-ui-menu:not(.red-ui-menu-dropdown) {
font-family: $primary-font;
font-size: 12px;
list-style-type: none;
padding: 0;
margin: 0;
li a {
display: block;
padding: 4px 8px 4px 16px;
clear: both;
font-weight: normal;
line-height: 20px;
color: $menuColor;
white-space: nowrap;
text-decoration: none;
&:hover,&:focus {
color: $menuHoverColor;
text-decoration: none;
background-color: $menuHoverBackground;
border: none;
outline: none;
}
}
&.red-ui-menu-compact {
font-size: 12px;
li a {
line-height: 16px;
}
}
}

View File

@@ -304,9 +304,6 @@ button.red-ui-button-small
&:first-child {
padding: 20px 20px 0;
}
&:last-child {
padding-bottom: 20px;
}
}
}
.red-ui-editor-type-expression-tab-content {
@@ -413,7 +410,7 @@ button.red-ui-button.red-ui-editor-node-appearance-button {
.red-ui-group-layout-picker {
padding: 5px;
background: $primary-background;
background: $secondary-background;
}
.red-ui-group-layout-picker-cell-text {
position: absolute;
@@ -718,6 +715,9 @@ div.red-ui-button-small.red-ui-color-picker-opacity-slider-handle {
button.red-ui-toggleButton.toggle {
text-align: left;
i {
min-width: 15px;
}
}
@@ -760,7 +760,7 @@ button.red-ui-toggleButton.toggle {
.red-ui-typedInput-value-label,.red-ui-typedInput-option-label {
select,.placeholder-input {
margin: 3px;
height: 26px;
height: 24px;
width: calc(100% - 10px);
padding-left: 3px;
}
@@ -831,8 +831,18 @@ span.red-ui-editor-subflow-env-lang-icon {
right: 4px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.red-ui-editor-subflow-env-input-type {
background: $secondary-background;
height: 100%;
box-sizing: border-box;
}
.red-ui-editor-subflow-env-input-type-placeholder {
color: $tertiary-text-color;
padding-left: 4px;
}
// .red-ui-editor-subflow-ui-grid {
// width: 100%;
// .red-ui-editableList-container {

View File

@@ -35,13 +35,21 @@
pointer-events: none;
-webkit-touch-callout: none;
@include disable-selection;
.red-ui-flow-node-label-text {
dominant-baseline: middle;
}
&.red-ui-flow-node-label-right .red-ui-flow-node-label-text {
text-anchor: end;
}
}
.red-ui-flow-port-label {
stroke-width: 0;
fill: $secondary-text-color;
font-size: 16px;
alignment-baseline: middle;
dominant-baseline: middle;
text-anchor: middle;
pointer-events: none;
-webkit-touch-callout: none;
@@ -98,6 +106,11 @@
pointer-events: stroke;
stroke-opacity: 0;
stroke-width: 3;
&.red-ui-flow-group-outline-select-background {
stroke: $view-background;
stroke-width: 6;
}
}
.red-ui-flow-group-body {
pointer-events: none;
@@ -109,6 +122,7 @@
}
.red-ui-flow-group-label {
@include disable-selection;
fill: $group-default-label-color;
}
@@ -145,6 +159,15 @@
.red-ui-flow-node-button {
fill: inherit;
&.red-ui-flow-node-button-disabled {
opacity: 0.4;
.red-ui-flow-node-button-button {
cursor: default;
}
}
}
.red-ui-flow-node-button-button {
cursor: pointer;
}
.red-ui-flow-node-button-background {
fill: $node-background-placeholder;
@@ -208,6 +231,9 @@ g.red-ui-flow-node-selected {
fill-opacity: 1;
stroke-dasharray: none;
}
.red-ui-flow-group, .red-ui-flow-group-body {
stroke-dasharray: 8, 3;
}
}
.red-ui-flow-node-disabled {
&.red-ui-flow-node, .red-ui-flow-node {
@@ -316,7 +342,10 @@ g.red-ui-flow-link-unknown path.red-ui-flow-link-line {
stroke-dasharray: 10, 4;
}
@keyframes red-ui-flow-port-tooltip-fadeIn { from { opacity:0; } to { opacity:1; } }
// @keyframes *must* be on multiple lines so build-custom-theme can filter them out
@keyframes red-ui-flow-port-tooltip-fadeIn {
from { opacity:0; } to { opacity:1; }
}
.red-ui-flow-port-tooltip {
opacity:0;

View File

@@ -37,7 +37,7 @@
border-radius: 4px;
font-family: $monospace-font !important;
font-size: 13px !important;
height: 300px;
height: 100%;
line-height: 1.3em;
padding: 6px 10px;
background: $clipboard-textarea-background;
@@ -62,6 +62,7 @@
background: $form-input-background;
&>div {
height: 100%;
box-sizing: border-box;
}
}
.red-ui-clipboard-dialog-box {

View File

@@ -71,38 +71,9 @@
}
.red-ui-notification-shake-horizontal {
-webkit-animation: red-ui-notification-shake-horizontal 0.3s steps(2, end) both;
animation: red-ui-notification-shake-horizontal 0.3s steps(2, end) both;
}
@-webkit-keyframes red-ui-notification-shake-horizontal {
0%,
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
10%,
30%,
50%,
70% {
-webkit-transform: translateX(-1px);
transform: translateX(-1px);
}
20%,
40%,
60% {
-webkit-transform: translateX(1px);
transform: translateX(1px);
}
// 80% {
// -webkit-transform: translateX(1px);
// transform: translateX(1px);
// }
// 90% {
// -webkit-transform: translateX(-1px);
// transform: translateX(-1px);
// }
animation: red-ui-notification-shake-horizontal 0.3s steps(2, end) both;
}
// @keyframes *must* be on multiple lines so build-custom-theme can filter them out
@keyframes red-ui-notification-shake-horizontal {
0%,
100% {
@@ -122,12 +93,4 @@
-webkit-transform: translateX(1px);
transform: translateX(1px);
}
// 80% {
// -webkit-transform: translateX(1px);
// transform: translateX(1px);
// }
// 90% {
// -webkit-transform: translateX(-1px);
// transform: translateX(-1px);
// }
}

View File

@@ -186,6 +186,21 @@
background-size: contain;
background-repeat: no-repeat;
}
.red-ui-search-result-node {
&.red-ui-palette-icon-flow,
&.red-ui-palette-icon-group,
&.red-ui-palette-icon-selection {
background: none;
border-color: transparent;
.red-ui-palette-icon-container {
background: none;
}
.red-ui-palette-icon-fa {
color: $secondary-text-color;
font-size: 18px;
}
}
}
.red-ui-palette-icon-fa {
color: white;
position: absolute;

View File

@@ -22,9 +22,19 @@
// border: 1px solid red;
box-sizing: border-box;
}
display: flex;
flex-direction: column;
>.red-ui-panel:first-child {
flex: 0 0 auto;
}
>.red-ui-panel:last-child {
flex: 1 1 auto;
}
}
.red-ui-panels-separator {
flex: 0 0 auto;
border-top: 1px solid $secondary-border-color;
border-bottom: 1px solid $secondary-border-color;
height: 7px;
@@ -37,10 +47,13 @@
.red-ui-panel {
overflow: auto;
height: calc(50% - 4px);
position: relative;
}
.red-ui-panels.red-ui-panels-horizontal {
height: 100%;
flex-direction: row;
&>.red-ui-panel {
vertical-align: top;
display: inline-block;

View File

@@ -150,6 +150,16 @@
.red-ui-popover a.red-ui-button,
.red-ui-popover button.red-ui-button {
&:not(.primary) {
border-color: $popover-button-border-color;
background: $popover-background;
color: $popover-color !important;
}
&:not(.primary):not(.disabled):not(.ui-button-disabled):hover {
border-color: $popover-button-border-color-hover;
}
&.primary {
border-color: $popover-button-border-color;
}

View File

@@ -18,7 +18,12 @@
.red-ui-editableList-container {
padding: 0px;
}
padding: 0;
.red-ui-projects-dialog-box {
box-sizing: border-box;
overflow-y: auto;
padding: 25px 25px 10px 25px;
}
}
#red-ui-project-settings-tab-settings {
overflow-y: scroll;
@@ -99,6 +104,7 @@
.red-ui-projects-dialog-screen-create {
min-height: 500px;
button.red-ui-projects-dialog-screen-create-type {
position: relative;
height: auto;
padding: 10px;
}
@@ -169,9 +175,14 @@
.red-ui-projects-dialog-project-list-container {
border: 1px solid $secondary-border-color;
border-radius: 2px;
display: flex;
flex-direction: column;
.red-ui-search-container {
flex-grow: 0;
}
}
.red-ui-projects-dialog-project-list-inner-container {
height: 300px;
flex-grow: 1 ;
overflow-y: scroll;
position:relative;
.red-ui-editableList-border {
@@ -254,6 +265,29 @@
}
}
}
.red-ui-projects-dialog-project-list-entry-delete-confirm {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 100%;
width: 1000px;
overflow: hidden;
padding: 5px 20px;
background: $secondary-background;
transition: left 0.4s;
white-space: nowrap;
> span {
line-height: 40px;
}
button {
margin-left: 20px;
}
}
.red-ui-projects-dialog-screen-create-type {
position: relative;
}
.red-ui-projects-dialog-screen-create-type.red-ui-button.toggle.selected:not(.disabled):not(:disabled) {
color: $secondary-text-color-active !important;
}

View File

@@ -42,7 +42,11 @@
background: $secondary-background;
border: 2px solid $primary-border-color;
text-align: center;
line-height:50px
line-height:50px;
&.selected {
background: $workspace-button-background-hover;
}
}
.red-ui-editor-radial-menu-opt-disabled {

View File

@@ -24,6 +24,17 @@
top: 0px;
border: 1px solid $primary-border-color;
box-shadow: 0 0 10px $shadow;
background: $secondary-background;
.red-ui-searchBox-container {
display: inline-block;
margin-right: 6px;
width: 100%;
}
&:not(.red-ui-type-search) .red-ui-searchBox-container {
width: calc(100% - 30px);
}
}
.red-ui-type-search {
@@ -39,6 +50,7 @@
border: 1px dashed $primary-border-color;
border-bottom: none;
padding: 0;
width: 100%;
}
.red-ui-search-results-container {
display: none;
@@ -87,6 +99,8 @@
}
.red-ui-palette-icon {
width: 15px;
position:relative;
left: -1px;
}
.red-ui-search-result-description {
margin-left:28px;
@@ -153,7 +167,7 @@
width: 30px;
float:left;
height: 25px;
border-radius: 5px;
border-radius: 3px;
border: 1px solid $node-border;
background-position: 5% 50%;
background-repeat: no-repeat;

View File

@@ -42,6 +42,7 @@
@import "tab-config";
@import "tab-context";
@import "tab-info";
@import "tab-help";
@import "popover";
@import "flow";
@import "palette-editor";

View File

@@ -20,6 +20,10 @@
height: 100%;
overflow-y:auto;
@include disable-selection;
&:focus {
outline: none;
}
}
ul.red-ui-sidebar-node-config-list {

View File

@@ -0,0 +1,27 @@
.red-ui-sidebar-help-stack {
// height: calc(100% - 39px);
}
.red-ui-help-search {
border-bottom: 1px solid $secondary-border-color;
}
.red-ui-sidebar-help-toc {
.red-ui-treeList-label {
font-size: 13px;
padding: 2px 0;
overflow: hidden;
white-space: nowrap;
}
}
#red-ui-sidebar-help-show-toc {
i.fa-angle-right {
transition: all 0.2s ease-in-out;
}
&.selected {
i.fa-angle-right {
transform: rotate(90deg);
}
}
}

View File

@@ -14,9 +14,25 @@
* limitations under the License.
**/
.red-ui-sidebar-info {
height: 100%;
}
.red-ui-sidebar-info hr {
margin: 10px 0;
}
.red-ui-info-header {
padding-left: 9px;
line-height: 21px;
cursor: default;
> * {
vertical-align: middle
}
> span {
display: inline-block;
margin-left: 5px;
}
border-bottom: 1px solid $secondary-border-color;
}
table.red-ui-info-table {
font-size: 14px;
margin: 0 0 10px;
@@ -125,6 +141,9 @@ div.red-ui-info-table {
font-size: 1.296em;
line-height: 1.3em;
margin: 8px auto;
&.red-ui-help-title {
border-bottom: 1px solid $tertiary-border-color;
}
}
h2 {
font-weight: 500;
@@ -214,12 +233,13 @@ div.red-ui-info-table {
}
.red-ui-sidebar-info-stack {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow-y: scroll;
height: 100%;
// position: absolute;
// top: 0;
// bottom: 0;
// left: 0;
// right: 0;
// overflow-y: scroll;
}
.red-ui-help-tips {
display: none;
@@ -227,20 +247,23 @@ div.red-ui-info-table {
left:0;
right:0;
bottom: 0;
height: 150px;
height: 0;
transition: height 0.2s, padding 0.2s;
box-sizing: border-box;
border-top: 1px solid $secondary-border-color;
background-color: $secondary-background;
padding: 20px;
padding: 0;
box-shadow: 0 5px 20px 0px $shadow;
overflow-y: auto;
}
.red-ui-sidebar-info.show-tips {
.red-ui-sidebar-info-stack {
bottom: 150px;
height: calc(100% - 150px);
}
.red-ui-help-tips {
display: block;
height: 150px;
padding: 20px;
}
}
@@ -279,3 +302,208 @@ div.red-ui-info-table {
border-radius: 4px;
padding: 2px 4px 2px;
}
.red-ui-info-outline,.red-ui-sidebar-help-toc {
display: flex;
flex-direction: column;
.red-ui-treeList {
flex-grow: 1;
position: relative;
}
.red-ui-treeList-container {
position: absolute;
top: 0;
bottom: 0;
}
.red-ui-treeList-container,.red-ui-editableList-border {
border: none;
border-radius: 0;
}
.red-ui-treeList-label {
font-size: 13px;
padding: 2px 0;
overflow: hidden;
}
.red-ui-info-outline-project {
border-bottom: 1px solid $secondary-border-color;
}
.red-ui-info-outline-item {
display: inline-block;
padding: 0;
font-size: 13px;
border: none;
.red-ui-palette-icon-fa {
position: relative;
top: 1px;
left: 0px;
}
&:hover {
background: inherit
}
&.red-ui-info-outline-item-flow {
.red-ui-search-result-description {
margin-left: 4px;
}
}
&.red-ui-info-outline-item-group .red-ui-search-result-node {
background: none;
border-color: transparent;
.red-ui-palette-icon-container {
background: none;
}
.red-ui-palette-icon-fa {
color: $secondary-text-color;
font-size: 18px;
}
}
&.red-ui-info-outline-item-empty {
font-style: italic;
color: $form-placeholder-color;
}
}
.red-ui-search-result-node {
width: 24px;
height: 20px;
margin-top: 1px;
}
.red-ui-palette-icon-container {
width: 24px;
}
.red-ui-palette-icon {
width: 20px;
}
.red-ui-search-result-description {
margin-left: 32px;
line-height: 22px;
white-space: nowrap;
}
.red-ui-search-result-node-label {
color: $secondary-text-color;
}
}
.red-ui-info-outline-item-control-spacer {
display: inline-block;
width: 23px;
}
.red-ui-info-outline-gutter {
display:none;
button {
position: absolute;
top: 1px;
left: 2px;
}
.red-ui-treeList-label:hover & {
display: inline;
}
}
.red-ui-info-outline-item-controls {
position: absolute;
top:0;
bottom: 0;
right: 0px;
padding: 2px 3px 0 1px;
text-align: right;
background: $list-item-background;
.red-ui-treeList-label:hover & {
background: $list-item-background-hover;
}
.red-ui-treeList-label.selected & {
background: $list-item-background-selected;
}
&.red-ui-info-outline-item-hover-controls button {
min-width: 23px;
}
.red-ui-treeList-label:not(:hover) &.red-ui-info-outline-item-hover-controls {
button {
border: none;
background: none;
}
}
.red-ui-info-outline-item-control-reveal,
.red-ui-info-outline-item-control-action {
display: none;
}
.red-ui-treeList-label:hover & {
.red-ui-info-outline-item-control-reveal,
.red-ui-info-outline-item-control-action {
display: inline-block;
}
}
.fa-ban {
display: none;
}
.red-ui-info-outline-item.red-ui-info-outline-item-disabled & {
.fa-ban {
display: inline-block;
}
.fa-circle-thin {
display: none;
}
}
button {
margin-right: 3px
}
}
.red-ui-info-outline-item-disabled {
.red-ui-search-result-node {
opacity: 0.4;
}
.red-ui-info-outline-item-label {
font-style: italic;
color: $secondary-text-color-disabled;
}
.red-ui-icons-flow {
opacity: 0.4;
}
}
.red-ui-icons {
display: inline-block;
width: 18px;
&:before {
white-space: pre;
content: ' '
}
}
.red-ui-icons-flow {
background-image: url('images/subflow_tab.svg');
background-repeat: no-repeat;
background-size: contain;
filter: brightness(2.5);
}
.red-ui-info-toolbar {
min-height: 39px;
height: 39px;
box-sizing: border-box;
text-align: left;
// padding-left: 9px;
// box-sizing: border-box;
// background: $palette-header-background;
// border-bottom: 1px solid $secondary-border-color;
.red-ui-searchBox-container {
position: absolute;
top: 6px;
right: 8px;
width: calc(100% - 130px);
max-width: 250px;
background: $palette-header-background;
}
}

View File

@@ -18,23 +18,32 @@
.red-ui-searchBox-container {
position: relative;
i {
position: absolute;
top: 9px;
font-size: 10px;
color: $secondary-text-color;
}
i.fa-search {
position: absolute;
pointer-events: none;
left: 8px;
top: 9px;
}
i.fa-caret-down {
position: absolute;
right: 6px;
font-size: 12px;
}
i.fa-times {
position: absolute;
right: 5px;
top: 9px;
right: 4px;
}
form.red-ui-searchBox-form {
margin: 0;
}
a.red-ui-searchBox-opts:hover {
color: $workspace-button-color-hover;
background: $workspace-button-background-hover;
}
input.red-ui-searchBox-input {
border-radius: 0;
border: none;
@@ -57,9 +66,12 @@
right: 0;
top: 0;
bottom: 0;
width: 20px;
width: 16px;
}
a.red-ui-searchBox-clear {
display: none;
}
.red-ui-searchBox-resultCount {
position: absolute;
right: 18px;
@@ -70,4 +82,36 @@
font-size: 9px;
border-radius: 4px;
}
&.red-ui-searchBox-has-options {
a.red-ui-searchBox-clear {
right: 16px;
}
.red-ui-searchBox-resultCount {
right: 33px;
}
input.red-ui-searchBox-input {
padding-right: 33px;
}
}
}
.red-ui-searchBox-compact {
input:focus.red-ui-searchBox-input {
outline: 1px solid $form-input-focus-color;
}
input.red-ui-searchBox-input,input:focus.red-ui-searchBox-input {
border: 1px solid $secondary-border-color;
border-radius: 3px;
font-size: 12px;
height: 26px;
}
i.fa-times,i.fa-search, i.fa-caret-down {
top: 7px;
}
.red-ui-searchBox-resultCount {
top: 3px;
padding: 0 6px;
}
}

View File

@@ -18,7 +18,7 @@
border: 1px solid $form-input-border-color;
border-radius: 4px;
height: 34px;
display: inline-block;
display: inline-flex;
padding: 0;
margin: 0;
vertical-align: middle;
@@ -26,12 +26,7 @@
overflow:visible;
position: relative;
.red-ui-typedInput-input-wrap {
position: absolute;
left:0;
right:0;
top:0;
bottom:0;
outline: red;
flex-grow: 1;
}
input.red-ui-typedInput-input {
width: 100%;
@@ -49,7 +44,7 @@
border-color: $form-input-focus-color !important;
}
.red-ui-typedInput-value-label {
position: absolute;
flex-grow: 1;
display: inline-block;
height: 32px;
box-sizing: border-box;
@@ -107,18 +102,17 @@ button.red-ui-typedInput-option-trigger
{
text-align: left;
border: none;
position: absolute;
flex-basis: auto;
box-sizing: border-box;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
padding: 0 1px 0 5px;
display:inline-block;
background: $form-button-background;
height: 32px;
line-height: 30px;
min-width: 23px;
vertical-align: middle;
color: $form-text-color;
white-space: nowrap;
i.red-ui-typedInput-icon {
margin-left: 1px;
margin-right: 2px;
@@ -154,7 +148,7 @@ button.red-ui-typedInput-option-trigger
text-decoration: none;
}
&.red-ui-typedInput-full-width {
width: 100%;
flex-grow: 1;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
@@ -170,7 +164,6 @@ button.red-ui-typedInput-option-expand {
border-bottom-right-radius: 4px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
right: 0;
}
button.red-ui-typedInput-option-trigger {
@@ -179,27 +172,23 @@ button.red-ui-typedInput-option-trigger {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
padding: 0 0 0 0;
position:absolute;
right: 0;
position:relative;
flex-grow: 1;
line-height: 32px;
display: inline-flex;
.red-ui-typedInput-option-label {
background:$form-button-background;
color: $form-text-color;
position:absolute;
left:0;
right:23px;
top: 0;
padding: 0 5px 0 8px;
i.red-ui-typedInput-icon {
margin-right: 4px;
}
flex-grow: 1;
padding: 0 0 0 8px;
display:inline-block;
}
.red-ui-typedInput-option-caret {
top: 0;
position: absolute;
right: 0;
bottom: 0;
width: 17px;
padding-left: 5px;
flex-grow: 0;
display:inline-block;
width: 23px;
text-align: center;
height: 100%;
&:before {
content:'';
display: inline-block;

View File

@@ -172,3 +172,44 @@ button.red-ui-footer-button-toggle {
margin-right: 0;
}
}
#red-ui-loading-progress {
position: absolute;
background: $primary-background;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 200;
& > div {
position: absolute;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height:80px;
text-align: center;
color: $secondary-text-color;
}
}
.red-ui-loading-bar {
box-sizing: border-box;
width: 300px;
height: 30px;
border: 2px solid $primary-border-color;
border-radius: 4px;
> span {
display: block;
height: 100%;
background: $secondary-border-color;
transition: width 0.2s;
width: 10%;
}
}
.red-ui-loading-bar-label {
font-size: 13px;
margin-bottom: 2px;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,626 +0,0 @@
/*!
* jQuery Migrate - v3.0.1 - 2017-09-26
* Copyright jQuery Foundation and other contributors
*/
;( function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define( [ "jquery" ], window, factory );
} else if ( typeof module === "object" && module.exports ) {
// Node/CommonJS
// eslint-disable-next-line no-undef
module.exports = factory( require( "jquery" ), window );
} else {
// Browser globals
factory( jQuery, window );
}
} )( function( jQuery, window ) {
"use strict";
jQuery.migrateVersion = "3.0.1";
/* exported migrateWarn, migrateWarnFunc, migrateWarnProp */
( function() {
var rbadVersions = /^[12]\./;
// Support: IE9 only
// IE9 only creates console object when dev tools are first opened
// IE9 console is a host object, callable but doesn't have .apply()
if ( !window.console || !window.console.log ) {
return;
}
// Need jQuery 3.0.0+ and no older Migrate loaded
if ( !jQuery || rbadVersions.test( jQuery.fn.jquery ) ) {
window.console.log( "JQMIGRATE: jQuery 3.0.0+ REQUIRED" );
}
if ( jQuery.migrateWarnings ) {
window.console.log( "JQMIGRATE: Migrate plugin loaded multiple times" );
}
// Show a message on the console so devs know we're active
window.console.log( "JQMIGRATE: Migrate is installed" +
( jQuery.migrateMute ? "" : " with logging active" ) +
", version " + jQuery.migrateVersion );
} )();
var warnedAbout = {};
// List of warnings already given; public read only
jQuery.migrateWarnings = [];
// Set to false to disable traces that appear with warnings
if ( jQuery.migrateTrace === undefined ) {
jQuery.migrateTrace = true;
}
// Forget any warnings we've already given; public
jQuery.migrateReset = function() {
warnedAbout = {};
jQuery.migrateWarnings.length = 0;
};
function migrateWarn( msg ) {
var console = window.console;
if ( !warnedAbout[ msg ] ) {
warnedAbout[ msg ] = true;
jQuery.migrateWarnings.push( msg );
if ( console && console.warn && !jQuery.migrateMute ) {
console.warn( "JQMIGRATE: " + msg );
if ( jQuery.migrateTrace && console.trace ) {
console.trace();
}
}
}
}
function migrateWarnProp( obj, prop, value, msg ) {
Object.defineProperty( obj, prop, {
configurable: true,
enumerable: true,
get: function() {
migrateWarn( msg );
return value;
},
set: function( newValue ) {
migrateWarn( msg );
value = newValue;
}
} );
}
function migrateWarnFunc( obj, prop, newFunc, msg ) {
obj[ prop ] = function() {
migrateWarn( msg );
return newFunc.apply( this, arguments );
};
}
if ( window.document.compatMode === "BackCompat" ) {
// JQuery has never supported or tested Quirks Mode
migrateWarn( "jQuery is not compatible with Quirks Mode" );
}
var oldInit = jQuery.fn.init,
oldIsNumeric = jQuery.isNumeric,
oldFind = jQuery.find,
rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,
rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
jQuery.fn.init = function( arg1 ) {
var args = Array.prototype.slice.call( arguments );
if ( typeof arg1 === "string" && arg1 === "#" ) {
// JQuery( "#" ) is a bogus ID selector, but it returned an empty set before jQuery 3.0
migrateWarn( "jQuery( '#' ) is not a valid selector" );
args[ 0 ] = [];
}
return oldInit.apply( this, args );
};
jQuery.fn.init.prototype = jQuery.fn;
jQuery.find = function( selector ) {
var args = Array.prototype.slice.call( arguments );
// Support: PhantomJS 1.x
// String#match fails to match when used with a //g RegExp, only on some strings
if ( typeof selector === "string" && rattrHashTest.test( selector ) ) {
// The nonstandard and undocumented unquoted-hash was removed in jQuery 1.12.0
// First see if qS thinks it's a valid selector, if so avoid a false positive
try {
window.document.querySelector( selector );
} catch ( err1 ) {
// Didn't *look* valid to qSA, warn and try quoting what we think is the value
selector = selector.replace( rattrHashGlob, function( _, attr, op, value ) {
return "[" + attr + op + "\"" + value + "\"]";
} );
// If the regexp *may* have created an invalid selector, don't update it
// Note that there may be false alarms if selector uses jQuery extensions
try {
window.document.querySelector( selector );
migrateWarn( "Attribute selector with '#' must be quoted: " + args[ 0 ] );
args[ 0 ] = selector;
} catch ( err2 ) {
migrateWarn( "Attribute selector with '#' was not fixed: " + args[ 0 ] );
}
}
}
return oldFind.apply( this, args );
};
// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML)
var findProp;
for ( findProp in oldFind ) {
if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) {
jQuery.find[ findProp ] = oldFind[ findProp ];
}
}
// The number of elements contained in the matched element set
jQuery.fn.size = function() {
migrateWarn( "jQuery.fn.size() is deprecated and removed; use the .length property" );
return this.length;
};
jQuery.parseJSON = function() {
migrateWarn( "jQuery.parseJSON is deprecated; use JSON.parse" );
return JSON.parse.apply( null, arguments );
};
jQuery.isNumeric = function( val ) {
// The jQuery 2.2.3 implementation of isNumeric
function isNumeric2( obj ) {
var realStringObj = obj && obj.toString();
return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
}
var newValue = oldIsNumeric( val ),
oldValue = isNumeric2( val );
if ( newValue !== oldValue ) {
migrateWarn( "jQuery.isNumeric() should not be called on constructed objects" );
}
return oldValue;
};
migrateWarnFunc( jQuery, "holdReady", jQuery.holdReady,
"jQuery.holdReady is deprecated" );
migrateWarnFunc( jQuery, "unique", jQuery.uniqueSort,
"jQuery.unique is deprecated; use jQuery.uniqueSort" );
// Now jQuery.expr.pseudos is the standard incantation
migrateWarnProp( jQuery.expr, "filters", jQuery.expr.pseudos,
"jQuery.expr.filters is deprecated; use jQuery.expr.pseudos" );
migrateWarnProp( jQuery.expr, ":", jQuery.expr.pseudos,
"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos" );
var oldAjax = jQuery.ajax;
jQuery.ajax = function( ) {
var jQXHR = oldAjax.apply( this, arguments );
// Be sure we got a jQXHR (e.g., not sync)
if ( jQXHR.promise ) {
migrateWarnFunc( jQXHR, "success", jQXHR.done,
"jQXHR.success is deprecated and removed" );
migrateWarnFunc( jQXHR, "error", jQXHR.fail,
"jQXHR.error is deprecated and removed" );
migrateWarnFunc( jQXHR, "complete", jQXHR.always,
"jQXHR.complete is deprecated and removed" );
}
return jQXHR;
};
var oldRemoveAttr = jQuery.fn.removeAttr,
oldToggleClass = jQuery.fn.toggleClass,
rmatchNonSpace = /\S+/g;
jQuery.fn.removeAttr = function( name ) {
var self = this;
jQuery.each( name.match( rmatchNonSpace ), function( i, attr ) {
if ( jQuery.expr.match.bool.test( attr ) ) {
migrateWarn( "jQuery.fn.removeAttr no longer sets boolean properties: " + attr );
self.prop( attr, false );
}
} );
return oldRemoveAttr.apply( this, arguments );
};
jQuery.fn.toggleClass = function( state ) {
// Only deprecating no-args or single boolean arg
if ( state !== undefined && typeof state !== "boolean" ) {
return oldToggleClass.apply( this, arguments );
}
migrateWarn( "jQuery.fn.toggleClass( boolean ) is deprecated" );
// Toggle entire class name of each element
return this.each( function() {
var className = this.getAttribute && this.getAttribute( "class" ) || "";
if ( className ) {
jQuery.data( this, "__className__", className );
}
// If the element has a class name or if we're passed `false`,
// then remove the whole classname (if there was one, the above saved it).
// Otherwise bring back whatever was previously saved (if anything),
// falling back to the empty string if nothing was stored.
if ( this.setAttribute ) {
this.setAttribute( "class",
className || state === false ?
"" :
jQuery.data( this, "__className__" ) || ""
);
}
} );
};
var internalSwapCall = false;
// If this version of jQuery has .swap(), don't false-alarm on internal uses
if ( jQuery.swap ) {
jQuery.each( [ "height", "width", "reliableMarginRight" ], function( _, name ) {
var oldHook = jQuery.cssHooks[ name ] && jQuery.cssHooks[ name ].get;
if ( oldHook ) {
jQuery.cssHooks[ name ].get = function() {
var ret;
internalSwapCall = true;
ret = oldHook.apply( this, arguments );
internalSwapCall = false;
return ret;
};
}
} );
}
jQuery.swap = function( elem, options, callback, args ) {
var ret, name,
old = {};
if ( !internalSwapCall ) {
migrateWarn( "jQuery.swap() is undocumented and deprecated" );
}
// Remember the old values, and insert the new ones
for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
ret = callback.apply( elem, args || [] );
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
return ret;
};
var oldData = jQuery.data;
jQuery.data = function( elem, name, value ) {
var curData;
// Name can be an object, and each entry in the object is meant to be set as data
if ( name && typeof name === "object" && arguments.length === 2 ) {
curData = jQuery.hasData( elem ) && oldData.call( this, elem );
var sameKeys = {};
for ( var key in name ) {
if ( key !== jQuery.camelCase( key ) ) {
migrateWarn( "jQuery.data() always sets/gets camelCased names: " + key );
curData[ key ] = name[ key ];
} else {
sameKeys[ key ] = name[ key ];
}
}
oldData.call( this, elem, sameKeys );
return name;
}
// If the name is transformed, look for the un-transformed name in the data object
if ( name && typeof name === "string" && name !== jQuery.camelCase( name ) ) {
curData = jQuery.hasData( elem ) && oldData.call( this, elem );
if ( curData && name in curData ) {
migrateWarn( "jQuery.data() always sets/gets camelCased names: " + name );
if ( arguments.length > 2 ) {
curData[ name ] = value;
}
return curData[ name ];
}
}
return oldData.apply( this, arguments );
};
var oldTweenRun = jQuery.Tween.prototype.run;
var linearEasing = function( pct ) {
return pct;
};
jQuery.Tween.prototype.run = function( ) {
if ( jQuery.easing[ this.easing ].length > 1 ) {
migrateWarn(
"'jQuery.easing." + this.easing.toString() + "' should use only one argument"
);
jQuery.easing[ this.easing ] = linearEasing;
}
oldTweenRun.apply( this, arguments );
};
jQuery.fx.interval = jQuery.fx.interval || 13;
// Support: IE9, Android <=4.4
// Avoid false positives on browsers that lack rAF
if ( window.requestAnimationFrame ) {
migrateWarnProp( jQuery.fx, "interval", jQuery.fx.interval,
"jQuery.fx.interval is deprecated" );
}
var oldLoad = jQuery.fn.load,
oldEventAdd = jQuery.event.add,
originalFix = jQuery.event.fix;
jQuery.event.props = [];
jQuery.event.fixHooks = {};
migrateWarnProp( jQuery.event.props, "concat", jQuery.event.props.concat,
"jQuery.event.props.concat() is deprecated and removed" );
jQuery.event.fix = function( originalEvent ) {
var event,
type = originalEvent.type,
fixHook = this.fixHooks[ type ],
props = jQuery.event.props;
if ( props.length ) {
migrateWarn( "jQuery.event.props are deprecated and removed: " + props.join() );
while ( props.length ) {
jQuery.event.addProp( props.pop() );
}
}
if ( fixHook && !fixHook._migrated_ ) {
fixHook._migrated_ = true;
migrateWarn( "jQuery.event.fixHooks are deprecated and removed: " + type );
if ( ( props = fixHook.props ) && props.length ) {
while ( props.length ) {
jQuery.event.addProp( props.pop() );
}
}
}
event = originalFix.call( this, originalEvent );
return fixHook && fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
};
jQuery.event.add = function( elem, types ) {
// This misses the multiple-types case but that seems awfully rare
if ( elem === window && types === "load" && window.document.readyState === "complete" ) {
migrateWarn( "jQuery(window).on('load'...) called after load event occurred" );
}
return oldEventAdd.apply( this, arguments );
};
jQuery.each( [ "load", "unload", "error" ], function( _, name ) {
jQuery.fn[ name ] = function() {
var args = Array.prototype.slice.call( arguments, 0 );
// If this is an ajax load() the first arg should be the string URL;
// technically this could also be the "Anything" arg of the event .load()
// which just goes to show why this dumb signature has been deprecated!
// jQuery custom builds that exclude the Ajax module justifiably die here.
if ( name === "load" && typeof args[ 0 ] === "string" ) {
return oldLoad.apply( this, args );
}
migrateWarn( "jQuery.fn." + name + "() is deprecated" );
args.splice( 0, 0, name );
if ( arguments.length ) {
return this.on.apply( this, args );
}
// Use .triggerHandler here because:
// - load and unload events don't need to bubble, only applied to window or image
// - error event should not bubble to window, although it does pre-1.7
// See http://bugs.jquery.com/ticket/11820
this.triggerHandler.apply( this, args );
return this;
};
} );
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup contextmenu" ).split( " " ),
function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
migrateWarn( "jQuery.fn." + name + "() event shorthand is deprecated" );
return arguments.length > 0 ?
this.on( name, null, data, fn ) :
this.trigger( name );
};
} );
// Trigger "ready" event only once, on document ready
jQuery( function() {
jQuery( window.document ).triggerHandler( "ready" );
} );
jQuery.event.special.ready = {
setup: function() {
if ( this === window.document ) {
migrateWarn( "'ready' event is deprecated" );
}
}
};
jQuery.fn.extend( {
bind: function( types, data, fn ) {
migrateWarn( "jQuery.fn.bind() is deprecated" );
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
migrateWarn( "jQuery.fn.unbind() is deprecated" );
return this.off( types, null, fn );
},
delegate: function( selector, types, data, fn ) {
migrateWarn( "jQuery.fn.delegate() is deprecated" );
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
migrateWarn( "jQuery.fn.undelegate() is deprecated" );
return arguments.length === 1 ?
this.off( selector, "**" ) :
this.off( types, selector || "**", fn );
},
hover: function( fnOver, fnOut ) {
migrateWarn( "jQuery.fn.hover() is deprecated" );
return this.on( "mouseenter", fnOver ).on( "mouseleave", fnOut || fnOver );
}
} );
var oldOffset = jQuery.fn.offset;
jQuery.fn.offset = function() {
var docElem,
elem = this[ 0 ],
origin = { top: 0, left: 0 };
if ( !elem || !elem.nodeType ) {
migrateWarn( "jQuery.fn.offset() requires a valid DOM element" );
return origin;
}
docElem = ( elem.ownerDocument || window.document ).documentElement;
if ( !jQuery.contains( docElem, elem ) ) {
migrateWarn( "jQuery.fn.offset() requires an element connected to a document" );
return origin;
}
return oldOffset.apply( this, arguments );
};
var oldParam = jQuery.param;
jQuery.param = function( data, traditional ) {
var ajaxTraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
if ( traditional === undefined && ajaxTraditional ) {
migrateWarn( "jQuery.param() no longer uses jQuery.ajaxSettings.traditional" );
traditional = ajaxTraditional;
}
return oldParam.call( this, data, traditional );
};
var oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
jQuery.fn.andSelf = function() {
migrateWarn( "jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()" );
return oldSelf.apply( this, arguments );
};
var oldDeferred = jQuery.Deferred,
tuples = [
// Action, add listener, callbacks, .then handlers, final state
[ "resolve", "done", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), "resolved" ],
[ "reject", "fail", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), "rejected" ],
[ "notify", "progress", jQuery.Callbacks( "memory" ),
jQuery.Callbacks( "memory" ) ]
];
jQuery.Deferred = function( func ) {
var deferred = oldDeferred(),
promise = deferred.promise();
deferred.pipe = promise.pipe = function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
migrateWarn( "deferred.pipe() is deprecated" );
return jQuery.Deferred( function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// Deferred.done(function() { bind to newDefer or newDefer.resolve })
// deferred.fail(function() { bind to newDefer or newDefer.reject })
// deferred.progress(function() { bind to newDefer or newDefer.notify })
deferred[ tuple[ 1 ] ]( function() {
var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ tuple[ 0 ] + "With" ](
this === promise ? newDefer.promise() : this,
fn ? [ returned ] : arguments
);
}
} );
} );
fns = null;
} ).promise();
};
if ( func ) {
func.call( deferred, deferred );
}
return deferred;
};
// Preserve handler of uncaught exceptions in promise chains
jQuery.Deferred.exceptionHook = oldDeferred.exceptionHook;
return jQuery;
} );

View File

@@ -1,215 +0,0 @@
/*! jQuery Migrate v3.0.1 | (c) jQuery Foundation and other contributors | jquery.org/license */
void 0 === jQuery.migrateMute && (jQuery.migrateMute = !0), function(e) {
"function" == typeof define && define.amd ? define([ "jquery" ], window, e) : "object" == typeof module && module.exports ? module.exports = e(require("jquery"), window) : e(jQuery, window);
}(function(e, t) {
"use strict";
function r(r) {
var n = t.console;
o[r] || (o[r] = !0, e.migrateWarnings.push(r), n && n.warn && !e.migrateMute && (n.warn("JQMIGRATE: " + r),
e.migrateTrace && n.trace && n.trace()));
}
function n(e, t, n, a) {
Object.defineProperty(e, t, {
configurable: !0,
enumerable: !0,
get: function() {
return r(a), n;
},
set: function(e) {
r(a), n = e;
}
});
}
function a(e, t, n, a) {
e[t] = function() {
return r(a), n.apply(this, arguments);
};
}
e.migrateVersion = "3.0.1", function() {
var r = /^[12]\./;
t.console && t.console.log && (e && !r.test(e.fn.jquery) || t.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),
e.migrateWarnings && t.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),
t.console.log("JQMIGRATE: Migrate is installed" + (e.migrateMute ? "" : " with logging active") + ", version " + e.migrateVersion));
}();
var o = {};
e.migrateWarnings = [], void 0 === e.migrateTrace && (e.migrateTrace = !0), e.migrateReset = function() {
o = {}, e.migrateWarnings.length = 0;
}, "BackCompat" === t.document.compatMode && r("jQuery is not compatible with Quirks Mode");
var i = e.fn.init, s = e.isNumeric, u = e.find, c = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, l = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
e.fn.init = function(e) {
var t = Array.prototype.slice.call(arguments);
return "string" == typeof e && "#" === e && (r("jQuery( '#' ) is not a valid selector"),
t[0] = []), i.apply(this, t);
}, e.fn.init.prototype = e.fn, e.find = function(e) {
var n = Array.prototype.slice.call(arguments);
if ("string" == typeof e && c.test(e)) try {
t.document.querySelector(e);
} catch (a) {
e = e.replace(l, function(e, t, r, n) {
return "[" + t + r + '"' + n + '"]';
});
try {
t.document.querySelector(e), r("Attribute selector with '#' must be quoted: " + n[0]),
n[0] = e;
} catch (e) {
r("Attribute selector with '#' was not fixed: " + n[0]);
}
}
return u.apply(this, n);
};
var d;
for (d in u) Object.prototype.hasOwnProperty.call(u, d) && (e.find[d] = u[d]);
e.fn.size = function() {
return r("jQuery.fn.size() is deprecated and removed; use the .length property"),
this.length;
}, e.parseJSON = function() {
return r("jQuery.parseJSON is deprecated; use JSON.parse"), JSON.parse.apply(null, arguments);
}, e.isNumeric = function(t) {
var n = s(t), a = function(t) {
var r = t && t.toString();
return !e.isArray(t) && r - parseFloat(r) + 1 >= 0;
}(t);
return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"),
a;
}, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"),
n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),
n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos");
var p = e.ajax;
e.ajax = function() {
var e = p.apply(this, arguments);
return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"),
a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")),
e;
};
var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g;
e.fn.removeAttr = function(t) {
var n = this;
return e.each(t.match(m), function(t, a) {
e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a),
n.prop(a, !1));
}), f.apply(this, arguments);
}, e.fn.toggleClass = function(t) {
return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"),
this.each(function() {
var r = this.getAttribute && this.getAttribute("class") || "";
r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || "");
}));
};
var h = !1;
e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) {
var n = e.cssHooks[r] && e.cssHooks[r].get;
n && (e.cssHooks[r].get = function() {
var e;
return h = !0, e = n.apply(this, arguments), h = !1, e;
});
}), e.swap = function(e, t, n, a) {
var o, i, s = {};
h || r("jQuery.swap() is undocumented and deprecated");
for (i in t) s[i] = e.style[i], e.style[i] = t[i];
o = n.apply(e, a || []);
for (i in t) e.style[i] = s[i];
return o;
};
var g = e.data;
e.data = function(t, n, a) {
var o;
if (n && "object" == typeof n && 2 === arguments.length) {
o = e.hasData(t) && g.call(this, t);
var i = {};
for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s),
o[s] = n[s]) : i[s] = n[s];
return g.call(this, t, i), n;
}
return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n),
arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments);
};
var v = e.Tween.prototype.run, j = function(e) {
return e;
};
e.Tween.prototype.run = function() {
e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"),
e.easing[this.easing] = j), v.apply(this, arguments);
}, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated");
var Q = e.fn.load, b = e.event.add, w = e.event.fix;
e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"),
e.event.fix = function(t) {
var n, a = t.type, o = this.fixHooks[a], i = e.event.props;
if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop());
if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a),
(i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop());
return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n;
}, e.event.add = function(e, n) {
return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"),
b.apply(this, arguments);
}, e.each([ "load", "unload", "error" ], function(t, n) {
e.fn[n] = function() {
var e = Array.prototype.slice.call(arguments, 0);
return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"),
e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e),
this));
};
}), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) {
e.fn[n] = function(e, t) {
return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n);
};
}), e(function() {
e(t.document).triggerHandler("ready");
}), e.event.special.ready = {
setup: function() {
this === t.document && r("'ready' event is deprecated");
}
}, e.fn.extend({
bind: function(e, t, n) {
return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n);
},
unbind: function(e, t) {
return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t);
},
delegate: function(e, t, n, a) {
return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a);
},
undelegate: function(e, t, n) {
return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n);
},
hover: function(e, t) {
return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e);
}
});
var x = e.fn.offset;
e.fn.offset = function() {
var n, a = this[0], o = {
top: 0,
left: 0
};
return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"),
o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o);
};
var k = e.param;
e.param = function(t, n) {
var a = e.ajaxSettings && e.ajaxSettings.traditional;
return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),
n = a), k.call(this, t, n);
};
var A = e.fn.andSelf || e.fn.addBack;
e.fn.andSelf = function() {
return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),
A.apply(this, arguments);
};
var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ];
return e.Deferred = function(t) {
var n = S(), a = n.promise();
return n.pipe = a.pipe = function() {
var t = arguments;
return r("deferred.pipe() is deprecated"), e.Deferred(function(r) {
e.each(q, function(o, i) {
var s = e.isFunction(t[o]) && t[o];
n[i[1]](function() {
var t = s && s.apply(this, arguments);
t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments);
});
}), t = null;
}).promise();
}, t && t.call(n, n), n;
}, e.Deferred.exceptionHook = S.exceptionHook, e;
});

File diff suppressed because one or more lines are too long

View File

@@ -191,6 +191,7 @@
'$merge':{ args:[ 'array' ]},
'$millis':{ args:[ ]},
'$min':{ args:[ 'array' ]},
'$moment':{ args:[ ]},
'$not':{ args:[ 'arg' ]},
'$now':{ args:[ ]},
'$number':{ args:[ 'arg' ]},

View File

@@ -16,14 +16,12 @@
<script type="text/html" data-template-name="inject">
<div class="form-row">
<label for="node-input-payload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input type="text" id="node-input-payload" style="width:70%">
<input type="hidden" id="node-input-payloadType">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic">
<div class="form-row node-input-property-container-row">
<ol id="node-input-property-container"></ol>
</div>
<div class="form-row" id="node-once">
@@ -114,12 +112,7 @@
</div>
</div>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-tips" data-i18n="[html]inject.tip"></div>
</script>
<style>
.inject-time-row {
@@ -155,37 +148,76 @@
</style>
<script type="text/javascript">
(function() {
function resizeDialog(size) {
size = size || { height: $(".red-ui-tray-content form").height() }
var rows = $("#dialog-form>div:not(.node-input-property-container-row):visible");
var height = size.height;
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-property-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-property-container").editableList('height',height);
}
RED.nodes.registerType('inject',{
category: 'common',
color:"#a6bbcf",
defaults: {
name: {value:""},
topic: {value:""},
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
payloadType: {value:"date"},
props:{value:[{p:"payload"},{p:"topic",vt:"str"}]},
repeat: {value:"", validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0) && (v <= 2147483))) }},
crontab: {value:""},
once: {value:false},
onceDelay: {value:0.1}
onceDelay: {value:0.1},
topic: {value:""},
payload: {value:"", validate: RED.validators.typedInput("payloadType")},
payloadType: {value:"date"},
},
icon: "inject.svg",
inputs:0,
outputs:1,
outputLabels: function(index) {
var lab = this.payloadType;
if (lab === "json") {
try {
lab = typeof JSON.parse(this.payload);
if (lab === "object") {
if (Array.isArray(JSON.parse(this.payload))) { lab = "Array"; }
}
} catch(e) {
return this._("inject.label.invalid"); }
var lab = '';
// if only payload and topic - display payload type
// if only one property - show it's type
// if more than one property (other than payload and topic) - show "x properties" where x is the number of properties.
// this.props will not be an array for legacy inject nodes until they are re-deployed
//
var props = this.props;
if (!Array.isArray(props)) {
props = [
{ p:"payload", v: this.payload, vt: this.payloadType },
{ p:"topic", v: this.topic, vt: "str" }
]
}
var name = "inject.label."+lab;
var label = this._(name);
if (name !== label) {
return label;
if (props) {
for (var i=0,l=props.length; i<l; i++) {
if (i > 0) lab += "\n";
if (i === 5) {
lab += " + "+(props.length-4);
break;
}
lab += props[i].p+": ";
var propType = props[i].p === "payload"? this.payloadType : props[i].vt;
if (propType === "json") {
try {
var parsedProp = JSON.parse(props[i].p === "payload"? this.payload : props[i].v);
propType = typeof parsedProp;
if (propType === "object" && Array.isArray(parsedProp)) {
propType = "Array";
}
} catch(e) {
propType = "invalid";
}
}
lab += this._("inject.label."+propType);
}
}
return lab;
},
@@ -201,27 +233,33 @@
}
if (this.name) {
return this.name+suffix;
} else if (this.payloadType === "string" ||
this.payloadType === "str" ||
this.payloadType === "num" ||
this.payloadType === "bool" ||
this.payloadType === "json") {
if ((this.topic !== "") && ((this.topic.length + this.payload.length) <= 32)) {
return this.topic + ":" + this.payload+suffix;
} else if (this.payload.length > 0 && this.payload.length < 24) {
return this.payload+suffix;
}
var payload = this.payload || "";
var payloadType = this.payloadType || "str";
var topic = this.topic || "";
if (payloadType === "string" ||
payloadType === "str" ||
payloadType === "num" ||
payloadType === "bool" ||
payloadType === "json") {
if ((topic !== "") && ((topic.length + payload.length) <= 32)) {
return topic + ":" + payload+suffix;
} else if (payload.length > 0 && payload.length < 24) {
return payload+suffix;
} else {
return this._("inject.inject")+suffix;
}
} else if (this.payloadType === 'date') {
if ((this.topic !== "") && (this.topic.length <= 16)) {
return this.topic + ":" + this._("inject.timestamp")+suffix;
} else if (payloadType === 'date' || payloadType === 'bin' || payloadType === 'env') {
if ((topic !== "") && (topic.length <= 16)) {
return topic + ":" + this._('inject.label.'+payloadType)+suffix;
} else {
return this._("inject.timestamp")+suffix;
return this._('inject.label.'+payloadType)+suffix;
}
} else if (this.payloadType === 'flow' || this.payloadType === 'global') {
var key = RED.utils.parseContextKey(this.payload);
return this.payloadType+"."+key.key+suffix;
} else if (payloadType === 'flow' || payloadType === 'global') {
var key = RED.utils.parseContextKey(payload);
return payloadType+"."+key.key+suffix;
} else {
return this._("inject.inject")+suffix;
}
@@ -239,13 +277,6 @@
} else if (this.payloadType === 'string' || this.payloadType === 'none') {
this.payloadType = "str";
}
$("#node-input-payloadType").val(this.payloadType);
$("#node-input-payload").typedInput({
default: 'str',
typeField: $("#node-input-payloadType"),
types:['flow','global','str','num','bool','json','bin','date','env']
});
$("#inject-time-type-select").on("change", function() {
$("#node-input-crontab").val('');
@@ -259,6 +290,11 @@
$("#node-once").hide();
$("#node-input-once").prop('checked', false);
}
// Scroll down
var scrollDiv = $("#dialog-form").parent();
scrollDiv.scrollTop(scrollDiv.prop('scrollHeight'));
resizeDialog();
});
$("#node-input-once").on("change", function() {
@@ -378,7 +414,70 @@
$("#inject-time-type-select").val(repeattype);
$("#inject-time-row-"+repeattype).show();
$("#node-input-payload").typedInput('type',this.payloadType);
/* */
$('#node-input-property-container').css('min-height','120px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var prop = opt;
if (!prop.hasOwnProperty('p')) {
prop = {p:"",v:"",vt:"str"};
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
var row = $('<div/>').appendTo(container);
var propertyName = $('<input/>',{class:"node-input-prop-property-name",type:"text"})
.css("width","30%")
.appendTo(row)
.typedInput({types:['msg']});
$('<div/>',{style: 'display:inline-block; padding:0px 6px;'})
.text('=')
.appendTo(row);
var propertyValue = $('<input/>',{class:"node-input-prop-property-value",type:"text"})
.css("width","calc(70% - 30px)")
.appendTo(row)
.typedInput({default:'str',types:['msg','flow','global','str','num','bool','json','bin','date','jsonata','env']});
propertyName.typedInput('value',prop.p);
propertyValue.typedInput('value',prop.v);
propertyValue.typedInput('type',prop.vt);
},
removable: true,
sortable: true
});
if (!this.props) {
var payload = {
p:'payload',
v: this.payload ? this.payload : '',
vt:this.payloadType ? this.payloadType : 'date'
};
var topic = {
p:'topic',
v: this.topic ? this.topic : '',
vt:'string'
}
this.props = [payload,topic];
}
for (var i=0; i<this.props.length; i++) {
var prop = this.props[i];
var newProp = { p: prop.p, v: prop.v, vt: prop.vt };
if (newProp.v === undefined) {
if (prop.p === 'payload') {
newProp.v = this.payload ? this.payload : '';
newProp.vt = this.payloadType ? this.payloadType : 'date';
} else if (prop.p === 'topic' && prop.vt === "str") {
newProp.v = this.topic ? this.topic : '';
}
}
$("#node-input-property-container").editableList('addItem',newProp);
}
$("#inject-time-type-select").trigger("change");
$("#inject-time-interval-time-start").trigger("change");
@@ -474,6 +573,34 @@
$("#node-input-repeat").val(repeat);
$("#node-input-crontab").val(crontab);
/* Gather the injected properties of the msg object */
var props = $("#node-input-property-container").editableList('items');
var node = this;
node.props= [];
delete node.payloadType;
delete node.payload;
node.topic = "";
props.each(function(i) {
var prop = $(this);
var p = {
p:prop.find(".node-input-prop-property-name").typedInput('value')
};
if (p.p) {
p.v = prop.find(".node-input-prop-property-value").typedInput('value');
p.vt = prop.find(".node-input-prop-property-value").typedInput('type');
if (p.p === "payload") { // save payload to old "legacy" property
node.payloadType = p.vt;
node.payload = p.v;
delete p.v;
delete p.vt;
} else if (p.p === "topic" && p.vt === "str") {
node.topic = p.v;
delete p.v;
}
node.props.push(p);
}
});
},
button: {
enabled: function() {
@@ -483,12 +610,7 @@
if (this.changed) {
return RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.undeployedChanges")}),"warning");
}
var payload = this.payload;
if ((this.payloadType === 'flow') ||
(this.payloadType === 'global')) {
var key = RED.utils.parseContextKey(payload);
payload = this.payloadType+"."+key.key;
}
var label = this._def.label.call(this);
if (label.length > 30) {
label = label.substring(0,50)+"...";
@@ -514,7 +636,8 @@
}
});
}
}
},
oneditresize: resizeDialog
});
})();
</script>

View File

@@ -20,9 +20,32 @@ module.exports = function(RED) {
function InjectNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.payload = n.payload;
this.payloadType = n.payloadType;
/* Handle legacy */
if(!Array.isArray(n.props)){
n.props = [];
n.props.push({
p:'payload',
v:n.payload,
vt:n.payloadType
});
n.props.push({
p:'topic',
v:n.topic,
vt:'str'
});
} else {
for (var i=0,l=n.props.length; i<l; i++) {
if (n.props[i].p === 'payload' && !n.props[i].hasOwnProperty('v')) {
n.props[i].v = n.payload;
n.props[i].vt = n.payloadType;
} else if (n.props[i].p === 'topic' && n.props[i].vt === 'str' && !n.props[i].hasOwnProperty('v')) {
n.props[i].v = n.topic;
}
}
}
this.props = n.props;
this.repeat = n.repeat;
this.crontab = n.crontab;
this.once = n.once;
@@ -31,65 +54,83 @@ module.exports = function(RED) {
this.cronjob = null;
var node = this;
node.props.forEach(function (prop) {
if (prop.vt === "jsonata") {
try {
var val = prop.v ? prop.v : "";
prop.exp = RED.util.prepareJSONataExpression(val, node);
}
catch (err) {
node.error(RED._("inject.errors.invalid-expr", {error:err.message}));
prop.exp = null;
}
}
});
if (node.repeat > 2147483) {
node.error(RED._("inject.errors.toolong", this));
delete node.repeat;
}
node.repeaterSetup = function () {
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000;
if (RED.settings.verbose) {
this.log(RED._("inject.repeat", this));
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000;
if (RED.settings.verbose) {
this.log(RED._("inject.repeat", this));
}
this.interval_id = setInterval(function() {
node.emit("input", {});
}, this.repeat);
} else if (this.crontab) {
if (RED.settings.verbose) {
this.log(RED._("inject.crontab", this));
}
this.cronjob = new cron.CronJob(this.crontab, function() { node.emit("input", {}); }, null, true);
}
this.interval_id = setInterval(function() {
node.emit("input", {});
}, this.repeat);
} else if (this.crontab) {
if (RED.settings.verbose) {
this.log(RED._("inject.crontab", this));
}
this.cronjob = new cron.CronJob(this.crontab, function() { node.emit("input", {}); }, null, true);
}
};
if (this.once) {
this.onceTimeout = setTimeout( function() {
node.emit("input",{});
node.repeaterSetup();
node.emit("input",{});
node.repeaterSetup();
}, this.onceDelay);
} else {
node.repeaterSetup();
node.repeaterSetup();
}
this.on("input",function(msg) {
msg.topic = this.topic;
if (this.payloadType !== 'flow' && this.payloadType !== 'global') {
try {
if ( (this.payloadType == null && this.payload === "") || this.payloadType === "date") {
msg.payload = Date.now();
} else if (this.payloadType == null) {
msg.payload = this.payload;
} else if (this.payloadType === 'none') {
msg.payload = "";
} else {
msg.payload = RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg);
}
this.send(msg);
msg = null;
} catch(err) {
this.error(err,msg);
}
} else {
RED.util.evaluateNodeProperty(this.payload,this.payloadType,this,msg, function(err,res) {
if (err) {
node.error(err,msg);
} else {
msg.payload = res;
node.send(msg);
}
this.on("input", function(msg) {
var errors = [];
});
this.props.forEach(p => {
var property = p.p;
var value = p.v ? p.v : '';
var valueType = p.vt ? p.vt : 'str';
if (!property) return;
if (valueType === "jsonata") {
if (p.exp) {
try {
var val = RED.util.evaluateJSONataExpression(p.exp, msg);
RED.util.setMessageProperty(msg, property, val, true);
}
catch (err) {
errors.push(err.message);
}
}
return;
}
try {
RED.util.setMessageProperty(msg,property,RED.util.evaluateNodeProperty(value, valueType, this, msg),true);
} catch (err) {
errors.push(err.toString());
}
});
if (errors.length) {
node.error(errors.join('; '), msg);
} else {
node.send(msg);
}
});
}

View File

@@ -6,25 +6,30 @@
<input id="node-input-complete" type="hidden">
<input id="node-input-targetType" type="hidden">
</div>
<div class="form-row">
<label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
<label for="node-input-tosidebar" style="width:70%">
<input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toSidebar"></span>
<input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toSidebar"></span>
</label>
</div>
<div class="form-row">
<label for="node-input-console"> </label>
<label for="node-input-console" style="width:70%">
<input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toConsole"></span>
<input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toConsole"></span>
</label>
</div>
<div class="form-row" id="node-tostatus-line">
<div class="form-row">
<label for="node-input-tostatus"> </label>
<label for="node-input-tostatus" style="width:70%">
<input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toStatus"></span>
<input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toStatus"></span>
</label>
</div>
<div class="form-row" id="node-tostatus-line">
<label for="node-input-typed-status"></label>
<input id="node-input-typed-status" type="text" style="width: 70%">
<input id="node-input-statusVal" type="hidden">
<input id="node-input-statusType" type="hidden">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
@@ -36,6 +41,36 @@
<script type="text/javascript">
(function() {
var subWindow = null;
function activateAjaxCall(node, active, successCallback) {
var url;
var body;
if (Array.isArray(node)) {
url = "debug/"+(active?"enable":"disable");
body = {nodes: node.map(function(n) { return n.id})}
node = node[0];
} else {
url = "debug/"+node.id+"/"+(active?"enable":"disable");
}
$.ajax({
url: url,
type: "POST",
data: body,
success: successCallback,
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status == 404) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.not-deployed")}),"error");
} else if (jqXHR.status === 0) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.no-response")}),"error");
} else {
// TODO where is the err.status comming from?
RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
}
}
});
}
RED.nodes.registerType('debug',{
category: 'common',
defaults: {
@@ -45,7 +80,9 @@
console: {value:false},
tostatus: {value:false},
complete: {value:"false", required:true},
targetType: {value:undefined}
targetType: {value:undefined},
statusVal: {value:""},
statusType: {value:"auto"}
},
label: function() {
var suffix = "";
@@ -73,38 +110,28 @@
onclick: function() {
var label = this.name||"debug";
var node = this;
$.ajax({
url: "debug/"+this.id+"/"+(this.active?"enable":"disable"),
type: "POST",
success: function(resp, textStatus, xhr) {
var historyEvent = {
t:'edit',
node:node,
changes:{
active:!node.active
},
dirty:node.dirty,
changed:node.changed
};
node.changed = true;
node.dirty = true;
RED.nodes.dirty(true);
RED.history.push(historyEvent);
RED.view.redraw();
if (xhr.status == 200) {
RED.notify(node._("debug.notification.activated",{label:label}),"success");
} else if (xhr.status == 201) {
RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
}
},
error: function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status == 404) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.not-deployed")}),"error");
} else if (jqXHR.status === 0) {
RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.no-response")}),"error");
} else {
RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
activateAjaxCall(node, node.active, function(resp, textStatus, xhr) {
var historyEvent = {
t:'edit',
node:node,
changes:{
active:!node.active
},
dirty:node.dirty,
changed:node.changed,
callback: function(ev) {
activateAjaxCall(ev.node, ev.node.active);
}
};
node.changed = true;
node.dirty = true;
RED.nodes.dirty(true);
RED.history.push(historyEvent);
RED.view.redraw();
if (xhr.status == 200) {
RED.notify(node._("debug.notification.activated",{label:label}),"success");
} else if (xhr.status == 201) {
RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
}
});
}
@@ -266,6 +293,78 @@
RED.events.on("project:change", this.clearMessageList);
RED.actions.add("core:clear-debug-messages", function() { RED.debug.clearMessageList(true) });
RED.actions.add("core:activate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(true), true); });
RED.actions.add("core:activate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, true),true); });
RED.actions.add("core:activate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, false),true); });
RED.actions.add("core:deactivate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(false), false); });
RED.actions.add("core:deactivate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, true),false); });
RED.actions.add("core:deactivate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, false),false); });
function getSelectedDebugNodes(state) {
var nodes = [];
var selection = RED.view.selection();
if (selection.nodes) {
selection.nodes.forEach(function(n) {
if (RED.nodes.subflow(n.z)) {
return;
}
if (n.type === 'debug' && n.active !== state) {
nodes.push(n);
} else if (n.type === 'group') {
nodes = nodes.concat( RED.group.getNodes(n,true).filter(function(n) {
return n.type === 'debug' && n.active !== state
}));
}
});
}
return nodes;
}
function getMatchingDebugNodes(state,globally) {
var nodes = [];
var filter = {type:"debug"};
if (!globally) {
filter.z = RED.workspaces.active();
}
var candidateNodes = RED.nodes.filterNodes(filter);
nodes = candidateNodes.filter(function(n) {
return n.active !== state && !RED.nodes.subflow(n.z)
})
return nodes;
}
function setDebugNodeState(nodes,state) {
var historyEvents = [];
if (nodes.length > 0) {
activateAjaxCall(nodes,false, function(resp, textStatus, xhr) {
nodes.forEach(function(n) {
historyEvents.push({
t: "edit",
node: n,
changed: n.changed,
changes: {
active: n.active
}
});
n.active = state;
n.changed = true;
n.dirty = true;
})
RED.history.push({
t: "multi",
events: historyEvents,
dirty: RED.nodes.dirty(),
callback: function() {
activateAjaxCall(nodes,nodes[0].active);
}
});
RED.nodes.dirty(true);
RED.view.redraw();
});
}
}
$("#red-ui-sidebar-debug-open").on("click", function(e) {
e.preventDefault();
subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
@@ -308,10 +407,20 @@
window.removeEventListener("message",this.handleWindowMessage);
RED.actions.remove("core:show-debug-tab");
RED.actions.remove("core:clear-debug-messages");
delete RED._debug;
},
oneditprepare: function() {
var autoType = {
value: "auto",
label: RED._("node-red:debug.autostatus"),
hasValue: false
};
$("#node-input-typed-status").typedInput({
default: "auto",
types:[autoType, "msg", "jsonata"],
typeField: $("#node-input-statusType")
});
var that = this;
var none = {
value: "none",
label: RED._("node-red:debug.none"),
@@ -321,6 +430,14 @@
this.tosidebar = true;
$("#node-input-tosidebar").prop('checked', true);
}
if (this.statusVal === undefined) {
this.statusVal = (this.complete === "false") ? "payload" : ((this.complete === "true") ? "payload" : this.complete+"");
$("#node-input-typed-status").typedInput('value',this.statusVal || "");
}
if (this.statusType === undefined) {
this.statusType = "auto";
$("#node-input-typed-status").typedInput('type',this.statusType || "auto");
}
if (typeof this.console === "string") {
this.console = (this.console == 'true');
$("#node-input-console").prop('checked', this.console);
@@ -331,6 +448,7 @@
label: RED._("node-red:debug.msgobj"),
hasValue: false
};
$("#node-input-typed-complete").typedInput({
default: "msg",
types:['msg', fullType, "jsonata"],
@@ -354,17 +472,29 @@
) {
$("#node-input-typed-complete").typedInput('value','payload');
}
if ($("#node-input-typed-complete").typedInput('type') === 'full') {
$("#node-tostatus-line").hide();
} else {
});
$("#node-input-tostatus").on('change',function() {
if ($(this).is(":checked")) {
if (!that.hasOwnProperty("statusVal") || that.statusVal === "") {
var type = $("#node-input-typed-complete").typedInput('type');
var comp = "payload";
if (type !== 'full') {
comp = $("#node-input-typed-complete").typedInput('value');
}
that.statusType = "auto";
that.statusVal = comp;
}
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
$("#node-tostatus-line").show();
}
});
$("#node-input-complete").on('change',function() {
if ($("#node-input-typed-complete").typedInput('type') === 'full') {
else {
$("#node-tostatus-line").hide();
} else {
$("#node-tostatus-line").show();
that.statusType = "auto";
that.statusVal = "";
$("#node-input-typed-status").typedInput('type',that.statusType);
$("#node-input-typed-status").typedInput('value',that.statusVal);
}
});
},
@@ -375,6 +505,7 @@
} else {
$("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
}
$("#node-input-statusVal").val($("#node-input-typed-status").typedInput('value'));
}
});
})();

View File

@@ -2,7 +2,7 @@ module.exports = function(RED) {
"use strict";
var util = require("util");
var events = require("events");
var path = require("path");
//var path = require("path");
var debuglength = RED.settings.debugMaxLength || 1000;
var useColors = RED.settings.debugUseColors || false;
util.inspect.styles.boolean = "red";
@@ -15,36 +15,20 @@ module.exports = function(RED) {
this.complete = hasEditExpression ? null : (n.complete||"payload").toString();
if (this.complete === "false") { this.complete = "payload"; }
this.console = ""+(n.console || false);
this.tostatus = (this.complete !== "true") && (n.tostatus || false);
this.tostatus = n.tostatus || false;
this.statusType = n.statusType || "auto";
this.statusVal = n.statusVal || this.complete;
this.tosidebar = n.tosidebar;
if (this.tosidebar === undefined) { this.tosidebar = true; }
this.severity = n.severity || 40;
this.active = (n.active === null || typeof n.active === "undefined") || n.active;
if (this.tostatus) { this.status({fill:"grey", shape:"ring"}); }
else { this.status({}); }
var hasStatExpression = (n.statusType === "jsonata");
var statExpression = hasStatExpression ? n.statusVal : null;
var node = this;
var levels = {
off: 1,
fatal: 10,
error: 20,
warn: 30,
info: 40,
debug: 50,
trace: 60,
audit: 98,
metric: 99
};
var colors = {
"0": "grey",
"10": "grey",
"20": "red",
"30": "yellow",
"40": "grey",
"50": "green",
"60": "blue"
};
var preparedEditExpression = null;
var preparedStatExpression = null;
if (editExpression) {
try {
preparedEditExpression = RED.util.prepareJSONataExpression(editExpression, this);
@@ -54,16 +38,22 @@ module.exports = function(RED) {
return;
}
}
if (statExpression) {
try {
preparedStatExpression = RED.util.prepareJSONataExpression(statExpression, this);
}
catch (e) {
node.error(RED._("debug.invalid-exp", {error: editExpression}));
return;
}
}
function prepareValue(msg, done) {
// Either apply the jsonata expression or...
if (preparedEditExpression) {
RED.util.evaluateJSONataExpression(preparedEditExpression, msg, (err, value) => {
if (err) {
done(RED._("debug.invalid-exp", {error: editExpression}));
} else {
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value});
}
if (err) { done(RED._("debug.invalid-exp", {error: editExpression})); }
else { done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value}); }
});
} else {
// Extract the required message property
@@ -71,17 +61,81 @@ module.exports = function(RED) {
var output = msg[property];
if (node.complete !== "false" && typeof node.complete !== "undefined") {
property = node.complete;
try {
output = RED.util.getMessageProperty(msg,node.complete);
} catch(err) {
output = undefined;
}
try { output = RED.util.getMessageProperty(msg,node.complete); }
catch(err) { output = undefined; }
}
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, property:property, msg:output});
}
}
function prepareStatus(msg, done) {
if (node.statusType === "auto") {
if (node.complete === "true") {
done(null,{msg:msg.payload});
}
else {
prepareValue(msg,function(err,debugMsg) {
if (err) { node.error(err); return; }
done(null,{msg:debugMsg.msg});
});
}
}
else {
// Either apply the jsonata expression or...
if (preparedStatExpression) {
RED.util.evaluateJSONataExpression(preparedStatExpression, msg, (err, value) => {
if (err) { done(RED._("debug.invalid-exp", {error:editExpression})); }
else { done(null,{msg:value}); }
});
}
else {
// Extract the required message property
var output;
try { output = RED.util.getMessageProperty(msg,node.statusVal); }
catch(err) { output = undefined; }
done(null,{msg:output});
}
}
}
this.on("input", function(msg, send, done) {
if (msg.hasOwnProperty("status") && msg.status.hasOwnProperty("source") && msg.status.source.hasOwnProperty("id") && (msg.status.source.id === node.id)) {
done();
return;
}
if (node.tostatus === true) {
prepareStatus(msg, function(err,debugMsg) {
if (err) { node.error(err); return; }
var output = debugMsg.msg;
var st = (typeof output === 'string') ? output : util.inspect(output);
var fill = "grey";
var shape = "dot";
if (typeof output === 'object' && output.hasOwnProperty("fill") && output.hasOwnProperty("shape") && output.hasOwnProperty("text")) {
fill = output.fill;
shape = output.shape;
st = output.text;
}
if (node.statusType === "auto") {
if (msg.hasOwnProperty("error")) {
fill = "red";
st = msg.error.message;
}
if (msg.hasOwnProperty("status")) {
fill = msg.status.fill || "grey";
shape = msg.status.shape || "ring";
st = msg.status.text || "";
}
}
if (st.length > 32) { st = st.substr(0,32) + "..."; }
var newStatus = {fill:fill, shape:shape, text:st};
if (JSON.stringify(newStatus) !== node.oldState) { // only send if we have to
node.status(newStatus);
node.oldState = JSON.stringify(newStatus);
}
});
}
if (this.complete === "true") {
// debug complete msg object
if (this.console === "true") {
@@ -91,7 +145,8 @@ module.exports = function(RED) {
sendDebug({id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:msg});
}
done();
} else {
}
else {
prepareValue(msg,function(err,debugMsg) {
if (err) {
node.error(err);
@@ -107,12 +162,6 @@ module.exports = function(RED) {
node.log(util.inspect(output, {colors:useColors}));
}
}
if (node.tostatus === true) {
var st = (typeof output === 'string')?output:util.inspect(output);
var severity = node.severity;
if (st.length > 32) { st = st.substr(0,32) + "..."; }
node.status({fill:colors[severity], shape:"dot", text:st});
}
if (node.active) {
if (node.tosidebar == true) {
sendDebug(debugMsg);
@@ -150,24 +199,49 @@ module.exports = function(RED) {
});
RED.log.addHandler(DebugNode.logHandler);
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var node = RED.nodes.getNode(req.params.id);
var state = req.params.state;
if (node !== null && typeof node !== "undefined" ) {
if (state === "enable") {
node.active = true;
res.sendStatus(200);
if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); }
} else if (state === "disable") {
node.active = false;
res.sendStatus(201);
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
node.oldStatus.shape = "dot";
node.status(node.oldStatus);
}
} else {
res.sendStatus(404);
function setNodeState(node,state) {
if (state) {
node.active = true;
if (node.tostatus) { node.status({fill:"grey", shape:"dot"}); }
} else {
node.active = false;
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
node.oldStatus.shape = "dot";
node.status(node.oldStatus);
}
}
}
RED.httpAdmin.post("/debug/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var state = req.params.state;
if (state !== 'enable' && state !== 'disable') {
res.sendStatus(404);
return;
}
var nodes = req.body && req.body.nodes;
if (Array.isArray(nodes)) {
nodes.forEach(function(id) {
var node = RED.nodes.getNode(id);
if (node !== null && typeof node !== "undefined" ) {
setNodeState(node, state === "enable");
}
})
res.sendStatus(state === "enable" ? 200 : 201);
} else {
res.sendStatus(400);
}
})
RED.httpAdmin.post("/debug/:id/:state", RED.auth.needsPermission("debug.write"), function(req,res) {
var state = req.params.state;
if (state !== 'enable' && state !== 'disable') {
res.sendStatus(404);
return;
}
var node = RED.nodes.getNode(req.params.id);
if (node !== null && typeof node !== "undefined" ) {
setNodeState(node,state === "enable");
res.sendStatus(state === "enable" ? 200 : 201);
} else {
res.sendStatus(404);
}

View File

@@ -2,7 +2,8 @@
<div class="form-row node-input-target-row">
<button id="node-input-complete-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="min-height: 100px">
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-complete-target-filter"></div>
<div id="node-input-complete-target-container-div"></div>
</div>
@@ -45,6 +46,22 @@
var editorRow = $("#dialog-form>div.node-input-target-list-row");
editorRow.css("height",height+"px");
};
var search = $("#node-input-complete-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
dirList.treeList("filter", null);
search.searchBox("count","");
} else {
var count = dirList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || item.node.type.toLowerCase().indexOf(val) > -1
});
search.searchBox("count",count+" / "+candidateNodes.length);
}
}
});
var dirList = $("#node-input-complete-target-container-div").css({width: "100%", height: "100%"})
.treeList({multi:true}).on("treelistitemmouseover", function(e, item) {
@@ -89,7 +106,8 @@
node: n,
label: label,
sublabel: sublabel,
selected: isChecked
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});

View File

@@ -14,7 +14,8 @@
<div class="form-row node-input-target-row">
<button id="node-input-catch-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="min-height: 100px">
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-catch-target-filter"></div>
<div id="node-input-catch-target-container-div"></div>
</div>
@@ -60,7 +61,22 @@
var editorRow = $("#dialog-form>div.node-input-target-list-row");
editorRow.css("height",height+"px");
};
var search = $("#node-input-catch-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
dirList.treeList("filter", null);
search.searchBox("count","");
} else {
var count = dirList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || item.node.type.toLowerCase().indexOf(val) > -1
});
search.searchBox("count",count+" / "+candidateNodes.length);
}
}
});
var dirList = $("#node-input-catch-target-container-div").css({width: "100%", height: "100%"})
.treeList({multi:true}).on("treelistitemmouseover", function(e, item) {
item.node.highlighted = true;
@@ -104,7 +120,8 @@
node: n,
label: label,
sublabel: sublabel,
selected: isChecked
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});

View File

@@ -10,7 +10,8 @@
<div class="form-row node-input-target-row">
<button id="node-input-status-target-select" class="red-ui-button" data-i18n="common.label.selectNodes"></button>
</div>
<div class="form-row node-input-target-row node-input-target-list-row" style="min-height: 100px">
<div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
<div style="position: absolute; top: -30px; right: 0;"><input type="text" id="node-input-status-target-filter"></div>
<div id="node-input-status-target-container-div"></div>
</div>
<div class="form-row">
@@ -48,6 +49,22 @@
var editorRow = $("#dialog-form>div.node-input-target-list-row");
editorRow.css("height",height+"px");
};
var search = $("#node-input-status-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
dirList.treeList("filter", null);
search.searchBox("count","");
} else {
var count = dirList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || item.node.type.toLowerCase().indexOf(val) > -1
});
search.searchBox("count",count+" / "+candidateNodes.length);
}
}
});
var dirList = $("#node-input-status-target-container-div").css({width: "100%", height: "100%"})
.treeList({multi:true}).on("treelistitemmouseover", function(e, item) {
@@ -92,7 +109,8 @@
node: n,
label: label,
sublabel: sublabel,
selected: isChecked
selected: isChecked,
checkbox: true
};
items.push(nodeItemMap[n.id]);
});

View File

@@ -4,6 +4,7 @@
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div style="position:relative; height: 30px; text-align: right;"><div style="display:inline-block"><input type="text" id="node-input-link-target-filter"></div></div>
<div class="form-row node-input-link-row"></div>
</script>
<script type="text/html" data-template-name="link out">
@@ -11,6 +12,7 @@
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div style="position:relative; height: 30px; text-align: right;"><div style="display:inline-block"><input type="text" id="node-input-link-target-filter"></div></div>
<div class="form-row node-input-link-row"></div>
</script>
@@ -47,6 +49,24 @@
});
var candidateNodes = RED.nodes.filterNodes({type:targetType});
var search = $("#node-input-link-target-filter").searchBox({
style: "compact",
delay: 300,
change: function() {
var val = $(this).val().trim().toLowerCase();
if (val === "") {
treeList.treeList("filter", null);
search.searchBox("count","");
} else {
var count = treeList.treeList("filter", function(item) {
return item.label.toLowerCase().indexOf(val) > -1 || (item.node && item.node.type.toLowerCase().indexOf(val) > -1)
});
search.searchBox("count",count+" / "+candidateNodes.length);
}
}
});
var flows = [];
var flowMap = {};
@@ -83,7 +103,8 @@
id: n.id,
node: n,
label: n.name||n.id,
selected: isChecked
selected: isChecked,
checkbox: true
})
}
});

View File

@@ -1,5 +1,5 @@
$(function() {
RED.i18n.init({},function() {
RED.i18n.init({apiRootUrl:"../../"},function() {
var options = {
messageMouseEnter: function(sourceId) {
window.opener.postMessage({event:"mouseEnter",id:sourceId},'*');

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