Compare commits

...

1361 Commits

Author SHA1 Message Date
Moshe Wajnberg
1532d9b6e2 Adding bidi preferences (#1375) 2017-09-17 09:05:26 +01:00
Dave Conway-Jones
a844ca161f Spinner fixes (#1371)
* Fix for function node invalid spinner values

to close #1370

* better validation of spinners for inject and delay

(don’t allow negative numbers)

* remove need for declaring local min variable
2017-08-21 22:00:23 +01:00
btsimonh
e09efba313 mqtt: Add 'name' to mqtt-broker node, and label it by this if it is set. (#1364)
This allows you to easily distinguish between broker nodes which are talking to the same server but with different credentials.
2017-08-09 22:22:40 +01:00
Nick O'Leary
96a0dbea2d Don't include subflow meta-port nodes in exported selection
Fixes #1362
2017-08-08 15:48:54 +01:00
Nick O'Leary
5b3b5271ad Remove test diff code 2017-08-07 16:38:15 +01:00
Kazuhito Yokoi
d7d13c12fe Modify messages to refer to language files (#1361) 2017-08-07 10:00:28 +01:00
Nick O'Leary
54220d0e71 Ensure shade elements have a higher z-index than ui elements 2017-08-04 22:20:58 +01:00
Nick O'Leary
4a2e3586f1 Allow delay node in rate-limit mode to be reset
Fixes #1360
2017-08-04 21:09:00 +01:00
Nick O'Leary
f808e85da9 Diff view: subflows can have port labels as well 2017-08-04 14:26:05 +01:00
Nick O'Leary
1671d1f580 Allow expanding diff elements to stay in-sync deeper 2017-08-04 14:23:28 +01:00
Nick O'Leary
7de1bf9d95 Better node properties layout in diff table 2017-08-03 23:04:39 +01:00
Nick O'Leary
7368b0cefb Make diff tool a maximised tray rather than dialog 2017-08-03 09:58:25 +01:00
Nick O'Leary
4af43d676a Include input/output labels in diff view 2017-08-02 21:57:23 +01:00
Nick O'Leary
67dc848b2d getNodeIcon should handle subflow types properly 2017-08-02 21:55:25 +01:00
Nick O'Leary
7ec8f0d26b Do not include tab types in typeSearch dialog 2017-08-02 21:54:58 +01:00
Nick O'Leary
eaf08a9971 Keep local/remote diff objects in sync as they expand 2017-07-31 23:29:36 +01:00
Nick O'Leary
5bdb9e972e Add httpStatic log statement on start up 2017-07-26 11:45:49 -07:00
Nick O'Leary
d4d87054c4 Ensure tab property changes are listed in diff view 2017-07-26 07:55:53 -07:00
Nick O'Leary
0f93929544 Fix diff view node properties table rendering 2017-07-26 07:47:19 -07:00
Nick O'Leary
1c0e794f87 Ensure tabs get their definition object properly attached 2017-07-26 07:46:22 -07:00
Nick O'Leary
f9bce5a5f9 Changelog for 0.17.5 2017-07-23 17:32:27 +01:00
Nick O'Leary
797ae096c8 Add express-session missing dependency for oauth 2017-07-23 17:31:42 +01:00
Nick O'Leary
6d76918424 Fix improper type tests is core test cases 2017-07-22 22:42:35 +01:00
Nick O'Leary
2aced893c6 File node: recreate write stream when file deleted
Fixes #1351
2017-07-22 22:28:45 +01:00
Nick O'Leary
f0373cd789 Add flow stopping trace messages 2017-07-21 11:15:40 +01:00
Kazuki Nakanishi
2f88dc64fc Fix userDir test case when .config.json exists (#1350) 2017-07-21 11:12:04 +01:00
Nick O'Leary
781ca77794 Do not try to send msg after http request error handled
Fixes #1344
2017-07-19 22:37:29 +01:00
Kazuhito Yokoi
c6e453fb00 Fix boundary problem in range node (#1338)
* Fix boundary problem in range node

* Remove duplicated test case

* Empty commit to retry Travis CI
2017-07-19 16:42:39 +01:00
Kazuhito Yokoi
a40b3dd377 Modify messages in node properties to refer messages.json (#1339) 2017-07-19 13:50:34 +01:00
martiall
096b3534d8 Fix settings.js replacing webSocketVerifyClient by webSocketNodeVerifyClient (#1343) 2017-07-14 11:34:29 +01:00
Nick O'Leary
5324244c55 Bump for 0.17.4 2017-07-10 13:16:13 +01:00
Nick O'Leary
993f1dc853 Add request node test case for POSTing 0 2017-07-09 12:18:05 +01:00
Patrik Åkerfeldt
d8a4e9e1ab Allow false and 0 in payload for httprequest (#1334) 2017-07-09 12:17:54 +01:00
Kazuhito Yokoi
b3ffd33507 Add file extension into flow name of library automatically (#1331) 2017-07-09 11:58:17 +01:00
Nick O'Leary
c93870316c Fix accessing global context from jsonata expressions
Fixes #1335
2017-07-09 10:40:23 +01:00
Nick O'Leary
fc9906624e Disable editor whilst a deploy is inflight
Fixes #1332
2017-07-08 21:16:52 +01:00
Nick O'Leary
ba6209ba54 Replace Unknown nodes with their real versions when node loaded 2017-07-08 17:30:17 +01:00
Nick O'Leary
f9769a73fe Retry auto-install of modules that fail
- introduces autoInstallModulesRetry - default 30000
 - backs off interval if repeated failures
 - fixes notification to the editor of an auto-reinstall
2017-07-08 17:30:17 +01:00
Kazuhito Yokoi
3a2f56cb95 Fix column name in link nodes to refer language file (#1330) 2017-07-07 11:43:07 +01:00
Nick O'Leary
a4d33879dc Use namespaces with link node title attributes i18n name
Fixes #1329
2017-07-06 17:57:53 +01:00
Nick O'Leary
e2a91d1ea9 Tidy up GPIO pin table presentation
Fixes #1328
2017-07-06 00:00:08 +01:00
Nick O'Leary
f30f80d117 Join: count of 0 should not send on every msg 2017-07-05 14:12:28 +01:00
Nick O'Leary
266274135e Handle importing only one end of a link node pair 2017-07-04 23:40:37 +01:00
Nick O'Leary
a10439b67c Make sending to Debug synchronous again
Fixes #1323

Being asynchronous meant the msg that was eventually sent to
Debug could be a modified version from later in the flow, if
the flow was other synchronous.
2017-07-04 23:30:51 +01:00
Nick O'Leary
0fd8d0e2bf Make send-error behaviour optional in file node
Existing nodes will have sendError enabled. New instances
will default to it being disabled.
2017-07-04 20:12:53 +01:00
Nick O'Leary
47e2707fd3 Restore File In node behaviour of sending msg on error 2017-07-04 19:55:09 +01:00
Nick O'Leary
f7bb4a7d60 Expose context.keys within Function node 2017-07-04 14:52:14 +01:00
Nick O'Leary
6102a31a31 JSON parser default should be not formatting output
If its a checkbox, then the default value should be a boolean,
not a string. Because "false" is truthy.
2017-07-04 13:44:37 +01:00
Nick O'Leary
1692c3b102 Update changelog/package for 0.17.3 2017-07-04 10:06:24 +01:00
Kazuhito Yokoi
ac60725d2a Fix flow library in menu to support period characters as flow name (#1320) 2017-07-04 10:02:24 +01:00
Nick O'Leary
1542f73fa5 Fix global leaks in theme.js 2017-07-04 09:43:16 +01:00
Nick O'Leary
70a22187f7 editorTheme not setting custom css/scripts properly 2017-07-04 09:33:27 +01:00
Kazuki Nakanishi
347e598715 Fix missing icons for some nodes (#1321) 2017-07-04 09:04:27 +01:00
Nick O'Leary
a737810c50 Add reformat button to JSONata test data editor 2017-07-03 21:57:55 +01:00
Nick O'Leary
92654a71fb Remove unused oldDepth from Delay node 2017-07-03 21:27:45 +01:00
Nick O'Leary
18615640e0 Update delay node status without spawning unecessary intervals 2017-07-03 21:23:14 +01:00
Nick O'Leary
b8c80a2310 Avoid stringify ServerResponse and Socket in Debug node
Fixes #1311
2017-07-03 20:55:04 +01:00
Kazuki Nakanishi
c34c98386e Fix creating userDir other than system drive on Windows (#1317) 2017-07-03 15:22:49 +01:00
Nick O'Leary
d8a3d2793f Trigger node not handling a duration of 0 as block mode
Fixes #1316
2017-07-03 15:20:37 +01:00
Dave Conway-Jones
360b0d9997 correct gpis pin 13 typo
to address #1314
2017-07-02 20:53:27 +01:00
Nick O'Leary
356f46aaf4 Bump 0.17.2 2017-07-02 11:15:09 +01:00
Dave Conway-Jones
87ac0507d9 and finally fix the gpio labels 2017-07-02 11:07:11 +01:00
Nick O'Leary
63657c18e2 Bump 0.17.1 2017-07-02 10:57:45 +01:00
Dave Conway-Jones
817f92a50e refix GPIO - more correctly - backwards compatible
existing installations now keep working
2017-07-02 09:59:37 +01:00
Dave Conway-Jones
304be96dd6 stop gpis node reporting bad status message on slow Pi 2017-07-02 00:50:55 +01:00
Dave Conway-Jones
9639081e7e re-sort package dev dips 2017-07-01 22:42:48 +01:00
Dave Conway-Jones
dca553048a Fix PI gpio to use BCM 2017-07-01 22:42:13 +01:00
Nick O'Leary
6201ed4d55 Prevent event thread contention when sending to Debug node
Closes #1311
2017-07-01 22:01:56 +01:00
Nguyen Thai Vinh
6db2c04585 Fix Bug: Can not display node icon when npm package has scope (#1305) (#1309) 2017-06-30 21:49:35 +01:00
Nick O'Leary
f3840512ba Clear moved flag when nodes are deployed 2017-06-30 21:48:38 +01:00
Nick O'Leary
9a6cf58565 Bump version for 0.17.0 2017-06-30 11:32:56 +01:00
Nick O'Leary
78076122ba Remove console.log 2017-06-30 10:39:28 +01:00
Nick O'Leary
7429f66d6b Mark nodes that have really moved as changed 2017-06-29 23:23:16 +01:00
Nick O'Leary
e59eff83b9 Ensure default switch node config matches what a no-op edit gives 2017-06-29 23:22:31 +01:00
Nick O'Leary
2083d85afa Update jsonata to latest 2017-06-29 15:55:55 +01:00
timolehto
4c9f1369c8 Set Proxy-Authorization when needed (#1146)
fixes #1145
2017-06-29 15:55:12 +01:00
Dave Conway-Jones
adca1d7855 File node - don't hose status web socket on multiple file writes
and add close behaviour to info
2017-06-29 11:40:50 +01:00
Kazuhito Yokoi
dfc4e99560 Add Chinese translation file (editor.json) (#1303) 2017-06-29 11:38:21 +01:00
Nick O'Leary
344076c943 Fix settings tests to remove nodeSettings reference 2017-06-29 11:36:16 +01:00
Nick O'Leary
710f1e2ca0 Be consistent in how node settings are addressed 2017-06-29 11:17:39 +01:00
Nick O'Leary
74ea85d19c Ensure existing grid settings are migrated to new keys 2017-06-28 22:16:11 +01:00
Dave Conway-Jones
dded98e30c tidied up implementation of file node close fix 2017-06-28 17:50:09 +01:00
Dave Conway-Jones
160c27c15a file node - close files when required 2017-06-28 17:36:04 +01:00
Nick O'Leary
a6a9025bab Typo in http node help 2017-06-28 17:15:42 +01:00
Chaya Stern
a780d4463c Support category with more than one word (#1301) 2017-06-28 14:27:54 +01:00
Nick O'Leary
23539ee907 Merge branch 'master' of github.com:node-red/node-red 2017-06-28 14:20:03 +01:00
Dave Conway-Jones
b515df611d fix file node to overwrite multiple files 2017-06-28 13:28:04 +01:00
Nick O'Leary
0d896fef0b Update Changelog for 0.17 2017-06-28 11:11:40 +01:00
Kazuhito Yokoi
283d5c64cb Update Japanese translation files (jsonata.json and messages.json) (#1300)
* Update Japanese translation file(jsonata.json)

* Update Japanese translation file(messages.json)
2017-06-28 09:26:07 +01:00
Kazuhito Yokoi
3134bc432b Improve editor messages (jsonata.json and messages.json) (#1299)
* Modify typo and improve messages in jsonata.json

* Change csv to CSV(messages.json)
2017-06-28 09:25:35 +01:00
Nick O'Leary
fd93fef73e Better template node help example 2017-06-27 21:53:12 +01:00
Dave Conway-Jones
8939a9c786 tiny bit of ; lint in switch node
#ocd
2017-06-27 17:16:18 +01:00
Nick O'Leary
52c0d360b2 Add buffer joiner mode to Join node 2017-06-27 17:11:11 +01:00
Dave Conway-Jones
d99432bff1 Use correct Buffer.from method rather than constructor
exec, tcp, ump and file nodes
2017-06-27 17:11:36 +01:00
Dave Conway-Jones
4dd2d3ac7d fix tcp node new Buffer alloc size 0 2017-06-27 16:58:17 +01:00
Nick O'Leary
aa7fe3668c HTTP Request node: add info on how to do form encoding 2017-06-27 14:58:13 +01:00
Nick O'Leary
83ebcf1dae Reset palette-manager tabs when settings dialog reopened 2017-06-27 14:17:26 +01:00
Nick O'Leary
c9317659c5 Prevent unmodified msg.headers from breaking HTTP Request flows
Closed #1015
2017-06-27 11:24:20 +01:00
Nick O'Leary
6562c558de Add help info for split node 2017-06-27 11:24:20 +01:00
Dave Conway-Jones
303f67c036 let node installer try to save with ~ version prefix to allow minor updates 2017-06-27 10:17:09 +01:00
Dave Conway-Jones
2482d122b8 Let join node auto re-assemble buffers
and add test
2017-06-26 23:10:08 +01:00
Nick O'Leary
1733c38b5c Update general dependencies 2017-06-26 15:03:32 +01:00
Nick O'Leary
7a1e4e9e99 Ensure all ace editors are destroyed in the expression editors 2017-06-26 14:23:48 +01:00
Nick O'Leary
e590313297 Expression editor - clear legacy flag for blank expressions 2017-06-26 14:12:20 +01:00
Nick O'Leary
b63d243e33 Update JSONata to 1.2.4
Closes #1275
2017-06-26 13:55:22 +01:00
Nick O'Leary
e9c1216d5c Handle logging out and already logged-out editor
Fixes #1288
2017-06-26 10:49:06 +01:00
Nick O'Leary
df9e50445e Merge branch 'master' into 0.17 2017-06-26 10:18:42 +01:00
Kazuhito Yokoi
61339face6 Add and improve Japanese translation file(editor.json, infotips.json and messages.json) (#1284)
* Update Japanese translation(editor.json)

* Add Japanese translation file(infotips.json)

* Add Japanese translation file(messages.json)
2017-06-26 10:08:05 +01:00
Chaya Stern
9cd751e977 Fix bug: Export Subflows (#1282)
* fix bug with export subflows

* fix bug with export config-nodes
2017-06-26 10:07:44 +01:00
Kazuhito Yokoi
7aa08ff885 Add Japanese translation file(jsonata.json) (#1271) 2017-06-26 09:41:16 +01:00
Dave Conway-Jones
a824caf712 update core nodes to use newer Buffer syntax 2017-06-24 13:53:45 +01:00
Dave Conway-Jones
395210e4f0 destroy editor to ensure fully removed on close (function, template, comment)
to close #1279
2017-06-24 12:15:03 +01:00
Dave Conway-Jones
e23354b2bb tidy up split node to remove todo comments 2017-06-24 12:09:52 +01:00
Dave Conway-Jones
bc472eb0b3 Bump ACE editor to v1.2.7 2017-06-23 22:08:03 +01:00
Dave Conway-Jones
256f8e7226 add allow es6 to .jshintrc 2017-06-23 21:49:35 +01:00
Dave Conway-Jones
f41959537b travis - don't allow node 8 fails, (and re-add 7) 2017-06-23 21:49:10 +01:00
Dave Conway-Jones
c9e05cf9f6 split node - in object mode allow msg.complete on its own 2017-06-23 21:48:13 +01:00
Dave Conway-Jones
82d9a02d92 Move udp sock error listener to only be instantiated once. 2017-06-23 16:20:28 +01:00
Dave Conway-Jones
dc9fa81346 let split of objects use key to set another property (e.g. topic)
and add tests
and update messages
2017-06-22 18:42:54 +01:00
Dave Conway-Jones
b91c178200 add "split/stream" ability to file in node
and add teste
2017-06-22 18:41:49 +01:00
Simon Asp
adebdf36a5 Bug fix in exec node. White spaces in arguments now works (#1285) 2017-06-18 11:55:39 +01:00
Dave Conway-Jones
4f34980c9f adding streaming modes into split node
and add tests
2017-06-16 22:26:14 +01:00
Dave Conway-Jones
e70766a535 fix split to pass tests... 2017-06-16 09:21:53 +01:00
Dave Conway-Jones
55110dfbac let split node reassemble based on a final packet. (as well as the first) 2017-06-16 09:16:23 +01:00
Dave Conway-Jones
56405ac903 let join also accumulate strings (and not fail) 2017-06-15 00:11:35 +01:00
Nick O'Leary
2b2136c468 Add typedInput binary mode icon 2017-06-14 22:29:38 +01:00
Dave Conway-Jones
f12031ee9e redo delay node status messages to be interval based 2017-06-14 22:25:44 +01:00
Nick O'Leary
c26852da77 Add buffer support to split node 2017-06-13 21:01:27 +01:00
Nick O'Leary
d9dc171c28 Add buffer mode to typedInput 2017-06-13 21:01:27 +01:00
Dave Conway-Jones
d407f31ae5 stop delay node spamming web socket (when in fast rate limit mode) 2017-06-09 19:42:12 +01:00
Nick O'Leary
f688b8d299 Refresh sidebar info when tab is changed 2017-06-06 10:27:03 +01:00
Dave Conway-Jones
d8e6a7b687 better spacing for library widget 2017-06-05 17:04:31 +01:00
Dave Conway-Jones
7c42b04eff updated split/join node (split still needs work before release) 2017-06-05 17:04:17 +01:00
Nick O'Leary
f527841c29 Fix gridSize for node width calculation to avoid odd resizing 2017-06-05 16:10:47 +01:00
Nick O'Leary
48a8dc0989 Redraw grid properly if gridSize changes 2017-06-05 16:07:21 +01:00
Nick O'Leary
7e35c9c754 Return flow rev on reload api when api v2 enabled
Closes #1273
2017-06-05 15:16:26 +01:00
Nick O'Leary
7502a2b1ff Update trigger help 2017-06-05 14:01:24 +01:00
Nick O'Leary
6c2de40dba Add cookie handling to HTTP Request node 2017-06-05 11:33:37 +01:00
Dave Conway-Jones
ef90f19eaa Make exec node explicitly call SIGTERM for default 2017-06-05 09:47:42 +01:00
Dave Conway-Jones
90ab34591a Add node 8 to travis (with allow failure) 2017-06-05 08:50:37 +01:00
Kazuhito Yokoi
21d3a3dd1e Modify typo in jsonata.json (#1270) 2017-05-31 08:44:44 +01:00
Nick O'Leary
b44e70115b Delay/Range node help tidy up 2017-05-26 14:27:53 +01:00
Nick O'Leary
ac31957707 Update delay node ui 2017-05-26 13:51:58 +01:00
Nick O'Leary
65e27a268d Scroll sidebar info tab to top when changing content 2017-05-24 21:41:18 +01:00
Nick O'Leary
6bd59b10c7 Ensure info tab sections are collapsible when set from palette 2017-05-24 21:11:23 +01:00
Nick O'Leary
6a6a692891 Only show tab info if there is an active tab 2017-05-24 20:58:16 +01:00
Nick O'Leary
479b18354d More core node info help tidy up 2017-05-24 16:55:53 +01:00
Nick O'Leary
9c6452544b Don't try to nls status text starting with '.'
Fixes #1258
2017-05-24 12:21:35 +01:00
Nick O'Leary
0a6ff900da Add guard against the http-request buffer fix being reverted 2017-05-24 11:18:52 +01:00
bartbutenaers
f54f863611 Revert "Multipart streaming"
This reverts commit bd671e75e6.
2017-05-24 11:08:08 +01:00
bartbutenaers
9cc04da7b2 Multipart streaming 2017-05-24 11:07:09 +01:00
bartbutenaers
d7f5b0c9d7 Always request buffer 2017-05-24 11:05:57 +01:00
bartbutenaers
9bd4598c6a Buffer fix 2017-05-24 11:04:33 +01:00
bartbutenaers
e3b052bc38 initial commit 2017-05-24 11:04:33 +01:00
Nick O'Leary
f215970649 Add http-request node unit tests 2017-05-24 10:36:47 +01:00
Nick O'Leary
dfe1cd4f90 Tidy up more core node help text 2017-05-23 17:26:23 +01:00
Nick O'Leary
3d2e6aea7b Remember test expression data on a per-node basis 2017-05-23 15:54:09 +01:00
Nick O'Leary
749b0d7019 Tidy up parser node edit dialogs and help text 2017-05-23 14:18:09 +01:00
Dave Conway-Jones
7978f85f7a Add Pretty print option to JSON node and
make XML and CSV nodes more consistent look and feel
2017-05-23 09:35:37 +01:00
Nick O'Leary
bd14acb68a Change debug message menu icon 2017-05-22 22:21:52 +01:00
Nick O'Leary
1e9ce550db Handle empty array/objects in debug view 2017-05-22 20:13:39 +01:00
Nick O'Leary
6278dfa77e Only check for reordered outputs if outputMap defiend 2017-05-22 13:45:56 +01:00
Nick O'Leary
2a3e355437 Add per-node filter option to Debug pane 2017-05-22 11:35:55 +01:00
Dave Conway-Jones
f6b0459d27 change pin selection table for pi gpis nodes 2017-05-20 02:36:03 +01:00
Dave Conway-Jones
790d6912fd re-add return to http request (removed in error) 2017-05-20 02:35:41 +01:00
Nick O'Leary
e69e5b4f50 Ensure node labels are reordered properly to match outputs 2017-05-19 22:56:29 +01:00
Nick O'Leary
483306e73c Avoid circular references when stingifying node objects 2017-05-19 20:36:22 +01:00
Dave Conway-Jones
1148a0b637 tcp request - remove confusing timeout wording from info 2017-05-15 22:05:33 +01:00
Dave Conway-Jones
524021f0fa http request node add transport validity check and warn. 2017-05-15 22:04:47 +01:00
Nick O'Leary
5b5f9aa01d Add 'none' placeholder for empty port label form 2017-05-15 16:26:42 +01:00
Nick O'Leary
f97f92c297 Strip BOM character from JSON files if present
Fixes #1239
2017-05-15 14:21:12 +01:00
Nick O'Leary
9d4139085b Handle HTTP In url that is missing its leading /
Fixes #1218
2017-05-15 14:10:06 +01:00
mw75
0ee7ffb5e5 Version check no meta (#1243)
* Version check on module loading - remove all metadata information bevor comparing the versions.

* refined regex
2017-05-15 13:57:35 +01:00
Nick O'Leary
8a7bb1be9f Log error when non-msg-object is returned from a Function 2017-05-15 13:54:05 +01:00
Nick O'Leary
d4135e80a6 Timeout a node that fails to close - default 15s timeout 2017-05-15 13:05:33 +01:00
Nick O'Leary
a5ade39d7c Fix selection of link nodes 2017-05-13 22:39:06 +01:00
Nick O'Leary
f39b4e7d22 Node status should be on by default 2017-05-12 22:47:59 +01:00
Nick O'Leary
080469cdf5 Ensure debug node marked changed when button pressed 2017-05-12 22:35:29 +01:00
Nick O'Leary
835ad29417 Fix pop-out debug window for all the recent updates 2017-05-12 22:22:47 +01:00
Nick O'Leary
c09bea4710 Add debug message menu 2017-05-12 22:12:55 +01:00
Nick O'Leary
879c0f4114 Don't mark a node changed when going from none to blank labels 2017-05-12 19:55:36 +01:00
Nick O'Leary
5feb07583b Don't include msg. in debug message copied paths 2017-05-12 10:19:50 +01:00
Nick O'Leary
5388002f54 Format Buffer numbers as hex by default 2017-05-11 21:15:16 +01:00
Nick O'Leary
c80fa9914b Merge branch '0.17' of github.com:node-red/node-red into 0.17 2017-05-11 21:00:40 +01:00
Dave Conway-Jones
b43d566968 Final TCP node nits - let 0 do it's thing as per every other timeout 2017-05-11 19:11:51 +01:00
Dave Conway-Jones
6b4e15dd0f fix tcp port not waiting as per info/previous behaviour
add separate return immediate mode rather than conflate ideas
2017-05-11 17:24:20 +01:00
Nick O'Leary
d9ef32d7e8 Remember formatting choices for dbg msg elements 2017-05-11 17:00:49 +01:00
Dave Conway-Jones
49389d6f06 Add new msg.delay option to delay node
and msg.reset to clear/fluch existing delays
2017-05-11 16:13:40 +01:00
Nick O'Leary
c75dc3cc36 Add test coverage for deleting a flow 2017-05-11 15:39:55 +01:00
btsimonh
c0eabf0438 Add note of removed flows in diffConfig (#1253) 2017-05-11 15:39:41 +01:00
Nick O'Leary
7730d0a4f8 Merge branch 'master' into 0.17 2017-05-11 15:10:12 +01:00
Nick O'Leary
e79da408a8 Allow debug msg elements to be pinned 2017-05-11 15:08:10 +01:00
Nick O'Leary
7381784d0f Only show debug tools under the debug tab 2017-05-10 16:56:03 +01:00
Nick O'Leary
085fb283e5 Fix test for valid js identifiers in debug path construction 2017-05-10 16:25:46 +01:00
Nick O'Leary
61e0e50e7b Remove unused modified flag on debug messages 2017-05-10 16:11:26 +01:00
Nick O'Leary
00460d856b Add copy path/value buttons to debug messages 2017-05-10 15:49:56 +01:00
Nathanaël Lécaudé
48958f392f TCP In: Fix error in timout callback (#1249)
Thanks @natcl
2017-05-09 22:09:21 +01:00
Dave Conway-Jones
a84efeb5d5 stop using sudo for Pi gpio access
(as PI user doesn’t need it) - other users must be in gpio group
2017-05-08 09:04:26 +01:00
Nick O'Leary
1c8c05ae04 Fix padding of config node edit dialog 2017-05-05 16:01:52 +01:00
Nick O'Leary
401d386812 Add force-deploy option when conflict detected 2017-05-05 15:52:37 +01:00
Nick O'Leary
6b07f58e8e NLS jsonata test messages 2017-05-05 13:43:39 +01:00
Dave Conway-Jones
6e8c978d12 Add sentence about clearing retained topic on mqtt
and use of administrator for ump on windows…
2017-05-05 12:31:18 +01:00
Nick O'Leary
5b2296b056 Add missing copyright header 2017-05-05 11:24:53 +01:00
Nick O'Leary
dbf0486acb Add JSONata expr tester and improved feedback 2017-05-05 11:23:24 +01:00
Nick O'Leary
b030e935ce Hide tip box on startup if disabled 2017-05-03 21:27:08 +01:00
Nick O'Leary
29bd43413a Add context.keys function to list top-level keys 2017-05-03 20:51:33 +01:00
Nick O'Leary
2249b9449c NLS Expression/JSON editor and fix their height calculation 2017-05-03 17:17:36 +01:00
Nick O'Leary
30920b1b78 Add $context/$flow/$global functions to jsonata 2017-05-03 15:48:30 +01:00
Nick O'Leary
8f92a3e875 Do not log node errors if handled by a Catch node 2017-05-03 13:42:38 +01:00
Nick O'Leary
ed1a55d9cd Provide feedback when enable/disable node fails 2017-05-03 13:29:35 +01:00
Nick O'Leary
93ef84f495 Move palette editor to settings panel 2017-05-03 11:38:16 +01:00
Nick O'Leary
ccfcbe8526 Move palette editor to userSettings dialog 2017-05-03 11:38:16 +01:00
Nick O'Leary
5938143002 Move view and keyboard into user settings dialog 2017-05-03 11:38:16 +01:00
Nick O'Leary
8135da71bd Add basic user settings panel 2017-05-03 11:38:16 +01:00
Dave Conway-Jones
a3c73a04c2 yet more core node info updates
sentiment, gpio, change and range
2017-04-26 21:52:33 +01:00
Dave Conway-Jones
7f90d31846 more core node info updates to newer style 2017-04-25 21:47:58 +01:00
Dave Conway-Jones
45fbd22e28 Update some core nodes info 2017-04-24 20:37:06 +01:00
Nick O'Leary
4689d56955 Allow a node to decide for itself if its button should be enabled or not
This means:

  1. an Inject node that has only been moved can still inject
  2. the Debug node is now marked as changed when its button is clicked
     which, without this fix, then prevented the button from being
     clicked to toggle its state again
2017-04-23 23:20:50 +01:00
Nick O'Leary
aa1b2808e7 Track node moves separately to node config changes 2017-04-23 23:20:36 +01:00
Cor Bosman
40ad4bdbd8 dont match only part of the node type (#1242) 2017-04-22 22:08:09 +01:00
Nick O'Leary
b6510d66e0 Update debug node to register the settings it uses 2017-04-22 09:03:52 +01:00
Nick O'Leary
4ea33ea482 Pass a 'removed' parameter to node close handler 2017-04-21 23:36:21 +01:00
Nick O'Leary
e13d410b4a Update tests for oauth -> strategy rename 2017-04-21 22:06:12 +01:00
Nick O'Leary
72da7e6c54 Rename oauth auth scheme to strategy as it works for openid 2017-04-21 21:54:48 +01:00
Nick O'Leary
fb05960d79 Allow oauth schemes provide a custom verify function 2017-04-21 21:17:18 +01:00
Nick O'Leary
7bd0943412 Provide single endpoint to load all node message catalogs
Replaces potentially dozens of http requests with one or two.
2017-04-21 11:49:35 +01:00
Nick O'Leary
bb2649d063 Ensure ace editor instances are freed if edit cancelled 2017-04-21 09:05:03 +01:00
Nick O'Leary
d743bdbf5a Clip overly long notification messages 2017-04-21 09:05:03 +01:00
Nick O'Leary
61890f19bc Use queryCommandSupported not queryCommandEnabled to check for copy support 2017-04-21 09:05:03 +01:00
Dave Conway-Jones
b756a8edef Make tcp send msg more consistent
to close #1236
2017-04-20 12:22:36 +01:00
Kazuki-Nakanishi
adcb2f1aa8 Fix exec node error tests on Windows (#1234) 2017-04-19 22:09:53 +01:00
Nathanaël Lécaudé
e574f4516f Update 31-tcpin.js (#1235)
TCP-IN: Add check to see if object exists, fixes issue #1222
2017-04-18 16:03:16 +01:00
Dave Conway-Jones
2ac9c11ec9 Add tip to tab description editor
(and remove icons)
2017-04-16 21:08:32 +01:00
Dave Conway-Jones
1c470ab9e3 Make tab info edit box resizable 2017-04-16 20:25:15 +01:00
Dave Conway-Jones
08b8a8e3af update messages for updated exec node 2017-04-16 20:24:38 +01:00
Dave Conway-Jones
11ee1a7dcb fix exec node error test 2017-04-13 11:48:33 +01:00
Dave Conway-Jones
a281b8c74e Make exec node spawn and exec outputs more consistent
(with an option to revert if necessary)
and new info docs
2017-04-13 11:36:54 +01:00
Nick O'Leary
5cb37148c6 Add editorTheme.logout.redirect to allow redirect on logout
Closes #1213
2017-04-12 21:41:16 +01:00
Kazuki-Nakanishi
05878d3176 Fix the test cases which sometimes fails due to timing. (#1228) 2017-04-12 20:54:31 +01:00
Nick O'Leary
d1c42262d6 Ensure all nodes have access to global context
Fixes #1230
2017-04-12 20:48:43 +01:00
Nick O'Leary
c54cf26848 Add support for oauth adminAuth configs 2017-04-12 10:09:03 +01:00
Nick O'Leary
bfb548636e Merge branch 'master' into 0.17 2017-04-11 14:53:44 +01:00
Nick O'Leary
36e1b2ba08 Don't process subscription for unauthenticated comms link
Fixes #851
2017-04-11 14:48:19 +01:00
Nick O'Leary
301ac279ff Handle IncomingMessage/ServerResponse object types in debug
Fixes #1202
2017-04-10 21:59:59 +01:00
Nick O'Leary
08d21ccba7 Clone credentials when passing to node
Fixes #1198
2017-04-10 21:45:04 +01:00
Nick O'Leary
62876ca377 Toggling debug node enabled/disabled state should set state dirty
Fixes #1203
2017-04-10 16:11:01 +01:00
Kazuki-Nakanishi
10f94148af Exec node for windows environment (#1200)
* Modify exec node to run on Windows.

* Remove unnecessary modification.
2017-04-10 16:06:19 +01:00
Nick O'Leary
31502c2ebc remove allow_failures flag from node 7.x 2017-04-10 15:51:24 +01:00
David
62b29ecb65 Make theme able to load custom javascript (#1211)
* Make theme able to load custom javascript
- Look for the field 'customScript' in editorTheme (settings.js)
- Add it to mustach context
- Load list on template side (index.mst)

* Add unit tests for customScripts

* Code review edits : generic behavior for theme.page.[css|scripts]
- Use the same way to share css and javascript files from a theme
- Allow string instead of array for theme.page.scripts
- Remove old customScript field
2017-04-10 15:46:44 +01:00
Nick O'Leary
67337e013a Merge branch 'master' into 0.17 2017-04-10 15:45:21 +01:00
Andrey Bezugliy
f987fa13ea Resolve dir argument of getLocalNodeFiles function (#1216)
* Resolve dir argument of getLocalNodeFiles function

The getLocalNodeFiles is called 3 times.  Each time it called, the callee needs to resolve the dir argument.
That was not done for several of calls, and local modules (specified in the "nodesDir" setting) were not returned to client because of that.

This fix will allow to make sure the dir is consistently resolved.

* Several changes in "localfilesystem_spec.js":
- Changed checkNodes to verify that every node's file property is resolved, i.e. containst absolute path, not relative.
- Added a unit-test "Finds nodes in settings.nodesDir (string,relative path)"
2017-04-10 15:41:20 +01:00
Nick O'Leary
73dfe631ce Add .trace and .debug to Node prototype 2017-04-10 15:32:40 +01:00
Nick O'Leary
83ca8147ca Merge branch 'pr_1197' into 0.17 2017-04-10 15:25:19 +01:00
Nick O'Leary
1c11e7f97b Shrink config node appearance in info table 2017-04-10 14:33:21 +01:00
Nick O'Leary
aefae79186 Display config nodes in Info sidebar table 2017-04-10 11:29:52 +01:00
Nick O'Leary
4b05a9bb6f Ensure flow info box updates after editing flow 2017-04-10 00:00:10 +01:00
Nick O'Leary
2453719a87 Make H3 sections in node help collapsible 2017-04-07 13:30:12 +01:00
Nick O'Leary
ea929b00e3 Hide Node info section when displaying changelog 2017-04-07 12:36:06 +01:00
Nick O'Leary
ede940a398 Allow tips to be hidden and cycled through 2017-04-07 12:24:39 +01:00
Nick O'Leary
67da853146 Add info tips back to the sidebar 2017-04-07 11:21:30 +01:00
Nick O'Leary
624befd704 Restructure info tab 2017-04-06 23:17:30 +01:00
Dave Conway-Jones
203539841d allow shadowing in .jshintrc (mainly to test signing commits) 2017-04-06 11:12:11 +01:00
Nick O'Leary
262db23f7d First pass of new node-info style 2017-04-05 16:19:23 +01:00
Dave Conway-Jones
28ea22f0e1 MQTT new style info 2017-03-29 21:45:28 +01:00
Dave Conway-Jones
3f349c3531 remove requirement for cmd in exec node config + new style info 2017-03-29 21:44:58 +01:00
Dave Conway-Jones
9928e8562a let inject "between time" also fire at start - Plus new info 2017-03-24 14:01:26 +00:00
Dave Conway-Jones
b1e3fc5761 remove repeat symbol from inject if repeat is 0 2017-03-23 22:04:53 +00:00
Nam Giang
b2390f1caf adding frequency configuration to pwm output (#1206) 2017-03-23 21:02:22 +00:00
Nick O'Leary
b9379f2ddf Provide notification when new flows deployed in the background 2017-03-17 21:29:03 +00:00
Kazuki-Nakanishi
38a950a6dc Add description to flow same as subflow 2017-03-17 01:29:19 +09:00
Nick O'Leary
fb24dca019 Add JSON Expression editor 2017-03-12 23:52:31 +00:00
Nick O'Leary
07d131c945 Update jsonata 2017-03-12 22:04:38 +00:00
Dave Conway-Jones
0c1c710afe make sure MQTT client closes if redeploy during reconnect
to close #1193
Thanks @tedhuang for the excellent problem determination
2017-03-12 22:04:38 +00:00
Nick O'Leary
15cd93c30f Update follow_redirects to fix http_proxy handling
Fixes #1172
2017-03-12 22:04:38 +00:00
Ben Hardill
a5d9e17a8c Allow nodes to have translations not in core (#1183)
* Allow nodes to have translations not in core

Currently only languages in the core are checked when
the editor requests a translation. This means that if
a node includes more translations they are not checked.

This change removes the check against that short list,
but it only checks the first language from the browser
suported list

* remove whitespace
2017-03-12 22:04:37 +00:00
Kazuhito Yokoi
a82926dd0d Modify Japanese translation file for editor 2017-03-12 22:04:37 +00:00
Kazuki Nakanishi
12435b997a Added a name icon and a description label on edit subflow window. 2017-03-12 22:04:37 +00:00
Nick O'Leary
5945be95cf Treat missing msg properties as undefined rather than throw error
Fixes #1167
2017-03-12 22:04:37 +00:00
Nick O'Leary
5c2e7ce407 Update jsonata 2017-03-12 22:03:14 +00:00
Dave Conway-Jones
834e894b1d make sure MQTT client closes if redeploy during reconnect
to close #1193
Thanks @tedhuang for the excellent problem determination
2017-03-10 20:12:52 +00:00
Dave Conway-Jones
d25dac69d2 ask istanbul for more reports as default
and create a simple “grunt coverage” task synonym.
2017-03-10 20:04:14 +00:00
Kazuki-Nakanishi
3cc4173399 Extend timeout for the test case of installing non-existant path. (#1191)
to fix timeout on slower hosts
2017-03-10 13:59:44 +00:00
Nick O'Leary
36ab16c1ed Update follow_redirects to fix http_proxy handling
Fixes #1172
2017-03-09 22:49:22 +00:00
Nick O'Leary
5356373681 Finalise nodeSettings and update tlsConfigDisableLocalFiles
- increase test coverage around registerType
2017-03-09 21:06:49 +00:00
Nick O'Leary
f45a2643f2 Change default value of tlsConfigDisableLocalFiles to false 2017-03-09 20:01:44 +00:00
Nick O'Leary
e55933706d Merge branch 'nodeSettings' into 0.17 2017-03-09 20:00:54 +00:00
Kazuki-Nakanishi
3b3d696e45 Add the node setting tlsConfigDisableLocalFiles for tls node. (#1190)
* Add the node setting tlsConfigDisableLocalFiles for tls node.

* Fix the bug that shows node setting when specified in settings.js and exportable is false.
2017-03-09 19:58:34 +00:00
Kazuki-Nakanishi
281351e6b3 Add istanbul to Gruntfile.js (#1189) 2017-03-09 15:28:12 +00:00
Kazuki-Nakanishi
34089aec70 Allow a node to declare what settings should be made available to the editor. (#1185)
* Implement register/exportNodeSettings.

* Change normaliseRegisterTypeName to normaliseNodeTypeName. Force it to name in a camel case.
2017-03-08 14:38:33 +00:00
Kazuki-Nakanishi
3658d0e039 Add wait for writing a library entry into a file. (#1186) 2017-03-08 10:00:40 +00:00
kazuhitoyokoi
7a10636128 Add node whitelist function (#1184) 2017-03-08 10:00:00 +00:00
Ben Hardill
604ba7f4bc Allow nodes to have translations not in core (#1183)
* Allow nodes to have translations not in core

Currently only languages in the core are checked when
the editor requests a translation. This means that if
a node includes more translations they are not checked.

This change removes the check against that short list,
but it only checks the first language from the browser
suported list

* remove whitespace
2017-03-08 09:58:39 +00:00
Dave Conway-Jones
27b7fb54e8 nail trigger test for windows AND linux 2017-03-06 19:06:10 +00:00
Dave Conway-Jones
d351aa842c add port label to file node and update info 2017-03-06 19:05:52 +00:00
Dave Conway-Jones
59da705b8f really close tcp node connection right away (if told to)
rather than wait then close
2017-03-06 19:05:16 +00:00
Dave Conway-Jones
99b8f16d88 give up on SIGQUIT for widows test
revert to SIGINT
2017-03-06 17:42:59 +00:00
Dave Conway-Jones
06ffe722d4 better tests for windows nodes 2017-03-06 17:40:09 +00:00
Dave Conway-Jones
6264104642 comment out 2nd exec node kill tests
(to be revisited)
2017-03-06 16:49:51 +00:00
Dave Conway-Jones
c97812c340 retry exec node tests
(diff behaviour on host)
2017-03-06 16:25:38 +00:00
Nick O'Leary
bd4c578230 NLS messages for Flow enabled/disable 2017-03-06 15:55:38 +00:00
Nick O'Leary
6ec2949b6f Don't display port labels for subflow pseudo-port nodes 2017-03-06 15:41:19 +00:00
Nick O'Leary
1ff23ebfd9 Stop some ui elements from clearing url anchor when clicked 2017-03-06 15:30:42 +00:00
Nick O'Leary
7698990e37 Allows flows to be enabled/disabled in the runtime 2017-03-06 15:29:05 +00:00
Nick O'Leary
17e092afb3 Allow tabs to be enabled/disabled in the editor 2017-03-06 15:29:05 +00:00
Dave Conway-Jones
2db65b9d1f fixes for grunt files tests on Windows 2017-03-06 15:28:23 +00:00
Dave Conway-Jones
c6436f47eb let exec node take msg.kill SIG... param and pid param
and redo test
2017-03-06 15:27:29 +00:00
Nick O'Leary
e88b4a4412 Merge pull request #1181 from kazuhitoyokoi/master
Modify Japanese translation file for editor
2017-03-06 11:22:33 +00:00
Kazuhito Yokoi
01a177adfb Modify Japanese translation file for editor 2017-03-06 11:18:23 +00:00
Nick O'Leary
052b5e0ea8 Merge pull request #1174 from Kazuki-Nakanishi/master
Added a name icon and a description label on edit subflow window.
2017-03-03 16:19:18 +00:00
Kazuki Nakanishi
68cd447109 Added a name icon and a description label on edit subflow window. 2017-03-03 14:10:20 +00:00
Dave Conway-Jones
4a8a5ed8d4 Add port labels to inject node (to show types) 2017-03-03 10:21:07 +00:00
Dave Conway-Jones
84077505b0 add off option to logging settings comment 2017-03-02 23:12:40 +00:00
Dave Conway-Jones
c4554b71d3 Add link label value as portLabels 2017-03-02 23:12:06 +00:00
Nick O'Leary
63ce743571 Treat missing msg properties as undefined rather than throw error
Fixes #1167
2017-03-02 14:02:26 +00:00
Nick O'Leary
6cf53c611b merge exec fixes 2017-03-02 13:41:01 +00:00
Nick O'Leary
d8720ee325 Third output from Exec node must be consistent for success/failure conditions 2017-03-02 13:34:01 +00:00
Nick O'Leary
73501f3ad3 Resync with master 2017-03-01 17:45:09 +00:00
Nick O'Leary
54ee655472 Log error stack traces if verbose flag is set 2017-03-01 17:00:27 +00:00
Nick O'Leary
571b9fb8e0 Merge pull request #1122 from CANDY-LINE/feature/i18n-issue
Fix empty extra node help content issue
2017-03-01 16:38:08 +00:00
Nick O'Leary
cdd6b243ff Merge pull request #1171 from SenseTecnic/tls-certkey-upload
UI to upload certificates and keys for TLS
2017-03-01 16:34:05 +00:00
Nick O'Leary
fca77a868f Allow a node to declare settings that should be exported 2017-03-01 15:01:07 +00:00
Dave Conway-Jones
424e854778 clipboard export text stay highlighted even when button deselected
i.e. if you hit button twice text stays selected.
2017-02-28 22:54:13 +00:00
mblackstock
0979d565bb changes as suggested by @knolleary 2017-02-28 14:03:35 -08:00
Dave Conway-Jones
f5e6ca3e10 ensure export clipboard keeps text selected and formatted 2017-02-28 21:50:09 +00:00
mblackstock
2bde07561f UI to upload certificates and keys for TLS, and send them to node red in configuration properties to store them in credentials file
by default upload buttons will be shown unless a cert or key path is already set
added new settings flag called 'tlsDisableLocalFiles' to disable UI for local paths for cloud hosted NR
2017-02-28 12:21:34 -08:00
Nick O'Leary
16c92cc739 Merge pull request #1156 from LinusU/patch-1
Use pre-calculated values for connection path
2017-02-28 10:10:12 +00:00
Dave Conway-Jones
8b31a918a4 Fix Pi GPIO debounce
To close #1139
2017-02-27 19:22:02 +00:00
cinhcet
ee0bd49918 exec node returns 0 on the third output if command ended without error. (#1160)
* exec node returns 0 on the third output if command ended without error.
Otherwise, the status of the node is updated and the error code is send through the third output.

* info text updated and the second output returns only something if stderr is not empty

* proper stderror handling

* proper handling of stderr
2017-02-22 22:22:06 +00:00
Dave Conway-Jones
a625eeeac8 move csv fixes to master
to fix #1142 in master
2017-02-22 20:19:44 +00:00
Dave Conway-Jones
bfcd795687 Fix wrong number of double quotes in CSV parsing
to close #1162
2017-02-20 22:44:37 +00:00
Nick O'Leary
e2a9be9cec Defer resizing tray components until they have finished building 2017-02-16 21:41:20 +00:00
Linus Unnebäck
37dd075309 Use pre-calculated values for connection path 2017-02-16 18:05:59 +01:00
Nick O'Leary
89769fb0e5 Merge pull request #1155 from LinusU/patch-1
Use textContent to avoid manual escaping
2017-02-16 15:37:21 +00:00
Linus Unnebäck
b24fac3dd8 Use textContent to avoid manual escaping 2017-02-16 16:28:00 +01:00
Nick O'Leary
4794fe495c Add events to test helper 2017-02-15 23:15:24 +00:00
Nick O'Leary
869fdbcc6a Remove event passing for icons/examples from the api layer 2017-02-15 23:07:50 +00:00
Dave Conway-Jones
702e6d3b51 slight filed size adjust for mqtt broker port field - allow 5 digits 2017-02-14 20:59:52 +00:00
Nick O'Leary
2913e13a30 Misconfigured WebSocket nodes should not register msg handlers 2017-02-13 21:39:31 +00:00
Nick O'Leary
5f1e37b7fa Leave a node to nls its own port labels 2017-02-10 22:10:53 +00:00
Nick O'Leary
ec0209b175 Allow a node to override default labels 2017-02-09 23:24:16 +00:00
Nick O'Leary
a17dcbde0f Remove console log from Switch node 2017-02-08 20:43:26 +00:00
Nick O'Leary
fbd159a23a Add placeholder text on label inputs and clear buttons 2017-02-08 10:48:26 +00:00
Nick O'Leary
599a6bf050 Add port labels to Subflow nodes 2017-02-08 10:48:25 +00:00
Nick O'Leary
185b16a858 Keep port label form in sync with output reordering 2017-02-08 10:48:25 +00:00
Nick O'Leary
e7e3ed4923 Basic node label editor 2017-02-08 10:48:25 +00:00
Nick O'Leary
47df5476ba Add RED.stack as a common ui component 2017-02-08 10:48:25 +00:00
Nick O'Leary
d7c516ab00 Port label editor starting point 2017-02-08 10:48:24 +00:00
Dave Conway-Jones
50838970ec let css node handle ip addresses without trying to parse
and only warn once if no template (and then send object anyway)
to close #1142
2017-02-07 21:14:16 +00:00
Dave Conway-Jones
1d15ee7034 let Hypriot on Pi detect gpio correctly
clean up duplicate labels
2017-02-07 21:14:16 +00:00
Dave Conway-Jones
7029541b4f Let watch node recurse into subdirectories
to close #1140
2017-02-07 21:14:16 +00:00
Dave Conway-Jones
ada8e447cc exec node can be killed on demand 2017-02-07 21:14:16 +00:00
Dave Conway-Jones
1841fc18fa let trigger node set repeated outputs 2017-02-07 21:14:16 +00:00
Dave Conway-Jones
94ee465682 clone message before send in stay connected mode
to Fix #1137
2017-02-02 09:57:04 +00:00
Nick O'Leary
3e021b3a75 Fix loader test to expect line numbers in load errors 2017-01-30 09:58:43 +00:00
Nick O'Leary
0643f149b7 Extract line number if available from node load errors 2017-01-30 09:37:08 +00:00
Nick O'Leary
939768eec0 Cache auth details to save needlessly recalculating hashes 2017-01-28 14:44:47 +00:00
Nick O'Leary
f2235dacdc Shuffle promises for creating default package.json 2017-01-28 14:21:22 +00:00
Nick O'Leary
50017c28da Allow port labels be i18n identifiers 2017-01-27 22:36:00 +00:00
Nick O'Leary
85b2a03a42 Create a package.json file in userDir if one doesn't exist 2017-01-27 22:35:17 +00:00
Nick O'Leary
829087550d Add inputLabels and outputLabels to node defn + Update Change node 2017-01-27 18:11:25 +00:00
Nick O'Leary
dd6f71fe85 Resize port labels based on content 2017-01-27 16:33:11 +00:00
Nick O'Leary
92a928680c Initial port label behaviour 2017-01-26 15:38:25 +00:00
Nick O'Leary
d008b1970c Add option to parse Template result as JSON before sending 2017-01-25 17:12:53 +00:00
Nick O'Leary
4affbb8c6b Numeric validator that accepts blank should accept undefined 2017-01-25 16:11:56 +00:00
Nick O'Leary
ddb2ea4b5f autoInstallModules option must honour version/pending_version 2017-01-25 11:07:02 +00:00
Nick O'Leary
a69683183f Refuse to update a non-local node module 2017-01-24 22:50:40 +00:00
Nick O'Leary
8d34f87667 Add websocketVerifyClient option to enable custom websocket auth
Fixes #1127
2017-01-24 21:37:08 +00:00
Nick O'Leary
128c4fe222 Add visual cue as to whether the workspace is focused 2017-01-24 16:14:03 +00:00
Nick O'Leary
b10141d71f Allow statusCode/headers to be set directly within HTTP Response node 2017-01-24 14:56:48 +00:00
Nick O'Leary
68e0b35364 Allow RED.validators.number to allow blank values as valid 2017-01-24 14:28:15 +00:00
Nick O'Leary
1324f5e59c Update CHANGELOG for 0.16.2 2017-01-23 15:57:37 +00:00
Nick O'Leary
7759aacb35 Ensure custom mustache context parent set in Template node
fixes #1126
2017-01-23 15:34:34 +00:00
Nick O'Leary
fd6f7cd881 Display debug node name in debug panel if its known 2017-01-23 13:57:06 +00:00
Nick O'Leary
3fdeb38bb7 Ensure auth-tokens are removed when no user is specified in settings 2017-01-21 23:49:20 +00:00
Nick O'Leary
e27f5d0460 Add node module update api and expose in palette editor 2017-01-21 23:46:44 +00:00
Nick O'Leary
0720128bd4 Support dropping json files into the editor 2017-01-19 15:34:14 +00:00
Nick O'Leary
540472a093 Ensure all a tags have blank target in info sidebar 2017-01-19 13:52:38 +00:00
Nick O'Leary
daca78b6cd Ensure links do not span tabs in the editor 2017-01-19 13:24:54 +00:00
Dave Conway-Jones
4195840b2c make links in added info open in blank page rather than current window 2017-01-19 11:00:22 +00:00
Daisuke Baba
57c529758e Add an edge case test 2017-01-19 17:19:41 +09:00
Daisuke Baba
5ba9a0eb3f Fix empty extra node help content issue 2017-01-19 16:55:57 +09:00
Nick O'Leary
b8888a5d46 Add RED.utils.getNodeLabel utility function 2017-01-18 15:52:09 +00:00
Nick O'Leary
0857f979ff Update ui_spec for icon module path 2017-01-18 13:14:12 +00:00
Nick O'Leary
11f4ae019c Include module name in requests for node icons 2017-01-18 13:06:22 +00:00
Nick O'Leary
0ffeb0c5af Avoid creating multiple reconnect timers in websocket node 2017-01-17 20:48:05 +00:00
Nick O'Leary
d6f6b41145 Fix inner reference in install fail message catalog entry
Fixes #1120
2017-01-17 09:54:17 +00:00
Nick O'Leary
64daaeb310 Add file upload support to HTTP In node 2017-01-16 22:39:30 +00:00
Nick O'Leary
0646b0060e Display buffer data properly for truncated buffers under Object property 2017-01-16 17:43:39 +00:00
Nick O'Leary
c794ca85fd Update changelog for 0.16.1 2017-01-16 10:30:36 +00:00
Nick O'Leary
5b4019dd3d Add colour swatches to debug when hex colour matched 2017-01-16 10:29:00 +00:00
Nick O'Leary
a03ccd7b59 Nodes with hasUsers set to false should not appear unused 2017-01-15 13:37:21 +00:00
Nick O'Leary
4b64aad5ce Change hard error to verbose warning if using old node.js level 2017-01-14 23:57:39 +00:00
Nick O'Leary
d146ff8794 Update debug_spec test for Error messages 2017-01-14 21:47:18 +00:00
Nick O'Leary
5349bf7628 Don't filter debug properties starting with _
Fixes #1117
2017-01-14 21:34:09 +00:00
Nick O'Leary
a79e4d1bb3 Node logged errors not displayed properly in debug pane
Fixes #1116
2017-01-14 21:33:11 +00:00
Nick O'Leary
f462435dc2 Do not look for existing nodes when checking for wires on paste
Fixes #1114
2017-01-13 14:16:12 +00:00
Nick O'Leary
48ad614441 -v option not enabling verbose mode properly 2017-01-13 00:01:19 +00:00
Nick O'Leary
f699516fdb Add node.js version check on startup 2017-01-12 10:40:04 +00:00
Nick O'Leary
ca5cbb640a Bump version 0.16 2017-01-11 20:44:53 +00:00
Nick O'Leary
0a96259ddf Update copyright header for JS Foundation 2017-01-11 15:24:33 +00:00
Nick O'Leary
d99b9c04e4 Update changelog 2017-01-11 14:34:59 +00:00
Nick O'Leary
64d261e053 Add deploy action 2017-01-11 14:33:40 +00:00
Nick O'Leary
eb027d98aa Add column headings to keymap table 2017-01-11 14:15:29 +00:00
Nick O'Leary
a95727b654 Scope input/export actions to be global 2017-01-11 14:15:14 +00:00
Nick O'Leary
4e636d7eec Fix arg passing lint error 2017-01-11 12:18:52 +00:00
Nick O'Leary
3cd53f617a Include unassigned keys to shortcut dialog 2017-01-11 11:41:25 +00:00
Nick O'Leary
b1684e82d8 Dynamically generate keyboard shortcut help dialog 2017-01-11 11:35:48 +00:00
Dave Conway-Jones
a55027b838 let copy of settings file occur on a clean install. 2017-01-11 10:12:29 +00:00
Nick O'Leary
28678acf74 Add debug logging around flow revision ids 2017-01-10 14:20:51 +00:00
Nick O'Leary
ce6594c8cc Do not tie debug src loading to needsPermission
Fixes #1111
2017-01-10 09:43:46 +00:00
Nick O'Leary
75855d5450 Initialise nodeApp regardless of httpAdmin setting
Closes #1096 #1095
2017-01-09 22:22:49 +00:00
Nick O'Leary
f248699a30 Display info tips slightly longer 2017-01-09 22:09:06 +00:00
Nick O'Leary
29594726ca Speed up reveal of search dialogs 2017-01-09 22:08:54 +00:00
Nick O'Leary
0a41b07297 Reorder Debug/Inject nodes in quick-add dialog 2017-01-09 16:41:16 +00:00
Nick O'Leary
e45cb7fac1 Ensure flows exist before delegating status/error events
Fixes #1069
2017-01-09 16:39:41 +00:00
Nick O'Leary
489dbfc72a Update package dependencies 2017-01-09 15:01:33 +00:00
Nick O'Leary
a89ae7d77a Update MQTT to latest 2.2.1 2017-01-09 14:35:45 +00:00
Nick O'Leary
a1eeff4034 Node status not being refreshed properly in the editor 2017-01-09 14:18:59 +00:00
Nick O'Leary
0e1013a570 Add install/remove dialog to increase friction
Closes #1109
2017-01-09 13:41:20 +00:00
Nick O'Leary
4562b06a60 Try to prevent auto-fill of password fields in node edit tray
Fixes #1081
2017-01-08 23:14:14 +00:00
zuhito
3c96218338 Add Japanese translation file(editor.json) (#1084) 2017-01-08 23:02:07 +00:00
Nick O'Leary
f0a4ea099c Fix whitespace in localfilesystem 2017-01-08 23:01:28 +00:00
btsimonh
c8d6693fba fix bug where savesettings did not honor local settings variables (#1073)
* fix bug where savesettings did not honor local settings variables

* don't create lib/flows on read;  It's already created in localfilesystem.init and in saveLibraryEntry -
so removed call to promiseDir, and added a return of [] if accessing a folder which did not exist.
This is important because else when settings.readOnly is true, it still creates folders.

* Fix a CI failure where path passed to getLibraryEntry is empty;
treat this case as meaning it was wanting a folder, and return empty if the folder dioes not exist

* Add a test for getLibraryEntry( type, '/' ) as called by node-red

* change newsettings to camelCase newSettings
2017-01-08 23:00:27 +00:00
Nick O'Leary
81bbdfe413 Tidy up unused/duplicate editor messages
Closes #922
2017-01-08 22:54:46 +00:00
Nick O'Leary
0e362943bf Add option to colourise debug console output
Closes #1103
2017-01-08 22:38:40 +00:00
Nick O'Leary
1e37fed90b Report node catalogue load errors
Closes #1009
2017-01-08 20:51:31 +00:00
Nick O'Leary
aafcfef387 Add property validation to nodes using typedInput 2017-01-06 23:18:50 +00:00
Nick O'Leary
4b83d8160f Add common validator for typedInput fields
Closes #1104
2017-01-06 22:20:09 +00:00
Nick O'Leary
73a41707e5 Property expressions must not be blank 2017-01-06 21:58:17 +00:00
Nick O'Leary
c989c533e8 Properly report module remove errors in palette editor
Fixes #1043
2017-01-06 16:53:54 +00:00
Nick O'Leary
707dc8c65c Update debug node console logging indicator icon
Closes #1094
2017-01-06 14:43:51 +00:00
Nick O'Leary
4c6157a06e Tidy up merge commit of validatePropertyExpression 2017-01-06 14:32:37 +00:00
Nick O'Leary
f973396821 Merge pull request #1102 from node-red/0.16
0.16
2017-01-06 14:30:52 +00:00
Nick O'Leary
e73216d4c1 Merge branch 'master' into 0.16 2017-01-06 14:30:13 +00:00
Dave Conway-Jones
e6de26736b add port if wires array > number of ports declared. 2017-01-06 14:06:30 +00:00
Nick O'Leary
d131addd63 Allow tips to be enabled/disabled via menu option 2017-01-06 13:33:23 +00:00
Nick O'Leary
0c7705beff Allow quoted property expressions
Fixes #1101
2017-01-06 11:23:53 +00:00
Dave Conway-Jones
08b11addec Let exec node (spawn) handle commands with spaces in path 2017-01-06 09:55:52 +00:00
Nick O'Leary
555f96cfaf Info-tips update 2017-01-05 23:33:19 +00:00
Nick O'Leary
59ffacb3df Fix merge conflicts 2017-01-05 10:07:23 +00:00
Nick O'Leary
83acb66f00 NLS the diff dialog 2017-01-04 22:02:35 +00:00
Nick O'Leary
1f9ae45875 Fix diff node table layout for Safari 2017-01-04 20:57:10 +00:00
Nick O'Leary
ffa628be2d Index all node properties for node search 2017-01-04 16:46:36 +00:00
Nick O'Leary
8916f6f829 Update CHANGELOG/version for 0.15.3 2017-01-04 15:11:53 +00:00
Nick O'Leary
215c8fd261 NLS type search 2017-01-01 22:14:33 +00:00
Nick O'Leary
061cc908a7 Hide common entries when filtering typeSearch 2017-01-01 21:59:09 +00:00
Nick O'Leary
18a519f9ed Remove node 0.10 from travis config 2017-01-01 11:41:03 +00:00
Nick O'Leary
7970c9dbe5 Merge changes by reimporting changed node config 2017-01-01 00:20:12 +00:00
Nick O'Leary
5ca0c066e2 Better handling of moved nodes 2017-01-01 00:20:12 +00:00
Nick O'Leary
563728c7b8 Some more merging code 2017-01-01 00:20:12 +00:00
Nick O'Leary
31a72b6562 Three-way-diff 2017-01-01 00:20:12 +00:00
Nick O'Leary
d3dfbc3034 Add proper three-way diff view 2017-01-01 00:20:11 +00:00
Josh
f143a6ba08 update welcome message to use logger so it can be turned off/on if required (#1083) 2016-12-23 11:31:23 +00:00
Dave Conway-Jones
28a65923b6 bump various package versions
(not touching mqtt and other major version)
2016-12-22 13:36:06 +00:00
Dave Conway-Jones
4ca3df77b3 Add ⇶ to debug node to indicate debugging also to console.log 2016-12-22 13:27:27 +00:00
Dave Conway-Jones
4cbe264869 Change file node to use node 4 syntax (drops support for 0.8) 2016-12-22 13:17:08 +00:00
Nick O'Leary
b6b65b6bf7 Update debug node test for circular references 2016-12-20 23:21:25 +00:00
Nick O'Leary
e7cc42a927 Use json-stringify-safe to detect circular references in debug msgs 2016-12-20 23:16:11 +00:00
Nick O'Leary
bba3ca8cc0 Avoid misinterpreting valid objects as encoded arrays in debug 2016-12-20 22:46:56 +00:00
Dave Conway-Jones
8423e2d245 add info for httprequest responseUrl property 2016-12-16 22:03:00 +00:00
Dave Conway-Jones
fc263718a1 Add res.responseUrl to httprequest node response 2016-12-16 21:54:24 +00:00
Nick O'Leary
c3a99cf5a4 Update CONTRIBUTING guide 2016-12-09 13:35:29 +00:00
Dave Conway-Jones
f6820ec615 Bump a load of packages (for 0.16 branch only)
Ready to drop node 0.10 - update ws, bcrypt, drop serial port node
2016-12-07 23:43:41 +00:00
Nick O'Leary
226ad3fe22 Add missing diff file 2016-12-07 13:51:20 +00:00
Nick O'Leary
a9b17e930c Add diff markers to tabs in diff-view 2016-12-07 13:48:30 +00:00
Nick O'Leary
932ea7ba8f Add flow diff view 2016-12-06 22:37:21 +00:00
Nick O'Leary
c720d78c39 Ensure runtime event notification gets cleared on restart 2016-12-05 14:39:34 +00:00
Nick O'Leary
8d21e441a0 Add notification when runtime stopped due to missing types
Part of #832
2016-12-05 13:24:24 +00:00
Nick O'Leary
16ecb1a9cb Overhaul keyboard handling and introduce editor actions 2016-12-04 22:59:43 +00:00
Nick O'Leary
f68acca427 Fix dynamically loading multiple node-sets from palette editor 2016-12-01 15:27:29 +00:00
Dave Conway-Jones
671d7e2beb debug - format if time if correct length/range 2016-11-28 17:28:49 +00:00
Nick O'Leary
52fc497412 Properly escape html strings passed to debug 2016-11-27 21:51:34 +00:00
Nathanaël Lécaudé
2084ad318f Tcpgetfix: Another small check (#1070)
* TCPget: Add another check for clients[connection_id]
2016-11-26 21:16:19 +00:00
Nathanaël Lécaudé
b530c1a43d TCPGet: Ensure done() is called only once (#1068)
* Add additional safety checks to avoid acting on non-existent objects

* TCPGet: yet more checks

* TCPGet: seperate connected properties

* TCPGet: properly handle node.done()
2016-11-25 18:14:51 +00:00
Nick O'Leary
f2797a4153 Fix package.json conflict 2016-11-24 20:52:48 +00:00
Nick O'Leary
659c326f89 Add jsonata snippets 2016-11-23 23:16:17 +00:00
Nick O'Leary
534b07d120 Include jsonata from dependency on build and improve func highlight 2016-11-23 23:15:30 +00:00
Nick O'Leary
de64fc8b8d Update rather than hide install button after success install 2016-11-23 10:58:38 +00:00
Nick O'Leary
1e234fcb73 Add editableList api doc comments 2016-11-23 10:58:19 +00:00
Nick O'Leary
fa9a7e725b Sort quick-add types and add most-recent used type section 2016-11-22 22:57:05 +00:00
Nick O'Leary
95b2675f03 Support query and search paths in url when opening debug sub window 2016-11-22 13:14:52 +00:00
Nick O'Leary
564902b886 Allow $ and _ at start of property identifiers
Fixes #1063
2016-11-21 21:36:18 +00:00
Nathanaël Lécaudé
071a04595a TCPGet: Separated the node.connected property for each instance (#1062)
* Add additional safety checks to avoid acting on non-existent objects

* TCPGet: yet more checks

* TCPGet: seperate connected properties
2016-11-19 16:25:54 +00:00
Nick O'Leary
eaa4b76ede Update jsonata version 2016-11-18 16:38:48 +00:00
Nicholas Humfrey
74a1713e99 Corrected 'overide' typo in XML node help (#1061)
Thanks @njh
2016-11-18 11:41:48 +00:00
Nathanaël Lécaudé
5f5aa0b2f7 TCPGet: Last property check (hopefully) (#1059)
* Add additional safety checks to avoid acting on non-existent objects

* TCPGet: yet more checks
2016-11-18 11:25:06 +00:00
Nathanaël Lécaudé
eef59fd40e Add additional safety checks to avoid acting on non-existent objects (#1057) 2016-11-17 21:04:38 +00:00
Dave Conway-Jones
361ff315e9 add --title for process name to command line options 2016-11-17 13:57:33 +00:00
Dave Conway-Jones
eeea8e530e add indicator for fire once on inject node 2016-11-17 13:56:37 +00:00
Dave Conway-Jones
8d5286703f reimplement $(env var) replace to share common code.
and add test to utils
2016-11-17 13:56:17 +00:00
Dave Conway-Jones
74f2180fa4 Fix error message for missing node html file, and add test.
To close #1053
2016-11-16 22:46:01 +00:00
Dave Conway-Jones
d042169f2e Let credentials also use $(...) substitutions from ENV
to close #1051
(and add to test)
2016-11-16 21:47:13 +00:00
Nick O'Leary
1fd87bf664 Improve debug message meta data contrast and legibility 2016-11-16 15:05:04 +00:00
Nick O'Leary
eeaff6b553 Add insert-function button to expression editor 2016-11-16 14:54:51 +00:00
Nick O'Leary
6efd048fd6 Rename insecureRedirect to requireHttps 2016-11-16 14:24:27 +00:00
Paul Slater
6e9e694f66 Add setting to cause insecure redirect (#1054)
* add support for editor insecure redirect setting

set insecureRedirect: true to cause the editor app to redirect insecure connections

* document insecureRedirect

* use req.originalUrl instead of req.url

url has the path removed, whereas originalUrl preserves the path - ie /red
2016-11-16 14:17:47 +00:00
telogis-nodered
44a0f1b505 Palette editor fixes (#1033)
* ensure remove button is only enabled for local modules when refreshing palette editor

* ensure local field is propagated to the nodes when a new module is added to the registry
2016-11-16 14:12:31 +00:00
Monkey Do
9790211891 Close comms on stopServer in test helper (#1020)
* Close comms on stopServer in test helper

Using this file in another project to test nodes, when running tests with gulp and karma the process never ends as comms are still open.
This resolves the problem.

* Moved test helper server on close to stopServer method
2016-11-16 14:09:04 +00:00
Adam Hořčica
be18cc9f2d Add support for flow and global context in Template node (#1048)
* Enable tests for flow and global context

* Add support for flow and global context in Template node

* Handle missing node context
2016-11-16 14:08:14 +00:00
Nick O'Leary
8caee09ea4 Preserve newlines in jsonata expression via tabs 2016-11-16 13:44:45 +00:00
Nick O'Leary
26f5305593 Add jsonata function help 2016-11-15 23:22:25 +00:00
Nick O'Leary
d33029027f Add expression editor for jsonata 2016-11-15 00:19:04 +00:00
Dave Conway-Jones
339aaaec57 Tcpgetfix (#1050)
* TCPget: Store incoming messages alongside the client object to keep reference
2016-11-14 20:20:27 +00:00
Dave Conway-Jones
db2425c473 Seperated info messages to their own file
auto detect size still needs work
2016-11-14 19:10:02 +00:00
Nathanaël Lécaudé
18731f6055 TCPget: Store incoming messages alongside the client object to keep reference 2016-11-14 13:30:43 -05:00
Nathanaël Lécaudé
34f1f7a31d Merge remote-tracking branch 'upstream/master' into tcpgetfix 2016-11-14 08:09:44 -05:00
Nathanaël Lécaudé
7ef153756b TCPget can now handle concurrent sessions (#1042)
* First release of multi connection tcpget

* Works when connection is left open

* Change scope of clients object

* Fix comparison to "" in tcpin

* Add security checks

* Better scope handling
2016-11-11 09:01:22 +00:00
Nick O'Leary
bf90509526 Add jsonata support to Change/Switch nodes 2016-11-10 23:58:34 +00:00
Nathanaël Lécaudé
d853eca489 Better scope handling 2016-11-10 17:35:44 -05:00
Nathanaël Lécaudé
869ae01da9 Add security checks 2016-11-10 16:45:01 -05:00
Dave Conway-Jones
d63996eea1 slight tidy of YAML PR (remove excess console.log in test)
and improve XML test coverage slightly
2016-11-10 21:29:07 +00:00
Nathanaël Lécaudé
9bbc8eda9d Added YAML parser node (#1034)
Thanks @natcl -
(sorry pressed closed by mistake !)
* Added YAML parser node

* Added YAML error strings in messages.json

* Change location of YAML library import

* Remove copyright

* Remove copyright

* Change order of yaml in Template node

* Add YAML test

* Add working test
2016-11-10 21:22:05 +00:00
Dave Conway-Jones
9cc1b03c56 small change to udp httpadmin
as it refers to both in and pout
2016-11-10 20:19:55 +00:00
Dave Conway-Jones
b1ab26e3ad update Font Awesome to 4.7.0 2016-11-10 20:15:06 +00:00
Nathanaël Lécaudé
96820418b5 Fix comparison to "" in tcpin 2016-11-10 11:17:27 -05:00
Nathanaël Lécaudé
385d9f16e9 Change scope of clients object 2016-11-09 22:33:55 -05:00
Nathanaël Lécaudé
d56fce37dd Works when connection is left open 2016-11-09 13:25:19 -05:00
Nathanaël Lécaudé
aef2c9e5cf First release of multi connection tcpget 2016-11-09 10:15:23 -05:00
Nick O'Leary
89a05c580f Handle drag whilst quick-add dialog open 2016-11-09 13:25:55 +00:00
Nick O'Leary
b85e562980 Combine quick-add and quick-join actions 2016-11-09 13:17:26 +00:00
Nick O'Leary
a0e6628757 Tweak search box styling 2016-11-08 21:18:34 +00:00
Nick O'Leary
60a41524f0 editableList delete button click event not cancelled 2016-11-08 17:01:21 +00:00
Nick O'Leary
6042395b81 Allow a node to reorder its outputs and maintain links
Fixes #1031
2016-11-08 17:00:47 +00:00
Nick O'Leary
8a5db8ce4b Handle explicitly set input widths on typedInput 2016-11-08 13:36:32 +00:00
Nick O'Leary
196d6e79e2 Don't pin change node input widths 2016-11-08 13:29:01 +00:00
Nick O'Leary
91f16215e5 Make typedInput keyboard navigable 2016-11-08 13:18:28 +00:00
Nick O'Leary
9c675a7847 Focus tray body when edit dialog opened 2016-11-08 09:58:20 +00:00
Nick O'Leary
f9e09e87d6 Hit enter to edit first node in selection 2016-11-07 21:51:03 +00:00
Nick O'Leary
73574d6293 Add quick-add node mode with cmd/ctrl-click 2016-11-07 21:25:09 +00:00
Ben Hardill
0a5a42b32a Fix node.error() not printing when passed false (#1037)
This should fix #1036
2016-11-07 18:28:35 +00:00
Nick O'Leary
de225205bd Fix safari/firefox detection of Meta key up 2016-11-06 00:24:01 +00:00
Nick O'Leary
8a47d36480 Add cmd/ctrl-click to quick add wires 2016-11-06 00:14:07 +00:00
Dave Conway-Jones
d5f3ba8d8a remove unnecessary require from JSON node 2016-11-04 19:55:02 +00:00
Nick O'Leary
782a06ce84 Tweak node info table colours 2016-11-04 14:30:41 +00:00
Nick O'Leary
5cdafc50fb Add node delete button to edit dialog 2016-11-04 14:29:04 +00:00
Nick O'Leary
0ca3cdb9ae tab-info node properties use RED.utils.createObjectElement 2016-11-03 14:34:38 +00:00
Nick O'Leary
a1d6cbd5fd Only expand strings that contain tabs/newlines 2016-11-03 14:34:38 +00:00
Nick O'Leary
6c36778cac Move debug message utils into core 2016-11-03 14:34:38 +00:00
Nick O'Leary
1c3a97a71a Make red.min.js a reusable library 2016-11-03 14:34:37 +00:00
Nick O'Leary
3489fe0cf4 Better toggling between raw/string views of buffers 2016-11-03 14:34:37 +00:00
Nick O'Leary
74b6d9dff9 Provide string view of buffers in debug messages 2016-11-03 14:34:37 +00:00
Nick O'Leary
06ee9aa05c Make strings expandable in debug 2016-11-03 14:34:37 +00:00
Nick O'Leary
f0f40a8606 Restore object keys values in debug sidebar 2016-11-03 14:34:37 +00:00
Nick O'Leary
1f2c9879bd Handle big arrays/buffers better in debug sidebar 2016-11-03 14:34:37 +00:00
Nick O'Leary
d1eb82bdf6 Show newlines/tabs in debug output 2016-11-03 14:34:37 +00:00
Nick O'Leary
8167f623e3 Update debug_spec for format changes 2016-11-03 14:34:37 +00:00
Nick O'Leary
9555e296a2 Close debug window when main window unloads 2016-11-03 14:34:37 +00:00
Nick O'Leary
f460283fa1 Full event passing between debug window and main window 2016-11-03 14:34:37 +00:00
Nick O'Leary
79da8e5a37 Move all common debug list code to its own library 2016-11-03 14:34:37 +00:00
Nick O'Leary
a35ce22218 Make debug message node id clickable 2016-11-03 14:34:36 +00:00
Nick O'Leary
1c905da8c2 Handle long strings in debug 2016-11-03 14:34:36 +00:00
Nick O'Leary
2b558768f1 Add debug filter box 2016-11-03 14:34:36 +00:00
Nick O'Leary
7607c4c882 Make inbuilt debug messages navigable 2016-11-03 14:34:36 +00:00
Nick O'Leary
c9f4813ce1 Fix debug path 2016-11-03 14:34:36 +00:00
Nick O'Leary
0428e27039 Improved type styling 2016-11-03 14:34:36 +00:00
Nick O'Leary
e30da2168d Make Debug object explorable 2016-11-03 14:34:36 +00:00
Nick O'Leary
0cd20768f4 Style the debug window to match the sidebar 2016-11-03 14:34:36 +00:00
Nick O'Leary
ab31f34862 Initial debug pop-out window 2016-11-03 14:34:36 +00:00
Dave Conway-Jones
9a4ff5cb43 fix test for CSV array input 2016-11-03 08:56:38 +00:00
Dave Conway-Jones
f66c91e18e different test for Pi (rather than use serial port name) 2016-11-03 08:56:18 +00:00
Dave Conway-Jones
a235745be7 Fix missing 0 handling for css node with array input 2016-11-02 15:49:51 +00:00
Nick O'Leary
9516da01e3 0.15.2 changelog 2016-10-28 08:48:10 +01:00
Nick O'Leary
7657bd2375 Bump 0.15.2 2016-10-28 08:43:21 +01:00
Nick O'Leary
0adcea9e7c Revert bidi changes to nodes and hide menu option until fixed
Fixes #1024
2016-10-28 08:37:33 +01:00
Dave Conway-Jones
aa8ad60083 Let xml node set options both ways
to close #1022  to close #975
Thanks @martin-doyle and @nikhildx
2016-10-26 22:06:35 +01:00
Dave Conway-Jones
5d98a86a6b bump serialport to use version 4
(precompiled versions more available)
2016-10-25 21:42:27 +01:00
Dave Conway-Jones
4418fdaed6 gpio node handle multiple bits of data returned in one go 2016-10-25 21:42:27 +01:00
Nick O'Leary
c58c45c917 HTTP In should pass application/octet-stream as buffer not string
Fixes #1023
2016-10-25 21:19:49 +01:00
Dave Conway-Jones
45eba5cabd tidy up udp node - repeat setting of var 2016-10-25 20:40:11 +01:00
Nick O'Leary
3ab0d0d865 Handle missing httpNodeRoot setting properly 2016-10-21 13:50:47 +01:00
Nick O'Leary
a6803081ab Config sidebar not handling node definition error properly 2016-10-21 13:47:54 +01:00
Nick O'Leary
8debed805b Add minimum show time to deploy spinner to avoid flicker 2016-10-21 12:59:55 +01:00
Nick O'Leary
fc9835512d Add work-in-progress update button to palette-editor 2016-10-21 10:29:26 +01:00
Nick O'Leary
5f0cab8cc2 Add log.removeHandler function 2016-10-20 23:31:40 +01:00
Nick O'Leary
bd391963bc Add Crtl/Shift/p shortcut for manage palette 2016-10-20 14:01:37 +01:00
Nick O'Leary
97fa28fb10 Add spinner to deploy button 2016-10-20 13:11:12 +01:00
Nick O'Leary
67d5b39c96 Status messages from nodes in subflows not delegated properly
Fixes #1016
2016-10-19 21:06:45 +01:00
Dave Conway-Jones
dbceef2581 fix spelling in join node info
Manual fix for #1014
Thanks @rogovski
2016-10-17 21:40:12 +01:00
Nick O'Leary
5b22ccfca6 Speed up tab scrolling 2016-10-15 20:58:27 +01:00
Nick O'Leary
714c254bab Update delay burst test to be more tolerant of timing
Fixes #1013
2016-10-14 22:35:43 +01:00
Nick O'Leary
90f4db9158 Bump 0.15.1 2016-10-13 19:53:43 +01:00
Nick O'Leary
eed470ddae Update default palette catalogue to use https 2016-10-13 16:22:25 +01:00
Nick O'Leary
49f72881f4 Disable palette editor if npm not found 2016-10-12 22:30:32 +01:00
Nick O'Leary
a76674032d Searching package catalogue should be case-insensitive
Fixes #1010
2016-10-12 20:08:08 +01:00
Nick O'Leary
ec392a7f9a contenteditable fields not handled in config nodes
Fixes #1011
2016-10-12 19:56:12 +01:00
Dave Conway-Jones
8a2ae6c480 Change html link refs from _new to _blank to be standards compliant 2016-10-12 17:53:27 +01:00
Nick O'Leary
b3796a8e24 Fix unit tests for /flows 2016-10-12 10:33:51 +01:00
Nick O'Leary
b9144ff987 Bump version 0.15.0 2016-10-12 10:27:08 +01:00
Nick O'Leary
5344949c71 Tidy up /flows api responses 2016-10-12 10:24:10 +01:00
Nick O'Leary
05cbba9a35 Exporting current flow not formatting tab node correctly 2016-10-11 21:34:52 +01:00
Nick O'Leary
325c6135cf Defeat the exec node test dragons 2016-10-11 20:31:42 +01:00
Dave Conway-Jones
fdea19a45b leave Pi GPIO pins in a sensible state on error 2016-10-11 15:37:34 +01:00
Nick O'Leary
fad63c0c18 Fix tab_config revealing unused config nodes 2016-10-11 15:06:34 +01:00
Nick O'Leary
f002560616 Exec node spawn mode should clone messages it reuses 2016-10-11 14:49:48 +01:00
Nick O'Leary
8e7d52e645 Avoid reencyrpting credentials if they haven't changed 2016-10-11 14:27:35 +01:00
Nick O'Leary
d119594cbf Tidy up exec node clean-up to remove failure-causing timing window 2016-10-11 13:25:19 +01:00
Nick O'Leary
84f7da6e93 Fix null checking in exec node test 2016-10-11 11:16:10 +01:00
Nick O'Leary
22e1bafe1b Fix exec test on node 0.10 2016-10-11 10:53:50 +01:00
Nick O'Leary
3f8e42e510 update changelog 2016-10-11 10:28:16 +01:00
Dave Conway-Jones
9704fb04d9 inject node label - show topic for timestamp mode if short 2016-10-11 09:27:02 +01:00
Nick O'Leary
dcfaf1e2b9 Update changelog 2016-10-11 00:17:06 +01:00
Nick O'Leary
42f7dc1947 Fix type checking in unit tests 2016-10-10 13:27:43 +01:00
Nick O'Leary
eb1a597456 Add npm build/test scripts
Closes #946 #660
2016-10-10 11:49:38 +01:00
Dave Conway-Jones
8368815db5 extra change tests for partial and complete match
to close #934
2016-10-10 11:48:52 +01:00
Nick O'Leary
9c6295d0d8 Lighten shade color in editor 2016-10-10 11:42:36 +01:00
Dave Conway-Jones
4d19f881e9 Let change node set type if total match
remove unnecessary 2 step move when not required.
add test for moving sub property up to main property
2016-10-10 11:10:36 +01:00
Dave Conway-Jones
3a8820397b clean up status on close for several core nodes. 2016-10-10 11:08:06 +01:00
Nick O'Leary
85b1c1fe97 Increase default apiMaxLength to 5mb and add to default settings
Closes #1001
2016-10-10 10:14:08 +01:00
Nick O'Leary
a4de9e94dd Update dependency versions 2016-10-10 10:02:41 +01:00
Nick O'Leary
0dd2c7fe24 Change node: reparse JSON set value each time to avoid pass-by-ref 2016-10-09 23:14:52 +01:00
Nick O'Leary
f22c3b549e Merge branch '0.15.0' 2016-10-09 23:00:28 +01:00
Nick O'Leary
3c60b3d2c9 Prevent search box opening when other modals are open 2016-10-09 22:54:47 +01:00
Nick O'Leary
f2d36b84b5 Don't hide install button on already-installed node modules 2016-10-09 22:23:47 +01:00
Nick O'Leary
9af08ef26a Update test helper for new flow api 2016-10-09 22:22:13 +01:00
Nick O'Leary
b4be1184fd Add v2 /flows api and deploy-overwrite protection 2016-10-09 22:02:40 +01:00
Nick O'Leary
c60e0d389c Mark nodes as changed when they are moved 2016-10-09 22:02:40 +01:00
Dave Conway-Jones
d658fe7709 move travis to node 6 and 7 - drop 5 and 0.12
move serialport  to 0.3.0 version
2016-10-06 13:31:59 +01:00
TJKoury
54036a2b4d Added parent containment option for draggable. (#1006)
* added parent containment option for draggable

* taking Nick's suggestion, #main-container it is
2016-10-02 22:45:49 +01:00
Dave Conway-Jones
2da9572a45 Better handle httprequest header capitalisation 2016-10-02 17:44:48 +01:00
Nick O'Leary
306825aa90 Enable es6 parsing in Function editor by default
Fixes #985
2016-09-30 23:51:27 +01:00
Nick O'Leary
c797073c05 Ignore bidi event handling on non-existent and non-Input elements
Closes #999
2016-09-30 23:35:05 +01:00
Nick O'Leary
d9d65d59d1 Fix timing window when scrolling search box results 2016-09-30 23:34:44 +01:00
Nick O'Leary
aad29e4487 Remove list of flows from menu 2016-09-30 23:34:26 +01:00
Nick O'Leary
b00985f99f Replace palette-edit button with menu option 2016-09-30 20:33:27 +01:00
Nick O'Leary
538a16a5fb Allow nodes to be imported with their credentials 2016-09-30 14:15:04 +01:00
Nick O'Leary
300a8d3a89 Click to close search box 2016-09-30 13:27:53 +01:00
Nick O'Leary
e3b7c5fce7 Add 'no matches' message to package search results 2016-09-30 11:19:47 +01:00
Nick O'Leary
2e87ebe800 Fix editableList sizing on safari 2016-09-30 10:46:13 +01:00
Nick O'Leary
7ed9e7cdd4 Update debug sidebar to use RED.view.reveal to show debug nodes 2016-09-29 23:49:58 +01:00
Nick O'Leary
7ff9c2885d Fix scrollable tab buttons changing location hash 2016-09-29 23:46:55 +01:00
Nick O'Leary
18c8bbb0fc Add workspace search option 2016-09-29 23:46:29 +01:00
Nick O'Leary
9a49fb9450 Add escape-to-clear to searchBox and other css fixes 2016-09-29 23:45:25 +01:00
Nick O'Leary
84457bc7b4 Add scrollOnAdd option to editableList 2016-09-29 23:44:49 +01:00
Dave Conway-Jones
15f1e2c85c Add swift markup to editor for open whisk node 2016-09-27 22:04:13 +01:00
Nick O'Leary
15e828e975 Adjust dragging tabs when partially scrolled 2016-09-27 00:05:43 +01:00
Nick O'Leary
e4626ee52b Scrollable tabs 👍 2016-09-26 22:56:28 +01:00
Nick O'Leary
1866c9c7ef Allow linking to individual flow via url hash 2016-09-24 22:57:41 +01:00
Nick O'Leary
a0f91aa814 Avoid duplicating existing subflows on import 2016-09-24 22:20:28 +01:00
Dave Conway-Jones
a89c7b1a70 Add full path tip to file node, And tidy up Pi node tips 2016-09-23 23:37:56 +01:00
Dave Conway-Jones
ded1376957 remove websocket node maxlistener warning 2016-09-23 23:36:58 +01:00
Nick O'Leary
252040f03b Add import-to-new-tab option 2016-09-23 22:02:12 +01:00
Nick O'Leary
d29abc2724 Encrypt credentials by default 2016-09-23 10:38:30 +01:00
Nick O'Leary
44c35d2644 Update test node helper module for storage api changes 2016-09-21 22:22:04 +01:00
Nick O'Leary
f9b972349d Move credential load/save storage functions under get/setFlows 2016-09-21 21:58:50 +01:00
Nick O'Leary
e06cadd761 Pass full runtime object to storage and flow sub-components 2016-09-21 10:22:04 +01:00
Nick O'Leary
ee45d6b48f Fix contenteditable div unfocused css 2016-09-20 10:10:28 +01:00
Nick O'Leary
d915b280d4 Add new options to export-nodes dialog 2016-09-19 13:54:23 +01:00
Nick O'Leary
39d90fe881 Update mqtt-broker node to use fully name-space qualified status messages 2016-09-19 09:36:38 +01:00
wajnberg
b9da1f18b4 Fixing issue 989 (#997)
* Fixing issue 989

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>

* Fixing the getRangeAt problem on Chrome

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>

* Fixing the getRangeAt problem on Chrome

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>
2016-09-18 21:20:50 +01:00
Dave Conway-Jones
69a0934173 Merge pull request #996 from Belphemur/delay-migration
Fix migration of Delay Node
2016-09-17 15:54:27 +01:00
Antoine Aflalo
289de85754 Fix the check for nbRateUnits 2016-09-17 10:38:30 -04:00
Dave Conway-Jones
0ec95041d9 another tiny nudge for code tag 2016-09-17 15:29:54 +01:00
Dave Conway-Jones
fcb6f78d54 give <code> tag slightly more bottom space 2016-09-17 14:06:01 +01:00
Dave Conway-Jones
29e9740668 Let UDP node better share same port instance if required 2016-09-17 14:05:26 +01:00
Antoine Aflalo
ea8c6d5cce Add number of units to the delay node (rate) (#994)
* Add possibility to set the value for the rate unit

Backward compatible, if the new nbRateUnits is not set, default to 1.
This way we can delay messages to 1 msg per X seconds/minutes/hours days
instead of always 1.
Useful when interacting with API that have a uncommon rate limiting like
1req per 2 seconds.

* Fix existing testing for delay

* Add new test for the nbRateUnits

* Fix label for timed and topic for delay node

* Schrink width of Units delay rate

* pluralisation of labels

* Dynamic pluralisation respecting i18n

* Remove debug data left
2016-09-16 14:27:14 +01:00
Alice Ferrazzi
e4c951984a typo fix (#990)
typo fix in mqtt broker help text
2016-09-14 23:13:08 +01:00
Dave Conway-Jones
0071afb205 update registry loader test to normalise path for windows
Thanks shrikes
2016-09-13 22:57:20 +01:00
Nick O'Leary
d3c7ac75be Set switch node rule input widths properly 2016-09-08 21:12:39 +01:00
Nick O'Leary
55d7420abf Remove tabs 2016-09-08 20:49:44 +01:00
wajnberg
489b56456f Completing STT support (#976)
* Completing STT support

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>

* Adressing Nick comments

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>
2016-09-08 20:46:30 +01:00
Nick O'Leary
1f24fcb364 Ensure errors thrown by RED.events handlers don't percolate up 2016-09-05 23:09:33 +01:00
Nick O'Leary
722b31edee Safely ignore subflow instance nodes in palette editor 2016-09-02 20:31:24 +01:00
Dave Conway-Jones
765f0393b0 Add test for change node ,move to sub-property 2016-08-28 12:09:37 +01:00
Dave Conway-Jones
6868ef044b Allow http middleware to skip rawBodyParser 2016-08-28 12:02:34 +01:00
Dave Conway-Jones
5dd0622e40 Let change node move property to sub-property. 2016-08-28 12:02:34 +01:00
Dave Conway-Jones
48bdab1dcf Add info to exec warning about buffered output if using python 2016-08-28 12:02:34 +01:00
Nick O'Leary
aee483e9f1 Stop nodes being added beyond the outer bounds of the workspace 2016-08-26 16:22:06 +01:00
Nick O'Leary
8542b9bf67 Fix splice handling when a subflow input/output node is selected 2016-08-26 13:34:29 +01:00
Nick O'Leary
feaf6f2501 Remove console.log from bidi 2016-08-26 13:27:19 +01:00
Nick O'Leary
d7d30aa972 Default config nodes to global scope unless in a subflow
Closes #972
2016-08-26 13:26:42 +01:00
Nick O'Leary
91c23d1f7d Fix palette-editor handling of subflows 2016-08-26 13:21:33 +01:00
Nick O'Leary
57479edc59 Merge branch 'palette-ui' into 0.15.0 2016-08-26 13:01:03 +01:00
Nick O'Leary
4b462eaae9 Move initInputEvents to prepareInput 2016-08-26 12:50:18 +01:00
Nick O'Leary
c60fb3bc25 Move setting text direction into bidi module 2016-08-26 00:40:01 +01:00
Nick O'Leary
b17c34402d Fix some more tabs/spaces in bidi work 2016-08-26 00:28:22 +01:00
Nick O'Leary
6ad71bd222 Move bidi code under RED.text 2016-08-25 17:09:56 +01:00
wajnberg
ccc08be0ee Bidi support for Text Direction and Structured Text (#961)
* Bidi support for Text Direction and Structured Text

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>

* Adding documentation for functions in bidi.js and format.js

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>

* Removing unused functions from format.js

Signed-off-by: Moshe Wajnberg <wajnberg@il.ibm.com>
2016-08-25 16:47:30 +01:00
telogis-nodered
2a2fc80931 Fix jquery selector, selecting more than one help pane/popover and displaying incorrectly. (#970) 2016-08-25 10:44:23 +01:00
James Thomas
9ebca91775 Fixes removeItem not passing row data to callback. (#965)
Call to .data('data') was happening after the remove() call, which
deletes the retained data. This was passing undefined back to the
callback for removeItem.

I've changed the data retrieval to a temporary variable before the
delete call.
2016-08-21 23:05:53 +01:00
Dave Conway-Jones
456fc23463 update README link to IBM ETS blog page 2016-08-18 13:50:46 +01:00
Nick O'Leary
eb17562f4d NLS the palette editor 2016-08-14 23:08:37 +01:00
Nick O'Leary
b7dbfd5cfc Only reload catalogue when requested 2016-08-13 00:33:41 +01:00
Nick O'Leary
cdc7ab562a Add sort options to palette-editor search 2016-08-12 23:00:28 +01:00
Nick O'Leary
e6b5552cba Add some more error handlers for custom node label functions
Closes #956
2016-08-11 14:49:22 +01:00
Nick O'Leary
eecf92183f Update to new catalogue format 2016-08-10 21:59:31 +01:00
Nick O'Leary
11656382a7 Allow palette-editor to be disabled via editorTheme 2016-08-10 20:15:17 +01:00
Nick O'Leary
e4d788ad0b Add install tab to palette-editor 2016-08-09 10:43:03 +01:00
Nick O'Leary
3017442702 Move common components and add searchBox 2016-08-09 10:41:26 +01:00
Nick O'Leary
ba37db275c Add node filter to palette-editor 2016-08-05 16:39:41 +01:00
Nick O'Leary
521e669879 Enable palette-editor remove buttons 2016-08-05 13:39:14 +01:00
Nick O'Leary
12e302c10a Collapse palette modules when palette-editor closed 2016-08-04 22:28:56 +01:00
Nick O'Leary
7220af3ef0 Move palette editor to left hand side 2016-08-04 16:49:36 +01:00
Dave Conway-Jones
42f4e0fa86 TCP node: pass on latest input msg properties
to close #944
2016-08-04 15:49:38 +01:00
Dave Conway-Jones
022d066fe0 Make sure MQTT broker is really set
To close #951
2016-08-04 10:02:27 +01:00
Dave Conway-Jones
4c9d7cbeed Merge pull request #955 from natcl/master
Fix escapce character catch in TCPGet + support 0x?? sequences
2016-08-02 20:15:31 +01:00
Nathanaël Lécaudé
1541e382e4 Fix escapce character catch in TCPGet + support 0x?? sequences 2016-08-02 12:32:49 -04:00
Dave Conway-Jones
1d9488d24f Merge pull request #954 from natcl/master
Fix split character in TCP Request node
2016-08-02 16:26:37 +01:00
Nathanaël Lécaudé
6cbc1afb9b Fix split character in TCP Request node 2016-08-02 11:09:41 -04:00
Nathanaël Lécaudé
3f86b660ed Add CSS hilighting to the template node (#950)
This can be useful when using the template node to create frontends, see this post:
https://groups.google.com/d/msg/node-red/q4DKaX87Ano/Xa1mLpOdAwAJ

Thanks !
2016-08-01 22:32:02 +01:00
Dave Conway-Jones
4603f2d9ca only update switch Prev value after all rules are run 2016-08-01 12:31:35 +01:00
Nick O'Leary
da818cf420 Add initial palette sidebar 2016-07-29 12:52:00 +01:00
Nick O'Leary
86a2ed652d Update changelog 2016-07-29 10:44:52 +01:00
Nick O'Leary
269761f222 Bump version/changelog 2016-07-29 10:43:53 +01:00
Dave Conway-Jones
53ca3046b3 Add RPi.GPIO lib test for ArchLinux 2016-07-28 18:20:18 +01:00
Nick O'Leary
f484156d8e Tell ace about Function node globals
Closes #927
2016-07-28 17:14:55 +01:00
Nick O'Leary
1da8712a4a Update ace to 1.2.4 2016-07-28 17:14:38 +01:00
Nick O'Leary
dd47eba88c Add proper help text to link nodes 2016-07-28 15:58:00 +01:00
Nick O'Leary
0ade8ff7a2 Add log warning if node module required version cannot be satisfied 2016-07-28 15:43:26 +01:00
Nick O'Leary
6a528b5fdb Allow config nodes to provide a sort function for their select list 2016-07-28 13:27:34 +01:00
Nick O'Leary
7f63ddc9ea Handle importing old mqtt-broker configs that lack properties 2016-07-27 23:05:48 +01:00
Nick O'Leary
d6b326c134 Handle empty credentials file
Closes #937
2016-07-26 22:23:49 +01:00
Nick O'Leary
d944298dd7 Tidy up mqtt nodes - linting and done handling
Closes #935
2016-07-26 21:33:00 +01:00
Nick O'Leary
0136ebd2b4 Fix invalid html in TCP and HTML node edit templates 2016-07-26 16:19:27 +01:00
Nick O'Leary
45f8def1ed Bump version + change log 2016-07-23 22:59:56 +01:00
Nick O'Leary
7c6e8eeefc Cannot clear cookies with http nodes 2016-07-23 22:41:37 +01:00
Dave Conway-Jones
e81e48cde3 Fix html parse node test 2016-07-20 20:58:52 +01:00
Dave Conway-Jones
8eebb6ea2d let HTML parse node allow msg.select set select
to close #943
2016-07-20 20:08:50 +01:00
Nick O'Leary
ad8290ebcb Validate nodes on import after any references have been remapped 2016-07-20 11:30:49 +01:00
Nick O'Leary
15b6f6268b Debug node handles objects without constructor property
Fixes #933
2016-07-15 22:41:35 +01:00
Nick O'Leary
92d5af7446 Ensure 'false' property values are displayed in info panel
Fixes #940
2016-07-15 22:33:17 +01:00
Nick O'Leary
d57425a15e Fix node enable/disable over restart - load configs after settings init 2016-07-15 00:11:28 +01:00
Nick O'Leary
a457c06500 Bump version 2016-07-06 23:22:26 +01:00
Nick O'Leary
906bbae899 Update CHANGELOG 2016-07-06 21:35:06 +01:00
Dave Conway-Jones
e360e57a5b Fix node.status to check hasOwnProperty("text") 2016-07-06 17:22:45 +01:00
Nick O'Leary
c5753a013c Handle DOMException when embedded in an iframe of different origin
Fixes #932
2016-07-06 13:28:51 +01:00
Nick O'Leary
691b083364 Update trigger node ui to use typedInputs 2016-07-05 15:39:00 +01:00
Dave Conway-Jones
b74a35b9d1 add extra test for CSV with odd quotes 2016-07-05 11:51:08 +01:00
Dave Conway-Jones
82269462a4 Fixed better handling of odd quotes in CSV node
(and a better commit message)
2016-07-05 11:31:25 +01:00
Dave Conway-Jones
d7943aab28 better handling of snatched quotes in css parser 2016-07-05 11:03:11 +01:00
Nick O'Leary
446eb8e978 Fix double firing of menu actions 2016-07-05 09:16:27 +01:00
Nick O'Leary
d91a99c833 Clarify the MQTT node sends msg.payload
Closes #929
2016-07-04 11:29:43 +01:00
Nick O'Leary
dc00870461 Fix select box handling in Safari
Fixes #928
2016-07-04 11:22:30 +01:00
Dave Conway-Jones
b8f578862e Add sql mode to ace editor 2016-07-04 09:58:03 +01:00
Jesse Naranjo
dc24c05229 Keyboard shortcuts dialog update (#923)
* Added Ctrl+Z to the Keyboard Shortcuts dialog.

* Added Arrow Keys and Shift + Arrow Keys shortcuts to the Keyboard Shortcuts dialog.

* Added the [Backspace] key to the Keyboard Shortcuts dialog.
2016-07-03 23:10:51 +01:00
Nick O'Leary
f62cf6818b Clear context in node test helper
Fixes #858
2016-07-03 23:08:53 +01:00
Nick O'Leary
c05e9da9c5 Allow node properties to be same as existing object functions
Fixes #880
2016-07-03 23:00:48 +01:00
Nick O'Leary
6c00194d35 Handle comms link closely whilst completing the initial connect 2016-06-30 00:44:06 +01:00
Nick O'Leary
6bc3f82afe Protect against node type names that clash with Object property names
Fixes #917
2016-06-30 00:38:48 +01:00
Nick O'Leary
12e46deea2 Ensure importing link nodes to a subflow doesn't add outbound links
Fixes #921
2016-06-29 23:51:08 +01:00
Nick O'Leary
8608d010b8 Clone default node properties to avoid reference leakage 2016-06-29 22:53:14 +01:00
Nick O'Leary
9d4d1acf2d Strip tab node definition when exporting 2016-06-29 21:58:14 +01:00
Nick O'Leary
23087447f1 Check for null config properties in editor before overwritting them 2016-06-29 21:32:39 +01:00
Nick O'Leary
3008e4e60f Add hasUsers flag to config nodes 2016-06-29 21:07:45 +01:00
Nick O'Leary
9d52ed5ff6 Add updateConfigNodeUsers function to editor 2016-06-28 14:57:48 +01:00
Nick O'Leary
5f047633c3 Scroll to bottom when item added to editableList 2016-06-28 10:56:03 +01:00
Nick O'Leary
d3be1f1e2c Fix lint error 2016-06-26 23:55:04 +01:00
Nick O'Leary
c3b1cf7c35 Form input widths behave more consistently when resizing
Fixes #919 #920
2016-06-26 23:48:59 +01:00
Nick O'Leary
682345da22 Inject node should reuse the message it is triggered with
Closes #914
2016-06-25 21:44:10 +01:00
Dave Conway-Jones
82f289c42e (un)Fix inject payload width field
to close #919
2016-06-25 15:53:03 +01:00
Dave Conway-Jones
78eae99bd4 Stop trigger node re-using old message…
to Close #916
Thanks @jimbojw
2016-06-25 10:44:44 +01:00
Nick O'Leary
9ec7bb8d41 bump version 2016-06-20 21:38:09 +01:00
Nick O'Leary
2b9bfbc309 MQTT In subscription qos not defaulting properly 2016-06-20 21:35:43 +01:00
Dave Conway-Jones
e50d04077b Let exec node handle 0 as well as "0" 2016-06-20 19:28:59 +01:00
Nick O'Leary
b6fcaacb77 Create default settings.js in the user-specified directory
Fixes #908
2016-06-20 14:41:47 +01:00
Nick O'Leary
939da4e551 bump version 2016-06-20 14:27:28 +01:00
Nick O'Leary
f30ce1f9eb Cannot add twitter credentials
Fixes #913
2016-06-20 14:25:11 +01:00
Nick O'Leary
343588b2a0 Support array references in Debug property field 2016-06-20 10:19:18 +01:00
Nick O'Leary
77b13ce9d4 Bump version & changelog 2016-06-20 09:56:29 +01:00
Nick O'Leary
7cb41d2ca9 Remove duplicate "Delete" entry in keyboard shortcut window
Fixes #911
2016-06-20 09:56:01 +01:00
Nicholas Humfrey
8bbc9e6502 Added 'exec' to the command in the node-red-pi script (#910) 2016-06-20 09:53:57 +01:00
Nick O'Leary
e29a0df3fd Handle undefined node properties when mapping array references 2016-06-20 09:38:16 +01:00
Nick O'Leary
0eba04aac0 Change example httpStatic to avoid node-red-dashboard clash 2016-06-19 20:25:31 +01:00
Nick O'Leary
b78210e3be Handle numberic msg.payload in HTTP Response node 2016-06-17 22:08:58 +01:00
Nick O'Leary
958de21be8 Update changelog 2016-06-17 21:44:06 +01:00
Nick O'Leary
0eb4742982 Update minor dependency versions and bump version 2016-06-17 21:42:17 +01:00
Nick O'Leary
78b1bf8f25 Merge branch '0.14.0' 2016-06-17 21:30:09 +01:00
Nick O'Leary
08f2741871 Ensure default settings copied to command-line specified userDir
Fixes #908
2016-06-17 21:16:31 +01:00
Dave Conway-Jones
98b24ae630 Merge pull request #798 from natcl/master
Add pinned tab icon for Safari
2016-06-17 14:24:36 +01:00
Dave Conway-Jones
7fc056c8e3 remove extraneous udp console.log
and two tiny whitespace changes
2016-06-17 08:18:26 +01:00
Nick O'Leary
0411623857 Update change log 2016-06-16 00:09:32 +01:00
Nick O'Leary
365d71264f Add index to editableList callback signature 2016-06-16 00:09:32 +01:00
Nick O'Leary
0d4d51fc39 Pass type/value on typedInput.change event 2016-06-16 00:09:32 +01:00
Nick O'Leary
b21745808b Don't mark 'edit subflow template' as primary button 2016-06-16 00:09:32 +01:00
Dave Conway-Jones
e4d5271d58 Better fix for css, reverting test 2016-06-14 23:55:50 +01:00
Dave Conway-Jones
8f2f3bf75d Fix CSV test 2016-06-14 23:20:09 +01:00
Dave Conway-Jones
9e96eba98f fix csv handling of "numbers" with E in... 2016-06-14 22:36:44 +01:00
Nick O'Leary
0441c83fd7 Fix use of hasOwnProperty in Flow
Closes #907
2016-06-14 20:30:37 +01:00
Nick O'Leary
d8405052d8 Dont hover disabled editor primary buttons 2016-06-14 14:38:52 +01:00
Nick O'Leary
cc02b07ff0 Improve edit tray button colour contrast 2016-06-14 14:28:25 +01:00
Nick O'Leary
2d6aac7d6f Update changelog 2016-06-13 22:36:47 +01:00
Nick O'Leary
589d43f0e5 Add RED.util to Function node sandbox 2016-06-13 22:16:36 +01:00
Nick O'Leary
13c1d1df7a Update Debug node to use typedInput for complete/property option 2016-06-13 22:00:42 +01:00
Nick O'Leary
08ade44dc8 Handle more edge cases with RED.util.normalisePropertyExpression 2016-06-13 22:00:42 +01:00
Dave Conway-Jones
8fb1c76247 update font-awesome fonts to latest and
bump some npm pre-req versions
2016-06-13 21:05:32 +01:00
Nick O'Leary
3ad9053d65 Fix multi-level sequences of split/join nodes 2016-06-13 17:44:20 +01:00
Dave Conway-Jones
8fe07e0f07 Limit Pi GPIO to dedicated GPIO pins
to avoid clashes with internal drivers (e.g. I2C, SPI, AMA0 etc)
2016-06-13 14:23:19 +01:00
Nick O'Leary
09b069c129 Add icons to parser nodes 2016-06-12 22:37:38 +01:00
Nick O'Leary
b2db083f39 Another rev of the split/join icons 2016-06-12 21:33:27 +01:00
Nick O'Leary
53e2f3e263 Update split/join icons 2016-06-12 12:24:52 +01:00
Nick O'Leary
945fbbc065 Capture error stack on node.error
Closes #879
2016-06-12 11:07:05 +01:00
Nick O'Leary
4dc9c7714c Clear node context on close
Fixes #870
2016-06-11 22:53:27 +01:00
Nick O'Leary
7302ac5871 Add merged object to Join node 2016-06-11 21:44:00 +01:00
Dave Conway-Jones
1cfad27d6f Delay node only warn once on queue >1000 messages
and then again at >10000 messages
2016-06-10 23:21:12 +01:00
Nick O'Leary
d82fe95076 Update split node docs 2016-06-10 22:51:57 +01:00
Nick O'Leary
8f8df4971c Fix switch node assumptions around string/number handling 2016-06-10 21:03:38 +01:00
Nick O'Leary
fd66569950 Update Join node implementation 2016-06-09 11:33:40 +01:00
Nick O'Leary
e97d9fb0b2 Add draft changelog for 0.14 2016-06-08 17:58:36 +01:00
Nick O'Leary
04424c2a7c Add CHANGELOG.md and make it accessible from menu 2016-06-08 16:18:24 +01:00
Nick O'Leary
241e2828e7 Add support to HTTP In node for PATCH requests
Closes #904
2016-06-08 11:31:59 +01:00
Nick O'Leary
5f6a0141f0 Add cookie handling to HTTP In and HTTP Response nodes 2016-06-08 11:09:18 +01:00
Nick O'Leary
ef2f71859c Join node ui updates 2016-06-07 23:18:46 +01:00
Dave Conway-Jones
fdaeeb5d01 add join icon 2016-06-07 23:18:46 +01:00
Nick O'Leary
e594ffe0f8 Update Join node runtime to match UI changes 2016-06-07 23:18:46 +01:00
Nick O'Leary
9f8c32ce8f Split node UI rework - WIP 2016-06-07 23:18:46 +01:00
Nick O'Leary
762eb07dd4 Add support for array-syntax in typedInput msg properties 2016-06-07 23:01:23 +01:00
Nick O'Leary
0300458ba8 Add error handling to all node definition api calls 2016-06-06 14:45:36 +01:00
Nick O'Leary
3959fcdc88 Handle null return from Function node in array of messages 2016-06-06 11:40:02 +01:00
Dave Conway-Jones
ea76c18f59 Add some info words to config nodes 2016-06-04 09:05:19 +01:00
Nick O'Leary
d125ecc671 Remove rogue console.log 2016-06-04 00:42:33 +01:00
Nick O'Leary
7d9b90a1f3 Disarm click-to-close whilst opening an edit tray 2016-06-04 00:42:08 +01:00
Nick O'Leary
7402c27b6a Reduce tab left-padding below a width threshold 2016-06-04 00:41:26 +01:00
Nick O'Leary
4e762e2063 Enable shift-drag detach of just the selected link 2016-05-31 23:42:00 +01:00
Nick O'Leary
0afe98b399 Move rename flow dialog to editor tray 2016-05-31 23:20:25 +01:00
Nick O'Leary
daed059c47 Emit editor:open/close events from the tray itself 2016-05-31 23:19:43 +01:00
Trisooma
f1ce0fab8b Option to enable cors for editor (#886)
Adds httpAdminCors setting
2016-05-31 14:55:03 +01:00
Nick O'Leary
b5d3f505e3 Defer loading of token sessions until they are accessed
Fixes #895
2016-05-31 14:39:50 +01:00
Nick O'Leary
6c8f688f33 Close the current edit tray when the workspace is clicked 2016-05-31 13:24:56 +01:00
Nick O'Leary
ed1b601a84 Editor buttons should have same border colour as other input elements 2016-05-31 13:09:27 +01:00
Nick O'Leary
add541f67f Restore the edit-select box add behaviour
This reverts commit 59a7c46482.
2016-05-31 13:01:49 +01:00
Nick O'Leary
bea8eb799f Add node/editor lifecycle events 2016-05-29 23:51:20 +01:00
Nick O'Leary
3cac48e86f Fix jshint issue in editableList 2016-05-29 22:41:25 +01:00
Nick O'Leary
64722da4a7 Make sidebars disabled-on-edit by default 2016-05-29 22:37:25 +01:00
Nick O'Leary
ada1e624d8 Update editableList apis 2016-05-29 22:37:25 +01:00
Dave Conway-Jones
69f83cb905 fully log node warnings on start
(i.e. don’t need -v for simple errors on start)
2016-05-26 10:38:24 +01:00
Dave Conway-Jones
807873f685 set pi gpio pin status correctly if set on start 2016-05-26 10:37:20 +01:00
Nick O'Leary
8d4be848b0 Workaround firefox not allowing SVG elements to have focus 2016-05-22 21:23:30 +01:00
Nick O'Leary
59a7c46482 Modify config node select box to have dedicated add button 2016-05-21 22:11:29 +01:00
Nick O'Leary
eabfeb9502 Slow down the tray slide animation slightly 2016-05-21 22:11:10 +01:00
Nick O'Leary
291240dd94 Add editableList widget and update Switch/Change nodes to use it 2016-05-20 22:13:28 +01:00
Nick O'Leary
2f6ed47168 Handle null node array references in catch/status nodes 2016-05-20 10:32:06 +01:00
Nick O'Leary
9a73568c7a Ensure node field change handlers are invoked after editprepare 2016-05-19 22:42:28 +01:00
Nick O'Leary
acdef87be7 Ensure editor resize is called even when limits are hit 2016-05-19 11:16:37 +01:00
Nick O'Leary
b14546605d Fix dialog button order in tab-delete and confirm-deploy dialogs 2016-05-19 11:16:37 +01:00
Nick O'Leary
5ad46106f4 Use onadd in link nodes to ensure imported links are updated 2016-05-19 11:16:37 +01:00
Dave Conway-Jones
3e9be9eed3 remove orion from build 2016-05-18 11:11:59 +01:00
Nick O'Leary
7318a7b767 Prevent parent window scrolling when view is focused
Fixes #635
2016-05-18 09:53:04 +01:00
Nick O'Leary
b78682f413 Change Inject repeat label icon 2016-05-18 09:35:43 +01:00
Nick O'Leary
e50659af09 Add repeat indicator to inject node label
Closes #887
2016-05-17 23:36:09 +01:00
Josh
3454e5ac77 Flows lib honours flowFilePretty setting (#837)
* Flow lib now adheres to pretty flow file, ui also adheres to this as well

* added settings mock object in flows_spec get api test

* reverted api changes, fixed parse of flow only

* try spell flows correctly
2016-05-17 22:09:57 +01:00
Nick O'Leary
9e26aeea1d Handle scoped node modules in the api 2016-05-17 21:56:03 +01:00
Nick O'Leary
d7715b05ee Ensure catch/status/link node references update on import 2016-05-17 09:39:18 +01:00
Nick O'Leary
db433efbef Link nodes show hidden wires when selected
2016-05-17 09:18:32 +01:00
Dave Conway-Jones
f1f8c887c6 bump font awesome to 4.6.2 level 2016-05-11 20:39:38 +01:00
Nick O'Leary
9ae4745ca5 Refocus workspace after closing edit tray 2016-05-11 17:15:36 +01:00
Nick O'Leary
726d9c8ec5 Set z-index of editor shade so it stays above tabs 2016-05-08 22:55:55 +01:00
Nick O'Leary
a9bfa4e79b Allow keyboard shortcuts to be scoped to a dom element
This gets rid of the need to enable/disable the keyboard handling
at various times.

Allows Ctrl-C to work as expected when selecting text in debug/info
sidebar.

Downside is shortcuts that apply to the workspace (select-all, copy
etc) now require the workspace to be focussed.
2016-05-08 22:50:55 +01:00
Nick O'Leary
8e6bba143a Escape regex chars in palette filter input 2016-05-08 20:55:13 +01:00
Nick O'Leary
feeba77f16 Remove console.log debug from tray 2016-05-06 17:20:25 +01:00
Nick O'Leary
ea41a0e842 Improve edit tray size handling for small screens 2016-05-06 17:19:56 +01:00
Dave Conway-Jones
74b7500181 Add javascript highlighter to template node
because it’s FF
2016-05-06 17:00:58 +01:00
Nick O'Leary
594ff8cd3d Add support for loading scoped node modules
Fixes #885
2016-05-06 10:16:41 +01:00
Nick O'Leary
337f5f9b98 Handle missing tab nodes in a loaded flow config 2016-05-04 22:09:11 +01:00
Nick O'Leary
41445a1b48 Merge branch 'config' into 0.14.0
explain why this merge is necessary,
2016-05-04 15:44:48 +01:00
Nick O'Leary
269763fa0c Allow workspace tabs to be re-ordered 2016-05-04 15:22:30 +01:00
Nick O'Leary
fa90eeac55 Make all dialog buttons consistent with editor tray 2016-05-03 21:36:22 +01:00
Nick O'Leary
edceffdaaf Ensure typedInput dropdown doesn't fall off the page 2016-05-03 17:01:45 +01:00
Nick O'Leary
ce25fc658b Move edit tray buttons to top 2016-05-03 15:45:29 +01:00
Dave Conway-Jones
b27db3e2e7 tiny changes to JSON and exec test for node6
no need to specify npm2 defaults are ok now. (on travis)
2016-04-30 17:05:10 +01:00
Dave Conway-Jones
622d4214f7 Let's try that node6 thing again... 2016-04-29 10:00:14 +01:00
Nick O'Leary
0c53b5310a Protect against node types with reserved names such as toString
Fixes #880
2016-04-28 14:17:48 +01:00
Nick O'Leary
45ff86eae5 Do not rely on the HTML file to identify where nodes are registered from 2016-04-28 11:23:42 +01:00
Dave Conway-Jones
47316b0fb7 Merge branch 'master' into 0.14.0 2016-04-27 23:22:37 +01:00
Dave Conway-Jones
c09be02e4e small fix to exec node test 2016-04-27 22:54:00 +01:00
Dave Conway-Jones
bd59398cab Add optional timeout to exec node
(both exec and spawn modes)
and add test for it (both exec and spawn)
also extra test for trigger node.
2016-04-27 22:32:58 +01:00
Nick O'Leary
8080ebceb4 Fix linting error on Flow.js 2016-04-27 12:37:20 +01:00
Nick O'Leary
1e2521c37a Add TLS node and update MQTT/HTTP nodes to use it 2016-04-27 12:33:02 +01:00
Nick O'Leary
b744491dd2 Ensure config nodes are instantiated in the right order 2016-04-27 12:33:02 +01:00
Nick O'Leary
2a089f7d90 Ensure parent nodes marked as changed due to child config node changes 2016-04-27 12:33:02 +01:00
Nick O'Leary
088e3e5374 Validate all edit dialog inputs when one changes 2016-04-27 12:33:02 +01:00
Nick O'Leary
bac8a3092f Recursively validate nodes after editing config node directly 2016-04-27 12:33:02 +01:00
Nick O'Leary
e56da17957 Disable keyboard shortcuts when editing a config node 2016-04-27 12:33:01 +01:00
Nick O'Leary
71b2e714ee Allow config select input to override default width 2016-04-27 12:33:01 +01:00
Nick O'Leary
1b06afb81c Preserve node properties on import 2016-04-27 12:33:01 +01:00
Nick O'Leary
819e48b03a Enable config nodes to reference other config nodes 2016-04-27 12:33:01 +01:00
Nick O'Leary
1861c1feb6 Restore tray size properly when maximised 2016-04-27 12:33:01 +01:00
Nick O'Leary
0efccc4758 Add quick resize buttons to tray 2016-04-27 12:33:01 +01:00
Nick O'Leary
a9feeaa1c9 Make tray resizble and remember size per-node-type 2016-04-27 12:33:01 +01:00
Nick O'Leary
f9c869f521 Refresh node info when edit tray closes 2016-04-27 12:33:01 +01:00
Nick O'Leary
9c766d76f3 Resize tray on create to ensure proper size 2016-04-27 12:33:01 +01:00
Nick O'Leary
333acccff6 Add subflow dialogs to the tray 2016-04-27 12:33:01 +01:00
Nick O'Leary
1790ebf567 Update info sidebar as trays open/close 2016-04-27 12:33:01 +01:00
Nick O'Leary
6354b68bae Config node tray 2016-04-27 12:33:01 +01:00
Nick O'Leary
41b10fd5e4 Add new style tray editor 2016-04-27 12:33:01 +01:00
Dave Conway-Jones
4ad540412a trigger node, fix send last message ...
(if extend not selected).
2016-04-24 21:24:15 +01:00
Dave Conway-Jones
8916cf273e Let trigger node also send last payload to arrive
and add test for it.
2016-04-24 17:42:24 +01:00
Dave Conway-Jones
b2923d0fc4 enhance a couple of tests to check more
Delay node checks  times properly for both types of queue. And File
checks to make sure other payload types are handled (a bit better than
they were)
2016-04-24 17:41:22 +01:00
Dave Conway-Jones
8fc0018cb9 Fix regression in delay node.
topic based queue was emptying all the time instead of spreading out
messages.
2016-04-24 11:08:58 +01:00
Dave Conway-Jones
d0f57efe0b test a few extra paths in several nodes
trigger, switch and file
(and linted delay just because)
2016-04-23 21:06:48 +01:00
Dave Conway-Jones
595ff63b72 Fix exec test for v0.10
Back out nvm 6 in travis (not there yet)
2016-04-23 17:41:56 +01:00
Dave Conway-Jones
9990046abb get more debug from travis for exec test
Don’t have v.10 locally.
And a,y as well try node v6 also ;-)
2016-04-23 17:29:31 +01:00
Dave Conway-Jones
8dacf72b3c try to increase coverage for exec and template nodes
(works locally - may fail on travis - lets see…)
2016-04-23 17:09:46 +01:00
Nick O'Leary
2801838ffa Throw an error if a Function node adds an input event listener 2016-04-21 22:25:47 +01:00
Dave Conway-Jones
59b34c2b3f Add timestamp as a default typedInput
and update Inject and change nodes to match,
and add some tests.
2016-04-18 14:38:36 +01:00
Nick O'Leary
f55f85aa14 Fix debug toolbar button sizes 2016-04-18 14:08:07 +01:00
Nick O'Leary
627a80419a Fix hang on partial deploy with disconnected mqtt node 2016-04-18 13:54:05 +01:00
Dave Conway-Jones
4bc482bc85 update load of grunt related versions
and mqtt and fs-extra and should. Fix tests to keep working.
2016-04-18 12:40:08 +01:00
Dave Conway-Jones
0a1257a23a Add Ace css support / remove swift 2016-04-18 12:38:32 +01:00
Dave Conway-Jones
51d99248d7 update marked.min.js 2016-04-18 12:21:03 +01:00
Dave Conway-Jones
af9aa74337 Add process.env.PORT to settings.js as we said we would 2016-04-18 09:12:12 +01:00
Nick O'Leary
321f5e615b Activate link splice on node centre not mouse position 2016-04-17 21:28:56 +01:00
Nick O'Leary
95c31f3e17 Add option to filter debug by flow and highlight subflow-emitting nodes 2016-04-15 20:20:16 -07:00
Nick O'Leary
cf69dbe1dc TypedInput: preload type icons to ensure width calc correct 2016-04-13 18:10:04 -07:00
Nick O'Leary
e92241bf97 Resize change node rules when they are added 2016-04-13 18:09:41 -07:00
Nick O'Leary
44dc37ef6d Add qos option to MQTT In node 2016-04-11 08:49:50 -07:00
Nick O'Leary
6b0bef61a5 Prompt for login if comms reconnect fails authentication 2016-04-11 08:49:49 -07:00
Nick O'Leary
0c227be02d Back off comms reconnect attempts after prolonged failures 2016-04-11 08:49:49 -07:00
Dave Conway-Jones
08794bad74 Add tests for Change node move function 2016-04-10 15:55:05 +01:00
Nick O'Leary
44693dd23a Enable finer grained permissions in adminAuth 2016-04-10 15:30:13 +01:00
Nick O'Leary
75a7be41eb Better notification message when action is not permitted 2016-04-10 15:30:13 +01:00
Dave Conway-Jones
913b09570c ensure tcp node creates a buffer of size 1 at least 2016-04-10 12:21:56 +01:00
Dave Conway-Jones
1c9b5dfd00 add status to exec spawn mode 2016-04-10 12:21:07 +01:00
Dave Conway-Jones
2954ae917b Add Move capability to change node 2016-04-10 12:20:46 +01:00
Dave Conway-Jones
736ddaeca4 Update Ace Editor 2016-04-10 12:19:59 +01:00
Gabe Johnson
b909e32201 Prevent RED.node.registerNode from overriding a constructor's prototype (#865)
* prevent registry.registerNodeConstructor from overriding a constructors protoype

* fix for node < v5.0.0

* exercise another code path

* altering __proto__ for node < v0.12

* move inheritance code to helper function
2016-04-07 22:18:28 +01:00
Nick O'Leary
bcff74327b Add CoC.md 2016-04-07 21:51:12 +01:00
Nick O'Leary
e60b63e72f Update to CoC 1.4 2016-04-07 21:13:40 +01:00
Nick O'Leary
2bf5d2b4e5 Adopt Contributor Covenant 1.2 2016-04-07 20:49:44 +01:00
Nick O'Leary
e1d09349ff Add link nodes 2016-04-07 17:08:51 +01:00
Nick O'Leary
f07c8108fc Change style of nodes in subflow template view 2016-04-07 16:28:04 +01:00
Nick O'Leary
39f5078d6b Return editorTheme default if value is undefined 2016-04-04 22:30:19 +01:00
Nick O'Leary
1d54761d48 Fix comparison of Buffers (again) 2016-04-01 10:32:11 +01:00
Nick O'Leary
7cb9b2da66 Use Buffer.equals not Buffer.compare for node 4+ 2016-04-01 10:23:00 +01:00
Nick O'Leary
b1896e3737 Fix RED.util.compareObjects for Function created objects and Buffers 2016-04-01 10:13:11 +01:00
Dave Conway-Jones
6fa78bdb04 bump serial port version number
uses typed widget to support other baud rates
2016-04-01 08:56:28 +01:00
Nick O'Leary
ee96f7d937 Fix closing tag in index.mst 2016-03-30 08:59:36 +01:00
Nick O'Leary
129ca0e39f bump version 2016-03-21 11:02:09 +00:00
Dave Conway-Jones
906703db5f Add timed release mode to delay node 2016-03-20 17:46:12 +00:00
Nick O'Leary
0cd4a2b4ec Add api/flow_spec tests
Part of #840
2016-03-18 21:01:21 +00:00
Nick O'Leary
aef8aaa0bd Enable link splicing for when import_dragging nodes
Closes #811
2016-03-17 11:12:45 +00:00
Nick O'Leary
428fbb8622 Fix uncaught exception on deploy whilst node sending messages 2016-03-16 15:37:44 +00:00
Nick O'Leary
b9f03e7d80 Deprecate old mqtt client and connection pool modules 2016-03-16 11:15:30 +00:00
Nick O'Leary
db686388b9 Fix registry test for Node 5 2016-03-16 11:05:10 +00:00
Nick O'Leary
626cba4002 Change node: add bool/num types to change mode
Closes #835 #835 #835
2016-03-13 23:10:10 +00:00
Nick O'Leary
37d4a6b9e2 Validate fields that are $(env-vars)
Closes #825
2016-03-13 14:29:36 +00:00
Nick O'Leary
12c4561aba Handle missing config nodes when validating node properties 2016-03-13 13:25:59 +00:00
Dave Conway-Jones
fed49e3718 pi node - don't try to send data if closing 2016-03-13 10:58:22 +00:00
Nick O'Leary
3af37d3984 Load node message catalog when added dynamically 2016-03-12 22:53:07 +00:00
Nick O'Leary
0f49a11228 Split palette labels on spaces and hypens when laying out 2016-03-12 22:41:23 +00:00
Nick O'Leary
27d3e165b0 Message catalog updates for zero-length flow file handling 2016-03-12 00:04:27 +00:00
Nick O'Leary
e941c22f6c Warn if editor routes are accessed but runtime not started
Closes #816
2016-03-12 00:03:50 +00:00
Nick O'Leary
7281e4deb6 Add zero-length flow file tests 2016-03-11 22:58:11 +00:00
Nick O'Leary
f2191e94b3 Better handling of zero-length flow files
Closes #819

If a flow file is found to be zero-bytes:
  If there is a non-empty backup, restore the backup and resolve
  If there is no backup or it is also empty, resolve empty flow
If a flow file is found to be invalid json:
  Log and resolve empty flow
2016-03-11 22:42:04 +00:00
Dave Conway-Jones
349ebfe4db remove extra brace added to library.js in error 2016-03-06 20:54:46 +00:00
Nick O'Leary
708365c4ac Allow runtime calls to RED._ to specify other namespace 2016-03-06 20:43:19 +00:00
Dave Conway-Jones
0e9ea0aff1 Replace - & _ from example node name labels with space
and align lines (ocd)
2016-03-05 17:07:39 +00:00
Dave Conway-Jones
63ba05a193 Better right alignment of numerics in delay and trigger nodes 2016-03-04 10:12:07 +00:00
Nick O'Leary
4b702815cf Strip node-red-contrib/node- prefix from Example menu labels 2016-03-03 11:02:37 +00:00
Nick O'Leary
55e66ebcac Allow node modules to include example flows 2016-03-02 23:34:24 +00:00
Nick O'Leary
dcd8b3699c Create node_modules in userDir
This ensures npm install puts modules under .node-red even if there's
already a node_modules dir in the parent directory.
2016-03-01 22:08:37 +00:00
Nick O'Leary
0e2d13172a Ensure errors in node def funcs don't break view rendering
Fixes #815

 - also fixes errors in the Catch/Status node label funcs #815
2016-03-01 21:58:57 +00:00
Nick O'Leary
2e2556fdad Merge pull request #805 from aryehof/InjectInfoUpdate
Updated Inject node info with instructions for flow and global options
2016-02-26 14:07:21 +00:00
Nick O'Leary
859a7538e1 Fix crash on repeated inject of invalid json payload 2016-02-26 10:35:15 +00:00
Dave Conway-Jones
0d1543ee8a Add tail node binary mode test 2016-02-25 08:52:43 +00:00
Dave Conway-Jones
d3a98dd355 Add binary mode to tail node 2016-02-24 23:06:27 +00:00
Dave Conway-Jones
ad10125303 revert Cheerio to somewhat smaller version 2016-02-23 09:47:49 +00:00
Dave Conway-Jones
b89e866d39 Add os/platform info to default debug 2016-02-22 17:47:16 +00:00
Dave Conway-Jones
afbaf1cfe0 make sample node info consistent <code> 2016-02-22 17:46:14 +00:00
Dave Conway-Jones
b3be8b30e7 remove direction flag from delay node 2016-02-22 17:45:28 +00:00
Aryeh Hoffman
8bfab8f73d Updated Inject node info with instructions for flow and global options 2016-02-21 18:17:05 +02:00
Nick O'Leary
c6ad2c9ad2 Don't force reconnect mqtt client if message arrives
Fixes the annoying mqtt connect/disconnect cycle
2016-02-19 22:52:43 +00:00
Nick O'Leary
3b44d9972e Bump package version 2016-02-19 21:21:22 +00:00
Nick O'Leary
af736c98f2 Add -p/--port option to override listening port 2016-02-19 21:18:50 +00:00
Nick O'Leary
f1377fa217 Invert toggle button colours so state is more obvious 2016-02-18 10:28:22 +00:00
Dave Conway-Jones
2ba146b9ff Add timeout to httprequest node
and override 2 min default in settings.js.
to Close #801
2016-02-15 09:45:58 +00:00
Dave Conway-Jones
2361607aa3 file node info to same style as others 2016-02-14 13:45:14 +00:00
Nick O'Leary
86ffc80098 Tidy up spinner css 2016-02-14 11:52:33 +00:00
Dave Conway-Jones
7f6915eb59 tcp node add reply (to all) capability
if no _session present.
2016-02-12 13:17:50 +00:00
Dave Conway-Jones
d69bcad028 hardware, logic, storage nodes info updates
(and udp)
2016-02-12 13:17:21 +00:00
Dave Conway-Jones
4cb45e2712 parser node info updates 2016-02-12 13:16:28 +00:00
Dave Conway-Jones
b7a0ad703a io and analysis nodes info updates 2016-02-12 13:15:53 +00:00
Dave Conway-Jones
7610b9a975 core nodes info updates 2016-02-12 13:15:05 +00:00
Dave Conway-Jones
7d95f621df update UDP node info to be more correct. 2016-02-11 22:21:12 +00:00
Nick O'Leary
bba210e112 Allow the template node to be treated as plain text 2016-02-11 13:16:15 +00:00
Nick O'Leary
3a97e20bde Validate MQTT In topics
Fixes #792
2016-02-10 22:38:59 +00:00
Nick O'Leary
4fe7ea00b0 httpNodeAuth should not block http options requests
Fixes #793#793#793
2016-02-10 21:57:46 +00:00
Nick O'Leary
3ec8ecd4de Disable perMessageDeflate on WS servers
Workaround for this issue: https://github.com/websockets/ws/pull/632
as it has been fixed in the 1.x release that drops support for
node 0.10...
2016-02-10 21:43:37 +00:00
Dave Conway-Jones
401e65e852 Merge pull request #799 from natcl/patch-1
Fix typo in delay node: replaced ramdom to random
Thanks @natcl
2016-02-09 23:09:10 +00:00
Nathanaël Lécaudé
e7c5b691a0 More ramdom --> random 2016-02-09 18:03:27 -05:00
Nathanaël Lécaudé
9f3ea8da67 Fix typo in delay node: replaced ramdom to random 2016-02-09 17:57:50 -05:00
Nathanaël Lécaudé
d1269b441d Update index.mst 2016-02-08 09:20:43 -05:00
Nathanaël Lécaudé
7615743aa5 Update theme.js 2016-02-08 09:20:07 -05:00
Nathanaël Lécaudé
dcaa0eeea4 Add node-red-icon-black.svg file to header
Add node-red-icon-black.svg file to header, according to Safari's pinned tab icon spec.
See :
https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/pinnedTabs/pinnedTabs.html
2016-02-08 00:05:17 -05:00
Nathanaël Lécaudé
1d5e2f703e Create node-red-icon-black.svg 2016-02-08 00:01:19 -05:00
Dave Conway-Jones
4d84d624b1 clear trigger status icon on re-deploy 2016-02-04 22:13:08 +00:00
Nick O'Leary
633a6a0ee6 Fix inject test to use a proper type 2016-02-04 21:52:27 +00:00
Nick O'Leary
c7bcd3f438 Don't default inject payload to blank string 2016-02-04 21:43:18 +00:00
Dave Conway-Jones
d3a29a6f16 fix trigger tests 2016-02-04 21:22:52 +00:00
Dave Conway-Jones
827711ca89 Fix util jshint as we need the behaviour. 2016-02-04 21:21:57 +00:00
Dave Conway-Jones
76e98f74fa let new typed-inputs return correctly
0 now returns correct type for boolean and number when required.
2016-02-04 21:06:20 +00:00
Dave Conway-Jones
fb09f4b22d trigger node, add configurable reset
and make it do strings when it says so, and numbers if you want.
2016-02-04 21:05:15 +00:00
Dave Conway-Jones
bb06585748 another tidy up on Pi GPIO node 2016-02-03 21:10:44 +00:00
Nick O'Leary
c76ba1dcc7 Allow function properties in settings
Fixes #790
2016-01-29 11:56:16 +00:00
Nick O'Leary
a115301b04 Fix order of config dialog calls to save/creds/validate 2016-01-29 11:56:16 +00:00
Dave Conway-Jones
72917117a9 Add debounce to Pi GPIO node 2016-01-25 09:56:35 +00:00
Nick O'Leary
6567739236 Bump version 2016-01-21 22:20:18 +00:00
Nick O'Leary
4aa6b47c0e Revert wrapping of http requestion object
Fixes #787
2016-01-21 22:15:25 +00:00
Nick O'Leary
03558b012c Bump version and dependencies 2016-01-18 11:09:52 +00:00
Nick O'Leary
3288efdad6 Remove unimplemented flow.enable/disable functions 2016-01-18 10:53:50 +00:00
Dave Conway-Jones
3902a343f3 Add ports in use warning to udp node
to close #786
Thanks @hugobox
2016-01-17 10:34:40 +00:00
Dave Conway-Jones
882b7d0391 change settings.js example to octalbonescript 2016-01-16 13:58:24 +00:00
Nick O'Leary
81f082825d Add 'previous value' option to Switch node 2016-01-15 11:35:59 +00:00
Nick O'Leary
392fd6fed3 Allow existing nodes to splice into links on drag 2016-01-14 15:59:45 +00:00
Nick O'Leary
51afed4041 Ensure config list refreshes properly on tab delete 2016-01-14 15:22:00 +00:00
Nick O'Leary
17e3b71d9c Allow update of global flow 2016-01-14 14:57:13 +00:00
Nick O'Leary
6e75089f3a CORS not properly configured on multiple http routes
Fixes #783
2016-01-13 12:54:34 +00:00
Nick O'Leary
6dc640b129 Add hidden count when config node filtered 2016-01-13 10:30:24 +00:00
Nick O'Leary
27cbaac343 Restore shift-drag to snap/unsnap to grid 2016-01-13 09:16:24 +00:00
Nick O'Leary
fa4006619e Make debug/config sidebar headers consistent 2016-01-12 23:55:18 +00:00
Nick O'Leary
cb8fe8462a Moving nodes with keyboard should flag workspace dirty 2016-01-12 23:08:13 +00:00
Nick O'Leary
abd51a5511 Notifications flagged as fixed should not be click-closable 2016-01-12 23:06:18 +00:00
Nick O'Leary
a0cc1e6b0c Add config node filter 2016-01-12 23:03:33 +00:00
Nick O'Leary
50399c6bfa Rework config sidebar and deploy warning 2016-01-12 17:54:53 +00:00
Nick O'Leary
de48c1be44 Wrap http request object to match http response object 2016-01-11 22:35:31 +00:00
Nick O'Leary
0786ec4b66 Move typedInput icons and update boolean 2016-01-11 21:24:35 +00:00
Nick O'Leary
db319e0ebc Ensure global context is seeded properly 2016-01-11 11:28:01 +00:00
Nick O'Leary
4fc568856a Clear link_splice style on drag end 2016-01-11 11:00:54 +00:00
Nick O'Leary
4c6771669b Fix palette node link splicing on Firefox 2016-01-10 22:25:20 +00:00
Nick O'Leary
9bca2a91c9 Tidy up view menu 2016-01-10 21:25:05 +00:00
Nick O'Leary
66eaaf5a48 Add 'view' menu and reorganise a few things 2016-01-09 20:39:03 +00:00
Nick O'Leary
9837f0e2e1 Highlight node port when dragging wires and undash the wires 2016-01-09 13:47:05 +00:00
Nick O'Leary
6b8ffb4c68 Fix lint issues in view 2016-01-09 00:31:05 +00:00
Nick O'Leary
f35dd34da9 Allow shift-click to detach existing wires 2016-01-09 00:29:04 +00:00
Nick O'Leary
ed19e4fa08 Splice nodes dragged from palette into links 2016-01-08 22:34:10 +00:00
Dave Conway-Jones
661e1a4f90 try to trim imported/dragged flows to [ ] 2016-01-08 19:54:16 +00:00
Nick O'Leary
5826de76ca Make dragging nodes from the palette line up better 2016-01-08 14:42:05 +00:00
Nick O'Leary
05888740e5 Update jquery version to 0.11.3 2016-01-08 14:41:37 +00:00
Nick O'Leary
41f3b0c333 Fix variable leak in theme.js 2016-01-08 13:41:33 +00:00
Nick O'Leary
70f3e72a20 Move version number as title of NR logo 2016-01-08 13:36:49 +00:00
Nick O'Leary
e873afd40b Moving nodes mark workspace as dirty 2016-01-08 11:08:48 +00:00
Nick O'Leary
2777c2937a Make version number slightly darker 2016-01-07 22:29:20 +00:00
Nick O'Leary
798903e4cc Move layout menu down one position 2016-01-07 22:28:03 +00:00
Nick O'Leary
58622ba18f Attach dialog close handlers to dialog parents 2016-01-07 20:08:31 +00:00
Nick O'Leary
c368dcd5b7 Ok/Cancel edit dialogs with Ctrl-Enter/Escape 2016-01-07 17:10:59 +00:00
Nick O'Leary
0b4c652ce7 Add version number of sidebar footer 2016-01-07 16:42:10 +00:00
Nick O'Leary
dbaacc411a Handle OSX Meta key when selecting nodes 2016-01-07 15:09:14 +00:00
Nick O'Leary
1850185d1e Add grid-alignment options 2016-01-07 14:39:01 +00:00
Nick O'Leary
2e9d445d36 Add oneditresize function definition 2016-01-06 17:01:14 +00:00
Nick O'Leary
aed89d82fb Fix template test 2016-01-06 17:01:14 +00:00
Nick O'Leary
231adac6d8 Rename typedInput.options 2016-01-06 17:01:14 +00:00
Nick O'Leary
587c4e5915 Update template node to use typedInput 2016-01-06 17:01:14 +00:00
Nick O'Leary
55f1cbf18f Ensure inject payload exists 2016-01-06 17:01:13 +00:00
Nick O'Leary
38168a545b Update Inject node to use typedInput 2016-01-06 17:01:13 +00:00
Nick O'Leary
43c6df49d7 Update typedInput nls 2016-01-06 17:01:13 +00:00
Nick O'Leary
f1c59faf72 Rename propertySelect to typedInput and add boolean opt 2016-01-06 17:01:13 +00:00
Nick O'Leary
5f7019325c Update switch/change help text to reflect updates 2016-01-06 17:01:13 +00:00
Nick O'Leary
fe4dae8518 Add propertySelect to switch node 2016-01-06 17:01:13 +00:00
Nick O'Leary
1f848b205b Add propertySelect support to Change node 2016-01-06 17:01:13 +00:00
Nick O'Leary
742c470d81 Add context/flow/global support to Function node 2016-01-06 17:01:13 +00:00
Nick O'Leary
5ead3342cc Add node context/flow/global 2016-01-06 17:01:13 +00:00
Nick O'Leary
b95dc2ecce Add propertySelect jquery widget 2016-01-06 17:01:13 +00:00
Nick O'Leary
4d0950215f Don't allow tabs or subflows to be added with new flow 2016-01-06 17:01:13 +00:00
Nick O'Leary
da0ce9fe0d Simplify flow api implementation and add logging messages 2016-01-06 17:01:13 +00:00
Nick O'Leary
ca62e720b5 Add missing spec file 2016-01-06 17:01:13 +00:00
Nick O'Leary
c4b1795396 Add add/update/delete flow apis 2016-01-06 17:01:13 +00:00
Nick O'Leary
fd2e47ed73 WIP: add flow api 2016-01-06 17:01:12 +00:00
Nick O'Leary
d5f2255a68 Handle null coreNodesPath 2016-01-06 17:01:12 +00:00
Nick O'Leary
05b58e9263 Allow core nodes dir to be provided to runtime via settings 2016-01-06 17:01:12 +00:00
Nick O'Leary
4a91c27e4b Allow server to be option on red.init 2016-01-06 17:01:12 +00:00
Nick O'Leary
3a03d46d8d Fix lint error in registry.js 2016-01-06 17:01:12 +00:00
Nick O'Leary
f03aff7006 Tidy up API passed to node modules 2016-01-06 17:01:12 +00:00
Nick O'Leary
043b8a3105 Register node message catalog directly, not via event 2016-01-06 17:01:12 +00:00
Nick O'Leary
1dd9984521 Pickup default language from i18n module 2016-01-06 17:01:12 +00:00
Nick O'Leary
d2be7f8c8f Move locale files under api/runtime components 2016-01-06 17:01:12 +00:00
Nick O'Leary
88dc202db2 Fix node test helper for api/runtime changes 2016-01-06 17:01:12 +00:00
Nick O'Leary
083d54b008 Add unit test for flow reload api 2016-01-06 17:01:11 +00:00
Nick O'Leary
87d77efa57 Add flow reload admin api 2016-01-06 17:01:11 +00:00
Nick O'Leary
35c4a41d7b Node id generation should only be done in runtime/util 2016-01-06 17:01:11 +00:00
Nick O'Leary
1ca3ca07d5 api/nodes accessing comms module incorrectly 2016-01-06 17:01:11 +00:00
Nick O'Leary
d673846e3d WIP: runtime api for node modules 2016-01-06 17:01:11 +00:00
Nick O'Leary
f62b7afede Remove all uses of fs.exists as it is deprecated
The tests still use it in places - particular localfilesystem tests,
but those tests need to be redone with sinon stubbing in place and
not rely on real fs operations.
2016-01-06 17:01:11 +00:00
Nick O'Leary
e65770a53a Add missing test resources
They were ignored as they have node_modules in the path...
2016-01-06 17:01:11 +00:00
Nick O'Leary
a92a741932 Fix incorrect async test completion 2016-01-06 17:01:11 +00:00
Nick O'Leary
45f67191ba Improve node registry test coverage 2016-01-06 17:01:11 +00:00
Nick O'Leary
93f5da325b Fix node test helper for runtime/api changes 2016-01-06 17:01:11 +00:00
Nick O'Leary
8fb955e182 Move comms from runtime to api component 2016-01-06 17:01:11 +00:00
Nick O'Leary
9f5e6a4b37 Update tests for runtime/api separation 2016-01-06 17:01:11 +00:00
Nick O'Leary
f43738446e WIP: separate runtime and api components 2016-01-06 17:01:11 +00:00
Nick O'Leary
923a46d304 Bump version 0.12.5 2016-01-06 16:55:38 +00:00
Dave Conway-Jones
b9b5eaccae better handle utf8 file output chars 2016-01-06 12:27:47 +00:00
Dave Conway-Jones
cda11491c2 bump sentiment node npm prereq 2016-01-06 12:27:47 +00:00
Nick O'Leary
98c539f662 Refresh active nodes when node properties change 2016-01-04 22:05:17 +00:00
Dave Conway-Jones
9fb958b302 close tcp node connection properly when required. 2015-12-23 20:01:05 +00:00
Dave Conway-Jones
8e25e76439 Add hint re servos to Pi GPIO node info 2015-12-23 11:50:47 +00:00
Nick O'Leary
62694da7e6 Ensure last mqtt node turns off the lights before closing
The mqtt-broker node disconnects when the last node using it
is closed. But that node-close was not waiting for the disconnect
to complete. This led to a race-condition where the using node
was recreated and started trying to use the broker node whilst it
was still disconnecting.
2015-12-22 23:31:22 +00:00
Dave Conway-Jones
86064651af Add Pi Keyboard code node 2015-12-21 10:27:58 +00:00
Dave Conway-Jones
65daaeb617 add attribute test to HTML parser node tests 2015-12-19 14:30:43 +00:00
Dave Conway-Jones
08b39f50b3 Add attribute capability to HTML parser node 2015-12-19 12:44:11 +00:00
Nick O'Leary
d0f7e5ca4d Bump version 0.12.4 2015-12-14 10:01:10 +00:00
Nick O'Leary
4eb5058e68 Add readOnly setting to prevent file writes in localfilesystem storage 2015-12-13 22:45:44 +00:00
Nick O'Leary
1054193298 Update example httpNodeAuth setting to be bcrypt 2015-12-13 21:27:57 +00:00
Nick O'Leary
38c6cf0450 Support bcrypt for httpNodeAuth 2015-12-13 20:46:27 +00:00
Dave Conway-Jones
5b04b86867 remove extraneous s from GPIO node... 2015-12-12 15:18:17 +00:00
Dave Conway-Jones
a074bcfd56 Pi no longer needs root workaround to access gpio
(stops PAM logging in Node-RED log under systemd)
2015-12-12 15:13:15 +00:00
Nick O'Leary
f93179d946 Rename library filename field to avoid id clash
Fixed #767
2015-12-12 12:57:33 +00:00
Nick O'Leary
2c347bc092 Bump version for 0.12.3 2015-12-11 22:02:37 +00:00
Dave Conway-Jones
0f7119f468 TCPget don't send nun msg on disconnect
(as we now send status anyway)
2015-12-11 14:17:50 +00:00
Dave Conway-Jones
2685a24705 Let TCPget node pass through other msg properties 2015-12-11 14:07:20 +00:00
Nick O'Leary
371f72f4f1 Skip delay node burst test 2015-12-11 14:04:24 +00:00
Nick O'Leary
c70c00043b Attached admin route before node route security 2015-12-11 13:42:44 +00:00
Nick O'Leary
50d0a88276 Ensure tabs are removed from runtime on partial deploy 2015-12-10 15:47:15 +00:00
Dave Conway-Jones
5bbf576dae set fa-icons perms 644 not 755... 2015-12-10 13:57:54 +00:00
Nick O'Leary
5d334e9619 Clarify auth settings in default settings.js 2015-12-10 13:20:58 +00:00
Dave Conway-Jones
98f9353338 bump serial port package dependency version. 2015-12-10 13:11:14 +00:00
Nick O'Leary
d3de7037e5 Move HTTPRequest node to its own file 2015-12-10 12:58:50 +00:00
Nick O'Leary
64431c6711 Ensure node.ports is properly intialised
Fixes #766
2015-12-10 10:46:12 +00:00
Dave Conway-Jones
d4ce193dc8 Fix trigger to block properly until reset
Fix to Close #764
2015-12-09 16:42:16 +00:00
Dave Conway-Jones
606305aec4 Bump FA-Icons to v4.5 2015-12-09 15:38:37 +00:00
Dave Conway-Jones
a95f44d68b remove annoying comma from comm.js
OCD reasons only
2015-12-09 13:37:20 +00:00
Dave Conway-Jones
ef2dc4b9e1 One more tidy up for tcp node 2015-12-07 22:39:42 +00:00
Dave Conway-Jones
9baca1772b Close tcp port for tcpin node (same as previous fix but for input) 2015-12-07 22:39:42 +00:00
Nick O'Leary
04cd19349d Don't reuse node-edit dialog for library export ui
Fixes #762
2015-12-07 22:15:14 +00:00
Dave Conway-Jones
1280e5bc8b Close tcp out node more forcibly. (and update status) on redeploy. 2015-12-07 17:41:51 +00:00
Dave Conway-Jones
dda90f956d Clear delay node status on re-deploy. (rate limit path) 2015-12-02 15:37:36 +00:00
Dave Conway-Jones
bc4b599513 Fix udp socket creation error on node v0.10 2015-12-01 14:52:15 +00:00
Dave Conway-Jones
090d52d678 narrowing in on tcpget fix, reconnect but don't resend.
to address issue #759
2015-12-01 13:41:39 +00:00
Dave Conway-Jones
a47ad4842a Clean up tcpget node connected status.
to address #759
2015-11-30 22:05:26 +00:00
Nick O'Leary
3d5ed840dc Bump version for 0.12.2 2015-11-28 20:32:19 +00:00
Nick O'Leary
11d75ff581 Inject time spinner incrementing value incorrectly 2015-11-26 09:56:49 +00:00
Nick O'Leary
306fb7a3d1 Kill processes run with exec node when flows redeployed 2015-11-24 23:09:44 +00:00
Nick O'Leary
0839b6f58e Debug node not handling null messages 2015-11-24 23:09:32 +00:00
Nick O'Leary
fceca703b3 Update tcp node status on reconnect after timeout
Closes #757
2015-11-24 22:40:39 +00:00
Nick O'Leary
4dc60d2477 Clarify debug rate limit method 2015-11-21 21:30:03 +00:00
Nick O'Leary
d840d0b67d Fix mqtt node lifecycle with partial deployments 2015-11-17 22:19:56 +00:00
Dave Conway-Jones
43dad4c465 ensure udp socket bind works more often 2015-11-16 08:38:22 +00:00
Dave Conway-Jones
60812b2d8a fix udp node messages
(timing issue still outstanding)
2015-11-16 00:25:26 +00:00
Nick O'Leary
35e2caff13 Handle errors thrown in Function node setTimeout/Interval 2015-11-15 22:22:17 +00:00
Nick O'Leary
1d9d5c6bc7 Add node 5 to travis 2015-11-14 21:32:28 +00:00
Nick O'Leary
4d99536ea7 Function setTimeout/Interval wrapper not returing timer id
Fixes #753
2015-11-14 21:21:14 +00:00
Nick O'Leary
34537180c3 Fix basic authentication on httpNode/Admin/Static 2015-11-10 15:44:48 +00:00
Nick O'Leary
cb01920ee6 Allow nodes to be installed by path name 2015-11-09 16:52:14 +00:00
Nick O'Leary
437b01a0ff Move node installer to its own module 2015-11-09 11:29:48 +00:00
Nick O'Leary
075a2abf71 Use child_process.execFile to prevent command injection 2015-11-08 14:26:11 +00:00
Nick O'Leary
985875cc75 Move node install/remove from server component to node engine 2015-11-08 14:06:36 +00:00
Nick O'Leary
1c45bc615f Enable touch-menu for links so they can be deleted 2015-11-06 16:46:07 +00:00
Nick O'Leary
fa7f2606fb bump version 2015-11-06 13:42:00 +00:00
Nick O'Leary
12b95f1c72 Enable config node dialog to have editor ui 2015-11-06 11:08:07 +00:00
Nick O'Leary
a0aee2021d Tidy up sheets/flows labelling 2015-11-05 14:22:15 +00:00
Nick O'Leary
c90fd1e6d8 Move credential http API handling to api component 2015-11-04 11:13:43 +00:00
Dave Conway-Jones
3b769fd2de add bash directive to nrgpio script 2015-11-04 08:42:00 +00:00
Nick O'Leary
71ecb89abc Merge branch 'flowengine' 2015-11-03 20:24:55 +00:00
Nick O'Leary
7b6bc1d3bc Increase default api request limit to 1mb
- expose it via settings.apiMaxLength
 - audit log api errors
2015-11-03 11:23:37 +00:00
Nick O'Leary
9c3be40fbe Automatically clear timeouts/intervals set in Function node
closes #744
2015-11-03 10:47:29 +00:00
Nick O'Leary
ab87fa9ce4 Ensure status/errors from global config nodes propagate properly 2015-11-03 10:20:00 +00:00
Nick O'Leary
d1940a023a Complete test coverage on flow engine refactor 2015-11-02 15:58:40 +00:00
Nick O'Leary
5a176a037c Update test helper for refactored flow engine 2015-11-02 15:58:40 +00:00
Nick O'Leary
ec25191c98 Flow Engine refactor
Each flow/tab now exists as its own logical object. This is the ground
work for allowing flows to be added/removed/updated independently.
2015-11-02 15:58:29 +00:00
Nick O'Leary
20b321f928 Handle null subflow info property 2015-10-26 11:12:49 +00:00
Dave Conway-Jones
425b016d63 Add missing space to label in delay node 2015-10-26 09:42:16 +00:00
Nick O'Leary
b2c7189ce4 Update package dependencies 2015-10-25 21:36:20 +00:00
Nick O'Leary
f66886dbdb Websocket input node not unsubscribing properly
Fixes #739
2015-10-23 23:01:25 +01:00
Nick O'Leary
712f8b4680 Add description field to Subflows 2015-10-23 22:14:39 +01:00
Nick O'Leary
f626ee060a Allow properties to be specified by environment variables
A property set to $(ABC) will be substituted with the environment
variable ABC - if it exists. If the property doesn't exist, the property
is left unchanged.
2015-10-23 22:14:39 +01:00
Dave Conway-Jones
86aa7c97be Make exec node status indication consistent with others 2015-10-22 19:02:22 +01:00
Dave Conway-Jones
30e3525987 Add status icon to trigger node while it is active 2015-10-22 16:27:07 +01:00
Dave Conway-Jones
ad44f838da update sample to refer to fa-icons 2015-10-20 19:30:42 +01:00
Dave Conway-Jones
2569a35b6c fix closing web socket timeout
to close #738 - thanks to @GSeva for spotting it.
2015-10-20 18:58:37 +01:00
Dave Conway-Jones
1ee5e50d50 Turn on tcp node socket keepalive when in server mode 2015-10-20 10:13:48 +01:00
Dave Conway-Jones
1dbec5eca8 slight tidy of Pi Mouse node 2015-10-20 10:02:57 +01:00
Nick O'Leary
2bc8db308c Add missing tab-config file 2015-10-17 19:05:23 +01:00
Nick O'Leary
f196740426 Restore config node tab 2015-10-16 21:56:20 +01:00
Dave Conway-Jones
20121b79c5 Let CSV node handle null columns in input array. array-> csv 2015-10-16 20:42:25 +01:00
Nick O'Leary
741a4cfe53 Don't assume def.align is set to 'right'
Fixes #734
2015-10-15 14:27:30 +01:00
Dave Conway-Jones
0343de9f34 Add status capability to function node 2015-10-15 13:33:05 +01:00
Nick O'Leary
4772bca14a Undo 'selection to subflow' not restoring nodes 2015-10-15 11:34:17 +01:00
Dave Conway-Jones
6ae1a5ba0d let CSV obj->css allow blank columns in template 2015-10-15 08:31:42 +01:00
Dave Conway-Jones
217c9718e4 catch missing template error in CSV parser node
and update help info
2015-10-14 23:38:29 +01:00
Dave Conway-Jones
61d7893467 Enhance CSV node to accept simple arrays -> css 2015-10-14 23:07:25 +01:00
Dave Conway-Jones
8f26c01f4b fix escaping of quotes in CSV node 2015-10-14 11:02:31 +01:00
Dave Conway-Jones
61045ddd7f try to fix debug node non-standard object type handling. 2015-10-10 22:41:07 +01:00
Dave Conway-Jones
1bf72a0bc3 correct TCP node server status message 2015-10-09 15:44:22 +01:00
Dave Conway-Jones
6d84b1bb8d update inspect to come from correct package (util)
(works from v0.10 onwards - but now deprecated in v4)
2015-10-09 13:36:35 +01:00
Dave Conway-Jones
8abd0b1fdf Detect/set correct method for http proxy
to close #732 — thanks @utaani
2015-10-09 09:19:09 +01:00
Dave Conway-Jones
81e125b7ba add bit more help to exec node
Point out that parameters with spaces should be quoted
2015-10-05 21:41:53 +01:00
Dave Conway-Jones
d5e1468718 Normalise spawn behaviour in exec node to accept identical parameters
Can now just tick or untick spawn and command still works.
2015-10-05 21:17:35 +01:00
Nick O'Leary
c232bf5ed6 Avoid unnecessary isUtf8 check on HTTP payloads 2015-10-05 21:10:32 +01:00
Nick O'Leary
21b25ffaee Merge pull request #730 from jthomas/master
Allow HTTP nodes to handle non-UTF8 content.
2015-10-05 20:52:35 +01:00
Dave Conway-Jones
ca0a93df08 Add Node-RED sag icon to default images 2015-10-05 13:46:42 +01:00
James Thomas
699a22c757 Allow HTTP nodes to handle non-UTF8 content.
Setting UTF-8 as the default body encoding stops us sending binary
content, e.g. audio, which can be decoded into a Buffer.

Use "Content-Type" header to decide whether to decode as UTF-8 or a
Buffer.
2015-10-05 11:53:29 +01:00
Nick O'Leary
8b2b1669b5 Add ignore-case flag to Switch regex rule
closes #366
2015-10-04 22:14:49 +01:00
Dave Conway-Jones
c1e8370916 Lets spawn msg.payload contain comma separated parameters
(like rest of parameters passed in to spawn via edit dialogue)
Will also accept an array…
2015-10-04 19:22:33 +01:00
Nick O'Leary
ddedea8b90 Resize change/switch rules with the dialog 2015-10-03 22:30:28 +01:00
Nick O'Leary
8f414ce458 Update auth revoke test for express 4 2015-10-03 20:32:24 +01:00
Nick O'Leary
453f23da20 Move to node 4.x.x in travis 2015-10-03 09:15:11 +01:00
Nick O'Leary
9e91e42a1b Increase delay burst test timeout
The test was occasionally timing out, despite it succeeding. Increased
the timeout to give it a bit more safety margin to complete
2015-10-03 09:06:51 +01:00
Nick O'Leary
b666734c79 Update dependency versions 2015-10-02 22:13:15 +01:00
Nick O'Leary
a2297f303d Update config node user list when node edits are undone 2015-10-02 21:27:31 +01:00
Nick O'Leary
ecde942255 Wrap msg.req/res objects and add deprecated warnings to functions 2015-10-02 21:27:31 +01:00
Nick O'Leary
d668d43a0a Move to express 4.x 2015-10-02 21:27:31 +01:00
Nick O'Leary
ca91a5dd95 Rename flow menu ids back to workspace 2015-10-02 21:27:31 +01:00
Nick O'Leary
5f9780d71c Improve error message if settings file fails to load 2015-10-02 21:27:31 +01:00
Nick O'Leary
ee37464741 Copy settings file to userDir on start-up if it makes sense
It will only copy the file if:
 - a custom file hasn't been specified (-s file)
 - there isn't an existing settings.js file in userDir
 - the default settings file (in install dir) hasn't been
   modified (mtime < ctime)
2015-10-02 21:27:31 +01:00
Nick O'Leary
8d73f927db Debug output should use overridden toString method if set
Closes #690
2015-10-02 21:27:31 +01:00
Nick O'Leary
4a0222bd1c Warn if a node references an unknown config node type
Closes #709
2015-10-02 21:27:31 +01:00
Nick O'Leary
c0b8f5e3e1 Add tab info to deploy error messages 2015-10-02 21:27:31 +01:00
Nick O'Leary
a9a0b263dc Add undo support for config-node delete 2015-10-02 21:27:30 +01:00
Nick O'Leary
f2b73187d8 Name flows back to sheets in the ui 2015-10-02 21:27:30 +01:00
Nick O'Leary
ef10ade0cc Improve handling of imported config nodes
Avoid creating unnecessary duplicates of config nodes, whilst
honouring the scope of the any existing node.

Also, 'undo' now removes any added config node
2015-10-02 21:27:30 +01:00
Nick O'Leary
719bb4263e Ensure config nodes are deleted when owning subflow is deleted 2015-10-02 21:27:30 +01:00
Nick O'Leary
b3602b268e Have grunt dev restart on message catalog changes 2015-10-02 21:27:30 +01:00
Nick O'Leary
66ec9bae27 Add warning if HTTP In node is missing path config 2015-10-02 21:27:30 +01:00
Nick O'Leary
d96b6e77c0 Allow config nodes to be scoped to an individual Flow 2015-10-02 21:27:30 +01:00
Nick O'Leary
da64c018ac Make the comms link be more tolerant to temporarily blips 2015-10-02 21:27:30 +01:00
Nick O'Leary
f9fb97adf2 Undo subflow rename not updating corresponding tab/menu labels 2015-10-02 21:27:30 +01:00
Nick O'Leary
8316bc6480 Move config node users tip into body of dialog 2015-10-02 21:27:30 +01:00
Nick O'Leary
08021e039a Better favicon 2015-10-02 21:27:30 +01:00
Dave Conway-Jones
cc6e0937a0 initialise status.text to be blank string if not set.
(and change test to use .text rather than .message)
(not that it matters at this level of test)
2015-10-02 21:27:30 +01:00
Nick O'Leary
c1d694a97c Add birth message to MQTT node 2015-10-02 21:27:30 +01:00
Dave Conway-Jones
fcf4f40c36 add basic status node test 2015-10-02 21:27:30 +01:00
Nick O'Leary
380b03399c Update to latest MQTT module version 2015-10-02 21:27:29 +01:00
Nick O'Leary
c33d02c53f Ensure MQTT node cleansession/keepalive defaults are used 2015-10-02 21:27:29 +01:00
Nick O'Leary
fa5e37993e Update mqtt node options to include will/cleansession/keepalive 2015-10-02 21:27:29 +01:00
Richard Ruston
437b2d506b Update MQTT node to use MQTT.js 1.2 and enable secure connections 2015-10-02 21:27:29 +01:00
Dave Conway-Jones
4ed09f6431 update FA icons to v4.4.0 2015-10-02 21:27:29 +01:00
Nick O'Leary
0b98a6acf8 Ensure catch/status nodes marked changed when edited 2015-10-02 21:27:29 +01:00
Nick O'Leary
1d73c86cb2 Add scope to status node 2015-10-02 21:27:29 +01:00
Nick O'Leary
40fe0f3239 Test Node.status calls through to Flow.handleStatus 2015-10-02 21:27:29 +01:00
Nick O'Leary
d1ea689999 Update catch node help text 2015-10-02 21:27:29 +01:00
Nick O'Leary
a6644ad5ff Add status node 2015-10-02 21:27:29 +01:00
Nick O'Leary
658746d2a3 Allow flow file to be specified with grunt dev
For example: grunt dev --flowFile=flows.json
2015-10-02 21:27:29 +01:00
Nick O'Leary
cbdd4de630 Errors in subflows propagate up to nearest catch node 2015-10-02 21:27:29 +01:00
Nick O'Leary
00c612485b Fix jshint errors 2015-10-02 21:27:29 +01:00
Nick O'Leary
3a6192bf73 Catch node can target specific nodes 2015-10-02 21:27:28 +01:00
Nick O'Leary
c64b5c2850 Add subflow tab image 2015-10-02 21:27:28 +01:00
Nick O'Leary
fdbf079896 Clean up subflow editor
- new appearance of subflow tabs
 - input/output buttons now counters
 - allow multiple input wires to the same node when converting to subflow
 - ensure edit history is propagated properly to instance nodes
2015-10-02 21:27:28 +01:00
Dave Conway-Jones
d1a5395727 update test for JSON parser to include array 2015-10-02 19:46:29 +01:00
Dave Conway-Jones
83a3642c0e Allow JSON node to handle array type 2015-10-02 17:30:23 +01:00
Nick O'Leary
9932d34304 Fix XML parse test
Workaround to https://github.com/Leonidas-from-XIV/node-xml2js/issues/239
2015-09-29 14:39:07 +01:00
Nick O'Leary
7aa37a1976 Bump version 2015-09-29 10:17:45 +01:00
Dave Conway-Jones
fa42fbdab8 Let XML node options be set
let msg.options to set a lot more options if required
2015-09-26 13:47:14 +01:00
Nick O'Leary
caa83ac830 Merge pull request #724 from vielmetti/travis-node-4
Support for Node 4.0.0 and Travis CI testing for same
2015-09-25 23:02:49 +01:00
Nick O'Leary
3963fa9738 Allow a language catalog to be a partial catalog 2015-09-24 21:56:45 +01:00
Edward Vielmetti
005a98d020 Update for node 4 testing.
Changes to .travis.yml
Patch from @dceejay to make a test portable
Patch from @dceejay to correct a case where an int was expected
2015-09-23 15:27:45 -04:00
Dave Conway-Jones
9560dc9408 remove delay spinner upper limit
e.g. 65 secs is perfectly valid…
close #728
2015-09-22 15:06:58 +01:00
Nick O'Leary
4ac9a5edf0 Merge pull request #726 from vielmetti/patch-2
Bump uglify to 2.4.24 to address security advisory
2015-09-22 10:15:54 +01:00
Edward Vielmetti
37e62597ae Bump uglify to 2.4.24 to address security advisory
Noted in https://nodesecurity.io/advisories/uglifyjs_incorrectly_handles_non-boolean_comparisons
2015-09-20 01:21:21 -04:00
Dave Conway-Jones
90bfe378d0 Add mobile category to palette order 2015-09-16 22:35:17 +01:00
Dave Conway-Jones
ce22b494ec Update README to use svg badges
to close #720
Thanks to @scherwi for the tip
2015-09-08 21:47:57 +01:00
Nick O'Leary
f9e0420647 Fix http node method-override nls message id 2015-08-31 16:06:00 +01:00
Dave Conway-Jones
2fe568d9ba Fix TCP node sending data
(it’s for the children)
2015-08-17 17:15:44 +01:00
Dave Conway-Jones
2d4979df4d only set tcp timeout if needs setting. 2015-08-15 22:16:48 +01:00
Dave Conway-Jones
b555b014b8 Update debug test to check lengths... 2015-08-12 21:56:19 +01:00
Dave Conway-Jones
999b888c54 debug nodes - show length of strings, buffers or size of arrays 2015-08-11 19:39:37 +01:00
Nick O'Leary
5193d7bddb Stop sending messages to ws connections that have errored
Fixes #708
2015-07-30 22:09:01 +01:00
Nick O'Leary
6b03379e4e Ensure exclusive conf node is removed on edit cancel
- If an exclusive conf node was added to a node, but the
   node's own edit dialog was canceled, the conf node remained
   but not associated with the node - effectively orphaning it
2015-07-22 22:28:30 +01:00
Nick O'Leary
08d687ad60 Update to travis container builds 2015-07-22 13:06:14 +01:00
Nick O'Leary
eb57089f06 Add flag to disable build check for tests 2015-07-22 11:41:58 +01:00
Nick O'Leary
a76e4fede1 Handle null acceptedLanguages
Closes #704
2015-07-19 22:11:25 +01:00
Nick O'Leary
705d043540 Replace bootstrap popover 2015-07-18 21:27:16 +01:00
Nick O'Leary
5462e251f8 Fix exclusive config node check when type not registered 2015-07-15 13:23:05 +01:00
Nick O'Leary
50788af6ca Add 0.12 to engine statement 2015-07-15 10:50:38 +01:00
Nick O'Leary
1a07c5a329 Bump 0.11.0 2015-07-15 10:48:33 +01:00
Nick O'Leary
9fb81b2814 Permit login with blank scope
Required for the editor, which doesn't know the appropriate scope
for the user logging in. The user will adopt their default permission
scope once logged in.
2015-07-15 10:12:45 +01:00
Dave Conway-Jones
10ad7fbf6e remove spaces before ? in messages 2015-07-14 23:47:58 +01:00
Nick O'Leary
811c4f2630 Ensure locales dir is included in release zip 2015-07-14 20:37:49 +01:00
Dave Conway-Jones
f7e3b0a64f Tiny pixel tweaks to new ui 2015-07-14 20:37:26 +01:00
Nick O'Leary
7d83d76fb3 Merge pull request #702 from node-red/ui-refresh
UI Refresh
2015-07-14 16:11:48 +01:00
Nick O'Leary
d3c41b38f7 More restylin 2015-07-14 15:59:56 +01:00
Nick O'Leary
57d6b16d5c Reset sidebar font size 2015-07-13 23:30:57 +01:00
Nick O'Leary
27aa5ae7db More UI refresh 2015-07-13 23:21:03 +01:00
Nick O'Leary
62e8f564b9 Fix node import error nls message 2015-07-13 16:28:23 +01:00
Nick O'Leary
a1d7bb4208 More restyling - workspace buttons 2015-07-13 15:08:17 +01:00
Nick O'Leary
5d8dae05c4 More ui redesign 2015-07-13 11:26:29 +01:00
Nick O'Leary
6bde07b5a0 Refresh appearance 2015-07-11 23:43:45 +01:00
Nick O'Leary
846ab08661 Allow node modules to declare supported versions of node-red 2015-07-10 21:42:14 +01:00
Nick O'Leary
999cf66b27 Add editor events component and migrate to it 2015-07-10 19:49:53 +01:00
Dave Conway-Jones
60539d890b Fix File node check of msg.payload to close #700
Also add feature to allow creation of directory(ies) if path to file
does not exist.
2015-07-10 14:59:23 +01:00
Nick O'Leary
e5a0f25d94 Keep sidebar tab menu in alphabetical order 2015-07-09 16:48:53 +01:00
Nick O'Leary
fde9d40098 Copy/clone config nodes properly on import/export 2015-07-08 22:12:52 +01:00
Nick O'Leary
f70e9ea076 Ensure RED._ is defined before initialising settings
- remove permissions requirement from locales files so the
   login dialog can be nls'd
2015-07-08 17:08:07 +01:00
Dave Conway-Jones
d0af4aac4d cleanup status on delay node 2015-07-08 15:06:46 +01:00
Dave Conway-Jones
7de3704210 lets exec node pass more than just string as the command payload. 2015-07-08 15:06:08 +01:00
Nick O'Leary
1c33b837b8 Fix delay node labels 2015-07-08 08:04:47 +01:00
Nick O'Leary
95d20d7fba Ensure status messages are strings 2015-07-08 08:02:23 +01:00
Nick O'Leary
90b8806e7c Merge pull request #697 from knolleary/node12
Add node 0.12 to Travis config and fix resulting errors
2015-07-05 23:11:19 +01:00
Nick O'Leary
39df80bf99 Fix exec test to restart helper server before each test 2015-07-05 23:02:10 +01:00
Nick O'Leary
bac4beae03 Fix Function error parsing for node 0.12 format 2015-07-05 22:40:24 +01:00
Nick O'Leary
a7b68c18b5 Bump fs-extra version to fix 0.12 support 2015-07-05 22:10:34 +01:00
Nick O'Leary
ef2360baee Add node 0.12 to Travis config 2015-07-04 22:08:58 +01:00
Nick O'Leary
8716e7e601 Ensure tab minimum size not applied when there is space for all 2015-07-03 20:54:31 +01:00
Nick O'Leary
00c2dae969 Set minimum size on workspace tab 2015-07-03 18:31:37 +01:00
Nick O'Leary
8782bc5896 Ensure sidebar panes are hidden, not removed on change 2015-07-03 11:17:27 +01:00
Nick O'Leary
6359b90352 Add sidebar menu and migrate existing panels to new api 2015-07-03 10:07:40 +01:00
Nick O'Leary
6cfa4976fe Fix nodes.install.installing message id 2015-07-02 13:25:15 +01:00
Nick O'Leary
35cd7cf2b8 Fix tcp status message 2015-07-02 10:56:27 +01:00
Nick O'Leary
b2d7f079b7 Merge pull request #694 from node-red/i18n
Add i18n support
2015-07-02 10:54:22 +01:00
Nick O'Leary
726069bc4b NLS status text in editor not runtime 2015-07-02 10:49:40 +01:00
Nick O'Leary
fbccf01933 Tidy up red.js runtime messages 2015-07-02 10:49:40 +01:00
Nick O'Leary
c9f3c6f4a3 Update trigger node ui 2015-07-02 10:49:40 +01:00
Nick O'Leary
c47da013ff Tidy up of editor i18n messages 2015-07-02 10:49:40 +01:00
Allen Boone
bc76499957 Use core category for custom nodes if core nodes disabled 2015-07-02 10:49:40 +01:00
Allen Boone
24afcff0ea Custom nodes category NLS 2015-07-02 10:49:40 +01:00
Nick O'Leary
6777f24845 Ensure library export dialog is i18n'd 2015-07-02 10:49:40 +01:00
Nick O'Leary
61e0923fc4 Restore when module dependency in red/api/nodes 2015-07-02 10:49:40 +01:00
Nick O'Leary
757caeb9a4 Try to use default palette label nls message if found 2015-07-02 10:49:40 +01:00
Allen Boone
fe9dc6b272 Palette category label NLS for core nodes 2015-07-02 10:49:40 +01:00
Nick O'Leary
24efdbe4da Add missing-type install hint nls messages 2015-07-02 10:49:39 +01:00
Nick O'Leary
9ca102cf81 Ensure error messages are toStringed 2015-07-02 10:49:39 +01:00
Nick O'Leary
48df31d7b7 NLS deprecated node message 2015-07-02 10:49:39 +01:00
Nick O'Leary
539afb1e1d Fix Inject node interval label 2015-07-02 10:49:39 +01:00
Nick O'Leary
bdcba44ca5 Remove moved node messages 2015-07-02 10:49:39 +01:00
Nick O'Leary
99a51b07ac Catch error loop detection nls 2015-07-02 10:49:39 +01:00
Allen Boone
5fbaca75b4 Fixed sidebar id issue 2015-07-02 10:49:39 +01:00
Allen Boone
a6974371b0 Fixed acceptedLanguage typo 2015-07-02 10:49:39 +01:00
Allen Boone
409fa49234 Added missing NLS strings to sidebar and index.mst 2015-07-02 10:49:39 +01:00
Nick O'Leary
9bbd6a70b8 Add namespaced i18n function to node definition 2015-07-02 10:49:39 +01:00
Nick O'Leary
f0b4cb608a Return locale specific node help 2015-07-02 10:49:39 +01:00
Allen Boone
284d7e26d1 Initialize list of supported languages from directories in the locale folder. 2015-07-02 10:49:39 +01:00
Scott Yoshizawa
965c0937ac NLS undo previous change (added require for ./red/log) 2015-07-02 10:49:39 +01:00
Nick O'Leary
d9cf6a4431 Only attempt to load one locale per catalog 2015-07-02 10:49:39 +01:00
Allen Boone
e6ed8ee509 locale exposed to editor 2015-07-02 10:49:39 +01:00
Scott Yoshizawa
2563649b3e NLS /red/nodes
NLS other js files under /red

NLS /red files (changed based on Nick's review)
2015-07-02 10:49:39 +01:00
Nick O'Leary
203bc41b06 Some more node i18n tidy up 2015-07-02 10:49:38 +01:00
Allen Boone
cb1d18c7c8 Fixed problem with RED._ being unavailable to module code 2015-07-02 10:49:38 +01:00
Nick O'Leary
5ea68dafc4 More node i18n tidy ups 2015-07-02 10:49:38 +01:00
Nick O'Leary
68bb8252af Ensure i18n func available to new config nodes 2015-07-02 10:49:38 +01:00
Nick O'Leary
406f742d29 Add jsonlint step to build 2015-07-02 10:49:38 +01:00
Nick O'Leary
5522e57f65 More node i18n tidy-up 2015-07-02 10:49:38 +01:00
Nick O'Leary
94e27dbfc5 Tidy up node i18n 2015-07-02 10:49:38 +01:00
Nick O'Leary
f5fc8f763f Pick up desired language from query string 2015-07-02 10:49:38 +01:00
Nick O'Leary
9058bf615c Fix invalid json in message catalog 2015-07-02 10:49:38 +01:00
Nick O'Leary
9d17137dec Ensure i18n message for Unknown nodes are available 2015-07-02 10:49:38 +01:00
Allen Boone
4a318553f7 Updated editor ui NLS strings 2015-07-02 10:49:38 +01:00
Allen Boone
0017074d38 Updated the notifications and errors to use NLS
removed errant comma
2015-07-02 10:49:36 +01:00
Allen Boone
a39a26fcc2 Converted editor menu to use NLS strings 2015-07-02 10:47:02 +01:00
Scott Yoshizawa
2fe859b111 NLS Core nodes
NLS exec node

NLS function/temple/delay nodes

NLS function/template/delay/trigger/comment nodes

NLS io nodes (mqtt/httpin/websocket/watch/serial)

NLS messages.json for tcpin

NLS io nodes (tcpin & udp half)

NLS io nodes (udp)

NLS logic nodes (switch/change)

NLS logic (range) and parsers (csv&html) nodes

NLS parser nodes (json/xml)

NLS test case update for logic/parsers

NLS analysis and hardware nodes

NLS storage nodes (file/redisout/mongodb) and test

NLS storage node (tail)

NLS social nodes (feedparse/email/irc)

NLS socal node (twitter half change)

NLS social node (twitter) and core node (unknown)
2015-07-02 10:46:57 +01:00
Nick O'Leary
c105b2df37 Add RED._ to test helper 2015-06-29 16:04:00 +01:00
Nick O'Leary
4fb86ab55a Fix !=0 comparison 2015-06-29 16:04:00 +01:00
Nick O'Leary
1ed98a5963 Dont create i18n function for subflows 2015-06-29 16:04:00 +01:00
Nick O'Leary
a4a29ceb3c Handle [html] data-i18n prefixes in config node dialog 2015-06-29 16:04:00 +01:00
Nick O'Leary
6249083431 Extract all core runtime messages 2015-06-29 16:04:00 +01:00
Nick O'Leary
aa18c65fa8 NLS enable the Inject node 2015-06-29 16:03:59 +01:00
Nick O'Leary
a7900940da Expose i18n in editor 2015-06-29 16:03:59 +01:00
Nick O'Leary
008bc98070 Ensure node help is blank if otherwise undefined 2015-06-29 16:03:59 +01:00
Nick O'Leary
0705589cc2 Load base locales in editor 2015-06-29 16:03:59 +01:00
Nick O'Leary
b2caba593f Add locales api endpoint 2015-06-29 16:03:59 +01:00
Nick O'Leary
6d4c64fcd5 i18n enable runtime node files 2015-06-29 16:03:59 +01:00
Nick O'Leary
7d41781fb4 Add initial red/i18n implementation 2015-06-29 16:03:59 +01:00
Nick O'Leary
0760facb77 Add .DS_store to gitignore 2015-06-29 16:02:01 +01:00
Nick O'Leary
a0ce095807 Error generating complete flow library list on OSX
Must use path.join to concatenate paths safely.
2015-06-29 16:00:10 +01:00
Nick O'Leary
df0110913a Remove rogue console.logs 2015-06-25 15:33:39 -07:00
Nick O'Leary
06731374a4 Fix trigger extend behaviour 2015-06-25 13:59:26 -07:00
Dave Conway-Jones
6c8b7c0082 Correct RPi pins labels... and add BCM pins also. 2015-06-24 12:39:27 +01:00
Dave Conway-Jones
93136961b9 make unspecified settings file totally obvious in debug. 2015-06-22 14:17:16 +01:00
Dave Conway-Jones
529a691e1d Add clearTimeout to function node sandbox
(to be a pair with setTimeout…)
2015-06-22 09:07:31 +01:00
Dave Conway-Jones
9f0b3eba47 Add basic exec node test 2015-06-22 08:26:38 +01:00
Nick O'Leary
6d897793cb Ensure node.outputs is always a number
Closes #686
2015-06-19 20:37:12 +01:00
Nick O'Leary
0e12fc6b02 Fix canvas focus issue on FF/IE 2015-06-17 22:52:04 +01:00
Nick O'Leary
c00558ea1b Remove old index.html 2015-06-17 22:46:54 +01:00
Dave Conway-Jones
bacf27a3ca mistook 2015-06-17 22:12:48 +01:00
Dave Conway-Jones
6560ea0630 Delete Dockerfile
mistook
2015-06-17 22:12:27 +01:00
Nick O'Leary
8338231ce5 Drop blank port from comms ws path 2015-06-17 22:09:27 +01:00
Dave Conway-Jones
5813a91244 adjust timing on file tail test
Runs cleaner on Mac
2015-06-17 22:08:53 +01:00
Nick O'Leary
dfd8ab3545 Detect mouse paste in Import nodes dialog 2015-06-17 20:48:56 +01:00
Nick O'Leary
a5b9b949a8 bump to 0.10.11 dev version 2015-06-17 14:58:22 +01:00
Nick O'Leary
72570e4510 Fix scope of knownUnknowns variable 2015-06-17 14:27:49 +01:00
Nick O'Leary
3002aead6b Add better install message on missing nodes 2015-06-17 14:18:47 +01:00
Nick O'Leary
841edbe6fb Ensure release files retain proper chmod status 2015-06-17 13:38:49 +01:00
Nick O'Leary
2b9aca0c56 Add bin to release package 2015-06-16 23:39:33 +01:00
Nick O'Leary
3a17c3ee6d Merge pull request #680 from cpswan/patch-1
https link (rather than git) in dev instructions
2015-06-16 23:38:58 +01:00
Chris Swan
df09252ee0 https link (rather than git) in dev instructions 2015-06-16 23:20:10 +01:00
Nick O'Leary
f51778d417 Bump to 0.10.9 2015-06-16 22:19:31 +01:00
414 changed files with 62597 additions and 17897 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.DS_store
.config.json
.dist
.jshintignore
@@ -14,3 +15,5 @@ flows*.json
nodes/node-red-nodes/
node_modules
public
locales/zz-ZZ
nodes/core/locales/zz-ZZ

View File

@@ -2,12 +2,18 @@
"asi": true, // allow missing semicolons
"curly": true, // require braces
"eqnull": true, // ignore ==null
//"eqeqeq": true, // enforce ===
"freeze": true, // don't allow override
"indent": 4, // default indent of 4
"forin": true, // require property filtering in "for in" loops
"immed": true, // require immediate functions to be wrapped in ( )
"nonbsp": true, // warn on unexpected whitespace breaking chars
//"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
//"unused": true, // Check for unused functions and variables
"loopfunc": true, // allow functions to be defined in loops
//"expr": true, // allow ternery operator syntax...
"sub": true // don't warn that foo['bar'] should be written as foo.bar
//"expr": true, // allow ternery operator syntax...
"shadow": true, // allow variable shadowing (re-use of names...)
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
"proto": true, // allow setting of __proto__ in node < v0.12,
"esversion": 6 // allow es6
}

View File

@@ -1,6 +1,5 @@
/Gruntfile.js
/.git/*
*.json
/lib/*
*.backup
/public/*

View File

@@ -1,8 +1,19 @@
sudo: false
language: node_js
before_install:
- npm install -g npm@~1.4.18
env:
- CXX="g++-4.8"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
- gcc-4.8
node_js:
- "0.10"
- "8"
- "7"
- "6"
- "4"
script:
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
before_script:

964
CHANGELOG.md Normal file
View File

@@ -0,0 +1,964 @@
#### 0.17.5: Maintenance Release
- Add express-session missing dependency for oauth
- Fix improper type tests is core test cases
- File node: recreate write stream when file deleted Fixes #1351
- Add flow stopping trace messages
- Fix userDir test case when .config.json exists (#1350)
- Do not try to send msg after http request error handled Fixes #1344
- Fix boundary problem in range node (#1338)
- Modify messages in node properties to refer messages.json (#1339)
- Fix settings.js replacing webSocketVerifyClient by webSocketNodeVerifyClient (#1343)
#### 0.17.4: Maintenance Release
- Add request node test case for POSTing 0
- Allow false and 0 in payload for httprequest (#1334)
- Add file extension into flow name of library automatically (#1331)
- Fix accessing global context from jsonata expressions Fixes #1335
- Disable editor whilst a deploy is inflight Fixes #1332
- Replace Unknown nodes with their real versions when node loaded
- Retry auto-install of modules that fail
- Fix column name in link nodes to refer language file (#1330)
- Use namespaces with link node title attributes i18n name Fixes #1329
- Tidy up GPIO pin table presentation Fixes #1328
- Join: count of 0 should not send on every msg
- Handle importing only one end of a link node pair
- Make sending to Debug synchronous again Fixes #1323
- Make send-error behaviour optional in file node
- Restore File In node behaviour of sending msg on error
- Expose context.keys within Function node
- JSON parser default should be not formatting output
#### 0.17.3: Maintenance Release
- Fix flow library in menu to support period characters as flow name (#1320)
- editorTheme not setting custom css/scripts properly
- Fix missing icons for some nodes (#1321)
- Add reformat button to JSONata test data editor
- Update delay node status without spawning unnecessary intervals
- Avoid stringify ServerResponse and Socket in Debug node Fixes #1311
- Fix creating userDir other than system drive on Windows (#1317)
- Trigger node not handling a duration of 0 as block mode Fixes #1316
- Unable to config GPIO Pin 13 Fixes #1314
#### 0.17.2: Maintenance Release
- Fix GPIO node labels
#### 0.17.1: Maintenance Release
- Fix PI gpio to use BCM
- Prevent event thread contention when sending to Debug node Closes #1311
- Fix Bug: Can not display node icon when npm package has scope (#1305) (#1309)
- Clear moved flag when nodes are deployed
#### 0.17: Milestone Release
Runtime
- Return flow rev on reload api when api v2 enabled Closes #1273
- Provide single endpoint to load all node message catalogs
- Add .trace and .debug to Node prototype
- Rename oauth auth scheme to strategy as it works for openid
- Allow oauth schemes provide a custom verify function
- Add support for oauth adminAuth configs
- Cache auth details to save needlessly recalculating hashes
- Add context.keys function to list top-level keys
- Strip BOM character from JSON files if present Fixes #1239
- Version check no meta (#1243)
- Ensure all nodes have access to global context Fixes #1230
- Don't process subscription for unauthenticated comms link Fixes #851
- Clone credentials when passing to node Fixes #1198
- Resolve dir argument of getLocalNodeFiles function (#1216)
- Add wait for writing a library entry into a file. (#1186)
- Use correct Buffer.from method rather than constructor
- update core nodes to use newer Buffer syntax
- Treat missing msg properties as undefined rather than throw error Fixes #1167
- Allows flows to be enabled/disabled in the runtime
- add off option to logging settings comment
- Log error stack traces if verbose flag is set
- Extract line number if available from node load errors
- Add node 8 to travis (with allow failure)
- Shuffle promises for creating default package.json
- Create a package.json file in userDir if one doesn't exist
- autoInstallModules option must honour version/pending_version
- Refuse to update a non-local node module
- Finalise nodeSettings and update tlsConfigDisableLocalFiles
- Allow a node to declare what settings should be made available to the editor. (#1185)
- Add node whitelist function (#1184)
- Allow a node to declare settings that should be exported
- Add test coverage for deleting a flow
- Update tests for oauth -> strategy rename
- Fix the test cases which sometimes fails due to timing. (#1228)
- Extend timeout for the test case of installing non-existant path. (#1191)
- Fix loader test to expect line numbers in load errors
- Update ui_spec for icon module path
- let node installer try to save with ~ version prefix to allow minor updates
- Log error when non-msg-object is returned from a Function
- Timeout a node that fails to close - default 15s timeout
- Pass a 'removed' parameter to node close handler
- Remove event passing for icons/examples from the api layer
- Update general dependencies
Nodes
- Do not log node errors if handled by a Catch node
- Fix wrong number of double quotes in CSV parsing
- let csv node handle ip addresses without trying to parse
- Update debug node to register the settings it uses
- Handle IncomingMessage/ServerResponse object types in debug Fixes #1202
- Toggling debug node enabled/disabled state should set state dirty Fixes #1203
- redo delay node status messages to be interval based
- Update delay node ui
- Add new msg.delay option to delay node
- stop delay node spamming web socket (when in fast rate limit mode)
- Delay/Range node help tidy up
- Bug fix in exec node. White spaces in arguments now works (#1285)
- Make exec node explicitly call SIGTERM for default
- Fix exec node error tests on Windows (#1234)
- update messages for updated exec node
- Make exec node spawn and exec outputs more consistent
- Exec node for windows environment (#1200)
- remove requirement for cmd in exec node config + new style info
- retry exec node tests
- let exec node take msg.kill SIG... param and pid param
- Third output from Exec node must be consistent for success/failure conditions
- exec node returns 0 on the third output if command ended without error. (#1160)
- exec node can be killed on demand
- add "split/stream" ability to file in node
- add port label to file node and update info
- Allow nodes to have translations not in core (#1183)
- fix tcp node new Buffer alloc size 0
- change pin selection table for pi gpis nodes
- stop using sudo for Pi gpio access
- adding frequency configuration to pwm output (#1206)
- Fix Pi GPIO debounce
- let Hypriot on Pi detect gpio correctly
- More core node info help tidy up
- Tidy up more core node help text
- Tidy up parser node edit dialogs and help text
- yet more core node info updates
- more core node info updates to newer style
- Update some core nodes info
- First pass of new node-info style
- MQTT new style info
- Fix empty extra node help content issue
- Handle HTTP In url that is missing its leading / Fixes #1218
- Add file upload support to HTTP In node
- HTTP Request node: add info on how to do form encoding
- Prevent unmodified msg.headers from breaking HTTP Request flows Closed #1015
- Add cookie handling to HTTP Request node
- Add guard against the http-request buffer fix being reverted
- Multipart streaming
- Add http-request node unit tests
- http request node add transport validity check and warn.
- Update follow_redirects to fix http_proxy handling Fixes #1172
- Allow statusCode/headers to be set directly within HTTP Response node
- let inject "between time" also fire at start - Plus new info
- remove repeat symbol from inject if repeat is 0
- Add port labels to inject node (to show types)
- Add buffer joiner mode to Join node
- Let join node auto re-assemble buffers
- let join also accumulate strings (and not fail)
- Add Pretty print option to JSON node and
- Fix selection of link nodes
- Add link label value as portLabels
- Add sentence about clearing retained topic on mqtt
- make sure MQTT client closes if redeploy during reconnect
- make sure MQTT client closes if redeploy during reconnect
- slight filed size adjust for mqtt broker port field - allow 5 digits
- Add help info for split node
- split node - in object mode allow msg.complete on its own
- let split of objects use key to set another property (e.g. topic)
- adding streaming modes into split node
- let split node reassemble based on a final packet. (as well as the first)
- Add buffer support to split node
- updated split/join node (split still needs work before release)
- Added a name icon and a description label on edit subflow window.
- Don't display port labels for subflow pseudo-port nodes
- Added a name icon and a description label on edit subflow window.
- tcp request - remove confusing timeout wording from info
- Final TCP node nits - let 0 do it's thing as per every other timeout
- fix tcp port not waiting as per info/previous behaviour
- TCP In: Fix error in timout callback (#1249)
- Make tcp send msg more consistent
- Update 31-tcpin.js (#1235)
- really close tcp node connection right away (if told to)
- clone message before send in stay connected mode
- Better template node help example
- Add option to parse Template result as JSON before sending
- nail trigger test for windows AND linux
- give up on SIGQUIT for widows test
- better tests for windows nodes
- comment out 2nd exec node kill tests
- fixes for grunt files tests on Windows
- Add events to test helper
- Change default value of tlsConfigDisableLocalFiles to false
- Add the node setting tlsConfigDisableLocalFiles for tls node. (#1190)
- UI to upload certificates and keys for TLS node
- Update trigger help
- let trigger node set repeated outputs
- Move udp sock error listener to only be instantiated once.
- Let watch node recurse into subdirectories
- Misconfigured WebSocket nodes should not register msg handlers
- Add websocketVerifyClient option to enable custom websocket auth Fixes #1127
Editor
- Bump ACE editor to v1.2.7
- Add RED.utils.getNodeLabel utility function
- Include module name in requests for node icons
- Change debug message menu icon
- Handle empty array/objects in debug view
- Add per-node filter option to Debug pane
- Ensure debug node marked changed when button pressed
- Fix pop-out debug window for all the recent updates
- Add debug message menu
- Don't include msg. in debug message copied paths
- Format Buffer numbers as hex by default
- Remember formatting choices for dbg msg elements
- Allow debug msg elements to be pinned
- Only show debug tools under the debug tab
- Fix test for valid js identifiers in debug path construction
- Remove unused modified flag on debug messages
- Add copy path/value buttons to debug messages
- dont match only part of the node type (#1242)
- Add editorTheme.logout.redirect to allow redirect on logout Closes #1213
- Handle logging out and already logged-out editor Fixes #1288
- Fix bug: Export Subflows (#1282)
- destroy editor to ensure fully removed on close (function, template, comment)
- Don't try to nls status text starting with '.' Fixes #1258
- Add note of removed flows in diffConfig (#1253)
- Add description to flow same as subflow
- Allow tabs to be enabled/disabled in the editor
- Make H3 sections in node help collapsible
- Add JSON Expression editor
- Expression editor - clear legacy flag for blank expressions
- Ensure node labels are reordered properly to match outputs
- Add 'none' placeholder for empty port label form
- Don't mark a node changed when going from none to blank labels
- Leave a node to nls its own port labels
- Allow a node to override default labels
- Add placeholder text on label inputs and clear buttons
- Add port labels to Subflow nodes
- Keep port label form in sync with output reordering
- Basic node label editor
- Port label editor starting point
- Allow port labels be i18n identifiers
- Add inputLabels and outputLabels to node defn + Update Change node
- Resize port labels based on content
- Initial port label behaviour
- Allow a node to decide for itself if its button should be enabled or not
- Provide feedback when enable/disable node fails
- Add node module update api and expose in palette editor
- Reset palette-manager tabs when settings dialog reopened
- Move palette editor to settings panel
- Move palette editor to userSettings dialog
- Move view and keyboard into user settings dialog
- Add basic user settings panel
- Node status should be on by default
- Make theme able to load custom javascript (#1211)
- Allow tips to be hidden and cycled through
- Add info tips back to the sidebar
- Add buffer mode to typedInput
- Add typedInput binary mode icon
- Ensure all ace editors are destroyed in the expression editors
- Refresh sidebar info when tab is changed
- better spacing for library widget
- Fix gridSize for node width calculation to avoid odd resizing
- Redraw grid properly if gridSize changes
- Scroll sidebar info tab to top when changing content
- Ensure info tab sections are collapsible when set from palette
- Only show tab info if there is an active tab
- Only check for reordered outputs if outputMap defiend
- Avoid circular references when stingifying node objects
- Fix padding of config node edit dialog
- Add force-deploy option when conflict detected
- Hide tip box on startup if disabled
- Track node moves separately to node config changes
- Ensure ace editor instances are freed if edit cancelled
- Clip overly long notification messages
- Use queryCommandSupported not queryCommandEnabled to check for copy support
- Add tip to tab description editor
- Make tab info edit box resizable
- Shrink config node appearance in info table
- Display config nodes in Info sidebar table
- Ensure flow info box updates after editing flow
- Hide Node info section when displaying changelog
- Restructure info tab
- Provide notification when new flows deployed in the background
- Stop some ui elements from clearing url anchor when clicked
- clipboard export text stay highlighted even when button deselected
- ensure export clipboard keeps text selected and formatted
- Defer resizing tray components until they have finished building
- Use pre-calculated values for connection path
- Use textContent to avoid manual escaping
- Add RED.stack as a common ui component
- Numeric validator that accepts blank should accept undefined
- Add visual cue as to whether the workspace is focused
- Allow RED.validators.number to allow blank values as valid
- Support dropping json files into the editor
- NLS Expression/JSON editor and fix their height calculation
- Update JSONata to 1.2.4 Closes #1275
- Remember test expression data on a per-node basis
- NLS jsonata test messages
- Add JSONata expr tester and improved feedback
- Add $context/$flow/$global functions to jsonata
- Update jsonata
Other
- add allow es6 to .jshintrc
- travis - don't allow node 8 fails, (and re-add 7)
- ask istanbul for more reports as default
- Add istanbul to Gruntfile.js (#1189)
#### 0.16.2: Maintenance Release
- Ensure custom mustache context parent set in Template node fixes #1126
- Display debug node name in debug panel if its known
- Ensure auth-tokens are removed when no user is specified in settings
- Ensure all a tags have blank target in info sidebar
- Ensure links do not span tabs in the editor
- Avoid creating multiple reconnect timers in websocket node
- Fix inner reference in install fail message catalog entry Fixes #1120
- Display buffer data properly for truncated buffers under Object property
#### 0.16.1: Maintenance Release
- Add colour swatches to debug when hex colour matched
- Nodes with hasUsers set to false should not appear unused
- Change hard error to verbose warning if using old node.js level
- Don't filter debug properties starting with _ Fixes #1117
- Node logged errors not displayed properly in debug pane Fixes #1116
- Do not look for existing nodes when checking for wires on paste Fixes #1114
- -v option not enabling verbose mode properly
- Add node.js version check on startup
#### 0.16.0: Milestone Release
Runtime
- Drop support for node 0.10 and 0.12
Nodes
- Add option to colourise debug console output Closes #1103
- Add property validation to nodes using typedInput
- Add common validator for typedInput fields Closes #1104
- Update debug node console logging indicator icon Closes #1094
- Let exec node (spawn) handle commands with spaces in path
- Add symbol to debug node to indicate debugging also to console.log
- Change file node to use node 4 syntax (drops support for 0.8)
- add info for httprequest responseUrl property
- Add res.responseUrl to httprequest node response
- Add support for flow and global context in Template node (#1048)
- Added YAML parser node (#1034)
- node-red-node-serialport removed as a default node
Editor
- Add install/remove dialog to increase friction Closes #1109
- Report node catalogue load errors Closes #1009
- Properly report module remove errors in palette editor Fixes #1043
- Update rather than hide install button after success install
- Tweak search box styling
- Display info tips slightly longer
- Allow tips to be enabled/disabled via menu option
- Info-tips update
- Make typedInput keyboard navigable
- update Font Awesome to 4.7.0
- Add expression editor for jsonata
- Overhaul keyboard handling and introduce editor actions
- Add Japanese translation file(editor.json) (#1084)
- Add quick-add node mode with cmd/ctrl-click
- Add cmd/ctrl-click to quick add wires
- Use json-stringify-safe to detect circular references in debug msgs
- debug - format if time if correct length/range
- Make Debug object explorable
- Initial debug pop-out window
- Add proper three-way diff view
- Focus tray body when edit dialog opened
- Hit enter to edit first node in selection
- Add node delete button to edit dialog
- Add notification when runtime stopped due to missing types Part of #832
Fixes
- Do not tie debug src loading to needsPermission Fixes #1111
- Initialise nodeApp regardless of httpAdmin setting Closes #1096 #1095
- Speed up reveal of search dialogs
- Ensure flows exist before delegating status/error events Fixes #1069
- Update package dependencies
- Update MQTT to latest 2.2.1
- Node status not being refreshed properly in the editor
- Try to prevent auto-fill of password fields in node edit tray Fixes #1081
- Fix whitespace in localfilesystem
- fix bug where savesettings did not honor local settings variables (#1073)
- Tidy up unused/duplicate editor messages Closes #922
- Property expressions must not be blank
- Tidy up merge commit of validatePropertyExpression
- add port if wires array > number of ports declared.
- Allow quoted property expressions Fixes #1101
- Index all node properties for node search
- Remove node 0.10 from travis config
- update welcome message to use logger so it can be turned off/on if required (#1083)
- Fix dynamically loading multiple node-sets from palette editor
- Allow a node to reorder its outputs and maintain links Fixes #1031
#### 0.15.3: Maintenance Release
- Tcpgetfix: Another small check (#1070)
- TCPGet: Ensure done() is called only once (#1068)
- Allow $ and _ at start of property identifiers Fixes #1063
- TCPGet: Separated the node.connected property for each instance (#1062)
- Corrected 'overide' typo in XML node help (#1061)
- TCPGet: Last property check (hopefully) (#1059)
- Add additional safety checks to avoid acting on non-existent objects (#1057)
- add --title for process name to command line options
- add indicator for fire once on inject node
- reimplement $(env var) replace to share common code.
- Fix error message for missing node html file, and add test.
- Let credentials also use $(...) substitutions from ENV
- Rename insecureRedirect to requireHttps
- Add setting to cause insecure redirect (#1054)
- Palette editor fixes (#1033)
- Close comms on stopServer in test helper (#1020)
- Tcpgetfix (#1050)
- TCPget: Store incoming messages alongside the client object to keep reference
- Merge remote-tracking branch 'upstream/master' into tcpgetfix
- TCPget can now handle concurrent sessions (#1042)
- Better scope handling
- Add security checks
- small change to udp httpadmin
- Fix comparison to "" in tcpin
- Change scope of clients object
- Works when connection is left open
- First release of multi connection tcpget
- Fix node.error() not printing when passed false (#1037)
- fix test for CSV array input
- different test for Pi (rather than use serial port name)
- Fix missing 0 handling for css node with array input
#### 0.15.2: Maintenance Release
- Revert bidi changes to nodes and hide menu option until fixed Fixes #1024
- Let xml node set options both ways
- Bump serialport to use version 4
- gpio node handle multiple bits of data returned in one go
- HTTP In should pass application/octet-stream as buffer not string Fixes #1023
- Handle missing httpNodeRoot setting properly
- Config sidebar not handling node definition error properly
- Add minimum show time to deploy spinner to avoid flicker
- Add work-in-progress update button to palette-editor
- Add log.removeHandler function
- Add Crtl/Shift/p shortcut for manage palette
- Add spinner to deploy button
- Status messages from nodes in subflows not delegated properly Fixes #1016
- fix spelling in join node info
- Speed up tab scrolling
- Update delay burst test to be more tolerant of timing Fixes #1013
#### 0.15.1: Maintenance Release
- Update default palette catalogue to use https
- Disable palette editor if npm not found - and fix for Windows
- Searching package catalogue should be case-insensitive Fixes #1010
- contenteditable fields not handled in config nodes Fixes #1011
- Change html link refs from `_new` to `_blank` to be standards compliant
#### 0.15.0: Milestone Release
Runtime
- Increase default apiMaxLength to 5mb and add to default settings Closes #1001
- Add v2 /flows api and deploy-overwrite protection
- Encrypt credentials by default
- Ensure errors thrown by RED.events handlers don't percolate up
Editor
- Mark nodes as changed when they are moved
- Added parent containment option for draggable. (#1006)
- Ignore bidi event handling on non-existent and non-Input elements Closes #999
- Remove list of flows from menu
- Allow nodes to be imported with their credentials
- Add workspace search option
- Add scrollOnAdd option to editableList
- Add swift markup to editor for open whisk node
- Scrollable tabs 👍
- Allow linking to individual flow via url hash
- Avoid duplicating existing subflows on import
- Add import-to-new-tab option
- Add new options to export-nodes dialog
- Stop nodes being added beyond the outer bounds of the workspace
- Default config nodes to global scope unless in a subflow Closes #972
- Bidi support for Text Direction and Structured Text (#961)
- Fix jQuery selector, selecting more than one help pane/popover and displaying incorrectly. (#970)
- Fixes removeItem not passing row data to callback. (#965)
- Move common components and add searchBox
- Add initial palette sidebar
Nodes
- Inject node label - show topic for timestamp mode if short
- Let change node set type if total match
- Clean up status on close for several core nodes.
- Change node: re-parse JSON set value each time to avoid pass-by-ref
- Better handle HTTP Request header capitalisation
- Enable ES6 parsing in Function editor by default Fixes #985
- Update debug sidebar to use RED.view.reveal to show debug nodes
- Add full path tip to file node, And tidy up Pi node tips
- Remove WebSocket node maxlistener warning
- Update mqtt-broker node to use fully name-space qualified status messages
- Let UDP node better share same port instance if required
- Add number of units to the delay node (rate) (#994)
- Allow http middleware to skip rawBodyParser
- Let change node move property to sub-property.
- Add info to exec warning about buffered output if using python
- TCP node: pass on latest input msg properties
- Make sure MQTT broker is really set
- Fix escape character catch in TCPGet + support 0x?? sequences
- Fix split character in TCP Request node
- Add CSS highlighting to the template node (#950)
- Only update switch previous value after all rules are run
Other
- Add npm build/test scripts Closes #946 #660
- Move travis to node 6 and 7 - drop 5 and 0.12
#### 0.14.6: Maintenance Release
Fixes
- Tell ace about Function node globals. Closes #927
- Tidy up mqtt nodes - linting and done handling. Closes #935
- Fix invalid html in TCP and HTML node edit templates
- Add proper help text to link nodes
- Handle importing old mqtt-broker configs that lack properties
- Update ace to 1.2.4
- Allow config nodes to provide a sort function for their select list
- Add log warning if node module required version cannot be satisfied
- Handle empty credentials file. Closes #937
- Add RPi.GPIO lib test for ArchLinux
#### 0.14.5: Maintenance Release
Fixes
- Cannot clear cookies with http nodes
- let HTML parse node allow msg.select set select
- Validate nodes on import after any references have been remapped
- Debug node handles objects without constructor property Fixes #933
- Ensure 'false' property values are displayed in info panel Fixes #940
- Fix node enable/disable over restart - load configs after settings init
#### 0.14.4: Maintenance Release
Nodes
- Update trigger node ui to use typedInputs
- Better handling of quotes in CSV node
- Clarify the MQTT node sends msg.payload - closes #929
- Inject node should reuse the message it is triggered with Closes #914
- Stop trigger node re-using old message
- Allow node.status text to be 'falsey' values
Fixes
- Handle DOMException when embedded in an iframe of different origin Fixes #932
- Fix double firing of menu actions
- Fix select box handling in Safari - fixes #928
- Clear context in node test helper Fixes #858
- Allow node properties to be same as existing object functions Fixes #880
- Handle comms link closing whilst completing the initial connect
- Protect against node type names that clash with Object property names Fixes #917
- Clone default node properties to avoid reference leakage
- Strip tab node definition when exporting
- Check for null config properties in editor before over-writing them
- Add hasUsers flag to config nodes
Editor
- Add sql mode to ace editor
- Keyboard shortcuts dialog update (#923)
- Ensure importing link nodes to a subflow doesn't add outbound links Fixes #921
- Add updateConfigNodeUsers function to editor
- Scroll to bottom when item added to editableList
- Form input widths behave more consistently when resizing Fixes #919 #920
#### 0.14.3: Maintenance Release
Fixes
- Create default setting.js in user-specified directory. Fixes #908
- MQTT In subscription qos not defaulting properly
- Let exec node handle 0 as well as "0"
#### 0.14.2: Maintenance Release
Fixes
- Cannot add new twitter credentials. Fixes #913
- Support array references in Debug property field
#### 0.14.1: Maintenance Release
Fixes
- Handle undefined property that led to missing wires in the editor
- Remove duplicate 'Delete' entry in keyboard shortcut window. Closes #911
- Add 'exec' to node-red-pi launch script. Closes #910
#### 0.14.0: Milestone Release
Editor
- Replace edit dialog with edit tray
- Enable shift-drag detach of just the selected link
- Allow workspace tabs to be re-ordered
- Scope keyboard shortcuts to dom elements
- Ensure parent nodes marked as changed due to child config node changes
- Validate all edit dialog inputs when one changes
- Add editableList widget and update Switch/Change nodes to use it
- Add option to filter Debug sidebar by flow and highlight subflow-emitting nodes
- Back off comms reconnect attempts after prolonged failures
- Prompt for login if comms reconnect fails authentication
- Change style of nodes in subflow template view
- Add CHANGELOG.md and make it accessible from menu
Runtime
- Always log node warnings on start without requiring -v
- Add support for loading scoped node modules. Closes #885
- Add process.env.PORT to settings.js
- Clear node context on deploy. Closes #870
- Enable finer grained permissions in adminAuth
Nodes
- Enable config nodes to reference other config nodes
- Add Split/Join nodes
- Add Link nodes
- Add support to HTTP In node for PATCH requests. Closes #904
- Add cookie handling to HTTP In and HTTP Response nodes
- Add repeat indicator to inject node label. Closes #887
- Add javascript highlighter to template node
- Add optional timeout to exec node
- Add TLS node and update MQTT/HTTP nodes to use it
- Let trigger node also send last payload to arrive
- Add timestamp as a default typedInput and update Inject and change nodes to match,
- Add QoS option to MQTT In node
- Add status to exec spawn mode
- Add Move capability to Change node
- Update Serial node to support custom baud rates
- Add support for array-syntax in typedInput msg properties
- Add RED.util to Function node sandbox
- Capture error stack on node.error. Closes #879
Fixes
- Add error handling to all node definition api calls
- Handle null return from Function node in array of messages
- Defer loading of token sessions until they are accessed. Fixes #895
- set pi gpio pin status correctly if set on start
- Prevent parent window scrolling when view is focused. Fixes #635
- Handle missing tab nodes in a loaded flow config
- Ensure typedInput dropdown doesn't fall off the page
- Protect against node types with reserved names such as toString. Fixes #880
- Do not rely on the HTML file to identify where nodes are registered from
- Preserve node properties on import
- Fix regression in delay node. topic based queue was emptying all the time instead of spreading out messages.
- Throw an error if a Function node adds an input event listener
- Fix hang on partial deploy with disconnected mqtt node
- TypedInput: preload type icons to ensure width calc correct
- Ensure tcp node creates a buffer of size 1 at least
- Return editorTheme default if value is undefined
- Fix RED.util.compareObjects for Function created objects and Buffers
- Ensure default settings copied to command-line specified userDir
#### 0.13.4: Maintenance Release
- Add timed release mode to delay node
- Enable link splicing for when import_dragging nodes. Closes #811
- Fix uncaught exception on deploy whilst node sending messages
- Deprecate old mqtt client and connection pool modules
- Change node: add bool/num types to change mode Closes #835
- Validate fields that are `$(env-vars)` Closes #825
- Handle missing config nodes when validating node properties
- Pi node - don't try to send data if closing
- Load node message catalog when added dynamically
- Split palette labels on spaces and hyphens when laying out
- Warn if editor routes are accessed but runtime not started Closes #816
- Better handling of zero-length flow files Closes #819
- Allow runtime calls to RED._ to specify other namespace
- Better right alignment of numerics in delay and trigger nodes
- Allow node modules to include example flows
- Create node_modules in userDir
- Ensure errors in node def functions don't break view rendering Fixes #815
- Updated Inject node info with instructions for flow and global options
#### 0.13.3: Maintenance Release
- Fix crash on repeated inject of invalid json payload
- Add binary mode to tail node
- Revert Cheerio to somewhat smaller version
- Add os/platform info to default debug
#### 0.13.2: Maintenance Release
- Don't force reconnect mqtt client if message arrives (fixes the MQTT connect/disconnect endless cycle)
- Add -p/--port option to override listening port
- Invert config node filter toggle button colours so state is more obvious
- Add timeout to httprequest node
- Tidy up of all node info content - make style consistent
- Make jquery spinner element css consistent with other inputs
- tcp node add reply (to all) capability
- Allow the template node to be treated as plain text
- Validate MQTT In topics Fixes #792
- httpNodeAuth should not block http options requests Fixes #793
- Disable perMessageDeflate on WS servers - fixes 'zlib binding closed' error
- Clear trigger status icon on re-deploy
- Don't default inject payload to blank string
- Trigger node, add configurable reset
- Allow function properties in settings Fixes #790 - fixes use of httpNodeMiddleware
- Fix order of config dialog calls to save/creds/validate
- Add debounce to Pi GPIO node
#### 0.13.1: Maintenance Release
- Revert wrapping of http request object
#### 0.13.0: Milestone Release
- Add 'previous value' option to Switch node
- Allow existing nodes to splice into links on drag
- CORS not properly configured on multiple http routes Fixes #783
- Restore shift-drag to snap/unsnap to grid
- Moving nodes with keyboard should flag workspace dirty
- Notifications flagged as fixed should not be click-closable
- Rework config sidebar and deploy warning
- Wrap http request object to match http response object
- Add 'view' menu and reorganise a few things
- Allow shift-click to detach existing wires
- Splice nodes dragged from palette into links
- try to trim imported/dragged flows to [ ]
- Move version number as title of NR logo
- Moving nodes mark workspace as dirty
- Ok/Cancel edit dialogs with Ctrl-Enter/Escape
- Handle OSX Meta key when selecting nodes
- Add grid-alignment options
- Add oneditresize function definition
- Rename propertySelect to typedInput and add boolean opt
- Add propertySelect to switch node
- Add propertySelect support to Change node
- Add context/flow/global support to Function node
- Add node context/flow/global
- Add propertySelect jquery widget
- Add add/update/delete flow apis
- Allow core nodes dir to be provided to runtime via settings
- Tidy up API passed to node modules
- Move locale files under api/runtime components
- Add flow reload admin api
#### 0.12.5: Maintenance Release
- Add attribute capability to HTML parser node
- Add Pi Keyboard code node
- Fix for MQTT client connection cycling on partial deploy
- Fix for tcp node properly closing connections
- Update sentiment node dependencies
- Fix for file node handling of UTF8 extended characters
#### 0.12.4: Maintenance Release
- Add readOnly setting to prevent file writes in localfilesystem storage
- Support bcrypt for httpNodeAuth
- Pi no longer needs root workaround to access gpio
- Fix: Input File node will not retain the file name
#### 0.12.3: Maintenance Release
- Fixes for TCP Get node reconnect handling
- Clear delay node status on re-deploy
- Update Font-Awesome to v4.5
- Fix trigger to block properly until reset
- Update example auth properties in settings.js
- Ensure httpNodeAuth doesn't get applied to admin routes
- TCP Get node not passing on existing msg properties
#### 0.12.2: Maintenance Release
- Enable touch-menu for links so they can be deleted
- Allow nodes to be installed by path name
- Fix basic authentication on httpNode/Admin/Static
- Handle errors thrown in Function node setTimeout/Interval
- Fix mqtt node lifecycle with partial deployments
- Update tcp node status on reconnect after timeout
- Debug node not handling null messages
- Kill processes run with exec node when flows redeployed
- Inject time spinner incrementing value incorrectly
#### 0.12.1: Maintenance Release
- Enable touch-menu for links so they can be deleted
- Allow nodes to be installed by path name
- Fix basic authentication on httpNode/Admin/Static
#### 0.12.0: Milestone Release
- Change/Switch rules now resize with dialog width
- Support for node 4.x
- Move to Express 4.x
- Copy default settings file to user dir on start up
- Config nodes can be scoped to a particular subflow/tab
- Comms link tolerates <5 second breaks in connection before notifying user
- MQTT node overhaul - add will/tls/birth message support
- Status node - to report status events from other nodes
- Error node can be targeted to specific other nodes
- JSON node can encode Array types
- Switch node regular expression rule can now be set to be case-insensitive
- HTTP In node can accept non-UTF8 payloads - will return a Buffer when appropriate
- Exec node configuration consistent regardless of the spawn option
- Function node can now display status icon/text
- CSV node can now handle arrays
- setInterval/clearInterval add to Function node
- Function node automatically clears all timers (setInterval/setTimeout) when the node is stopped
#### 0.11.2: Maintenance Release
- Allow XML parser options be set on the message
- Add 'mobile' category to the palette (no core nodes included)
- Allow a message catalog provide a partial translation
- Fix HTTP Node nls message id
- Remove delay spinner upper limit
- Update debug node output to include length of payload
#### 0.11.1: Maintenance Release
- Fix exclusive config node check when type not registered (prevented HTTP In node from being editable unless the swagger node was also installed)
#### 0.11.0: Milestone Release
- Add Node 0.12 support
- Internationalization support
- Editor UI refresh
- Add RBE node
- File node optionally creates path to file
- Function node can access `clearTimeout`
- Fix: Unable to login with 'read' permission
#### 0.10.10: Maintenance Release
- Fix permissions issue with packaged nrgpio script
- Add better help message if deprecated node missing
#### 0.10.9: Maintenance Release
Fix packaging of bin scripts
#### 0.10.8: Maintenance Release
- Nodes moved out of core
- still included as a dependency: twitter, serial, email, feedparser
- no longer included: mongo, arduino, irc, redis
- node icon defn can be a function
- http_proxy support
- httpNodeMiddleware setting
- Trigger node ui refresh
- editorTheme setting
- Warn on deploy of unused config nodes
- catch node prevents error loops
#### 0.10.6: Maintenance Release
Changes:
- Performance improvements in editor
- Palette appearance update
- Warn on navigation with undeployed changes
- Disable undeployed node action buttons
- Disable subflow node action buttons
- Add Catch node
- Add logging functions to Function node
- Add send function to Function node
- Update Change node to support multiple rules
#### 0.10.4: Maintenance Release
Changes:
- http request node passes on request url as msg.url
- handle config nodes appearing out of order in flow file - don't assume they are always at the start
- move subflow palette category to the top, to make it more obvious
- fix labelling of Raspberry Pi pins
- allow email node to mark mail as read
- fix saving library content
- add node-red and node-red-pi start scripts
- use $HOME/.node-red for user data unless specified otherwise (or existing data is found in install dir)
#### 0.10.3: Maintenance Release
Fixes:
- httpAdminAuth was too aggressively deprecated (ie removed); restoring with a console warning when used
- adds reporting of node.js version on start-up
- mongo node skip/limit options can be strings or numbers
- CSV parser passes through provided message object
#### 0.10.2: Maintenance Release
Fixes:
- subflow info sidebar more useful
- adds missing font-awesome file
- inject node day selection defaulted to invalid selection
- loading a flow with no tabs failed to add nodes to default tab

74
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at team@nodered.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -7,6 +7,10 @@ We welcome contributions, but request you follow these guidelines.
- [Pull-Requests](#pull-requests)
- [Contributor License Agreement](#contributor-license-agreement)
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
By participating, you are expected to uphold this code. Please report unacceptable
behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
## Raising issues
Please raise any bug reports on the relevant project's issue tracker. Be sure to
@@ -34,21 +38,13 @@ If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it may well get rejected if you haven't discussed it on
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
### Contributor License Agreement
All contributors need to sign the JS Foundation's Contributor License Agreement.
It is an online process and quick to do. You can read the details of the agreement
here: https://cla.js.foundation/node-red/node-red.
In order for us to accept pull-requests, the contributor must first complete
a Contributor License Agreement (CLA). This clarifies the intellectual
property license granted with any contribution. It is for your protection as a
Contributor as well as the protection of IBM and its customers; it does not
change your rights to use your own Contributions for any other purpose.
If you raise a pull-request without having signed the CLA, you will be prompted
to do so automatically.
You can download the CLAs here:
- [individual](http://nodered.org/cla/node-red-cla-individual.pdf)
- [corporate](http://nodered.org/cla/node-red-cla-corporate.pdf)
If you are an IBMer, please contact us directly as the contribution process is
slightly different.
### Coding standards

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013, 2015 IBM Corp.
* 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.
@@ -18,6 +18,12 @@ var path = require("path");
module.exports = function(grunt) {
var nodemonArgs = ["-v"];
var flowFile = grunt.option('flowFile');
if (flowFile) {
nodemonArgs.push(flowFile);
}
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
paths: {
@@ -35,6 +41,17 @@ module.exports = function(grunt) {
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
mocha_istanbul: {
options: {
globals: ['expect'],
timeout: 3000,
ignoreLeaks: false,
ui: 'bdd',
reportFormats: ['lcov'],
print: 'both'
},
coverage: { src: ['test/**/*_spec.js'] }
},
jshint: {
options: {
jshintrc:true
@@ -80,7 +97,7 @@ module.exports = function(grunt) {
src: ['test/**/*.js']
},
options: {
"expr": true
"expr": true
}
}
},
@@ -89,51 +106,77 @@ module.exports = function(grunt) {
separator: ";",
},
build: {
src: [
// Ensure editor source files are concatenated in
// the right order
"editor/js/main.js",
"editor/js/settings.js",
"editor/js/user.js",
"editor/js/comms.js",
"editor/js/ui/state.js",
"editor/js/nodes.js",
"editor/js/history.js",
"editor/js/validators.js",
"editor/js/ui/deploy.js",
"editor/js/ui/menu.js",
"editor/js/ui/keyboard.js",
"editor/js/ui/tabs.js",
"editor/js/ui/workspaces.js",
"editor/js/ui/view.js",
"editor/js/ui/sidebar.js",
"editor/js/ui/palette.js",
"editor/js/ui/tab-info.js",
"editor/js/ui/tab-config.js",
"editor/js/ui/editor.js",
"editor/js/ui/clipboard.js",
"editor/js/ui/library.js",
"editor/js/ui/notifications.js",
"editor/js/ui/subflow.js",
"editor/js/ui/touch/radialMenu.js"
],
dest: "public/red/red.js"
src: [
// Ensure editor source files are concatenated in
// the right order
"editor/js/red.js",
"editor/js/events.js",
"editor/js/i18n.js",
"editor/js/settings.js",
"editor/js/user.js",
"editor/js/comms.js",
"editor/js/text/bidi.js",
"editor/js/text/format.js",
"editor/js/ui/state.js",
"editor/js/nodes.js",
"editor/js/history.js",
"editor/js/validators.js",
"editor/js/ui/utils.js",
"editor/js/ui/common/editableList.js",
"editor/js/ui/common/checkboxSet.js",
"editor/js/ui/common/menu.js",
"editor/js/ui/common/panels.js",
"editor/js/ui/common/popover.js",
"editor/js/ui/common/searchBox.js",
"editor/js/ui/common/tabs.js",
"editor/js/ui/common/stack.js",
"editor/js/ui/common/typedInput.js",
"editor/js/ui/actions.js",
"editor/js/ui/deploy.js",
"editor/js/ui/diff.js",
"editor/js/ui/keyboard.js",
"editor/js/ui/workspaces.js",
"editor/js/ui/view.js",
"editor/js/ui/sidebar.js",
"editor/js/ui/palette.js",
"editor/js/ui/tab-info.js",
"editor/js/ui/tab-config.js",
"editor/js/ui/palette-editor.js",
"editor/js/ui/editor.js",
"editor/js/ui/tray.js",
"editor/js/ui/clipboard.js",
"editor/js/ui/library.js",
"editor/js/ui/notifications.js",
"editor/js/ui/search.js",
"editor/js/ui/typeSearch.js",
"editor/js/ui/subflow.js",
"editor/js/ui/userSettings.js",
"editor/js/ui/touch/radialMenu.js"
],
dest: "public/red/red.js"
},
vendor: {
files: {
"public/vendor/vendor.js": [
"editor/vendor/jquery/js/jquery-1.11.1.min.js",
"editor/vendor/jquery/js/jquery-1.11.3.min.js",
"editor/vendor/bootstrap/js/bootstrap.min.js",
"editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js",
"editor/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"editor/vendor/marked/marked.min.js",
"editor/vendor/orion/built-editor.min.js",
"editor/vendor/d3/d3.v3.min.js"
"editor/vendor/d3/d3.v3.min.js",
"editor/vendor/i18next/i18next.min.js"
],
"public/vendor/vendor.css": [
"editor/vendor/orion/built-editor.css"
// TODO: resolve relative resource paths in
// bootstrap/FA/jquery
],
"public/vendor/jsonata/jsonata.min.js": [
"node_modules/jsonata/jsonata-es5.min.js",
"editor/vendor/jsonata/formatter.js"
],
"public/vendor/ace/worker-jsonata.js": [
"node_modules/jsonata/jsonata-es5.min.js",
"editor/vendor/jsonata/worker-jsonata.js"
]
}
}
@@ -141,7 +184,10 @@ module.exports = function(grunt) {
uglify: {
build: {
files: {
'public/red/red.min.js': 'public/red/red.js'
'public/red/red.min.js': 'public/red/red.js',
'public/red/main.min.js': 'public/red/main.js',
'public/vendor/ace/mode-jsonata.js': 'editor/vendor/jsonata/mode-jsonata.js',
'public/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js'
}
}
},
@@ -153,13 +199,32 @@ module.exports = function(grunt) {
files: [{
dest: 'public/red/style.min.css',
src: 'editor/sass/style.scss'
},
{
dest: 'public/vendor/bootstrap/css/bootstrap.min.css',
src: 'editor/vendor/bootstrap/css/bootstrap.css'
}]
}
},
jsonlint: {
messages: {
src: [
'nodes/core/locales/en-US/messages.json',
'red/api/locales/en-US/editor.json',
'red/runtime/locales/en-US/runtime.json'
]
},
keymaps: {
src: [
'editor/js/keymap.json'
]
}
},
attachCopyright: {
js: {
src: [
'public/red/red.min.js'
'public/red/red.min.js',
'public/red/main.min.js'
]
},
css: {
@@ -189,13 +254,33 @@ module.exports = function(grunt) {
files: [
'editor/js/**/*.js'
],
tasks: ['concat','uglify','attachCopyright:js']
tasks: ['copy:build','concat','uglify','attachCopyright:js']
},
sass: {
files: [
'editor/sass/**/*.scss'
],
tasks: ['sass','attachCopyright:css']
},
json: {
files: [
'nodes/core/locales/en-US/messages.json',
'red/api/locales/en-US/editor.json',
'red/runtime/locales/en-US/runtime.json'
],
tasks: ['jsonlint:messages']
},
keymaps: {
files: [
'editor/js/keymap.json'
],
tasks: ['jsonlint:keymaps','copy:build']
},
misc: {
files: [
'CHANGELOG.md'
],
tasks: ['copy:build']
}
},
@@ -204,8 +289,8 @@ module.exports = function(grunt) {
dev: {
script: 'red.js',
options: {
args:['-v'],
ext: 'js,html',
args: nodemonArgs,
ext: 'js,html,json',
watch: [
'red','nodes'
]
@@ -224,39 +309,54 @@ module.exports = function(grunt) {
copy: {
build: {
files:[{
cwd: 'editor/images',
src: '**',
expand: true,
dest: 'public/red/images/'
},
{
cwd: 'editor/vendor',
src: [
'ace/**',
'bootstrap/css/**',
'bootstrap/img/**',
'jquery/css/**',
'font-awesome/**'
],
expand: true,
dest: 'public/vendor/'
},
{
cwd: 'editor/icons',
src: '**',
expand: true,
dest: 'public/icons/'
},
{
expand: true,
src: ['editor/index.html','editor/favicon.ico'],
dest: 'public/',
flatten: true
}]
files:[
{
src: 'editor/js/main.js',
dest: 'public/red/main.js'
},
{
src: 'editor/js/keymap.json',
dest: 'public/red/keymap.json'
},
{
cwd: 'editor/images',
src: '**',
expand: true,
dest: 'public/red/images/'
},
{
cwd: 'editor/vendor',
src: [
'ace/**',
//'bootstrap/css/**',
'bootstrap/img/**',
'jquery/css/**',
'font-awesome/**'
],
expand: true,
dest: 'public/vendor/'
},
{
cwd: 'editor/icons',
src: '**',
expand: true,
dest: 'public/icons/'
},
{
expand: true,
src: ['editor/index.html','editor/favicon.ico'],
dest: 'public/',
flatten: true
},
{
src: 'CHANGELOG.md',
dest: 'public/red/about'
}
]
},
release: {
files: [{
mode: true,
expand: true,
src: [
'*.md',
@@ -269,13 +369,24 @@ module.exports = function(grunt) {
'nodes/core/**',
'red/**',
'public/**',
'editor/templates/**'
'editor/templates/**',
'bin/**'
],
dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>')
}]
}
},
chmod: {
options: {
mode: '755'
},
release: {
// Target-specific file/dir lists and/or options go here.
src: [
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*')
]
}
},
compress: {
release: {
options: {
@@ -299,11 +410,14 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-nodemon');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-chmod');
grunt.loadNpmTasks('grunt-jsonlint');
grunt.loadNpmTasks('grunt-mocha-istanbul');
grunt.registerMultiTask('attachCopyright', function() {
var files = this.data.src;
var copyright = "/**\n"+
" * Copyright 2013, 2015 IBM Corp.\n"+
" * Copyright JS Foundation and other contributors, http://js.foundation\n"+
" *\n"+
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"+
" * you may not use this file except in compliance with the License.\n"+
@@ -319,7 +433,7 @@ module.exports = function(grunt) {
" **/\n";
if (files) {
for (var i=0;i<files.length;i++) {
for (var i=0; i<files.length; i++) {
var file = files[i];
if (!grunt.file.exists(file)) {
grunt.log.warn('File '+ file + ' not found');
@@ -364,7 +478,7 @@ module.exports = function(grunt) {
grunt.registerTask('build',
'Builds editor content',
['clean:build','concat:build','concat:vendor','uglify:build','sass:build','copy:build','attachCopyright']);
['clean:build','jsonlint','concat:build','concat:vendor','copy:build','uglify:build','sass:build','attachCopyright']);
grunt.registerTask('dev',
'Developer mode: run node-red, watch for source changes and build/restart',
@@ -372,6 +486,9 @@ module.exports = function(grunt) {
grunt.registerTask('release',
'Create distribution zip file',
['build','clean:release','copy:release','compress:release']);
['build','clean:release','copy:release','chmod:release','compress:release']);
grunt.registerTask('coverage',
'Run Istanbul code test coverage task',
['build','mocha_istanbul']);
};

View File

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

View File

@@ -2,8 +2,8 @@
http://nodered.org
[![Build Status](https://travis-ci.org/node-red/node-red.png)](https://travis-ci.org/node-red/node-red)
[![Coverage Status](https://coveralls.io/repos/node-red/node-red/badge.png?branch=master)](https://coveralls.io/r/node-red/node-red?branch=master)
[![Build Status](https://travis-ci.org/node-red/node-red.svg)](https://travis-ci.org/node-red/node-red)
[![Coverage Status](https://coveralls.io/repos/node-red/node-red/badge.svg?branch=master)](https://coveralls.io/r/node-red/node-red?branch=master)
A visual tool for wiring the Internet of Things.
@@ -29,24 +29,23 @@ For further help, or general discussion, please use the
If you want to run the latest code from git, here's how to get started:
1. Install grunt, the build tool
1. Clone the code:
npm install -g grunt-cli
2. Clone the code:
git clone git@github.com:node-red/node-red.git
git clone https://github.com/node-red/node-red.git
cd node-red
3. Install the node-red dependencies
2. Install the node-red dependencies
npm install
4. Build the code
3. Build the code
grunt build
npm run build
5. Run
4. Run
npm start
or
node red.js
@@ -55,16 +54,21 @@ If you want to run the latest code from git, here's how to get started:
Before raising a pull-request, please read our
[contributing guide](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md).
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
By participating, you are expected to uphold this code. Please report unacceptable
behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
## Authors
Node-RED is a creation of [IBM Emerging Technology](http://ibm.com/blogs/et).
Node-RED is a project of the [JS Foundation](http://js.foundation).
It was created by [IBM Emerging Technology](https://www.ibm.com/blogs/emerging-technology/).
* Nick O'Leary [@knolleary](http://twitter.com/knolleary)
* Dave Conway-Jones [@ceejay](http://twitter.com/ceejay)
For more open-source projects from IBM, head over [here](http://ibm.github.io).
## Copyright and license
Copyright 2013, 2015 IBM Corp. under [the Apache 2.0 license](LICENSE).
Copyright JS Foundation and other contributors, http://js.foundation under [the Apache 2.0 license](LICENSE).

View File

@@ -1,6 +1,6 @@
#!/bin/bash
#
# Copyright 2015 IBM Corp.
# 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.
@@ -40,4 +40,4 @@ SCRIPT_PATH="`pwd`";
cd $CURRENT_PATH
# Run Node-RED
/usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS
exec /usr/bin/env node $OPTIONS $SCRIPT_PATH/../red.js $ARGS

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 B

After

Width:  |  Height:  |  Size: 508 B

BIN
editor/icons/cog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

BIN
editor/icons/join.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
editor/icons/link-out.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

BIN
editor/icons/parser-csv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

BIN
editor/icons/parser-xml.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

BIN
editor/icons/split.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

After

Width:  |  Height:  |  Size: 192 B

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="480" height="480" viewBox="0, 0, 480, 480">
<g id="Calque_1">
<path d="M408,16 C438.928,16 464,41.072 464,72 L464,408 C464,438.928 438.928,464 408,464 L72,464 C41.072,464 16,438.928 16,408 L16,296.002 L69.339,296.002 C89.715,296.002 105.993,279.497 105.993,259.12 L105.992,242.19 C190.296,243.397 214.83,265.317 241.661,288.777 C267.502,311.375 296.48,335.662 371.989,336.261 L371.993,344.57 C372.002,364.947 388.693,382 409.069,382 L463.991,382 L463.991,356 L409.069,356 C402.189,356 396.991,351.449 396.991,344.569 L396.991,308.32 C396.991,301.44 402.189,296 409.069,296 L463.991,296 L463.991,272 L409.069,272 C388.693,272 372.002,287.943 371.993,308.32 L371.99,316.908 C300.63,316.672 280.362,296.883 254.41,274.189 C232.267,254.825 206.244,233.534 148.914,225.789 C149.412,225.361 149.872,224.945 150.353,224.505 C161.391,214.382 167.343,202.153 173.167,191.593 C178.99,181.034 184.469,172.221 193.444,166.061 C200.725,161.064 211.08,157.338 226.992,156.647 L226.993,165.123 C226.997,185.5 243.431,202.999 263.808,202.999 L411.141,202.999 C431.517,202.999 447.993,185.5 447.993,165.123 L447.993,128.874 C447.993,108.497 431.517,91.999 411.141,91.999 L263.808,91.999 C243.431,91.999 226.983,108.496 226.993,128.874 L226.998,137.281 C207.794,138.053 193.238,142.713 182.496,150.086 C169.469,159.028 162.277,171.247 156.21,182.247 C150.144,193.247 145.009,203.104 137.25,210.218 C130.497,216.411 121.157,221.193 105.993,222.976 L105.993,222.579 C106.111,202.203 89.715,186.002 69.339,186.002 L16,186.002 L16,72 C16,41.072 41.072,16 72,16 L408,16 z" fill="#000000"/>
<path d="M16,211.002 L69.339,211.002 C76.219,211.002 81.992,215.991 81.992,222.871 L81.992,259.12 C81.992,266 76.219,272.002 69.339,272.002 L16,272.002 L16,211.002 z" fill="#000000"/>
<path d="M411.135,116.997 C418.015,116.997 422.987,121.992 422.987,128.872 L422.987,165.122 C422.987,172.002 418.015,176.998 411.135,176.998 L263.802,176.998 C256.923,176.998 250.99,172.002 250.99,165.122 L250.99,128.872 C250.99,121.993 256.923,116.997 263.802,116.997 L411.135,116.997 z" fill="#000000"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="480" width="480" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 480.00002 479.99999">
<title>Node-RED Icon</title>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title>Node-RED Icon</dc:title>
<cc:license rdf:resource="http://creativecommons.org/licenses/by/3.0/"/>
<dc:creator>
<cc:Agent>
<dc:title>Nick O&apos;Leary</dc:title>
</cc:Agent>
</dc:creator>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by/3.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
<g transform="translate(0 -572.36)">
<rect style="color-rendering:auto;color:#000000;isolation:auto;mix-blend-mode:normal;shape-rendering:auto;solid-color:#000000;image-rendering:auto" ry="56" height="448" width="448" y="588.36" x="16" fill="#8f0000"/>
<g transform="matrix(8.545 0 0 8.545 -786.19 -1949.8)">
<path style="color-rendering:auto;text-decoration-color:#000000;color:#000000;isolation:auto;mix-blend-mode:normal;shape-rendering:auto;solid-color:#000000;block-progression:tb;text-decoration-line:none;text-decoration-style:solid;image-rendering:auto;white-space:normal;text-indent:0;text-transform:none" d="m104.41 321.21c0.0138-2.3846-1.905-4.2806-4.2896-4.2806h-6.243v2.9257h6.243c0.80513 0 1.4808 0.58383 1.4808 1.389v4.2422c0 0.80513-0.67566 1.5075-1.4808 1.5075h-6.243v2.8086h6.243c2.3846 0 4.2895-1.9315 4.2895-4.3162l-0.00005-1.9812c9.8659 0.14125 12.737 2.7065 15.877 5.4519 3.0241 2.6446 6.4153 5.4869 15.252 5.557l0.00046 0.97238c0.001 2.3846 1.9543 4.3803 4.3389 4.3803h6.4273v-3.0427h-6.4273c-0.80514 0-1.4135-0.53255-1.4135-1.3377v-4.2422c0-0.80513 0.60835-1.4418 1.4135-1.4418h6.4273v-2.8086h-6.4273c-2.3846 0-4.3379 1.8658-4.3389 4.2504l-0.00045 1.005c-8.351-0.0276-10.723-2.3434-13.76-4.9992-2.5914-2.2662-5.6368-4.7578-12.346-5.6642 0.0583-0.0501 0.11211-0.0987 0.16838-0.15027 1.2918-1.1846 1.9884-2.6158 2.6699-3.8516 0.68148-1.2357 1.3227-2.267 2.373-2.9879 0.85207-0.58483 2.0639-1.0208 3.926-1.1017l0.00018 0.99192c0.00043 2.3846 1.9236 4.4325 4.3083 4.4325h17.242c2.3846 0 4.3127-2.0479 4.3127-4.4325v-4.2422c0-2.3846-1.9281-4.3153-4.3127-4.3153h-17.242c-2.3846 0-4.3095 1.9306-4.3083 4.3153l0.00051 0.98395c-2.2474 0.0903-3.9508 0.6357-5.2079 1.4985-1.5245 1.0464-2.3662 2.4764-3.0762 3.7637-0.70992 1.2873-1.3108 2.4408-2.2188 3.2734-0.79034 0.72475-1.8834 1.2844-3.658 1.493zm18.468-12.356h17.242c0.80514 0 1.387 0.58455 1.387 1.3897v4.2422c0 0.80514-0.5819 1.3898-1.387 1.3898h-17.242c-0.80514 0-1.4994-0.58462-1.4994-1.3898v-4.2422c0-0.80513 0.69431-1.3897 1.4994-1.3897z" fill="#fff"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

View File

@@ -1,177 +0,0 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<!--
Copyright 2013, 2015 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<head>
<title>Node-RED</title>
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="vendor/jquery/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" media="screen">
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="vendor/vendor.css">
<link rel="stylesheet" href="red/style.min.css">
</head>
<body spellcheck="false">
<div id="header">
<span class="logo"><img src="red/images/node-red.png"> <span>Node-RED</span></span>
<ul class="header-toolbar hide">
<li><a id="btn-sidemenu" class="button" data-toggle="dropdown" href="#"><i class="fa fa-bars"></i></a></li>
<ul>
</div>
<div id="main-container" class="sidebar-closed hide">
<div id="palette">
<img src="red/images/spin.svg" class="palette-spinner hide"/>
<div id="palette-container" class="palette-scroll">
</div>
<div id="palette-search">
<i class="fa fa-search"></i><input id="palette-search-input" type="text" placeholder="filter"><a href="#" id="palette-search-clear"><i class="fa fa-times"></i></a></input>
</div>
</div><!-- /palette -->
<div id="workspace">
<ul id="workspace-tabs"></ul>
<div id="workspace-add-tab"><a id="btn-workspace-add-tab" href="#"><i class="fa fa-plus"></i></a></div>
<div id="chart"></div>
<div id="workspace-toolbar">
<a class="button" id="workspace-subflow-edit" href="#"><i class="fa fa-pencil"></i> edit name</a>
<a class="button disabled" id="workspace-subflow-add-input" href="#"><i class="fa fa-plus"></i> input</a>
<a class="button" id="workspace-subflow-add-output" href="#"><i class="fa fa-plus"></i> output</a>
<a class="button" id="workspace-subflow-delete" href="#"><i class="fa fa-trash"></i> delete subflow</a>
</div>
</div>
<div id="chart-zoom-controls">
<div class="btn-group">
<a class="btn btn-mini" id="btn-zoom-out" href="#"><i class="fa fa-search-minus"></i></a>
<a class="btn btn-mini" id="btn-zoom-zero" href="#"><i class="fa fa-dot-circle-o"></i></a>
<a class="btn btn-mini" id="btn-zoom-in" href="#"><i class="fa fa-search-plus"></i></a>
</div>
</div>
<div id="sidebar">
<ul id="sidebar-tabs"></ul>
<div id="sidebar-content"></div>
</div>
<div id="sidebar-separator"></div>
</div>
<div id="notifications"></div>
<div id="dropTarget"><div>Drop the flow here<br/><i class="fa fa-download"></i></div></div>
<div id="dialog" class="hide"><form id="dialog-form" class="form-horizontal"></form></div>
<div id="node-config-dialog" class="hide"><form id="dialog-config-form" class="form-horizontal"></form><div class="form-tips" id="node-config-dialog-user-count"></div></div>
<div id="subflow-dialog" class="hide">
<form class="form-horizontal">
<div class="form-row">
<label>Name</label><input type="text" id="subflow-input-name">
</div>
</form>
<div class="form-tips" id="subflow-dialog-user-count"></div>
</div>
<div id="node-dialog-confirm-deploy" class="hide">
<form class="form-horizontal">
<div id="node-dialog-confirm-deploy-config" style="text-align: center; padding-top: 30px;">
Some of the nodes are not properly configured. Are you sure you want to deploy?
</div>
<div id="node-dialog-confirm-deploy-unknown" style="text-align: center; padding-top: 10px;">
The workspace contains some unknown node types:
<ul style="width: 300px; margin: auto; text-align: left;" id="node-dialog-confirm-deploy-unknown-list"></ul>
Are you sure you want to deploy?
</div>
</form>
</div>
<div id="node-dialog-library-save-confirm" class="hide">
<form class="form-horizontal">
<div style="text-align: center; padding-top: 30px;">
A <span id="node-dialog-library-save-type"></span> called <span id="node-dialog-library-save-name"></span> already exists. Overwrite?
</div>
</form>
</div>
<div id="node-dialog-library-save" class="hide">
<form class="form-horizontal">
<div class="form-row">
<label for="node-dialog-library-save-folder"><i class="fa fa-folder-open"></i> Folder</label>
<input type="text" id="node-dialog-library-save-folder" placeholder="Folder">
</div>
<div class="form-row">
<label for="node-dialog-library-save-filename"><i class="fa fa-file"></i> Filename</label>
<input type="text" id="node-dialog-library-save-filename" placeholder="Filename">
</div>
</form>
</div>
<div id="node-dialog-library-lookup" class="hide">
<form class="form-horizontal">
<div class="form-row">
<ul id="node-dialog-library-breadcrumbs" class="breadcrumb">
<li class="active"><a href="#">Library</a></li>
</ul>
</div>
<div class="form-row">
<div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;">
<div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div>
</div>
<div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;">
<div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div>
</div>
</div>
</form>
</div>
<div id="node-dialog-rename-workspace" class="hide">
<form class="form-horizontal">
<div class="form-row">
<label for="node-input-workspace-name" ><i class="fa fa-tag"></i> Name:</label>
<input type="text" id="node-input-workspace-name">
</div>
</form>
</div>
<div id="node-dialog-delete-workspace" class="hide">
<form class="form-horizontal">
<div style="text-align: center; padding-top: 30px;">
Are you sure you want to delete '<span id="node-dialog-delete-workspace-name"></span>'?
</div>
</form>
</div>
<script type="text/x-red" data-template-name="export-library-dialog">
<div class="form-row">
<label for="node-input-filename" ><i class="fa fa-file"></i> Filename:</label>
<input type="text" id="node-input-filename" placeholder="Filename">
</div>
</script>
<script type="text/x-red" data-template-name="subflow">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="name">
</div>
</script>
<script src="vendor/vendor.js"></script>
<script src="vendor/ace/ace.js"></script>
<script src="vendor/ace/ext-language_tools.js"></script>
<script src="red/red.min.js"></script>
</body>
</html>

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2014 IBM Corp.
* 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.
@@ -13,23 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.comms = (function() {
var errornotification = null;
var clearErrorTimer = null;
var connectCountdownTimer = null;
var connectCountdown = 10;
var subscriptions = {};
var ws;
var pendingAuth = false;
var reconnectAttempts = 0;
var active = false;
function connectWS() {
var path = location.hostname+":"+location.port+document.location.pathname;
active = true;
var path = location.hostname;
var port = location.port;
if (port.length !== 0) {
path = path+":"+port;
}
path = path+document.location.pathname;
path = path+(path.slice(-1) == "/"?"":"/")+"comms";
path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
var auth_tokens = RED.settings.get("auth-tokens");
pendingAuth = (auth_tokens!=null);
function completeConnection() {
for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) {
@@ -37,9 +47,10 @@ RED.comms = (function() {
}
}
}
ws = new WebSocket(path);
ws.onopen = function() {
reconnectAttempts = 0;
if (errornotification) {
clearErrorTimer = setTimeout(function() {
errornotification.close();
@@ -54,9 +65,17 @@ RED.comms = (function() {
}
ws.onmessage = function(event) {
var msg = JSON.parse(event.data);
if (pendingAuth && msg.auth == "ok") {
pendingAuth = false;
completeConnection();
if (pendingAuth && msg.auth) {
if (msg.auth === "ok") {
pendingAuth = false;
completeConnection();
} else if (msg.auth === "fail") {
// anything else is an error...
active = false;
RED.user.login({updateMenu:true},function() {
connectWS();
})
}
} else if (msg.topic) {
for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) {
@@ -74,16 +93,45 @@ RED.comms = (function() {
}
};
ws.onclose = function() {
if (errornotification == null) {
errornotification = RED.notify("<b>Error</b>: Lost connection to server","error",true);
} else if (clearErrorTimer) {
if (!active) {
return;
}
if (clearErrorTimer) {
clearTimeout(clearErrorTimer);
clearErrorTimer = null;
}
setTimeout(connectWS,1000);
reconnectAttempts++;
if (reconnectAttempts < 10) {
setTimeout(connectWS,1000);
if (reconnectAttempts > 5 && errornotification == null) {
errornotification = RED.notify(RED._("notification.errors.lostConnection"),"error",true);
}
} else if (reconnectAttempts < 20) {
setTimeout(connectWS,2000);
} else {
connectCountdown = 60;
connectCountdownTimer = setInterval(function() {
connectCountdown--;
if (connectCountdown === 0) {
errornotification.update(RED._("notification.errors.lostConnection"));
clearInterval(connectCountdownTimer);
connectWS();
} else {
var msg = RED._("notification.errors.lostConnectionReconnect",{time: connectCountdown})+' <a href="#">'+ RED._("notification.errors.lostConnectionTry")+'</a>';
errornotification.update(msg);
$(errornotification).find("a").click(function(e) {
e.preventDefault();
errornotification.update(RED._("notification.errors.lostConnection"));
clearInterval(connectCountdownTimer);
connectWS();
})
}
},1000);
}
}
}
function subscribe(topic,callback) {
if (subscriptions[topic] == null) {
subscriptions[topic] = [];
@@ -93,7 +141,7 @@ RED.comms = (function() {
ws.send(JSON.stringify({subscribe:topic}));
}
}
function unsubscribe(topic,callback) {
if (subscriptions[topic]) {
for (var i=0;i<subscriptions[topic].length;i++) {
@@ -107,7 +155,7 @@ RED.comms = (function() {
}
}
}
return {
connect: connectWS,
subscribe: subscribe,

53
editor/js/events.js Normal file
View File

@@ -0,0 +1,53 @@
/**
* 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.events = (function() {
var handlers = {};
function on(evt,func) {
handlers[evt] = handlers[evt]||[];
handlers[evt].push(func);
}
function off(evt,func) {
var handler = handlers[evt];
if (handler) {
for (var i=0;i<handler.length;i++) {
if (handler[i] === func) {
handler.splice(i,1);
return;
}
}
}
}
function emit(evt,arg) {
if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) {
try {
handlers[evt][i](arg);
} catch(err) {
console.log("RED.events.emit error: ["+evt+"] "+(err.toString()));
console.log(err);
}
}
}
}
return {
on: on,
off: off,
emit: emit
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013, 2015 IBM Corp.
* 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.
@@ -15,7 +15,290 @@
**/
RED.history = (function() {
var undo_history = [];
function undoEvent(ev) {
var i;
var len;
var node;
var subflow;
var modifiedTabs = {};
if (ev) {
if (ev.t == 'multi') {
len = ev.events.length;
for (i=len-1;i>=0;i--) {
undoEvent(ev.events[i]);
}
} else if (ev.t == 'replace') {
RED.nodes.clear();
var imported = RED.nodes.import(ev.config);
imported[0].forEach(function(n) {
if (ev.changed[n.id]) {
n.changed = true;
}
})
RED.nodes.version(ev.rev);
} else if (ev.t == 'add') {
if (ev.nodes) {
for (i=0;i<ev.nodes.length;i++) {
node = RED.nodes.node(ev.nodes[i]);
if (node.z) {
modifiedTabs[node.z] = true;
}
RED.nodes.remove(ev.nodes[i]);
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.workspaces) {
for (i=0;i<ev.workspaces.length;i++) {
RED.nodes.removeWorkspace(ev.workspaces[i].id);
RED.workspaces.remove(ev.workspaces[i]);
}
}
if (ev.subflows) {
for (i=0;i<ev.subflows.length;i++) {
RED.nodes.removeSubflow(ev.subflows[i]);
RED.workspaces.remove(ev.subflows[i]);
}
}
if (ev.subflow) {
if (ev.subflow.instances) {
ev.subflow.instances.forEach(function(n) {
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
node.dirty = true;
}
});
}
if (ev.subflow.hasOwnProperty('changed')) {
subflow = RED.nodes.subflow(ev.subflow.id);
if (subflow) {
subflow.changed = ev.subflow.changed;
}
}
}
if (ev.removedLinks) {
for (i=0;i<ev.removedLinks.length;i++) {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "delete") {
if (ev.workspaces) {
for (i=0;i<ev.workspaces.length;i++) {
RED.nodes.addWorkspace(ev.workspaces[i]);
RED.workspaces.add(ev.workspaces[i]);
}
}
if (ev.subflow && ev.subflow.subflow) {
RED.nodes.addSubflow(ev.subflow.subflow);
}
if (ev.subflowInputs && ev.subflowInputs.length > 0) {
subflow = RED.nodes.subflow(ev.subflowInputs[0].z);
subflow.in.push(ev.subflowInputs[0]);
subflow.in[0].dirty = true;
}
if (ev.subflowOutputs && ev.subflowOutputs.length > 0) {
subflow = RED.nodes.subflow(ev.subflowOutputs[0].z);
ev.subflowOutputs.sort(function(a,b) { return a.i-b.i});
for (i=0;i<ev.subflowOutputs.length;i++) {
var output = ev.subflowOutputs[i];
subflow.out.splice(output.i,0,output);
for (var j=output.i+1;j<subflow.out.length;j++) {
subflow.out[j].i++;
subflow.out[j].dirty = true;
}
RED.nodes.eachLink(function(l) {
if (l.source.type == "subflow:"+subflow.id) {
if (l.sourcePort >= output.i) {
l.sourcePort++;
}
}
});
}
}
if (ev.subflow && ev.subflow.hasOwnProperty('instances')) {
ev.subflow.instances.forEach(function(n) {
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
node.dirty = true;
}
});
}
if (subflow) {
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.nodes) {
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.add(ev.nodes[i]);
modifiedTabs[ev.nodes[i].z] = true;
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
}
}
if (ev.changes) {
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
node = RED.nodes.node(i);
if (node) {
for (var d in ev.changes[i]) {
if (ev.changes[i].hasOwnProperty(d)) {
node[d] = ev.changes[i][d];
}
}
node.dirty = true;
}
}
}
}
} else if (ev.t == "move") {
for (i=0;i<ev.nodes.length;i++) {
var n = ev.nodes[i];
n.n.x = n.ox;
n.n.y = n.oy;
n.n.dirty = true;
n.n.moved = n.moved;
}
// A move could have caused a link splice
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.removedLinks) {
for (i=0;i<ev.removedLinks.length;i++) {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "edit") {
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
if (ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
// This is a config node property
var currentConfigNode = RED.nodes.node(ev.node[i]);
if (currentConfigNode) {
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
}
var newConfigNode = RED.nodes.node(ev.changes[i]);
if (newConfigNode) {
newConfigNode.users.push(ev.node);
}
}
ev.node[i] = ev.changes[i];
}
}
if (ev.subflow) {
if (ev.subflow.hasOwnProperty('inputCount')) {
if (ev.node.in.length > ev.subflow.inputCount) {
ev.node.in.splice(ev.subflow.inputCount);
} else if (ev.subflow.inputs.length > 0) {
ev.node.in = ev.node.in.concat(ev.subflow.inputs);
}
}
if (ev.subflow.hasOwnProperty('outputCount')) {
if (ev.node.out.length > ev.subflow.outputCount) {
ev.node.out.splice(ev.subflow.outputCount);
} else if (ev.subflow.outputs.length > 0) {
ev.node.out = ev.node.out.concat(ev.subflow.outputs);
}
}
if (ev.subflow.hasOwnProperty('instances')) {
ev.subflow.instances.forEach(function(n) {
var node = RED.nodes.node(n.id);
if (node) {
node.changed = n.changed;
node.dirty = true;
}
});
}
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
n.inputs = ev.node.in.length;
n.outputs = ev.node.out.length;
RED.editor.updateNodeProperties(n);
});
} else {
var outputMap;
if (ev.outputMap) {
outputMap = {};
for (var port in ev.outputMap) {
if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== "-1") {
outputMap[ev.outputMap[port]] = port;
}
}
}
RED.editor.updateNodeProperties(ev.node,outputMap);
RED.editor.validateNode(ev.node);
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
}
}
ev.node.dirty = true;
ev.node.changed = ev.changed;
} else if (ev.t == "createSubflow") {
if (ev.nodes) {
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
n.z = ev.activeWorkspace;
n.dirty = true;
});
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.remove(ev.nodes[i]);
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
RED.nodes.removeSubflow(ev.subflow.subflow);
RED.workspaces.remove(ev.subflow.subflow);
if (ev.removedLinks) {
for (i=0;i<ev.removedLinks.length;i++) {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
} else if (ev.t == "reorder") {
if (ev.order) {
RED.workspaces.order(ev.order);
}
}
Object.keys(modifiedTabs).forEach(function(id) {
var subflow = RED.nodes.subflow(id);
if (subflow) {
RED.editor.validateNode(subflow);
}
});
RED.nodes.dirty(ev.dirty);
RED.view.redraw(true);
RED.palette.refresh();
RED.workspaces.refresh();
RED.sidebar.config.refresh();
}
}
return {
//TODO: this function is a placeholder until there is a 'save' event that can be listened to
markAllDirty: function() {
@@ -23,6 +306,9 @@ RED.history = (function() {
undo_history[i].dirty = true;
}
},
list: function() {
return undo_history
},
depth: function() {
return undo_history.length;
},
@@ -31,179 +317,10 @@ RED.history = (function() {
},
pop: function() {
var ev = undo_history.pop();
var i;
var node;
var modifiedTabs = {};
if (ev) {
if (ev.t == 'add') {
if (ev.nodes) {
for (i=0;i<ev.nodes.length;i++) {
node = RED.nodes.node(ev.nodes[i]);
if (node.z) {
modifiedTabs[node.z] = true;
}
RED.nodes.remove(ev.nodes[i]);
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
if (ev.workspaces) {
for (i=0;i<ev.workspaces.length;i++) {
RED.nodes.removeWorkspace(ev.workspaces[i].id);
RED.workspaces.remove(ev.workspaces[i]);
}
}
if (ev.subflows) {
for (i=0;i<ev.subflows.length;i++) {
RED.nodes.removeSubflow(ev.subflows[i]);
RED.workspaces.remove(ev.subflows[i]);
}
}
} else if (ev.t == "delete") {
if (ev.workspaces) {
for (i=0;i<ev.workspaces.length;i++) {
RED.nodes.addWorkspace(ev.workspaces[i]);
RED.workspaces.add(ev.workspaces[i]);
}
}
if (ev.subflow) {
RED.nodes.addSubflow(ev.subflow);
}
var subflow;
if (ev.subflowInputs && ev.subflowInputs.length > 0) {
subflow = RED.nodes.subflow(ev.subflowInputs[0].z);
subflow.in.push(ev.subflowInputs[0]);
subflow.in[0].dirty = true;
}
if (ev.subflowOutputs && ev.subflowOutputs.length > 0) {
subflow = RED.nodes.subflow(ev.subflowOutputs[0].z);
ev.subflowOutputs.sort(function(a,b) { return a.i-b.i});
for (i=0;i<ev.subflowOutputs.length;i++) {
var output = ev.subflowOutputs[i];
subflow.out.splice(output.i,0,output);
for (var j=output.i+1;j<subflow.out.length;j++) {
subflow.out[j].i++;
subflow.out[j].dirty = true;
}
RED.nodes.eachLink(function(l) {
if (l.source.type == "subflow:"+subflow.id) {
if (l.sourcePort >= output.i) {
l.sourcePort++;
}
}
});
}
}
if (subflow) {
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
n.changed = true;
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.nodes) {
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.add(ev.nodes[i]);
modifiedTabs[ev.nodes[i].z] = true;
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
}
}
} else if (ev.t == "move") {
for (i=0;i<ev.nodes.length;i++) {
var n = ev.nodes[i];
n.n.x = n.ox;
n.n.y = n.oy;
n.n.dirty = true;
}
} else if (ev.t == "edit") {
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
ev.node[i] = ev.changes[i];
}
}
if (ev.subflow) {
if (ev.subflow.hasOwnProperty('inputCount')) {
if (ev.node.in.length > ev.subflow.inputCount) {
ev.node.in.splice(ev.subflow.inputCount);
} else if (ev.subflow.inputs.length > 0) {
ev.node.in = ev.node.in.concat(ev.subflow.inputs);
}
}
if (ev.subflow.hasOwnProperty('outputCount')) {
if (ev.node.out.length > ev.subflow.outputCount) {
ev.node.out.splice(ev.subflow.outputCount);
} else if (ev.subflow.outputs.length > 0) {
ev.node.out = ev.node.out.concat(ev.subflow.outputs);
}
}
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
n.changed = ev.changed;
n.inputs = ev.node.in.length;
n.outputs = ev.node.out.length;
RED.editor.updateNodeProperties(n);
});
RED.palette.refresh();
} else {
RED.editor.updateNodeProperties(ev.node);
RED.editor.validateNode(ev.node);
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.addLink(ev.links[i]);
}
}
ev.node.dirty = true;
ev.node.changed = ev.changed;
} else if (ev.t == "createSubflow") {
if (ev.nodes) {
RED.nodes.filterNodes({z:ev.subflow.id}).forEach(function(n) {
n.z = ev.activeWorkspace;
n.dirty = true;
});
for (i=0;i<ev.nodes.length;i++) {
RED.nodes.remove(ev.nodes[i]);
}
}
if (ev.links) {
for (i=0;i<ev.links.length;i++) {
RED.nodes.removeLink(ev.links[i]);
}
}
RED.nodes.removeSubflow(ev.subflow);
RED.workspaces.remove(ev.subflow);
if (ev.removedLinks) {
for (i=0;i<ev.removedLinks.length;i++) {
RED.nodes.addLink(ev.removedLinks[i]);
}
}
}
Object.keys(modifiedTabs).forEach(function(id) {
var subflow = RED.nodes.subflow(id);
if (subflow) {
RED.editor.validateNode(subflow);
}
});
RED.nodes.dirty(ev.dirty);
RED.view.redraw(true);
RED.palette.refresh();
}
undoEvent(ev);
},
peek: function() {
return undo_history[undo_history.length-1];
}
}

86
editor/js/i18n.js Normal file
View File

@@ -0,0 +1,86 @@
/**
* 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.i18n = (function() {
return {
init: function(done) {
i18n.init({
resGetPath: 'locales/__ns__?lng=__lng__',
dynamicLoad: false,
load:'current',
ns: {
namespaces: ["editor","node-red","jsonata","infotips"],
defaultNs: "editor"
},
fallbackLng: ['en-US'],
useCookie: false
},function() {
done();
});
RED["_"] = function() {
return i18n.t.apply(null,arguments);
}
},
loadCatalog: function(namespace,done) {
var languageList = i18n.functions.toLanguages(i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
$.ajax({
headers: {
"Accept":"application/json"
},
cache: false,
url: 'locales/'+namespace+'?lng='+lang,
success: function(data) {
i18n.addResourceBundle(lang,namespace,data);
toLoad--;
if (toLoad === 0) {
done();
}
}
});
})
},
loadNodeCatalogs: function(done) {
var languageList = i18n.functions.toLanguages(i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
$.ajax({
headers: {
"Accept":"application/json"
},
cache: false,
url: 'locales/nodes?lng='+lang,
success: function(data) {
var namespaces = Object.keys(data);
namespaces.forEach(function(ns) {
i18n.addResourceBundle(lang,ns,data[ns]);
});
toLoad--;
if (toLoad === 0) {
done();
}
}
});
})
}
}
})();

39
editor/js/keymap.json Normal file
View File

@@ -0,0 +1,39 @@
{
"*": {
"ctrl-shift-p":"core:manage-palette",
"ctrl-f": "core:search",
"ctrl-=": "core:zoom-in",
"ctrl--": "core:zoom-out",
"ctrl-0": "core:zoom-reset",
"ctrl-enter": "core:confirm-edit-tray",
"ctrl-escape": "core:cancel-edit-tray",
"ctrl-g i": "core:show-info-tab",
"ctrl-g d": "core:show-debug-tab",
"ctrl-g c": "core:show-config-tab",
"ctrl-e": "core:show-export-dialog",
"ctrl-i": "core:show-import-dialog",
"ctrl-space": "core:toggle-sidebar",
"ctrl-,": "core:show-user-settings"
},
"workspace": {
"backspace": "core:delete-selection",
"delete": "core:delete-selection",
"enter": "core:edit-selected-node",
"ctrl-c": "core:copy-selection-to-internal-clipboard",
"ctrl-x": "core:cut-selection-to-internal-clipboard",
"ctrl-v": "core:paste-from-internal-clipboard",
"ctrl-z": "core:undo",
"ctrl-a": "core:select-all-nodes",
"shift-?": "core:show-help",
"up": "core:move-selection-up",
"right": "core:move-selection-right",
"down": "core:move-selection-down",
"left": "core:move-selection-left",
"shift-up": "core:step-selection-up",
"shift-right": "core:step-selection-right",
"shift-down": "core:step-selection-down",
"shift-left": "core:step-selection-left",
"ctrl-shift-j": "core:show-previous-tab",
"ctrl-shift-k": "core:show-next-tab"
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013, 2015 IBM Corp.
* 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.
@@ -13,12 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var RED = (function() {
function loadSettings() {
RED.settings.init(loadNodeList);
}
(function() {
function loadNodeList() {
$.ajax({
@@ -29,7 +24,7 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
RED.nodes.setNodeList(data);
loadNodes();
RED.i18n.loadNodeCatalogs(loadNodes);
}
});
}
@@ -43,9 +38,10 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
$("body").append(data);
$(".palette-spinner").hide();
$(".palette-scroll").show();
$("#palette-search").show();
$("body").i18n();
$("#palette > .palette-spinner").hide();
$(".palette-scroll").removeClass("hide");
$("#palette-search").removeClass("hide");
loadFlows();
}
});
@@ -54,137 +50,210 @@ var RED = (function() {
function loadFlows() {
$.ajax({
headers: {
"Accept":"application/json"
"Accept":"application/json",
},
cache: false,
url: 'flows',
success: function(nodes) {
RED.nodes.import(nodes);
var currentHash = window.location.hash;
RED.nodes.version(nodes.rev);
RED.nodes.import(nodes.flows);
RED.nodes.dirty(false);
RED.view.redraw(true);
if (/^#flow\/.+$/.test(currentHash)) {
RED.workspaces.show(currentHash.substring(6));
}
var persistentNotifications = {};
RED.comms.subscribe("notification/#",function(topic,msg) {
var parts = topic.split("/");
var notificationId = parts[1];
if (notificationId === "runtime-deploy") {
// handled in ui/deploy.js
return;
}
if (notificationId === "node") {
// handled below
return;
}
if (msg.text) {
var text = RED._(msg.text,{default:msg.text});
if (!persistentNotifications.hasOwnProperty(notificationId)) {
persistentNotifications[notificationId] = RED.notify(text,msg.type,msg.timeout === undefined,msg.timeout);
} else {
persistentNotifications[notificationId].update(text,msg.timeout);
}
} else if (persistentNotifications.hasOwnProperty(notificationId)) {
persistentNotifications[notificationId].close();
delete persistentNotifications[notificationId];
}
});
RED.comms.subscribe("status/#",function(topic,msg) {
var parts = topic.split("/");
var node = RED.nodes.node(parts[1]);
if (node) {
node.status = msg;
if (statusEnabled) {
node.dirty = true;
RED.view.redraw();
if (msg.hasOwnProperty("text")) {
if (msg.text[0] !== ".") {
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
}
}
node.status = msg;
node.dirty = true;
RED.view.redraw();
}
});
RED.comms.subscribe("node/#",function(topic,msg) {
RED.comms.subscribe("notification/node/#",function(topic,msg) {
var i,m;
var typeList;
var info;
if (topic == "node/added") {
if (topic == "notification/node/added") {
var addedTypes = [];
for (i=0;i<msg.length;i++) {
m = msg[i];
msg.forEach(function(m) {
var id = m.id;
RED.nodes.addNodeSet(m);
addedTypes = addedTypes.concat(m.types);
$.get('nodes/'+id, function(data) {
$("body").append(data);
RED.i18n.loadCatalog(id, function() {
$.get('nodes/'+id, function(data) {
$("body").append(data);
});
});
}
});
if (addedTypes.length) {
typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
RED.notify("Node"+(addedTypes.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
} else if (topic == "node/removed") {
} else if (topic == "notification/node/removed") {
for (i=0;i<msg.length;i++) {
m = msg[i];
info = RED.nodes.removeNodeSet(m.id);
if (info.added) {
typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
RED.notify("Node"+(m.types.length!=1 ? "s":"")+" removed from palette:"+typeList,"success");
RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success");
}
}
} else if (topic == "node/enabled") {
} else if (topic == "notification/node/enabled") {
if (msg.types) {
info = RED.nodes.getNodeSet(msg.id);
if (info.added) {
RED.nodes.enableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" enabled:"+typeList,"success");
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
$.get('nodes/'+msg.id, function(data) {
$("body").append(data);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
});
}
}
} else if (topic == "node/disabled") {
} else if (topic == "notification/node/disabled") {
if (msg.types) {
RED.nodes.disableNodeSet(msg.id);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" disabled:"+typeList,"success");
RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success");
}
} else if (topic == "node/upgraded") {
RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success");
RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version);
}
// Refresh flow library to ensure any examples are updated
RED.library.loadFlowLibrary();
});
}
});
}
var statusEnabled = false;
function toggleStatus(state) {
statusEnabled = state;
RED.view.status(statusEnabled);
function showAbout() {
$.get('red/about', function(data) {
var aboutHeader = '<div style="text-align:center;">'+
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
RED.sidebar.info.set(aboutHeader+marked(data));
RED.sidebar.info.show();
});
}
function loadEditor() {
RED.menu.init({id:"btn-sidemenu",
options: [
{id:"menu-item-sidebar",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
{id:"menu-item-status",label:"Display node status",toggle:true,onselect:toggleStatus, selected: true},
null,
{id:"menu-item-import",label:"Import",options:[
{id:"menu-item-import-clipboard",label:"Clipboard",onselect:RED.clipboard.import},
{id:"menu-item-import-library",label:"Library",options:[]}
]},
{id:"menu-item-export",label:"Export",disabled:true,options:[
{id:"menu-item-export-clipboard",label:"Clipboard",disabled:true,onselect:RED.clipboard.export},
{id:"menu-item-export-library",label:"Library",disabled:true,onselect:RED.library.export}
]},
null,
{id:"menu-item-config-nodes",label:"Configuration nodes",onselect:RED.sidebar.config.show},
null,
{id:"menu-item-subflow",label:"Subflows", options: [
{id:"menu-item-subflow-create",label:"Create subflow",onselect:RED.subflow.createSubflow},
{id:"menu-item-subflow-convert",label:"Selection to subflow",disabled:true,onselect:RED.subflow.convertToSubflow},
]},
null,
{id:"menu-item-workspace",label:"Workspaces",options:[
{id:"menu-item-workspace-add",label:"Add",onselect:RED.workspaces.add},
{id:"menu-item-workspace-edit",label:"Rename",onselect:RED.workspaces.edit},
{id:"menu-item-workspace-delete",label:"Delete",onselect:RED.workspaces.remove},
null
]},
null,
{id:"menu-item-keyboard-shortcuts",label:"Keyboard Shortcuts",onselect:RED.keyboard.showHelp},
{id:"menu-item-help",
label: RED.settings.theme("menu.menu-item-help.label","Node-RED Website"),
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
}
]
var menuOptions = [];
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
// {id:"menu-item-view-show-grid",setting:"view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:"core:toggle-show-grid"},
// {id:"menu-item-view-snap-grid",setting:"view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:"core:toggle-snap-grid"},
// {id:"menu-item-status",setting:"node-show-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:"core:toggle-status", selected: true},
//null,
// {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[
// {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}},
// {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}},
// {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}},
// {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}}
// ]},
// null,
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:"core:toggle-sidebar", selected: true},
null
]});
menuOptions.push(null);
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"},
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
]});
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:"core:show-export-dialog"},
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"}
]});
menuOptions.push(null);
menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"});
menuOptions.push(null);
menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:"core:show-config-tab"});
menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:"core:add-flow"},
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:"core:edit-flow"},
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:"core:remove-flow"}
]});
menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:"core:create-subflow"},
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:"core:convert-to-subflow"},
]});
menuOptions.push(null);
if (RED.settings.theme('palette.editable') !== false) {
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:"core:manage-palette"});
menuOptions.push(null);
}
menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.settings"),onselect:"core:show-user-settings"});
menuOptions.push(null);
menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"});
menuOptions.push({id:"menu-item-help",
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
});
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
RED.view.init();
RED.userSettings.init();
RED.user.init();
RED.library.init();
RED.keyboard.init();
RED.palette.init();
if (RED.settings.theme('palette.editable') !== false) {
RED.palette.editor.init();
}
RED.sidebar.init();
RED.subflow.init();
RED.workspaces.init();
RED.clipboard.init();
RED.view.init();
RED.search.init();
RED.editor.init();
RED.diff.init();
RED.menu.init({id:"btn-sidemenu",options: menuOptions});
RED.deploy.init(RED.settings.theme("deployButton",null));
RED.keyboard.add(/* ? */ 191,{shift:true},function(){RED.keyboard.showHelp();d3.event.preventDefault();});
RED.actions.add("core:show-about", showAbout);
RED.nodes.init();
RED.comms.connect();
$("#main-container").show();
@@ -194,17 +263,15 @@ var RED = (function() {
}
$(function() {
if ((window.location.hostname !== "localhost") && (window.location.hostname !== "127.0.0.1")) {
document.title = document.title+" : "+window.location.hostname;
}
ace.require("ace/ext/language_tools");
RED.settings.init(loadEditor);
RED.i18n.init(function() {
RED.settings.init(loadEditor);
})
});
return {
};
})();

File diff suppressed because it is too large Load Diff

16
editor/js/red.js Normal file
View File

@@ -0,0 +1,16 @@
/**
* 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.
**/
var RED = {};

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2014 IBM, Antoine Aflalo
* 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.
@@ -16,9 +16,9 @@
RED.settings = (function () {
var loadedSettings = {};
var hasLocalStorage = function () {
try {
return 'localStorage' in window && window['localStorage'] !== null;
@@ -33,6 +33,7 @@ RED.settings = (function () {
}
localStorage.setItem(key, JSON.stringify(value));
};
/**
* If the key is not set in the localStorage it returns <i>undefined</i>
* Else return the JSON parsed value
@@ -74,7 +75,7 @@ RED.settings = (function () {
RED.settings.set("auth-tokens",{access_token: accessToken});
window.location.search = "";
}
$.ajaxSetup({
beforeSend: function(jqXHR,settings) {
// Only attach auth header for requests to relative paths
@@ -83,13 +84,14 @@ RED.settings = (function () {
if (auth_tokens) {
jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token);
}
jqXHR.setRequestHeader("Node-RED-API-Version","v2");
}
}
});
load(done);
}
var load = function(done) {
$.ajax({
headers: {
@@ -100,7 +102,7 @@ RED.settings = (function () {
url: 'settings',
success: function (data) {
setProperties(data);
if (RED.settings.user && RED.settings.user.anonymous) {
if (!RED.settings.user || RED.settings.user.anonymous) {
RED.settings.remove("auth-tokens");
}
console.log("Node-RED: " + data.version);
@@ -112,9 +114,9 @@ RED.settings = (function () {
window.location.search = "";
}
RED.user.login(function() { load(done); });
} else {
console.log("Unexpected error:",jqXHR.status,textStatus);
}
} else {
console.log("Unexpected error:",jqXHR.status,textStatus);
}
}
});
};
@@ -129,6 +131,9 @@ RED.settings = (function () {
for (var i=0;i<parts.length;i++) {
v = v[parts[i]];
}
if (v === undefined) {
return defaultValue;
}
return v;
} catch(err) {
return defaultValue;
@@ -141,7 +146,6 @@ RED.settings = (function () {
set: set,
get: get,
remove: remove,
theme: theme
}
})

167
editor/js/text/bidi.js Normal file
View File

@@ -0,0 +1,167 @@
/**
* 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.text = {};
RED.text.bidi = (function() {
var textDir = "";
var textDirPref = "auto";
var bidiEnabled = false;
var LRE = "\u202A",
RLE = "\u202B",
PDF = "\u202C";
function isRTLValue(stringValue) {
var length = stringValue.length;
for (var i=0;i<length;i++) {
if (isBidiChar(stringValue.charCodeAt(i))) {
return true;
}
else if(isLatinChar(stringValue.charCodeAt(i))) {
return false;
}
}
return false;
}
function isBidiChar(c) {
return (c >= 0x05d0 && c <= 0x05ff)||
(c >= 0x0600 && c <= 0x065f)||
(c >= 0x066a && c <= 0x06ef)||
(c >= 0x06fa && c <= 0x07ff)||
(c >= 0xfb1d && c <= 0xfdff)||
(c >= 0xfe70 && c <= 0xfefc);
}
function isLatinChar(c){
return (c > 64 && c < 91)||(c > 96 && c < 123)
}
/**
* Determines the text direction of a given string.
* @param value - the string
*/
function resolveBaseTextDir(value) {
if (textDir == "auto") {
if (isRTLValue(value)) {
return "rtl";
} else {
return "ltr";
}
}
else {
return textDir;
}
}
function onInputChange() {
$(this).attr("dir", resolveBaseTextDir($(this).val()));
}
/**
* Adds event listeners to the Input to ensure its text-direction attribute
* is properly set based on its content.
* @param input - the input field
*/
function prepareInput(input) {
input.on("keyup",onInputChange).on("paste",onInputChange).on("cut",onInputChange);
// Set the initial text direction
onInputChange.call(input);
}
/**
* Enforces the text direction of a given string by adding
* UCC (Unicode Control Characters)
* @param value - the string
*/
function enforceTextDirectionWithUCC(value) {
if (value) {
var dir = resolveBaseTextDir(value);
if (dir == "ltr") {
return LRE + value + PDF;
}
else if (dir == "rtl") {
return RLE + value + PDF;
}
}
return value;
}
/**
* Enforces the text direction for all the spans with style bidiAware under
* workspace or sidebar div
*/
function enforceTextDirectionOnPage() {
$("#workspace").find('span.bidiAware').each(function() {
$(this).attr("dir", resolveBaseTextDir($(this).html()));
});
$("#sidebar").find('span.bidiAware').each(function() {
$(this).attr("dir", resolveBaseTextDir($(this).text()));
});
}
/**
* Sets the text direction
* @param dir - the actual text direction
*/
function setTextDirection(dir) {
textDir = dir;
RED.nodes.eachNode(function(n) { n.dirty = true;});
RED.view.redraw();
RED.palette.refresh();
enforceTextDirectionOnPage();
}
/**
* Gets the bidi enabled preference
*/
function getBidiEnabled() {
return bidiEnabled;
}
/**
* Sets the bidi enabled preference
* @param state - the bidi enabled preference
*/
function setBidiEnabled(state) {
bidiEnabled = state;
setTextDirection((state ? textDirPref : ""));
}
/**
* Gets the text direction preference
*/
function getTextDirPref() {
return textDirPref;
}
/**
* Sets the text direction preference
* @param dirPref - text direction preference
*/
function setTextDirPref(dirPref) {
textDirPref = dirPref;
setTextDirection(textDirPref);
}
return {
setBidiEnabled: setBidiEnabled,
setTextDirPref: setTextDirPref,
getBidiEnabled: getBidiEnabled,
getTextDirPref: getTextDirPref,
enforceTextDirectionWithUCC: enforceTextDirectionWithUCC,
resolveBaseTextDir: resolveBaseTextDir,
prepareInput: prepareInput
}
})();

1330
editor/js/text/format.js Normal file

File diff suppressed because it is too large Load Diff

35
editor/js/ui/actions.js Normal file
View File

@@ -0,0 +1,35 @@
RED.actions = (function() {
var actions = {
}
function addAction(name,handler) {
actions[name] = handler;
}
function removeAction(name) {
delete actions[name];
}
function getAction(name) {
return actions[name];
}
function invokeAction(name) {
if (actions.hasOwnProperty(name)) {
actions[name]();
}
}
function listActions() {
var result = [];
Object.keys(actions).forEach(function(action) {
var shortcut = RED.keyboard.getShortcut(action);
result.push({id:action,scope:shortcut?shortcut.scope:undefined,key:shortcut?shortcut.key:undefined,user:shortcut?shortcut.user:undefined})
})
return result;
}
return {
add: addAction,
remove: removeAction,
get: getAction,
invoke: invokeAction,
list: listActions
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -16,118 +16,300 @@
RED.clipboard = (function() {
var dialog = $('<div id="clipboard-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>')
.appendTo("body")
.dialog({
modal: true,
autoOpen: false,
width: 500,
resizable: false,
buttons: [
{
id: "clipboard-dialog-ok",
text: "Ok",
click: function() {
if (/Import/.test(dialog.dialog("option","title"))) {
RED.view.importNodes($("#clipboard-import").val());
}
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-cancel",
text: "Cancel",
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-close",
text: "Close",
click: function() {
$( this ).dialog( "close" );
}
}
],
open: function(e) {
$(this).parent().find(".ui-dialog-titlebar-close").hide();
RED.keyboard.disable();
},
close: function(e) {
RED.keyboard.enable();
}
});
var dialogContainer = dialog.children(".dialog-form");
var exportNodesDialog = '<div class="form-row">'+
'<label for="node-input-export" style="display: block; width:100%;"><i class="fa fa-clipboard"></i> Nodes:</label>'+
'<textarea readonly style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+
'</div>'+
'<div class="form-tips">'+
'Select the text above and copy to the clipboard with Ctrl-C.'+
'</div>';
var importNodesDialog = '<div class="form-row">'+
'<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5" placeholder="Paste nodes here"></textarea>'+
'</div>';
var dialog;
var dialogContainer;
var exportNodesDialog;
var importNodesDialog;
var disabled = false;
function setupDialogs() {
dialog = $('<div id="clipboard-dialog" class="hide node-red-dialog"><form class="dialog-form form-horizontal"></form></div>')
.appendTo("body")
.dialog({
modal: true,
autoOpen: false,
width: 500,
resizable: false,
buttons: [
{
id: "clipboard-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-close",
class: "primary",
text: RED._("common.label.close"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-copy",
class: "primary",
text: RED._("clipboard.export.copy"),
click: function() {
$("#clipboard-export").select();
document.execCommand("copy");
document.getSelection().removeAllRanges();
RED.notify(RED._("clipboard.nodesExported"));
$( this ).dialog( "close" );
}
},
{
id: "clipboard-dialog-ok",
class: "primary",
text: RED._("common.label.import"),
click: function() {
RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new');
$( this ).dialog( "close" );
}
}
],
open: function(e) {
$(this).parent().find(".ui-dialog-titlebar-close").hide();
},
close: function(e) {
}
});
dialogContainer = dialog.children(".dialog-form");
exportNodesDialog =
'<div class="form-row">'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.export.copy"></label>'+
'<span id="export-range-group" class="button-group">'+
'<a id="export-range-selected" class="editor-button toggle" href="#" data-i18n="clipboard.export.selected"></a>'+
'<a id="export-range-flow" class="editor-button toggle" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="export-range-full" class="editor-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+
'</span>'+
'</div>'+
'<div class="form-row">'+
'<textarea readonly style="resize: none; width: 100%; border-radius: 4px;font-family: monospace; font-size: 12px; background:#f3f3f3; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+
'</div>'+
'<div class="form-row" style="text-align: right;">'+
'<span id="export-format-group" class="button-group">'+
'<a id="export-format-mini" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+
'<a id="export-format-full" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+
'</span>'+
'</div>';
importNodesDialog = '<div class="form-row">'+
'<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5" placeholder="'+
RED._("clipboard.pasteNodes")+
'"></textarea>'+
'</div>'+
'<div class="form-row">'+
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+
'<span id="import-tab" class="button-group">'+
'<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+
'<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+
'</span>'+
'</div>';
}
function validateImport() {
var importInput = $("#clipboard-import");
var v = importInput.val();
v = v.substring(v.indexOf('['),v.lastIndexOf(']')+1);
try {
JSON.parse(v);
importInput.removeClass("input-error");
importInput.val(v);
$("#clipboard-dialog-ok").button("enable");
} catch(err) {
if (v !== "") {
importInput.addClass("input-error");
}
$("#clipboard-dialog-ok").button("disable");
}
}
function importNodes() {
if (disabled) {
return;
}
dialogContainer.empty();
dialogContainer.append($(importNodesDialog));
dialogContainer.i18n();
$("#clipboard-dialog-ok").show();
$("#clipboard-dialog-cancel").show();
$("#clipboard-dialog-close").hide();
$("#clipboard-dialog-copy").hide();
$("#clipboard-dialog-ok").button("disable");
$("#clipboard-import").keyup(function() {
var v = $(this).val();
try {
JSON.parse(v);
$(this).removeClass("input-error");
$("#clipboard-dialog-ok").button("enable");
} catch(err) {
if (v !== "") {
$(this).addClass("input-error");
}
$("#clipboard-dialog-ok").button("disable");
$("#clipboard-import").keyup(validateImport);
$("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)});
$("#import-tab > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
});
dialog.dialog("option","title","Import nodes").dialog("open");
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
}
function exportNodes() {
if (disabled) {
return;
}
dialogContainer.empty();
dialogContainer.append($(exportNodesDialog));
dialogContainer.i18n();
var format = RED.settings.flowFilePretty ? "export-format-full" : "export-format-mini";
$("#export-format-group > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
$("#clipboard-export").focus();
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
var flow = $("#clipboard-export").val();
if (flow.length > 0) {
var nodes = JSON.parse(flow);
format = $(this).attr('id');
if (format === 'export-format-full') {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
}
$("#clipboard-export").val(flow);
$("#clipboard-export").focus();
}
});
$("#export-range-group > a").click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
$("#clipboard-export").focus();
return;
}
$(this).parent().children().removeClass('selected');
$(this).addClass('selected');
var type = $(this).attr('id');
var flow = "";
var nodes = null;
if (type === 'export-range-selected') {
var selection = RED.view.selection();
// Don't include the subflow meta-port nodes in the exported selection
nodes = RED.nodes.createExportableNodeSet(selection.nodes.filter(function(n) { return n.type !== 'subflow'}));
} else if (type === 'export-range-flow') {
var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.filterNodes({z:activeWorkspace});
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
nodes.unshift(parentNode);
nodes = RED.nodes.createExportableNodeSet(nodes);
} else if (type === 'export-range-full') {
nodes = RED.nodes.createCompleteNodeSet(false);
}
if (nodes !== null) {
if (format === "export-format-full") {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
}
}
if (flow.length > 0) {
$("#export-copy").removeClass('disabled');
} else {
$("#export-copy").addClass('disabled');
}
$("#clipboard-export").val(flow);
$("#clipboard-export").focus();
})
$("#clipboard-dialog-ok").hide();
$("#clipboard-dialog-cancel").hide();
$("#clipboard-dialog-close").show();
$("#clipboard-dialog-copy").hide();
$("#clipboard-dialog-close").hide();
var selection = RED.view.selection();
if (selection.nodes) {
var nns = RED.nodes.createExportableNodeSet(selection.nodes);
$("#clipboard-export")
.val(JSON.stringify(nns))
.focus(function() {
var textarea = $(this);
textarea.select();
textarea.mouseup(function() {
textarea.unbind("mouseup");
return false;
})
});
dialog.dialog("option","title","Export nodes to clipboard").dialog( "open" );
$("#export-range-selected").click();
} else {
$("#export-range-selected").addClass('disabled').removeClass('selected');
$("#export-range-flow").click();
}
if (format === "export-format-full") {
$("#export-format-full").click();
} else {
$("#export-format-mini").click();
}
$("#clipboard-export")
.focus(function() {
var textarea = $(this);
textarea.select();
textarea.mouseup(function() {
textarea.unbind("mouseup");
return false;
})
});
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
$("#clipboard-export").focus();
if (!document.queryCommandSupported("copy")) {
$("#clipboard-dialog-cancel").hide();
$("#clipboard-dialog-close").show();
} else {
$("#clipboard-dialog-cancel").show();
$("#clipboard-dialog-copy").show();
}
}
function hideDropTarget() {
$("#dropTarget").hide();
RED.keyboard.remove(/* ESCAPE */ 27);
RED.keyboard.remove("escape");
}
function copyText(value,element,msg) {
var truncated = false;
if (typeof value !== "string" ) {
value = JSON.stringify(value, function(key,value) {
if (value !== null && typeof value === 'object') {
if (value.__encoded__ && value.hasOwnProperty('data') && value.hasOwnProperty('length')) {
truncated = value.data.length !== value.length;
return value.data;
}
}
return value;
});
}
if (truncated) {
msg += "_truncated";
}
$("#clipboard-hidden").val(value).select();
var result = document.execCommand("copy");
if (result && element) {
var popover = RED.popover.create({
target: element,
direction: 'left',
size: 'small',
content: RED._(msg)
});
setTimeout(function() {
popover.close();
},1000);
popover.open();
}
return result;
}
return {
init: function() {
RED.view.on("selection-changed",function(selection) {
setupDialogs();
$('<input type="text" id="clipboard-hidden">').appendTo("body");
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
RED.menu.setDisabled("menu-item-export-clipboard",true);
@@ -138,20 +320,30 @@ RED.clipboard = (function() {
RED.menu.setDisabled("menu-item-export-library",false);
}
});
RED.keyboard.add(/* e */ 69,{ctrl:true},function(){exportNodes();d3.event.preventDefault();});
RED.keyboard.add(/* i */ 73,{ctrl:true},function(){importNodes();d3.event.preventDefault();});
RED.actions.add("core:show-export-dialog",exportNodes);
RED.actions.add("core:show-import-dialog",importNodes);
RED.events.on("editor:open",function() { disabled = true; });
RED.events.on("editor:close",function() { disabled = false; });
RED.events.on("search:open",function() { disabled = true; });
RED.events.on("search:close",function() { disabled = false; });
RED.events.on("type-search:open",function() { disabled = true; });
RED.events.on("type-search:close",function() { disabled = false; });
$('#chart').on("dragenter",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
$("#dropTarget").css({display:'table'});
RED.keyboard.add(/* ESCAPE */ 27,hideDropTarget);
RED.keyboard.add("*", "escape" ,hideDropTarget);
}
});
$('#dropTarget').on("dragover",function(event) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
event.preventDefault();
}
})
@@ -159,20 +351,30 @@ RED.clipboard = (function() {
hideDropTarget();
})
.on("drop",function(event) {
var data = event.originalEvent.dataTransfer.getData("text/plain");
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
var data = event.originalEvent.dataTransfer.getData("text/plain");
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
RED.view.importNodes(data);
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
var files = event.originalEvent.dataTransfer.files;
if (files.length === 1) {
var file = files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
RED.view.importNodes(e.target.result);
};
})(file);
reader.readAsText(file);
}
}
hideDropTarget();
RED.view.importNodes(data);
event.preventDefault();
});
},
import: importNodes,
export: exportNodes
export: exportNodes,
copyText: copyText
}
})();

View File

@@ -0,0 +1,131 @@
/**
* 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.
**/
(function($) {
$.widget( "nodered.checkboxSet", {
_create: function() {
var that = this;
this.uiElement = this.element.wrap( "<span>" ).parent();
this.uiElement.addClass("red-ui-checkboxSet");
if (this.options.parent) {
this.parent = this.options.parent;
this.parent.checkboxSet('addChild',this.element);
}
this.children = [];
this.partialFlag = false;
this.stateValue = 0;
var initialState = this.element.prop('checked');
this.options = [
$('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-square-o"></i></span>').appendTo(this.uiElement),
$('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-check-square-o"></i></span>').appendTo(this.uiElement),
$('<span class="red-ui-checkboxSet-option hide"><i class="fa fa-minus-square-o"></i></span>').appendTo(this.uiElement)
];
if (initialState) {
this.options[1].show();
} else {
this.options[0].show();
}
this.element.change(function() {
if (this.checked) {
that.options[0].hide();
that.options[1].show();
that.options[2].hide();
} else {
that.options[1].hide();
that.options[0].show();
that.options[2].hide();
}
var isChecked = this.checked;
that.children.forEach(function(child) {
child.checkboxSet('state',isChecked,false,true);
})
})
this.uiElement.click(function(e) {
e.stopPropagation();
// state returns null for a partial state. Clicking on that should
// result in false.
that.state((that.state()===false)?true:false);
})
if (this.parent) {
this.parent.checkboxSet('updateChild',this);
}
},
_destroy: function() {
if (this.parent) {
this.parent.checkboxSet('removeChild',this.element);
}
},
addChild: function(child) {
var that = this;
this.children.push(child);
},
removeChild: function(child) {
var index = this.children.indexOf(child);
if (index > -1) {
this.children.splice(index,1);
}
},
updateChild: function(child) {
var checkedCount = 0;
this.children.forEach(function(c,i) {
if (c.checkboxSet('state') === true) {
checkedCount++;
}
});
if (checkedCount === 0) {
this.state(false,true);
} else if (checkedCount === this.children.length) {
this.state(true,true);
} else {
this.state(null,true);
}
},
disable: function() {
this.uiElement.addClass('disabled');
},
state: function(state,suppressEvent,suppressParentUpdate) {
if (arguments.length === 0) {
return this.partialFlag?null:this.element.is(":checked");
} else {
this.partialFlag = (state === null);
var trueState = this.partialFlag||state;
this.element.prop('checked',trueState);
if (state === true) {
this.options[0].hide();
this.options[1].show();
this.options[2].hide();
} else if (state === false) {
this.options[2].hide();
this.options[1].hide();
this.options[0].show();
} else if (state === null) {
this.options[0].hide();
this.options[1].hide();
this.options[2].show();
}
if (!suppressEvent) {
this.element.trigger('change',null);
}
if (!suppressParentUpdate && this.parent) {
this.parent.checkboxSet('updateChild',this);
}
}
}
})
})(jQuery);

View File

@@ -0,0 +1,327 @@
/**
* 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.
**/
(function($) {
/**
* options:
* - addButton : boolean|string - text for add label, default 'add'
* - height : number|'auto'
* - resize : function - called when list as a whole is resized
* - resizeItem : function(item) - called to resize individual item
* - sortable : boolean|string - string is the css selector for handle
* - sortItems : function(items) - when order of items changes
* - connectWith : css selector of other sortables
* - removable : boolean - whether to display delete button on items
* - addItem : function(row,index,itemData) - when an item is added
* - removeItem : function(itemData) - called when an item is removed
* - filter : function(itemData) - called for each item to determine if it should be shown
* - sort : function(itemDataA,itemDataB) - called to sort items
* - scrollOnAdd : boolean - whether to scroll to newly added items
* methods:
* - addItem(itemData)
* - removeItem(itemData)
* - width(width)
* - height(height)
* - items()
* - empty()
* - filter(filter)
* - sort(sort)
* - length()
*/
$.widget( "nodered.editableList", {
_create: function() {
var that = this;
this.element.addClass('red-ui-editableList-list');
this.uiWidth = this.element.width();
this.uiContainer = this.element
.wrap( "<div>" )
.parent();
if (this.options.header) {
this.options.header.addClass("red-ui-editableList-header");
this.borderContainer = this.uiContainer.wrap("<div>").parent();
this.borderContainer.prepend(this.options.header);
this.topContainer = this.borderContainer.wrap("<div>").parent();
} else {
this.topContainer = this.uiContainer.wrap("<div>").parent();
}
this.topContainer.addClass('red-ui-editableList');
if (this.options.class) {
this.topContainer.addClass(this.options.class);
}
if (this.options.addButton !== false) {
var addLabel;
if (typeof this.options.addButton === 'string') {
addLabel = this.options.addButton
} else {
if (RED && RED._) {
addLabel = RED._("editableList.add");
} else {
addLabel = 'add';
}
}
$('<a href="#" class="editor-button editor-button-small" style="margin-top: 4px;"><i class="fa fa-plus"></i> '+addLabel+'</a>')
.appendTo(this.topContainer)
.click(function(evt) {
evt.preventDefault();
that.addItem({});
});
}
if (this.element.css("position") === "absolute") {
["top","left","bottom","right"].forEach(function(s) {
var v = that.element.css(s);
if (v!=="auto" && v!=="") {
that.topContainer.css(s,v);
that.uiContainer.css(s,"0");
that.element.css(s,'auto');
}
})
this.element.css("position","static");
this.topContainer.css("position","absolute");
this.uiContainer.css("position","absolute");
}
if (this.options.header) {
this.borderContainer.addClass("red-ui-editableList-border");
} else {
this.uiContainer.addClass("red-ui-editableList-border");
}
this.uiContainer.addClass("red-ui-editableList-container");
this.uiHeight = this.element.height();
this.activeFilter = this.options.filter||null;
this.activeSort = this.options.sort||null;
this.scrollOnAdd = this.options.scrollOnAdd;
if (this.scrollOnAdd === undefined) {
this.scrollOnAdd = true;
}
var minHeight = this.element.css("minHeight");
if (minHeight !== '0px') {
this.uiContainer.css("minHeight",minHeight);
this.element.css("minHeight",0);
}
if (this.options.height !== 'auto') {
this.uiContainer.css("overflow-y","scroll");
if (!isNaN(this.options.height)) {
this.uiHeight = this.options.height;
}
}
this.element.height('auto');
var attrStyle = this.element.attr('style');
var m;
if ((m = /width\s*:\s*(\d+%)/i.exec(attrStyle)) !== null) {
this.element.width('100%');
this.uiContainer.width(m[1]);
}
if (this.options.sortable) {
var handle = (typeof this.options.sortable === 'string')?
this.options.sortable :
".red-ui-editableList-item-handle";
var sortOptions = {
axis: "y",
update: function( event, ui ) {
if (that.options.sortItems) {
that.options.sortItems(that.items());
}
},
handle:handle,
cursor: "move",
tolerance: "pointer",
forcePlaceholderSize:true,
placeholder: "red-ui-editabelList-item-placeholder",
start: function(e, ui){
ui.placeholder.height(ui.item.height()-4);
}
};
if (this.options.connectWith) {
sortOptions.connectWith = this.options.connectWith;
}
this.element.sortable(sortOptions);
}
this._resize();
// this.menu = this._createMenu(this.types, function(v) { that.type(v) });
// this.type(this.options.default||this.types[0].value);
},
_resize: function() {
var currentFullHeight = this.topContainer.height();
var innerHeight = this.uiContainer.height();
var delta = currentFullHeight - innerHeight;
if (this.uiHeight !== 0) {
this.uiContainer.height(this.uiHeight-delta);
}
if (this.options.resize) {
this.options.resize();
}
if (this.options.resizeItem) {
var that = this;
this.element.children().each(function(i) {
that.options.resizeItem($(this).find(".red-ui-editableList-item-content"),i);
});
}
},
_destroy: function() {
},
_refreshFilter: function() {
var that = this;
var count = 0;
if (!this.activeFilter) {
return this.element.children().show();
}
var items = this.items();
items.each(function (i,el) {
var data = el.data('data');
try {
if (that.activeFilter(data)) {
el.parent().show();
count++;
} else {
el.parent().hide();
}
} catch(err) {
console.log(err);
el.parent().show();
count++;
}
});
return count;
},
_refreshSort: function() {
if (this.activeSort) {
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'));
});
$.each(items,function(idx,li) {
that.element.append(li);
})
}
},
width: function(desiredWidth) {
this.uiWidth = desiredWidth;
this._resize();
},
height: function(desiredHeight) {
this.uiHeight = desiredHeight;
this._resize();
},
addItem: function(data) {
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) {
li.appendTo(this.element);
}
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
row.data('data',data);
if (this.options.sortable === true) {
$('<i class="red-ui-editableList-item-handle fa fa-bars"></i>').appendTo(li);
li.addClass("red-ui-editableList-item-sortable");
}
if (this.options.removable) {
var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove editor-button editor-button-small"}).appendTo(li);
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
li.addClass("red-ui-editableList-item-removable");
deleteButton.click(function(evt) {
evt.preventDefault();
var data = row.data('data');
li.addClass("red-ui-editableList-item-deleting")
li.fadeOut(300, function() {
$(this).remove();
if (that.options.removeItem) {
that.options.removeItem(data);
}
});
});
}
if (this.options.addItem) {
var index = that.element.children().length-1;
setTimeout(function() {
that.options.addItem(row,index,data);
if (that.activeFilter) {
try {
if (!that.activeFilter(data)) {
li.hide();
}
} catch(err) {
}
}
if (!that.activeSort && that.scrollOnAdd) {
setTimeout(function() {
that.uiContainer.scrollTop(that.element.height());
},0);
}
},0);
}
},
addItems: function(items) {
for (var i=0; i<items.length;i++) {
this.addItem(items[i]);
}
},
removeItem: function(data) {
var items = this.element.children().filter(function(f) {
return data === $(this).find(".red-ui-editableList-item-content").data('data');
});
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"); });
},
empty: function() {
this.element.empty();
},
filter: function(filter) {
if (filter !== undefined) {
this.activeFilter = filter;
}
return this._refreshFilter();
},
sort: function(sort) {
if (sort !== undefined) {
this.activeSort = sort;
}
return this._refreshSort();
},
length: function() {
return this.element.children().length;
}
});
})(jQuery);

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2014 IBM Corp.
* 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.
@@ -13,9 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.menu = (function() {
var menuItems = {};
@@ -29,22 +26,32 @@ RED.menu = (function() {
return null;
}
}
function setInitialState() {
var savedStateActive = isSavedStateActive(opt.id);
var savedStateActive = RED.settings.get("menu-" + opt.id);
if (opt.setting) {
// May need to migrate pre-0.17 setting
if (savedStateActive !== null) {
RED.settings.set(opt.setting,savedStateActive);
RED.settings.remove("menu-" + opt.id);
} else {
savedStateActive = RED.settings.get(opt.setting);
}
}
if (savedStateActive) {
link.addClass("active");
opt.onselect.call(opt, true);
triggerAction(opt.id,true);
} else if (savedStateActive === false) {
link.removeClass("active");
opt.onselect.call(opt, false);
triggerAction(opt.id,false);
} else if (opt.hasOwnProperty("selected")) {
if (opt.selected) {
link.addClass("active");
} else {
link.removeClass("active");
}
opt.onselect.call(opt, opt.selected);
triggerAction(opt.id,opt.selected);
}
}
@@ -52,12 +59,16 @@ RED.menu = (function() {
item = $('<li class="divider"></li>');
} else {
item = $('<li></li>');
if (opt.group) {
item.addClass("menu-group-"+opt.group);
}
var linkContent = '<a '+(opt.id?'id="'+opt.id+'" ':'')+'tabindex="-1" href="#">';
if (opt.toggle) {
linkContent += '<i class="fa fa-square pull-left"></i>';
linkContent += '<i class="fa fa-check-square pull-left"></i>';
}
if (opt.icon !== undefined) {
if (/\.png/.test(opt.icon)) {
@@ -66,22 +77,23 @@ RED.menu = (function() {
linkContent += '<i class="'+(opt.icon?opt.icon:'" style="display: inline-block;"')+'"></i> ';
}
}
if (opt.sublabel) {
linkContent += '<span class="menu-label-container"><span class="menu-label">'+opt.label+'</span>'+
'<span class="menu-sublabel">'+opt.sublabel+'</span></span>'
} else {
linkContent += '<span class="menu-label">'+opt.label+'</span>'
}
linkContent += '</a>';
var link = $(linkContent).appendTo(item);
menuItems[opt.id] = opt;
if (opt.onselect) {
link.click(function() {
link.click(function(e) {
e.preventDefault();
if ($(this).parent().hasClass("disabled")) {
return;
}
@@ -103,10 +115,12 @@ RED.menu = (function() {
setSelected(opt.id, !selected);
}
} else {
opt.onselect.call(opt);
triggerAction(opt.id);
}
});
setInitialState();
if (opt.toggle) {
setInitialState();
}
} else if (opt.href) {
link.attr("target","_blank").attr("href",opt.href);
} else if (!opt.options) {
@@ -129,17 +143,6 @@ RED.menu = (function() {
if (opt.disabled) {
item.addClass("disabled");
}
if (opt.tip) {
item.popover({
placement:"left",
trigger: "hover",
delay: { show: 350, hide: 20 },
html: true,
container:'body',
content: opt.tip
});
}
}
@@ -148,15 +151,13 @@ RED.menu = (function() {
}
function createMenu(options) {
var button = $("#"+options.id);
var menuParent = $("#"+options.id);
//button.click(function(event) {
// $("#"+options.id+"-submenu").show();
// event.preventDefault();
//});
var topMenu = $("<ul/>",{id:options.id+"-submenu", class:"dropdown-menu pull-right"}).insertAfter(button);
var topMenu = $("<ul/>",{id:options.id+"-submenu", class:"dropdown-menu pull-right"});
if (menuParent.length === 1) {
topMenu.insertAfter(menuParent);
}
var lastAddedSeparator = false;
for (var i=0;i<options.options.length;i++) {
@@ -169,20 +170,27 @@ RED.menu = (function() {
}
}
}
return topMenu;
}
function isSavedStateActive(id) {
return RED.settings.get("menu-" + id);
function triggerAction(id, args) {
var opt = menuItems[id];
var callback = opt.onselect;
if (typeof opt.onselect === 'string') {
callback = RED.actions.get(opt.onselect);
}
if (callback) {
callback.call(opt,args);
} else {
console.log("No callback for",id,opt.onselect);
}
}
function isSelected(id) {
return $("#" + id).hasClass("active");
}
function setSavedState(id, state) {
RED.settings.set("menu-" + id, state);
}
function setSelected(id,state) {
if (isSelected(id) == state) {
return;
@@ -194,9 +202,13 @@ RED.menu = (function() {
$("#"+id).removeClass("active");
}
if (opt && opt.onselect) {
opt.onselect.call(opt,state);
triggerAction(opt.id,state);
}
setSavedState(id, state);
RED.settings.set(opt.setting||("menu-"+opt.id), state);
}
function toggleSelected(id) {
setSelected(id,!isSelected(id));
}
function setDisabled(id,state) {
@@ -208,7 +220,27 @@ RED.menu = (function() {
}
function addItem(id,opt) {
createMenuItem(opt).appendTo("#"+id+"-submenu");
var item = createMenuItem(opt);
if (opt.group) {
var groupItems = $("#"+id+"-submenu").children(".menu-group-"+opt.group);
if (groupItems.length === 0) {
item.appendTo("#"+id+"-submenu");
} else {
for (var i=0;i<groupItems.length;i++) {
var groupItem = groupItems[i];
var label = $(groupItem).find(".menu-label").html();
if (opt.label < label) {
$(groupItem).before(item);
break;
}
}
if (i === groupItems.length) {
item.appendTo("#"+id+"-submenu");
}
}
} else {
item.appendTo("#"+id+"-submenu");
}
}
function removeItem(id) {
$("#"+id).parent().remove();
@@ -218,16 +250,6 @@ RED.menu = (function() {
var opt = menuItems[id];
if (opt) {
opt.onselect = action;
$("#"+id).click(function() {
if ($(this).parent().hasClass("disabled")) {
return;
}
if (menuItems[id].toggle) {
setSelected(id,!isSelected(id));
} else {
menuItems[id].onselect.call(menuItems[id]);
}
});
}
}
@@ -235,6 +257,7 @@ RED.menu = (function() {
init: createMenu,
setSelected: setSelected,
isSelected: isSelected,
toggleSelected: toggleSelected,
setDisabled: setDisabled,
addItem: addItem,
removeItem: removeItem,

View File

@@ -0,0 +1,81 @@
/**
* 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.panels = (function() {
function createPanel(options) {
var container = options.container || $("#"+options.id);
var children = container.children();
if (children.length !== 2) {
throw new Error("Container must have exactly two children");
}
container.addClass("red-ui-panels");
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
var startPosition;
var panelHeights = [];
var modifiedHeights = false;
var panelRatio;
separator.draggable({
axis: "y",
containment: container,
scroll: false,
start:function(event,ui) {
var height = container.height();
startPosition = ui.position.top;
panelHeights = [$(children[0]).height(),$(children[1]).height()];
},
drag: function(event,ui) {
var height = container.height();
var delta = ui.position.top-startPosition;
var newHeights = [panelHeights[0]+delta,panelHeights[1]-delta];
$(children[0]).height(newHeights[0]);
$(children[1]).height(newHeights[1]);
if (options.resize) {
options.resize(newHeights[0],newHeights[1]);
}
ui.position.top -= delta;
panelRatio = newHeights[0]/height;
},
stop:function(event,ui) {
modifiedHeights = true;
}
});
return {
resize: function(height) {
var panelHeights = [$(children[0]).height(),$(children[1]).height()];
container.height(height);
if (modifiedHeights) {
var topPanelHeight = panelRatio*height;
var bottomPanelHeight = height - topPanelHeight - 48;
panelHeights = [topPanelHeight,bottomPanelHeight];
$(children[0]).height(panelHeights[0]);
$(children[1]).height(panelHeights[1]);
}
if (options.resize) {
options.resize(panelHeights[0],panelHeights[1]);
}
}
}
}
return {
create: createPanel
}
})();

View File

@@ -0,0 +1,135 @@
/**
* 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.popover = (function() {
var deltaSizes = {
"default": {
top: 10,
leftRight: 17,
leftLeft: 25
},
"small": {
top: 5,
leftRight: 8,
leftLeft: 16
}
}
function createPopover(options) {
var target = options.target;
var direction = options.direction || "right";
var trigger = options.trigger;
var content = options.content;
var delay = options.delay;
var width = options.width||"auto";
var size = options.size||"default";
if (!deltaSizes[size]) {
throw new Error("Invalid RED.popover size value:",size);
}
var timer = null;
var active;
var div;
var openPopup = function() {
if (active) {
div = $('<div class="red-ui-popover red-ui-popover-'+direction+'"></div>').appendTo("body");
if (size !== "default") {
div.addClass("red-ui-popover-size-"+size);
}
if (typeof content === 'function') {
content.call(res).appendTo(div);
} else {
div.html(content);
}
if (width !== "auto") {
div.width(width);
}
var targetPos = target.offset();
var targetWidth = target.width();
var targetHeight = target.height();
var divHeight = div.height();
var divWidth = div.width();
if (direction === 'right') {
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight});
} else if (direction === 'left') {
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth});
}
div.fadeIn("fast");
}
}
var closePopup = function() {
if (!active) {
if (div) {
div.fadeOut("fast",function() {
$(this).remove();
});
div = null;
}
}
}
if (trigger === 'hover') {
target.on('mouseenter',function(e) {
clearTimeout(timer);
active = true;
timer = setTimeout(openPopup,delay.show);
});
target.on('mouseleave', function(e) {
if (timer) {
clearTimeout(timer);
}
active = false;
setTimeout(closePopup,delay.hide);
});
} else if (trigger === 'click') {
target.click(function(e) {
e.preventDefault();
e.stopPropagation();
active = !active;
if (!active) {
closePopup();
} else {
openPopup();
}
});
}
var res = {
setContent: function(_content) {
content = _content;
},
open: function () {
active = true;
openPopup();
},
close: function () {
active = false;
closePopup();
}
}
return res;
}
return {
create: createPopover
}
})();

View File

@@ -0,0 +1,99 @@
/**
* 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.
**/
(function($) {
$.widget( "nodered.searchBox", {
_create: function() {
var that = this;
this.currentTimeout = null;
this.lastSent = "";
this.element.val("");
this.uiContainer = this.element.wrap("<div>").parent();
this.uiContainer.addClass("red-ui-searchBox-container");
$('<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.on("click",function(e) {
e.preventDefault();
that.element.val("");
that._change("",true);
that.element.focus();
});
this.resultCount = $('<span>',{class:"red-ui-searchBox-resultCount hide"}).appendTo(this.uiContainer);
this.element.val("");
this.element.on("keydown",function(evt) {
if (evt.keyCode === 27) {
that.element.val("");
}
})
this.element.on("keyup",function(evt) {
that._change($(this).val());
});
this.element.on("focus",function() {
$("body").one("mousedown",function() {
that.element.blur();
});
});
},
_change: function(val,instant) {
var fireEvent = false;
if (val === "") {
this.clearButton.hide();
fireEvent = true;
} else {
this.clearButton.show();
fireEvent = (val.length >= (this.options.minimumLength||0));
}
var current = this.element.val();
fireEvent = fireEvent && current !== this.lastSent;
if (fireEvent) {
if (!instant && this.options.delay > 0) {
clearTimeout(this.currentTimeout);
var that = this;
this.currentTimeout = setTimeout(function() {
that.lastSent = that.element.val();
that._trigger("change");
},this.options.delay);
} else {
this._trigger("change");
}
}
},
value: function(val) {
if (val === undefined) {
return this.element.val();
} else {
this.element.val(val);
this._change(val);
}
},
count: function(val) {
if (val === undefined || val === null || val === "") {
this.resultCount.text("").hide();
} else {
this.resultCount.text(val).show();
}
},
change: function() {
this._trigger("change");
}
});
})(jQuery);

View File

@@ -0,0 +1,119 @@
/**
* 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.stack = (function() {
function createStack(options) {
var container = options.container;
var entries = [];
var visible = true;
return {
add: function(entry) {
entries.push(entry);
entry.container = $('<div class="palette-category">').appendTo(container);
if (!visible) {
entry.container.hide();
}
var header = $('<div class="palette-header"></div>').appendTo(entry.container);
entry.content = $('<div></div>').appendTo(entry.container);
if (entry.collapsible !== false) {
header.click(function() {
if (options.singleExpanded) {
if (!entry.isExpanded()) {
for (var i=0;i<entries.length;i++) {
if (entries[i].isExpanded()) {
entries[i].collapse();
}
}
entry.expand();
}
} else {
entry.toggle();
}
});
var icon = $('<i class="fa fa-angle-down"></i>').appendTo(header);
if (entry.expanded) {
icon.addClass("expanded");
} else {
entry.content.hide();
}
} else {
header.css("cursor","default");
}
entry.title = $('<span></span>').html(entry.title).appendTo(header);
entry.toggle = function() {
if (entry.isExpanded()) {
entry.collapse();
return false;
} else {
entry.expand();
return true;
}
};
entry.expand = function() {
if (!entry.isExpanded()) {
if (entry.onexpand) {
entry.onexpand.call(entry);
}
icon.addClass("expanded");
entry.content.slideDown(200);
return true;
}
};
entry.collapse = function() {
if (entry.isExpanded()) {
icon.removeClass("expanded");
entry.content.slideUp(200);
return true;
}
};
entry.isExpanded = function() {
return icon.hasClass("expanded");
};
return entry;
},
hide: function() {
visible = false;
entries.forEach(function(entry) {
entry.container.hide();
});
return this;
},
show: function() {
visible = true;
entries.forEach(function(entry) {
entry.container.show();
});
return this;
}
}
}
return {
create: createStack
}
})();

379
editor/js/ui/common/tabs.js Normal file
View File

@@ -0,0 +1,379 @@
/**
* 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.tabs = (function() {
function createTabs(options) {
var tabs = {};
var currentTabWidth;
var currentActiveTabWidth = 0;
var ul = options.element || $("#"+options.id);
var wrapper = ul.wrap( "<div>" ).parent();
var scrollContainer = ul.wrap( "<div>" ).parent();
wrapper.addClass("red-ui-tabs");
if (options.vertical) {
wrapper.addClass("red-ui-tabs-vertical");
}
if (options.addButton && typeof options.addButton === 'function') {
wrapper.addClass("red-ui-tabs-add");
var addButton = $('<div class="red-ui-tab-button"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
addButton.find('a').click(function(evt) {
evt.preventDefault();
options.addButton();
})
}
var scrollLeft;
var scrollRight;
if (options.scrollable) {
wrapper.addClass("red-ui-tabs-scrollable");
scrollContainer.addClass("red-ui-tabs-scroll-container");
scrollContainer.scroll(updateScroll);
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();});
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();});
}
function scrollEventHandler(evt,dir) {
evt.preventDefault();
if ($(this).hasClass('disabled')) {
return;
}
var currentScrollLeft = scrollContainer.scrollLeft();
scrollContainer.animate( { scrollLeft: dir }, 100);
var interval = setInterval(function() {
var newScrollLeft = scrollContainer.scrollLeft()
if (newScrollLeft === currentScrollLeft) {
clearInterval(interval);
return;
}
currentScrollLeft = newScrollLeft;
scrollContainer.animate( { scrollLeft: dir }, 100);
},100);
$(this).one('mouseup',function() {
clearInterval(interval);
})
}
ul.children().first().addClass("active");
ul.children().addClass("red-ui-tab");
function onTabClick() {
if (options.onclick) {
options.onclick(tabs[$(this).attr('href').slice(1)]);
}
activateTab($(this));
return false;
}
function updateScroll() {
if (ul.children().length !== 0) {
var sl = scrollContainer.scrollLeft();
var scWidth = scrollContainer.width();
var ulWidth = ul.width();
if (sl === 0) {
scrollLeft.hide();
} else {
scrollLeft.show();
}
if (sl === ulWidth-scWidth) {
scrollRight.hide();
} else {
scrollRight.show();
}
}
}
function onTabDblClick() {
if (options.ondblclick) {
options.ondblclick(tabs[$(this).attr('href').slice(1)]);
}
return false;
}
function activateTab(link) {
if (typeof link === "string") {
link = ul.find("a[href='#"+link+"']");
}
if (link.length === 0) {
return;
}
if (!link.parent().hasClass("active")) {
ul.children().removeClass("active");
ul.children().css({"transition": "width 100ms"});
link.parent().addClass("active");
if (options.scrollable) {
var pos = link.parent().position().left;
if (pos-21 < 0) {
scrollContainer.animate( { scrollLeft: '+='+(pos-50) }, 300);
} else if (pos + 120 > scrollContainer.width()) {
scrollContainer.animate( { scrollLeft: '+='+(pos + 140-scrollContainer.width()) }, 300);
}
}
if (options.onchange) {
options.onchange(tabs[link.attr('href').slice(1)]);
}
updateTabWidths();
setTimeout(function() {
ul.children().css({"transition": ""});
},100);
}
}
function activatePreviousTab() {
var previous = ul.find("li.active").prev();
if (previous.length > 0) {
activateTab(previous.find("a"));
}
}
function activateNextTab() {
var next = ul.find("li.active").next();
if (next.length > 0) {
activateTab(next.find("a"));
}
}
function updateTabWidths() {
if (options.vertical) {
return;
}
var tabs = ul.find("li.red-ui-tab");
var width = wrapper.width();
var tabCount = tabs.size();
var tabWidth = (width-12-(tabCount*6))/tabCount;
currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = currentTabWidth+"%";
if (options.scrollable) {
tabWidth = Math.max(tabWidth,140);
currentTabWidth = tabWidth+"px";
currentActiveTabWidth = 0;
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
ul.width(listWidth);
updateScroll();
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
if (tabWidth < options.minimumActiveTabWidth) {
tabCount -= 1;
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
} else {
currentActiveTabWidth = 0;
}
}
tabs.css({width:currentTabWidth});
if (tabWidth < 50) {
ul.find(".red-ui-tab-close").hide();
ul.find(".red-ui-tab-icon").hide();
ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"})
} else {
ul.find(".red-ui-tab-close").show();
ul.find(".red-ui-tab-icon").show();
ul.find(".red-ui-tab-label").css({paddingLeft:""})
}
if (currentActiveTabWidth !== 0) {
ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth});
ul.find("li.red-ui-tab.active .red-ui-tab-close").show();
ul.find("li.red-ui-tab.active .red-ui-tab-icon").show();
ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""})
}
}
ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
setTimeout(function() {
updateTabWidths();
},0);
function removeTab(id) {
var li = ul.find("a[href='#"+id+"']").parent();
if (li.hasClass("active")) {
var tab = li.prev();
if (tab.size() === 0) {
tab = li.next();
}
activateTab(tab.find("a"));
}
li.remove();
if (options.onremove) {
options.onremove(tabs[id]);
}
delete tabs[id];
updateTabWidths();
}
return {
addTab: function(tab) {
tabs[tab.id] = tab;
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
li.attr('id',"red-ui-tab-"+(tab.id.replace(".","-")));
li.data("tabId",tab.id);
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
if (tab.icon) {
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
}
var span = $('<span/>',{class:"bidiAware"}).text(tab.label).appendTo(link);
span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label));
link.on("click",onTabClick);
link.on("dblclick",onTabDblClick);
if (tab.closeable) {
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
closeLink.append('<i class="fa fa-times" />');
closeLink.on("click",function(event) {
event.preventDefault();
removeTab(tab.id);
});
}
updateTabWidths();
if (options.onadd) {
options.onadd(tab);
}
link.attr("title",tab.label);
if (ul.find("li.red-ui-tab").size() == 1) {
activateTab(link);
}
if (options.onreorder) {
var originalTabOrder;
var tabDragIndex;
var tabElements = [];
var startDragIndex;
li.draggable({
axis:"x",
distance: 20,
start: function(event,ui) {
originalTabOrder = [];
tabElements = [];
ul.children().each(function(i) {
tabElements[i] = {
el:$(this),
text: $(this).text(),
left: $(this).position().left,
width: $(this).width()
};
if ($(this).is(li)) {
tabDragIndex = i;
startDragIndex = i;
}
originalTabOrder.push($(this).data("tabId"));
});
ul.children().each(function(i) {
if (i!==tabDragIndex) {
$(this).css({
position: 'absolute',
left: tabElements[i].left+"px",
width: tabElements[i].width+2,
transition: "left 0.3s"
});
}
})
if (!li.hasClass('active')) {
li.css({'zIndex':1});
}
},
drag: function(event,ui) {
ui.position.left += tabElements[tabDragIndex].left+scrollContainer.scrollLeft();
var tabCenter = ui.position.left + tabElements[tabDragIndex].width/2 - scrollContainer.scrollLeft();
for (var i=0;i<tabElements.length;i++) {
if (i === tabDragIndex) {
continue;
}
if (tabCenter > tabElements[i].left && tabCenter < tabElements[i].left+tabElements[i].width) {
if (i < tabDragIndex) {
tabElements[i].left += tabElements[tabDragIndex].width+8;
tabElements[tabDragIndex].el.detach().insertBefore(tabElements[i].el);
} else {
tabElements[i].left -= tabElements[tabDragIndex].width+8;
tabElements[tabDragIndex].el.detach().insertAfter(tabElements[i].el);
}
tabElements[i].el.css({left:tabElements[i].left+"px"});
tabElements.splice(i, 0, tabElements.splice(tabDragIndex, 1)[0]);
tabDragIndex = i;
break;
}
}
},
stop: function(event,ui) {
ul.children().css({position:"relative",left:"",transition:""});
if (!li.hasClass('active')) {
li.css({zIndex:""});
}
updateTabWidths();
if (startDragIndex !== tabDragIndex) {
options.onreorder(originalTabOrder, $.makeArray(ul.children().map(function() { return $(this).data('tabId');})));
}
activateTab(tabElements[tabDragIndex].el.data('tabId'));
}
})
}
},
removeTab: removeTab,
activateTab: activateTab,
nextTab: activateNextTab,
previousTab: activatePreviousTab,
resize: updateTabWidths,
count: function() {
return ul.find("li.red-ui-tab").size();
},
contains: function(id) {
return ul.find("a[href='#"+id+"']").length > 0;
},
renameTab: function(id,label) {
tabs[id].label = label;
var tab = ul.find("a[href='#"+id+"']");
tab.attr("title",label);
tab.find("span.bidiAware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label));
updateTabWidths();
},
order: function(order) {
var existingTabOrder = $.makeArray(ul.children().map(function() { return $(this).data('tabId');}));
if (existingTabOrder.length !== order.length) {
return
}
var i;
var match = true;
for (i=0;i<order.length;i++) {
if (order[i] !== existingTabOrder[i]) {
match = false;
break;
}
}
if (match) {
return;
}
var existingTabMap = {};
var existingTabs = ul.children().detach().each(function() {
existingTabMap[$(this).data("tabId")] = $(this);
});
for (i=0;i<order.length;i++) {
existingTabMap[order[i]].appendTo(ul);
}
}
}
}
return {
create: createTabs
}
})();

View File

@@ -0,0 +1,472 @@
/**
* 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.
**/
(function($) {
var allOptions = {
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression},
flow: {value:"flow",label:"flow.",validate:RED.utils.validatePropertyExpression},
global: {value:"global",label:"global.",validate:RED.utils.validatePropertyExpression},
str: {value:"str",label:"string",icon:"red/images/typedInput/az.png"},
num: {value:"num",label:"number",icon:"red/images/typedInput/09.png",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/},
bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.png",options:["true","false"]},
json: {
value:"json",
label:"JSON",
icon:"red/images/typedInput/json.png",
validate: function(v) { try{JSON.parse(v);return true;}catch(e){return false;}},
expand: function() {
var that = this;
var value = this.value();
try {
value = JSON.stringify(JSON.parse(value),null,4);
} catch(err) {
}
RED.editor.editJSON({
value: value,
complete: function(v) {
var value = v;
try {
value = JSON.stringify(JSON.parse(v));
} catch(err) {
}
that.value(value);
}
})
}
},
re: {value:"re",label:"regular expression",icon:"red/images/typedInput/re.png"},
date: {value:"date",label:"timestamp",hasValue:false},
jsonata: {
value: "jsonata",
label: "expression",
icon: "red/images/typedInput/expr.png",
validate: function(v) { try{jsonata(v);return true;}catch(e){return false;}},
expand:function() {
var that = this;
RED.editor.editExpression({
value: this.value().replace(/\t/g,"\n"),
complete: function(v) {
that.value(v.replace(/\n/g,"\t"));
}
})
}
},
bin: {
value: "bin",
label: "buffer",
icon: "red/images/typedInput/bin.png",
expand: function() {
var that = this;
RED.editor.editBuffer({
value: this.value(),
complete: function(v) {
that.value(v);
}
})
}
}
};
var nlsd = false;
$.widget( "nodered.typedInput", {
_create: function() {
if (!nlsd && RED && RED._) {
for (var i in allOptions) {
if (allOptions.hasOwnProperty(i)) {
allOptions[i].label = RED._("typedInput.type."+i,{defaultValue:allOptions[i].label});
}
}
}
nlsd = true;
var that = this;
this.disarmClick = false;
this.element.addClass('red-ui-typedInput');
this.uiWidth = this.element.outerWidth();
this.elementDiv = this.element.wrap("<div>").parent().addClass('red-ui-typedInput-input');
this.uiSelect = this.elementDiv.wrap( "<div>" ).parent();
var attrStyle = this.element.attr('style');
var m;
if ((m = /width\s*:\s*(\d+(%|px))/i.exec(attrStyle)) !== null) {
this.element.css('width','100%');
this.uiSelect.width(m[1]);
this.uiWidth = null;
} else {
this.uiSelect.width(this.uiWidth);
}
["Right","Left"].forEach(function(d) {
var m = that.element.css("margin"+d);
that.uiSelect.css("margin"+d,m);
that.element.css("margin"+d,0);
});
this.uiSelect.addClass("red-ui-typedInput-container");
this.options.types = this.options.types||Object.keys(allOptions);
this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect);
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
this.types(this.options.types);
if (this.options.typeField) {
this.typeField = $(this.options.typeField).hide();
var t = this.typeField.val();
if (t && this.typeMap[t]) {
this.options.default = t;
}
} else {
this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect);
}
this.element.on('focus', function() {
that.uiSelect.addClass('red-ui-typedInput-focus');
});
this.element.on('blur', function() {
that.uiSelect.removeClass('red-ui-typedInput-focus');
});
this.element.on('change', function() {
that.validate();
})
this.selectTrigger.click(function(event) {
event.preventDefault();
that._showTypeMenu();
});
this.selectTrigger.on('keydown',function(evt) {
if (evt.keyCode === 40) {
// Down
that._showTypeMenu();
}
}).on('focus', function() {
that.uiSelect.addClass('red-ui-typedInput-focus');
})
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
this.optionSelectTrigger.click(function(event) {
event.preventDefault();
that._showOptionSelectMenu();
}).on('keydown', function(evt) {
if (evt.keyCode === 40) {
// Down
that._showOptionSelectMenu();
}
}).on('blur', function() {
that.uiSelect.removeClass('red-ui-typedInput-focus');
}).on('focus', function() {
that.uiSelect.addClass('red-ui-typedInput-focus');
});
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"><i class="fa fa-ellipsis-h"></i></button>').appendTo(this.uiSelect);
this.type(this.options.default||this.typeList[0].value);
},
_showTypeMenu: function() {
if (this.typeList.length > 1) {
this._showMenu(this.menu,this.selectTrigger);
this.menu.find("[value='"+this.propertyType+"']").focus();
} else {
this.element.focus();
}
},
_showOptionSelectMenu: function() {
if (this.optionMenu) {
this.optionMenu.css({
minWidth:this.optionSelectLabel.width()
});
this._showMenu(this.optionMenu,this.optionSelectLabel);
var selectedOption = this.optionMenu.find("[value='"+this.value()+"']");
if (selectedOption.length === 0) {
selectedOption = this.optionMenu.children(":first");
}
selectedOption.focus();
}
},
_hideMenu: function(menu) {
$(document).off("mousedown.close-property-select");
menu.hide();
if (this.elementDiv.is(":visible")) {
this.element.focus();
} else if (this.optionSelectTrigger.is(":visible")){
this.optionSelectTrigger.focus();
} else {
this.selectTrigger.focus();
}
},
_createMenu: function(opts,callback) {
var that = this;
var menu = $("<div>").addClass("red-ui-typedInput-options");
opts.forEach(function(opt) {
if (typeof opt === 'string') {
opt = {value:opt,label:opt};
}
var op = $('<a href="#"></a>').attr("value",opt.value).appendTo(menu);
if (opt.label) {
op.text(opt.label);
}
if (opt.icon) {
$('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op);
} else {
op.css({paddingLeft: "18px"});
}
op.click(function(event) {
event.preventDefault();
callback(opt.value);
that._hideMenu(menu);
});
});
menu.css({
display: "none",
});
menu.appendTo(document.body);
menu.on('keydown', function(evt) {
if (evt.keyCode === 40) {
// DOWN
$(this).children(":focus").next().focus();
} else if (evt.keyCode === 38) {
// UP
$(this).children(":focus").prev().focus();
} else if (evt.keyCode === 27) {
that._hideMenu(menu);
}
})
return menu;
},
_showMenu: function(menu,relativeTo) {
if (this.disarmClick) {
this.disarmClick = false;
return
}
var that = this;
var pos = relativeTo.offset();
var height = relativeTo.height();
var menuHeight = menu.height();
var top = (height+pos.top-3);
if (top+menuHeight > $(window).height()) {
top -= (top+menuHeight)-$(window).height()+5;
}
menu.css({
top: top+"px",
left: (2+pos.left)+"px",
});
menu.slideDown(100);
this._delay(function() {
that.uiSelect.addClass('red-ui-typedInput-focus');
$(document).on("mousedown.close-property-select", function(event) {
if(!$(event.target).closest(menu).length) {
that._hideMenu(menu);
}
if ($(event.target).closest(relativeTo).length) {
that.disarmClick = true;
event.preventDefault();
}
})
});
},
_getLabelWidth: function(label) {
var labelWidth = label.outerWidth();
if (labelWidth === 0) {
var container = $('<div class="red-ui-typedInput-container"></div>').css({
position:"absolute",
top:0,
left:-1000
}).appendTo(document.body);
var newTrigger = label.clone().appendTo(container);
labelWidth = newTrigger.outerWidth();
container.remove();
}
return labelWidth;
},
_resize: function() {
if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
if (this.typeMap[this.propertyType] && this.typeMap[this.propertyType].hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
var labelWidth = this._getLabelWidth(this.selectTrigger);
this.elementDiv.css('left',labelWidth+"px");
if (this.optionExpandButton.is(":visible")) {
this.elementDiv.css('right',"22px");
} else {
this.elementDiv.css('right','0');
}
if (this.optionSelectTrigger) {
this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'});
}
}
},
_destroy: function() {
this.menu.remove();
},
types: function(types) {
var that = this;
var currentType = this.type();
this.typeMap = {};
this.typeList = types.map(function(opt) {
var result;
if (typeof opt === 'string') {
result = allOptions[opt];
} else {
result = opt;
}
that.typeMap[result.value] = result;
return result;
});
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
if (this.menu) {
this.menu.remove();
}
this.menu = this._createMenu(this.typeList, function(v) { that.type(v) });
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
this.type(this.typeList[0].value);
}
},
width: function(desiredWidth) {
this.uiWidth = desiredWidth;
this._resize();
},
value: function(value) {
if (!arguments.length) {
return this.element.val();
} else {
if (this.typeMap[this.propertyType].options) {
if (this.typeMap[this.propertyType].options.indexOf(value) === -1) {
value = "";
}
this.optionSelectLabel.text(value);
}
this.element.val(value);
this.element.trigger('change',this.type(),value);
}
},
type: function(type) {
if (!arguments.length) {
return this.propertyType;
} else {
var that = this;
var opt = this.typeMap[type];
if (opt && this.propertyType !== type) {
this.propertyType = type;
this.typeField.val(type);
this.selectLabel.empty();
var image;
if (opt.icon) {
image = new Image();
image.name = opt.icon;
image.src = opt.icon;
$('<img>',{src:opt.icon,style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel);
} else {
this.selectLabel.text(opt.label);
}
if (opt.options) {
if (this.optionExpandButton) {
this.optionExpandButton.hide();
}
if (this.optionSelectTrigger) {
this.optionSelectTrigger.show();
this.elementDiv.hide();
this.optionMenu = this._createMenu(opt.options,function(v){
that.optionSelectLabel.text(v);
that.value(v);
});
var currentVal = this.element.val();
if (opt.options.indexOf(currentVal) !== -1) {
this.optionSelectLabel.text(currentVal);
} else {
this.value(opt.options[0]);
}
}
} else {
if (this.optionMenu) {
this.optionMenu.remove();
this.optionMenu = null;
}
if (this.optionSelectTrigger) {
this.optionSelectTrigger.hide();
}
if (opt.hasValue === false) {
this.oldValue = this.element.val();
this.element.val("");
this.elementDiv.hide();
} else {
if (this.oldValue !== undefined) {
this.element.val(this.oldValue);
delete this.oldValue;
}
this.elementDiv.show();
}
if (opt.expand && typeof opt.expand === 'function') {
this.optionExpandButton.show();
this.optionExpandButton.off('click');
this.optionExpandButton.on('click',function(evt) {
evt.preventDefault();
opt.expand.call(that);
})
} else {
this.optionExpandButton.hide();
}
this.element.trigger('change',this.propertyType,this.value());
}
if (image) {
image.onload = function() { that._resize(); }
image.onerror = function() { that._resize(); }
} else {
this._resize();
}
}
}
},
validate: function() {
var result;
var value = this.value();
var type = this.type();
if (this.typeMap[type] && this.typeMap[type].validate) {
var val = this.typeMap[type].validate;
if (typeof val === 'function') {
result = val(value);
} else {
result = val.test(value);
}
} else {
result = true;
}
if (result) {
this.uiSelect.removeClass('input-error');
} else {
this.uiSelect.addClass('input-error');
}
return result;
},
show: function() {
this.uiSelect.show();
this._resize();
},
hide: function() {
this.uiSelect.hide();
}
});
})(jQuery);

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -13,29 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.deploy = (function() {
var deploymentTypes = {
"full":{img:"red/images/deploy-full-o.png"},
"nodes":{img:"red/images/deploy-nodes-o.png"},
"flows":{img:"red/images/deploy-flows-o.png"}
}
var ignoreDeployWarnings = {
unknown: false,
unusedConfig: false,
invalid: false
}
var deploymentType = "full";
var deployInflight = false;
var currentDiff = null;
function changeDeploymentType(type) {
deploymentType = type;
$("#btn-deploy img").attr("src",deploymentTypes[type].img);
$("#btn-deploy-icon").attr("src",deploymentTypes[type].img);
}
/**
* options:
* type: "default" - Button with drop-down options - no further customisation available
@@ -46,75 +49,166 @@ RED.deploy = (function() {
function init(options) {
options = options || {};
var type = options.type || "default";
if (type == "default") {
$('<li><span class="deploy-button-group button-group">'+
'<a id="btn-deploy" class="deploy-button disabled" href="#"><img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> <span>Deploy</span></a>'+
'<a id="btn-deploy" class="deploy-button disabled" href="#">'+
'<span class="deploy-button-content">'+
'<img id="btn-deploy-icon" src="red/images/deploy-full-o.png"> '+
'<span>'+RED._("deploy.deploy")+'</span>'+
'</span>'+
'<span class="deploy-button-spinner hide">'+
'<img src="red/images/spin.svg"/>'+
'</span>'+
'</a>'+
'<a id="btn-deploy-options" data-toggle="dropdown" class="deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+
'</span></li>').prependTo(".header-toolbar");
RED.menu.init({id:"btn-deploy-options",
options: [
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.png",label:"Full",sublabel:"Deploys everything in the workspace",selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.png",label:"Modified Flows",sublabel:"Only deploys flows that contain changed nodes", onselect:function(s) {if(s){changeDeploymentType("flows")}}},
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.png",label:"Modified Nodes",sublabel:"Only deploys nodes that have changed",onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.png",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.png",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.png",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
]
});
} else if (type == "simple") {
var label = options.label || "Deploy";
var label = options.label || RED._("deploy.deploy");
var icon = 'red/images/deploy-full-o.png';
if (options.hasOwnProperty('icon')) {
icon = options.icon;
}
$('<li><span class="deploy-button-group button-group">'+
'<a id="btn-deploy" class="deploy-button disabled" href="#">'+
(icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+
'<span>'+label+'</span></a>'+
'<span class="deploy-button-content">'+
(icon?'<img id="btn-deploy-icon" src="'+icon+'"> ':'')+
'<span>'+label+'</span>'+
'</span>'+
'<span class="deploy-button-spinner hide">'+
'<img src="red/images/spin.svg"/>'+
'</span>'+
'</a>'+
'</span></li>').prependTo(".header-toolbar");
}
$('#btn-deploy').click(function() { save(); });
$('#btn-deploy').click(function(event) {
event.preventDefault();
save();
});
RED.actions.add("core:deploy-flows",save);
$( "#node-dialog-confirm-deploy" ).dialog({
title: "Confirm deploy",
title: RED._('deploy.confirm.button.confirm'),
modal: true,
autoOpen: false,
width: 550,
height: "auto",
buttons: [
{
text: "Confirm deploy",
text: RED._("common.label.cancel"),
click: function() {
var ignoreChecked = $( "#node-dialog-confirm-deploy-hide" ).prop("checked");
if (ignoreChecked) {
ignoreDeployWarnings[$( "#node-dialog-confirm-deploy-type" ).val()] = true;
}
save(true);
$( this ).dialog( "close" );
}
},
{
text: "Cancel",
id: "node-dialog-confirm-deploy-review",
text: RED._("deploy.confirm.button.review"),
class: "primary disabled",
click: function() {
if (!$("#node-dialog-confirm-deploy-review").hasClass('disabled')) {
RED.diff.showRemoteDiff();
$( this ).dialog( "close" );
}
}
},
{
id: "node-dialog-confirm-deploy-merge",
text: RED._("deploy.confirm.button.merge"),
class: "primary disabled",
click: function() {
RED.diff.mergeDiff(currentDiff);
$( this ).dialog( "close" );
}
},
{
id: "node-dialog-confirm-deploy-deploy",
text: RED._("deploy.confirm.button.confirm"),
class: "primary",
click: function() {
var ignoreChecked = $( "#node-dialog-confirm-deploy-hide" ).prop("checked");
if (ignoreChecked) {
ignoreDeployWarnings[$( "#node-dialog-confirm-deploy-type" ).val()] = true;
}
save(true,/conflict/.test($("#node-dialog-confirm-deploy-type" ).val()));
$( this ).dialog( "close" );
}
},
{
id: "node-dialog-confirm-deploy-overwrite",
text: RED._("deploy.confirm.button.overwrite"),
class: "primary",
click: function() {
save(true,/conflict/.test($("#node-dialog-confirm-deploy-type" ).val()));
$( this ).dialog( "close" );
}
}
],
create: function() {
$("#node-dialog-confirm-deploy").parent().find("div.ui-dialog-buttonpane")
.append('<div style="height:0; vertical-align: middle; display:inline-block;">'+
'<input style="vertical-align:top;" type="checkbox" id="node-dialog-confirm-deploy-hide">'+
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+
.prepend('<div style="height:0; vertical-align: middle; display:inline-block; margin-top: 13px; float:left;">'+
'<input style="vertical-align:top;" type="checkbox" id="node-dialog-confirm-deploy-hide"> '+
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide" data-i18n="deploy.confirm.doNotWarn"></label>'+
'<input type="hidden" id="node-dialog-confirm-deploy-type">'+
'</div>');
},
open: function() {
var deployType = $("#node-dialog-confirm-deploy-type" ).val();
if (/conflict/.test(deployType)) {
$( "#node-dialog-confirm-deploy" ).dialog('option','title', RED._('deploy.confirm.button.review'));
$("#node-dialog-confirm-deploy-deploy").hide();
$("#node-dialog-confirm-deploy-review").addClass('disabled').show();
$("#node-dialog-confirm-deploy-merge").addClass('disabled').show();
$("#node-dialog-confirm-deploy-overwrite").toggle(deployType === "deploy-conflict");
currentDiff = null;
$("#node-dialog-confirm-deploy-conflict-checking").show();
$("#node-dialog-confirm-deploy-conflict-auto-merge").hide();
$("#node-dialog-confirm-deploy-conflict-manual-merge").hide();
var now = Date.now();
RED.diff.getRemoteDiff(function(diff) {
var ellapsed = Math.max(1000 - (Date.now()-now), 0);
currentDiff = diff;
setTimeout(function() {
$("#node-dialog-confirm-deploy-conflict-checking").hide();
var d = Object.keys(diff.conflicts);
if (d.length === 0) {
$("#node-dialog-confirm-deploy-conflict-auto-merge").show();
$("#node-dialog-confirm-deploy-merge").removeClass('disabled')
} else {
$("#node-dialog-confirm-deploy-conflict-manual-merge").show();
}
$("#node-dialog-confirm-deploy-review").removeClass('disabled')
},ellapsed);
})
$("#node-dialog-confirm-deploy-hide").parent().hide();
} else {
$( "#node-dialog-confirm-deploy" ).dialog('option','title', RED._('deploy.confirm.button.confirm'));
$("#node-dialog-confirm-deploy-deploy").show();
$("#node-dialog-confirm-deploy-overwrite").hide();
$("#node-dialog-confirm-deploy-review").hide();
$("#node-dialog-confirm-deploy-merge").hide();
$("#node-dialog-confirm-deploy-hide").parent().show();
}
}
});
RED.nodes.on('change',function(state) {
RED.events.on('nodes:change',function(state) {
if (state.dirty) {
window.onbeforeunload = function() {
return "You have undeployed changes.\n\nLeaving this page will lose these changes.";
return RED._("deploy.confirm.undeployedChanges");
}
$("#btn-deploy").removeClass("disabled");
} else {
@@ -122,20 +216,84 @@ RED.deploy = (function() {
$("#btn-deploy").addClass("disabled");
}
});
var activeNotifyMessage;
RED.comms.subscribe("notification/runtime-deploy",function(topic,msg) {
if (!activeNotifyMessage) {
var currentRev = RED.nodes.version();
if (currentRev === null || deployInflight || currentRev === msg.revision) {
return;
}
var message = $('<div>'+RED._('deploy.confirm.backgroundUpdate')+
'<br><br><div class="ui-dialog-buttonset">'+
'<button>'+RED._('deploy.confirm.button.ignore')+'</button>'+
'<button class="primary">'+RED._('deploy.confirm.button.review')+'</button>'+
'</div></div>');
$(message.find('button')[0]).click(function(evt) {
evt.preventDefault();
activeNotifyMessage.close();
activeNotifyMessage = null;
})
$(message.find('button')[1]).click(function(evt) {
evt.preventDefault();
activeNotifyMessage.close();
var nns = RED.nodes.createCompleteNodeSet();
resolveConflict(nns,false);
activeNotifyMessage = null;
})
activeNotifyMessage = RED.notify(message,null,true);
}
});
}
function save(force) {
if (RED.nodes.dirty()) {
//$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy
function getNodeInfo(node) {
var tabLabel = "";
if (node.z) {
var tab = RED.nodes.workspace(node.z);
if (!tab) {
tab = RED.nodes.subflow(node.z);
tabLabel = tab.name;
} else {
tabLabel = tab.label;
}
}
var label = RED.utils.getNodeLabel(node,node.id);
return {tab:tabLabel,type:node.type,label:label};
}
function sortNodeInfo(A,B) {
if (A.tab < B.tab) { return -1;}
if (A.tab > B.tab) { return 1;}
if (A.type < B.type) { return -1;}
if (A.type > B.type) { return 1;}
if (A.name < B.name) { return -1;}
if (A.name > B.name) { return 1;}
return 0;
}
if (!force) {
function resolveConflict(currentNodes, activeDeploy) {
$( "#node-dialog-confirm-deploy-config" ).hide();
$( "#node-dialog-confirm-deploy-unknown" ).hide();
$( "#node-dialog-confirm-deploy-unused" ).hide();
$( "#node-dialog-confirm-deploy-conflict" ).show();
$( "#node-dialog-confirm-deploy-type" ).val(activeDeploy?"deploy-conflict":"background-conflict");
$( "#node-dialog-confirm-deploy" ).dialog( "open" );
}
function save(skipValidation,force) {
if (!$("#btn-deploy").hasClass("disabled")) {
if (!skipValidation) {
var hasUnknown = false;
var hasInvalid = false;
var hasUnusedConfig = false;
var unknownNodes = [];
var invalidNodes = [];
RED.nodes.eachNode(function(node) {
hasInvalid = hasInvalid || !node.valid;
if (!node.valid) {
invalidNodes.push(getNodeInfo(node));
}
if (node.type === "unknown") {
if (unknownNodes.indexOf(node.name) == -1) {
unknownNodes.push(node.name);
@@ -143,29 +301,22 @@ RED.deploy = (function() {
}
});
hasUnknown = unknownNodes.length > 0;
var unusedConfigNodes = {};
var unusedConfigNodes = [];
RED.nodes.eachConfig(function(node) {
if (node.users.length === 0) {
var label = "";
if (typeof node._def.label == "function") {
label = node._def.label.call(node);
} else {
label = node._def.label;
}
label = label || node.id;
unusedConfigNodes[node.type] = unusedConfigNodes[node.type] || [];
unusedConfigNodes[node.type].push(label);
if (node.users.length === 0 && (node._def.hasUsers !== false)) {
unusedConfigNodes.push(getNodeInfo(node));
hasUnusedConfig = true;
}
});
$( "#node-dialog-confirm-deploy-config" ).hide();
$( "#node-dialog-confirm-deploy-unknown" ).hide();
$( "#node-dialog-confirm-deploy-unused" ).hide();
$( "#node-dialog-confirm-deploy-conflict" ).hide();
var showWarning = false;
if (hasUnknown && !ignoreDeployWarnings.unknown) {
showWarning = true;
$( "#node-dialog-confirm-deploy-type" ).val("unknown");
@@ -176,19 +327,18 @@ RED.deploy = (function() {
showWarning = true;
$( "#node-dialog-confirm-deploy-type" ).val("invalid");
$( "#node-dialog-confirm-deploy-config" ).show();
invalidNodes.sort(sortNodeInfo);
$( "#node-dialog-confirm-deploy-invalid-list" )
.html("<li>"+invalidNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"}).join("</li><li>")+"</li>");
} else if (hasUnusedConfig && !ignoreDeployWarnings.unusedConfig) {
showWarning = true;
$( "#node-dialog-confirm-deploy-type" ).val("unusedConfig");
$( "#node-dialog-confirm-deploy-unused" ).show();
var unusedNodeLabels = [];
var unusedTypes = Object.keys(unusedConfigNodes).sort();
unusedTypes.forEach(function(type) {
unusedConfigNodes[type].forEach(function(label) {
unusedNodeLabels.push(type+": "+label);
});
});
$( "#node-dialog-confirm-deploy-unused-list" )
.html("<li>"+unusedNodeLabels.join("</li><li>")+"</li>");
// showWarning = true;
// $( "#node-dialog-confirm-deploy-type" ).val("unusedConfig");
// $( "#node-dialog-confirm-deploy-unused" ).show();
//
// unusedConfigNodes.sort(sortNodeInfo);
// $( "#node-dialog-confirm-deploy-unused-list" )
// .html("<li>"+unusedConfigNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"}).join("</li><li>")+"</li>");
}
if (showWarning) {
$( "#node-dialog-confirm-deploy-hide" ).prop("checked",false);
@@ -196,57 +346,96 @@ RED.deploy = (function() {
return;
}
}
var nns = RED.nodes.createCompleteNodeSet();
$("#btn-deploy-icon").removeClass('fa-download');
$("#btn-deploy-icon").addClass('spinner');
RED.nodes.dirty(false);
var startTime = Date.now();
$(".deploy-button-content").css('opacity',0);
$(".deploy-button-spinner").show();
$("#btn-deploy").addClass("disabled");
var data = {flows:nns};
if (!force) {
data.rev = RED.nodes.version();
}
deployInflight = true;
$("#header-shade").show();
$("#editor-shade").show();
$("#palette-shade").show();
$("#sidebar-shade").show();
$.ajax({
url:"flows",
type: "POST",
data: JSON.stringify(nns),
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
headers: {
"Node-RED-Deployment-Type":deploymentType
}
}).done(function(data,textStatus,xhr) {
RED.notify("Successfully deployed","success");
RED.nodes.dirty(false);
RED.nodes.version(data.rev);
RED.nodes.originalFlow(nns);
if (hasUnusedConfig) {
RED.notify(
'<p>'+RED._("deploy.successfulDeploy")+'</p>'+
'<p>'+RED._("deploy.unusedConfigNodes")+' <a href="#" onclick="RED.sidebar.config.show(true); return false;">'+RED._("deploy.unusedConfigNodesLink")+'</a></p>',"success",false,6000);
} else {
RED.notify(RED._("deploy.successfulDeploy"),"success");
}
RED.nodes.eachNode(function(node) {
if (node.changed) {
node.dirty = true;
node.changed = false;
}
if (node.moved) {
node.dirty = true;
node.moved = false;
}
if(node.credentials) {
delete node.credentials;
}
});
RED.nodes.eachConfig(function (confNode) {
confNode.changed = false;
if (confNode.credentials) {
delete confNode.credentials;
}
});
RED.nodes.eachWorkspace(function(ws) {
ws.changed = false;
})
// Once deployed, cannot undo back to a clean state
RED.history.markAllDirty();
RED.view.redraw();
RED.events.emit("deploy");
}).fail(function(xhr,textStatus,err) {
RED.nodes.dirty(true);
if (xhr.responseText) {
RED.notify("<strong>Error</strong>: "+xhr.responseJSON.message,"error");
$("#btn-deploy").removeClass("disabled");
if (xhr.status === 401) {
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
} else if (xhr.status === 409) {
resolveConflict(nns, true);
} else if (xhr.responseText) {
RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
} else {
RED.notify("<strong>Error</strong>: no response from server","error");
RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
}
}).always(function() {
$("#btn-deploy-icon").removeClass('spinner');
$("#btn-deploy-icon").addClass('fa-download');
deployInflight = false;
var delta = Math.max(0,300-(Date.now()-startTime));
setTimeout(function() {
$(".deploy-button-content").css('opacity',1);
$(".deploy-button-spinner").hide();
$("#header-shade").hide();
$("#editor-shade").hide();
$("#palette-shade").hide();
$("#sidebar-shade").hide();
},delta);
});
}
}
return {
init: init
}

1342
editor/js/ui/diff.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013 IBM Corp.
* 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.
@@ -15,107 +15,516 @@
**/
RED.keyboard = (function() {
var active = true;
var isMac = /Mac/i.test(window.navigator.platform);
var handlers = {};
var partialState;
var keyMap = {
"left":37,
"up":38,
"right":39,
"down":40,
"escape":27,
"enter": 13,
"backspace": 8,
"delete": 46,
"space": 32,
";":186,
"=":187,
",":188,
"-":189,
".":190,
"/":191,
"\\":220,
"'":222,
"?":191 // <- QWERTY specific
}
var metaKeyCodes = {
16:true,
17:true,
18: true,
91:true,
93: true
}
var actionToKeyMap = {}
var defaultKeyMap = {};
// FF generates some different keycodes because reasons.
var firefoxKeyCodeMap = {
59:186,
61:187,
173:189
}
function init() {
var userKeymap = RED.settings.get('keymap') || {};
$.getJSON("red/keymap.json",function(data) {
for (var scope in data) {
if (data.hasOwnProperty(scope)) {
var keys = data[scope];
for (var key in keys) {
if (keys.hasOwnProperty(key)) {
if (!userKeymap.hasOwnProperty(keys[key])) {
addHandler(scope,key,keys[key],false);
defaultKeyMap[keys[key]] = {
scope:scope,
key:key,
user:false
};
}
}
}
}
}
for (var action in userKeymap) {
if (userKeymap.hasOwnProperty(action)) {
var obj = userKeymap[action];
if (obj.hasOwnProperty('key')) {
addHandler(obj.scope, obj.key, action, true);
}
}
}
});
RED.userSettings.add({
id:'keyboard',
title: RED._("keyboard.keyboard"),
get: getSettingsPane,
focus: function() {
setTimeout(function() {
$("#user-settings-tab-keyboard-filter").focus();
},200);
}
})
}
function revertToDefault(action) {
var currentAction = actionToKeyMap[action];
if (currentAction) {
removeHandler(currentAction.key);
}
if (defaultKeyMap.hasOwnProperty(action)) {
var obj = defaultKeyMap[action];
addHandler(obj.scope, obj.key, action, false);
}
}
function parseKeySpecifier(key) {
var parts = key.toLowerCase().split("-");
var modifiers = {};
var keycode;
var blank = 0;
for (var i=0;i<parts.length;i++) {
switch(parts[i]) {
case "ctrl":
case "cmd":
modifiers.ctrl = true;
modifiers.meta = true;
break;
case "alt":
modifiers.alt = true;
break;
case "shift":
modifiers.shift = true;
break;
case "":
blank++;
keycode = keyMap["-"];
break;
default:
if (keyMap.hasOwnProperty(parts[i])) {
keycode = keyMap[parts[i]];
} else if (parts[i].length > 1) {
return null;
} else {
keycode = parts[i].toUpperCase().charCodeAt(0);
}
break;
}
}
return [keycode,modifiers];
}
function resolveKeyEvent(evt) {
var slot = partialState||handlers;
if (evt.ctrlKey || evt.metaKey) {
slot = slot.ctrl;
}
if (slot && evt.shiftKey) {
slot = slot.shift;
}
if (slot && evt.altKey) {
slot = slot.alt;
}
var keyCode = firefoxKeyCodeMap[evt.keyCode] || evt.keyCode;
if (slot && slot[keyCode]) {
var handler = slot[keyCode];
if (!handler.scope) {
if (partialState) {
partialState = null;
return resolveKeyEvent(evt);
} else if (Object.keys(handler).length > 0) {
partialState = handler;
evt.preventDefault();
return null;
} else {
return null;
}
} else if (handler.scope && handler.scope !== "*") {
var target = evt.target;
while (target.nodeName !== 'BODY' && target.id !== handler.scope) {
target = target.parentElement;
}
if (target.nodeName === 'BODY') {
handler = null;
}
}
partialState = null;
return handler;
} else if (partialState) {
partialState = null;
return resolveKeyEvent(evt);
}
}
d3.select(window).on("keydown",function() {
if (!active) { return; }
var handler = handlers[d3.event.keyCode];
if (handler && handler.ondown) {
if (!handler.modifiers ||
((!handler.modifiers.shift || d3.event.shiftKey) &&
(!handler.modifiers.ctrl || d3.event.ctrlKey || d3.event.metaKey) &&
(!handler.modifiers.alt || d3.event.altKey) )) {
handler.ondown();
}
}
});
d3.select(window).on("keyup",function() {
if (!active) { return; }
var handler = handlers[d3.event.keyCode];
if (handler && handler.onup) {
if (!handler.modifiers ||
((!handler.modifiers.shift || d3.event.shiftKey) &&
(!handler.modifiers.ctrl || d3.event.ctrlKey || d3.event.metaKey) &&
(!handler.modifiers.alt || d3.event.altKey) )) {
handler.onup();
}
}
});
function addHandler(key,modifiers,ondown,onup) {
var mod = modifiers;
var cbdown = ondown;
var cbup = onup;
if (typeof modifiers == "function") {
mod = {};
cbdown = modifiers;
cbup = ondown;
}
handlers[key] = {modifiers:mod, ondown:cbdown, onup:cbup};
}
function removeHandler(key) {
delete handlers[key];
}
var dialog = null;
function showKeyboardHelp() {
if (!RED.settings.theme("menu.menu-item-keyboard-shortcuts",true)) {
if (metaKeyCodes[d3.event.keyCode]) {
return;
}
if (!dialog) {
dialog = $('<div id="keyboard-help-dialog" class="hide">'+
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
'<table class="keyboard-shortcuts">'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">a</span></td><td>Select all nodes</td></tr>'+
'<tr><td><span class="help-key">Shift</span> + <span class="help-key">Click</span></td><td>Select all connected nodes</td></tr>'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">Click</span></td><td>Add/remove node from selection</td></tr>'+
'<tr><td><span class="help-key">Delete</span></td><td>Delete selected nodes or link</td></tr>'+
'<tr><td>&nbsp;</td><td></td></tr>'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">i</span></td><td>Import nodes</td></tr>'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">e</span></td><td>Export selected nodes</td></tr>'+
'</table>'+
'</div>'+
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
'<table class="keyboard-shortcuts">'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">Space</span></td><td>Toggle sidebar</td></tr>'+
'<tr><td></td><td></td></tr>'+
'<tr><td><span class="help-key">Delete</span></td><td>Delete selected nodes or link</td></tr>'+
'<tr><td></td><td></td></tr>'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">c</span></td><td>Copy selected nodes</td></tr>'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">x</span></td><td>Cut selected nodes</td></tr>'+
'<tr><td><span class="help-key">Ctrl/&#8984;</span> + <span class="help-key">v</span></td><td>Paste nodes</td></tr>'+
'</table>'+
'</div>'+
'</div>')
.appendTo("body")
.dialog({
modal: true,
autoOpen: false,
width: "800",
title:"Keyboard shortcuts",
resizable: false,
open: function() {
RED.keyboard.disable();
},
close: function() {
RED.keyboard.enable();
}
});
var handler = resolveKeyEvent(d3.event);
if (handler && handler.ondown) {
if (typeof handler.ondown === "string") {
RED.actions.invoke(handler.ondown);
} else {
handler.ondown();
}
d3.event.preventDefault();
}
dialog.dialog("open");
});
function addHandler(scope,key,modifiers,ondown) {
var mod = modifiers;
var cbdown = ondown;
if (typeof modifiers == "function" || typeof modifiers === "string") {
mod = {};
cbdown = modifiers;
}
var keys = [];
var i=0;
if (typeof key === 'string') {
if (typeof cbdown === 'string') {
actionToKeyMap[cbdown] = {scope:scope,key:key};
if (typeof ondown === 'boolean') {
actionToKeyMap[cbdown].user = ondown;
}
}
var parts = key.split(" ");
for (i=0;i<parts.length;i++) {
var parsedKey = parseKeySpecifier(parts[i]);
if (parsedKey) {
keys.push(parsedKey);
} else {
return;
}
}
} else {
keys.push([key,mod])
}
var slot = handlers;
for (i=0;i<keys.length;i++) {
key = keys[i][0];
mod = keys[i][1];
if (mod.ctrl) {
slot.ctrl = slot.ctrl||{};
slot = slot.ctrl;
}
if (mod.shift) {
slot.shift = slot.shift||{};
slot = slot.shift;
}
if (mod.alt) {
slot.alt = slot.alt||{};
slot = slot.alt;
}
slot[key] = slot[key] || {};
slot = slot[key];
//slot[key] = {scope: scope, ondown:cbdown};
}
slot.scope = scope;
slot.ondown = cbdown;
}
function removeHandler(key,modifiers) {
var mod = modifiers || {};
var keys = [];
var i=0;
if (typeof key === 'string') {
var parts = key.split(" ");
for (i=0;i<parts.length;i++) {
var parsedKey = parseKeySpecifier(parts[i]);
if (parsedKey) {
keys.push(parsedKey);
} else {
console.log("Unrecognised key specifier:",key)
return;
}
}
} else {
keys.push([key,mod])
}
var slot = handlers;
for (i=0;i<keys.length;i++) {
key = keys[i][0];
mod = keys[i][1];
if (mod.ctrl) {
slot = slot.ctrl;
}
if (slot && mod.shift) {
slot = slot.shift;
}
if (slot && mod.alt) {
slot = slot.alt;
}
if (!slot[key]) {
return;
}
slot = slot[key];
}
if (typeof slot.ondown === "string") {
if (typeof modifiers === 'boolean' && modifiers) {
actionToKeyMap[slot.ondown] = {user: modifiers}
} else {
delete actionToKeyMap[slot.ondown];
}
}
delete slot.scope;
delete slot.ondown;
}
var cmdCtrlKey = '<span class="help-key">'+(isMac?'&#8984;':'Ctrl')+'</span>';
function formatKey(key) {
var formattedKey = isMac?key.replace(/ctrl-?/,"&#8984;"):key;
formattedKey = isMac?formattedKey.replace(/alt-?/,"&#8997;"):key;
formattedKey = formattedKey.replace(/shift-?/,"&#8679;")
formattedKey = formattedKey.replace(/left/,"&#x2190;")
formattedKey = formattedKey.replace(/up/,"&#x2191;")
formattedKey = formattedKey.replace(/right/,"&#x2192;")
formattedKey = formattedKey.replace(/down/,"&#x2193;")
return '<span class="help-key-block"><span class="help-key">'+formattedKey.split(" ").join('</span> <span class="help-key">')+'</span></span>';
}
function validateKey(key) {
key = key.trim();
var parts = key.split(" ");
for (i=0;i<parts.length;i++) {
var parsedKey = parseKeySpecifier(parts[i]);
if (!parsedKey) {
return false;
}
}
return true;
}
function editShortcut(e) {
e.preventDefault();
var container = $(this);
var object = container.data('data');
if (!container.hasClass('keyboard-shortcut-entry-expanded')) {
endEditShortcut();
var key = container.find(".keyboard-shortcut-entry-key");
var scope = container.find(".keyboard-shortcut-entry-scope");
container.addClass('keyboard-shortcut-entry-expanded');
var keyInput = $('<input type="text">').attr('placeholder',RED._('keyboard.unassigned')).val(object.key||"").appendTo(key);
keyInput.on("keyup",function(e) {
if (e.keyCode === 13) {
return endEditShortcut();
}
var currentVal = $(this).val();
currentVal = currentVal.trim();
var valid = (currentVal === "" || RED.keyboard.validateKey(currentVal));
$(this).toggleClass("input-error",!valid);
})
var scopeSelect = $('<select><option value="*" data-i18n="keyboard.global"></option><option value="workspace" data-i18n="keyboard.workspace"></option></select>').appendTo(scope);
scopeSelect.i18n();
scopeSelect.val(object.scope||'*');
var div = $('<div class="keyboard-shortcut-edit button-group-vertical"></div>').appendTo(scope);
var okButton = $('<button class="editor-button editor-button-small"><i class="fa fa-check"></i></button>').appendTo(div);
var revertButton = $('<button class="editor-button editor-button-small"><i class="fa fa-reply"></i></button>').appendTo(div);
okButton.click(function(e) {
e.stopPropagation();
endEditShortcut();
});
revertButton.click(function(e) {
e.stopPropagation();
RED.keyboard.revertToDefault(object.id);
container.empty();
container.removeClass('keyboard-shortcut-entry-expanded');
var shortcut = RED.keyboard.getShortcut(object.id);
var userKeymap = RED.settings.get('keymap') || {};
delete userKeymap[object.id];
RED.settings.set('keymap',userKeymap);
var obj = {
id:object.id,
scope:shortcut?shortcut.scope:undefined,
key:shortcut?shortcut.key:undefined,
user:shortcut?shortcut.user:undefined
}
buildShortcutRow(container,obj);
})
keyInput.focus();
}
}
function endEditShortcut(cancel) {
var container = $('.keyboard-shortcut-entry-expanded');
if (container.length === 1) {
var object = container.data('data');
var keyInput = container.find(".keyboard-shortcut-entry-key input");
var scopeSelect = container.find(".keyboard-shortcut-entry-scope select");
if (!cancel) {
var key = keyInput.val().trim();
var scope = scopeSelect.val();
var valid = (key === "" || RED.keyboard.validateKey(key));
if (valid) {
var current = RED.keyboard.getShortcut(object.id);
if ((!current && key) || (current && (current.scope !== scope || current.key !== key))) {
var keyDiv = container.find(".keyboard-shortcut-entry-key");
var scopeDiv = container.find(".keyboard-shortcut-entry-scope");
keyDiv.empty();
scopeDiv.empty();
if (object.key) {
RED.keyboard.remove(object.key,true);
}
container.find(".keyboard-shortcut-entry-text i").css("opacity",1);
if (key === "") {
keyDiv.parent().addClass("keyboard-shortcut-entry-unassigned");
keyDiv.append($('<span>').text(RED._('keyboard.unassigned')) );
delete object.key;
delete object.scope;
} else {
keyDiv.parent().removeClass("keyboard-shortcut-entry-unassigned");
keyDiv.append(RED.keyboard.formatKey(key))
$("<span>").text(scope).appendTo(scopeDiv);
object.key = key;
object.scope = scope;
RED.keyboard.add(object.scope,object.key,object.id,true);
}
var userKeymap = RED.settings.get('keymap') || {};
userKeymap[object.id] = RED.keyboard.getShortcut(object.id);
RED.settings.set('keymap',userKeymap);
}
}
}
keyInput.remove();
scopeSelect.remove();
$('.keyboard-shortcut-edit').remove();
container.removeClass('keyboard-shortcut-entry-expanded');
}
}
function buildShortcutRow(container,object) {
var item = $('<div class="keyboard-shortcut-entry">').appendTo(container);
container.data('data',object);
var text = object.id.replace(/(^.+:([a-z]))|(-([a-z]))/g,function() {
if (arguments[5] === 0) {
return arguments[2].toUpperCase();
} else {
return " "+arguments[4].toUpperCase();
}
});
var label = $('<div>').addClass("keyboard-shortcut-entry-text").text(text).appendTo(item);
var user = $('<i class="fa fa-user"></i>').prependTo(label);
if (!object.user) {
user.css("opacity",0);
}
var key = $('<div class="keyboard-shortcut-entry-key">').appendTo(item);
if (object.key) {
key.append(RED.keyboard.formatKey(object.key));
} else {
item.addClass("keyboard-shortcut-entry-unassigned");
key.append($('<span>').text(RED._('keyboard.unassigned')) );
}
var scope = $('<div class="keyboard-shortcut-entry-scope">').appendTo(item);
$("<span>").text(object.scope === '*'?'global':object.scope||"").appendTo(scope);
container.click(editShortcut);
}
function getSettingsPane() {
var pane = $('<div id="user-settings-tab-keyboard"></div>');
$('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+
'<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input id="user-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+
'<div class="keyboard-shortcut-entry-key" data-i18n="keyboard.shortcut"></div>'+
'<div class="keyboard-shortcut-entry-scope" data-i18n="keyboard.scope"></div>'+
'</div>').appendTo(pane);
pane.find("input").searchBox({
delay: 100,
change: function() {
var filterValue = $(this).val().trim();
if (filterValue === "") {
shortcutList.editableList('filter', null);
} else {
filterValue = filterValue.replace(/\s/g,"");
shortcutList.editableList('filter', function(data) {
return data.id.toLowerCase().replace(/^.*:/,"").replace("-","").indexOf(filterValue) > -1;
})
}
}
});
var shortcutList = $('<ol class="keyboard-shortcut-list"></ol>').css({
position: "absolute",
top: "32px",
bottom: "0",
left: "0",
right: "0"
}).appendTo(pane).editableList({
addButton: false,
scrollOnAdd: false,
addItem: function(container,i,object) {
buildShortcutRow(container,object);
},
});
var shortcuts = RED.actions.list();
shortcuts.sort(function(A,B) {
var Aid = A.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase();
var Bid = B.id.replace(/^.*:/,"").replace(/[ -]/g,"").toLowerCase();
return Aid.localeCompare(Bid);
});
shortcuts.forEach(function(s) {
shortcutList.editableList('addItem',s);
});
return pane;
}
return {
init: init,
add: addHandler,
remove: removeHandler,
disable: function(){ active = false;},
enable: function(){ active = true; },
showHelp: showKeyboardHelp
getShortcut: function(actionName) {
return actionToKeyMap[actionName];
},
revertToDefault: revertToDefault,
formatKey: formatKey,
validateKey: validateKey
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013, 2015 IBM Corp.
* 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.
@@ -14,8 +14,10 @@
* limitations under the License.
**/
RED.library = (function() {
var exportToLibraryDialog;
function loadFlowLibrary() {
$.getJSON("library/flows",function(data) {
//console.log(data);
@@ -25,7 +27,9 @@ RED.library = (function() {
var li;
var a;
var ul = document.createElement("ul");
ul.id = "menu-item-import-library-submenu";
if (root === "") {
ul.id = "menu-item-import-library-submenu";
}
ul.className = "dropdown-menu";
if (data.d) {
for (i in data.d) {
@@ -34,7 +38,8 @@ RED.library = (function() {
li.className = "dropdown-submenu pull-left";
a = document.createElement("a");
a.href="#";
a.innerHTML = i;
var label = i.replace(/^node-red-contrib-/,"").replace(/^node-red-node-/,"").replace(/-/," ").replace(/_/," ");
a.innerHTML = label;
li.appendChild(a);
li.appendChild(buildMenu(data.d[i],root+(root!==""?"/":"")+i));
ul.appendChild(li);
@@ -51,7 +56,7 @@ RED.library = (function() {
a.flowName = root+(root!==""?"/":"")+data.f[i];
a.onclick = function() {
$.get('library/flows/'+this.flowName, function(data) {
RED.view.importNodes(data);
RED.view.importNodes(data);
});
};
li.appendChild(a);
@@ -61,17 +66,27 @@ RED.library = (function() {
}
return ul;
};
var examples;
if (data.d && data.d._examples_) {
examples = data.d._examples_;
delete data.d._examples_;
}
var menu = buildMenu(data,"");
$("#menu-item-import-examples").remove();
if (examples) {
RED.menu.addItem("menu-item-import",{id:"menu-item-import-examples",label:RED._("menu.label.examples"),options:[]})
$("#menu-item-import-examples-submenu").replaceWith(buildMenu(examples,"_examples_"));
}
//TODO: need an api in RED.menu for this
$("#menu-item-import-library-submenu").replaceWith(menu);
});
}
function createUI(options) {
var libraryData = {};
var selectedLibraryItem = null;
var libraryEditor = null;
// Orion editor has set/getText
// ACE editor has set/getValue
// normalise to set/getValue
@@ -84,18 +99,18 @@ RED.library = (function() {
if (options.editor.getText) {
options.editor.getValue = options.editor.getText;
}
function buildFileListItem(item) {
var li = document.createElement("li");
li.onmouseover = function(e) { $(this).addClass("list-hover"); };
li.onmouseout = function(e) { $(this).removeClass("list-hover"); };
return li;
}
function buildFileList(root,data) {
var ul = document.createElement("ul");
var li;
for (var i=0;i<data.length;i++) {
for (var i=0; i<data.length; i++) {
var v = data[i];
if (typeof v === "string") {
// directory
@@ -104,7 +119,7 @@ RED.library = (function() {
var dirName = v;
return function(e) {
var bcli = $('<li class="active"><span class="divider">/</span> <a href="#">'+dirName+'</a></li>');
$("a",bcli).click(function(e) {
$("a",bcli).click(function(e) {
$(this).parent().nextAll().remove();
$.getJSON("library/"+options.url+root+dirName,function(data) {
$("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data));
@@ -115,7 +130,7 @@ RED.library = (function() {
$(".active",bc).removeClass("active");
bc.append(bcli);
$.getJSON("library/"+options.url+root+dirName,function(data) {
$("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data));
$("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data));
});
}
})();
@@ -123,42 +138,40 @@ RED.library = (function() {
ul.appendChild(li);
} else {
// file
li = buildFileListItem(v);
li.innerHTML = v.name;
li.onclick = (function() {
var item = v;
return function(e) {
$(".list-selected",ul).removeClass("list-selected");
$(this).addClass("list-selected");
$.get("library/"+options.url+root+item.fn, function(data) {
selectedLibraryItem = item;
libraryEditor.setValue(data,-1);
});
}
})();
ul.appendChild(li);
li = buildFileListItem(v);
li.innerHTML = v.name;
li.onclick = (function() {
var item = v;
return function(e) {
$(".list-selected",ul).removeClass("list-selected");
$(this).addClass("list-selected");
$.get("library/"+options.url+root+item.fn, function(data) {
selectedLibraryItem = item;
libraryEditor.setValue(data,-1);
});
}
})();
ul.appendChild(li);
}
}
return ul;
}
$('#node-input-name').addClass('input-append-left').css("width","65%").after(
'<div class="btn-group" style="margin-left: 0px;">'+
'<button id="node-input-'+options.type+'-lookup" class="btn input-append-right" data-toggle="dropdown"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></button>'+
$('#node-input-name').css("width","66%").after(
'<div class="btn-group" style="margin-left: 5px;">'+
'<a id="node-input-'+options.type+'-lookup" class="editor-button" data-toggle="dropdown"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></a>'+
'<ul class="dropdown-menu pull-right" role="menu">'+
'<li><a id="node-input-'+options.type+'-menu-open-library" tabindex="-1" href="#">Open Library...</a></li>'+
'<li><a id="node-input-'+options.type+'-menu-save-library" tabindex="-1" href="#">Save to Library...</a></li>'+
'<li><a id="node-input-'+options.type+'-menu-open-library" tabindex="-1" href="#">'+RED._("library.openLibrary")+'</a></li>'+
'<li><a id="node-input-'+options.type+'-menu-save-library" tabindex="-1" href="#">'+RED._("library.saveToLibrary")+'</a></li>'+
'</ul></div>'
);
$('#node-input-'+options.type+'-menu-open-library').click(function(e) {
$("#node-select-library").children().remove();
var bc = $("#node-dialog-library-breadcrumbs");
bc.children().first().nextAll().remove();
libraryEditor.setValue('',-1);
$.getJSON("library/"+options.url,function(data) {
$("#node-select-library").append(buildFileList("/",data));
$("#node-dialog-library-breadcrumbs a").click(function(e) {
@@ -168,10 +181,10 @@ RED.library = (function() {
});
$( "#node-dialog-library-lookup" ).dialog( "open" );
});
e.preventDefault();
});
$('#node-input-'+options.type+'-menu-save-library').click(function(e) {
//var found = false;
var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
@@ -217,7 +230,7 @@ RED.library = (function() {
$( "#node-dialog-library-save" ).dialog( "open" );
e.preventDefault();
});
libraryEditor = ace.edit('node-select-library-text');
libraryEditor.setTheme("ace/theme/tomorrow");
if (options.mode) {
@@ -230,19 +243,26 @@ RED.library = (function() {
});
libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
libraryEditor.$blockScrolling = Infinity;
$( "#node-dialog-library-lookup" ).dialog({
title: options.type+" library",
title: RED._("library.typeLibrary", {type:options.type}),
modal: true,
autoOpen: false,
width: 800,
height: 450,
buttons: [
{
text: "Ok",
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
}
},
{
text: RED._("common.label.load"),
class: "primary",
click: function() {
if (selectedLibraryItem) {
for (var i=0;i<options.fields.length;i++) {
for (var i=0; i<options.fields.length; i++) {
var field = options.fields[i];
$("#node-input-"+field).val(selectedLibraryItem[field]);
}
@@ -250,12 +270,6 @@ RED.library = (function() {
}
$( this ).dialog( "close" );
}
},
{
text: "Cancel",
click: function() {
$( this ).dialog( "close" );
}
}
],
open: function(e) {
@@ -270,16 +284,16 @@ RED.library = (function() {
$(".form-row:last-child",form).children().height(form.height()-60);
}
});
function saveToLibrary(overwrite) {
var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
if (name === "") {
name = "Unnamed "+options.type;
name = RED._("library.unnamedType",{type:options.type});
}
var filename = $("#node-dialog-library-save-filename").val().replace(/(^\s*)|(\s*$)/g,"");
var pathname = $("#node-dialog-library-save-folder").val().replace(/(^\s*)|(\s*$)/g,"");
if (filename === "" || !/.+\.js$/.test(filename)) {
RED.notify("Invalid filename","warning");
RED.notify(RED._("library.invalidFilename"),"warning");
return;
}
var fullpath = pathname+(pathname===""?"":"/")+filename;
@@ -304,15 +318,14 @@ RED.library = (function() {
// }
//}
//if (exists) {
// $("#node-dialog-library-save-type").html(options.type);
// $("#node-dialog-library-save-name").html(fullpath);
// $("#node-dialog-library-save-content").html(RED._("library.dialogSaveOverwrite",{libraryType:options.type,libraryName:fullpath}));
// $("#node-dialog-library-save-confirm").dialog( "open" );
// return;
//}
}
var queryArgs = [];
var data = {};
for (var i=0;i<options.fields.length;i++) {
for (var i=0; i<options.fields.length; i++) {
var field = options.fields[i];
if (field == "name") {
data.name = name;
@@ -320,7 +333,7 @@ RED.library = (function() {
data[field] = $("#node-input-"+field).val();
}
}
data.text = options.editor.getValue();
$.ajax({
url:"library/"+options.url+'/'+fullpath,
@@ -328,50 +341,56 @@ RED.library = (function() {
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8"
}).done(function(data,textStatus,xhr) {
RED.notify("Saved "+options.type,"success");
RED.notify(RED._("library.savedType", {type:options.type}),"success");
}).fail(function(xhr,textStatus,err) {
RED.notify("Saved failed: "+xhr.responseJSON.message,"error");
if (xhr.status === 401) {
RED.notify(RED._("library.saveFailed",{message:RED._("user.notAuthorized")}),"error");
} else {
RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error");
}
});
}
$( "#node-dialog-library-save-confirm" ).dialog({
title: "Save to library",
title: RED._("library.saveToLibrary"),
modal: true,
autoOpen: false,
width: 530,
height: 230,
buttons: [
{
text: "Ok",
text: RED._("common.label.cancel"),
click: function() {
saveToLibrary(true);
$( this ).dialog( "close" );
}
},
{
text: "Cancel",
text: RED._("common.label.save"),
class: "primary",
click: function() {
saveToLibrary(true);
$( this ).dialog( "close" );
}
}
]
});
$( "#node-dialog-library-save" ).dialog({
title: "Save to library",
title: RED._("library.saveToLibrary"),
modal: true,
autoOpen: false,
width: 530,
height: 230,
buttons: [
{
text: "Ok",
text: RED._("common.label.cancel"),
click: function() {
saveToLibrary(false);
$( this ).dialog( "close" );
}
},
{
text: "Cancel",
text: RED._("common.label.save"),
class: "primary",
click: function() {
saveToLibrary(false);
$( this ).dialog( "close" );
}
}
@@ -379,18 +398,20 @@ RED.library = (function() {
});
}
function exportFlow() {
//TODO: don't rely on the main dialog
var nns = RED.nodes.createExportableNodeSet(RED.view.selection().nodes);
$("#dialog-form").html($("script[data-template-name='export-library-dialog']").html());
$("#node-input-filename").attr('nodes',JSON.stringify(nns));
$( "#dialog" ).dialog("option","title","Export nodes to library").dialog( "open" );
$("#node-input-library-filename").attr('nodes',JSON.stringify(nns));
exportToLibraryDialog.dialog( "open" );
}
return {
init: function() {
RED.view.on("selection-changed",function(selection) {
RED.actions.add("core:library-export",exportFlow);
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
RED.menu.setDisabled("menu-item-export-clipboard",true);
@@ -401,16 +422,72 @@ RED.library = (function() {
RED.menu.setDisabled("menu-item-export-library",false);
}
});
if (RED.settings.theme("menu.menu-item-import-library") !== false) {
if (RED.settings.theme("menu.menu-item-import-library") !== false) {
loadFlowLibrary();
}
exportToLibraryDialog = $('<div id="library-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>')
.appendTo("body")
.dialog({
modal: true,
autoOpen: false,
width: 500,
resizable: false,
title: RED._("library.exportToLibrary"),
buttons: [
{
id: "library-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "library-dialog-ok",
class: "primary",
text: RED._("common.label.export"),
click: function() {
//TODO: move this to RED.library
var flowName = $("#node-input-library-filename").val();
if (!/^\s*$/.test(flowName)) {
$.ajax({
url:'library/flows/'+flowName,
type: "POST",
data: $("#node-input-library-filename").attr('nodes'),
contentType: "application/json; charset=utf-8"
}).done(function() {
RED.library.loadFlowLibrary();
RED.notify(RED._("library.savedNodes"),"success");
}).fail(function(xhr,textStatus,err) {
if (xhr.status === 401) {
RED.notify(RED._("library.saveFailed",{message:RED._("user.notAuthorized")}),"error");
} else {
RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error");
}
});
}
$( this ).dialog( "close" );
}
}
],
open: function(e) {
$(this).parent().find(".ui-dialog-titlebar-close").hide();
},
close: function(e) {
}
});
exportToLibraryDialog.children(".dialog-form").append($(
'<div class="form-row">'+
'<label for="node-input-library-filename" data-i18n="[append]editor:library.filename"><i class="fa fa-file"></i> </label>'+
'<input type="text" id="node-input-library-filename" data-i18n="[placeholder]editor:library.fullFilenamePlaceholder">'+
'<input type="text" style="display: none;" />'+ // Second hidden input to prevent submit on Enter
'</div>'
));
},
create: createUI,
loadFlowLibrary: loadFlowLibrary,
export: exportFlow
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013 IBM Corp.
* 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.
@@ -30,13 +30,17 @@ RED.notify = (function() {
}
var n = document.createElement("div");
n.id="red-notification-"+c;
n.className = "alert";
n.className = "notification";
n.fixed = fixed;
if (type) {
n.className = "alert alert-"+type;
n.className = "notification notification-"+type;
}
n.style.display = "none";
n.innerHTML = msg;
if (typeof msg === "string") {
n.innerHTML = msg;
} else {
$(n).append(msg);
}
$("#notifications").append(n);
$(n).slideDown(300);
n.close = (function() {
@@ -44,11 +48,36 @@ RED.notify = (function() {
return function() {
currentNotifications.splice(currentNotifications.indexOf(nn),1);
$(nn).slideUp(300, function() {
nn.parentNode.removeChild(nn);
nn.parentNode.removeChild(nn);
});
};
})();
n.update = (function() {
var nn = n;
return function(msg,timeout) {
if (typeof msg === "string") {
nn.innerHTML = msg;
} else {
$(nn).empty().append(msg);
}
if (timeout !== undefined && timeout > 0) {
window.clearTimeout(nn.timeoutid);
nn.timeoutid = window.setTimeout(nn.close,timeout);
} else {
window.clearTimeout(nn.timeoutid);
}
}
})();
if (!fixed) {
$(n).click((function() {
var nn = n;
return function() {
nn.close();
window.clearTimeout(nn.timeoutid);
};
})());
n.timeoutid = window.setTimeout(n.close,timeout||3000);
}
currentNotifications.push(n);
@@ -56,4 +85,3 @@ RED.notify = (function() {
return n;
}
})();

View File

@@ -0,0 +1,956 @@
/**
* 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.palette.editor = (function() {
var disabled = false;
var editorTabs;
var filterInput;
var searchInput;
var nodeList;
var packageList;
var loadedList = [];
var filteredList = [];
var loadedIndex = {};
var typesInUse = {};
var nodeEntries = {};
var eventTimers = {};
var activeFilter = "";
function semVerCompare(A,B) {
var aParts = A.split(".").map(function(m) { return parseInt(m);});
var bParts = B.split(".").map(function(m) { return parseInt(m);});
for (var i=0;i<3;i++) {
var j = aParts[i]-bParts[i];
if (j<0) { return -1 }
if (j>0) { return 1 }
}
return 0;
}
function delayCallback(start,callback) {
var delta = Date.now() - start;
if (delta < 300) {
delta = 300;
} else {
delta = 0;
}
setTimeout(function() {
callback();
},delta);
}
function changeNodeState(id,state,shade,callback) {
shade.show();
var start = Date.now();
$.ajax({
url:"nodes/"+id,
type: "PUT",
data: JSON.stringify({
enabled: state
}),
contentType: "application/json; charset=utf-8"
}).done(function(data,textStatus,xhr) {
delayCallback(start,function() {
shade.hide();
callback();
});
}).fail(function(xhr,textStatus,err) {
delayCallback(start,function() {
shade.hide();
callback(xhr);
});
})
}
function installNodeModule(id,version,shade,callback) {
var requestBody = {
module: id
};
if (callback === undefined) {
callback = shade;
shade = version;
} else {
requestBody.version = version;
}
shade.show();
$.ajax({
url:"nodes",
type: "POST",
data: JSON.stringify(requestBody),
contentType: "application/json; charset=utf-8"
}).done(function(data,textStatus,xhr) {
shade.hide();
callback();
}).fail(function(xhr,textStatus,err) {
shade.hide();
callback(xhr);
});
}
function removeNodeModule(id,callback) {
$.ajax({
url:"nodes/"+id,
type: "DELETE"
}).done(function(data,textStatus,xhr) {
callback();
}).fail(function(xhr,textStatus,err) {
callback(xhr);
})
}
function refreshNodeModuleList() {
for (var id in nodeEntries) {
if (nodeEntries.hasOwnProperty(id)) {
_refreshNodeModule(id);
}
}
}
function refreshNodeModule(module) {
if (!eventTimers.hasOwnProperty(module)) {
eventTimers[module] = setTimeout(function() {
delete eventTimers[module];
_refreshNodeModule(module);
},100);
}
}
function getContrastingBorder(rgbColor){
var parts = /^rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)[,)]/.exec(rgbColor);
if (parts) {
var r = parseInt(parts[1]);
var g = parseInt(parts[2]);
var b = parseInt(parts[3]);
var yiq = ((r*299)+(g*587)+(b*114))/1000;
if (yiq > 160) {
r = Math.floor(r*0.8);
g = Math.floor(g*0.8);
b = Math.floor(b*0.8);
return "rgb("+r+","+g+","+b+")";
}
}
return rgbColor;
}
function formatUpdatedAt(dateString) {
var now = new Date();
var d = new Date(dateString);
var delta = (Date.now() - new Date(dateString).getTime())/1000;
if (delta < 60) {
return RED._('palette.editor.times.seconds');
}
delta = Math.floor(delta/60);
if (delta < 10) {
return RED._('palette.editor.times.minutes');
}
if (delta < 60) {
return RED._('palette.editor.times.minutesV',{count:delta});
}
delta = Math.floor(delta/60);
if (delta < 24) {
return RED._('palette.editor.times.hoursV',{count:delta});
}
delta = Math.floor(delta/24);
if (delta < 7) {
return RED._('palette.editor.times.daysV',{count:delta})
}
var weeks = Math.floor(delta/7);
var days = delta%7;
if (weeks < 4) {
return RED._('palette.editor.times.weeksV',{count:weeks})
}
var months = Math.floor(weeks/4);
weeks = weeks%4;
if (months < 12) {
return RED._('palette.editor.times.monthsV',{count:months})
}
var years = Math.floor(months/12);
months = months%12;
if (months === 0) {
return RED._('palette.editor.times.yearsV',{count:years})
} else {
return RED._('palette.editor.times.year'+(years>1?'s':'')+'MonthsV',{y:years,count:months})
}
}
function _refreshNodeModule(module) {
if (!nodeEntries.hasOwnProperty(module)) {
nodeEntries[module] = {info:RED.nodes.registry.getModule(module)};
var index = [module];
for (var s in nodeEntries[module].info.sets) {
if (nodeEntries[module].info.sets.hasOwnProperty(s)) {
index.push(s);
index = index.concat(nodeEntries[module].info.sets[s].types)
}
}
nodeEntries[module].index = index.join(",").toLowerCase();
nodeList.editableList('addItem', nodeEntries[module]);
} else {
var moduleInfo = nodeEntries[module].info;
var nodeEntry = nodeEntries[module].elements;
if (nodeEntry) {
var activeTypeCount = 0;
var typeCount = 0;
nodeEntries[module].totalUseCount = 0;
nodeEntries[module].setUseCount = {};
for (var setName in moduleInfo.sets) {
if (moduleInfo.sets.hasOwnProperty(setName)) {
var inUseCount = 0;
var set = moduleInfo.sets[setName];
var setElements = nodeEntry.sets[setName];
if (set.enabled) {
activeTypeCount += set.types.length;
}
typeCount += set.types.length;
for (var i=0;i<moduleInfo.sets[setName].types.length;i++) {
var t = moduleInfo.sets[setName].types[i];
inUseCount += (typesInUse[t]||0);
var swatch = setElements.swatches[t];
if (set.enabled) {
var def = RED.nodes.getType(t);
if (def && def.color) {
swatch.css({background:def.color});
swatch.css({border: "1px solid "+getContrastingBorder(swatch.css('backgroundColor'))})
} else {
swatch.css({background:"#eee",border:"1px dashed #999"})
}
} else {
swatch.css({background:"#eee",border:"1px dashed #999"})
}
}
nodeEntries[module].setUseCount[setName] = inUseCount;
nodeEntries[module].totalUseCount += inUseCount;
if (inUseCount > 0) {
setElements.enableButton.html(RED._('palette.editor.inuse'));
setElements.enableButton.addClass('disabled');
} else {
setElements.enableButton.removeClass('disabled');
if (set.enabled) {
setElements.enableButton.html(RED._('palette.editor.disable'));
} else {
setElements.enableButton.html(RED._('palette.editor.enable'));
}
}
setElements.setRow.toggleClass("palette-module-set-disabled",!set.enabled);
}
}
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
nodeEntry.setCount.html(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
if (nodeEntries[module].totalUseCount > 0) {
nodeEntry.enableButton.html(RED._('palette.editor.inuse'));
nodeEntry.enableButton.addClass('disabled');
nodeEntry.removeButton.hide();
} else {
nodeEntry.enableButton.removeClass('disabled');
if (moduleInfo.local) {
nodeEntry.removeButton.css('display', 'inline-block');
}
if (activeTypeCount === 0) {
nodeEntry.enableButton.html(RED._('palette.editor.enableall'));
} else {
nodeEntry.enableButton.html(RED._('palette.editor.disableall'));
}
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
}
}
if (moduleInfo.pending_version) {
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
nodeEntry.updateButton.html(RED._('palette.editor.updated')).addClass('disabled').show();
} else if (loadedIndex.hasOwnProperty(module)) {
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) === 1) {
nodeEntry.updateButton.show();
nodeEntry.updateButton.html(RED._('palette.editor.update',{version:loadedIndex[module].version}));
} else {
nodeEntry.updateButton.hide();
}
} else {
nodeEntry.updateButton.hide();
}
}
}
function filterChange(val) {
activeFilter = val.toLowerCase();
var visible = nodeList.editableList('filter');
var size = nodeList.editableList('length');
if (val === "") {
filterInput.searchBox('count');
} else {
filterInput.searchBox('count',visible+" / "+size);
}
}
var catalogueCount;
var catalogueLoadStatus = [];
var catalogueLoadStart;
var catalogueLoadErrors = false;
var activeSort = sortModulesAZ;
function handleCatalogResponse(err,catalog,index,v) {
catalogueLoadStatus.push(err||v);
if (!err) {
if (v.modules) {
v.modules.forEach(function(m) {
loadedIndex[m.id] = m;
m.index = [m.id];
if (m.keywords) {
m.index = m.index.concat(m.keywords);
}
if (m.updated_at) {
m.timestamp = new Date(m.updated_at).getTime();
} else {
m.timestamp = 0;
}
m.index = m.index.join(",").toLowerCase();
})
loadedList = loadedList.concat(v.modules);
}
searchInput.searchBox('count',loadedList.length);
} else {
catalogueLoadErrors = true;
}
if (catalogueCount > 1) {
$(".palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>"+catalogueLoadStatus.length+"/"+catalogueCount);
}
if (catalogueLoadStatus.length === catalogueCount) {
if (catalogueLoadErrors) {
RED.notify(RED._('palette.editor.errors.catalogLoadFailed',{url: catalog}),"error",false,8000);
}
var delta = 250-(Date.now() - catalogueLoadStart);
setTimeout(function() {
$("#palette-module-install-shade").hide();
},Math.max(delta,0));
}
}
function initInstallTab() {
if (loadedList.length === 0) {
loadedList = [];
loadedIndex = {};
packageList.editableList('empty');
$(".palette-module-shade-status").html(RED._('palette.editor.loading'));
var catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json'];
catalogueLoadStatus = [];
catalogueLoadErrors = false;
catalogueCount = catalogues.length;
if (catalogues.length > 1) {
$(".palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>0/"+catalogues.length);
}
$("#palette-module-install-shade").show();
catalogueLoadStart = Date.now();
var handled = 0;
catalogues.forEach(function(catalog,index) {
$.getJSON(catalog, {_: new Date().getTime()},function(v) {
handleCatalogResponse(null,catalog,index,v);
refreshNodeModuleList();
}).fail(function(jqxhr, textStatus, error) {
handleCatalogResponse(jqxhr,catalog,index);
}).always(function() {
handled++;
if (handled === catalogueCount) {
searchInput.searchBox('change');
}
})
});
}
}
function refreshFilteredItems() {
packageList.editableList('empty');
var currentFilter = searchInput.searchBox('value').trim();
if (currentFilter === ""){
packageList.editableList('addItem',{count:loadedList.length})
return;
}
filteredList.sort(activeSort);
for (var i=0;i<Math.min(10,filteredList.length);i++) {
packageList.editableList('addItem',filteredList[i]);
}
if (filteredList.length === 0) {
packageList.editableList('addItem',{});
}
if (filteredList.length > 10) {
packageList.editableList('addItem',{start:10,more:filteredList.length-10})
}
}
function sortModulesAZ(A,B) {
return A.info.id.localeCompare(B.info.id);
}
function sortModulesRecent(A,B) {
return -1 * (A.info.timestamp-B.info.timestamp);
}
function init() {
if (RED.settings.theme('palette.editable') === false) {
return;
}
createSettingsPane();
RED.userSettings.add({
id:'palette',
title: RED._("palette.editor.palette"),
get: getSettingsPane,
close: function() {
settingsPane.detach();
},
focus: function() {
editorTabs.resize();
setTimeout(function() {
filterInput.focus();
},200);
}
})
RED.actions.add("core:manage-palette",function() {
RED.userSettings.show('palette');
});
RED.events.on('registry:module-updated', function(ns) {
refreshNodeModule(ns.module);
});
RED.events.on('registry:node-set-enabled', function(ns) {
refreshNodeModule(ns.module);
});
RED.events.on('registry:node-set-disabled', function(ns) {
refreshNodeModule(ns.module);
});
RED.events.on('registry:node-type-added', function(nodeType) {
if (!/^subflow:/.test(nodeType)) {
var ns = RED.nodes.registry.getNodeSetForType(nodeType);
refreshNodeModule(ns.module);
}
});
RED.events.on('registry:node-type-removed', function(nodeType) {
if (!/^subflow:/.test(nodeType)) {
var ns = RED.nodes.registry.getNodeSetForType(nodeType);
refreshNodeModule(ns.module);
}
});
RED.events.on('registry:node-set-added', function(ns) {
refreshNodeModule(ns.module);
for (var i=0;i<filteredList.length;i++) {
if (filteredList[i].info.id === ns.module) {
var installButton = filteredList[i].elements.installButton;
installButton.addClass('disabled');
installButton.html(RED._('palette.editor.installed'));
break;
}
}
});
RED.events.on('registry:node-set-removed', function(ns) {
var module = RED.nodes.registry.getModule(ns.module);
if (!module) {
var entry = nodeEntries[ns.module];
if (entry) {
nodeList.editableList('removeItem', entry);
delete nodeEntries[ns.module];
for (var i=0;i<filteredList.length;i++) {
if (filteredList[i].info.id === ns.module) {
var installButton = filteredList[i].elements.installButton;
installButton.removeClass('disabled');
installButton.html(RED._('palette.editor.install'));
break;
}
}
}
}
});
RED.events.on('nodes:add', function(n) {
if (!/^subflow:/.test(n.type)) {
typesInUse[n.type] = (typesInUse[n.type]||0)+1;
if (typesInUse[n.type] === 1) {
var ns = RED.nodes.registry.getNodeSetForType(n.type);
refreshNodeModule(ns.module);
}
}
})
RED.events.on('nodes:remove', function(n) {
if (typesInUse.hasOwnProperty(n.type)) {
typesInUse[n.type]--;
if (typesInUse[n.type] === 0) {
delete typesInUse[n.type];
var ns = RED.nodes.registry.getNodeSetForType(n.type);
refreshNodeModule(ns.module);
}
}
})
}
var settingsPane;
function getSettingsPane() {
initInstallTab();
editorTabs.activateTab('nodes');
return settingsPane;
}
function createSettingsPane() {
settingsPane = $('<div id="user-settings-tab-palette"></div>');
var content = $('<div id="palette-editor">'+
'<ul id="palette-editor-tabs"></ul>'+
'</div>').appendTo(settingsPane);
editorTabs = RED.tabs.create({
element: settingsPane.find('#palette-editor-tabs'),
onchange:function(tab) {
content.find(".palette-editor-tab").hide();
tab.content.show();
if (filterInput) {
filterInput.searchBox('value',"");
}
if (searchInput) {
searchInput.searchBox('value',"");
}
if (tab.id === 'install') {
if (searchInput) {
searchInput.focus();
}
} else {
if (filterInput) {
filterInput.focus();
}
}
},
minimumActiveTabWidth: 110
});
var modulesTab = $('<div>',{class:"palette-editor-tab"}).appendTo(content);
editorTabs.addTab({
id: 'nodes',
label: RED._('palette.editor.tab-nodes'),
content: modulesTab
})
var filterDiv = $('<div>',{class:"palette-search"}).appendTo(modulesTab);
filterInput = $('<input type="text" data-i18n="[placeholder]palette.filter"></input>')
.appendTo(filterDiv)
.searchBox({
delay: 200,
change: function() {
filterChange($(this).val());
}
});
nodeList = $('<ol>',{id:"palette-module-list", style:"position: absolute;top: 35px;bottom: 0;left: 0;right: 0px;"}).appendTo(modulesTab).editableList({
addButton: false,
scrollOnAdd: false,
sort: function(A,B) {
return A.info.name.localeCompare(B.info.name);
},
filter: function(data) {
if (activeFilter === "" ) {
return true;
}
return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1);
},
addItem: function(container,i,object) {
var entry = object.info;
if (entry) {
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
var titleRow = $('<div class="palette-module-meta palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
$('<span>').html(entry.name).appendTo(titleRow);
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
var setButton = $('<a href="#" class="editor-button editor-button-small palette-module-set-button"><i class="fa fa-angle-right palette-module-node-chevron"></i> </a>').appendTo(buttonRow);
var setCount = $('<span>').appendTo(setButton);
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.update')).appendTo(buttonGroup);
updateButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
updateButton.click(function(evt) {
evt.preventDefault();
if ($(this).hasClass('disabled')) {
return;
}
$("#palette-module-install-confirm").data('module',entry.name);
$("#palette-module-install-confirm").data('version',loadedIndex[entry.name].version);
$("#palette-module-install-confirm").data('shade',shade);
$("#palette-module-install-confirm-body").html(entry.local?
RED._("palette.editor.confirm.update.body"):
RED._("palette.editor.confirm.cannotUpdate.body")
);
$(".palette-module-install-confirm-button-install").hide();
$(".palette-module-install-confirm-button-remove").hide();
if (entry.local) {
$(".palette-module-install-confirm-button-update").show();
} else {
$(".palette-module-install-confirm-button-update").hide();
}
$("#palette-module-install-confirm")
.dialog('option', 'title',RED._("palette.editor.confirm.update.title"))
.dialog('open');
})
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.remove')).appendTo(buttonGroup);
removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
removeButton.click(function(evt) {
evt.preventDefault();
$("#palette-module-install-confirm").data('module',entry.name);
$("#palette-module-install-confirm").data('shade',shade);
$("#palette-module-install-confirm-body").html(RED._("palette.editor.confirm.remove.body"));
$(".palette-module-install-confirm-button-install").hide();
$(".palette-module-install-confirm-button-remove").show();
$(".palette-module-install-confirm-button-update").hide();
$("#palette-module-install-confirm")
.dialog('option', 'title', RED._("palette.editor.confirm.remove.title"))
.dialog('open');
})
if (!entry.local) {
removeButton.hide();
}
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.disableall')).appendTo(buttonGroup);
var contentRow = $('<div>',{class:"palette-module-content"}).appendTo(container);
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
object.elements = {
updateButton: updateButton,
removeButton: removeButton,
enableButton: enableButton,
setCount: setCount,
container: container,
shade: shade,
versionSpan: versionSpan,
sets: {}
}
setButton.click(function(evt) {
evt.preventDefault();
if (container.hasClass('expanded')) {
container.removeClass('expanded');
contentRow.slideUp();
} else {
container.addClass('expanded');
contentRow.slideDown();
}
})
var setList = Object.keys(entry.sets)
setList.sort(function(A,B) {
return A.toLowerCase().localeCompare(B.toLowerCase());
});
setList.forEach(function(setName) {
var set = entry.sets[setName];
var setRow = $('<div>',{class:"palette-module-set"}).appendTo(contentRow);
var buttonGroup = $('<div>',{class:"palette-module-set-button-group"}).appendTo(setRow);
var typeSwatches = {};
set.types.forEach(function(t) {
var typeDiv = $('<div>',{class:"palette-module-type"}).appendTo(setRow);
typeSwatches[t] = $('<span>',{class:"palette-module-type-swatch"}).appendTo(typeDiv);
$('<span>',{class:"palette-module-type-node"}).html(t).appendTo(typeDiv);
})
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').appendTo(buttonGroup);
enableButton.click(function(evt) {
evt.preventDefault();
if (object.setUseCount[setName] === 0) {
var currentSet = RED.nodes.registry.getNodeSet(set.id);
shade.show();
var newState = !currentSet.enabled
changeNodeState(set.id,newState,shade,function(xhr){
if (xhr) {
if (xhr.responseJSON) {
RED.notify(RED._('palette.editor.errors.'+(newState?'enable':'disable')+'Failed',{module: id,message:xhr.responseJSON.message}));
}
}
});
}
})
object.elements.sets[set.name] = {
setRow: setRow,
enableButton: enableButton,
swatches: typeSwatches
};
});
enableButton.click(function(evt) {
evt.preventDefault();
if (object.totalUseCount === 0) {
changeNodeState(entry.name,(container.hasClass('disabled')),shade,function(xhr){
if (xhr) {
if (xhr.responseJSON) {
RED.notify(RED._('palette.editor.errors.installFailed',{module: id,message:xhr.responseJSON.message}));
}
}
});
}
})
refreshNodeModule(entry.name);
} else {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
}
}
});
var installTab = $('<div>',{class:"palette-editor-tab hide"}).appendTo(content);
editorTabs.addTab({
id: 'install',
label: RED._('palette.editor.tab-install'),
content: installTab
})
var toolBar = $('<div>',{class:"palette-editor-toolbar"}).appendTo(installTab);
var searchDiv = $('<div>',{class:"palette-search"}).appendTo(installTab);
searchInput = $('<input type="text" data-i18n="[placeholder]palette.search"></input>')
.appendTo(searchDiv)
.searchBox({
delay: 300,
change: function() {
var searchTerm = $(this).val().trim().toLowerCase();
if (searchTerm.length > 0) {
filteredList = loadedList.filter(function(m) {
return (m.index.indexOf(searchTerm) > -1);
}).map(function(f) { return {info:f}});
refreshFilteredItems();
searchInput.searchBox('count',filteredList.length+" / "+loadedList.length);
} else {
searchInput.searchBox('count',loadedList.length);
packageList.editableList('empty');
packageList.editableList('addItem',{count:loadedList.length});
}
}
});
$('<span>').html(RED._("palette.editor.sort")+' ').appendTo(toolBar);
var sortGroup = $('<span class="button-group"></span>').appendTo(toolBar);
var sortAZ = $('<a href="#" class="sidebar-header-button-toggle selected" data-i18n="palette.editor.sortAZ"></a>').appendTo(sortGroup);
var sortRecent = $('<a href="#" class="sidebar-header-button-toggle" data-i18n="palette.editor.sortRecent"></a>').appendTo(sortGroup);
sortAZ.click(function(e) {
e.preventDefault();
if ($(this).hasClass("selected")) {
return;
}
$(this).addClass("selected");
sortRecent.removeClass("selected");
activeSort = sortModulesAZ;
refreshFilteredItems();
});
sortRecent.click(function(e) {
e.preventDefault();
if ($(this).hasClass("selected")) {
return;
}
$(this).addClass("selected");
sortAZ.removeClass("selected");
activeSort = sortModulesRecent;
refreshFilteredItems();
});
var refreshSpan = $('<span>').appendTo(toolBar);
var refreshButton = $('<a href="#" class="sidebar-header-button"><i class="fa fa-refresh"></i></a>').appendTo(refreshSpan);
refreshButton.click(function(e) {
e.preventDefault();
loadedList = [];
loadedIndex = {};
initInstallTab();
})
packageList = $('<ol>',{style:"position: absolute;top: 78px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({
addButton: false,
scrollOnAdd: false,
addItem: function(container,i,object) {
if (object.count) {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container);
return
}
if (object.more) {
container.addClass('palette-module-more');
var moreRow = $('<div>',{class:"palette-module-header palette-module"}).appendTo(container);
var moreLink = $('<a href="#"></a>').html(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
moreLink.click(function(e) {
e.preventDefault();
packageList.editableList('removeItem',object);
for (var i=object.start;i<Math.min(object.start+10,object.start+object.more);i++) {
packageList.editableList('addItem',filteredList[i]);
}
if (object.more > 10) {
packageList.editableList('addItem',{start:object.start+10, more:object.more-10})
}
})
return;
}
if (object.info) {
var entry = object.info;
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
var titleRow = $('<div class="palette-module-meta"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
$('<span>',{class:"palette-module-name"}).html(entry.name||entry.id).appendTo(titleRow);
$('<a target="_blank" class="palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow);
var descRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
$('<div>',{class:"palette-module-description"}).html(entry.description).appendTo(descRow);
var metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
$('<span class="palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
$('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup);
installButton.click(function(e) {
e.preventDefault();
if (!$(this).hasClass('disabled')) {
$("#palette-module-install-confirm").data('module',entry.id);
$("#palette-module-install-confirm").data('version',entry.version);
$("#palette-module-install-confirm").data('url',entry.url);
$("#palette-module-install-confirm").data('shade',shade);
$("#palette-module-install-confirm-body").html(RED._("palette.editor.confirm.install.body"));
$(".palette-module-install-confirm-button-install").show();
$(".palette-module-install-confirm-button-remove").hide();
$(".palette-module-install-confirm-button-update").hide();
$("#palette-module-install-confirm")
.dialog('option', 'title', RED._("palette.editor.confirm.install.title"))
.dialog('open');
}
})
if (nodeEntries.hasOwnProperty(entry.id)) {
installButton.addClass('disabled');
installButton.html(RED._('palette.editor.installed'));
}
object.elements = {
installButton:installButton
}
} else {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
}
}
});
$('<div id="palette-module-install-shade" class="palette-module-shade hide"><div class="palette-module-shade-status"></div><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(installTab);
$('<div id="palette-module-install-confirm" class="hide"><form class="form-horizontal"><div id="palette-module-install-confirm-body" class="node-dialog-confirm-row"></div></form></div>').appendTo(document.body);
$("#palette-module-install-confirm").dialog({
title: RED._('palette.editor.confirm.title'),
modal: true,
autoOpen: false,
width: 550,
height: "auto",
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
}
},
{
text: RED._("palette.editor.confirm.button.review"),
class: "primary palette-module-install-confirm-button-install",
click: function() {
var url = $(this).data('url');
window.open(url);
}
},
{
text: RED._("palette.editor.confirm.button.install"),
class: "primary palette-module-install-confirm-button-install",
click: function() {
var id = $(this).data('module');
var version = $(this).data('version');
var shade = $(this).data('shade');
installNodeModule(id,version,shade,function(xhr) {
if (xhr) {
if (xhr.responseJSON) {
RED.notify(RED._('palette.editor.errors.installFailed',{module: id,message:xhr.responseJSON.message}));
}
}
});
$( this ).dialog( "close" );
}
},
{
text: RED._("palette.editor.confirm.button.remove"),
class: "primary palette-module-install-confirm-button-remove",
click: function() {
var id = $(this).data('module');
var shade = $(this).data('shade');
shade.show();
removeNodeModule(id, function(xhr) {
shade.hide();
if (xhr) {
if (xhr.responseJSON) {
RED.notify(RED._('palette.editor.errors.removeFailed',{module: id,message:xhr.responseJSON.message}));
}
}
})
$( this ).dialog( "close" );
}
},
{
text: RED._("palette.editor.confirm.button.update"),
class: "primary palette-module-install-confirm-button-update",
click: function() {
var id = $(this).data('module');
var version = $(this).data('version');
var shade = $(this).data('shade');
shade.show();
installNodeModule(id,version,shade,function(xhr) {
if (xhr) {
if (xhr.responseJSON) {
RED.notify(RED._('palette.editor.errors.updateFailed',{module: id,message:xhr.responseJSON.message}));
}
}
});
$( this ).dialog( "close" );
}
}
]
})
}
return {
init: init
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013, 2015 IBM Corp.
* 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.
@@ -17,32 +17,56 @@
RED.palette = (function() {
var exclusion = ['config','unknown','deprecated'];
var core = ['subflows', 'input', 'output', 'function', 'social', 'storage', 'analysis', 'advanced'];
var coreCategories = ['subflows', 'input', 'output', 'function', 'social', 'mobile', 'storage', 'analysis', 'advanced'];
function createCategoryContainer(category){
var escapedCategory = category.replace(" ","_");
var catDiv = $("#palette-container").append('<div id="palette-container-'+category+'" class="palette-category hide">'+
'<div id="palette-header-'+category+'" class="palette-header"><i class="expanded fa fa-caret-down"></i><span>'+category.replace("_"," ")+'</span></div>'+
var categoryContainers = {};
function createCategoryContainer(category, label){
label = (label || category).replace(/_/g, " ");
var catDiv = $('<div id="palette-container-'+category+'" class="palette-category palette-close hide">'+
'<div id="palette-header-'+category+'" class="palette-header"><i class="expanded fa fa-angle-down"></i><span>'+label+'</span></div>'+
'<div class="palette-content" id="palette-base-category-'+category+'">'+
'<div id="palette-'+category+'-input"></div>'+
'<div id="palette-'+category+'-output"></div>'+
'<div id="palette-'+category+'-function"></div>'+
'</div>'+
'</div>');
'</div>').appendTo("#palette-container");
categoryContainers[category] = {
container: catDiv,
close: function() {
catDiv.removeClass("palette-open");
catDiv.addClass("palette-closed");
$("#palette-base-category-"+category).slideUp();
$("#palette-header-"+category+" i").removeClass("expanded");
},
open: function() {
catDiv.addClass("palette-open");
catDiv.removeClass("palette-closed");
$("#palette-base-category-"+category).slideDown();
$("#palette-header-"+category+" i").addClass("expanded");
},
toggle: function() {
if (catDiv.hasClass("palette-open")) {
categoryContainers[category].close();
} else {
categoryContainers[category].open();
}
}
};
$("#palette-header-"+category).on('click', function(e) {
$(this).next().slideToggle();
$(this).children("i").toggleClass("expanded");
categoryContainers[category].toggle();
});
}
function setLabel(type, el,label) {
var nodeWidth = 80;
function setLabel(type, el,label, info) {
var nodeWidth = 82;
var nodeHeight = 25;
var lineHeight = 20;
var portHeight = 10;
var words = label.split(" ");
var words = label.split(/[ -]/);
var displayLines = [];
@@ -67,30 +91,29 @@ RED.palette = (function() {
el.css({height:multiLineNodeHeight+"px"});
var labelElement = el.find(".palette_label");
labelElement.html(lines);
labelElement.html(lines).attr('dir', RED.text.bidi.resolveBaseTextDir(lines));
el.find(".palette_port").css({top:(multiLineNodeHeight/2-5)+"px"});
var popOverContent;
try {
var l = "<p><b>"+label+"</b></p>";
var l = "<p><b>"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"</b></p>";
if (label != type) {
l = "<p><b>"+label+"</b><br/><i>"+type+"</i></p>";
l = "<p><b>"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"</b><br/><i>"+type+"</i></p>";
}
popOverContent = $(l+($("script[data-help-name|='"+type+"']").html()||"<p>no information available</p>").trim())
popOverContent = $(l+(info?info:$("script[data-help-name='"+type+"']").html()||"<p>"+RED._("palette.noInfo")+"</p>").trim())
.filter(function(n) {
return this.nodeType == 1 || (this.nodeType == 3 && this.textContent.trim().length > 0)
return (this.nodeType == 1 && this.nodeName == "P") || (this.nodeType == 3 && this.textContent.trim().length > 0)
}).slice(0,2);
} catch(err) {
// Malformed HTML may cause errors. TODO: need to understand what can break
console.log("Error generating pop-over label for '"+type+"'.");
// NON-NLS: internal debug
console.log("Error generating pop-over label for ",type);
console.log(err.toString());
popOverContent = "<p><b>"+label+"</b></p><p>no information available</p>";
popOverContent = "<p><b>"+label+"</b></p><p>"+RED._("palette.noInfo")+"</p>";
}
el.data('popover').options.content = popOverContent;
el.data('popover').setContent(popOverContent);
}
function escapeNodeType(nt) {
@@ -102,34 +125,33 @@ RED.palette = (function() {
if ($("#palette_node_"+nodeTypeId).length) {
return;
}
if (exclusion.indexOf(def.category)===-1) {
var category = def.category.replace(" ","_");
var category = def.category.replace(/ /g,"_");
var rootCategory = category.split("-")[0];
var d = document.createElement("div");
d.id = "palette_node_"+nodeTypeId;
d.type = nt;
var label;
if (typeof def.paletteLabel === "undefined") {
label = /^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
} else {
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
var label = /^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
if (typeof def.paletteLabel !== "undefined") {
try {
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
} catch(err) {
console.log("Definition error: "+nt+".paletteLabel",err);
}
}
$('<div/>',{class:"palette_label"+(def.align=="right"?" palette_label_right":"")}).appendTo(d);
d.className="palette_node";
if (def.icon) {
var icon_url = (typeof def.icon === "function" ? def.icon.call({}) : def.icon);
var icon_url = RED.utils.getNodeIcon(def);
var iconContainer = $('<div/>',{class:"palette_icon_container"+(def.align=="right"?" palette_icon_container_right":"")}).appendTo(d);
$('<div/>',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer);
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
}
d.style.backgroundColor = def.color;
@@ -147,7 +169,12 @@ RED.palette = (function() {
}
if ($("#palette-base-category-"+rootCategory).length === 0) {
createCategoryContainer(rootCategory);
if(coreCategories.indexOf(rootCategory) !== -1){
createCategoryContainer(rootCategory, RED._("node-red:palette.label."+rootCategory, {defaultValue:rootCategory}));
} else {
var ns = def.set.id;
createCategoryContainer(rootCategory, RED._(ns+":palette.label."+rootCategory, {defaultValue:rootCategory}));
}
}
$("#palette-container-"+rootCategory).show();
@@ -158,44 +185,131 @@ RED.palette = (function() {
$("#palette-"+category).append(d);
d.onmousedown = function(e) { e.preventDefault(); };
$(d).popover({
title:d.type,
placement:"right",
var popover = RED.popover.create({
target:$(d),
trigger: "hover",
delay: { show: 750, hide: 50 },
html: true,
container:'body'
width: "300px",
content: "hi",
delay: { show: 750, hide: 50 }
});
$(d).data('popover',popover);
// $(d).popover({
// title:d.type,
// placement:"right",
// trigger: "hover",
// delay: { show: 750, hide: 50 },
// html: true,
// container:'body'
// });
$(d).click(function() {
RED.view.focus();
var help = '<div class="node-help">'+($("script[data-help-name|='"+d.type+"']").html()||"")+"</div>";
$("#tab-info").html(help);
var helpText;
if (nt.indexOf("subflow:") === 0) {
helpText = marked(RED.nodes.subflow(nt.substring(8)).info||"");
} else {
helpText = $("script[data-help-name='"+d.type+"']").html()||"";
}
RED.sidebar.info.set(helpText);
});
var chart = $("#chart");
var chartOffset = chart.offset();
var chartSVG = $("#chart>svg").get(0);
var activeSpliceLink;
var mouseX;
var mouseY;
var spliceTimer;
$(d).draggable({
helper: 'clone',
appendTo: 'body',
revert: true,
revertDuration: 50,
start: function() {RED.view.focus();}
containment:'#main-container',
start: function() {RED.view.focus();},
stop: function() { d3.select('.link_splice').classed('link_splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}},
drag: function(e,ui) {
// TODO: this is the margin-left of palette node. Hard coding
// it here makes me sad
//console.log(ui.helper.position());
ui.position.left += 17.5;
if (def.inputs > 0 && def.outputs > 0) {
mouseX = ui.position.left+(ui.helper.width()/2) - chartOffset.left + chart.scrollLeft();
mouseY = ui.position.top+(ui.helper.height()/2) - chartOffset.top + chart.scrollTop();
if (!spliceTimer) {
spliceTimer = setTimeout(function() {
var nodes = [];
var bestDistance = Infinity;
var bestLink = null;
if (chartSVG.getIntersectionList) {
var svgRect = chartSVG.createSVGRect();
svgRect.x = mouseX;
svgRect.y = mouseY;
svgRect.width = 1;
svgRect.height = 1;
nodes = chartSVG.getIntersectionList(svgRect,chartSVG);
mouseX /= RED.view.scale();
mouseY /= RED.view.scale();
} else {
// Firefox doesn't do getIntersectionList and that
// makes us sad
mouseX /= RED.view.scale();
mouseY /= RED.view.scale();
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
}
for (var i=0;i<nodes.length;i++) {
if (d3.select(nodes[i]).classed('link_background')) {
var length = nodes[i].getTotalLength();
for (var j=0;j<length;j+=10) {
var p = nodes[i].getPointAtLength(j);
var d2 = ((p.x-mouseX)*(p.x-mouseX))+((p.y-mouseY)*(p.y-mouseY));
if (d2 < 200 && d2 < bestDistance) {
bestDistance = d2;
bestLink = nodes[i];
}
}
}
}
if (activeSpliceLink && activeSpliceLink !== bestLink) {
d3.select(activeSpliceLink.parentNode).classed('link_splice',false);
}
if (bestLink) {
d3.select(bestLink.parentNode).classed('link_splice',true)
} else {
d3.select('.link_splice').classed('link_splice',false);
}
if (activeSpliceLink !== bestLink) {
if (bestLink) {
$(ui.helper).data('splice',d3.select(bestLink).data()[0]);
} else {
$(ui.helper).removeData('splice');
}
}
activeSpliceLink = bestLink;
spliceTimer = null;
},200);
}
}
}
});
var nodeInfo = null;
if (def.category == "subflows") {
$(d).dblclick(function(e) {
RED.workspaces.show(nt.substring(8));
e.preventDefault();
});
nodeInfo = marked(def.info||"");
}
setLabel(nt,$(d),label,nodeInfo);
setLabel(nt,$(d),label);
var categoryNode = $("#palette-container-"+category);
if (categoryNode.find(".palette_node").length === 1) {
if (!categoryNode.find("i").hasClass("expanded")) {
categoryNode.find(".palette-content").slideToggle();
categoryNode.find("i").toggleClass("expanded");
}
categoryContainers[category].open();
}
}
}
@@ -242,20 +356,13 @@ RED.palette = (function() {
} else if (portOutput.length !== 0 && sf.out.length === 0) {
portOutput.remove();
}
setLabel(sf.type+":"+sf.id,paletteNode,sf.name);
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||""));
});
}
function filterChange() {
var val = $("#palette-search-input").val();
if (val === "") {
$("#palette-search-clear").hide();
} else {
$("#palette-search-clear").show();
}
var re = new RegExp(val,'i');
$(".palette_node").each(function(i,el) {
function filterChange(val) {
var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i');
$("#palette-container .palette_node").each(function(i,el) {
var currentLabel = $(el).find(".palette_label").text();
if (val === "" || re.test(el.id) || re.test(currentLabel)) {
$(this).show();
@@ -263,39 +370,101 @@ RED.palette = (function() {
$(this).hide();
}
});
for (var category in categoryContainers) {
if (categoryContainers.hasOwnProperty(category)) {
if (categoryContainers[category].container
.find(".palette_node")
.filter(function() { return $(this).css('display') !== 'none'}).length === 0) {
categoryContainers[category].close();
} else {
categoryContainers[category].open();
}
}
}
}
function init() {
$(".palette-spinner").show();
RED.events.on('registry:node-type-added', function(nodeType) {
var def = RED.nodes.getType(nodeType);
addNodeType(nodeType,def);
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
def.onpaletteadd.call(def);
}
});
RED.events.on('registry:node-type-removed', function(nodeType) {
removeNodeType(nodeType);
});
RED.events.on('registry:node-set-enabled', function(nodeSet) {
for (var j=0;j<nodeSet.types.length;j++) {
showNodeType(nodeSet.types[j]);
var def = RED.nodes.getType(nodeSet.types[j]);
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
def.onpaletteadd.call(def);
}
}
});
RED.events.on('registry:node-set-disabled', function(nodeSet) {
for (var j=0;j<nodeSet.types.length;j++) {
hideNodeType(nodeSet.types[j]);
var def = RED.nodes.getType(nodeSet.types[j]);
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
def.onpaletteremove.call(def);
}
}
});
RED.events.on('registry:node-set-removed', function(nodeSet) {
if (nodeSet.added) {
for (var j=0;j<nodeSet.types.length;j++) {
removeNodeType(nodeSet.types[j]);
var def = RED.nodes.getType(nodeSet.types[j]);
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
def.onpaletteremove.call(def);
}
}
}
});
$("#palette > .palette-spinner").show();
$("#palette-search input").searchBox({
delay: 100,
change: function() {
filterChange($(this).val());
}
})
var categoryList = coreCategories;
if (RED.settings.paletteCategories) {
RED.settings.paletteCategories.forEach(createCategoryContainer);
} else {
core.forEach(createCategoryContainer);
categoryList = RED.settings.paletteCategories;
} else if (RED.settings.theme('palette.categories')) {
categoryList = RED.settings.theme('palette.categories');
}
$("#palette-search-input").focus(function(e) {
RED.keyboard.disable();
if (!Array.isArray(categoryList)) {
categoryList = coreCategories
}
categoryList.forEach(function(category){
createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category}));
});
$("#palette-search-input").blur(function(e) {
RED.keyboard.enable();
});
$("#palette-search-clear").on("click",function(e) {
$("#palette-collapse-all").on("click", function(e) {
e.preventDefault();
$("#palette-search-input").val("");
filterChange();
$("#palette-search-input").focus();
for (var cat in categoryContainers) {
if (categoryContainers.hasOwnProperty(cat)) {
categoryContainers[cat].close();
}
}
});
$("#palette-search-input").val("");
$("#palette-search-input").on("keyup",function() {
filterChange();
});
$("#palette-search-input").on("focus",function() {
$("body").one("mousedown",function() {
$("#palette-search-input").blur();
});
$("#palette-expand-all").on("click", function(e) {
e.preventDefault();
for (var cat in categoryContainers) {
if (categoryContainers.hasOwnProperty(cat)) {
categoryContainers[cat].open();
}
}
});
}

286
editor/js/ui/search.js Normal file
View File

@@ -0,0 +1,286 @@
/**
* 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.search = (function() {
var disabled = false;
var dialog = null;
var searchInput;
var searchResults;
var selected = -1;
var visible = false;
var index = {};
var keys = [];
var results = [];
function indexNode(n) {
var l = RED.utils.getNodeLabel(n);
if (l) {
l = (""+l).toLowerCase();
index[l] = index[l] || {};
index[l][n.id] = {node:n,label:l}
}
l = l||n.label||n.name||n.id||"";
var properties = ['id','type','name','label','info'];
if (n._def && n._def.defaults) {
properties = properties.concat(Object.keys(n._def.defaults));
}
for (var i=0;i<properties.length;i++) {
if (n.hasOwnProperty(properties[i])) {
var v = n[properties[i]];
if (typeof v === 'string' || typeof v === 'number') {
v = (""+v).toLowerCase();
index[v] = index[v] || {};
index[v][n.id] = {node:n,label:l};
}
}
}
}
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 search(val) {
searchResults.editableList('empty');
selected = -1;
results = [];
if (val.length > 0) {
val = val.toLowerCase();
var i;
var j;
var list = [];
var nodes = {};
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];
nodes[node.node.id] = nodes[node.node.id] = node;
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
}
}
}
list = Object.keys(nodes);
list.sort(function(A,B) {
return nodes[A].index - nodes[B].index;
});
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])
}
} else {
searchResults.editableList('addItem',{});
}
}
}
function ensureSelectedIsVisible() {
var selectedEntry = searchResults.find("li.selected");
if (selectedEntry.length === 1) {
var scrollWindow = searchResults.parent();
var scrollHeight = scrollWindow.height();
var scrollOffset = scrollWindow.scrollTop();
var y = selectedEntry.position().top;
var h = selectedEntry.height();
if (y+h > scrollHeight) {
scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-10)},50);
} else if (y<0) {
scrollWindow.animate({scrollTop: '+='+(y-10)},50);
}
}
}
function createDialog() {
dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#main-container");
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.searchInput">').appendTo(searchDiv).searchBox({
delay: 200,
change: function() {
search($(this).val());
}
});
searchInput.on('keydown',function(evt) {
var children;
if (results.length > 0) {
if (evt.keyCode === 40) {
// Down
children = searchResults.children();
if (selected < children.length-1) {
if (selected > -1) {
$(children[selected]).removeClass('selected');
}
selected++;
}
$(children[selected]).addClass('selected');
ensureSelectedIsVisible();
evt.preventDefault();
} else if (evt.keyCode === 38) {
// Up
children = searchResults.children();
if (selected > 0) {
if (selected < children.length) {
$(children[selected]).removeClass('selected');
}
selected--;
}
$(children[selected]).addClass('selected');
ensureSelectedIsVisible();
evt.preventDefault();
} else if (evt.keyCode === 13) {
// Enter
if (results.length > 0) {
reveal(results[Math.max(0,selected)].node);
}
}
}
});
searchInput.i18n();
var searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog);
searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;"}).appendTo(searchResultsDiv).editableList({
addButton: false,
addItem: function(container,i,object) {
var node = object.node;
if (node === undefined) {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
} else {
var def = node._def;
var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
var colour = def.color;
var icon_url = RED.utils.getNodeIcon(def,node);
if (node.type === 'tab') {
colour = "#C0DEED";
}
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
if (node.z) {
var workspace = RED.nodes.workspace(node.z);
if (!workspace) {
workspace = RED.nodes.subflow(node.z);
workspace = "subflow:"+workspace.name;
} else {
workspace = "flow:"+workspace.label;
}
$('<div>',{class:"red-ui-search-result-node-flow"}).html(workspace).appendTo(contentDiv);
}
$('<div>',{class:"red-ui-search-result-node-label"}).html(object.label || node.id).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
div.click(function(evt) {
evt.preventDefault();
reveal(node);
});
}
},
scrollOnAdd: false
});
}
function reveal(node) {
hide();
RED.view.reveal(node.id);
}
function show() {
if (disabled) {
return;
}
if (!visible) {
RED.keyboard.add("*","escape",function(){hide()});
$("#header-shade").show();
$("#editor-shade").show();
$("#palette-shade").show();
$("#sidebar-shade").show();
$("#sidebar-separator").hide();
indexWorkspace();
if (dialog === null) {
createDialog();
}
dialog.slideDown(300);
RED.events.emit("search:open");
visible = true;
}
searchInput.focus();
}
function hide() {
if (visible) {
RED.keyboard.remove("escape");
visible = false;
$("#header-shade").hide();
$("#editor-shade").hide();
$("#palette-shade").hide();
$("#sidebar-shade").hide();
$("#sidebar-separator").show();
if (dialog !== null) {
dialog.slideUp(200,function() {
searchInput.searchBox('value','');
});
}
RED.events.emit("search:close");
}
}
function init() {
RED.actions.add("core:search",show);
RED.events.on("editor:open",function() { disabled = true; });
RED.events.on("editor:close",function() { disabled = false; });
RED.events.on("type-search:open",function() { disabled = true; });
RED.events.on("type-search:close",function() { disabled = false; });
$("#header-shade").on('mousedown',hide);
$("#editor-shade").on('mousedown',hide);
$("#palette-shade").on('mousedown',hide);
$("#sidebar-shade").on('mousedown',hide);
}
return {
init: init,
show: show,
hide: hide
};
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013, 2015 IBM Corp.
* 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.
@@ -20,25 +20,84 @@ RED.sidebar = (function() {
id:"sidebar-tabs",
onchange:function(tab) {
$("#sidebar-content").children().hide();
$("#"+tab.id).show();
$("#sidebar-footer").children().hide();
if (tab.onchange) {
tab.onchange.call(tab);
}
$(tab.wrapper).show();
if (tab.toolbar) {
$(tab.toolbar).show();
}
},
onremove: function(tab) {
$("#"+tab.id).remove();
}
$(tab.wrapper).hide();
if (tab.onremove) {
tab.onremove.call(tab);
}
},
minimumActiveTabWidth: 110
});
function addTab(title,content,closeable) {
$("#sidebar-content").append(content);
$(content).hide();
sidebar_tabs.addTab({id:"tab-"+title,label:title,closeable:closeable});
//content.style.position = "absolute";
//$('#sidebar').tabs("refresh");
var knownTabs = {
};
function addTab(title,content,closeable,visible) {
var options;
if (typeof title === "string") {
// TODO: legacy support in case anyone uses this...
options = {
id: content.id,
label: title,
name: title,
content: content,
closeable: closeable,
visible: visible
}
} else if (typeof title === "object") {
options = title;
}
options.wrapper = $('<div>',{style:"height:100%"}).appendTo("#sidebar-content")
options.wrapper.append(options.content);
options.wrapper.hide();
if (!options.enableOnEdit) {
options.shade = $('<div>',{class:"sidebar-shade hide"}).appendTo(options.wrapper);
}
if (options.toolbar) {
$("#sidebar-footer").append(options.toolbar);
$(options.toolbar).hide();
}
var id = options.id;
RED.menu.addItem("menu-item-view-menu",{
id:"menu-item-view-menu-"+options.id,
label:options.name,
onselect:function() {
showSidebar(options.id);
},
group: "sidebar-tabs"
});
knownTabs[options.id] = options;
if (options.visible !== false) {
sidebar_tabs.addTab(knownTabs[options.id]);
}
}
function removeTab(title) {
sidebar_tabs.removeTab("tab-"+title);
function removeTab(id) {
sidebar_tabs.removeTab(id);
$(knownTabs[id].wrapper).remove();
if (knownTabs[id].footer) {
knownTabs[id].footer.remove();
}
delete knownTabs[id];
RED.menu.removeItem("menu-item-view-menu-"+id);
}
var sidebarSeparator = {};
$("#sidebar-separator").draggable({
axis: "x",
@@ -50,16 +109,15 @@ RED.sidebar = (function() {
sidebarSeparator.chartWidth = $("#workspace").width();
sidebarSeparator.chartRight = winWidth-$("#workspace").width()-$("#workspace").offset().left-2;
if (!RED.menu.isSelected("menu-item-sidebar")) {
sidebarSeparator.opening = true;
var newChartRight = 15;
var newChartRight = 7;
$("#sidebar").addClass("closing");
$("#workspace").css("right",newChartRight);
$("#chart-zoom-controls").css("right",newChartRight+20);
$("#editor-stack").css("right",newChartRight+1);
$("#sidebar").width(0);
RED.menu.setSelected("menu-item-sidebar",true);
eventHandler.emit("resize");
RED.events.emit("sidebar:resize");
}
sidebarSeparator.width = $("#sidebar").width();
},
@@ -67,9 +125,9 @@ RED.sidebar = (function() {
var d = ui.position.left-sidebarSeparator.start;
var newSidebarWidth = sidebarSeparator.width-d;
if (sidebarSeparator.opening) {
newSidebarWidth -= 13;
newSidebarWidth -= 3;
}
if (newSidebarWidth > 150) {
if (sidebarSeparator.chartWidth+d < 200) {
ui.position.left = 200+sidebarSeparator.start-sidebarSeparator.chartWidth;
@@ -77,7 +135,7 @@ RED.sidebar = (function() {
newSidebarWidth = sidebarSeparator.width-d;
}
}
if (newSidebarWidth < 150) {
if (!sidebarSeparator.closing) {
$("#sidebar").addClass("closing");
@@ -95,11 +153,11 @@ RED.sidebar = (function() {
var newChartRight = sidebarSeparator.chartRight-d;
$("#workspace").css("right",newChartRight);
$("#chart-zoom-controls").css("right",newChartRight+20);
$("#editor-stack").css("right",newChartRight+1);
$("#sidebar").width(newSidebarWidth);
sidebar_tabs.resize();
eventHandler.emit("resize");
RED.events.emit("sidebar:resize");
},
stop:function(event,ui) {
if (sidebarSeparator.closing) {
@@ -107,16 +165,16 @@ RED.sidebar = (function() {
RED.menu.setSelected("menu-item-sidebar",false);
if ($("#sidebar").width() < 180) {
$("#sidebar").width(180);
$("#workspace").css("right",208);
$("#chart-zoom-controls").css("right",228);
$("#workspace").css("right",187);
$("#editor-stack").css("right",188);
}
}
$("#sidebar-separator").css("left","auto");
$("#sidebar-separator").css("right",($("#sidebar").width()+13)+"px");
eventHandler.emit("resize");
$("#sidebar-separator").css("right",($("#sidebar").width()+2)+"px");
RED.events.emit("sidebar:resize");
}
});
function toggleSidebar(state) {
if (!state) {
$("#main-container").addClass("sidebar-closed");
@@ -124,46 +182,40 @@ RED.sidebar = (function() {
$("#main-container").removeClass("sidebar-closed");
sidebar_tabs.resize();
}
eventHandler.emit("resize");
RED.events.emit("sidebar:resize");
}
function showSidebar(id) {
if (id) {
sidebar_tabs.activateTab("tab-"+id);
}
}
function containsTab(id) {
return sidebar_tabs.contains("tab-"+id);
}
function init () {
RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("menu-item-sidebar",!RED.menu.isSelected("menu-item-sidebar"));d3.event.preventDefault();});
showSidebar();
RED.sidebar.info.show();
// hide info bar at start if screen rather narrow...
if ($(window).width() < 600) { toggleSidebar(); }
}
var eventHandler = (function() {
var handlers = {};
return {
on: function(evt,func) {
handlers[evt] = handlers[evt]||[];
handlers[evt].push(func);
},
emit: function(evt,arg) {
if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) {
handlers[evt][i](arg);
}
}
if (!containsTab(id)) {
sidebar_tabs.addTab(knownTabs[id]);
}
sidebar_tabs.activateTab(id);
if (!RED.menu.isSelected("menu-item-sidebar")) {
RED.menu.setSelected("menu-item-sidebar",true);
}
}
})();
}
function containsTab(id) {
return sidebar_tabs.contains(id);
}
function init () {
RED.actions.add("core:toggle-sidebar",function(state){
if (state === undefined) {
RED.menu.toggleSelected("menu-item-sidebar");
} else {
toggleSidebar(state);
}
});
showSidebar();
RED.sidebar.info.init();
RED.sidebar.config.init();
// hide info bar at start if screen rather narrow...
if ($(window).width() < 600) { RED.menu.setSelected("menu-item-sidebar",false); }
}
return {
init: init,
addTab: addTab,
@@ -171,7 +223,6 @@ RED.sidebar = (function() {
show: showSidebar,
containsTab: containsTab,
toggleSidebar: toggleSidebar,
on: eventHandler.on
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013 IBM Corp.
* 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.
@@ -22,5 +22,6 @@ RED.state = {
EDITING: 5,
EXPORT: 6,
IMPORT: 7,
IMPORT_DRAGGING: 8
IMPORT_DRAGGING: 8,
QUICK_JOINING: 9
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -15,14 +15,17 @@
**/
RED.subflow = (function() {
function getSubflow() {
return RED.nodes.subflow(RED.workspaces.active());
}
function findAvailableSubflowIOPosition(subflow) {
var pos = {x:70,y:70};
function findAvailableSubflowIOPosition(subflow,isInput) {
var pos = {x:50,y:30};
if (!isInput) {
pos.x += 110;
}
for (var i=0;i<subflow.out.length+subflow.in.length;i++) {
var port;
if (i < subflow.out.length) {
@@ -37,10 +40,13 @@ RED.subflow = (function() {
}
return pos;
}
function addSubflowInput() {
var subflow = RED.nodes.subflow(RED.workspaces.active());
var position = findAvailableSubflowIOPosition(subflow);
if (subflow.in.length === 1) {
return;
}
var position = findAvailableSubflowIOPosition(subflow,true);
var newInput = {
type:"subflow",
direction:"in",
@@ -56,32 +62,51 @@ RED.subflow = (function() {
var wasDirty = RED.nodes.dirty();
var wasChanged = subflow.changed;
subflow.changed = true;
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+subflow.id) {
n.changed = true;
n.inputs = subflow.in.length;
RED.editor.updateNodeProperties(n);
}
});
var result = refresh(true);
var historyEvent = {
t:'edit',
node:subflow,
dirty:wasDirty,
changed:wasChanged,
subflow: {
inputCount: oldInCount
inputCount: oldInCount,
instances: result.instances
}
};
RED.history.push(historyEvent);
$("#workspace-subflow-add-input").toggleClass("disabled",true);
RED.view.select();
RED.nodes.dirty(true);
RED.view.redraw();
$("#workspace-subflow-input-add").addClass("active");
$("#workspace-subflow-input-remove").removeClass("active");
}
function removeSubflowInput() {
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
if (activeSubflow.in.length === 0) {
return;
}
var removedInput = activeSubflow.in[0];
var removedInputLinks = [];
RED.nodes.eachLink(function(l) {
if (l.source.type == "subflow" && l.source.z == activeSubflow.id && l.source.i == removedInput.i) {
removedInputLinks.push(l);
} else if (l.target.type == "subflow:"+activeSubflow.id) {
removedInputLinks.push(l);
}
});
removedInputLinks.forEach(function(l) { RED.nodes.removeLink(l)});
activeSubflow.in = [];
$("#workspace-subflow-input-add").removeClass("active");
$("#workspace-subflow-input-remove").addClass("active");
activeSubflow.changed = true;
return {subflowInputs: [ removedInput ], links:removedInputLinks};
}
function addSubflowOutput(id) {
var subflow = RED.nodes.subflow(RED.workspaces.active());
var position = findAvailableSubflowIOPosition(subflow);
var position = findAvailableSubflowIOPosition(subflow,false);
var newOutput = {
type:"subflow",
direction:"out",
@@ -97,94 +122,272 @@ RED.subflow = (function() {
var wasDirty = RED.nodes.dirty();
var wasChanged = subflow.changed;
subflow.changed = true;
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+subflow.id) {
n.changed = true;
n.outputs = subflow.out.length;
RED.editor.updateNodeProperties(n);
}
});
var result = refresh(true);
var historyEvent = {
t:'edit',
node:subflow,
dirty:wasDirty,
changed:wasChanged,
subflow: {
outputCount: oldOutCount
outputCount: oldOutCount,
instances: result.instances
}
};
RED.history.push(historyEvent);
RED.view.select();
RED.nodes.dirty(true);
RED.view.redraw();
$("#workspace-subflow-output .spinner-value").html(subflow.out.length);
}
function init() {
function removeSubflowOutput(removedSubflowOutputs) {
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
if (activeSubflow.out.length === 0) {
return;
}
if (typeof removedSubflowOutputs === "undefined") {
removedSubflowOutputs = [activeSubflow.out[activeSubflow.out.length-1]];
}
var removedLinks = [];
removedSubflowOutputs.sort(function(a,b) { return b.i-a.i});
for (i=0;i<removedSubflowOutputs.length;i++) {
var output = removedSubflowOutputs[i];
activeSubflow.out.splice(output.i,1);
var subflowRemovedLinks = [];
var subflowMovedLinks = [];
RED.nodes.eachLink(function(l) {
if (l.target.type == "subflow" && l.target.z == activeSubflow.id && l.target.i == output.i) {
subflowRemovedLinks.push(l);
}
if (l.source.type == "subflow:"+activeSubflow.id) {
if (l.sourcePort == output.i) {
subflowRemovedLinks.push(l);
} else if (l.sourcePort > output.i) {
subflowMovedLinks.push(l);
}
}
});
subflowRemovedLinks.forEach(function(l) { RED.nodes.removeLink(l)});
subflowMovedLinks.forEach(function(l) { l.sourcePort--; });
removedLinks = removedLinks.concat(subflowRemovedLinks);
for (var j=output.i;j<activeSubflow.out.length;j++) {
activeSubflow.out[j].i--;
activeSubflow.out[j].dirty = true;
}
}
activeSubflow.changed = true;
return {subflowOutputs: removedSubflowOutputs, links: removedLinks}
}
function refresh(markChange) {
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
refreshToolbar(activeSubflow);
var subflowInstances = [];
if (activeSubflow) {
RED.nodes.filterNodes({type:"subflow:"+activeSubflow.id}).forEach(function(n) {
subflowInstances.push({
id: n.id,
changed: n.changed
});
if (markChange) {
n.changed = true;
}
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);
});
RED.editor.validateNode(activeSubflow);
return {
instances: subflowInstances
}
}
}
function refreshToolbar(activeSubflow) {
if (activeSubflow) {
$("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0);
$("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0);
$("#workspace-subflow-output .spinner-value").html(activeSubflow.out.length);
}
}
function showWorkspaceToolbar(activeSubflow) {
var toolbar = $("#workspace-toolbar");
toolbar.empty();
$('<a class="button" id="workspace-subflow-edit" href="#" data-i18n="[append]subflow.editSubflowProperties"><i class="fa fa-pencil"></i> </a>').appendTo(toolbar);
$('<span style="margin-left: 5px;" data-i18n="subflow.input"></span> '+
'<div style="display: inline-block;" class="button-group">'+
'<a id="workspace-subflow-input-remove" class="button active" href="#">0</a>'+
'<a id="workspace-subflow-input-add" class="button" href="#">1</a>'+
'</div>').appendTo(toolbar);
$('<span style="margin-left: 5px;" data-i18n="subflow.output"></span> <div id="workspace-subflow-output" style="display: inline-block;" class="button-group spinner-group">'+
'<a id="workspace-subflow-output-remove" class="button" href="#"><i class="fa fa-minus"></i></a>'+
'<div class="spinner-value">3</div>'+
'<a id="workspace-subflow-output-add" class="button" href="#"><i class="fa fa-plus"></i></a>'+
'</div>').appendTo(toolbar);
// $('<a class="button disabled" id="workspace-subflow-add-input" href="#" data-i18n="[append]subflow.input"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
// $('<a class="button" id="workspace-subflow-add-output" href="#" data-i18n="[append]subflow.output"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
$('<a class="button" id="workspace-subflow-delete" href="#" data-i18n="[append]subflow.deleteSubflow"><i class="fa fa-trash"></i> </a>').appendTo(toolbar);
toolbar.i18n();
$("#workspace-subflow-output-remove").click(function(event) {
event.preventDefault();
var wasDirty = RED.nodes.dirty();
var wasChanged = activeSubflow.changed;
var result = removeSubflowOutput();
if (result) {
var inst = refresh(true);
RED.history.push({
t:'delete',
links:result.links,
subflowOutputs: result.subflowOutputs,
changed: wasChanged,
dirty:wasDirty,
subflow: {
instances: inst.instances
}
});
RED.view.select();
RED.nodes.dirty(true);
RED.view.redraw(true);
}
});
$("#workspace-subflow-output-add").click(function(event) {
event.preventDefault();
addSubflowOutput();
});
$("#workspace-subflow-input-add").click(function(event) {
event.preventDefault();
addSubflowInput();
});
$("#workspace-subflow-input-remove").click(function(event) {
event.preventDefault();
var wasDirty = RED.nodes.dirty();
var wasChanged = activeSubflow.changed;
activeSubflow.changed = true;
var result = removeSubflowInput();
if (result) {
var inst = refresh(true);
RED.history.push({
t:'delete',
links:result.links,
changed: wasChanged,
subflowInputs: result.subflowInputs,
dirty:wasDirty,
subflow: {
instances: inst.instances
}
});
RED.view.select();
RED.nodes.dirty(true);
RED.view.redraw(true);
}
});
$("#workspace-subflow-edit").click(function(event) {
RED.editor.editSubflow(RED.nodes.subflow(RED.workspaces.active()));
event.preventDefault();
});
$("#workspace-subflow-add-input").click(function(event) {
event.preventDefault();
if ($(this).hasClass("disabled")) {
return;
}
addSubflowInput();
});
$("#workspace-subflow-add-output").click(function(event) {
event.preventDefault();
if ($(this).hasClass("disabled")) {
return;
}
addSubflowOutput();
});
$("#workspace-subflow-delete").click(function(event) {
event.preventDefault();
var removedNodes = [];
var removedLinks = [];
var startDirty = RED.nodes.dirty();
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+getSubflow().id) {
removedNodes.push(n);
}
if (n.z == getSubflow().id) {
removedNodes.push(n);
}
});
for (var i=0;i<removedNodes.length;i++) {
var rmlinks = RED.nodes.remove(removedNodes[i].id);
removedLinks = removedLinks.concat(rmlinks);
}
var activeSubflow = getSubflow();
RED.nodes.removeSubflow(activeSubflow);
RED.history.push({
t:'delete',
nodes:removedNodes,
links:removedLinks,
subflow: activeSubflow,
dirty:startDirty
});
RED.workspaces.remove(activeSubflow);
RED.nodes.dirty(true);
RED.view.redraw();
var historyEvent = removeSubflow(RED.workspaces.active());
historyEvent.t = 'delete';
historyEvent.dirty = startDirty;
RED.history.push(historyEvent);
});
RED.view.on("selection-changed",function(selection) {
refreshToolbar(activeSubflow);
$("#chart").css({"margin-top": "40px"});
$("#workspace-toolbar").show();
}
function hideWorkspaceToolbar() {
$("#workspace-toolbar").hide().empty();
$("#chart").css({"margin-top": "0"});
}
function removeSubflow(id) {
var removedNodes = [];
var removedLinks = [];
var activeSubflow = RED.nodes.subflow(id);
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+activeSubflow.id) {
removedNodes.push(n);
}
if (n.z == activeSubflow.id) {
removedNodes.push(n);
}
});
RED.nodes.eachConfig(function(n) {
if (n.z == activeSubflow.id) {
removedNodes.push(n);
}
});
var removedConfigNodes = [];
for (var i=0;i<removedNodes.length;i++) {
var removedEntities = RED.nodes.remove(removedNodes[i].id);
removedLinks = removedLinks.concat(removedEntities.links);
removedConfigNodes = removedConfigNodes.concat(removedEntities.nodes);
}
// TODO: this whole delete logic should be in RED.nodes.removeSubflow..
removedNodes = removedNodes.concat(removedConfigNodes);
RED.nodes.removeSubflow(activeSubflow);
RED.workspaces.remove(activeSubflow);
RED.nodes.dirty(true);
RED.view.redraw();
return {
nodes:removedNodes,
links:removedLinks,
subflow: {
subflow: activeSubflow
}
}
}
function init() {
RED.events.on("workspace:change",function(event) {
var activeSubflow = RED.nodes.subflow(event.workspace);
if (activeSubflow) {
showWorkspaceToolbar(activeSubflow);
} else {
hideWorkspaceToolbar();
}
});
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-subflow-convert",true);
} else {
RED.menu.setDisabled("menu-item-subflow-convert",false);
}
});
RED.actions.add("core:create-subflow",createSubflow);
RED.actions.add("core:convert-to-subflow",convertToSubflow);
}
function createSubflow() {
var lastIndex = 0;
RED.nodes.eachSubflow(function(sf) {
@@ -193,47 +396,53 @@ RED.subflow = (function() {
lastIndex = Math.max(lastIndex,m[1]);
}
});
var name = "Subflow "+(lastIndex+1);
var subflowId = RED.nodes.id();
var subflow = {
type:"subflow",
id:subflowId,
name:name,
info:"",
in: [],
out: []
};
RED.nodes.addSubflow(subflow);
RED.history.push({
t:'createSubflow',
subflow: subflow,
subflow: {
subflow:subflow
},
dirty:RED.nodes.dirty()
});
RED.workspaces.show(subflowId);
RED.nodes.dirty(true);
}
function convertToSubflow() {
var selection = RED.view.selection();
if (!selection.nodes) {
RED.notify("<strong>Cannot create subflow</strong>: no nodes selected","error");
RED.notify(RED._("subflow.errors.noNodesSelected"),"error");
return;
}
var i;
var i,n;
var nodes = {};
var new_links = [];
var removedLinks = [];
var candidateInputs = [];
var candidateOutputs = [];
var candidateInputNodes = {};
var boundingBox = [selection.nodes[0].x,
selection.nodes[0].y,
selection.nodes[0].x,
selection.nodes[0].y];
for (i=0;i<selection.nodes.length;i++) {
var n = selection.nodes[i];
n = selection.nodes[i];
nodes[n.id] = {n:n,outputs:{}};
boundingBox = [
Math.min(boundingBox[0],n.x),
@@ -242,14 +451,14 @@ RED.subflow = (function() {
Math.max(boundingBox[3],n.y)
]
}
var center = [(boundingBox[2]+boundingBox[0]) / 2,(boundingBox[3]+boundingBox[1]) / 2];
RED.nodes.eachLink(function(link) {
if (nodes[link.source.id] && nodes[link.target.id]) {
// A link wholely within the selection
}
if (nodes[link.source.id] && !nodes[link.target.id]) {
// An outbound link from the selection
candidateOutputs.push(link);
@@ -258,10 +467,11 @@ RED.subflow = (function() {
if (!nodes[link.source.id] && nodes[link.target.id]) {
// An inbound link
candidateInputs.push(link);
candidateInputNodes[link.target.id] = link.target;
removedLinks.push(link);
}
});
var outputs = {};
candidateOutputs = candidateOutputs.filter(function(v) {
if (outputs[v.source.id+":"+v.sourcePort]) {
@@ -274,17 +484,12 @@ RED.subflow = (function() {
return true;
});
candidateOutputs.sort(function(a,b) { return a.source.y-b.source.y});
if (candidateInputs.length > 1) {
RED.notify("<strong>Cannot create subflow</strong>: multiple inputs to selection","error");
if (Object.keys(candidateInputNodes).length > 1) {
RED.notify(RED._("subflow.errors.multipleInputsToSelection"),"error");
return;
}
//if (candidateInputs.length == 0) {
// RED.notify("<strong>Cannot create subflow</strong>: no input to selection","error");
// return;
//}
var lastIndex = 0;
RED.nodes.eachSubflow(function(sf) {
var m = (new RegExp("^Subflow (\\d+)$")).exec(sf.name);
@@ -292,23 +497,24 @@ RED.subflow = (function() {
lastIndex = Math.max(lastIndex,m[1]);
}
});
var name = "Subflow "+(lastIndex+1);
var subflowId = RED.nodes.id();
var subflow = {
type:"subflow",
id:subflowId,
name:name,
in: candidateInputs.map(function(v,i) { var index = i; return {
info:"",
in: Object.keys(candidateInputNodes).map(function(v,i) { var index = i; return {
type:"subflow",
direction:"in",
x:v.target.x-(v.target.w/2)-80,
y:v.target.y,
x:candidateInputNodes[v].x-(candidateInputNodes[v].w/2)-80,
y:candidateInputNodes[v].y,
z:subflowId,
i:index,
id:RED.nodes.id(),
wires:[{id:v.target.id}]
wires:[{id:candidateInputNodes[v].id}]
}}),
out: candidateOutputs.map(function(v,i) { var index = i; return {
type:"subflow",
@@ -321,8 +527,9 @@ RED.subflow = (function() {
wires:[{id:v.source.id,port:v.sourcePort}]
}})
};
RED.nodes.addSubflow(subflow);
var subflowInstance = {
id:RED.nodes.id(),
type:"subflow:"+subflow.id,
@@ -337,13 +544,13 @@ RED.subflow = (function() {
subflowInstance._def = RED.nodes.getType(subflowInstance.type);
RED.editor.validateNode(subflowInstance);
RED.nodes.add(subflowInstance);
candidateInputs.forEach(function(l) {
var link = {source:l.source, sourcePort:l.sourcePort, target: subflowInstance};
new_links.push(link);
RED.nodes.addLink(link);
});
candidateOutputs.forEach(function(output,i) {
output.targets.forEach(function(target) {
var link = {source:subflowInstance, sourcePort:i, target: target};
@@ -351,7 +558,7 @@ RED.subflow = (function() {
RED.nodes.addLink(link);
});
});
subflow.in.forEach(function(input) {
input.wires.forEach(function(wire) {
var link = {source: input, sourcePort: 0, target: RED.nodes.node(wire.id) }
@@ -366,37 +573,59 @@ RED.subflow = (function() {
RED.nodes.addLink(link);
});
});
for (i=0;i<removedLinks.length;i++) {
RED.nodes.removeLink(removedLinks[i]);
}
for (i=0;i<selection.nodes.length;i++) {
selection.nodes[i].z = subflow.id;
n = selection.nodes[i];
if (/^link /.test(n.type)) {
n.links = n.links.filter(function(id) {
var isLocalLink = nodes.hasOwnProperty(id);
if (!isLocalLink) {
var otherNode = RED.nodes.node(id);
if (otherNode && otherNode.links) {
var i = otherNode.links.indexOf(n.id);
if (i > -1) {
otherNode.links.splice(i,1);
}
}
}
return isLocalLink;
});
}
n.z = subflow.id;
}
RED.history.push({
t:'createSubflow',
nodes:[subflowInstance.id],
links:new_links,
subflow: subflow,
subflow: {
subflow: subflow
},
activeWorkspace: RED.workspaces.active(),
removedLinks: removedLinks,
dirty:RED.nodes.dirty()
});
RED.view.select(null);
RED.editor.validateNode(subflow);
RED.nodes.dirty(true);
RED.view.redraw(true);
}
return {
init: init,
createSubflow: createSubflow,
convertToSubflow: convertToSubflow
convertToSubflow: convertToSubflow,
removeSubflow: removeSubflow,
refresh: refresh,
removeInput: removeSubflowInput,
removeOutput: removeSubflowOutput
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013 IBM Corp.
* 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.
@@ -14,71 +14,302 @@
* limitations under the License.
**/
RED.sidebar.config = (function() {
var content = document.createElement("div");
content.id = "tab-config";
content.style.paddingTop = "4px";
content.style.paddingLeft = "4px";
content.style.paddingRight = "4px";
var list = $("<ul>",{class:"tab-config-list"}).appendTo(content);
function show() {
if (!RED.sidebar.containsTab("config")) {
RED.sidebar.addTab("config",content,true);
content.className = "sidebar-node-config";
$('<div class="button-group sidebar-header">'+
'<a class="sidebar-header-button-toggle selected" id="workspace-config-node-filter-all" href="#"><span data-i18n="sidebar.config.filterAll"></span></a>'+
'<a class="sidebar-header-button-toggle" id="workspace-config-node-filter-unused" href="#"><span data-i18n="sidebar.config.filterUnused"></span></a> '+
'</div>'
).appendTo(content);
var toolbar = $('<div>'+
'<a class="sidebar-footer-button" id="workspace-config-node-collapse-all" href="#"><i class="fa fa-angle-double-up"></i></a> '+
'<a class="sidebar-footer-button" id="workspace-config-node-expand-all" href="#"><i class="fa fa-angle-double-down"></i></a>'+
'</div>');
var globalCategories = $("<div>").appendTo(content);
var flowCategories = $("<div>").appendTo(content);
var subflowCategories = $("<div>").appendTo(content);
var showUnusedOnly = false;
var categories = {};
function getOrCreateCategory(name,parent,label) {
name = name.replace(/\./i,"-");
if (!categories[name]) {
var container = $('<div class="palette-category workspace-config-node-category" id="workspace-config-node-category-'+name+'"></div>').appendTo(parent);
var header = $('<div class="workspace-config-node-tray-header palette-header"><i class="fa fa-angle-down expanded"></i></div>').appendTo(container);
if (label) {
$('<span class="config-node-label"/>').text(label).appendTo(header);
} else {
$('<span class="config-node-label" data-i18n="sidebar.config.'+name+'">').appendTo(header);
}
$('<span class="config-node-filter-info"></span>').appendTo(header);
category = $('<ul class="palette-content config-node-list"></ul>').appendTo(container);
container.i18n();
var icon = header.find("i");
var result = {
label: label,
list: category,
size: function() {
return result.list.find("li:not(.config_node_none)").length
},
open: function(snap) {
if (!icon.hasClass("expanded")) {
icon.addClass("expanded");
if (snap) {
result.list.show();
} else {
result.list.slideDown();
}
}
},
close: function(snap) {
if (icon.hasClass("expanded")) {
icon.removeClass("expanded");
if (snap) {
result.list.hide();
} else {
result.list.slideUp();
}
}
},
isOpen: function() {
return icon.hasClass("expanded");
}
};
header.on('click', function(e) {
if (result.isOpen()) {
result.close();
} else {
result.open();
}
});
categories[name] = result;
} else {
if (categories[name].label !== label) {
categories[name].list.parent().find('.config-node-label').text(label);
categories[name].label = label;
}
}
return categories[name];
}
function createConfigNodeList(id,nodes) {
var category = getOrCreateCategory(id.replace(/\./i,"-"))
var list = category.list;
nodes.sort(function(A,B) {
if (A.type < B.type) { return -1;}
if (A.type > B.type) { return 1;}
return 0;
});
if (showUnusedOnly) {
var hiddenCount = nodes.length;
nodes = nodes.filter(function(n) {
return n._def.hasUsers!==false && n.users.length === 0;
})
hiddenCount = hiddenCount - nodes.length;
if (hiddenCount > 0) {
list.parent().find('.config-node-filter-info').text(RED._('sidebar.config.filtered',{count:hiddenCount})).show();
} else {
list.parent().find('.config-node-filter-info').hide();
}
} else {
list.parent().find('.config-node-filter-info').hide();
}
list.empty();
if (nodes.length === 0) {
$('<li class="config_node_none" data-i18n="sidebar.config.none">NONE</li>').i18n().appendTo(list);
category.close(true);
} else {
var currentType = "";
nodes.forEach(function(node) {
var label = RED.utils.getNodeLabel(node,node.id);
if (node.type != currentType) {
$('<li class="config_node_type">'+node.type+'</li>').appendTo(list);
currentType = node.type;
}
var entry = $('<li class="palette_node config_node palette_node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list);
$('<div class="palette_label"></div>').text(label).appendTo(entry);
if (node._def.hasUsers !== false) {
var iconContainer = $('<div/>',{class:"palette_icon_container palette_icon_container_right"}).text(node.users.length).appendTo(entry);
if (node.users.length === 0) {
entry.addClass("config_node_unused");
}
}
entry.on('click',function(e) {
RED.sidebar.info.refresh(node);
});
entry.on('dblclick',function(e) {
RED.editor.editConfig("", node.type, node.id);
});
var userArray = node.users.map(function(n) { return n.id });
entry.on('mouseover',function(e) {
RED.nodes.eachNode(function(node) {
if( userArray.indexOf(node.id) != -1) {
node.highlighted = true;
node.dirty = true;
}
});
RED.view.redraw();
});
entry.on('mouseout',function(e) {
RED.nodes.eachNode(function(node) {
if(node.highlighted) {
node.highlighted = false;
node.dirty = true;
}
});
RED.view.redraw();
});
});
category.open(true);
}
}
function refreshConfigNodeList() {
var validList = {"global":true};
getOrCreateCategory("global",globalCategories);
RED.nodes.eachWorkspace(function(ws) {
validList[ws.id.replace(/\./g,"-")] = true;
getOrCreateCategory(ws.id,flowCategories,ws.label);
})
RED.nodes.eachSubflow(function(sf) {
validList[sf.id.replace(/\./g,"-")] = true;
getOrCreateCategory(sf.id,subflowCategories,sf.name);
})
$(".workspace-config-node-category").each(function() {
var id = $(this).attr('id').substring("workspace-config-node-category-".length);
if (!validList[id]) {
$(this).remove();
delete categories[id];
}
})
var globalConfigNodes = [];
var configList = {};
RED.nodes.eachConfig(function(cn) {
if (cn.z) {//} == RED.workspaces.active()) {
configList[cn.z.replace(/\./g,"-")] = configList[cn.z.replace(/\./g,"-")]||[];
configList[cn.z.replace(/\./g,"-")].push(cn);
} else if (!cn.z) {
globalConfigNodes.push(cn);
}
});
for (var id in validList) {
if (validList.hasOwnProperty(id)) {
createConfigNodeList(id,configList[id]||[]);
}
}
createConfigNodeList('global',globalConfigNodes);
}
function init() {
RED.sidebar.addTab({
id: "config",
label: RED._("sidebar.config.label"),
name: RED._("sidebar.config.name"),
content: content,
toolbar: toolbar,
closeable: true,
visible: false,
onchange: function() { refreshConfigNodeList(); }
});
RED.actions.add("core:show-config-tab",function() {RED.sidebar.show('config')});
$("#workspace-config-node-collapse-all").on("click", function(e) {
e.preventDefault();
for (var cat in categories) {
if (categories.hasOwnProperty(cat)) {
categories[cat].close();
}
}
});
$("#workspace-config-node-expand-all").on("click", function(e) {
e.preventDefault();
for (var cat in categories) {
if (categories.hasOwnProperty(cat)) {
if (categories[cat].size() > 0) {
categories[cat].open();
}
}
}
});
$('#workspace-config-node-filter-all').on("click",function(e) {
e.preventDefault();
if (showUnusedOnly) {
$(this).addClass('selected');
$('#workspace-config-node-filter-unused').removeClass('selected');
showUnusedOnly = !showUnusedOnly;
refreshConfigNodeList();
}
});
$('#workspace-config-node-filter-unused').on("click",function(e) {
e.preventDefault();
if (!showUnusedOnly) {
$(this).addClass('selected');
$('#workspace-config-node-filter-all').removeClass('selected');
showUnusedOnly = !showUnusedOnly;
refreshConfigNodeList();
}
});
}
function show(id) {
if (typeof id === 'boolean') {
if (id) {
$('#workspace-config-node-filter-unused').click();
} else {
$('#workspace-config-node-filter-all').click();
}
}
refreshConfigNodeList();
if (typeof id === "string") {
$('#workspace-config-node-filter-all').click();
id = id.replace(/\./g,"-");
setTimeout(function() {
var node = $(".palette_node_id_"+id);
var y = node.position().top;
var h = node.height();
var scrollWindow = $(".sidebar-node-config");
var scrollHeight = scrollWindow.height();
if (y+h > scrollHeight) {
scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-30)},150);
} else if (y<0) {
scrollWindow.animate({scrollTop: '+='+(y-10)},150);
}
var flash = 21;
var flashFunc = function() {
if ((flash%2)===0) {
node.removeClass('node_highlighted');
} else {
node.addClass('node_highlighted');
}
flash--;
if (flash >= 0) {
setTimeout(flashFunc,100);
}
}
flashFunc();
},100);
}
refresh();
RED.sidebar.show("config");
}
function refresh() {
list.empty();
RED.nodes.eachConfig(function(node) {
var li = list.find("#tab-config-list-type-"+node.type);
if (li.length === 0) {
li = $("<li>",{id:"tab-config-list-type-"+node.type}).appendTo(list);
$('<div class="tab-config-list-type">'+node.type+'</div>').appendTo(li);
}
var label = "";
if (typeof node._def.label == "function") {
label = node._def.label.call(node);
} else {
label = node._def.label;
}
label = label || "&nbsp;";
var entry = $('<div class="tab-config-list-entry"></div>').appendTo(li);
entry.on('dblclick',function(e) {
RED.editor.editConfig("", node.type, node.id);
});
var userArray = node.users.map(function(n) { return n.id });
entry.on('mouseover',function(e) {
RED.nodes.eachNode(function(node) {
if( userArray.indexOf(node.id) != -1) {
node.highlighted = true;
node.dirty = true;
}
});
RED.view.redraw();
});
entry.on('mouseout',function(e) {
RED.nodes.eachNode(function(node) {
if(node.highlighted) {
node.highlighted = false;
node.dirty = true;
}
});
RED.view.redraw();
});
$('<div class="tab-config-list-label">'+label+'</div>').appendTo(entry);
$('<div class="tab-config-list-users">'+node.users.length+'</div>').appendTo(entry);
});
}
return {
init:init,
show:show,
refresh:refresh
refresh:refreshConfigNodeList
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013, 2015 IBM Corp.
* 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.
@@ -26,18 +26,73 @@ RED.sidebar.info = (function() {
smartypants: false
});
var content = document.createElement("div");
content.id = "tab-info";
content.style.paddingTop = "4px";
content.style.paddingLeft = "4px";
content.style.paddingRight = "4px";
var content;
var sections;
var nodeSection;
var infoSection;
var tipBox;
var propertiesExpanded = false;
function show() {
if (!RED.sidebar.containsTab("info")) {
RED.sidebar.addTab("info",content,false);
var expandedSections = {
"property": false
};
function init() {
content = document.createElement("div");
content.className = "sidebar-node-info"
RED.actions.add("core:show-info-tab",show);
var stackContainer = $("<div>",{class:"sidebar-node-info-stack"}).appendTo(content);
sections = RED.stack.create({
container: stackContainer
}).hide();
nodeSection = sections.add({
title: RED._("sidebar.info.node"),
collapsible: false
});
infoSection = sections.add({
title: RED._("sidebar.info.information"),
collapsible: false
});
infoSection.content.css("padding","6px");
infoSection.container.css("border-bottom","none");
var tipContainer = $('<div class="node-info-tips"></div>').appendTo(content);
tipBox = $('<div class="node-info-tip"></div>').appendTo(tipContainer);
var tipButtons = $('<div class="node-info-tips-buttons"></div>').appendTo(tipContainer);
var tipRefresh = $('<a href="#" class="workspace-footer-button"><i class="fa fa-refresh"></a>').appendTo(tipButtons);
tipRefresh.click(function(e) {
e.preventDefault();
tips.next();
})
var tipClose = $('<a href="#" class="workspace-footer-button"><i class="fa fa-times"></a>').appendTo(tipButtons);
tipClose.click(function(e) {
e.preventDefault();
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"),
content: content,
enableOnEdit: true
});
if (tips.enabled()) {
tips.start();
} else {
tips.stop();
}
}
function show() {
RED.sidebar.show("info");
}
@@ -58,112 +113,251 @@ RED.sidebar.info = (function() {
return value;
}
function refresh(node) {
var table = '<table class="node-info"><tbody>';
table += '<tr class="blank"><td colspan="2">Node</td></tr>';
if (node.type != "subflow" && node.name) {
table += "<tr><td>Name</td><td>&nbsp;"+node.name+"</td></tr>";
}
table += "<tr><td>Type</td><td>&nbsp;"+node.type+"</td></tr>";
table += "<tr><td>ID</td><td>&nbsp;"+node.id+"</td></tr>";
var m = /^subflow(:(.+))?$/.exec(node.type);
if (m) {
var subflowNode;
if (m[2]) {
subflowNode = RED.nodes.subflow(m[2]);
} else {
subflowNode = node;
function addTargetToExternalLinks(el) {
$(el).find("a").each(function(el) {
var href = $(this).attr('href');
if (/^https?:/.test(href)) {
$(this).attr('target','_blank');
}
table += '<tr class="blank"><td colspan="2">Subflow</td></tr>';
var userCount = 0;
var subflowType = "subflow:"+subflowNode.id;
RED.nodes.eachNode(function(n) {
if (n.type === subflowType) {
userCount++;
}
});
table += "<tr><td>name</td><td>"+subflowNode.name+"</td></tr>";
table += "<tr><td>instances</td><td>"+userCount+"</td></tr>";
}
if (!m && node.type != "subflow" && node.type != "comment") {
table += '<tr class="blank"><td colspan="2"><a href="#" class="node-info-property-header"><i style="width: 10px; text-align: center;" class="fa fa-caret-'+(propertiesExpanded?"down":"right")+'"></i> Properties</a></td></tr>';
if (node._def) {
for (var n in node._def.defaults) {
if (n != "name" && node._def.defaults.hasOwnProperty(n)) {
var val = node[n]||"";
var type = typeof val;
if (type === "string") {
if (val.length === 0) {
val += '<span style="font-style: italic; color: #ccc;">blank</span>';
} else {
if (val.length > 30) {
val = val.substring(0,30)+" ...";
});
return el;
}
function refresh(node) {
sections.show();
$(nodeSection.content).empty();
$(infoSection.content).empty();
var table = $('<table class="node-info"></table>');
var tableBody = $('<tbody>').appendTo(table);
var propRow;
var subflowNode;
if (node.type === "tab") {
nodeSection.title.html(RED._("sidebar.info.flow"));
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.tabName")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).html('&nbsp;'+(node.label||""))
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.id")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).html((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
} else {
nodeSection.title.html(RED._("sidebar.info.node"));
if (node.type !== "subflow" && node.name) {
$('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td>&nbsp;<span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody);
}
$('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td>&nbsp;"+node.type+"</td></tr>").appendTo(tableBody);
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.id")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
var m = /^subflow(:(.+))?$/.exec(node.type);
if (!m && node.type != "subflow" && node.type != "comment") {
if (node._def) {
var count = 0;
var defaults = node._def.defaults;
for (var n in defaults) {
if (n != "name" && defaults.hasOwnProperty(n)) {
var val = node[n];
var type = typeof val;
count++;
propRow = $('<tr class="node-info-property-row'+(expandedSections.property?"":" hide")+'"><td>'+n+"</td><td></td></tr>").appendTo(tableBody);
if (defaults[n].type) {
var configNode = RED.nodes.node(val);
if (!configNode) {
RED.utils.createObjectElement(undefined).appendTo(propRow.children()[1]);
} else {
var configLabel = RED.utils.getNodeLabel(configNode,val);
var container = propRow.children()[1];
var div = $('<span>',{class:""}).appendTo(container);
var nodeDiv = $('<div>',{class:"palette_node palette_node_small"}).appendTo(div);
var colour = configNode._def.color;
var icon_url = RED.utils.getNodeIcon(configNode._def);
nodeDiv.css({'backgroundColor':colour, "cursor":"pointer"});
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).html(configLabel).appendTo(container);
nodeDiv.on('dblclick',function() {
RED.editor.editConfig("", configNode.type, configNode.id);
})
}
val = val.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
} else {
RED.utils.createObjectElement(val).appendTo(propRow.children()[1]);
}
} else if (type === "number") {
val = val.toString();
} else if ($.isArray(val)) {
val = "[<br/>";
for (var i=0;i<Math.min(node[n].length,10);i++) {
var vv = JSON.stringify(node[n][i],jsonFilter," ").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
val += "&nbsp;"+i+": "+vv+"<br/>";
}
if (node[n].length > 10) {
val += "&nbsp;... "+node[n].length+" items<br/>";
}
val += "]";
} else {
val = JSON.stringify(val,jsonFilter," ");
val = val.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
}
table += '<tr class="node-info-property-row'+(propertiesExpanded?"":" hide")+'"><td>'+n+"</td><td>"+val+"</td></tr>";
}
if (count > 0) {
$('<tr class="node-info-property-expand blank"><td colspan="2"><a href="#" class=" node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="node-info-property-show-more">'+RED._("sidebar.info.showMore")+'</span><span class="node-info-property-show-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a></td></tr>').appendTo(tableBody);
}
}
}
}
table += "</tbody></table><hr/>";
if (node.type != "comment") {
var helpText = $("script[data-help-name|='"+node.type+"']").html()||"";
table += '<div class="node-help">'+helpText+"</div>";
}
if (node._def && node._def.info) {
var info = node._def.info;
table += '<div class="node-help">'+marked(typeof info === "function" ? info.call(node) : info)+'</div>';
//table += '<div class="node-help">'+(typeof info === "function" ? info.call(node) : info)+'</div>';
}
if (m) {
if (m[2]) {
subflowNode = RED.nodes.subflow(m[2]);
} else {
subflowNode = node;
}
$("#tab-info").html(table);
$(".node-info-property-header").click(function(e) {
var icon = $(this).find("i");
if (icon.hasClass("fa-caret-right")) {
icon.removeClass("fa-caret-right");
icon.addClass("fa-caret-down");
$(".node-info-property-row").show();
propertiesExpanded = true;
} else {
icon.addClass("fa-caret-right");
icon.removeClass("fa-caret-down");
$(".node-info-property-row").hide();
propertiesExpanded = false;
$('<tr class="blank"><th colspan="2">'+RED._("sidebar.info.subflow")+'</th></tr>').appendTo(tableBody);
var userCount = 0;
var subflowType = "subflow:"+subflowNode.id;
RED.nodes.eachNode(function(n) {
if (n.type === subflowType) {
userCount++;
}
});
$('<tr class="node-info-subflow-row"><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+subflowNode.name+'</span></td></tr>').appendTo(tableBody);
$('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+userCount+'</td></tr>').appendTo(tableBody);
}
}
$(table).appendTo(nodeSection.content);
var infoText = "";
if (!subflowNode && node.type !== "comment" && node.type !== "tab") {
var helpText = $("script[data-help-name='"+node.type+"']").html()||"";
infoText = helpText;
} else if (node.type === "tab") {
infoText = marked(node.info||"");
}
if (subflowNode) {
infoText = infoText + marked(subflowNode.info||"");
} else if (node._def && node._def.info) {
var info = node._def.info;
var textInfo = (typeof info === "function" ? info.call(node) : info);
// TODO: help
infoText = infoText + marked(textInfo);
}
if (infoText) {
setInfoText(infoText);
}
$(".node-info-property-header").click(function(e) {
e.preventDefault();
expandedSections["property"] = !expandedSections["property"];
$(this).toggleClass("expanded",expandedSections["property"]);
$(".node-info-property-row").toggle(expandedSections["property"]);
});
}
function clear() {
$("#tab-info").html("");
function setInfoText(infoText) {
var info = addTargetToExternalLinks($('<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(infoSection.content);
info.find(".bidiAware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
var foldingHeader = "H3";
info.find(foldingHeader).wrapInner('<a class="node-info-header expanded" href="#"></a>')
.find("a").prepend('<i class="fa fa-angle-right">').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);
})
}
RED.view.on("selection-changed",function(selection) {
var tips = (function() {
var enabled = true;
var startDelay = 1000;
var cycleDelay = 15000;
var startTimeout;
var refreshTimeout;
var tipCount = -1;
RED.actions.add("core:toggle-show-tips",function(state) {
if (state === undefined) {
RED.userSettings.toggle("view-show-tips");
} else {
enabled = state;
if (enabled) {
startTips();
} else {
stopTips();
}
}
});
function setTip() {
var r = Math.floor(Math.random() * tipCount);
var tip = RED._("infotips:info.tip"+r);
var m;
while ((m=/({{(.*?)}})/.exec(tip))) {
var shortcut = RED.keyboard.getShortcut(m[2]);
if (shortcut) {
tip = tip.replace(m[1],RED.keyboard.formatKey(shortcut.key));
} else {
return;
}
}
while ((m=/(\[(.*?)\])/.exec(tip))) {
tip = tip.replace(m[1],RED.keyboard.formatKey(m[2]));
}
tipBox.html(tip).fadeIn(200);
if (startTimeout) {
startTimeout = null;
refreshTimeout = setInterval(cycleTips,cycleDelay);
}
}
function cycleTips() {
tipBox.fadeOut(300,function() {
setTip();
})
}
function startTips() {
$(".sidebar-node-info").addClass('show-tips');
if (enabled) {
if (!startTimeout && !refreshTimeout) {
if (tipCount === -1) {
do {
tipCount++;
} while(RED._("infotips:info.tip"+tipCount)!=="infotips:info.tip"+tipCount);
}
startTimeout = setTimeout(setTip,startDelay);
}
}
}
function stopTips() {
$(".sidebar-node-info").removeClass('show-tips');
clearInterval(refreshTimeout);
clearTimeout(startTimeout);
refreshTimeout = null;
startTimeout = null;
}
function nextTip() {
clearInterval(refreshTimeout);
startTimeout = true;
setTip();
}
return {
start: startTips,
stop: stopTips,
next: nextTip,
enabled: function() { return enabled; }
}
})();
function clear() {
sections.hide();
//
}
function set(html) {
// tips.stop();
sections.show();
nodeSection.container.hide();
$(infoSection.content).empty();
setInfoText(html);
$(".sidebar-node-info-stack").scrollTop(0);
}
RED.events.on("view:selection-changed",function(selection) {
if (selection.nodes) {
if (selection.nodes.length == 1) {
var node = selection.nodes[0];
@@ -174,18 +368,27 @@ RED.sidebar.info = (function() {
}
}
} else {
var subflow = RED.nodes.subflow(RED.workspaces.active());
if (subflow) {
refresh(subflow);
var activeWS = RED.workspaces.active();
var flow = RED.nodes.workspace(activeWS) || RED.nodes.subflow(activeWS);
if (flow) {
refresh(flow);
} else {
clear();
var workspace = RED.nodes.workspace(RED.workspaces.active());
if (workspace && workspace.info) {
refresh(workspace);
} else {
clear();
}
}
}
});
return {
init: init,
show: show,
refresh:refresh,
clear: clear
refresh: refresh,
clear: clear,
set: set
}
})();

View File

@@ -1,134 +0,0 @@
/**
* Copyright 2013 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.tabs = (function() {
function createTabs(options) {
var tabs = {};
var ul = $("#"+options.id)
ul.addClass("red-ui-tabs");
ul.children().first().addClass("active");
ul.children().addClass("red-ui-tab");
function onTabClick() {
activateTab($(this));
return false;
}
function onTabDblClick() {
if (options.ondblclick) {
options.ondblclick(tabs[$(this).attr('href').slice(1)]);
}
return false;
}
function activateTab(link) {
if (typeof link === "string") {
link = ul.find("a[href='#"+link+"']");
}
if (!link.parent().hasClass("active")) {
ul.children().removeClass("active");
link.parent().addClass("active");
if (options.onchange) {
options.onchange(tabs[link.attr('href').slice(1)]);
}
}
}
function updateTabWidths() {
var tabs = ul.find("li.red-ui-tab");
var width = ul.width();
var tabCount = tabs.size();
var tabWidth = (width-6-(tabCount*7))/tabCount;
var pct = 100*tabWidth/width;
tabs.css({width:pct+"%"});
}
ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
updateTabWidths();
function removeTab(id) {
var li = ul.find("a[href='#"+id+"']").parent();
if (li.hasClass("active")) {
var tab = li.prev();
if (tab.size() === 0) {
tab = li.next();
}
activateTab(tab.find("a"));
}
li.remove();
if (options.onremove) {
options.onremove(tabs[id]);
}
delete tabs[id];
updateTabWidths();
}
return {
addTab: function(tab) {
tabs[tab.id] = tab;
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
link.html(tab.label);
link.on("click",onTabClick);
link.on("dblclick",onTabDblClick);
if (tab.closeable) {
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
closeLink.html('<i class="fa fa-times" />');
closeLink.on("click",function(event) {
removeTab(tab.id);
});
}
updateTabWidths();
if (options.onadd) {
options.onadd(tab);
}
link.attr("title",tab.label);
if (ul.find("li.red-ui-tab").size() == 1) {
activateTab(link);
}
},
removeTab: removeTab,
activateTab: activateTab,
resize: updateTabWidths,
count: function() {
return ul.find("li.red-ui-tab").size();
},
contains: function(id) {
return ul.find("a[href='#"+id+"']").length > 0;
},
renameTab: function(id,label) {
tabs[id].label = label;
var tab = ul.find("a[href='#"+id+"']");
tab.attr("title",label);
tab.text(label);
updateTabWidths();
}
}
}
return {
create: createTabs
}
})();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2014 IBM Corp.
* 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.

265
editor/js/ui/tray.js Normal file
View File

@@ -0,0 +1,265 @@
/**
* 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.tray = (function() {
var stack = [];
var editorStack = $("#editor-stack");
var openingTray = false;
function resize() {
}
function showTray(options) {
var el = $('<div class="editor-tray"></div>');
var header = $('<div class="editor-tray-header"></div>').appendTo(el);
var bodyWrapper = $('<div class="editor-tray-body-wrapper"></div>').appendTo(el);
var body = $('<div class="editor-tray-body"></div>').appendTo(bodyWrapper);
var footer = $('<div class="editor-tray-footer"></div>').appendTo(el);
var resizer = $('<div class="editor-tray-resize-handle"></div>').appendTo(el);
// var growButton = $('<a class="editor-tray-resize-button" style="cursor: w-resize;"><i class="fa fa-angle-left"></i></a>').appendTo(resizer);
// var shrinkButton = $('<a class="editor-tray-resize-button" style="cursor: e-resize;"><i style="margin-left: 1px;" class="fa fa-angle-right"></i></a>').appendTo(resizer);
if (options.title) {
$('<div class="editor-tray-titlebar">'+options.title+'</div>').appendTo(header);
}
if (options.width === Infinity) {
options.maximized = true;
resizer.addClass('editor-tray-resize-maximised');
}
var buttonBar = $('<div class="editor-tray-toolbar"></div>').appendTo(header);
var primaryButton;
if (options.buttons) {
for (var i=0;i<options.buttons.length;i++) {
var button = options.buttons[i];
var b = $('<button>').button().appendTo(buttonBar);
if (button.id) {
b.attr('id',button.id);
}
if (button.text) {
b.html(button.text);
}
if (button.click) {
b.click((function(action) {
return function(evt) {
if (!$(this).hasClass('disabled')) {
action(evt);
}
};
})(button.click));
}
if (button.class) {
b.addClass(button.class);
if (button.class === "primary") {
primaryButton = button;
}
}
}
}
el.appendTo(editorStack);
var tray = {
tray: el,
header: header,
body: body,
footer: footer,
options: options,
primaryButton: primaryButton
};
stack.push(tray);
if (!options.maximized) {
el.draggable({
handle: resizer,
axis: "x",
start:function(event,ui) {
el.width('auto');
},
drag: function(event,ui) {
var absolutePosition = editorStack.position().left+ui.position.left
if (absolutePosition < 7) {
ui.position.left += 7-absolutePosition;
} else if (ui.position.left > -tray.preferredWidth-1) {
ui.position.left = -Math.min(editorStack.position().left-7,tray.preferredWidth-1);
}
if (tray.options.resize) {
setTimeout(function() {
tray.options.resize({width: -ui.position.left});
},0);
}
tray.width = -ui.position.left;
},
stop:function(event,ui) {
el.width(-ui.position.left);
el.css({left:''});
if (tray.options.resize) {
tray.options.resize({width: -ui.position.left});
}
tray.width = -ui.position.left;
}
});
}
function finishBuild() {
$("#header-shade").show();
$("#editor-shade").show();
$("#palette-shade").show();
$(".sidebar-shade").show();
tray.preferredWidth = Math.max(el.width(),500);
body.css({"minWidth":tray.preferredWidth-40});
if (options.width) {
if (options.width > $("#editor-stack").position().left-8) {
options.width = $("#editor-stack").position().left-8;
}
el.width(options.width);
} else {
el.width(tray.preferredWidth);
}
tray.width = el.width();
if (tray.width > $("#editor-stack").position().left-8) {
tray.width = Math.max(0/*tray.preferredWidth*/,$("#editor-stack").position().left-8);
el.width(tray.width);
}
// tray.body.parent().width(Math.min($("#editor-stack").position().left-8,tray.width));
el.css({
right: -(el.width()+10)+"px",
transition: "right 0.25s ease"
});
$("#workspace").scrollLeft(0);
handleWindowResize();
openingTray = true;
setTimeout(function() {
setTimeout(function() {
if (!options.width) {
el.width(Math.min(tray.preferredWidth,$("#editor-stack").position().left-8));
}
if (options.resize) {
options.resize({width:el.width()});
}
if (options.show) {
options.show();
}
setTimeout(function() {
// Delay resetting the flag, so we don't close prematurely
openingTray = false;
},200);
body.find(":focusable:first").focus();
},150);
el.css({right:0});
},0);
}
if (options.open) {
if (options.open.length === 1) {
options.open(el);
finishBuild();
} else {
options.open(el,finishBuild);
}
} else {
finishBuild();
}
}
function handleWindowResize() {
if (stack.length > 0) {
var tray = stack[stack.length-1];
var trayHeight = tray.tray.height()-tray.header.outerHeight()-tray.footer.outerHeight();
tray.body.height(trayHeight);
if (tray.options.maximized || tray.width > $("#editor-stack").position().left-8) {
tray.width = $("#editor-stack").position().left-8;
tray.tray.width(tray.width);
// tray.body.parent().width(tray.width);
} else if (tray.width < tray.preferredWidth) {
tray.width = Math.min($("#editor-stack").position().left-8,tray.preferredWidth);
tray.tray.width(tray.width);
// tray.body.parent().width(tray.width);
}
if (tray.options.resize) {
tray.options.resize({width:tray.width, height:trayHeight});
}
}
}
return {
init: function init() {
$(window).resize(handleWindowResize);
RED.events.on("sidebar:resize",handleWindowResize);
$("#editor-shade").click(function() {
if (!openingTray) {
var tray = stack[stack.length-1];
if (tray && tray.primaryButton) {
tray.primaryButton.click();
}
}
});
},
show: function show(options) {
if (stack.length > 0) {
var oldTray = stack[stack.length-1];
oldTray.tray.css({
right: -(oldTray.tray.width()+10)+"px"
});
setTimeout(function() {
oldTray.tray.detach();
showTray(options);
},250)
} else {
RED.events.emit("editor:open");
showTray(options);
}
},
close: function close(done) {
if (stack.length > 0) {
var tray = stack.pop();
tray.tray.css({
right: -(tray.tray.width()+10)+"px"
});
setTimeout(function() {
if (tray.options.close) {
tray.options.close();
}
tray.tray.remove();
if (stack.length > 0) {
var oldTray = stack[stack.length-1];
oldTray.tray.appendTo("#editor-stack");
setTimeout(function() {
handleWindowResize();
oldTray.tray.css({right:0});
if (oldTray.options.show) {
oldTray.options.show();
}
},0);
}
if (done) {
done();
}
if (stack.length === 0) {
$("#header-shade").hide();
$("#editor-shade").hide();
$("#palette-shade").hide();
$(".sidebar-shade").hide();
RED.events.emit("editor:close");
RED.view.focus();
}
},250)
}
}
}
})();

295
editor/js/ui/typeSearch.js Normal file
View File

@@ -0,0 +1,295 @@
RED.typeSearch = (function() {
var shade;
var disabled = false;
var dialog = null;
var searchInput;
var searchResults;
var searchResultsDiv;
var selected = -1;
var visible = false;
var activeFilter = "";
var addCallback;
var typesUsed = {};
function search(val) {
activeFilter = val.toLowerCase();
var visible = searchResults.editableList('filter');
setTimeout(function() {
selected = 0;
searchResults.children().removeClass('selected');
searchResults.children(":visible:first").addClass('selected');
},100);
}
function ensureSelectedIsVisible() {
var selectedEntry = searchResults.find("li.selected");
if (selectedEntry.length === 1) {
var scrollWindow = searchResults.parent();
var scrollHeight = scrollWindow.height();
var scrollOffset = scrollWindow.scrollTop();
var y = selectedEntry.position().top;
var h = selectedEntry.height();
if (y+h > scrollHeight) {
scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-10)},50);
} else if (y<0) {
scrollWindow.animate({scrollTop: '+='+(y-10)},50);
}
}
}
function createDialog() {
//shade = $('<div>',{class:"red-ui-type-search-shade"}).appendTo("#main-container");
dialog = $("<div>",{id:"red-ui-type-search",class:"red-ui-search red-ui-type-search"}).appendTo("#main-container");
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
searchInput = $('<input type="text">').attr("placeholder",RED._("search.addNode")).appendTo(searchDiv).searchBox({
delay: 50,
change: function() {
search($(this).val());
}
});
searchInput.on('keydown',function(evt) {
var children = searchResults.children(":visible");
if (children.length > 0) {
if (evt.keyCode === 40) {
// Down
if (selected < children.length-1) {
if (selected > -1) {
$(children[selected]).removeClass('selected');
}
selected++;
}
$(children[selected]).addClass('selected');
ensureSelectedIsVisible();
evt.preventDefault();
} else if (evt.keyCode === 38) {
// Up
if (selected > 0) {
if (selected < children.length) {
$(children[selected]).removeClass('selected');
}
selected--;
}
$(children[selected]).addClass('selected');
ensureSelectedIsVisible();
evt.preventDefault();
} else if (evt.keyCode === 13) {
// Enter
var index = Math.max(0,selected);
if (index < children.length) {
// TODO: dips into editableList impl details
confirm($(children[index]).find(".red-ui-editableList-item-content").data('data'));
}
}
}
});
searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog);
searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 0;bottom: 0;left: 0;right: 0;"}).appendTo(searchResultsDiv).editableList({
addButton: false,
filter: function(data) {
if (activeFilter === "" ) {
return true;
}
if (data.recent || data.common) {
return false;
}
return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1);
},
addItem: function(container,i,object) {
var def = object.def;
object.index = object.type.toLowerCase();
if (object.separator) {
container.addClass("red-ui-search-result-separator")
}
var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
var colour = def.color;
var icon_url = RED.utils.getNodeIcon(def);
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
if (def.inputs > 0) {
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
}
if (def.outputs > 0) {
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
}
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
var label = object.label;
object.index += "|"+label.toLowerCase();
$('<div>',{class:"red-ui-search-result-node-label"}).html(label).appendTo(contentDiv);
div.click(function(evt) {
evt.preventDefault();
confirm(object);
});
},
scrollOnAdd: false
});
}
function confirm(def) {
hide();
typesUsed[def.type] = Date.now();
addCallback(def.type);
}
function handleMouseActivity(evt) {
if (visible) {
var t = $(evt.target);
while (t.prop('nodeName').toLowerCase() !== 'body') {
if (t.attr('id') === 'red-ui-type-search') {
return;
}
t = t.parent();
}
hide(true);
}
}
function show(opts) {
if (!visible) {
RED.keyboard.add("*","escape",function(){hide()});
if (dialog === null) {
createDialog();
}
visible = true;
setTimeout(function() {
$(document).on('mousedown.type-search',handleMouseActivity);
$(document).on('mouseup.type-search',handleMouseActivity);
$(document).on('click.type-search',handleMouseActivity);
},200);
} else {
dialog.hide();
searchResultsDiv.hide();
}
refreshTypeList();
addCallback = opts.add;
RED.events.emit("type-search:open");
//shade.show();
dialog.css({left:opts.x+"px",top:opts.y+"px"}).show();
searchResultsDiv.slideDown(300);
setTimeout(function() {
searchResultsDiv.find(".red-ui-editableList-container").scrollTop(0);
searchInput.focus();
},100);
}
function hide(fast) {
if (visible) {
RED.keyboard.remove("escape");
visible = false;
if (dialog !== null) {
searchResultsDiv.slideUp(fast?50:200,function() {
dialog.hide();
searchInput.searchBox('value','');
});
//shade.hide();
}
RED.events.emit("type-search:close");
RED.view.focus();
$(document).off('mousedown.type-search');
$(document).off('mouseup.type-search');
$(document).off('click.type-search');
}
}
function getTypeLabel(type, def) {
var label = type;
if (typeof def.paletteLabel !== "undefined") {
try {
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
label += " ("+type+")";
} catch(err) {
console.log("Definition error: "+type+".paletteLabel",err);
}
}
return label;
}
function refreshTypeList() {
var i;
searchResults.editableList('empty');
searchInput.searchBox('value','');
selected = -1;
var common = [
'inject','debug','function','change','switch'
];
var recentlyUsed = Object.keys(typesUsed);
recentlyUsed.sort(function(a,b) {
return typesUsed[b]-typesUsed[a];
});
recentlyUsed = recentlyUsed.filter(function(t) {
return common.indexOf(t) === -1;
});
var items = [];
RED.nodes.registry.getNodeTypes().forEach(function(t) {
var def = RED.nodes.getType(t);
if (def.category !== 'config' && t !== 'unknown' && t !== 'tab') {
items.push({type:t,def: def, label:getTypeLabel(t,def)});
}
});
items.sort(function(a,b) {
var al = a.label.toLowerCase();
var bl = b.label.toLowerCase();
if (al < bl) {
return -1;
} else if (al === bl) {
return 0;
} else {
return 1;
}
})
var commonCount = 0;
var item;
for(i=0;i<common.length;i++) {
item = {
type: common[i],
common: true,
def: RED.nodes.getType(common[i])
};
item.label = getTypeLabel(item.type,item.def);
if (i === common.length-1) {
item.separator = true;
}
searchResults.editableList('addItem', item);
}
for(i=0;i<Math.min(5,recentlyUsed.length);i++) {
item = {
type:recentlyUsed[i],
def: RED.nodes.getType(recentlyUsed[i]),
recent: true
};
item.label = getTypeLabel(item.type,item.def);
if (i === recentlyUsed.length-1) {
item.separator = true;
}
searchResults.editableList('addItem', item);
}
for (i=0;i<items.length;i++) {
searchResults.editableList('addItem', items[i]);
}
setTimeout(function() {
selected = 0;
searchResults.children(":first").addClass('selected');
},100);
}
return {
show: show,
hide: hide
};
})();

View File

@@ -0,0 +1,249 @@
/**
* 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.userSettings = (function() {
var trayWidth = 700;
var settingsVisible = false;
var panes = [];
function addPane(options) {
panes.push(options);
}
function show(initialTab) {
if (settingsVisible) {
return;
}
settingsVisible = true;
var tabContainer;
var trayOptions = {
title: RED._("menu.label.userSettings"),
buttons: [
{
id: "node-dialog-ok",
text: RED._("common.label.close"),
class: "primary",
click: function() {
RED.tray.close();
}
}
],
resize: function(dimensions) {
trayWidth = dimensions.width;
},
open: function(tray) {
var trayBody = tray.find('.editor-tray-body');
var settingsContent = $('<div></div>').appendTo(trayBody);
var tabContainer = $('<div></div>',{id:"user-settings-tabs-container"}).appendTo(settingsContent);
$('<ul></ul>',{id:"user-settings-tabs"}).appendTo(tabContainer);
var settingsTabs = RED.tabs.create({
id: "user-settings-tabs",
vertical: true,
onchange: function(tab) {
setTimeout(function() {
$("#user-settings-tabs-content").children().hide();
$("#" + tab.id).show();
if (tab.pane.focus) {
tab.pane.focus();
}
},50);
}
});
var tabContents = $('<div></div>',{id:"user-settings-tabs-content"}).appendTo(settingsContent);
panes.forEach(function(pane) {
settingsTabs.addTab({
id: "user-settings-tab-"+pane.id,
label: pane.title,
pane: pane
});
pane.get().hide().appendTo(tabContents);
});
settingsContent.i18n();
settingsTabs.activateTab("user-settings-tab-"+(initialTab||'view'))
$("#sidebar-shade").show();
},
close: function() {
settingsVisible = false;
panes.forEach(function(pane) {
if (pane.close) {
pane.close();
}
});
$("#sidebar-shade").hide();
},
show: function() {}
}
if (trayWidth !== null) {
trayOptions.width = trayWidth;
}
RED.tray.show(trayOptions);
}
var viewSettings = [
{
title: "menu.label.view.grid",
options: [
{setting:"view-show-grid",oldSetting:"menu-menu-item-view-show-grid",label:"menu.label.view.showGrid",toggle:true,onchange:"core:toggle-show-grid"},
{setting:"view-snap-grid",oldSetting:"menu-menu-item-view-snap-grid",label:"menu.label.view.snapGrid",toggle:true,onchange:"core:toggle-snap-grid"},
{setting:"view-grid-size",label:"menu.label.view.gridSize",type:"number",default: 20, onchange:RED.view.gridSize}
]
},
{
title: "menu.label.nodes",
options: [
{setting:"view-node-status",oldSetting:"menu-menu-item-status",label:"menu.label.displayStatus",default: true, toggle:true,onchange:"core:toggle-status"}
]
},
{
title: "menu.label.other",
options: [
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"}
]
}
];
var allSettings = {};
function createViewPane() {
var pane = $('<div id="user-settings-tab-view" class="node-help"></div>');
viewSettings.forEach(function(section) {
$('<h3></h3>').text(RED._(section.title)).appendTo(pane);
section.options.forEach(function(opt) {
var initialState = RED.settings.get(opt.setting);
var row = $('<div class="user-settings-row"></div>').appendTo(pane);
var input;
if (opt.toggle) {
input = $('<label for="user-settings-'+opt.setting+'"><input id="user-settings-'+opt.setting+'" type="checkbox"> '+RED._(opt.label)+'</label>').appendTo(row).find("input");
input.prop('checked',initialState);
} else {
$('<label for="user-settings-'+opt.setting+'">'+RED._(opt.label)+'</label>').appendTo(row);
$('<input id="user-settings-'+opt.setting+'" type="'+(opt.type||"text")+'">').appendTo(row).val(initialState);
}
});
})
addBidiPreferences(pane);
return pane;
}
function addBidiPreferences(pane) {
$('<h3></h3>').text(RED._("menu.label.bidi")).appendTo(pane);
var row;
// Bidi enabled toggle
row = $('<div class="user-settings-row"></div>').appendTo(pane);
var input = $('<label for="user-settings-view-bidi-enabled"><input id="user-settings-view-bidi-enabled" type="checkbox"> '+RED._("menu.label.bidiSupport") +'</label>').appendTo(row).find("input");
input.prop('checked',RED.text.bidi.getBidiEnabled());
// Text Direction combo
row = $('<div class="user-settings-row"></div>').appendTo(pane);
$('<label for="user-settings-view-text-direction">'+RED._("menu.label.view.textDir")+'</label>').appendTo(row);
var select = $('<select id="user-settings-view-text-direction"><option value="ltr">' + RED._("menu.label.view.ltr") + '</option><option value="rtl">' + RED._("menu.label.view.rtl") + '</option><option value="auto">' + RED._("menu.label.view.auto") + '</option></select>').appendTo(row);
select.val(RED.text.bidi.getTextDirPref());
select.prop('disabled', !RED.text.bidi.getBidiEnabled());
input.change(function() {
RED.text.bidi.setBidiEnabled(input.prop('checked'));
select.prop('disabled', !RED.text.bidi.getBidiEnabled());
});
select.change(function() {
RED.text.bidi.setTextDirPref(select.val());
});
}
function setSelected(id, value) {
var opt = allSettings[id];
RED.settings.set(opt.setting,value);
var callback = opt.onchange;
if (typeof callback === 'string') {
callback = RED.actions.get(callback);
}
if (callback) {
callback.call(opt,value);
}
}
function toggle(id) {
var opt = allSettings[id];
var state = RED.settings.get(opt.setting);
setSelected(id,!state);
}
function init() {
RED.actions.add("core:show-user-settings",show);
RED.actions.add("core:show-help", function() { show('keyboard')});
addPane({
id:'view',
title: RED._("menu.label.view.view"),
get: createViewPane,
close: function() {
viewSettings.forEach(function(section) {
section.options.forEach(function(opt) {
var input = $("#user-settings-"+opt.setting);
if (opt.toggle) {
setSelected(opt.setting,input.prop('checked'));
} else {
setSelected(opt.setting,input.val());
}
});
})
}
})
viewSettings.forEach(function(section) {
section.options.forEach(function(opt) {
if (opt.oldSetting) {
var oldValue = RED.settings.get(opt.oldSetting);
if (oldValue !== undefined && oldValue !== null) {
RED.settings.set(opt.setting,oldValue);
RED.settings.remove(opt.oldSetting);
}
}
allSettings[opt.setting] = opt;
if (opt.onchange) {
var value = RED.settings.get(opt.setting);
if (value === null && opt.hasOwnProperty('default')) {
value = opt.default;
RED.settings.set(opt.setting,value);
}
var callback = opt.onchange;
if (typeof callback === 'string') {
callback = RED.actions.get(callback);
}
if (callback) {
callback.call(opt,value);
}
}
});
});
}
return {
init: init,
toggle: toggle,
show: show,
add: addPane
};
})();

741
editor/js/ui/utils.js Normal file
View File

@@ -0,0 +1,741 @@
/**
* 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.utils = (function() {
function formatString(str) {
return str.replace(/\r?\n/g,"&crarr;").replace(/\t/g,"&rarr;");
}
function sanitize(m) {
return m.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
}
function buildMessageSummaryValue(value) {
var result;
if (Array.isArray(value)) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
} else if (value === null) {
result = $('<span class="debug-message-object-value debug-message-type-null">null</span>');
} else if (typeof value === 'object') {
if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.length+']');
} else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
} else {
result = $('<span class="debug-message-object-value debug-message-type-meta">object</span>');
}
} else if (typeof value === 'string') {
var subvalue;
if (value.length > 30) {
subvalue = sanitize(value.substring(0,30))+"&hellip;";
} else {
subvalue = sanitize(value);
}
result = $('<span class="debug-message-object-value debug-message-type-string"></span>').html('"'+formatString(subvalue)+'"');
} else {
result = $('<span class="debug-message-object-value debug-message-type-other"></span>').text(""+value);
}
return result;
}
function makeExpandable(el,onbuild,ontoggle,expand) {
el.addClass("debug-message-expandable");
el.prop('toggle',function() {
return function(state) {
var parent = el.parent();
if (parent.hasClass('collapsed')) {
if (state) {
if (onbuild && !parent.hasClass('built')) {
onbuild();
parent.addClass('built');
}
parent.removeClass('collapsed');
return true;
}
} else {
if (!state) {
parent.addClass('collapsed');
return true;
}
}
return false;
}
});
el.click(function(e) {
var parent = $(this).parent();
var currentState = !parent.hasClass('collapsed');
if ($(this).prop('toggle')(!currentState)) {
if (ontoggle) {
ontoggle(!currentState);
}
}
// if (parent.hasClass('collapsed')) {
// if (onbuild && !parent.hasClass('built')) {
// onbuild();
// parent.addClass('built');
// }
// if (ontoggle) {
// ontoggle(true);
// }
// parent.removeClass('collapsed');
// } else {
// parent.addClass('collapsed');
// if (ontoggle) {
// ontoggle(false);
// }
// }
e.preventDefault();
});
if (expand) {
el.click();
}
}
var pinnedPaths = {};
var formattedPaths = {};
function addMessageControls(obj,sourceId,key,msg,rootPath,strippedKey) {
if (!pinnedPaths.hasOwnProperty(sourceId)) {
pinnedPaths[sourceId] = {}
}
var tools = $('<span class="debug-message-tools"></span>').appendTo(obj);
var copyTools = $('<span class="debug-message-tools-copy button-group"></span>').appendTo(tools);
if (!!key) {
var copyPath = $('<button class="editor-button editor-button-small"><i class="fa fa-terminal"></i></button>').appendTo(copyTools).click(function(e) {
e.preventDefault();
e.stopPropagation();
RED.clipboard.copyText(key,copyPath,"clipboard.copyMessagePath");
})
}
var copyPayload = $('<button class="editor-button editor-button-small"><i class="fa fa-clipboard"></i></button>').appendTo(copyTools).click(function(e) {
e.preventDefault();
e.stopPropagation();
RED.clipboard.copyText(msg,copyPayload,"clipboard.copyMessageValue");
})
if (strippedKey !== '') {
var isPinned = pinnedPaths[sourceId].hasOwnProperty(strippedKey);
var pinPath = $('<button class="editor-button editor-button-small debug-message-tools-pin"><i class="fa fa-map-pin"></i></button>').appendTo(tools).click(function(e) {
e.preventDefault();
e.stopPropagation();
if (pinnedPaths[sourceId].hasOwnProperty(strippedKey)) {
delete pinnedPaths[sourceId][strippedKey];
$(this).removeClass("selected");
obj.removeClass("debug-message-row-pinned");
} else {
var rootedPath = "$"+(strippedKey[0] === '['?"":".")+strippedKey;
pinnedPaths[sourceId][strippedKey] = normalisePropertyExpression(rootedPath);
$(this).addClass("selected");
obj.addClass("debug-message-row-pinned");
}
}).toggleClass("selected",isPinned);
obj.toggleClass("debug-message-row-pinned",isPinned);
}
}
function checkExpanded(strippedKey,expandPaths,minRange,maxRange) {
if (expandPaths && expandPaths.length > 0) {
if (strippedKey === '' && minRange === undefined) {
return true;
}
for (var i=0;i<expandPaths.length;i++) {
var p = expandPaths[i];
if (p.indexOf(strippedKey) === 0 && (p[strippedKey.length] === "." || p[strippedKey.length] === "[") ) {
if (minRange !== undefined && p[strippedKey.length] === "[") {
var subkey = p.substring(strippedKey.length);
var m = (/\[(\d+)\]/.exec(subkey));
if (m) {
var index = parseInt(m[1]);
return minRange<=index && index<=maxRange;
}
} else {
return true;
}
}
}
}
return false;
}
function formatNumber(element,obj,sourceId,path,cycle,initialFormat) {
var format = (formattedPaths[sourceId] && formattedPaths[sourceId][path]) || initialFormat || "dec";
if (cycle) {
if (format === 'dec') {
if ((obj.toString().length===13) && (obj<=2147483647000)) {
format = 'dateMS';
} else if ((obj.toString().length===10) && (obj<=2147483647)) {
format = 'dateS';
} else {
format = 'hex'
}
} else if (format === 'dateMS' || format == 'dateS') {
format = 'hex';
} else {
format = 'dec';
}
formattedPaths[sourceId] = formattedPaths[sourceId]||{};
formattedPaths[sourceId][path] = format;
} else if (initialFormat !== undefined){
formattedPaths[sourceId] = formattedPaths[sourceId]||{};
formattedPaths[sourceId][path] = format;
}
if (format === 'dec') {
element.text(""+obj);
} else if (format === 'dateMS') {
element.text((new Date(obj)).toISOString());
} else if (format === 'dateS') {
element.text((new Date(obj*1000)).toISOString());
} else if (format === 'hex') {
element.text("0x"+(obj).toString(16));
}
}
function formatBuffer(element,button,sourceId,path,cycle) {
var format = (formattedPaths[sourceId] && formattedPaths[sourceId][path]) || "raw";
if (cycle) {
if (format === 'raw') {
format = 'string';
} else {
format = 'raw';
}
formattedPaths[sourceId] = formattedPaths[sourceId]||{};
formattedPaths[sourceId][path] = format;
}
if (format === 'raw') {
button.text('raw');
element.removeClass('debug-message-buffer-string').addClass('debug-message-buffer-raw');
} else if (format === 'string') {
button.text('string');
element.addClass('debug-message-buffer-string').removeClass('debug-message-buffer-raw');
}
}
function buildMessageElement(obj,options) {
options = options || {};
var key = options.key;
var typeHint = options.typeHint;
var hideKey = options.hideKey;
var path = options.path;
var sourceId = options.sourceId;
var rootPath = options.rootPath;
var expandPaths = options.expandPaths;
var ontoggle = options.ontoggle;
var exposeApi = options.exposeApi;
var subElements = {};
var i;
var e;
var entryObj;
var expandableHeader;
var header;
var headerHead;
var value;
var strippedKey;
if (path !== undefined && rootPath !== undefined) {
strippedKey = path.substring(rootPath.length+(path[rootPath.length]==="."?1:0));
}
var element = $('<span class="debug-message-element"></span>');
element.collapse = function() {
element.find(".debug-message-expandable").parent().addClass("collapsed");
}
header = $('<span class="debug-message-row"></span>').appendTo(element);
if (sourceId) {
addMessageControls(header,sourceId,path,obj,rootPath,strippedKey);
}
if (!key) {
element.addClass("debug-message-top-level");
if (sourceId) {
var pinned = pinnedPaths[sourceId];
expandPaths = [];
if (pinned) {
for (var pinnedPath in pinned) {
if (pinned.hasOwnProperty(pinnedPath)) {
try {
var res = getMessageProperty({$:obj},pinned[pinnedPath]);
if (res !== undefined) {
expandPaths.push(pinnedPath);
}
} catch(err) {
}
}
}
expandPaths.sort();
}
element.clearPinned = function() {
element.find(".debug-message-row-pinned").removeClass("debug-message-row-pinned");
pinnedPaths[sourceId] = {};
}
}
} else {
if (!hideKey) {
$('<span class="debug-message-object-key"></span>').text(key).appendTo(header);
$('<span>: </span>').appendTo(header);
}
}
entryObj = $('<span class="debug-message-object-value"></span>').appendTo(header);
var isArray = Array.isArray(obj);
var isArrayObject = false;
if (obj && typeof obj === 'object' && obj.hasOwnProperty('type') && obj.hasOwnProperty('data') && ((obj.__encoded__ && obj.type === 'array') || obj.type === 'Buffer')) {
isArray = true;
isArrayObject = true;
}
if (obj === null || obj === undefined) {
$('<span class="debug-message-type-null">'+obj+'</span>').appendTo(entryObj);
} else if (typeof obj === 'string') {
if (/[\t\n\r]/.test(obj)) {
element.addClass('collapsed');
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
makeExpandable(header, function() {
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header);
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
$('<pre class="debug-message-type-string"></pre>').text(obj).appendTo(row);
},function(state) {if (ontoggle) { ontoggle(path,state);}}, checkExpanded(strippedKey,expandPaths));
}
e = $('<span class="debug-message-type-string debug-message-object-header"></span>').html('"'+formatString(sanitize(obj))+'"').appendTo(entryObj);
if (/^#[0-9a-f]{6}$/i.test(obj)) {
$('<span class="debug-message-type-string-swatch"></span>').css('backgroundColor',obj).appendTo(e);
}
} else if (typeof obj === 'number') {
e = $('<span class="debug-message-type-number"></span>').appendTo(entryObj);
if (Number.isInteger(obj) && (obj >= 0)) { // if it's a +ve integer
e.addClass("debug-message-type-number-toggle");
e.click(function(evt) {
evt.preventDefault();
formatNumber($(this), obj, sourceId, path, true);
});
}
formatNumber(e,obj,sourceId,path,false,typeHint==='hex'?'hex':undefined);
} else if (isArray) {
element.addClass('collapsed');
var originalLength = obj.length;
if (typeHint) {
var m = /\[(\d+)\]/.exec(typeHint);
if (m) {
originalLength = parseInt(m[1]);
}
}
var data = obj;
var type = 'array';
if (isArrayObject) {
data = obj.data;
if (originalLength === undefined) {
originalLength = data.length;
}
if (data.__encoded__) {
data = data.data;
}
type = obj.type.toLowerCase();
} else if (/buffer/.test(typeHint)) {
type = 'buffer';
}
var fullLength = data.length;
if (originalLength > 0) {
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
var arrayRows = $('<div class="debug-message-array-rows"></div>').appendTo(element);
element.addClass('debug-message-buffer-raw');
}
if (key) {
headerHead = $('<span class="debug-message-type-meta"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
} else {
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
$('<span>[ </span>').appendTo(headerHead);
var arrayLength = Math.min(originalLength,10);
for (i=0;i<arrayLength;i++) {
buildMessageSummaryValue(data[i]).appendTo(headerHead);
if (i < arrayLength-1) {
$('<span>, </span>').appendTo(headerHead);
}
}
if (originalLength > arrayLength) {
$('<span> &hellip;</span>').appendTo(headerHead);
}
if (arrayLength === 0) {
$('<span class="debug-message-type-meta">empty</span>').appendTo(headerHead);
}
$('<span> ]</span>').appendTo(headerHead);
}
if (originalLength > 0) {
makeExpandable(header,function() {
if (!key) {
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(header);
}
if (type === 'buffer') {
var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element);
var sr = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(stringRow);
var stringEncoding = "";
try {
stringEncoding = String.fromCharCode.apply(null, new Uint16Array(data))
} catch(err) {
console.log(err);
}
$('<pre class="debug-message-type-string"></pre>').text(stringEncoding).appendTo(sr);
var bufferOpts = $('<span class="debug-message-buffer-opts"></span>').appendTo(headerHead);
var switchFormat = $('<a href="#"></a>').addClass('selected').html('raw').appendTo(bufferOpts).click(function(e) {
e.preventDefault();
e.stopPropagation();
formatBuffer(element,$(this),sourceId,path,true);
});
formatBuffer(element,switchFormat,sourceId,path,false);
}
var row;
if (fullLength <= 10) {
for (i=0;i<fullLength;i++) {
row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows);
subElements[path+"["+i+"]"] = buildMessageElement(
data[i],
{
key: ""+i,
typeHint: type==='buffer'?'hex':false,
hideKey: false,
path: path+"["+i+"]",
sourceId: sourceId,
rootPath: rootPath,
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi
}
).appendTo(row);
}
} else {
for (i=0;i<fullLength;i+=10) {
var minRange = i;
row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows);
header = $('<span></span>').appendTo(row);
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').appendTo(header);
makeExpandable(header, (function() {
var min = minRange;
var max = Math.min(fullLength-1,(minRange+9));
var parent = row;
return function() {
for (var i=min;i<=max;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(parent);
subElements[path+"["+i+"]"] = buildMessageElement(
data[i],
{
key: ""+i,
typeHint: type==='buffer'?'hex':false,
hideKey: false,
path: path+"["+i+"]",
sourceId: sourceId,
rootPath: rootPath,
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi
}
).appendTo(row);
}
}
})(),
(function() { var path = path+"["+i+"]"; return function(state) {if (ontoggle) { ontoggle(path,state);}}})(),
checkExpanded(strippedKey,expandPaths,minRange,Math.min(fullLength-1,(minRange+9))));
$('<span class="debug-message-object-key"></span>').html("["+minRange+" &hellip; "+Math.min(fullLength-1,(minRange+9))+"]").appendTo(header);
}
if (fullLength < originalLength) {
$('<div class="debug-message-object-entry collapsed"><span class="debug-message-object-key">['+fullLength+' &hellip; '+originalLength+']</span></div>').appendTo(arrayRows);
}
}
},
function(state) {if (ontoggle) { ontoggle(path,state);}},
checkExpanded(strippedKey,expandPaths));
}
} else if (typeof obj === 'object') {
element.addClass('collapsed');
var keys = Object.keys(obj);
if (key || keys.length > 0) {
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
makeExpandable(header, function() {
if (!key) {
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html('object').appendTo(header);
}
for (i=0;i<keys.length;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
var newPath = path;
if (newPath) {
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(keys[i])) {
newPath += (newPath.length > 0?".":"")+keys[i];
} else {
newPath += "[\""+keys[i].replace(/"/,"\\\"")+"\"]"
}
}
subElements[newPath] = buildMessageElement(
obj[keys[i]],
{
key: keys[i],
typeHint: false,
hideKey: false,
path: newPath,
sourceId: sourceId,
rootPath: rootPath,
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi
}
).appendTo(row);
}
if (keys.length === 0) {
$('<div class="debug-message-object-entry debug-message-type-meta collapsed"></div>').text("empty").appendTo(element);
}
},
function(state) {if (ontoggle) { ontoggle(path,state);}},
checkExpanded(strippedKey,expandPaths));
}
if (key) {
$('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj);
} else {
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
$('<span>{ </span>').appendTo(headerHead);
var keysLength = Math.min(keys.length,5);
for (i=0;i<keysLength;i++) {
$('<span class="debug-message-object-key"></span>').text(keys[i]).appendTo(headerHead);
$('<span>: </span>').appendTo(headerHead);
buildMessageSummaryValue(obj[keys[i]]).appendTo(headerHead);
if (i < keysLength-1) {
$('<span>, </span>').appendTo(headerHead);
}
}
if (keys.length > keysLength) {
$('<span> &hellip;</span>').appendTo(headerHead);
}
if (keysLength === 0) {
$('<span class="debug-message-type-meta">empty</span>').appendTo(headerHead);
}
$('<span> }</span>').appendTo(headerHead);
}
} else {
$('<span class="debug-message-type-other"></span>').text(""+obj).appendTo(entryObj);
}
if (exposeApi) {
element.prop('expand', function() { return function(targetPath, state) {
if (path === targetPath) {
if (header.prop('toggle')) {
header.prop('toggle')(state);
}
} else if (subElements[targetPath] && subElements[targetPath].prop('expand') ) {
subElements[targetPath].prop('expand')(targetPath,state);
} else {
for (var p in subElements) {
if (subElements.hasOwnProperty(p)) {
if (targetPath.indexOf(p) === 0) {
if (subElements[p].prop('expand') ) {
subElements[p].prop('expand')(targetPath,state);
}
break;
}
}
}
}
}});
}
return element;
}
function normalisePropertyExpression(str) {
// This must be kept in sync with validatePropertyExpression
// in editor/js/ui/utils.js
var length = str.length;
if (length === 0) {
throw new Error("Invalid property expression: zero-length");
}
var parts = [];
var start = 0;
var inString = false;
var inBox = false;
var quoteChar;
var v;
for (var i=0;i<length;i++) {
var c = str[i];
if (!inString) {
if (c === "'" || c === '"') {
if (i != start) {
throw new Error("Invalid property expression: unexpected "+c+" at position "+i);
}
inString = true;
quoteChar = c;
start = i+1;
} else if (c === '.') {
if (i===0) {
throw new Error("Invalid property expression: unexpected . at position 0");
}
if (start != i) {
v = str.substring(start,i);
if (/^\d+$/.test(v)) {
parts.push(parseInt(v));
} else {
parts.push(v);
}
}
if (i===length-1) {
throw new Error("Invalid property expression: unterminated expression");
}
// Next char is first char of an identifier: a-z 0-9 $ _
if (!/[a-z0-9\$\_]/i.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1));
}
start = i+1;
} else if (c === '[') {
if (i === 0) {
throw new Error("Invalid property expression: unexpected "+c+" at position "+i);
}
if (start != i) {
parts.push(str.substring(start,i));
}
if (i===length-1) {
throw new Error("Invalid property expression: unterminated expression");
}
// Next char is either a quote or a number
if (!/["'\d]/.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1));
}
start = i+1;
inBox = true;
} else if (c === ']') {
if (!inBox) {
throw new Error("Invalid property expression: unexpected "+c+" at position "+i);
}
if (start != i) {
v = str.substring(start,i);
if (/^\d+$/.test(v)) {
parts.push(parseInt(v));
} else {
throw new Error("Invalid property expression: unexpected array expression at position "+start);
}
}
start = i+1;
inBox = false;
} else if (c === ' ') {
throw new Error("Invalid property expression: unexpected ' ' at position "+i);
}
} else {
if (c === quoteChar) {
if (i-start === 0) {
throw new Error("Invalid property expression: zero-length string at position "+start);
}
parts.push(str.substring(start,i));
// If inBox, next char must be a ]. Otherwise it may be [ or .
if (inBox && !/\]/.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected array expression at position "+start);
} else if (!inBox && i+1!==length && !/[\[\.]/.test(str[i+1])) {
throw new Error("Invalid property expression: unexpected "+str[i+1]+" expression at position "+(i+1));
}
start = i+1;
inString = false;
}
}
}
if (inBox || inString) {
throw new Error("Invalid property expression: unterminated expression");
}
if (start < length) {
parts.push(str.substring(start));
}
return parts;
}
function validatePropertyExpression(str) {
try {
var parts = normalisePropertyExpression(str);
return true;
} catch(err) {
return false;
}
}
function getMessageProperty(msg,expr) {
var result = null;
var msgPropParts;
if (typeof expr === 'string') {
if (expr.indexOf('msg.')===0) {
expr = expr.substring(4);
}
msgPropParts = normalisePropertyExpression(expr);
} else {
msgPropParts = expr;
}
var m;
msgPropParts.reduce(function(obj, key) {
result = (typeof obj[key] !== "undefined" ? obj[key] : undefined);
if (result === undefined && obj.hasOwnProperty('type') && obj.hasOwnProperty('data')&& obj.hasOwnProperty('length')) {
result = (typeof obj.data[key] !== "undefined" ? obj.data[key] : undefined);
}
return result;
}, msg);
return result;
}
function getNodeIcon(def,node) {
if (def.category === 'config') {
return "icons/node-red/cog.png"
} else if (node && node.type === 'tab') {
return "icons/node-red/subflow.png"
} else if (node && node.type === 'unknown') {
return "icons/node-red/alert.png"
} else if (node && node.type === 'subflow') {
return "icons/node-red/subflow.png"
}
var icon_url;
if (typeof def.icon === "function") {
try {
icon_url = def.icon.call(node);
} catch(err) {
console.log("Definition error: "+def.type+".icon",err);
icon_url = "arrow-in.png";
}
} else {
icon_url = def.icon;
}
return "icons/"+def.set.module+"/"+icon_url;
}
function getNodeLabel(node,defaultLabel) {
defaultLabel = defaultLabel||"";
var l;
if (node.type === 'tab') {
l = node.label || defaultLabel
} else {
l = node._def.label;
try {
l = (typeof l === "function" ? l.call(node) : l)||defaultLabel;
} catch(err) {
console.log("Definition error: "+node.type+".label",err);
l = defaultLabel;
}
}
return RED.text.bidi.enforceTextDirectionWithUCC(l);
}
return {
createObjectElement: buildMessageElement,
getMessageProperty: getMessageProperty,
normalisePropertyExpression: normalisePropertyExpression,
validatePropertyExpression: validatePropertyExpression,
getNodeIcon: getNodeIcon,
getNodeLabel: getNodeLabel,
}
})();

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -16,11 +16,11 @@
RED.workspaces = (function() {
var activeWorkspace = 0;
var workspaceIndex = 0;
function addWorkspace(ws) {
function addWorkspace(ws,skipHistoryEntry) {
if (ws) {
workspace_tabs.addTab(ws);
workspace_tabs.resize();
@@ -28,198 +28,264 @@ RED.workspaces = (function() {
var tabId = RED.nodes.id();
do {
workspaceIndex += 1;
} while($("#workspace-tabs a[title='Sheet "+workspaceIndex+"']").size() !== 0);
ws = {type:"tab",id:tabId,label:"Sheet "+workspaceIndex};
} while ($("#workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
ws = {type:"tab",id:tabId,disabled: false,info:"",label:RED._('workspace.defaultName',{number:workspaceIndex})};
RED.nodes.addWorkspace(ws);
workspace_tabs.addTab(ws);
workspace_tabs.activateTab(tabId);
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
if (!skipHistoryEntry) {
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
}
}
RED.view.focus();
return ws;
}
function deleteWorkspace(ws,force) {
function deleteWorkspace(ws) {
if (workspace_tabs.count() == 1) {
return;
}
var nodes = [];
if (!force) {
nodes = RED.nodes.filterNodes({z:ws.id});
}
if (force || nodes.length === 0) {
removeWorkspace(ws);
var historyEvent = RED.nodes.removeWorkspace(ws.id);
historyEvent.t = 'delete';
historyEvent.dirty = RED.nodes.dirty();
historyEvent.workspaces = [ws];
RED.history.push(historyEvent);
RED.nodes.dirty(true);
} else {
$( "#node-dialog-delete-workspace" ).dialog('option','workspace',ws);
$( "#node-dialog-delete-workspace-name" ).text(ws.label);
$( "#node-dialog-delete-workspace" ).dialog('open');
}
}
function showRenameWorkspaceDialog(id) {
var ws = RED.nodes.workspace(id);
$( "#node-dialog-rename-workspace" ).dialog("option","workspace",ws);
if (workspace_tabs.count() == 1) {
$( "#node-dialog-rename-workspace").next().find(".leftButton")
.prop('disabled',true)
.addClass("ui-state-disabled");
} else {
$( "#node-dialog-rename-workspace").next().find(".leftButton")
.prop('disabled',false)
.removeClass("ui-state-disabled");
}
$( "#node-input-workspace-name" ).val(ws.label);
$( "#node-dialog-rename-workspace" ).dialog("open");
removeWorkspace(ws);
var historyEvent = RED.nodes.removeWorkspace(ws.id);
historyEvent.t = 'delete';
historyEvent.dirty = RED.nodes.dirty();
historyEvent.workspaces = [ws];
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
}
function showRenameWorkspaceDialog(id) {
var workspace = RED.nodes.workspace(id);
RED.view.state(RED.state.EDITING);
var tabflowEditor;
var trayOptions = {
title: RED._("workspace.editFlow",{name:workspace.label}),
buttons: [
{
id: "node-dialog-delete",
class: 'leftButton'+((workspace_tabs.count() == 1)?" disabled":""),
text: RED._("common.label.delete"), //'<i class="fa fa-trash"></i>',
click: function() {
deleteWorkspace(workspace);
RED.tray.close();
}
},
{
id: "node-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
RED.tray.close();
}
},
{
id: "node-dialog-ok",
class: "primary",
text: RED._("common.label.done"),
click: function() {
var label = $( "#node-input-name" ).val();
var changed = false;
var changes = {};
if (workspace.label != label) {
changes.label = workspace.label;
changed = true;
workspace.label = label;
workspace_tabs.renameTab(workspace.id,label);
}
var disabled = $("#node-input-disabled").prop("checked");
if (workspace.disabled !== disabled) {
changes.disabled = workspace.disabled;
changed = true;
workspace.disabled = disabled;
}
var info = tabflowEditor.getValue();
if (workspace.info !== info) {
changes.info = workspace.info;
changed = true;
workspace.info = info;
}
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('workspace-disabled',workspace.disabled);
// $("#workspace").toggleClass("workspace-disabled",workspace.disabled);
if (changed) {
var historyEvent = {
t: "edit",
changes:changes,
node: workspace,
dirty: RED.nodes.dirty()
}
workspace.changed = true;
RED.history.push(historyEvent);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
var selection = RED.view.selection();
if (!selection.nodes && !selection.links) {
RED.sidebar.info.refresh(workspace);
}
}
RED.tray.close();
}
}
],
resize: function(dimensions) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var editorRow = $("#dialog-form>div.node-text-editor-row");
var height = $("#dialog-form").height();
for (var i=0; i<rows.size(); i++) {
height -= $(rows[i]).outerHeight(true);
}
height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
height -= 28;
$(".node-text-editor").css("height",height+"px");
tabflowEditor.resize();
},
open: function(tray) {
var trayBody = tray.find('.editor-tray-body');
var dialogForm = $('<form id="dialog-form" class="form-horizontal"></form>').appendTo(trayBody);
$('<div class="form-row">'+
'<label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>'+
'<input type="text" id="node-input-name">'+
'</div>').appendTo(dialogForm);
$('<div class="form-row">'+
'<label for="node-input-disabled-btn" data-i18n="editor:workspace.status"></label>'+
'<button id="node-input-disabled-btn" class="editor-button"><i class="fa fa-toggle-on"></i> <span id="node-input-disabled-label"></span></button> '+
'<input type="checkbox" id="node-input-disabled" style="display: none;"/>'+
'</div>').appendTo(dialogForm);
$('<div class="form-row node-text-editor-row">'+
'<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+
'<div style="height:250px;" class="node-text-editor" id="node-input-info"></div>'+
'</div>').appendTo(dialogForm);
tabflowEditor = RED.editor.createEditor({
id: 'node-input-info',
mode: 'ace/mode/markdown',
value: ""
});
$('<div class="form-tips" data-i18n="editor:workspace.tip"></div>').appendTo(dialogForm);
dialogForm.find('#node-input-disabled-btn').on("click",function(e) {
var i = $(this).find("i");
if (i.hasClass('fa-toggle-off')) {
i.addClass('fa-toggle-on');
i.removeClass('fa-toggle-off');
$("#node-input-disabled").prop("checked",false);
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
} else {
i.addClass('fa-toggle-off');
i.removeClass('fa-toggle-on');
$("#node-input-disabled").prop("checked",true);
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
}
})
if (workspace.hasOwnProperty("disabled")) {
$("#node-input-disabled").prop("checked",workspace.disabled);
if (workspace.disabled) {
dialogForm.find("#node-input-disabled-btn i").removeClass('fa-toggle-on').addClass('fa-toggle-off');
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
} else {
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
}
} else {
workspace.disabled = false;
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
}
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
dialogForm.submit(function(e) { e.preventDefault();});
$("#node-input-name").val(workspace.label);
RED.text.bidi.prepareInput($("#node-input-name"));
tabflowEditor.getSession().setValue(workspace.info || "", -1);
dialogForm.i18n();
},
close: function() {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
RED.sidebar.info.refresh(workspace);
tabflowEditor.destroy();
}
}
RED.tray.show(trayOptions);
}
var workspace_tabs;
function createWorkspaceTabs() {
workspace_tabs = RED.tabs.create({
id: "workspace-tabs",
onchange: function(tab) {
var event = {
old: activeWorkspace
}
activeWorkspace = tab.id;
event.workspace = activeWorkspace;
// $("#workspace").toggleClass("workspace-disabled",tab.disabled);
RED.events.emit("workspace:change",event);
window.location.hash = 'flow/'+tab.id;
RED.sidebar.config.refresh();
RED.view.focus();
},
onclick: function(tab) {
RED.view.focus();
},
ondblclick: function(tab) {
if (tab.type != "subflow") {
showRenameWorkspaceDialog(tab.id);
} else {
RED.editor.editSubflow(RED.nodes.subflow(tab.id));
}
},
onadd: function(tab) {
$('<span class="workspace-disabled-icon"><i class="fa fa-ban"></i> </span>').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label");
if (tab.disabled) {
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('workspace-disabled');
}
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
},
onremove: function(tab) {
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
},
onreorder: function(oldOrder, newOrder) {
RED.history.push({t:'reorder',order:oldOrder,dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
setWorkspaceOrder(newOrder);
},
minimumActiveTabWidth: 150,
scrollable: true,
addButton: function() {
addWorkspace();
}
});
}
var workspace_tabs = RED.tabs.create({
id: "workspace-tabs",
onchange: function(tab) {
if (tab.type == "subflow") {
$("#workspace-toolbar").show();
} else {
$("#workspace-toolbar").hide();
}
var event = {
old: activeWorkspace
}
activeWorkspace = tab.id;
event.workspace = activeWorkspace;
eventHandler.emit("change",event);
},
ondblclick: function(tab) {
if (tab.type != "subflow") {
showRenameWorkspaceDialog(tab.id);
} else {
RED.editor.editSubflow(RED.nodes.subflow(tab.id));
}
},
onadd: function(tab) {
RED.menu.addItem("menu-item-workspace",{
id:"menu-item-workspace-menu-"+tab.id.replace(".","-"),
label:tab.label,
onselect:function() {
workspace_tabs.activateTab(tab.id);
}
});
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
},
onremove: function(tab) {
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-"));
}
});
$("#node-dialog-rename-workspace form" ).submit(function(e) { e.preventDefault();});
$( "#node-dialog-rename-workspace" ).dialog({
modal: true,
autoOpen: false,
width: 500,
title: "Rename sheet",
buttons: [
{
class: 'leftButton',
text: "Delete",
click: function() {
var workspace = $(this).dialog('option','workspace');
$( this ).dialog( "close" );
deleteWorkspace(workspace);
}
},
{
text: "Ok",
click: function() {
var workspace = $(this).dialog('option','workspace');
var label = $( "#node-input-workspace-name" ).val();
if (workspace.label != label) {
workspace_tabs.renameTab(workspace.id,label);
RED.nodes.dirty(true);
$("#menu-item-workspace-menu-"+workspace.id.replace(".","-")).text(label);
// TODO: update entry in menu
}
$( this ).dialog( "close" );
}
},
{
text: "Cancel",
click: function() {
$( this ).dialog( "close" );
}
}
],
open: function(e) {
RED.keyboard.disable();
},
close: function(e) {
RED.keyboard.enable();
}
});
$( "#node-dialog-delete-workspace" ).dialog({
modal: true,
autoOpen: false,
width: 500,
title: "Confirm delete",
buttons: [
{
text: "Ok",
click: function() {
var workspace = $(this).dialog('option','workspace');
deleteWorkspace(workspace,true);
$( this ).dialog( "close" );
}
},
{
text: "Cancel",
click: function() {
$( this ).dialog( "close" );
}
}
],
open: function(e) {
RED.keyboard.disable();
},
close: function(e) {
RED.keyboard.enable();
}
});
function init() {
$('#btn-workspace-add-tab').on("click",function(e) {addWorkspace(); e.preventDefault()});
RED.sidebar.on("resize",workspace_tabs.resize);
createWorkspaceTabs();
RED.events.on("sidebar:resize",workspace_tabs.resize);
RED.actions.add("core:show-next-tab",workspace_tabs.nextTab);
RED.actions.add("core:show-previous-tab",workspace_tabs.previousTab);
RED.menu.setAction('menu-item-workspace-delete',function() {
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
});
$(window).resize(function() {
workspace_tabs.resize();
});
RED.actions.add("core:add-flow",addWorkspace);
RED.actions.add("core:edit-flow",editWorkspace);
RED.actions.add("core:remove-flow",removeWorkspace);
}
// TODO: DRY
var eventHandler = (function() {
var handlers = {};
return {
on: function(evt,func) {
handlers[evt] = handlers[evt]||[];
handlers[evt].push(func);
},
emit: function(evt,arg) {
if (handlers[evt]) {
for (var i=0;i<handlers[evt].length;i++) {
handlers[evt][i](arg);
}
}
}
}
})();
function editWorkspace(id) {
showRenameWorkspaceDialog(id||activeWorkspace);
}
function removeWorkspace(ws) {
if (!ws) {
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
@@ -229,15 +295,20 @@ RED.workspaces = (function() {
}
}
}
function setWorkspaceOrder(order) {
RED.nodes.setWorkspaceOrder(order.filter(function(id) {
return RED.nodes.workspace(id) !== undefined;
}));
workspace_tabs.order(order);
}
return {
init: init,
on: eventHandler.on,
add: addWorkspace,
remove: removeWorkspace,
edit: function(id) {
showRenameWorkspaceDialog(id||activeWorkspace);
},
order: setWorkspaceOrder,
edit: editWorkspace,
contains: function(id) {
return workspace_tabs.contains(id);
},
@@ -251,17 +322,24 @@ RED.workspaces = (function() {
if (!workspace_tabs.contains(id)) {
var sf = RED.nodes.subflow(id);
if (sf) {
addWorkspace({type:"subflow",id:id,label:"Subflow: "+sf.name, closeable: true});
addWorkspace({type:"subflow",id:id,icon:"red/images/subflow_tab.png",label:sf.name, closeable: true});
} else {
return;
}
}
}
workspace_tabs.activateTab(id);
},
refresh: function() {
RED.nodes.eachWorkspace(function(ws) {
workspace_tabs.renameTab(ws.id,ws.label);
})
RED.nodes.eachSubflow(function(sf) {
if (workspace_tabs.contains(sf.id)) {
workspace_tabs.renameTab(sf.id,"Subflow: "+sf.name);
workspace_tabs.renameTab(sf.id,sf.name);
}
});
RED.sidebar.config.refresh();
},
resize: function() {
workspace_tabs.resize();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2014, 2015 IBM Corp.
* 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.
@@ -14,13 +14,13 @@
* limitations under the License.
**/
RED.user = (function() {
function login(opts,done) {
if (typeof opts == 'function') {
done = opts;
opts = {};
}
var dialog = $('<div id="node-dialog-login" class="hide">'+
'<div style="display: inline-block;width: 250px; vertical-align: top; margin-right: 10px; margin-bottom: 20px;"><img id="node-dialog-login-image" src=""/></div>'+
'<div style="display: inline-block; width: 250px; vertical-align: bottom; margin-left: 10px; margin-bottom: 20px;">'+
@@ -32,31 +32,27 @@ RED.user = (function() {
autoOpen: false,
dialogClass: "ui-dialog-no-close",
modal: true,
closeOnEscape: false,
closeOnEscape: !!opts.cancelable,
width: 600,
resizable: false,
draggable: false
});
$("#node-dialog-login-fields").empty();
$.ajax({
dataType: "json",
url: "auth/login",
success: function(data) {
var i=0;
if (data.type == "credentials") {
var i=0;
if (data.image) {
$("#node-dialog-login-image").attr("src",data.image);
} else {
$("#node-dialog-login-image").attr("src","red/images/node-red-256.png");
}
for (;i<data.prompts.length;i++) {
var field = data.prompts[i];
var row = $("<div/>",{id:"rrr"+i,class:"form-row"});
$('<label for="node-dialog-login-'+field.id+'">'+field.label+':</label><br/>').appendTo(row);
var row = $("<div/>",{class:"form-row"});
$('<label for="node-dialog-login-'+field.id+'">'+RED._(field.label)+':</label><br/>').appendTo(row);
var input = $('<input style="width: 100%" id="node-dialog-login-'+field.id+'" type="'+field.type+'" tabIndex="'+(i+1)+'"/>').appendTo(row);
if (i<data.prompts.length-1) {
input.keypress(
(function() {
@@ -72,21 +68,21 @@ RED.user = (function() {
}
row.appendTo("#node-dialog-login-fields");
}
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">Login failed</span><img src="red/images/spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
(opts.cancelable?'<a href="#" id="node-dialog-login-cancel" style="margin-right: 20px;" tabIndex="'+(i+1)+'">Cancel</a>':'')+
'<input type="submit" id="node-dialog-login-submit" style="width: auto;" tabIndex="'+(i+2)+'" value="Login"></div>').appendTo("#node-dialog-login-fields");
$('<div class="form-row" style="text-align: right; margin-top: 10px;"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">'+RED._("user.loginFailed")+'</span><img src="red/images/spin.svg" style="height: 30px; margin-right: 10px; " class="login-spinner hide"/>'+
(opts.cancelable?'<a href="#" id="node-dialog-login-cancel" style="margin-right: 20px;" tabIndex="'+(i+1)+'">'+RED._("common.label.cancel")+'</a>':'')+
'<input type="submit" id="node-dialog-login-submit" style="width: auto;" tabIndex="'+(i+2)+'" value="'+RED._("user.login")+'"></div>').appendTo("#node-dialog-login-fields");
$("#node-dialog-login-submit").button();
$("#node-dialog-login-fields").submit(function(event) {
$("#node-dialog-login-submit").button("option","disabled",true);
$("#node-dialog-login-failed").hide();
$(".login-spinner").show();
var body = {
client_id: "node-red-editor",
grant_type: "password",
scope:"*"
scope:""
}
for (var i=0;i<data.prompts.length;i++) {
var field = data.prompts[i];
@@ -99,6 +95,9 @@ RED.user = (function() {
}).done(function(data,textStatus,xhr) {
RED.settings.set("auth-tokens",data);
$("#node-dialog-login").dialog('destroy').remove();
if (opts.updateMenu) {
updateUserMenu();
}
done();
}).fail(function(jqXHR,textStatus,errorThrown) {
RED.settings.remove("auth-tokens");
@@ -109,39 +108,85 @@ RED.user = (function() {
});
event.preventDefault();
});
if (opts.cancelable) {
$("#node-dialog-login-cancel").button().click(function( event ) {
$("#node-dialog-login").dialog('destroy').remove();
} else if (data.type == "strategy") {
i = 0;
for (;i<data.prompts.length;i++) {
var field = data.prompts[i];
var row = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
var loginButton = $('<a href="#"></a>',{style: "padding: 10px"}).appendTo(row).click(function() {
document.location = field.url;
});
if (field.image) {
$("<img>",{src:field.image}).appendTo(loginButton);
} else if (field.label) {
var label = $('<span></span>').text(field.label);
if (field.icon) {
$('<i></i>',{class: "fa fa-2x "+field.icon, style:"vertical-align: middle"}).appendTo(loginButton);
label.css({
"verticalAlign":"middle",
"marginLeft":"8px"
});
}
label.appendTo(loginButton);
}
loginButton.button();
}
}
dialog.dialog("open");
}
if (opts.cancelable) {
$("#node-dialog-login-cancel").button().click(function( event ) {
$("#node-dialog-login").dialog('destroy').remove();
});
}
var loginImageSrc = data.image || "red/images/node-red-256.png";
$("#node-dialog-login-image").load(function() {
dialog.dialog("open");
}).attr("src",loginImageSrc);
}
});
}
function logout() {
var tokens = RED.settings.get("auth-tokens");
var token = tokens?tokens.access_token:"";
$.ajax({
url: "auth/revoke",
type: "POST",
data: {token:RED.settings.get("auth-tokens").access_token},
success: function() {
RED.settings.remove("auth-tokens");
data: {token:token}
}).done(function(data,textStatus,xhr) {
RED.settings.remove("auth-tokens");
if (data && data.redirect) {
document.location.href = data.redirect;
} else {
document.location.reload(true);
}
}).fail(function(jqXHR,textStatus,errorThrown) {
if (jqXHR.status === 401) {
document.location.reload(true);
} else {
console.log(textStatus);
}
})
}
function updateUserMenu() {
$("#usermenu-submenu li").remove();
$("#btn-usermenu-submenu li").remove();
if (RED.settings.user.anonymous) {
RED.menu.addItem("btn-usermenu",{
id:"usermenu-item-login",
label:"Login",
label:RED._("menu.label.login"),
onselect: function() {
RED.user.login({cancelable:true},function() {
RED.settings.load(function() {
RED.notify("Logged in as "+RED.settings.user.username,"success");
RED.notify(RED._("user.loggedInAs",{name:RED.settings.user.username}),"success");
updateUserMenu();
});
});
@@ -154,31 +199,36 @@ RED.user = (function() {
});
RED.menu.addItem("btn-usermenu",{
id:"usermenu-item-logout",
label:"Logout",
label:RED._("menu.label.logout"),
onselect: function() {
RED.user.logout();
}
});
}
}
function init() {
if (RED.settings.user) {
if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu")) {
$('<li><a id="btn-usermenu" class="button hide" data-toggle="dropdown" href="#"><i class="fa fa-user"></i></a></li>')
var userMenu = $('<li><a id="btn-usermenu" class="button hide" data-toggle="dropdown" href="#"></a></li>')
.prependTo(".header-toolbar");
if (RED.settings.user.image) {
$('<span class="user-profile"></span>').css({
backgroundImage: "url("+RED.settings.user.image+")",
}).appendTo(userMenu.find("a"));
} else {
$('<i class="fa fa-user"></i>').appendTo(userMenu.find("a"));
}
RED.menu.init({id:"btn-usermenu",
options: []
});
updateUserMenu();
}
}
}
return {
init: init,

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2013 IBM Corp.
* 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.
@@ -14,6 +14,22 @@
* limitations under the License.
**/
RED.validators = {
number: function(){return function(v) { return v!=='' && !isNaN(v);}},
regex: function(re){return function(v) { return re.test(v);}}
number: function(blankAllowed){return function(v) { return (blankAllowed&&(v===''||v===undefined)) || (v!=='' && !isNaN(v));}},
regex: function(re){return function(v) { return re.test(v);}},
typedInput: function(ptypeName,isConfig) { return function(v) {
var ptype = $("#node-"+(isConfig?"config-":"")+"input-"+ptypeName).val() || this[ptypeName];
if (ptype === 'json') {
try {
JSON.parse(v);
return true;
} catch(err) {
return false;
}
} else if (ptype === 'msg' || ptype === 'flow' || ptype === 'global' ) {
return RED.utils.validatePropertyExpression(v);
} else if (ptype === 'num') {
return /^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(v);
}
return true;
}}
};

8
editor/sass/ace.scss Normal file
View File

@@ -0,0 +1,8 @@
.ace_gutter {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.ace_scroller {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.

69
editor/sass/colors.scss Normal file
View File

@@ -0,0 +1,69 @@
/**
* 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.
**/
$background-color: #f3f3f3;
$form-placeholder-color: #bbbbbb;
$form-text-color: #444;
$form-input-focus-color: rgba(85,150,230,0.8);
$form-input-border-color: #ccc;
$form-input-border-selected-color: #aaa;
$node-selected-color: #ff7f0e;
$port-selected-color: #ff7f0e;
$link-color: #888;
$link-link-color: #ccc;
$link-link-active-color: #ff7f0e;
$link-subflow-color: #bbb;
$link-unknown-color: #f00;
$primary-border-color: #bbbbbb;
$secondary-border-color: #dddddd;
$tab-background-active: #fff;
$tab-background-inactive: #f0f0f0;
$tab-background-hover: #ddd;
$palette-header-background: #f3f3f3;
$workspace-button-background: #fff;
$workspace-button-background-hover: #ddd;
$workspace-button-background-active: #efefef;
$workspace-button-color: #888;
$workspace-button-color-disabled: #ccc;
$workspace-button-color-focus: #999;
$workspace-button-color-hover: #666;
$workspace-button-color-active: #666;
$workspace-button-color-selected: #AAA;
$workspace-button-toggle-color: #999;
$workspace-button-toggle-color-selected: #888;
$workspace-button-toggle-color-disabled: #ddd;
$workspace-button-color-focus-outline: rgba(85,150,230,0.2);
$typedInput-button-background: #efefef;
$typedInput-button-background-hover: #ddd;
$typedInput-button-background-active: #ddd;
$editor-button-color-primary: #eee;
$editor-button-background-primary: #AD1625;
$editor-button-background-primary-hover: #6E0A1E;
$editor-button-color: #999;
$editor-button-background: #fff;
$shade-color: rgba(200,200,200,0.5);

265
editor/sass/debug.scss Normal file
View File

@@ -0,0 +1,265 @@
/**
* 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.
**/
.debug-window {
padding:0;
margin:0;
background: #fff;
line-height: 20px;
}
.debug-window .debug-message-payload {
font-size: 14px;
}
.debug-content {
position: absolute;
top: 43px;
bottom: 0px;
left:0px;
right: 0px;
overflow-y: scroll;
}
.debug-filter-box {
position:absolute;
top: 42px;
left: 0px;
right: 0px;
z-index: 20;
background: #f9f9f9;
padding: 10px;
border-bottom: 1px solid #ddd;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
}
.debug-filter-row {
.red-ui-nodeList {
margin: 10px 0;
}
}
.debug-message {
position: relative;
border-bottom: 1px solid #eee;
border-left: 8px solid #eee;
border-right: 8px solid #eee;
padding: 2px;
&>.debug-message-meta .debug-message-tools {
display: none;
}
&.debug-message-hover {
border-right-color: #999;
&>.debug-message-meta .debug-message-tools {
display: inline-block;
}
}
.debug-message-row {
.debug-message-tools-pin {
display: none;
}
&.debug-message-row-pinned .debug-message-tools-pin {
display: inline-block;
}
&:hover {
background: #f3f3f3;
&>.debug-message-tools {
.debug-message-tools-copy {
display: inline-block;
}
.debug-message-tools-pin {
display: inline-block;
}
}
}
}
}
.debug-message-meta .debug-message-tools {
.editor-button-small {
font-size: 11px;
}
}
.debug-message-tools {
.button-group:not(:last-child) {
margin-right: 3px;
}
.editor-button-small {
height: 16px;
line-height: 14px;
font-size: 8px;
border-radius: 1px;
padding: 0 3px;
min-width: 18px;
i.fa-terminal {
// terminal icon is a bit thin, so darken its color for better contrast
color: darken($editor-button-color, 30%) !important;
}
&.selected {
color: darken($workspace-button-color-selected, 10%) !important;
background: darken($workspace-button-background-active,10%);
}
}
}
.debug-message-meta {
background: #fff;
font-size: 10px;
color: #777;
}
.debug-message-date {
padding: 1px 5px 1px 1px;
}
.debug-message-topic {
display: block;
color: #a66;
}
.debug-message-name {
padding: 1px 5px;
color: #777;
}
.debug-message-tools {
position: absolute;
top: 3px;
right: 1px;
.debug-message-tools-copy {
display: none;
}
}
.debug-message-payload {
display: block;
padding: 2px;
background: #fff;
}
.debug-message-level-log {
border-left-color: #eee;
border-right-color: #eee;
}
.debug-message-level-30 {
border-left-color: #ffdf9d;
border-right-color: #ffdf9d;
}
.debug-message-level-20 {
border-left-color: #f99;
border-right-color: #f99;
}
.debug-message-object-entry {
position: relative;
padding-left: 15px;
}
.debug-message-element {
color: #333;
font-family: Menlo, monospace;
font-size: 12px !important;
line-height: 1.3em;
}
.debug-message-object-key {
color: #792e90;
}
.debug-message-object-value {
}
.debug-message-object-handle {
color: #666;
font-size: 1em;
width: 1em;
text-align: center;
transition: transform 0.1s ease-in-out;
transform: rotate(90deg);
}
.debug-message-element:not(.debug-message-top-level)>.debug-message-expandable>.debug-message-object-handle {
margin-left: -1em;
}
.debug-message-object-entry>.debug-message-expandable>.debug-message-object-handle {
margin-left: -1em;
}
.debug-message-object-entry.collapsed>span>.debug-message-object-handle {
transform: rotate(0deg);
}
.debug-message-element.collapsed>span>.debug-message-object-handle {
transform: rotate(0deg);
}
.debug-message-object-entry.collapsed > .debug-message-object-entry {
display:none;
}
.debug-message-element.collapsed .debug-message-object-entry {
display:none;
}
.debug-message-element:not(.collapsed)>.debug-message-expandable>.debug-message-object-value>.debug-message-object-header {
display:none;
}
.debug-message-element.collapsed .debug-message-buffer-opts {
display: none;
}
.debug-message-element.collapsed .debug-message-object-type-header {
display:none;
}
.debug-message-object-entry pre {
font-family: Menlo, monospace;
font-size: 12px;
line-height: 1.4em;
margin: 0 0 0 -1em;
}
.debug-message-type-other { color: #2033d6; }
.debug-message-type-string { color: #b72828; }
.debug-message-type-null { color: #666; font-style: italic;}
.debug-message-type-meta { color: #666; font-style: italic;}
.debug-message-type-number { color: #2033d6; };
.debug-message-type-number-toggle { cursor: pointer;}
.debug-message-row {
display: block;
padding: 4px 2px 2px;
position: relative;
&.debug-message-row-pinned {
background: #f6f6f6;
}
}
.debug-message-expandable {
cursor: pointer;
}
.debug-message-expandable:hover .debug-message-object-handle {
color: #b72828 !important;
}
.debug-message-buffer-opts a {
font-size: 9px;
color: #bbb;
border: 1px solid #bbb;
border-radius: 2px;
padding: 2px 5px;
margin-left: 5px;
}
.debug-message-buffer-opts a:hover {
text-decoration: none;
color: #999;
border: 1px solid #999;
background: #f3f3f3;
}
.debug-message-buffer-raw > .debug-message-string-rows {
display: none;
}
.debug-message-buffer-string > .debug-message-array-rows {
display: none;
}
.debug-message-type-string-swatch {
display: inline-block;
width: 1.1em;
height: 0.9em;
vertical-align: middle;
border-radius: 3px;
margin: 0 4px;
}

536
editor/sass/diff.scss Normal file
View File

@@ -0,0 +1,536 @@
/**
* 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.
**/
#node-dialog-view-diff {
.red-ui-editableList-container {
border-radius:1px;
padding:0;
background: #f9f9f9;
}
#node-dialog-view-diff-diff {
position: absolute;
top:80px;
bottom:10px;
left:10px;
right:10px;
li {
background: #f9f9f9;
padding: 0px;
border: none;
min-height: 0;
}
}
.red-ui-editableList-item-content {
padding: 5px;
// padding-bottom: 5px;
}
}
#node-dialog-view-diff-headers {
position: absolute;
left:237px;
right:18px;
top: 55px;
height: 25px;
div {
height: 25px;
display: inline-block;
box-sizing: border-box;
width: 50%;
background: #f9f9f9;
text-align: center;
border-top: 1px solid $secondary-border-color;
border-color:$secondary-border-color;
border-left: 1px solid $secondary-border-color;
}
div:last-child {
border-right: 1px solid $secondary-border-color;
}
}
.node-diff-toolbar {
position:absolute;
top:0;
left:0;
right:0;
height: 43px;
box-sizing: border-box;
color: #666;
text-align: right;
padding: 8px 10px;
background: #f3f3f3;
border-bottom: 1px solid $secondary-border-color;
white-space: nowrap;
}
.node-diff-tab {
background: #fff;
border: 1px solid #ddd;
border-radius: 1px;
overflow: hidden;
&.collapsed {
.node-diff-tab-title .node-diff-chevron {
transform: rotate(-90deg);
}
.node-diff-node-entry {
display: none;
}
}
}
.node-diff-tab-stats {
font-size: 0.9em;
}
.node-diff-chevron {
display: inline-block;
width: 15px;
text-align: center;
margin-left: 3px;
transition: transform 0.1s ease-in-out;
}
.node-diff-node-entry {
margin-left: 20px;
font-size: 0.9em;
&:first-child {
border-top: 1px solid $secondary-border-color;
}
&:not(:last-child) {
border-bottom: 1px solid $secondary-border-color;
}
&.collapsed {
.node-diff-chevron {
transform: rotate(-90deg);
}
.node-diff-node-entry-properties {
display: none;
}
}
&:not(.collapsed) {
.node-diff-node-entry-cell:not(:first-child) {
//display: none;
}
.node-diff-node-entry-cell:first-child {
//width: 100%
}
}
table {
border-collapse: collapse;
table-layout:fixed;
width: calc(100% - 20px);
margin-left: 20px;
}
col:first-child {
width: 180px;
}
col:not(:first-child) {
width: 100%;
}
td, th {
border-top: 1px solid #f3f3f3;
border-left: 1px solid $secondary-border-color;
&:first-child {
border-left: none;
}
padding: 0 0 0 3px;
text-align: left;
overflow-x: auto;
}
tr {
vertical-align: top;
&:first-child td {
white-space:nowrap;
overflow:hidden;
}
&:hover {
background: #f9f9f9;
}
}
td {
.node-diff-status {
margin-left: 0;
}
}
tr:not(.node-diff-property-header) {
.node-diff-status {
width: 12px;
margin-left: 0;
margin-top: 0;
margin-bottom: 0;
margin-right: 5px;
}
}
}
.node-diff-three-way {
.node-diff-node-entry-cell {
width: calc((100% - 220px) / 2);
&:first-child {
width: 220px;
}
}
col:not(:first-child) {
width:50%;
}
.node-diff-node-entry {
.node-diff-node-entry-cell {
width: calc((100% + 20px - 220px) / 2);
&:first-child {
width: 200px;
}
}
}
}
.node-diff-column {
display:inline-block;
height:100%;
width:50%;
box-sizing: border-box;
white-space:nowrap;
overflow: hidden;
&:first-child {
border-right: 1px solid $secondary-border-color
}
}
.node-diff-tab-title {
cursor: pointer;
padding: 0;
// background: #f6f6f6;
&:hover {
background: #f9f9f9;
}
}
.node-diff-tab-title-meta {
vertical-align: middle;
display: inline-block;
padding-top: 2px;
}
.node-diff-node-entry-header {
cursor: pointer;
&:hover {
background: #f9f9f9;
}
}
.node-diff-node-entry-node {
vertical-align: middle;
display: inline-block;
margin: 5px;
width: 18px;
height: 15px;
background: #ddd;
border-radius: 2px;
border: 1px solid #999;
background-position: 5% 50%;
background-repeat: no-repeat;
background-size: contain;
position: relative;
.palette_icon {
background-position: 49% 50%;
width: 15px;
}
.palette_icon_container {
width: 18px;
}
}
.node-diff-tab-empty {
.node-diff-chevron i {
display: none;
}
.node-diff-tab-title {
cursor: default;
&:hover {
background: none;
}
}
}
.node-diff-node-deleted {
//background: #fadddd;
cursor: default !important;
.node-diff-status {
color: #f80000;
}
.node-diff-node-entry-node {
opacity: 0.5;
}
.node-diff-node-description {
opacity: 0.5;
text-decoration: line-through;
}
}
.node-diff-node-added {
//background: #eefaee;
cursor: default !important;
.node-diff-status {
color: #009900;
}
}
.node-diff-node-moved {
//background: #eefaee;
.node-diff-status {
color: #3f81b3;
}
}
.node-diff-node-changed {
//background: #fff2ca;
.node-diff-status {
color: #f89406;
}
}
.node-diff-node-unchanged {
//background: #fff2ca;
.node-diff-status {
color: #bbb;
}
}
.node-diff-node-conflict {
.node-diff-status {
color: #9b45ce;
}
}
.node-diff-node-entry-title {
display: inline-block;
.node-diff-status {
margin-left: 15px;
}
}
.node-diff-node-entry-properties {
margin: 0;
color: #666;
}
.node-diff-status {
display: inline-block;
height: 20px;
margin-left: 5px;
vertical-align: top;
margin-top: 6px;
margin-bottom: 6px;
text-align: center;
}
.node-diff-element {
display: inline-block;
width: calc(100% - 20px);
}
.node-diff-node-description {
color: $form-text-color;
margin-right: 5px;
padding-top: 5px;
display: inline-block;
&:after {
content: "";
display: table;
clear: both;
}
}
.node-diff-node-meta {
float: right;
//font-size: 0.9em;
color: #999;
margin-top: 7px;
margin-right: 10px;
}
.node-diff-count { color: #999}
.node-diff-added { color: #009900}
.node-diff-deleted { color: #f80000}
.node-diff-changed { color: #f89406}
.node-diff-conflicted { color: purple}
.node-diff-node-entry-cell {
display: inline-block;
vertical-align: top;
box-sizing: border-box;
width: calc( (100% - 20px) / 2);
height: 32px;
border-left: 1px solid $secondary-border-color;
padding-top: 2px;
white-space: nowrap;
overflow: hidden;
position: relative;
}
.node-diff-empty {
background: #f3f3f3;
background: repeating-linear-gradient(
20deg,
#fff, #fff 5px,
#f6f6f6 5px,
#f6f6f6 10px
);
}
.node-diff-node-entry-cell:first-child {
border-left: none;
}
.node-diff-property-cell-label {
margin-left: 20px;
vertical-align: top;
box-sizing: border-box;
padding-left: 8px;
width: 120px;
}
.node-diff-property-wires {
display: inline-block;
.node-diff-node-entry-node {
width: 18px;
height: 15px;
}
.palette_icon_container {
width: 18px;
}
.palette_icon {
width: 15px;
}
ul,li,ol {
background: none !important;
}
ul {
vertical-align: middle;
display: inline-block;
margin-left: 5px;
}
li {
list-style-type: none !important;
}
ol {
font-size: 0.9em;
margin: 0;
& > span {
vertical-align: middle;
display: inline-block;
width: 30px;
text-align: center;
}
& > li:not(:last-child) {
border-bottom: 1px solid #999;
}
}
}
.node-diff-node-props .node-diff-node-entry-cell:first-child {
padding: 6px 0px;
span:not(.node-diff-chevron) {
margin-left: 5px;
}
}
.node-diff-property-cell {
// vertical-align: top;
// display:inline-block;
//
// box-sizing: border-box;
// padding: 1px 5px;
//min-height: 30px;
&.node-diff-node-changed {
background: #fff2e1 !important;
}
&.node-diff-node-conflict {
background: #ffdad4 !important;
}
}
.node-diff-selectbox {
position: absolute;
top:0;
right:0;
bottom:0;
width: 35px;
text-align: center;
border-left: 1px solid #eee;
margin:0;
input {
margin-top: 8px;
}
&:hover {
background: #f3f3f3;
}
}
.node-diff-node-entry-conflict.node-diff-select-remote {
.node-diff-node-remote {
background: #e7ffe3;
label {
border-left-color: #b8daad;
}
}
.node-diff-node-local {
background: #ffe1e1;
label {
border-left-color: #e4bcbc;
}
}
}
.node-diff-node-entry-conflict.node-diff-select-local {
.node-diff-node-local {
background: #e7ffe3;
label {
border-left-color: #b8daad;
}
}
.node-diff-node-remote {
background: #ffe1e1;
label {
border-left-color: #e4bcbc;
}
}
}
#node-dialog-confirm-deploy {
.node-dialog-confirm-row {
text-align: left; padding-top: 10px;
}
ul {
font-size: 0.9em;
width: 400px;
margin: 10px auto;
text-align: left;
}
.node-dialog-confirm-conflict-row {
img {
vertical-align:middle;
height: 30px;
margin-right: 10px;
}
i {
vertical-align:middle;
text-align: center;
font-size: 30px;
width: 30px;
margin-right: 10px;
}
div {
vertical-align: middle;
width: calc(100% - 60px);
display:inline-block;
}
}
}
#node-diff-toolbar-resolved-conflicts .node-diff-status {
margin:0;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -23,6 +23,7 @@
width: 100%;
height: 100%;
display: none;
z-index:100;
}
#dropTarget div {
display: table-cell;
@@ -34,4 +35,3 @@
#dropTarget div i {
font-size: 80px;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -14,8 +14,153 @@
* limitations under the License.
**/
.dialog-form, #dialog-form, #dialog-config-form {
#editor-stack {
position: absolute;
margin: 0;
top: 0;
bottom: 0px;
right: 323px;
width: 0;
z-index: 5;
}
.editor-tray {
position:absolute;
margin: 0;
top: 0;
//min-width: 500px;
width: auto;
right: -1000px;
bottom: 0;
background: #fff;
border-left: 1px solid $secondary-border-color;
border-bottom: 1px solid $primary-border-color;
box-sizing: content-box;
}
.editor-tray.open {
right: 0;
}
.editor-tray-body-wrapper {
width: 100%;
box-sizing: border-box;
overflow: auto;
}
.editor-tray-body {
position: relative;
box-sizing: border-box;
padding: 0.1px; // prevent margin collapsing
.dialog-form,#dialog-form, #node-config-dialog-edit-form {
margin: 20px;
height: calc(100% - 40px);
}
}
.editor-tray-content {
overflow: auto;
}
.editor-tray-header {
@include disable-selection;
position: relative;
box-sizing: border-box;
font-weight: bold;
border-bottom: 1px solid $secondary-border-color;
background: $palette-header-background;
&:after {
content: "";
display: table;
clear: both;
}
}
.editor-tray-footer {
@include component-footer;
height: 35px;
button {
@include editor-button;
padding: 3px 7px;
font-size: 11px;
}
}
.editor-tray-toolbar {
text-align: right;
padding: 6px;
button {
@include editor-button;
&.toggle {
@include workspace-button-toggle;
}
}
}
.editor-tray-titlebar {
border-bottom: 1px solid $secondary-border-color;
padding: 8px;
}
.editor-tray-breadcrumbs {
list-style-type: none;
margin: 0;
padding:0;
li {
display: inline-block;
padding:0;
margin:0;
&:not(:last-child) {
color: $editor-button-color;
font-weight: normal;
&:after {
display: inline-block;
content: '>';
margin: 0 5px;
}
}
}
}
.editor-tray-resize-handle {
position: absolute;
top: 0px;
bottom: 0px;
width: 7px;
left: -9px;
background: $background-color url(images/grip.png) no-repeat 50% 50%;
cursor: col-resize;
border-left: 1px solid $primary-border-color;
box-shadow: -1px 0 6px rgba(0,0,0,0.1);
&.editor-tray-resize-maximised {
background: $background-color;
cursor: default;
}
}
.editor-tray-resize-button {
@include workspace-button;
display: block;
height: 37px;
line-height: 35px;
border: none;
border-bottom: 1px solid $secondary-border-color;
margin: 0;
background: $background-color;
color: $workspace-button-color;
}
#palette-shade, #editor-shade, #header-shade, #sidebar-shade {
@include shade;
z-index: 2;
}
#sidebar-shade {
left: -8px;
top: -1px;
bottom: -1px;
}
.dialog-form,#dialog-form, #node-config-dialog-edit-form {
height: 100%;
}
@@ -23,48 +168,33 @@
border-color: rgb(214, 97, 95) !important;
}
.leftButton {
margin-right: 200px !important;
}
.form-row {
clear: both;
margin-bottom:10px;
color: $form-text-color;
margin-bottom:12px;
}
.form-row label {
display: inline-block;
width: 100px;
}
.form-row input {
.form-row input, .form-row div[contenteditable="true"] {
width:70%;
}
input.input-append-left {
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
}
button.input-append-right {
border-top-left-radius: 0px !important;
border-bottom-left-radius: 0px !important;
border-top-right-radius: 4px !important;
border-bottom-right-radius: 4px !important;
margin-left: -1px !important;
padding-left: 4px !important;
padding-right: 4px !important;
}
.form-tips {
background: lightgoldenrodyellow;
font-size: 12px;
background: #ffe;
padding: 8px;
border-radius: 5px;
border: 1px solid #999;
border-radius: 2px;
border: 1px solid $secondary-border-color;
max-width: 450px;
}
.form-tips code {
border: none;
padding: auto;
}
.form-tips a {
text-decoration: underline;
}
.node-text-editor {
border:1px solid #ccc;
@@ -74,3 +204,135 @@ button.input-append-right {
font-family: monospace !important;
}
.editor-button {
@include workspace-button;
height: 34px;
line-height: 32px;
font-size: 13px;
border-radius: 4px;
padding: 0 10px;
&.toggle {
@include workspace-button-toggle;
}
}
.editor-button-small {
height: 20px;
line-height: 18px;
font-size: 10px;
border-radius: 2px;
padding: 0 5px;
}
#node-config-dialog-scope-container {
cursor: auto;
float: right;
font-size: 12px !important;
line-height: 35px;
}
#node-config-dialog-scope-warning {
display: inline-block;
margin-right: 5px;
color: #AD1625;
vertical-align: middle;
}
#node-config-dialog-scope {
margin: 1px 0 0 0;
padding: 0;
height: 22px;
width: 200px;
}
#node-config-dialog-user-count {
vertical-align: middle;
display:inline-block;
margin-right: 20px;
float:left;
font-size: 12px;
line-height: 35px;
}
.node-input-expression-editor #dialog-form {
margin: 0;
height: 100%;
.red-ui-panel {
&:first-child {
padding: 20px 20px 0;
}
&:last-child {
padding-bottom: 20px;
}
}
}
.node-input-expression-tab-content {
position: relative;
padding: 0 20px;
}
#node-input-expression-help {
position: absolute;
top: 35px;
left:0;
right: 0;
bottom:0;
padding: 0 20px;
overflow: auto;
box-sizing: border-box;
}
#node-input-expression-panel-info {
& > .form-row {
margin: 0;
& > div:first-child {
margin-top: 10px;
}
}
}
.node-input-expression-legacy, .node-input-buffer-type {
font-size: 0.8em;
float: left;
cursor: pointer;
border: 1px solid white;
padding: 2px 5px;
border-radius: 2px;
&:hover {
border-color: $form-input-border-color;
}
}
.node-input-buffer-type {
float: none;
text-align: right;
}
#clipboard-hidden {
position: absolute;
top: -3000px;
}
.node-label-form-row {
margin: 5px 0;
label {
margin-right: 20px;
text-align: right;
width: 30px;
}
button {
margin-left: 10px;
}
input {
width: calc(100% - 100px);
}
}
.node-label-form-none {
span {
padding-left: 50px;
width: 100px;
color: #999;
}
}
.ace_read-only {
background: #eee !important;
.ace_cursor {
color: transparent !important;
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -19,7 +19,7 @@
}
.lasso {
stroke-width: 2px;
stroke-width: 1px;
stroke: #ff7f0e;
fill: rgba(20,125,255,0.1);
stroke-dasharray: 10 5;
@@ -49,10 +49,6 @@
margin-left: 20px;
}
#workspace {
@include component-border;
}
.node_label_italic {
font-style: italic;
}
@@ -90,7 +86,7 @@
.node {
stroke: #999;
cursor: move;
stroke-width: 2;
stroke-width: 1;
}
.node_unknown {
stroke-dasharray:10,4;
@@ -116,11 +112,11 @@
.node_button {
fill: inherit;
}
.port {
stroke: #999;
stroke-width: 2;
stroke-width: 1;
fill: #ddd;
cursor: crosshair;
}
@@ -133,7 +129,6 @@
fill-opacity: 0.5;
}
.node_error {
stroke: #ff0000;
stroke-width: 2;
@@ -152,26 +147,54 @@
pointer-events: none;
-webkit-touch-callout: none;
@include disable-selection;
}
.node_invalid {
stroke: #ff0000;
}
.node_selected {
stroke: #ff7f0e !important;
stroke-width: 2;
stroke: $node-selected-color !important;
}
.node_highlighted {
border-color: #dd1616 !important;
border-style: dashed !important;
stroke: #dd1616;
stroke-width: 3;
stroke-width: 2;
stroke-dasharray: 10, 4;
}
.node_hovered {
}
.port_hovered {
stroke: #ff7f0e;
fill: #ff7f0e;
.node_subflow .node {
stroke-dasharray:8, 3;
}
.node_quickadd * {
stroke-dasharray: 12,3;
}
.node_status_label {
@include disable-selection;
stroke-width: 0;
fill: #888;
font-size:9pt;
stroke:#000;
text-anchor:start;
}
.port_hovered {
stroke: $port-selected-color;
fill: $port-selected-color;
}
.port_quick_link {
stroke: $port-selected-color;
fill: $port-selected-color;
}
.subflowport {
stroke-dasharray: 5,5;
fill: #eee;
@@ -179,35 +202,53 @@
}
.drag_line {
stroke: #ff7f0e;
stroke-width: 5;
stroke: $node-selected-color;
stroke-width: 3;
fill: none;
pointer-events: none;
}
.drag_line_hidden {
stroke: #ff7f0e;
stroke: $node-selected-color;
stroke-width: 0;
pointer-events: none;
fill: none;
}
.link_line {
stroke: #7f7f7f;
stroke-width: 4;
stroke: $link-color;
stroke-width: 3;
fill: none;
pointer-events: none;
}
.link_subflow {
stroke: #bbb;
.link_link {
stroke-width: 2;
stroke-dasharray: 10,5;
stroke-width: 3;
stroke: $link-link-color;
fill: none;
stroke-dasharray: 15,2;
pointer-events: none;
}
.link_port {
fill: #fff;
stroke: $link-link-color;
stroke-width: 1;
}
.link_group_active .link_port {
stroke: $link-link-active-color;
}
.link_group:hover {
cursor: pointer;
}
.link_subflow {
stroke: $link-subflow-color;
stroke-dasharray: 10,5;
stroke-width: 2;
}
.link_outline {
stroke: #fff;
stroke-width: 6;
stroke-width: 4;
cursor: crosshair;
fill: none;
pointer-events: none;
@@ -215,17 +256,41 @@
.link_background {
stroke: #fff;
opacity: 0;
stroke-width: 25;
stroke-width: 20;
cursor: crosshair;
fill: none;
}
.link_splice > .link_line {
stroke-dasharray: 15,8;
}
g.link_selected path.link_line {
stroke: #ff7f0e;
stroke: $node-selected-color;
}
g.link_unknown path.link_line {
stroke: #f00;
stroke: $link-unknown-color;
stroke-width: 2;
stroke-dasharray: 10, 4;
}
@keyframes port_tooltip_fadeIn { from { opacity:0; } to { opacity:1; } }
.port_tooltip {
opacity:0;
animation: 0.1s ease-in 0s 1 normal forwards port_tooltip_fadeIn;
pointer-events: none;
path {
fill: white;
stroke: #999;
stroke-width: 1;
}
}
.port_tooltip_label {
stroke-width: 0;
fill: #666;
font-size: 12px;
pointer-events: none;
-webkit-touch-callout: none;
@include disable-selection;
}

1089
editor/sass/forms.scss Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -47,7 +47,7 @@ span.logo {
font-size: 30px;
line-height: 30px;
text-decoration: none;
span {
vertical-align: middle;
font-size: 16px !important;
@@ -55,14 +55,14 @@ span.logo {
img {
height: 18px;
}
a {
color: inherit;
&:hover {
text-decoration: none;
}
}
}
.header-toolbar {
@@ -70,13 +70,13 @@ span.logo {
margin: 0;
list-style: none;
float: right;
> li {
display: inline-block;
padding: 0;
margin: 0;
position: relative;
}
}
@@ -97,20 +97,21 @@ span.logo {
vertical-align: middle;
border-left: 2px solid #000;
border-right: 2px solid #000;
&:hover {
border-color: $headerMenuItemHover;
}
}
.button-group {
#header .button-group {
display: inline-block;
margin: auto 15px;
vertical-align: middle;
clear: both;
}
.button-group > a {
#header .button-group > a {
display: inline-block;
position: relative;
float: left;
line-height: 22px;
font-size: 14px;
@@ -122,30 +123,44 @@ span.logo {
.deploy-button {
background: $deployButton;
color: #eee !important;
&:hover {
background: $deployButtonHover;
}
&:active {
background: $deployButtonActive;
color: #ccc !important;
}
}
.deploy-button-spinner {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
text-align: center;
img {
opacity: 0.8;
height: 100%;
}
}
#btn-deploy {
padding: 4px 12px;
&.disabled {
cursor: default;
background: $deployDisabledButton;
color: #999 !important;
img {
.deploy-button-content>img {
opacity: 0.3;
}
&+ #btn-deploy-options {
background: $deployDisabledButton;
color: #ddd;
@@ -157,8 +172,8 @@ span.logo {
background: $deployDisabledButton;
}
}
img {
.deploy-button-content>img {
margin-right: 8px;
}
}
@@ -265,3 +280,12 @@ span.logo {
color: #fff;
}
#btn-usermenu .user-profile {
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
display: inline-block;
width: 40px;
height: 35px;
vertical-align: middle;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -14,6 +14,18 @@
* limitations under the License.
**/
.ui-widget {
font-size: 14px !important;
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
}
.ui-widget input, .ui-widget div[contenteditable="true"], .ui-widget select, .ui-widget textarea, .ui-widget button {
font-size: 14px !important;
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
}
.ui-widget input, .ui-widget div[contenteditable="true"] {
box-shadow: none;
}
/* jQuery Theme overrides */
.ui-tabs .ui-tabs-panel {
padding: 0px;
@@ -27,23 +39,25 @@
.ui-dialog {
border-radius: 1px;
border: 1px solid #eee;
background: #fff;
padding: 0;
box-shadow: 2px 2px 12px rgba(0,0,0,0.2);
@include component-shadow;
}
.ui-dialog .ui-dialog-content {
padding: 25px 25px 10px 25px;
}
.ui-dialog .ui-dialog-title {
width: auto;
}
.ui-dialog .ui-dialog-titlebar {
padding: 10px;
background: #f0f0f0;
background: #f3f3f3;
border: none;
border-bottom: 2px solid #888;
border-bottom: 1px solid #999;
border-radius: 0;
}
.ui-corner-all {
border-radius: 2px;
border-radius: 1px;
}
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
background: #f3f3f3;
@@ -51,3 +65,80 @@
.ui-dialog-no-close .ui-dialog-titlebar-close {
display: none;
}
.ui-dialog-buttonset {
text-align: right;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
float: none;
}
.ui-dialog-buttonset button {
@include workspace-button;
font-size: 14px;
padding: 6px 14px;
margin-right: 8px;
color: $editor-button-color;
background: $editor-button-background;
&.leftButton {
float: left;
margin-top: 7px;
}
&:not(.leftButton):not(:last-child) {
margin-right: 16px;
}
&.primary {
border-color: $editor-button-background-primary;
color: $editor-button-color-primary !important;
background: $editor-button-background-primary;
&:not(.disabled):hover {
border-color: $editor-button-background-primary-hover;
background: $editor-button-background-primary-hover;
color: $editor-button-color-primary !important;
}
&.disabled {
border-color: $form-input-border-color;
color: $workspace-button-color-disabled !important;
background: $editor-button-background;
}
}
&.disabled {
background: none;
}
&.disabled {
background: none;
}
&.disabled:focus {
outline: none;
}
.ui-button-text {
padding: 0;
}
}
.ui-dialog .ui-dialog-buttonpane {
padding: .3em 1em .5em 1em;
}
.ui-spinner {
border-radius: 4px;
padding: 0;
border: 1px solid $form-input-border-color;
}
.ui-spinner input {
margin: 0 17px 0 0;
padding: 6px;
border: none;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
&:focus {
outline: none;
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -16,18 +16,112 @@
#keyboard-help-dialog {
font-size: 0.9em;
padding-top: 10px;
}
.keyboard-shortcuts {
padding: 10px;
#user-settings-tab-keyboard .red-ui-editableList-container {
border-radius: 0;
border: none;
padding: 0;
}
.keyboard-shortcuts td {
padding: 7px 5px;
margin-bottom: 10px;
white-space: pre;
.keyboard-shortcut-entry.keyboard-shortcut-list-header {
padding:0 5px 0 5px;
div {
color: #666 !important;
}
.red-ui-searchBox-container {
width: calc(100% - 20px);
}
.keyboard-shortcut-entry-scope {
text-align: center;
}
}
.keyboard-shortcuts td:first-child {
.keyboard-shortcut-list-header {
border-bottom: 1px solid $primary-border-color;
}
.keyboard-shortcut-list {
position: absolute;
top:30px;
left:10px;
right:10px;
bottom:10px;
li {
padding: 0;
.red-ui-editableList-item-content {
padding: 8px;
cursor: pointer;
}
}
li:hover {
background: #f6f6f6;
}
}
.keyboard-shortcut-entry {
div {
display: inline-block;
}
// white-space: nowrap;
select {
margin: 0;
width: calc(100% - 30px);
font-size: 0.9em;
margin-right: 5px;
}
}
.keyboard-shortcut-entry-key {
width:160px;
vertical-align: middle;
input {
margin:0;
width: calc(100% - 5px);
}
}
.keyboard-shortcut-entry-text {
vertical-align: middle;
width: calc(100% - 160px - 100px - 10px);
overflow: hidden;
i {
color: #ccc;
margin-right: 5px;
}
}
.keyboard-shortcut-entry-scope {
width:100px;
color: #999;
vertical-align: middle;
text-align: right;
padding-right: 10px;
}
.keyboard-shortcut-entry:not(.keyboard-shortcut-list-header) {
.keyboard-shortcut-entry-scope {
font-size: 0.8em;
}
}
.keyboard-shortcut-entry-unassigned {
color: #999;
.keyboard-shortcut-entry-key {
font-style: italic;
}
}
.keyboard-shortcut-entry-expanded {
.keyboard-shortcut-entry-key {
width: 150px;
}
.keyboard-shortcut-entry-text {
}
.keyboard-shortcut-entry-scope {
width: 110px;
}
span {
display: none;
}
}
.keyboard-shortcut-edit {
}
.help-key {
border: 1px solid #ddd;
@@ -37,4 +131,6 @@
font-family: Courier, monospace;
box-shadow: #999 1px 1px 1px;
}
.help-key-block {
white-space: nowrap;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -22,8 +22,207 @@
user-select: none;
}
@mixin component-border {
border: 1px solid #000;
border-radius: 3px;
@mixin enable-selection {
-webkit-user-select: auto;
-khtml-user-select: auto;
-moz-user-select: auto;
-ms-user-select: auto;
user-select: auto;
}
@mixin component-border {
border: 1px solid $primary-border-color;
box-sizing: border-box;
}
@mixin workspace-button {
@include disable-selection;
box-sizing: border-box;
display: inline-block;
color: $workspace-button-color !important;
background: $workspace-button-background;
border: 1px solid $form-input-border-color;
text-align: center;
margin:0;
text-decoration: none;
cursor:pointer;
&.disabled {
cursor: default;
color: $workspace-button-color-disabled !important;
}
&:hover, &:focus {
text-decoration: none;
}
&:not(.disabled):hover {
color: $workspace-button-color-hover !important;
background: $workspace-button-background-hover;
}
&:not(.disabled):focus {
color: $workspace-button-color-focus !important;
}
&:not(.disabled):active {
color: $workspace-button-color-active !important;
background: $workspace-button-background-active;
text-decoration: none;
}
&.selected:not(.disabled) {
color: $workspace-button-color-selected !important;
background: $workspace-button-background-active;
}
.button-group &:not(:first-child) {
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.button-group &:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.button-group-vertical & {
display: block;
min-width: 22px;
}
.button-group-vertical &:not(:first-child) {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.button-group-vertical &:not(:last-child) {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
&:focus {
outline: 1px solid $workspace-button-color-focus-outline;
}
}
.button-group-vertical {
display: inline-block;
vertical-align: middle;
}
.button-group:not(:last-child) {
margin-right: 10px;
}
@mixin workspace-button-toggle {
@include workspace-button;
color: $workspace-button-toggle-color !important;
background:$workspace-button-background-active;
margin-bottom: 1px;
&.selected:not(.disabled) {
color: $workspace-button-toggle-color-selected !important;
background: $workspace-button-background;
border-bottom-width: 2px;
border-bottom-color: $form-input-border-selected-color;
margin-bottom: 0;
cursor: default;
}
&.disabled {
color: $workspace-button-toggle-color-disabled !important;
}
}
@mixin editor-button {
@include workspace-button;
font-size: 14px;
padding: 6px 14px;
margin-right: 8px;
color: $editor-button-color !important;
background: $editor-button-background;
&.primary {
border-color: $editor-button-background-primary;
color: $editor-button-color-primary !important;
background: $editor-button-background-primary;
&.disabled, &.ui-state-disabled {
background: none;
color: $editor-button-color !important;
border-color: $form-input-border-color;
}
&:not(.disabled):not(.ui-button-disabled):hover {
border-color: $editor-button-background-primary-hover;
background: $editor-button-background-primary-hover;
color: $editor-button-color-primary !important;
}
}
&:not(.disabled):hover {
//color: $editor-button-color;
}
&.disabled {
background: none;
}
&.disabled:focus {
outline: none;
}
&.leftButton {
float: left;
margin-top: 1px;
}
&:not(.leftButton):not(:last-child) {
margin-right: 16px;
}
&.ui-state-disabled {
opacity: 1;
}
}
@mixin component-footer {
border-top: 1px solid $primary-border-color;
background: #f3f3f3;
text-align: right;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 25px;
line-height: 23px;
padding: 0 10px;
.button-group:not(:last-child) {
margin-right: 5px;
}
}
@mixin component-footer-button {
@include workspace-button;
font-size: 11px;
line-height: 17px;
width: 18px;
height: 18px;
&.text-button {
width: auto;
padding: 0 5px;
}
}
@mixin component-footer-button-toggle {
@include workspace-button-toggle;
font-size: 11px;
line-height: 17px;
height: 18px;
&.text-button {
width: auto;
padding: 0 5px;
}
}
@mixin component-shadow {
border: 1px solid $secondary-border-color;
box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
}
@mixin shade {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: $shade-color;
z-index: 5;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -14,10 +14,6 @@
* limitations under the License.
**/
.notification {
position: absolute;
}
#notifications {
z-index: 10000;
width: 500px;
@@ -26,7 +22,31 @@
position: absolute;
top: 1px;
}
#notifications .alert {
box-shadow: 0 0 1px 1px;
margin-bottom: 5px;
.notification {
box-sizing: border-box;
position: relative;
padding: 14px 18px;
margin-bottom: 4px;
box-shadow: 0 1px 1px 1px rgba(0,0,0, 0.15);
background-color: #fff;
color: #666;
border: 1px solid #325C80;
border-left-width: 16px;
overflow: hidden;
}
.notification a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
.notification-success {
border-color: #4B8400;
}
.notification-warning {
border-color: #D74108;
}
.notification-error {
border-color: #AD1625;
}

View File

@@ -0,0 +1,226 @@
/**
* 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.
**/
#user-settings-tab-palette {
height: 100%;
}
#palette-editor {
text-align: left;
position: absolute;
top: 0px;
right: 0;
bottom: 0;
left:0;
padding: 0;
box-sizing:border-box;
background: #fff;
.red-ui-editableList-container {
border: none;
border-radius: 0;
padding: 0px;
li {
// border: none;
// border-top: 1px solid $primary-border-color;
padding: 0px;
.disabled {
background: #f3f3f3;
.palette-module-name {
font-style: italic;
color: #aaa;
}
.palette-module-version {
color: #aaa;
}
}
.red-ui-editableList-item-content {
padding: 12px 16px;
}
&:last-child {
// border-bottom: 1px solid $primary-border-color;
}
}
}
.palette-editor-tab {
position:absolute;
top:35px;
left:0;
right:0;
bottom:0
}
.palette-editor-toolbar {
background: #f3f3f3;
box-sizing: border-box;
padding: 8px 10px;
border-bottom: 1px solid $primary-border-color;
text-align: right;
}
.palette-module-button-group {
position: absolute;
right: 0;
bottom: 0;
a {
margin-left: 5px;
}
}
.palette-module-shade {
@include shade;
text-align: center;
padding-top: 20px;
}
#palette-module-install-shade {
padding-top: 80px;
}
.palette-module-shade-status {
color: #666;
}
.palette-module-meta {
color: #666;
position: relative;
&.disabled {
color: #ccc;
}
.fa {
width: 15px;
text-align: center;
margin-right: 5px;
}
}
.palette-module-name {
white-space: nowrap;
@include enable-selection;
}
.palette-module-version, .palette-module-updated, .palette-module-link {
font-style:italic;
font-size: 0.8em;
@include enable-selection;
}
.palette-module-updated {
margin-left: 10px;
}
.palette-module-link {
margin-left: 5px;
}
.palette-module-description {
margin-left: 20px;
font-size: 0.9em;
color: #999;
}
.palette-module-link {
}
.palette-module-set-button-group {
}
.palette-module-count {
border-radius: 4px;
background: #eee;
padding: 2px 8px;
font-size: 12px;
}
.palette-module-content {
display: none;
padding: 10px 3px;
}
i.fa.palette-module-node-chevron {
width: 8px;
margin-right: 0;
transform: rotate(0deg);
transition: transform 0.2s ease-in-out;
}
.expanded {
i.fa.palette-module-node-chevron {
transform: rotate(90deg);
}
.palette-module-set-button {
background:#f3f3f3 !important;
}
}
.palette-module-set {
border:1px solid $secondary-border-color;
border-radius: 0;
padding: 5px;
position: relative;
&:not(:last-child) {
border-bottom: none;
}
&:first-child {
border-top-right-radius: 2px;
border-top-left-radius: 2px;
}
&:last-child {
border-bottom-right-radius: 2px;
border-bottom-left-radius: 2px;
}
}
.palette-module-type {
color: #666;
padding-left: 5px;
font-size: 0.9em;
@include enable-selection;
}
.palette-module-type-swatch {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 3px;
vertical-align: middle;
margin-right: 5px;
background: #fff;
border: 1px solid #fff;
}
.palette-module-set-button-group {
position: absolute;
right: 4px;
top: 4px;
}
.palette-module-set-disabled {
background: #eee;
.palette-module-type {
color: #999;
}
}
.palette-module-more {
padding: 0 !important;
margin-top: 10px;
margin-bottom: 10px;
background: $tab-background-inactive;
a {
display: block;
text-align: center;
padding: 12px 8px;
color: #AD1625;
&:hover {
text-decoration: none;
background: $tab-background-hover;
}
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2015 IBM Corp.
* 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.
@@ -17,99 +17,86 @@
#palette {
position: absolute;
top: 5px;
bottom: 10px;
left:10px;
top: 0px;
bottom: 0px;
left:0px;
background: #f3f3f3;
width: 170px;
width: 180px;
text-align: center;
@include disable-selection;
@include component-border;
transition: width 0.2s ease-in-out;
}
.palette-expanded {
& #palette {
width: 380px;
box-shadow: 1px 0 6px rgba(0,0,0,0.1);
}
& #workspace { left: 379px !important; }
& #palette-collapse-all { display: none; }
& #palette-expand-all { display: none; }
& #palette-container { display: none !important; }
& #palette-search { display: none !important; }
& #palette-edit { background: $workspace-button-background-active }
& #palette-editor { display: block !important }
}
.palette-scroll {
display: none;
position: absolute;
top: 0;
top: 35px;
right: 0;
bottom: 35px;
bottom: 25px;
left:0;
padding: 5px;
padding: 0;
overflow-y: auto;
box-sizing:border-box;
}
.palette-spinner {
padding-top: 40px;
#palette > .palette-spinner {
padding-top: 80px;
}
#palette-search {
position: absolute;
display: none;
bottom: 0;
left:0;
right:0;
.palette-search {
position: relative;
overflow: hidden;
background: #f3f3f3;
background: #ffffff;
text-align: center;
height: 35px;
padding: 3px;
border-top: 1px solid #999;
box-sizing:border-box;
}
#palette-search i.fa-search {
position: absolute;
pointer-events: none;
left: 4px;
top: 10px;
}
#palette-search i.fa-times {
position: absolute;
right: 6px;
top: 10px;
}
#palette-search-clear {
display: none;
color: #000;
}
#palette-search input {
border-radius: 0;
border: none;
width: 100%;
box-shadow: none;
-webkit-box-shadow: none;
padding: 3px 17px;
margin: 0px;
height: 30px;
border-bottom: 1px solid $primary-border-color;
box-sizing:border-box;
}
#palette-search input:focus {
border: none;
box-shadow: none;
-webkit-box-shadow: none;
#palette-footer {
@include component-footer;
}
.palette-button {
@include component-footer-button;
}
.palette-category {
border: 1px solid #999;
border-radius: 3px;
margin-bottom: 5px;
border-bottom: 1px solid #ccc;
}
.palette-content {
background: #fff;
border-top: 1px solid #aaa;
padding-bottom: 3px;
padding: 3px;
}
.palette-header {
background: #f3f3f3;
border-radius: 3px;
position: relative;
background: $palette-header-background;
cursor: pointer;
text-align: left;
padding: 1px;
padding: 9px;
font-weight: bold;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.palette-header i {
margin: 3px 4px 3px 3px;
margin: 3px 10px 3px 3px;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
@@ -126,23 +113,25 @@
clear: both;
}
.palette_label {
margin: 4px 0 4px 28px;
font-size: 13px;
margin: 4px 0 4px 32px;
line-height: 20px;
overflow: hidden;
text-align: center;
@include disable-selection;
}
.palette_label_right {
margin: 4px 28px 4px 0;
margin: 4px 32px 4px 0;
}
.palette_node {
display: block;
cursor:move;
font-size:13px;
background: #ddd;
margin: 10px auto;
height: 25px;
border-radius: 6px;
border: 2px solid #999;
border-radius: 5px;
border: 1px solid #999;
background-position: 5% 50%;
background-repeat: no-repeat;
width: 120px;
@@ -150,7 +139,7 @@
position: relative;
}
.palette_node:hover {
border-color: #ff7f0e;
border-color: $node-selected-color;
background-color: #eee;
}
.palette_port {
@@ -181,14 +170,14 @@
bottom:0;
left:0;
width: 30px;
border-right: 2px solid rgba(0,0,0,0.1);
border-right: 1px solid rgba(0,0,0,0.1);
background-color: rgba(0,0,0,0.05);
}
.palette_icon_container_right {
left: auto;
right: 0;
border-right: none;
border-left: 2px solid rgba(0,0,0,0.1);
border-left: 1px solid rgba(0,0,0,0.1);
}
.palette_icon {
display: inline-block;
@@ -198,3 +187,22 @@
background-size: contain;
background-repeat: no-repeat;
}
.palette_node_small {
display: inline-block;
position: relative;
width: 18px;
height: 15px;
margin: 3px 0px;
vertical-align: middle;
cursor: default;
.palette_icon_container {
width: 18px;
border-right: none;
}
.palette_icon {
margin-left: -1px;
width: 15px;
}
}

40
editor/sass/panels.scss Normal file
View File

@@ -0,0 +1,40 @@
/**
* 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-ui-panels {
position: relative;
& > div {
// border: 1px solid red;
box-sizing: border-box;
}
}
.red-ui-panels-separator {
border-top: 1px solid $secondary-border-color;
border-bottom: 1px solid $secondary-border-color;
height: 7px;
box-sizing: border-box;
cursor: ns-resize;
background: $background-color url(images/grip.png) no-repeat 50% 50%;
}
.red-ui-panel {
overflow: auto;
height: calc(50% - 4px);
}

96
editor/sass/popover.scss Normal file
View File

@@ -0,0 +1,96 @@
/**
* 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-ui-popover {
display: none;
position: absolute;
width: auto;
padding: 10px;
height: auto;
background: #fff;
z-index: 1000;
font-size: 14px;
line-height: 1.4em;
@include component-shadow;
}
.red-ui-popover:after, .red-ui-popover:before {
top: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.red-ui-popover.red-ui-popover-right:after, .red-ui-popover.red-ui-popover-right:before {
right: 100%;
}
.red-ui-popover.red-ui-popover-left:after, .red-ui-popover.red-ui-popover-left:before {
left: 100%;
}
.red-ui-popover.red-ui-popover-right:after {
border-color: rgba(136, 183, 213, 0);
border-right-color: #fff;
border-width: 10px;
margin-top: -10px;
}
.red-ui-popover.red-ui-popover-right:before {
border-color: rgba(194, 225, 245, 0);
border-right-color: $primary-border-color;
border-width: 11px;
margin-top: -11px;
}
.red-ui-popover.red-ui-popover-left:after {
border-color: rgba(136, 183, 213, 0);
border-left-color: #fff;
border-width: 10px;
margin-top: -10px;
}
.red-ui-popover.red-ui-popover-left:before {
border-color: rgba(194, 225, 245, 0);
border-left-color: $primary-border-color;
border-width: 11px;
margin-top: -11px;
}
.red-ui-popover-size-small {
font-size: 11px;
padding: 5px;
&.red-ui-popover-right:after {
border-width: 5px;
margin-top: -5px;
}
&.red-ui-popover-right:before {
border-width: 6px;
margin-top: -6px;
}
&.red-ui-popover-left:after {
border-width: 5px;
margin-top: -5px;
}
&.red-ui-popover-left:before {
border-width: 6px;
margin-top: -6px;
}
}

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