Compare commits

...

216 Commits

Author SHA1 Message Date
Dave Conway-Jones
746512b8b8 Remove sentiment from core
(moved to node-red-nodes)
2018-06-14 20:44:17 +01:00
Nick O'Leary
56db1da3cf Merge pull request #1732 from node-red/pi-nodes-editable-when-na
let Pi nodes be visible/editable on all platforms
2018-06-13 15:46:21 +01:00
Nick O'Leary
d46b66878a Show unknown node properties in info tab 2018-06-13 14:56:09 +01:00
Nick O'Leary
6cad80c4ad Add node icon picker widget 2018-06-12 23:46:06 +01:00
Nick O'Leary
68779caa2e Only edit nodes on dbl click on primary button with no modifiers 2018-06-12 15:34:08 +01:00
Nick O'Leary
2a122ed283 Allow subflows to be put in any palette category 2018-06-12 12:54:32 +01:00
Nick O'Leary
17c5fdf0d5 Add flow navigator widget 2018-06-08 23:32:17 +01:00
Nick O'Leary
f6274445a2 Merge branch 'master' into 0.19 2018-06-06 21:41:48 +01:00
Nick O'Leary
3b0300b834 Cache flow library result to improve response time
Fixes #1753
2018-06-06 21:38:44 +01:00
Nick O'Leary
4fbf1fe780 Add middle-button-drag to pan the workspace 2018-06-06 20:51:30 +01:00
Nick O'Leary
7136dc1c72 Merge pull request #1749 from kazuhitoyokoi/0.19
Add i18n support for projectSettings.js
2018-06-04 23:32:55 +01:00
Kazuhito Yokoi
0e4cedbc5e Remove new lines 2018-06-04 07:21:48 +09:00
Kazuhito Yokoi
dc139bcc30 Remove new line 2018-06-04 07:15:26 +09:00
Kazuhito Yokoi
ab788bc1e3 Add i18n support for projectSettings.js 2018-06-01 12:58:09 +09:00
Nick O'Leary
95b4c8d515 Merge pull request #1748 from node-red-hitachi/0.19-editor-diff-i18n-jp
Add i18n support for project
2018-05-31 10:44:36 +01:00
Nick O'Leary
b025644525 Merge pull request #1744 from node-red-hitachi/0.19-i18n-defaultFileSet
Add i18n support for default file set for a project
2018-05-31 08:51:53 +01:00
Yuma Matsuura
9e87a60597 modify translate project diff 2018-05-31 16:47:03 +09:00
Yuma Matsuura
5a70bea67a add translate project diff 2018-05-31 16:46:46 +09:00
Hiroyasu Nishiyama
2a95af3928 merged 0.19-allow-i18n-translation-in-runtime 2018-05-30 21:59:20 +09:00
Nick O'Leary
0a0ca380d3 Ensure apiMaxLength applies to HTTP Nodes
Fixes #1278
2018-05-30 13:32:38 +01:00
Nick O'Leary
4cfbf7f71c Merge pull request #1743 from node-red-hitachi/0.19-allow-i18n-translation-in-runtime
Allow i18n translation in runtime
2018-05-30 13:20:05 +01:00
Hiroyasu Nishiyama
de43148341 change current_locale to getCurrentLocale 2018-05-30 20:32:56 +09:00
Nick O'Leary
0a2aab7d68 Merge pull request #1746 from node-red-hitachi/0.19-user-settings-projects-i18n-jp
Modify i18n support for user settings of project
2018-05-30 10:30:25 +01:00
Nick O'Leary
745821c420 Merge pull request #1745 from node-red-hitachi/0.19-version-projects-i18n-jp
Add i18n support for version control of project
2018-05-30 10:30:12 +01:00
Nick O'Leary
57c4c754d0 Merge pull request #1742 from node-red-hitachi/0.19-editor-main-i18n-jp
Update i18n support for main editor interface and Japanese message …
2018-05-30 10:22:38 +01:00
Nick O'Leary
4b5c437533 Merge pull request #1741 from node-red-hitachi/0.19-editor-projects-i18n-jp
Add i18n support for projects interface and Japanese message catalogue
2018-05-30 10:21:29 +01:00
Nick O'Leary
8d63b6a1ed Merge pull request #1734 from node-red-hitachi/0.19-fix-icon-scan-test-for-win
Fix test failure of icon scan on Windows
2018-05-30 10:18:57 +01:00
Nick O'Leary
245a8adbf9 Merge pull request #1736 from node-red-hitachi/0.19-httpreq
Move to request module
2018-05-30 10:18:21 +01:00
Yuma Matsuura
4f7d98aace modify translate user settings 2018-05-29 10:12:52 +09:00
Kazuki-Nakanishi
b0c693cc3a move comment from json to js 2018-05-28 17:06:38 +09:00
Kazuki-Nakanishi
b2cca10e8b Add i18n support for version control of project 2018-05-28 17:01:53 +09:00
Hiroyasu Nishiyama
a84b2ab5bb update defaultFileSet test for i18n support 2018-05-27 22:30:05 +09:00
Hiroyasu Nishiyama
4565342b05 add i18n support for project default files generation 2018-05-27 01:38:54 +09:00
Hiroyasu Nishiyama
0ad54cc2d1 allow i18n translation in runtime 2018-05-27 01:05:50 +09:00
Hiroyasu Nishiyama
865853da19 add some i18n support for main editor interface and Japanese message catalogue 2018-05-26 20:08:39 +09:00
Hiroyasu Nishiyama
392ed706fd add i18n support for projects interface and Japanese message catalogue 2018-05-26 14:21:30 +09:00
Nick O'Leary
0ff0f25aaf Merge branch 'master' into 0.19 2018-05-25 13:58:15 +01:00
Nick O'Leary
c157960846 Change debug sidebar icon 2018-05-25 13:55:35 +01:00
YumaMatsuura
a5c00b5c81 add translate-user-settings (#1740) 2018-05-25 13:55:03 +01:00
Nick O'Leary
472bbdb59f Fix typo in CHANGELOG 2018-05-25 13:27:58 +01:00
Nick O'Leary
7877093713 Bump 0.18.7 2018-05-25 13:23:18 +01:00
Nick O'Leary
8cb2e51407 Relax twitter node version ready for major version bump 2018-05-25 11:40:14 +01:00
Nick O'Leary
d5cee81fb6 Merge branch 'pr_1739' 2018-05-25 11:37:37 +01:00
Nick O'Leary
bca020bc4d Tidy up default grunt task and fixup test break due to reorder
Fixes #1738
2018-05-25 11:36:17 +01:00
Nick O'Leary
5069f2844c Bump jsonata version 2018-05-25 10:55:44 +01:00
Nick O'Leary
252df81f59 Pass Date into the Function node sandbox to fix instanceof tests 2018-05-25 10:55:44 +01:00
KatsuyaHoshii
7f89a4a26f Update .travis.yml 2018-05-25 11:48:33 +09:00
Dave Conway-Jones
40f4167894 let TCP in node report remote ip and port when in single packet mode 2018-05-24 21:39:46 +01:00
Nick O'Leary
0ef16989cd Do not trim wires if node declares outputs in defaults but misses value
Fixes #1737
2018-05-24 20:27:07 +01:00
Dave Conway-Jones
3df3d6f516 add debug to trigger test to help work out fails 2018-05-24 10:02:51 +01:00
Edward Vielmetti
10395ef254 typo fix *hierarchy (#1735) 2018-05-24 09:48:05 +01:00
Hiroyasu Nishiyama
83854c28db fix test failure of icon scan on windows 2018-05-24 12:06:39 +09:00
Nick O'Leary
fcbea2629c Support flow.disabled and .info in /flow API 2018-05-23 22:41:39 +01:00
Nick O'Leary
26bc142cc2 Handle loading empty nodesDir 2018-05-23 10:59:08 +01:00
Nick O'Leary
a4eb8e11c3 Collapse sidebar tabs 2018-05-23 10:25:47 +01:00
HirokiUchikawa
9fd5d1db56 Move to request module 2018-05-23 17:16:20 +09:00
Dave Conway-Jones
1d05b4c981 relax test spec slightly 2018-05-23 08:58:04 +01:00
HirokiUchikawa
61f6535be8 Add test case for preventing following redirect 2018-05-23 16:54:03 +09:00
Dave Conway-Jones
7dd329b5ee Add basic loading tests for GPIO nodes 2018-05-22 17:26:52 +01:00
Dave Conway-Jones
b761904424 let Pi nodes be visible/editable on all platforms
even where they are not physically available.
2018-05-22 15:48:24 +01:00
Nick O'Leary
36105412b1 Add 'private' property to userDir generated package.json
This stops the warnings from npm about missing repo and license fields.
As there's no expectation for a user to publish their userDir to npm, then
setting private is entirely appropriate.
2018-05-22 11:41:22 +01:00
Nick O'Leary
184b1b018c Add missing resource file 2018-05-21 22:38:07 +01:00
Nick O'Leary
f3e1b85d82 Add RED.require to allow nodes to access other modules 2018-05-21 22:08:04 +01:00
Nick O'Leary
626d012775 Do not disable the export-clipboard menu option with empty selection 2018-05-21 16:14:43 +01:00
Nick O'Leary
9ad9c0ec6a Add $env function to JSONata expressions 2018-05-21 15:28:15 +01:00
Nick O'Leary
e13fed9fc6 Widen support for env var to use ${} or $() syntax 2018-05-21 15:19:50 +01:00
Nick O'Leary
eb6d093e56 Add env-var support to TypedInput 2018-05-21 15:10:06 +01:00
Hiroyasu Nishiyama
af1ea610ea allow id and name reference in function node code (#1731) 2018-05-21 11:34:56 +01:00
Nick O'Leary
d4d9190919 Bump version 2018-05-18 11:03:49 +01:00
Nick O'Leary
4d3d1a02a8 Add editorTheme.projects.enabled to default settings.js 2018-05-18 11:03:00 +01:00
Nick O'Leary
30c2aa96d6 Update changelog 2018-05-17 12:21:06 +01:00
Nick O'Leary
4edb1f80b0 Update mailing list references to new forum 2018-05-17 12:17:55 +01:00
Nick O'Leary
0a82459233 Handle a node having wires in the editor on ports it no longer has
Fixes #1724
2018-05-17 11:28:35 +01:00
Dave Conway-Jones
db87b0dfa5 Add missing ACE snippet files
to stop 404 in console
2018-05-15 22:10:14 +01:00
Nick O'Leary
cd42cf7583 Fix wireClippedNodes is not defined
Fixes #1726
2018-05-12 17:02:07 +01:00
Nick O'Leary
2d5980ff2a Split node html to isolate bad nodes when loading 2018-05-11 22:30:57 +01:00
Nick O'Leary
d49c7a3adb Avoid unnecessary use of .html() where .text() will do 2018-05-11 14:05:52 +01:00
Nick O'Leary
4fdd09a262 Changelog tidy 2018-05-10 13:04:37 +01:00
Nick O'Leary
d6878512c4 Bump version for 0.18.5 2018-05-10 13:02:59 +01:00
Nick O'Leary
8b1b8250ff update changelog 2018-05-10 11:29:20 +01:00
Hiroyasu Nishiyama
9dccbf747e Japanese message catalogue update (#1723)
* update Japanese message catalogue for mqtt node

* update Japanese message catalogue for udp node

* update Japanese message catalogue for html node

* update Japanese message catalogue for rpi-gpio node
2018-05-10 11:26:56 +01:00
Nick O'Leary
08727e1938 Show node load errors in the palette manager 2018-05-10 11:21:59 +01:00
Nick O'Leary
7584820987 Filter req.user in /settings to prevent leaking info 2018-05-09 10:03:22 +01:00
Nick O'Leary
d572356642 Update to latest test-helper module 2018-05-08 23:44:39 +01:00
Nick O'Leary
3b5a2815a9 Merge master 2018-05-08 23:27:27 +01:00
Nick O'Leary
f3cf01df25 Update changelog 2018-05-08 22:06:32 +01:00
Nick O'Leary
63e6e64ad3 Merge branch 'pr_1719' 2018-05-08 17:23:57 +01:00
Nick O'Leary
e8d7b48bff Fix up sizing of mqtt message inputs 2018-05-08 17:23:28 +01:00
mblackstock
12944d1ebd add back removed Retain message 2018-05-08 08:30:10 -07:00
Nick O'Leary
fa1ff6e393 Update changelog 2018-05-08 15:41:25 +01:00
Nick O'Leary
98546b6e6a Fixup Function node error line reporting 2018-05-08 11:40:16 +01:00
Nick O'Leary
2fef6fd1fa Fix proper closing of http request test ssl/proxy servers 2018-05-08 11:26:28 +01:00
Nick O'Leary
20cf91f1dc Merge branch 'pr_1700' 2018-05-08 10:47:35 +01:00
Nick O'Leary
2efa78d590 Fix up function stack issues 2018-05-08 10:47:20 +01:00
Nick O'Leary
880af0671a Merge branch 'pr_1706' 2018-05-08 10:44:35 +01:00
Nick O'Leary
62471e4531 Handle null error object in Flow.handleError
Fixes #1721
2018-05-08 10:37:41 +01:00
mblackstock
b15f8535f8 document close message 2018-05-06 20:02:20 -07:00
mblackstock
7a3a4493da tighten vertically, change section order 2018-05-06 15:38:45 -07:00
mblackstock
11078235c4 added deleted 'retain' in tip 2018-05-06 15:08:15 -07:00
mblackstock
f3e05cd08a set default expand behaviour 2018-05-04 16:52:21 -07:00
Nick O'Leary
0ca3cabbe8 Refector how Project object is instantiated 2018-05-04 16:24:00 +01:00
mblackstock
44a75c1291 move to two lines, add publish on close 2018-05-03 13:47:14 -07:00
Dave Conway-Jones
4a4513a746 Add type checks to switch node options (#1714)
* Add type checks to switch node options

* add isType to messages.json
2018-05-03 11:24:44 +01:00
iurly
60ff8660de node-red-pi: fix behavior with old bash version (#1713)
For some reason the following will result
in an endless loop under bash-4.3.42:

while([ -h "${SCRIPT_PATH}" ])

Just remove the round brackets (parentheses) to fix the issue.
They're not needed anyway.
2018-05-03 09:41:37 +01:00
Nathan Allen
6fa0d671c0 Fix ENOENT error on first start when no user dir (#1711)
* Fix ENOENT error on first start when no user dir

Write backup using `copySync` and move it below the `fsync` to ensure file is present when backup is made.

* Check for path to exist before attempting backup
2018-05-03 09:40:51 +01:00
mblackstock
f478d7c9f0 experiments with mqtt ui (wip) 2018-05-02 16:02:53 -07:00
Nick O'Leary
53e3e08d70 Handle cloning a project without package.json 2018-05-02 16:24:58 +01:00
Nick O'Leary
c4d1ccb6f5 Keep remote branch state in sync between editor and runtime 2018-05-02 13:59:39 +01:00
Nick O'Leary
e3520309fc Add clone project to welcome screen 2018-05-02 13:38:50 +01:00
Martin Guillon
27bf72372e fix after comments 2018-05-01 14:00:05 +02:00
Nick O'Leary
ae4b1b17a9 Increase trigger node test timings 2018-05-01 12:59:53 +01:00
Dave Conway-Jones
94cb03f4b5 bind to correct port when doing udp broadcast/multicast (#1686)
* bind to correct port when doing broadcast/multicast

to allow better re-use of ports.

* allow udp multicast to work out if ip address

makes life easier for mortals

* udp also handle bind to ipv6 multicast if

tidy prompts to suit new function

* udp node, add face to debug log for multicast if known
2018-05-01 12:43:51 +01:00
Dave Conway-Jones
e691351976 update settings comments to describe how to setup for ipv6 (#1675)
* change default server bind to support ipv6 and ipv4

to close #1674

* Add comment re ipv6 so folk know it's capable

* slightly more words re ipv6 config

* Leave defaults as ipv4 but add doc to settings
2018-05-01 12:43:10 +01:00
Dave Conway-Jones
3190de873e add output property select to HTML parse node (#1701) 2018-05-01 12:42:27 +01:00
Christopher Hiller
e8a637498d add Node.js v10 to build matrix (#1708)
* add Node.js v10 to build matrix

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>

* only compute coverage once

We have to pick *which* version of Node.js to run coverage on, so I just
picked the latest.

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
2018-04-24 23:21:34 +01:00
Christopher Hiller
e1195ac00a fix many test problems (#1677)
* fix many test problems

- adds [stoppable](https://npm.im/stoppable) to force-stop net & http
  servers
- upgrades to latest mocha
- much cleanup of servers
- some removal of useless code

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>

* increase wait time to hack at race condition

* PoC with fork of stoppable

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>

* fix custom stoppable url for newer npm

* make travis go faster; attempt to avoid npm troubles

* fix coveralls executable path

* add extra time for flake to trigger spec

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
2018-04-23 12:37:26 +01:00
KatsuyaHoshii
6cd9ccc37c Refactor test cases 2018-04-23 14:31:37 +09:00
Nick O'Leary
25345302e8 Only add _alias/z to log messages if they are defined 2018-04-18 10:28:51 +01:00
Nick O'Leary
eccd5e9801 Handle additional debug msg props in Node_spec 2018-04-17 23:29:56 +01:00
mblackstock
ff355af9f2 use newer test helper 2018-04-17 11:59:47 -07:00
Martin Guillon
5967f4b0d4 fix error stack 2018-04-17 15:46:09 +02:00
Nick O'Leary
ff18618032 Highlight subflow node when log msg comes from inside
Fixes #1698
2018-04-17 12:44:58 +01:00
Martin Guillon
20f03c356c better script error handling.
Also pass the error in msg so that it can handled later
2018-04-17 10:52:53 +02:00
Nick O'Leary
27fdc9e56e Remove credential props after diffing flow to prevent future false positives
Fixes #1359
2018-04-16 15:36:23 +01:00
Nick O'Leary
52d9578a19 Log error if settings unavailable when saving user settings
Fixes #1645
2018-04-16 15:02:28 +01:00
Nick O'Leary
f4c2938b41 Ensure node wires array is not longer than outputs value
Fixes #1678
2018-04-16 13:23:36 +01:00
Nick O'Leary
9f703de5ec Allow importing an unknown config node to be undone
Fixes #1681
2018-04-16 11:20:37 +01:00
Dave Conway-Jones
a327fd85e2 Fix template to default typed input field
to close #1697
2018-04-16 11:14:15 +01:00
Dave Conway-Jones
9d22a86ec8 fix typo in switch label, make function label consistent 2018-04-16 11:12:21 +01:00
Ted
29e0b194dd Handle and display for invalid flow credentials when project is disabled #1689 (#1694)
* Handle and display for invalid flow credentials when project is disabled #1689

* fixed extra character

* fixed whitespace
2018-04-15 11:51:26 +01:00
Nick O'Leary
ae9cf13fc2 Fix http request doc type
Fixes #1690
2018-04-15 11:46:10 +01:00
Nick O'Leary
64ae67586a Ensure keyboard shortcuts get saved in runtime settings
Fixes #1696
2018-04-15 11:43:03 +01:00
Dave Conway-Jones
838c7a5e89 make debug slightly larger to pass WCAG AA rating 2018-04-05 11:25:08 +01:00
Dave Conway-Jones
89bfc90f40 Make core nodes labels more consistent, to close #1673
and make them translateable
2018-03-30 14:31:59 +01:00
Dave Conway-Jones
acad9f57f9 Add "not available" to common messages 2018-03-30 14:03:04 +01:00
Fabien Marchewka
0d08dc410e Prevent Following Redirect (#615) (#1684) 2018-03-29 08:28:44 +01:00
Nick O'Leary
ebb3fb96cd Merge pull request #1670 from node-red-hitachi/subflow-icon-change
Enable user defined icon for subflow
2018-03-27 10:22:20 +01:00
Nick O'Leary
f31f23ff07 Allow template node to be updated more than once
Fixes #1671
2018-03-27 10:14:39 +01:00
KatsuyaHoshii
d2aa3d1868 Add SSL server certificate 2018-03-27 17:07:29 +09:00
KatsuyaHoshii
c9e2fce94d test for httprequest node 2018-03-27 16:09:04 +09:00
Kazuki-Nakanishi
8b0e76dd55 Hide the subflow check logic inside getDefaultNodeIcon function 2018-03-22 14:14:09 +09:00
Dave Conway-Jones
884618adfe remove down carat from typed input with only 1 type 2018-03-20 21:01:10 +00:00
Nick O'Leary
98f7271ac8 Merge pull request #1657 from node-red-hitachi/move-i18n-info-text
move i18n info text of core nodes under nodes/core/locales directory
2018-03-20 20:44:54 +00:00
Dave Conway-Jones
087cd121b8 add debug and trace to function node (#1654) 2018-03-20 20:40:36 +00:00
Kazuki Nakanishi
2d52527fb4 Don't mark a subflow changed when actually modified nothing (#1665) 2018-03-20 20:39:46 +00:00
Kazuki Nakanishi
fe289e62b5 Fix the problem that output labels of switch node sometimes disappear (#1664) 2018-03-20 20:37:29 +00:00
Nick O'Leary
2845475e3f Keep backup of .config.json 2018-03-20 00:04:52 +00:00
Nick O'Leary
b307492487 Add warning if using _credentialSecret 2018-03-20 00:04:52 +00:00
Nick O'Leary
d48284f7ea Remove unused references to settings 2018-03-20 00:04:52 +00:00
Dave Conway-Jones
7e416797e9 make trigger test a bit more robust 2018-03-19 17:33:18 +00:00
Kroderia
5d54ca7477 Chinese translations for core nodes (#1607)
* Fix typo

* Fix and Update some Chinese translations.

* Fix and Add Chinese translations to match all en-US's items
2018-03-17 17:49:17 +00:00
Qi Xiu
b979b4e61a Master chinese3 (#1666)
* Translated jsonata.json to Chinese

* Translated file jsonata.json to Chinese
2018-03-17 17:48:01 +00:00
Kazuki Nakanishi
2527f7984a Translate rpi-gpio node (#1669)
Thanks
2018-03-17 17:46:44 +00:00
Kazuki-Nakanishi
d9350b2362 Enable user defined icon for subflow 2018-03-14 13:51:50 +09:00
Kazuhito Yokoi
bd0b903f1a Fix typo in info messages of file node 2018-03-14 01:19:37 +00:00
Kazuhito Yokoi
f243c0df19 Fix typo in info messages of json node 2018-03-14 01:18:00 +00:00
Kazuhito Yokoi
7482978953 Fix typo in info messages of html node 2018-03-14 01:16:59 +00:00
Kazuhito Yokoi
77966689d4 Fix typo in info messages of csv node 2018-03-14 01:15:36 +00:00
Kazuhito Yokoi
cf43939d65 Fix typo in info messages of split node 2018-03-14 01:11:11 +00:00
Kazuhito Yokoi
391ac4b351 Fix typo in info messages of change node 2018-03-14 01:09:29 +00:00
Kazuhito Yokoi
e1e48aadd9 Fix typo in info messages of switch node 2018-03-14 01:08:10 +00:00
Kazuhito Yokoi
0681f206c4 Fix typo in info messages of udp node 2018-03-14 01:05:38 +00:00
Kazuhito Yokoi
d257c6f3d3 Fix typo in info messages of tcpin node 2018-03-14 01:04:21 +00:00
Kazuhito Yokoi
fa45c82cdc Fix typo in info messages of watch node 2018-03-14 01:01:58 +00:00
Kazuhito Yokoi
e805b58da6 Fix typo in info messages of websocket node 2018-03-14 01:00:13 +00:00
Kazuhito Yokoi
943976d207 Fix typo in info messages of trigger node 2018-03-14 00:49:44 +00:00
Kazuhito Yokoi
3a2e5a6ccd Fix typo in info messages of exec node 2018-03-14 00:47:50 +00:00
Kazuhito Yokoi
35ef036246 Fix typo in info messages of debug node 2018-03-14 00:46:07 +00:00
Kazuhito Yokoi
e09c3bbdd3 Fix typo in info messages of inject node 2018-03-14 00:41:07 +00:00
Nick O'Leary
3b12076d4b Ignore subflow debug nodes when building filter
Fixes #1660

As the editor doesn't know the ids of subflow instance debug nodes
there's no easy way to build a list of them as part of the filter
options. So for now, disable the filter option if we don't know
about the debug node.
2018-03-03 22:41:02 +00:00
Hiroyasu Nishiyama
cfcf78ae28 fix failure of node installation (#1658) 2018-03-03 07:35:17 +00:00
Hiroyasu Nishiyama
341ff9bf5c move i18n info text of core nodes under nodes/core/locales directory 2018-03-03 10:39:11 +09:00
mblackstock
10d8ca30b0 use node-red-node-test-helper for node tests 2018-03-01 20:41:16 -08:00
Dave Conway-Jones
4ebb5d099e add trigger reset test for null on 2nd output 2018-03-01 14:00:14 +00:00
Dave Conway-Jones
1e82b66bf0 remove octalbonescript example line from settings as no longer supported 2018-03-01 11:41:53 +00:00
Nick O'Leary
06a5e4273b Move all event emitting into runtime side, not api side 2018-02-28 11:24:12 +00:00
Dave Conway-Jones
e123e7b0b0 Fix pi gpio output of boolean to actually send 1/0
rather than true/false
2018-02-27 23:26:32 +00:00
Nick O'Leary
aeadc40c65 Bump for 0.18.4 2018-02-27 16:41:10 +00:00
Nick O'Leary
7ef418ec52 Ensure sshkey file path is properly escaped on Windows 2018-02-27 13:05:10 +00:00
Nick O'Leary
2ed52820b6 Fix fs/fspath reference 2018-02-27 11:11:02 +00:00
Nick O'Leary
e8fd7484b6 Normalize ssh key paths for Windows file names 2018-02-27 10:58:54 +00:00
Nick O'Leary
ce5242cfe8 Ensure userDir is an absolute path when used with sshkeygen 2018-02-26 23:46:08 +00:00
Nick O'Leary
af947879d8 Merge pull request #1614 from node-red-hitachi/no-tabs
Fix the problem that the last flow tab can be deleted
2018-02-22 19:02:12 -08:00
Kazuki-Nakanishi
3ed112cde6 Changed coding style 2018-02-23 11:48:40 +09:00
Nick O'Leary
99c6a9eccd Merge pull request #1646 from node-red-hitachi/no-defaults-node
Fixed the problems when using a node without defaults
2018-02-22 18:12:41 -08:00
Nick O'Leary
2029f6ea0a Merge pull request #1638 from node-red-hitachi/i18n-info-jp
add Japanese info text of core nodes
2018-02-22 18:01:56 -08:00
Nick O'Leary
e984e1f30f Merge pull request #1616 from node-red-hitachi/fix-i18n-message-lookup
fix message lookup for core nodes in case of i18 locales directory ex…
2018-02-22 17:59:52 -08:00
Kazuki-Nakanishi
f21260370f Fixed the problems when using a node without defaults 2018-02-22 14:10:31 +09:00
Dave Conway-Jones
fdae75c99b ensure trigger gets reset when 2nd output is null
to fix #1644
2018-02-21 21:56:03 +00:00
Nick O'Leary
a0489f2a0d Fix tests for existing file flag in settings 2018-02-21 08:38:52 -08:00
Nick O'Leary
0123eacbdb Merge pull request #1642 from node-red-hitachi/subflow-icon
Disable user defined icon for subflow
2018-02-21 08:24:41 -08:00
Nick O'Leary
53401b6aa7 Fix merging a remote diff 2018-02-20 15:01:45 -08:00
Nick O'Leary
9a5139f452 Detect if there are no existing flows to migrate into a project 2018-02-20 14:30:37 -08:00
Nick O'Leary
2ee0c8c228 Use relative urls when retriving flow history 2018-02-20 14:27:47 -08:00
Kazuki-Nakanishi
c53562cc9c Disable user defined icon for subflow 2018-02-20 15:29:52 +09:00
Nick O'Leary
ec5d7c2e5c Add credentialSecret to clone pane 2018-02-18 17:09:19 +00:00
Nick O'Leary
d6fc258485 Delay clearing inflight when changing credentials key 2018-02-18 16:43:40 +00:00
Nick O'Leary
f953612695 Mark deploy inflight when reverting a file change 2018-02-18 16:30:47 +00:00
Kazuki-Nakanishi
2ab93acca8 Revise the fix for the problem that the last flow tab can be deleted 2018-02-16 11:54:52 +09:00
Nick O'Leary
326c6c496e Handle missing_flow_file error on clone properly 2018-02-15 22:47:07 +00:00
Nick O'Leary
9f7f50664c Remote project from cached list on delete so it can be reused 2018-02-15 22:46:36 +00:00
Nick O'Leary
f6f1436123 getDefaultNodeIcon should handle subflow instance nodes
Fixes #1635
2018-02-15 15:34:15 +00:00
Hiroyasu Nishiyama
c3c519419d merge i18n-info-jp-storage 2018-02-15 22:47:15 +09:00
Hiroyasu Nishiyama
e569a80b72 merge i18n-info-jp-parsers 2018-02-15 22:47:05 +09:00
Hiroyasu Nishiyama
284f437c1a merge i18n-info-jp-logic 2018-02-15 22:46:58 +09:00
Hiroyasu Nishiyama
1fd44a9958 merge i18n-info-jp-io 2018-02-15 22:46:46 +09:00
Hiroyasu Nishiyama
cad34742f6 merge i18n-info-jp-core 2018-02-15 22:46:18 +09:00
Hiroyasu Nishiyama
323359b3c8 merge i18n-info-jp-analysis 2018-02-15 22:46:10 +09:00
Hiroyasu Nishiyama
35db8b45f0 add Japanese info text for io category nodes 2018-02-15 22:39:46 +09:00
Hiroyasu Nishiyama
7face138fd add Japanese info text for analysis category nodes 2018-02-12 14:04:29 +09:00
Hiroyasu Nishiyama
382b83b093 add Japanese info text for parsers category nodes 2018-02-12 12:24:03 +09:00
Hiroyasu Nishiyama
691687d1bc add Japanese info text for storage category nodes 2018-02-11 23:07:07 +09:00
Hiroyasu Nishiyama
5814b80a72 add Japanese info text for logic category nodes 2018-02-11 20:59:01 +09:00
Hiroyasu Nishiyama
e147fbb1fa add Japanese info text for core category nodes 2018-02-11 20:52:44 +09:00
Hiroyasu Nishiyama
ce9643d21b fix message lookup for core nodes in case of i18 locales directory exists 2018-02-07 21:59:58 +09:00
Kazuki-Nakanishi
c316284924 Fix the problem that the last flow tab can be deleted 2018-02-07 14:19:18 +09:00
218 changed files with 8159 additions and 2983 deletions

View File

@@ -8,7 +8,9 @@ If your issue is:
- a feature request or suggestion for a change,
- or problems with 3rd party (`node-red-contrib-`) nodes
please use the [mailing list](https://groups.google.com/forum/#!forum/node-red), [slack team](https://nodered.org/slack) or ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
That way the whole Node-RED user community can help, rather than rely on the core development team.

View File

@@ -16,7 +16,7 @@ Put an `x` in the boxes that apply
<!--
If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it **may well get rejected** if it hasn't been discussed on
the [mailing list](https://groups.google.com/forum/#!forum/node-red) or
the [forum](https://discourse.nodered.org) or
[slack team](https://nodered.org/slack) first.
-->

View File

@@ -1,20 +1,12 @@
sudo: false
language: node_js
env:
- CXX="g++-4.8"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
- gcc-4.8
node_js:
- "8"
- "6"
- "4"
script:
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
before_script:
- npm install -g istanbul
- npm install coveralls
matrix:
include:
- node_js: "10"
script:
- ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
before_script:
- npm install -g istanbul coveralls
- node_js: "8"
- node_js: "6"
- node_js: "4"

View File

@@ -1,3 +1,114 @@
#### 0.18.7: Maintenance Release
Editor Fixes
- Do not trim wires if node declares outputs in defaults but misses value Fixes #1737
Node Fixes
- Relax twitter node version ready for major version bump
- Pass Date into the Function node sandbox to fix instanceof tests
- let TCP in node report remote ip and port when in single packet mode
- typo fix in node help (#1735)
Other Fixes
- Tidy up default grunt task and fixup test break due to reorder Fixes #1738
- Bump jsonata version
#### 0.18.6: Maintenance Release
Editor Fixes
- Handle a node having wires in the editor on ports it no longer has Fixes #1724
- Add missing ACE snippet files
- Fix wireClippedNodes is not defined Fixes #1726
- Split node html to isolate bad nodes when loading
- Avoid unnecessary use of .html() where .text() will do
- Add editorTheme.projects.enabled to default settings.js"
#### 0.18.5: Maintenance Release
Projects
- Add clone project to welcome screen
- Handle cloning a project without package.json
- Keep remote branch state in sync between editor and runtime
New Features
- Add type checks to switch node options (#1714)
- add output property select to HTML parse node (#1701)
- Add Prevent Following Redirect to HTTP Request node (#615) (#1684)
- Add debug and trace functions to function node (#1654)
- Enable user defined icon for subflow
- Add MQTT disconnect message and rework broker node UI (#1719)
- Japanese message catalogue updates (#1723)
- Show node load errors in the Palette Manager view
Editor Fixes
- Highlight subflow node when log msg comes from inside Fixes #1698
- Ensure node wires array is not longer than outputs value Fixes #1678
- Allow importing an unknown config node to be undone Fixes #1681
- Ensure keyboard shortcuts get saved in runtime settings Fixes #1696
- Don't mark a subflow changed when actually modified nothing (#1665)
Node Fixes
- bind to correct port when doing udp broadcast/multicast (#1686)
- Provide full error stack in Function node log message (#1700)
- Fix http request doc type Fixes #1690
- Make debug slightly larger to pass WCAG AA rating
- Make core nodes labels more consistent, to close #1673
- Allow template node to be updated more than once Fixes #1671
- Fix the problem that output labels of switch node sometimes disappear (#1664)
- Chinese translations for core nodes (#1607)
Runtime Fixes
- Handle and display for invalid flow credentials when project is disabled #1689 (#1694)
- node-red-pi: fix behavior with old bash version (#1713)
- Fix ENOENT error on first start when no user dir (#1711)
- Handle null error object in Flow.handleError Fixes #1721
- update settings comments to describe how to setup for ipv6 (#1675)
- Remove credential props after diffing flow to prevent future false positives Fixes #1359
- Log error if settings unavailable when saving user settings Fixes #1645
- Keep backup of .config.json
- Add warning if using \_credentialSecret from .config.json
- Filter req.user in /settings to prevent potentially leaking info
#### 0.18.4: Maintenance Release
Projects
- Ensure sshkey file path is properly escaped on Windows
- Normalize ssh key paths for Windows file names
- Ensure userDir is an absolute path when used with sshkeygen
- Detect if there are no existing flows to migrate into a project
- Use relative urls when retriving flow history
- Add credentialSecret to clone pane
- Delay clearing inflight when changing credentials key
- Mark deploy inflight when reverting a file change
- Handle missing_flow_file error on clone properly
- Remote project from cached list on delete so it can be reused
- Fix tests for existing file flag in settings
Editor Fixes
- Fix merging a remote diff
- Fixed the problems when using a node without defaults
- Disable user defined icon for subflow
- getDefaultNodeIcon should handle subflow instance nodes Fixes #1635
- Add Japanese info text for core nodes
- Fix message lookup for core nodes in case of i18 locales directory exists
- Prevent the last tab from being deleted
Node Fixes
- Ensure trigger gets reset when 2nd output is null
#### 0.18.3: Maintenance Release
Projects

View File

@@ -30,13 +30,13 @@ At a minimum, please include:
## Feature requests
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
For feature requests, please raise them on the [forum](https://discourse.nodered.org).
## Pull-Requests
If you want to raise a pull-request with a new feature, or a refactoring
of existing code, it may well get rejected if you haven't discussed it on
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
the [forum](https://discourse.nodered.org) first.
All contributors need to sign the JS Foundation's Contributor License Agreement.
It is an online process and quick to do. You can read the details of the agreement

View File

@@ -55,7 +55,7 @@ module.exports = function(grunt) {
reportFormats: ['lcov','html'],
print: 'both'
},
all: { src: ['test/**/*_spec.js'] },
all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]}
},
@@ -144,6 +144,7 @@ module.exports = function(grunt) {
"editor/js/ui/keyboard.js",
"editor/js/ui/workspaces.js",
"editor/js/ui/view.js",
"editor/js/ui/view-navigator.js",
"editor/js/ui/sidebar.js",
"editor/js/ui/palette.js",
"editor/js/ui/tab-info.js",
@@ -474,7 +475,7 @@ module.exports = function(grunt) {
grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components',
['build','test-core','test-editor','test-nodes']);
['build','jshint:editor','mocha_istanbul:all']);
grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code',

View File

@@ -22,8 +22,7 @@ started.
More documentation can be found [here](http://nodered.org/docs).
For further help, or general discussion, please use the
[mailing list](https://groups.google.com/forum/#!forum/node-red).
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
## Developers

View File

@@ -31,7 +31,7 @@ done
# Find the real location of this script
CURRENT_PATH=`pwd`
SCRIPT_PATH="${BASH_SOURCE[0]}";
while([ -h "${SCRIPT_PATH}" ]); do
while [ -h "${SCRIPT_PATH}" ]; do
cd "`dirname "${SCRIPT_PATH}"`"
SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

View File

@@ -191,7 +191,7 @@ RED.history = (function() {
} else if (ev.t == "edit") {
for (i in ev.changes) {
if (ev.changes.hasOwnProperty(i)) {
if (ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
// This is a config node property
var currentConfigNode = RED.nodes.node(ev.node[i]);
if (currentConfigNode) {
@@ -229,10 +229,12 @@ RED.history = (function() {
}
});
}
RED.editor.validateNode(ev.node);
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
n.inputs = ev.node.in.length;
n.outputs = ev.node.out.length;
RED.editor.updateNodeProperties(n);
RED.editor.validateNode(n);
});
} else {
var outputMap;

View File

@@ -15,6 +15,25 @@
**/
(function() {
function appendNodeConfig(nodeConfig) {
var m = /<!-- --- \[red-module:(\S+)\] --- -->/.exec(nodeConfig.trim());
var moduleId;
if (m) {
moduleId = m[1];
} else {
moduleId = "unknown";
}
try {
$("body").append(nodeConfig);
} catch(err) {
RED.notify(RED._("notification.errors.failedToAppendNode",{module:moduleId, error:err.toString()}),{
type: "error",
timeout: 10000
});
console.log("["+moduleId+"] "+err.toString());
}
}
function loadNodeList() {
$.ajax({
headers: {
@@ -55,7 +74,11 @@
cache: false,
url: 'nodes',
success: function(data) {
$("body").append(data);
var configs = data.trim().split(/(?=<!-- --- \[red-module:\S+\] --- -->)/);
configs.forEach(function(data) {
appendNodeConfig(data);
});
$("body").i18n();
$("#palette > .palette-spinner").hide();
$(".palette-scroll").removeClass("hide");
@@ -130,13 +153,13 @@
loadFlows(function() {
var project = RED.projects.getActiveProject();
var message = {
"change-branch":"Change to local branch '"+project.git.branches.local+"'",
"merge-abort":"Git merge aborted",
"loaded":"Project '"+msg.project+"' loaded",
"updated":"Project '"+msg.project+"' updated",
"pull":"Project '"+msg.project+"' reloaded",
"revert": "Project '"+msg.project+"' reloaded",
"merge-complete":"Git merge completed"
"change-branch": RED._("notification.project.change-branch", {project: project.git.branches.local}),
"merge-abort": RED._("notification.project.merge-abort"),
"loaded": RED._("notification.project.loaded", {project: msg.project}),
"updated": RED._("notification.project.updated", {project: msg.project}),
"pull": RED._("notification.project.pull", {project: msg.project}),
"revert": RED._("notification.project.revert", {project: msg.project}),
"merge-complete": RED._("notification.project.merge-complete")
}[msg.action];
RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh()
@@ -160,7 +183,7 @@
if (!!RED.projects.getActiveProject()) {
options.buttons = [
{
text: "Manage project dependencies",
text: RED._("notification.label.manage-project-dep"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.settings.show('deps');
@@ -171,7 +194,7 @@
} else {
options.buttons = [
{
text: "Close",
text: RED._("common.label.close"),
click: function() {
persistentNotifications[notificationId].hideNotification();
}
@@ -179,13 +202,25 @@
]
}
} else if (msg.error === "credentials_load_failed") {
if (RED.user.hasPermission("projects.write")) {
if (RED.settings.theme("projects.enabled",false)) {
// projects enabled
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("notification.label.setup-cred"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showCredentialsPrompt();
}
}
]
}
} else {
options.buttons = [
{
text: "Setup credentials",
text: RED._("common.label.close"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showCredentialsPrompt();
}
}
]
@@ -194,7 +229,7 @@
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: "Setup project files",
text: RED._("notification.label.setup-project"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showFilesPrompt();
@@ -202,17 +237,29 @@
}
]
}
} else if (msg.error === "missing_package_file") {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: RED._("notification.label.create-default-package"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.createDefaultPackageFile();
}
}
]
}
} else if (msg.error === "project_empty") {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: "No thanks",
text: RED._("notification.label.no-thanks"),
click: function() {
persistentNotifications[notificationId].hideNotification();
}
},
{
text: "Create default project files",
text: RED._("notification.label.create-default-project"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.createDefaultFileSet();
@@ -226,7 +273,7 @@
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: "Show merge conflicts",
text: RED._("notification.label.show-merge-conflicts"),
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.sidebar.versionControl.showLocalChanges();
@@ -272,7 +319,7 @@
addedTypes = addedTypes.concat(m.types);
RED.i18n.loadCatalog(id, function() {
$.get('nodes/'+id, function(data) {
$("body").append(data);
appendNodeConfig(data);
});
});
});
@@ -300,7 +347,7 @@
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
$.get('nodes/'+msg.id, function(data) {
$("body").append(data);
appendNodeConfig(data);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
});
@@ -335,10 +382,10 @@
function loadEditor() {
var menuOptions = [];
if (RED.settings.theme("projects.enabled",false)) {
menuOptions.push({id:"menu-item-projects-menu",label:"Projects",options:[
{id:"menu-item-projects-new",label:"New",disabled:false,onselect:"core:new-project"},
{id:"menu-item-projects-open",label:"Open",disabled:false,onselect:"core:open-project"},
{id:"menu-item-projects-settings",label:"Project Settings",disabled:false,onselect:"core:show-project-settings"}
menuOptions.push({id:"menu-item-projects-menu",label:RED._("menu.label.projects"),options:[
{id:"menu-item-projects-new",label:RED._("menu.label.projects-new"),disabled:false,onselect:"core:new-project"},
{id:"menu-item-projects-open",label:RED._("menu.label.projects-open"),disabled:false,onselect:"core:open-project"},
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
]});
}
@@ -363,8 +410,8 @@
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"},
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
]});
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:"core:show-export-dialog"},
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),options:[
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-export-dialog"},
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"}
]});
menuOptions.push(null);

View File

@@ -133,7 +133,7 @@ RED.nodes = (function() {
registerNodeType: function(nt,def) {
nodeDefinitions[nt] = def;
def.type = nt;
if (def.category != "subflows") {
if (nt.substring(0,8) != "subflow:") {
def.set = nodeSets[typeToId[nt]];
nodeSets[typeToId[nt]].added = true;
nodeSets[typeToId[nt]].enabled = true;
@@ -355,8 +355,8 @@ RED.nodes = (function() {
RED.nodes.registerType("subflow:"+sf.id, {
defaults:{name:{value:""}},
info: sf.info,
icon:"subflow.png",
category: "subflows",
icon: function() { return sf.icon||"subflow.png" },
category: sf.category || "subflows",
inputs: sf.in.length,
outputs: sf.out.length,
color: "#da9",
@@ -491,7 +491,9 @@ RED.nodes = (function() {
for (var j=0;j<wires.length;j++) {
var w = wires[j];
if (w.target.type != "subflow") {
node.wires[w.sourcePort].push(w.target.id);
if (w.sourcePort < node.wires.length) {
node.wires[w.sourcePort].push(w.target.id);
}
}
}
@@ -517,6 +519,7 @@ RED.nodes = (function() {
node.type = n.type;
node.name = n.name;
node.info = n.info;
node.category = n.category;
node.in = [];
node.out = [];
@@ -550,7 +553,11 @@ RED.nodes = (function() {
if (node.out.length > 0 && n.outputLabels && !/^\s*$/.test(n.outputLabels.join(""))) {
node.outputLabels = n.outputLabels.slice();
}
if (n.icon) {
if (n.icon !== "node-red/subflow.png") {
node.icon = n.icon;
}
}
return node;
}
@@ -749,7 +756,7 @@ RED.nodes = (function() {
if (!isInitialLoad && unknownTypes.length > 0) {
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
var type = "type"+(unknownTypes.length > 1?"s":"");
RED.notify("<strong>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</strong>"+typeList,"error",false,10000);
RED.notify("<p>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</p>"+typeList,"error",false,10000);
}
var activeWorkspace = RED.workspaces.active();
@@ -1008,6 +1015,13 @@ RED.nodes = (function() {
set: registry.getNodeSet("node-red/unknown")
};
node.users = [];
// This is a config node, so delete the default
// non-config node properties
delete node.x;
delete node.y;
delete node.wires;
delete node.inputLabels;
delete node.outputLabels;
}
var orig = {};
for (var p in n) {
@@ -1020,10 +1034,31 @@ RED.nodes = (function() {
node.type = "unknown";
}
if (node._def.category != "config") {
node.inputs = n.inputs||node._def.inputs;
node.outputs = n.outputs||node._def.outputs;
if (n.hasOwnProperty('inputs')) {
node.inputs = n.inputs;
node._config.inputs = JSON.stringify(n.inputs);
} else {
node.inputs = node._def.inputs;
}
if (n.hasOwnProperty('outputs')) {
node.outputs = n.outputs;
node._config.outputs = JSON.stringify(n.outputs);
} else {
node.outputs = node._def.outputs;
}
if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) {
if (!node._def.defaults.hasOwnProperty("outputs") || !isNaN(parseInt(n.outputs))) {
// If 'wires' is longer than outputs, clip wires
console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs);
node.wires = node.wires.slice(0,node.outputs);
} else {
// The node declares outputs in its defaults, but has not got a valid value
// Defer to the length of the wires array
node.outputs = node.wires.length;
}
}
for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) {
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
node[d] = n[d];
node._config[d] = JSON.stringify(n[d]);
}
@@ -1043,7 +1078,9 @@ RED.nodes = (function() {
addNode(node);
RED.editor.validateNode(node);
node_map[n.id] = node;
if (node._def.category != "config") {
// If an 'unknown' config node, it will not have been caught by the
// proper config node handling, so needs adding to new_nodes here
if (node.type === "unknown" || node._def.category !== "config") {
new_nodes.push(node);
}
}

View File

@@ -309,18 +309,6 @@ RED.clipboard = (function() {
$('<input type="text" id="clipboard-hidden">').appendTo("body");
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
RED.menu.setDisabled("menu-item-export-clipboard",true);
RED.menu.setDisabled("menu-item-export-library",true);
} else {
RED.menu.setDisabled("menu-item-export",false);
RED.menu.setDisabled("menu-item-export-clipboard",false);
RED.menu.setDisabled("menu-item-export-library",false);
}
});
RED.actions.add("core:show-export-dialog",exportNodes);
RED.actions.add("core:show-import-dialog",importNodes);

View File

@@ -19,12 +19,14 @@ RED.popover = (function() {
"default": {
top: 10,
leftRight: 17,
leftLeft: 25
leftLeft: 25,
leftBottom: 8,
},
"small": {
top: 5,
leftRight: 17,
leftLeft: 16
leftLeft: 16,
leftBottom: 3,
}
}
function createPopover(options) {
@@ -69,6 +71,8 @@ RED.popover = (function() {
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight});
} else if (direction === 'left') {
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth});
} else if (direction === 'bottom') {
div.css({top: targetPos.top+targetHeight+deltaSizes[size].top,left:targetPos.left+targetWidth/2-divWidth/2 - deltaSizes[size].leftBottom});
}
if (instant) {
div.show();

View File

@@ -19,8 +19,10 @@
RED.tabs = (function() {
function createTabs(options) {
var tabs = {};
var pinnedTabsCount = 0;
var currentTabWidth;
var currentActiveTabWidth = 0;
var collapsibleMenu;
var ul = options.element || $("#"+options.id);
var wrapper = ul.wrap( "<div>" ).parent();
@@ -50,6 +52,55 @@ RED.tabs = (function() {
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();});
}
if (options.collapsible) {
// var dropDown = $('<div>',{class:"red-ui-tabs-select"}).appendTo(wrapper);
// ul.hide();
wrapper.addClass("red-ui-tabs-collapsible");
var collapsedButtonsRow = $('<div class="red-ui-tab-link-buttons"></div>').appendTo(wrapper);
var selectButton = $('<a href="#"><i class="fa fa-caret-down"></i></a>').appendTo(collapsedButtonsRow);
selectButton.addClass("red-ui-tab-link-button-menu")
selectButton.click(function(evt) {
evt.preventDefault();
if (!collapsibleMenu) {
var pinnedOptions = [];
var options = [];
ul.children().each(function(i,el) {
var id = $(el).data('tabId');
var opt = {
id:"red-ui-tabs-menu-option-"+id,
label: tabs[id].name,
onselect: function() {
activateTab(id);
}
};
if (tabs[id].pinned) {
pinnedOptions.push(opt);
} else {
options.push(opt);
}
});
options = pinnedOptions.concat(options);
collapsibleMenu = RED.menu.init({id:"debug-message-option-menu",options: options});
collapsibleMenu.css({
position: "absolute"
})
collapsibleMenu.on('mouseleave', function(){ $(this).hide() });
collapsibleMenu.on('mouseup', function() { $(this).hide() });
collapsibleMenu.appendTo("body");
var elementPos = selectButton.offset();
collapsibleMenu.css({
top: (elementPos.top+selectButton.height()-20)+"px",
left: (elementPos.left - collapsibleMenu.width() + selectButton.width())+"px"
})
}
collapsibleMenu.toggle();
})
}
function scrollEventHandler(evt,dir) {
evt.preventDefault();
if ($(this).hasClass('disabled')) {
@@ -118,6 +169,9 @@ RED.tabs = (function() {
ul.children().removeClass("active");
ul.children().css({"transition": "width 100ms"});
link.parent().addClass("active");
var parentId = link.parent().attr('id');
wrapper.find(".red-ui-tab-link-button").removeClass("active");
$("#"+parentId+"-link-button").addClass("active");
if (options.scrollable) {
var pos = link.parent().position().left;
if (pos-21 < 0) {
@@ -155,41 +209,70 @@ RED.tabs = (function() {
var tabs = ul.find("li.red-ui-tab");
var width = wrapper.width();
var tabCount = tabs.size();
var tabWidth = (width-12-(tabCount*6))/tabCount;
currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = currentTabWidth+"%";
if (options.scrollable) {
tabWidth = Math.max(tabWidth,140);
currentTabWidth = tabWidth+"px";
currentActiveTabWidth = 0;
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
ul.width(listWidth);
updateScroll();
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
if (tabWidth < options.minimumActiveTabWidth) {
tabCount -= 1;
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
var tabWidth;
if (options.collapsible) {
tabWidth = width - collapsedButtonsRow.width()-10;
if (tabWidth < 198) {
var delta = 198 - tabWidth;
var b = collapsedButtonsRow.find("a:last").prev();
while (b.is(":not(:visible)")) {
b = b.prev();
}
if (!b.hasClass("red-ui-tab-link-button-pinned")) {
b.hide();
}
tabWidth = width - collapsedButtonsRow.width()-10;
} else {
currentActiveTabWidth = 0;
var space = width - 198 - collapsedButtonsRow.width();
if (space > 40) {
collapsedButtonsRow.find("a:not(:visible):first").show();
tabWidth = width - collapsedButtonsRow.width()-10;
}
}
}
tabs.css({width:currentTabWidth});
if (tabWidth < 50) {
ul.find(".red-ui-tab-close").hide();
ul.find(".red-ui-tab-icon").hide();
ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"})
tabs.css({width:tabWidth});
} else {
ul.find(".red-ui-tab-close").show();
ul.find(".red-ui-tab-icon").show();
ul.find(".red-ui-tab-label").css({paddingLeft:""})
}
if (currentActiveTabWidth !== 0) {
ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth});
ul.find("li.red-ui-tab.active .red-ui-tab-close").show();
ul.find("li.red-ui-tab.active .red-ui-tab-icon").show();
ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""})
var tabWidth = (width-12-(tabCount*6))/tabCount;
currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = currentTabWidth+"%";
if (options.scrollable) {
tabWidth = Math.max(tabWidth,140);
currentTabWidth = tabWidth+"px";
currentActiveTabWidth = 0;
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
ul.width(listWidth);
updateScroll();
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
if (tabWidth < options.minimumActiveTabWidth) {
tabCount -= 1;
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
currentTabWidth = (100*tabWidth/width)+"%";
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
} else {
currentActiveTabWidth = 0;
}
}
if (options.collapsible) {
console.log(currentTabWidth);
}
tabs.css({width:currentTabWidth});
if (tabWidth < 50) {
ul.find(".red-ui-tab-close").hide();
ul.find(".red-ui-tab-icon").hide();
ul.find(".red-ui-tab-label").css({paddingLeft:Math.min(12,Math.max(0,tabWidth-38))+"px"})
} else {
ul.find(".red-ui-tab-close").show();
ul.find(".red-ui-tab-icon").show();
ul.find(".red-ui-tab-label").css({paddingLeft:""})
}
if (currentActiveTabWidth !== 0) {
ul.find("li.red-ui-tab.active").css({"width":options.minimumActiveTabWidth});
ul.find("li.red-ui-tab.active .red-ui-tab-close").show();
ul.find("li.red-ui-tab.active .red-ui-tab-icon").show();
ul.find("li.red-ui-tab.active .red-ui-tab-label").css({paddingLeft:""})
}
}
}
@@ -210,11 +293,15 @@ RED.tabs = (function() {
activateTab(tab.find("a"));
}
li.remove();
if (tabs[id].pinned) {
pinnedTabsCount--;
}
if (options.onremove) {
options.onremove(tabs[id]);
}
delete tabs[id];
updateTabWidths();
collapsibleMenu = null;
}
return {
@@ -223,13 +310,55 @@ RED.tabs = (function() {
var li = $("<li/>",{class:"red-ui-tab"}).appendTo(ul);
li.attr('id',"red-ui-tab-"+(tab.id.replace(".","-")));
li.data("tabId",tab.id);
if (options.maximumTabWidth) {
li.css("maxWidth",options.maximumTabWidth+"px");
}
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
if (tab.icon) {
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
} else if (tab.iconClass) {
$('<i>',{class:"red-ui-tab-icon "+tab.iconClass}).appendTo(link);
}
var span = $('<span/>',{class:"bidiAware"}).text(tab.label).appendTo(link);
span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label));
if (options.collapsible) {
li.addClass("red-ui-tab-pinned");
var pinnedLink = $('<a href="#'+tab.id+'" class="red-ui-tab-link-button"></a>');
if (tab.pinned) {
if (pinnedTabsCount === 0) {
pinnedLink.prependTo(collapsedButtonsRow)
} else {
pinnedLink.insertAfter(collapsedButtonsRow.find("a.red-ui-tab-link-button-pinned:last"));
}
} else {
pinnedLink.insertBefore(collapsedButtonsRow.find("a:last"));
}
pinnedLink.attr('id',li.attr('id')+"-link-button");
if (tab.iconClass) {
$('<i>',{class:tab.iconClass}).appendTo(pinnedLink);
} else {
$('<i>',{class:"fa fa-lemon-o"}).appendTo(pinnedLink);
}
pinnedLink.click(function(evt) {
evt.preventDefault();
activateTab(tab.id);
});
if (tab.pinned) {
pinnedLink.addClass("red-ui-tab-link-button-pinned");
pinnedTabsCount++;
}
RED.popover.create({
target:$(pinnedLink),
trigger: "hover",
size: "small",
direction: "bottom",
content: tab.name,
delay: { show: 550, hide: 10 }
});
}
link.on("click",onTabClick);
link.on("dblclick",onTabDblClick);
if (tab.closeable) {
@@ -326,6 +455,7 @@ RED.tabs = (function() {
}
})
}
collapsibleMenu = null;
},
removeTab: removeTab,
activateTab: activateTab,

View File

@@ -76,6 +76,11 @@
}
})
}
},
env: {
value: "env",
label: "env variable",
icon: "red/images/typedInput/env.png"
}
};
var nlsd = false;
@@ -116,7 +121,9 @@
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);
if (this.options.types.length > 1) {
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
}
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
this.types(this.options.types);

View File

@@ -408,9 +408,12 @@ RED.deploy = (function() {
delete confNode.credentials;
}
});
RED.nodes.eachSubflow(function(subflow) {
subflow.changed = false;
});
RED.nodes.eachWorkspace(function(ws) {
ws.changed = false;
})
});
// Once deployed, cannot undo back to a clean state
RED.history.markAllDirty();
RED.view.redraw();

View File

@@ -51,11 +51,11 @@ RED.diff = (function() {
var tabForLabel = (object.newTab || object.tab).n;
var titleSpan = $('<span>',{class:"node-diff-tab-title-meta"}).appendTo(originalCell);
if (tabForLabel.type === 'tab') {
titleSpan.html(tabForLabel.label||tabForLabel.id);
titleSpan.text(tabForLabel.label||tabForLabel.id);
} else if (tab.type === 'subflow') {
titleSpan.html((tabForLabel.name||tabForLabel.id));
titleSpan.text((tabForLabel.name||tabForLabel.id));
} else {
titleSpan.html(RED._("diff.globalNodes"));
titleSpan.text(RED._("diff.globalNodes"));
}
var flowStats = {
local: {
@@ -131,7 +131,7 @@ RED.diff = (function() {
}
}
$('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalNodeDiv);
$('<span>').html(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
$('<span>').text(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
row.click(function(evt) {
evt.preventDefault();
@@ -206,7 +206,7 @@ RED.diff = (function() {
}
}
var localStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(localCell);
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
$('<span class="node-diff-status"></span>').text(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
if (flowStats.conflicts + flowStats.local.addedCount + flowStats.local.changedCount + flowStats.local.deletedCount > 0) {
$('<span class="node-diff-status"> [ </span>').appendTo(localStats);
@@ -245,7 +245,7 @@ RED.diff = (function() {
}
}
var remoteStats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(remoteCell);
$('<span class="node-diff-status"></span>').html(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
$('<span class="node-diff-status"></span>').text(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
if (flowStats.conflicts + flowStats.remote.addedCount + flowStats.remote.changedCount + flowStats.remote.deletedCount > 0) {
$('<span class="node-diff-status"> [ </span>').appendTo(remoteStats);
if (flowStats.conflicts > 0) {
@@ -464,7 +464,7 @@ RED.diff = (function() {
wires.forEach(function(p,i) {
var port = $("<li>").appendTo(list);
if (p && p.length > 0) {
$("<span>").html(i+1).appendTo(port);
$("<span>").text(i+1).appendTo(port);
var links = $("<ul>").appendTo(port);
p.forEach(function(d) {
c++;
@@ -474,15 +474,15 @@ RED.diff = (function() {
var def = RED.nodes.getType(node.type)||{};
createNode(node,def).appendTo(entry);
} else {
entry.html(d);
entry.text(d);
}
})
} else {
port.html('none');
port.text('none');
}
})
if (c === 0) {
result.html("none");
result.text("none");
} else {
list.appendTo(result);
}
@@ -507,7 +507,7 @@ RED.diff = (function() {
createNodeIcon(node,def).appendTo(nodeTitleDiv);
var contentDiv = $('<div>',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
var nodeLabel = node.label || node.name || node.id;
$('<span>',{class:"node-diff-node-label"}).html(nodeLabel).appendTo(contentDiv);
$('<span>',{class:"node-diff-node-label"}).text(nodeLabel).appendTo(contentDiv);
return nodeTitleDiv;
}
function createNodeDiffRow(node,stats,CurrentDiff) {
@@ -739,7 +739,7 @@ RED.diff = (function() {
var status;
row = $("<tr>").appendTo(nodePropertiesTableBody);
$("<td>",{class:"node-diff-property-cell-label"}).html("id").appendTo(row);
$("<td>",{class:"node-diff-property-cell-label"}).text("id").appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) {
localCell.addClass("node-diff-node-unchanged");
@@ -782,7 +782,7 @@ RED.diff = (function() {
conflict = true;
}
row = $("<tr>").appendTo(nodePropertiesTableBody);
$("<td>",{class:"node-diff-property-cell-label"}).html("position").appendTo(row);
$("<td>",{class:"node-diff-property-cell-label"}).text("position").appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) {
localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged"));
@@ -850,7 +850,7 @@ RED.diff = (function() {
conflict = true;
}
row = $("<tr>").appendTo(nodePropertiesTableBody);
$("<td>",{class:"node-diff-property-cell-label"}).html("wires").appendTo(row);
$("<td>",{class:"node-diff-property-cell-label"}).text("wires").appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) {
if (!conflict) {
@@ -917,7 +917,7 @@ RED.diff = (function() {
}
row = $("<tr>").appendTo(nodePropertiesTableBody);
var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).html(d).appendTo(row);
var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).text(d).appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) {
if (!conflict) {
@@ -1233,7 +1233,7 @@ RED.diff = (function() {
// currentDiff = diff;
var trayOptions = {
title: options.title||"Review Changes", //TODO: nls
title: options.title||RED._("diff.reviewChanges"),
width: Infinity,
overlay: true,
buttons: [
@@ -1391,7 +1391,7 @@ RED.diff = (function() {
}
})
RED.nodes.version(remoteDiff.rev);
RED.nodes.version(diff.remoteDiff.rev);
RED.view.redraw(true);
RED.palette.refresh();
@@ -1416,7 +1416,7 @@ RED.diff = (function() {
function showTextDiff(textA,textB) {
var trayOptions = {
title: "Compare Changes", //TODO: nls
title: RED._("diff.compareChanges"),
width: Infinity,
overlay: true,
buttons: [
@@ -1721,80 +1721,17 @@ RED.diff = (function() {
if (commitOptions.unmerged) {
$('<span style="float: right;"><span id="node-diff-toolbar-resolved-conflicts"></span></span>').appendTo(content);
}
// var tools = $('<span style="float: right;" class="button-group"></span>').appendTo(content);
// $('<button class="editor-button editor-button-small">show flow diff</button>').appendTo(tools).click(function(e) {
// e.preventDefault();
// e.stopPropagation();
// var projectName = commitOptions.project.name;
// var filename = commitOptions.project.files.flow;
// var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
// var oldVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
// var newVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
// var promises = [];
// if (commitOptions.commonRev) {
// var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
// promises.push($.getJSON(commonVersionUrl));
// } else {
// promises.push($.when(null));
// }
// promises.push($.getJSON(oldVersionUrl));
// promises.push($.getJSON(newVersionUrl));
// $.when.apply($,promises).done(function(commonVersion, oldVersion,newVersion) {
// var commonFlow;
// var oldFlow;
// var newFlow;
// if (commonVersion) {
// try {
// commonFlow = JSON.parse(commonVersion[0].content||"[]");
// } catch(err) {
// console.log("Common Version doesn't contain valid JSON:",commonVersionUrl);
// console.log(err);
// return;
// }
// }
// try {
// oldFlow = JSON.parse(oldVersion[0].content||"[]");
// } catch(err) {
// console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
// console.log(err);
// return;
// }
// if (!commonFlow) {
// commonFlow = oldFlow;
// }
// try {
// newFlow = JSON.parse(newVersion[0].content||"[]");
// } catch(err) {
// console.log("New Version doesn't contain valid JSON:",newFlow);
// console.log(err);
// return;
// }
// var localDiff = generateDiff(commonFlow,oldFlow);
// var remoteDiff = generateDiff(commonFlow,newFlow);
// var diff = resolveDiffs(localDiff,remoteDiff);
// showDiff(diff,{
// title: filename,
// mode: commitOptions.commonRev?'merge':'view',
// oldRevTitle: commitOptions.oldRevTitle,
// newRevTitle: commitOptions.newRevTitle
// });
// // var flowDiffRow = $("<tr>").insertAfter(diffRow);
// // var content = $('<td colspan="3"></td>').appendTo(flowDiffRow);
// // currentDiff = diff;
// // var diffTable = buildDiffPanel(content,diff,{mode:"view"}).finish();
// });
// })
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
var flowDiffContent = $('<td class="flow-diff" colspan="3"></td>').appendTo(diffRow);
var projectName = commitOptions.project.name;
var filename = commitOptions.project.files.flow;
var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
var oldVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
var newVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
var commonVersionUrl = "projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
var oldVersionUrl = "projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
var newVersionUrl = "projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
var promises = [$.Deferred(),$.Deferred(),$.Deferred()];
if (commitOptions.commonRev) {
var commonVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
var commonVersionUrl = "projects/"+projectName+"/files/"+commitOptions.commonRev+"/"+filename;
$.ajax({dataType: "json",url: commonVersionUrl}).then(function(data) { promises[0].resolve(data); }).fail(function() { promises[0].resolve(null);})
} else {
promises[0].resolve(null);
@@ -1810,7 +1747,7 @@ RED.diff = (function() {
try {
commonFlow = JSON.parse(commonVersion.content||"[]");
} catch(err) {
console.log("Common Version doesn't contain valid JSON:",commonVersionUrl);
console.log(RED._("diff.commonVersionError"),commonVersionUrl);
console.log(err);
return;
}
@@ -1818,7 +1755,7 @@ RED.diff = (function() {
try {
oldFlow = JSON.parse(oldVersion.content||"[]");
} catch(err) {
console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
console.log(RED._("diff.oldVersionError"),oldVersionUrl);
console.log(err);
return;
}
@@ -1828,7 +1765,7 @@ RED.diff = (function() {
try {
newFlow = JSON.parse(newVersion.content||"[]");
} catch(err) {
console.log("New Version doesn't contain valid JSON:",newFlow);
console.log(RED._("diff.newVersionError"),newFlow);
console.log(err);
return;
}
@@ -1860,11 +1797,11 @@ RED.diff = (function() {
if (isBinary) {
var diffBinaryRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
var binaryContent = $('<td colspan="3"></td>').appendTo(diffBinaryRow);
$('<span></span>').text("Cannot show binary file contents").appendTo(binaryContent);
$('<span></span>').text(RED._("diff.noBinaryFileShowed")).appendTo(binaryContent);
} else {
if (commitOptions.unmerged) {
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content);
conflictHeader = $('<span style="float: right;">'+RED._("diff.conflictHeader",{resolved:resolvedConflicts, unresolved:unresolvedConflicts})+'</span>').appendTo(content);
}
hunks.forEach(function(hunk) {
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
@@ -1977,7 +1914,7 @@ RED.diff = (function() {
diffRow.remove();
addedRows.find(".linetext").addClass('added');
conflictHeader.empty();
$('<span><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(conflictHeader);
$('<span>'+RED._("diff.conflictHeader",{resolved:resolvedConflicts, unresolved:unresolvedConflicts})+'</span>').appendTo(conflictHeader);
conflictResolutions[file.file] = conflictResolutions[file.file] || {};
conflictResolutions[file.file][hunk.localChangeStart] = {
@@ -2009,7 +1946,7 @@ RED.diff = (function() {
function showCommitDiff(options) {
var commit = parseCommitDiff(options.commit);
var trayOptions = {
title: "View Commit Changes", //TODO: nls
title: RED._("diff.viewCommitDiff"),
width: Infinity,
overlay: true,
buttons: [
@@ -2071,7 +2008,7 @@ RED.diff = (function() {
}
var trayOptions = {
title: title||"Compare Changes", //TODO: nls
title: title|| RED._("diff.compareChanges"),
width: Infinity,
overlay: true,
buttons: [
@@ -2104,7 +2041,7 @@ RED.diff = (function() {
trayOptions.buttons.push(
{
id: "node-diff-view-resolve-diff",
text: "Save conflict resolution",
text: RED._("diff.saveConflict"),
class: "primary disabled",
click: function() {
if (!$("#node-diff-view-resolve-diff").hasClass('disabled')) {

View File

@@ -48,7 +48,7 @@ RED.editor = (function() {
isValid = validateNode(subflow);
hasChanged = subflow.changed;
}
node.valid = isValid;
node.valid = isValid && validateNodeProperties(node, node._def.defaults, node);
node.changed = node.changed || hasChanged;
} else if (node._def) {
node.valid = validateNodeProperties(node, node._def.defaults, node);
@@ -108,17 +108,6 @@ RED.editor = (function() {
}
}
}
if (node.icon) {
var iconPath = RED.utils.separateIconPath(node.icon);
if (!iconPath.module) {
return isValid;
}
var iconSets = RED.nodes.getIconSets();
var iconFileList = iconSets[iconPath.module];
if (!iconFileList || iconFileList.indexOf(iconPath.file) === -1) {
isValid = false;
}
}
return isValid;
}
@@ -170,24 +159,8 @@ RED.editor = (function() {
}
}
}
if (node._def.hasOwnProperty("defaults") && !node._def.defaults.hasOwnProperty("icon") && node.icon) {
var iconPath = RED.utils.separateIconPath(node.icon);
var iconSets = RED.nodes.getIconSets();
var iconFileList = iconSets[iconPath.module];
var iconModule = $("#node-settings-icon-module");
var iconFile = $("#node-settings-icon-file");
if (!iconFileList) {
iconModule.addClass("input-error");
iconFile.removeClass("input-error");
} else if (iconFileList.indexOf(iconPath.file) === -1) {
iconModule.removeClass("input-error");
iconFile.addClass("input-error");
} else {
iconModule.removeClass("input-error");
iconFile.removeClass("input-error");
}
}
}
function validateNodeEditorProperty(node,defaults,property,prefix) {
var input = $("#"+prefix+"-"+property);
if (input.length > 0) {
@@ -655,7 +628,7 @@ RED.editor = (function() {
return A.i-B.i;
})
rows.forEach(function(r,i) {
r.r.find("label").html((i+1)+".");
r.r.find("label").text((i+1)+".");
r.r.appendTo(outputsDiv);
})
if (rows.length === 0) {
@@ -691,12 +664,12 @@ RED.editor = (function() {
function buildLabelRow(type, index, value, placeHolder) {
var result = $('<div>',{class:"node-label-form-row"});
if (type === undefined) {
$('<span>').html(RED._("editor.noDefaultLabel")).appendTo(result);
$('<span>').text(RED._("editor.noDefaultLabel")).appendTo(result);
result.addClass("node-label-form-none");
} else {
result.addClass("");
var id = "node-label-form-"+type+"-"+index;
$('<label>',{for:id}).html((index+1)+".").appendTo(result);
$('<label>',{for:id}).text((index+1)+".").appendTo(result);
var input = $('<input>',{type:"text",id:id, placeholder: placeHolder}).val(value).appendTo(result);
var clear = $('<button class="editor-button editor-button-small"><i class="fa fa-times"></i></button>').appendTo(result);
clear.click(function(evt) {
@@ -706,6 +679,97 @@ RED.editor = (function() {
}
return result;
}
function showIconPicker(container, node, iconPath, done) {
var containerPos = container.offset();
var pickerBackground = $('<div>').css({
position: "absolute",top:0,bottom:0,left:0,right:0,zIndex:20
}).appendTo("body");
var top = containerPos.top - 30;
if (top+280 > $( window ).height()) {
top = $( window ).height() - 280;
}
var picker = $('<div class="red-ui-icon-picker">').css({
top: top+"px",
left: containerPos.left+"px",
}).appendTo("body");
var hide = function() {
pickerBackground.remove();
picker.remove();
RED.keyboard.remove("escape");
}
RED.keyboard.add("*","escape",function(){hide()});
pickerBackground.on("mousedown", hide);
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(picker);
searchInput = $('<input type="text">').attr("placeholder","Search icons").appendTo(searchDiv).searchBox({
delay: 50,
change: function() {
var searchTerm = $(this).val().trim();
if (searchTerm === "") {
iconList.find(".red-ui-icon-list-module").show();
iconList.find(".red-ui-icon-list-icon").show();
} else {
iconList.find(".red-ui-icon-list-module").hide();
iconList.find(".red-ui-icon-list-icon").each(function(i,n) {
if ($(n).data('icon').indexOf(searchTerm) === -1) {
$(n).hide();
} else {
$(n).show();
}
});
}
}
});
var row = $('<div>').appendTo(picker);
var iconList = $('<div class="red-ui-icon-list">').appendTo(picker);
var metaRow = $('<div class="red-ui-icon-meta"></div>').appendTo(picker);
var summary = $('<span>').appendTo(metaRow);
var resetButton = $('<button class="editor-button editor-button-small">use default</button>').appendTo(metaRow).click(function(e) {
e.preventDefault();
hide();
done(null);
});
var iconSets = RED.nodes.getIconSets();
Object.keys(iconSets).forEach(function(moduleName) {
var icons = iconSets[moduleName];
if (icons.length > 0) {
// selectIconModule.append($("<option></option>").val(moduleName).text(moduleName));
var header = $('<div class="red-ui-icon-list-module"></div>').text(moduleName).appendTo(iconList);
$('<i class="fa fa-cube"></i>').prependTo(header);
icons.forEach(function(icon) {
var iconDiv = $('<div>',{class:"red-ui-icon-list-icon"}).appendTo(iconList);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconDiv);
var colour = node._def.color;
var icon_url = "icons/"+moduleName+"/"+icon;
iconDiv.data('icon',icon_url)
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 (iconPath.module === moduleName && iconPath.file === icon) {
iconDiv.addClass("selected");
}
iconDiv.on("mouseover", function() {
summary.text(icon);
})
iconDiv.on("mouseout", function() {
summary.html("&nbsp;");
})
iconDiv.click(function() {
hide();
done(moduleName+"/"+icon);
})
})
}
});
picker.slideDown(100);
searchInput.focus();
}
function buildLabelForm(container,node) {
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
@@ -742,81 +806,78 @@ RED.editor = (function() {
buildLabelRow().appendTo(outputsDiv);
}
if (!node._def.defaults.hasOwnProperty("icon")) {
$('<div class="form-row"><div id="node-settings-icon"></div></div>').appendTo(dialogForm);
var iconDiv = $("#node-settings-icon");
$('<label data-i18n="editor.settingIcon">').appendTo(iconDiv);
var iconForm = $('<div>',{class:"node-label-form-row"});
iconForm.appendTo(iconDiv);
$('<label>').appendTo(iconForm);
if ((!node._def.defaults || !node._def.defaults.hasOwnProperty("icon"))) {
$('<hr>').appendTo(dialogForm);
var iconRow = $('<div class="form-row"></div>').appendTo(dialogForm);
$('<label style="width: 50px" data-i18n="editor.settingIcon">').appendTo(iconRow);
var selectIconModule = $('<select id="node-settings-icon-module"><option value=""></option></select>').appendTo(iconForm);
var iconPath;
if (node.icon) {
iconPath = RED.utils.separateIconPath(node.icon);
} else {
iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
}
var iconSets = RED.nodes.getIconSets();
Object.keys(iconSets).forEach(function(moduleName) {
selectIconModule.append($("<option></option>").val(moduleName).text(moduleName));
});
if (iconPath.module && !iconSets[iconPath.module]) {
selectIconModule.append($("<option disabled></option>").val(iconPath.module).text(iconPath.module));
}
selectIconModule.val(iconPath.module);
var iconModuleHidden = $('<input type="hidden" id="node-settings-icon-module-hidden"></input>').appendTo(iconForm);
iconModuleHidden.val(iconPath.module);
var iconButton = $('<button class="editor-button">').appendTo(iconRow);
var selectIconFile = $('<select id="node-settings-icon-file"><option value=""></option></select>').appendTo(iconForm);
selectIconModule.change(function() {
moduleChange(selectIconModule, selectIconFile, iconModuleHidden, iconFileHidden, iconSets, true);
});
var iconFileHidden = $('<input type="hidden" id="node-settings-icon-file-hidden"></input>').appendTo(iconForm);
iconFileHidden.val(iconPath.file);
selectIconFile.change(function() {
selectIconFile.removeClass("input-error");
var fileName = selectIconFile.val();
iconFileHidden.val(fileName);
});
var clear = $('<button class="editor-button editor-button-small"><i class="fa fa-times"></i></button>').appendTo(iconForm);
clear.click(function(evt) {
evt.preventDefault();
var iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
selectIconModule.val(iconPath.module);
moduleChange(selectIconModule, selectIconFile, iconModuleHidden, iconFileHidden, iconSets, true);
selectIconFile.removeClass("input-error");
selectIconFile.val(iconPath.file);
iconFileHidden.val(iconPath.file);
});
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconButton);
var colour = node._def.color;
var icon_url = RED.utils.getNodeIcon(node._def,node);
nodeDiv.css('backgroundColor',colour);
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
var iconDiv = $('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
moduleChange(selectIconModule, selectIconFile, iconModuleHidden, iconFileHidden, iconSets, false);
var iconFileList = iconSets[selectIconModule.val()];
if (!iconFileList || iconFileList.indexOf(iconPath.file) === -1) {
selectIconFile.append($("<option disabled></option>").val(iconPath.file).text(iconPath.file));
}
selectIconFile.val(iconPath.file);
iconButton.click(function(e) {
e.preventDefault();
var iconPath;
var icon = $("#node-settings-icon").text()||"";
if (icon) {
iconPath = RED.utils.separateIconPath(icon);
} else {
iconPath = RED.utils.getDefaultNodeIcon(node._def, node);
}
showIconPicker(iconRow,node,iconPath,function(newIcon) {
$("#node-settings-icon").text(newIcon||"");
var icon_url = RED.utils.getNodeIcon(node._def,{type:node.type,icon:newIcon});
iconDiv.css("backgroundImage","url("+icon_url+")");
});
})
$('<div class="uneditable-input" id="node-settings-icon">').text(node.icon).appendTo(iconRow);
}
}
function moduleChange(selectIconModule, selectIconFile, iconModuleHidden, iconFileHidden, iconSets, updateIconFile) {
selectIconFile.children().remove();
var moduleName = selectIconModule.val();
if (moduleName !== null) {
iconModuleHidden.val(moduleName);
function updateLabels(editing_node, changes, outputMap) {
var inputLabels = $("#node-label-form-inputs").children().find("input");
var outputLabels = $("#node-label-form-outputs").children().find("input");
var hasNonBlankLabel = false;
var changed = false;
var newValue = inputLabels.map(function() {
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
return v;
}).toArray().slice(0,editing_node.inputs);
if ((editing_node.inputLabels === undefined && hasNonBlankLabel) ||
(editing_node.inputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.inputLabels))) {
changes.inputLabels = editing_node.inputLabels;
editing_node.inputLabels = newValue;
changed = true;
}
var iconFileList = iconSets[moduleName];
if (iconFileList) {
iconFileList.forEach(function(fileName) {
if (updateIconFile) {
updateIconFile = false;
iconFileHidden.val(fileName);
hasNonBlankLabel = false;
newValue = new Array(editing_node.outputs);
outputLabels.each(function() {
var index = $(this).attr('id').substring(23); // node-label-form-output-<index>
if (outputMap && outputMap.hasOwnProperty(index)) {
index = parseInt(outputMap[index]);
if (index === -1) {
return;
}
selectIconFile.append($("<option></option>").val(fileName).text(fileName));
});
}
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
newValue[index] = v;
});
if ((editing_node.outputLabels === undefined && hasNonBlankLabel) ||
(editing_node.outputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.outputLabels))) {
changes.outputLabels = editing_node.outputLabels;
editing_node.outputLabels = newValue;
changed = true;
}
selectIconFile.prop("disabled", !iconFileList);
selectIconModule.removeClass("input-error");
return changed;
}
function showEditDialog(node) {
@@ -1034,47 +1095,12 @@ RED.editor = (function() {
// }
var removedLinks = updateNodeProperties(editing_node,outputMap);
var inputLabels = $("#node-label-form-inputs").children().find("input");
var outputLabels = $("#node-label-form-outputs").children().find("input");
var hasNonBlankLabel = false;
newValue = inputLabels.map(function() {
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
return v;
}).toArray().slice(0,editing_node.inputs);
if ((editing_node.inputLabels === undefined && hasNonBlankLabel) ||
(editing_node.inputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.inputLabels))) {
changes.inputLabels = editing_node.inputLabels;
editing_node.inputLabels = newValue;
changed = true;
}
hasNonBlankLabel = false;
newValue = new Array(editing_node.outputs);
outputLabels.each(function() {
var index = $(this).attr('id').substring(23); // node-label-form-output-<index>
if (outputMap && outputMap.hasOwnProperty(index)) {
index = parseInt(outputMap[index]);
if (index === -1) {
return;
}
}
var v = $(this).val();
hasNonBlankLabel = hasNonBlankLabel || v!== "";
newValue[index] = v;
})
if ((editing_node.outputLabels === undefined && hasNonBlankLabel) ||
(editing_node.outputLabels !== undefined && JSON.stringify(newValue) !== JSON.stringify(editing_node.outputLabels))) {
changes.outputLabels = editing_node.outputLabels;
editing_node.outputLabels = newValue;
if (updateLabels(editing_node, changes, outputMap)) {
changed = true;
}
if (!editing_node._def.defaults.hasOwnProperty("icon")) {
var iconModule = $("#node-settings-icon-module-hidden").val();
var iconFile = $("#node-settings-icon-file-hidden").val();
var icon = (iconModule && iconFile) ? iconModule+"/"+iconFile : "";
if (!editing_node._def.defaults || !editing_node._def.defaults.hasOwnProperty("icon")) {
var icon = $("#node-settings-icon").text()||""
if (!isDefaultIcon) {
if (icon !== editing_node.icon) {
changes.icon = editing_node.icon;
@@ -1352,7 +1378,7 @@ RED.editor = (function() {
dialogForm.i18n();
if (node_def.hasUsers !== false) {
$("#node-config-dialog-user-count").find("span").html(RED._("editor.nodesUse", {count:editing_config_node.users.length})).parent().show();
$("#node-config-dialog-user-count").find("span").text(RED._("editor.nodesUse", {count:editing_config_node.users.length})).parent().show();
}
done();
});
@@ -1675,25 +1701,38 @@ RED.editor = (function() {
editing_node.info = newDescription;
changed = true;
}
var inputLabels = $("#node-label-form-inputs").children().find("input");
var outputLabels = $("#node-label-form-outputs").children().find("input");
var newValue = inputLabels.map(function() { return $(this).val();}).toArray().slice(0,editing_node.inputs);
if (JSON.stringify(newValue) !== JSON.stringify(editing_node.inputLabels)) {
changes.inputLabels = editing_node.inputLabels;
editing_node.inputLabels = newValue;
if (updateLabels(editing_node, changes, null)) {
changed = true;
}
newValue = outputLabels.map(function() { return $(this).val();}).toArray().slice(0,editing_node.outputs);
if (JSON.stringify(newValue) !== JSON.stringify(editing_node.outputLabels)) {
changes.outputLabels = editing_node.outputLabels;
editing_node.outputLabels = newValue;
var icon = $("#node-settings-icon").text()||"";
if ((editing_node.icon === undefined && icon !== "node-red/subflow.png") ||
(editing_node.icon !== undefined && editing_node.icon !== icon)) {
changes.icon = editing_node.icon;
editing_node.icon = icon;
changed = true;
}
var newCategory = $("#subflow-input-category").val().trim();
if (newCategory === "_custom_") {
newCategory = $("#subflow-input-custom-category").val().trim();
if (newCategory === "") {
newCategory = editing_node.category;
}
}
if (newCategory === 'subflows') {
newCategory = '';
}
if (newCategory != editing_node.category) {
changes['category'] = editing_node.category;
editing_node.category = newCategory;
changed = true;
}
RED.palette.refresh();
if (changed) {
var wasChanged = editing_node.changed;
editing_node.changed = true;
validateNode(editing_node);
var subflowInstances = [];
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+editing_node.id) {
@@ -1704,10 +1743,9 @@ RED.editor = (function() {
n.changed = true;
n.dirty = true;
updateNodeProperties(n);
validateNode(n);
}
});
var wasChanged = editing_node.changed;
editing_node.changed = true;
RED.nodes.dirty(true);
var historyEvent = {
t:'edit',
@@ -1760,8 +1798,6 @@ RED.editor = (function() {
});
portLabels.content.addClass("editor-tray-content");
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
}
@@ -1774,6 +1810,33 @@ RED.editor = (function() {
$("#subflow-input-name").val(subflow.name);
RED.text.bidi.prepareInput($("#subflow-input-name"));
$("#subflow-input-category").empty();
var categories = RED.palette.getCategories();
categories.sort(function(A,B) {
return A.label.localeCompare(B.label);
})
categories.forEach(function(cat) {
$("#subflow-input-category").append($("<option></option>").val(cat.id).text(cat.label));
})
$("#subflow-input-category").append($("<option></option>").attr('disabled',true).text("---"));
$("#subflow-input-category").append($("<option></option>").val("_custom_").text(RED._("palette.addCategory")));
$("#subflow-input-category").change(function() {
var val = $(this).val();
if (val === "_custom_") {
$("#subflow-input-category").width(120);
$("#subflow-input-custom-category").show();
} else {
$("#subflow-input-category").width(250);
$("#subflow-input-custom-category").hide();
}
})
$("#subflow-input-category").val(subflow.category||"subflows");
subflowEditor.getSession().setValue(subflow.info||"",-1);
var userCount = 0;
var subflowType = "subflow:"+editing_node.id;
@@ -1783,7 +1846,7 @@ RED.editor = (function() {
userCount++;
}
});
$("#subflow-dialog-user-count").html(RED._("subflow.subflowInstances", {count:userCount})).show();
$("#subflow-dialog-user-count").text(RED._("subflow.subflowInstances", {count:userCount})).show();
buildLabelForm(portLabels.content,subflow);
trayBody.i18n();
@@ -1839,7 +1902,7 @@ RED.editor = (function() {
text: RED._("common.label.done"),
class: "primary",
click: function() {
$("#node-input-expression-help").html("");
$("#node-input-expression-help").text("");
onComplete(expressionEditor.getValue());
RED.tray.close();
}

View File

@@ -389,6 +389,7 @@ RED.keyboard = (function() {
var currentEditorSettings = RED.settings.get('editor') || {};
var userKeymap = currentEditorSettings.keymap || {};
userKeymap[object.id] = null;
currentEditorSettings.keymap = userKeymap;
RED.settings.set('editor',currentEditorSettings);
var obj = {
@@ -442,6 +443,7 @@ RED.keyboard = (function() {
var currentEditorSettings = RED.settings.get('editor') || {};
var userKeymap = currentEditorSettings.keymap || {};
userKeymap[object.id] = RED.keyboard.getShortcut(object.id);
currentEditorSettings.keymap = userKeymap;
RED.settings.set('editor',currentEditorSettings);
}
}

View File

@@ -414,12 +414,8 @@ RED.library = (function() {
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
RED.menu.setDisabled("menu-item-export-clipboard",true);
RED.menu.setDisabled("menu-item-export-library",true);
} else {
RED.menu.setDisabled("menu-item-export",false);
RED.menu.setDisabled("menu-item-export-clipboard",false);
RED.menu.setDisabled("menu-item-export-library",false);
}
});

View File

@@ -96,7 +96,7 @@ RED.notifications = (function() {
if (options.buttons) {
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(n)
options.buttons.forEach(function(buttonDef) {
var b = $('<button>').html(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
var b = $('<button>').text(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
if (buttonDef.id) {
b.attr('id',buttonDef.id);
}
@@ -171,7 +171,7 @@ RED.notifications = (function() {
if (options.buttons) {
var buttonSet = $('<div style="margin-top: 20px;" class="ui-dialog-buttonset"></div>').appendTo(nn)
options.buttons.forEach(function(buttonDef) {
var b = $('<button>').html(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
var b = $('<button>').text(buttonDef.text).click(buttonDef.click).appendTo(buttonSet);
if (buttonDef.id) {
b.attr('id',buttonDef.id);
}

View File

@@ -208,6 +208,8 @@ RED.palette.editor = (function() {
if (nodeEntry) {
var activeTypeCount = 0;
var typeCount = 0;
var errorCount = 0;
nodeEntry.errorList.empty();
nodeEntries[module].totalUseCount = 0;
nodeEntries[module].setUseCount = {};
@@ -216,7 +218,10 @@ RED.palette.editor = (function() {
var inUseCount = 0;
var set = moduleInfo.sets[setName];
var setElements = nodeEntry.sets[setName];
if (set.err) {
errorCount++;
$("<li>").text(set.err).appendTo(nodeEntry.errorList);
}
if (set.enabled) {
activeTypeCount += set.types.length;
}
@@ -242,24 +247,31 @@ RED.palette.editor = (function() {
nodeEntries[module].totalUseCount += inUseCount;
if (inUseCount > 0) {
setElements.enableButton.html(RED._('palette.editor.inuse'));
setElements.enableButton.text(RED._('palette.editor.inuse'));
setElements.enableButton.addClass('disabled');
} else {
setElements.enableButton.removeClass('disabled');
if (set.enabled) {
setElements.enableButton.html(RED._('palette.editor.disable'));
setElements.enableButton.text(RED._('palette.editor.disable'));
} else {
setElements.enableButton.html(RED._('palette.editor.enable'));
setElements.enableButton.text(RED._('palette.editor.enable'));
}
}
setElements.setRow.toggleClass("palette-module-set-disabled",!set.enabled);
}
}
if (errorCount === 0) {
nodeEntry.errorRow.hide()
} else {
nodeEntry.errorRow.show();
}
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
nodeEntry.setCount.html(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
nodeEntry.setCount.text(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
if (nodeEntries[module].totalUseCount > 0) {
nodeEntry.enableButton.html(RED._('palette.editor.inuse'));
nodeEntry.enableButton.text(RED._('palette.editor.inuse'));
nodeEntry.enableButton.addClass('disabled');
nodeEntry.removeButton.hide();
} else {
@@ -268,20 +280,20 @@ RED.palette.editor = (function() {
nodeEntry.removeButton.css('display', 'inline-block');
}
if (activeTypeCount === 0) {
nodeEntry.enableButton.html(RED._('palette.editor.enableall'));
nodeEntry.enableButton.text(RED._('palette.editor.enableall'));
} else {
nodeEntry.enableButton.html(RED._('palette.editor.disableall'));
nodeEntry.enableButton.text(RED._('palette.editor.disableall'));
}
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
}
}
if (moduleInfo.pending_version) {
nodeEntry.versionSpan.html(moduleInfo.version+' <i class="fa fa-long-arrow-right"></i> '+moduleInfo.pending_version).appendTo(nodeEntry.metaRow)
nodeEntry.updateButton.html(RED._('palette.editor.updated')).addClass('disabled').show();
nodeEntry.updateButton.text(RED._('palette.editor.updated')).addClass('disabled').show();
} else if (loadedIndex.hasOwnProperty(module)) {
if (semVerCompare(loadedIndex[module].version,moduleInfo.version) === 1) {
nodeEntry.updateButton.show();
nodeEntry.updateButton.html(RED._('palette.editor.update',{version:loadedIndex[module].version}));
nodeEntry.updateButton.text(RED._('palette.editor.update',{version:loadedIndex[module].version}));
} else {
nodeEntry.updateButton.hide();
}
@@ -355,7 +367,7 @@ RED.palette.editor = (function() {
loadedIndex = {};
packageList.editableList('empty');
$(".palette-module-shade-status").html(RED._('palette.editor.loading'));
$(".palette-module-shade-status").text(RED._('palette.editor.loading'));
var catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json'];
catalogueLoadStatus = [];
catalogueLoadErrors = false;
@@ -461,7 +473,7 @@ RED.palette.editor = (function() {
if (filteredList[i].info.id === ns.module) {
var installButton = filteredList[i].elements.installButton;
installButton.addClass('disabled');
installButton.html(RED._('palette.editor.installed'));
installButton.text(RED._('palette.editor.installed'));
break;
}
}
@@ -477,7 +489,7 @@ RED.palette.editor = (function() {
if (filteredList[i].info.id === ns.module) {
var installButton = filteredList[i].elements.installButton;
installButton.removeClass('disabled');
installButton.html(RED._('palette.editor.install'));
installButton.text(RED._('palette.editor.install'));
break;
}
}
@@ -583,15 +595,18 @@ RED.palette.editor = (function() {
if (entry) {
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
var titleRow = $('<div class="palette-module-meta palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
$('<span>').html(entry.name).appendTo(titleRow);
$('<span>').text(entry.name).appendTo(titleRow);
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
var errorRow = $('<div class="palette-module-meta palette-module-errors"><i class="fa fa-warning"></i></div>').hide().appendTo(headerRow);
var errorList = $('<ul class="palette-module-error-list"></ul>').appendTo(errorRow);
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
var setButton = $('<a href="#" class="editor-button editor-button-small palette-module-set-button"><i class="fa fa-angle-right palette-module-node-chevron"></i> </a>').appendTo(buttonRow);
var setCount = $('<span>').appendTo(setButton);
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.update')).appendTo(buttonGroup);
var updateButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.update')).appendTo(buttonGroup);
updateButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
updateButton.click(function(evt) {
evt.preventDefault();
@@ -602,7 +617,7 @@ RED.palette.editor = (function() {
})
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.remove')).appendTo(buttonGroup);
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.remove')).appendTo(buttonGroup);
removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
removeButton.click(function(evt) {
evt.preventDefault();
@@ -611,7 +626,7 @@ RED.palette.editor = (function() {
if (!entry.local) {
removeButton.hide();
}
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.disableall')).appendTo(buttonGroup);
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.disableall')).appendTo(buttonGroup);
var contentRow = $('<div>',{class:"palette-module-content"}).appendTo(container);
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
@@ -620,6 +635,8 @@ RED.palette.editor = (function() {
updateButton: updateButton,
removeButton: removeButton,
enableButton: enableButton,
errorRow: errorRow,
errorList: errorList,
setCount: setCount,
container: container,
shade: shade,
@@ -649,9 +666,8 @@ RED.palette.editor = (function() {
set.types.forEach(function(t) {
var typeDiv = $('<div>',{class:"palette-module-type"}).appendTo(setRow);
typeSwatches[t] = $('<span>',{class:"palette-module-type-swatch"}).appendTo(typeDiv);
$('<span>',{class:"palette-module-type-node"}).html(t).appendTo(typeDiv);
$('<span>',{class:"palette-module-type-node"}).text(t).appendTo(typeDiv);
})
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').appendTo(buttonGroup);
enableButton.click(function(evt) {
evt.preventDefault();
@@ -689,7 +705,7 @@ RED.palette.editor = (function() {
})
refreshNodeModule(entry.name);
} else {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
}
}
});
@@ -729,7 +745,7 @@ RED.palette.editor = (function() {
});
$('<span>').html(RED._("palette.editor.sort")+' ').appendTo(toolBar);
$('<span>').text(RED._("palette.editor.sort")+' ').appendTo(toolBar);
var sortGroup = $('<span class="button-group"></span>').appendTo(toolBar);
var sortAZ = $('<a href="#" class="sidebar-header-button-toggle selected" data-i18n="palette.editor.sortAZ"></a>').appendTo(sortGroup);
var sortRecent = $('<a href="#" class="sidebar-header-button-toggle" data-i18n="palette.editor.sortRecent"></a>').appendTo(sortGroup);
@@ -771,13 +787,13 @@ RED.palette.editor = (function() {
scrollOnAdd: false,
addItem: function(container,i,object) {
if (object.count) {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container);
$('<div>',{class:"red-ui-search-empty"}).text(RED._('palette.editor.moduleCount',{count:object.count})).appendTo(container);
return
}
if (object.more) {
container.addClass('palette-module-more');
var moreRow = $('<div>',{class:"palette-module-header palette-module"}).appendTo(container);
var moreLink = $('<a href="#"></a>').html(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
var moreLink = $('<a href="#"></a>').text(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
moreLink.click(function(e) {
e.preventDefault();
packageList.editableList('removeItem',object);
@@ -794,17 +810,17 @@ RED.palette.editor = (function() {
var entry = object.info;
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
var titleRow = $('<div class="palette-module-meta"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
$('<span>',{class:"palette-module-name"}).html(entry.name||entry.id).appendTo(titleRow);
$('<span>',{class:"palette-module-name"}).text(entry.name||entry.id).appendTo(titleRow);
$('<a target="_blank" class="palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow);
var descRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
$('<div>',{class:"palette-module-description"}).html(entry.description).appendTo(descRow);
$('<div>',{class:"palette-module-description"}).text(entry.description).appendTo(descRow);
var metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
$('<span class="palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
$('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup);
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').text(RED._('palette.editor.install')).appendTo(buttonGroup);
installButton.click(function(e) {
e.preventDefault();
if (!$(this).hasClass('disabled')) {
@@ -813,14 +829,14 @@ RED.palette.editor = (function() {
})
if (nodeEntries.hasOwnProperty(entry.id)) {
installButton.addClass('disabled');
installButton.html(RED._('palette.editor.installed'));
installButton.text(RED._('palette.editor.installed'));
}
object.elements = {
installButton:installButton
}
} else {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
}
}
});

View File

@@ -21,7 +21,18 @@ RED.palette = (function() {
var categoryContainers = {};
function createCategoryContainer(category, label) {
function createCategory(originalCategory,rootCategory,category,ns) {
if ($("#palette-base-category-"+rootCategory).length === 0) {
createCategoryContainer(originalCategory,rootCategory, ns+":palette.label."+rootCategory);
}
$("#palette-container-"+rootCategory).show();
if ($("#palette-"+category).length === 0) {
$("#palette-base-category-"+rootCategory).append('<div id="palette-'+category+'"></div>');
}
}
function createCategoryContainer(originalCategory,category, labelId) {
var label = RED._(labelId, {defaultValue:category});
label = (label || category).replace(/_/g, " ");
var catDiv = $('<div id="palette-container-'+category+'" class="palette-category palette-close hide">'+
'<div id="palette-header-'+category+'" class="palette-header"><i class="expanded fa fa-angle-down"></i><span>'+label+'</span></div>'+
@@ -31,7 +42,8 @@ RED.palette = (function() {
'<div id="palette-'+category+'-function"></div>'+
'</div>'+
'</div>').appendTo("#palette-container");
catDiv.data('category',originalCategory);
catDiv.data('label',label);
categoryContainers[category] = {
container: catDiv,
close: function() {
@@ -116,6 +128,12 @@ RED.palette = (function() {
el.data('popover').setContent(popOverContent);
}
function setIcon(element,sf) {
var iconElement = element.find(".palette_icon");
var icon_url = RED.utils.getNodeIcon(sf._def,sf);
iconElement.attr("style", "background-image: url("+icon_url+")");
}
function escapeNodeType(nt) {
return nt.replace(" ","_").replace(".","_").replace(":","_");
}
@@ -127,6 +145,7 @@ RED.palette = (function() {
}
if (exclusion.indexOf(def.category)===-1) {
var originalCategory = def.category;
var category = def.category.replace(/ /g,"_");
var rootCategory = category.split("-")[0];
@@ -147,7 +166,6 @@ RED.palette = (function() {
d.className="palette_node";
if (def.icon) {
var icon_url = RED.utils.getNodeIcon(def);
var iconContainer = $('<div/>',{class:"palette_icon_container"+(def.align=="right"?" palette_icon_container_right":"")}).appendTo(d);
@@ -168,21 +186,12 @@ RED.palette = (function() {
d.appendChild(portIn);
}
if ($("#palette-base-category-"+rootCategory).length === 0) {
if(coreCategories.indexOf(rootCategory) !== -1){
createCategoryContainer(rootCategory, RED._("node-red:palette.label."+rootCategory, {defaultValue:rootCategory}));
} else {
var ns = def.set.id;
createCategoryContainer(rootCategory, RED._(ns+":palette.label."+rootCategory, {defaultValue:rootCategory}));
}
}
$("#palette-container-"+rootCategory).show();
if ($("#palette-"+category).length === 0) {
$("#palette-base-category-"+rootCategory).append('<div id="palette-'+category+'"></div>');
}
createCategory(def.category,rootCategory,category,(coreCategories.indexOf(rootCategory) !== -1)?"node-red":def.set.id);
$("#palette-"+category).append(d);
$(d).data('category',rootCategory);
d.onmousedown = function(e) { e.preventDefault(); };
var popover = RED.popover.create({
@@ -302,7 +311,7 @@ RED.palette = (function() {
});
var nodeInfo = null;
if (def.category == "subflows") {
if (nt.indexOf("subflow:") === 0) {
$(d).dblclick(function(e) {
RED.workspaces.show(nt.substring(8));
e.preventDefault();
@@ -375,6 +384,32 @@ RED.palette = (function() {
portOutput.remove();
}
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||""));
setIcon(paletteNode,sf);
var currentCategory = paletteNode.data('category');
var newCategory = (sf.category||"subflows");
if (currentCategory !== newCategory) {
var category = newCategory.replace(/ /g,"_");
createCategory(newCategory,category,category,"node-red");
var currentCategoryNode = paletteNode.closest(".palette-category");
var newCategoryNode = $("#palette-"+category);
newCategoryNode.append(paletteNode);
if (newCategoryNode.find(".palette_node").length === 1) {
categoryContainers[category].open();
}
paletteNode.data('category',newCategory);
if (currentCategoryNode.find(".palette_node").length === 0) {
if (currentCategoryNode.find("i").hasClass("expanded")) {
currentCategoryNode.find(".palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
}
}
}
});
}
@@ -464,7 +499,7 @@ RED.palette = (function() {
categoryList = coreCategories
}
categoryList.forEach(function(category){
createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category}));
createCategoryContainer(category, category, "palette.label."+category);
});
$("#palette-collapse-all").on("click", function(e) {
@@ -484,13 +519,20 @@ RED.palette = (function() {
}
});
}
function getCategories() {
var categories = [];
$("#palette-container .palette-category").each(function(i,d) {
categories.push({id:$(d).data('category'),label:$(d).data('label')});
})
return categories;
}
return {
init: init,
add:addNodeType,
remove:removeNodeType,
hide:hideNodeType,
show:showNodeType,
refresh:refreshNodeTypes
refresh:refreshNodeTypes,
getCategories: getCategories
};
})();

View File

@@ -49,7 +49,7 @@ RED.projects.settings = (function() {
var tabContainer;
var trayOptions = {
title: "Project Settings",// RED._("menu.label.userSettings"),, // TODO: nls
title: RED._("menu.label.userSettings"),
buttons: [
{
id: "node-dialog-ok",
@@ -173,14 +173,14 @@ RED.projects.settings = (function() {
container.empty();
var bg = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').appendTo(container);
var input = $('<input type="text" style="width: calc(100% - 150px); margin-right: 10px;">').val(summary||"").appendTo(container);
$('<button class="editor-button">Cancel</button>')
$('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
updateProjectSummary(activeProject.summary, container);
editButton.show();
});
$('<button class="editor-button">Save</button>')
$('<button class="editor-button">' + RED._("common.label.save") + '</button>')
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
@@ -223,7 +223,7 @@ RED.projects.settings = (function() {
if (summary) {
container.text(summary).removeClass('node-info-node');
} else {
container.text("No summary available").addClass('node-info-none');// TODO: nls
container.text(RED._("sidebar.project.projectSettings.noSummaryAvailable")).addClass('node-info-none');
}
}
@@ -235,7 +235,7 @@ RED.projects.settings = (function() {
var summaryContent = $('<div></div>',{style:"color: #999"}).appendTo(summary);
updateProjectSummary(activeProject.summary, summaryContent);
if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="float: right;">edit description</button>')
$('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.editDescription') + '</button>')
.prependTo(summary)
.click(function(evt) {
evt.preventDefault();
@@ -250,7 +250,7 @@ RED.projects.settings = (function() {
updateProjectDescription(activeProject, descriptionContent);
if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="float: right;">edit README.md</button>')
$('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.editReadme') + '</button>')
.prependTo(description)
.click(function(evt) {
evt.preventDefault();
@@ -316,7 +316,7 @@ RED.projects.settings = (function() {
// depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls
// }
if (totalCount === 0) {
depsList.editableList('addItem',{index:0, label:"None"}); // TODO: nls
depsList.editableList('addItem',{index:0, label:RED._("sidebar.project.projectSettings.none")});
}
}
@@ -381,7 +381,7 @@ RED.projects.settings = (function() {
function createDependenciesPane(activeProject) {
var pane = $('<div id="project-settings-tab-deps" class="project-settings-tab-pane node-help"></div>');
if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">edit</button>')
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">' + RED._("sidebar.project.projectSettings.edit") + '</button>')
.appendTo(pane)
.click(function(evt) {
evt.preventDefault();
@@ -444,14 +444,14 @@ RED.projects.settings = (function() {
}
var icon = $('<i class="fa '+iconClass+'"></i>').appendTo(titleRow);
entry.icon = icon;
$('<span>').html(entry.id).appendTo(titleRow);
$('<span>').text(entry.id).appendTo(titleRow);
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
var buttons = $('<div class="palette-module-button-group"></div>').appendTo(metaRow);
if (RED.user.hasPermission("projects.write")) {
if (!entry.installed && RED.settings.theme('palette.editable') !== false) {
$('<a href="#" class="editor-button editor-button-small">install</a>').appendTo(buttons)
$('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.install") + '</a>').appendTo(buttons)
.click(function(evt) {
evt.preventDefault();
RED.palette.editor.install(entry,row,function(err) {
@@ -468,7 +468,7 @@ RED.projects.settings = (function() {
});
})
} else if (entry.known && entry.count === 0) {
$('<a href="#" class="editor-button editor-button-small">remove from project</a>').appendTo(buttons)
$('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.removeFromProject") + '</a>').appendTo(buttons)
.click(function(evt) {
evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies);
@@ -484,7 +484,7 @@ RED.projects.settings = (function() {
});
});
} else if (!entry.known) {
$('<a href="#" class="editor-button editor-button-small">add to project</a>').appendTo(buttons)
$('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.addToProject") + '</a>').appendTo(buttons)
.click(function(evt) {
evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies);
@@ -723,10 +723,10 @@ RED.projects.settings = (function() {
// }
function createFilesSection(activeProject,pane) {
var title = $('<h3></h3>').text("Files").appendTo(pane);
var title = $('<h3></h3>').text(RED._("sidebar.project.projectSettings.files")).appendTo(pane);
var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
if (RED.user.hasPermission("projects.write")) {
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.projectSettings.edit') + '</button>')
.appendTo(title)
.click(function(evt) {
evt.preventDefault();
@@ -750,7 +750,7 @@ RED.projects.settings = (function() {
// Flow files
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
$('<label for=""></label>').text('Flow').appendTo(row);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.flow")).appendTo(row);
var flowFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
var flowFileLabelText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.files.flow).appendTo(flowFileLabel);
@@ -787,7 +787,7 @@ RED.projects.settings = (function() {
})
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
$('<label for=""></label>').text('Credentials').appendTo(row);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.credentials")).appendTo(row);
var credFileLabel = $('<div class="uneditable-input">').text(activeProject.files.credentials).appendTo(row);
var credFileInput = $('<div class="uneditable-input">').text(activeProject.files.credentials).hide().insertAfter(credFileLabel);
@@ -899,12 +899,12 @@ RED.projects.settings = (function() {
var credentialFormRows = $('<div>',{style:"margin-top:10px"}).hide().appendTo(credentialStateLabel);
var credentialSetLabel = $('<div style="margin: 20px 0 10px 5px;">Set the encryption key:</div>').hide().appendTo(credentialFormRows);
var credentialChangeLabel = $('<div style="margin: 20px 0 10px 5px;">Change the encryption key:</div>').hide().appendTo(credentialFormRows);
var credentialResetLabel = $('<div style="margin: 20px 0 10px 5px;">Reset the encryption key:</div>').hide().appendTo(credentialFormRows);
var credentialSetLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.setTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
var credentialChangeLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.changeTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
var credentialResetLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.resetTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
var credentialSecretExistingRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows);
$('<label for=""></label>').text('Current key').appendTo(credentialSecretExistingRow);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.currentKey")).appendTo(credentialSecretExistingRow);
var credentialSecretExistingInput = $('<input type="password">').appendTo(credentialSecretExistingRow)
.on("change keyup paste",function() {
if (popover) {
@@ -917,10 +917,10 @@ RED.projects.settings = (function() {
var credentialSecretNewRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows);
$('<label for=""></label>').text('New key').appendTo(credentialSecretNewRow);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.newKey")).appendTo(credentialSecretNewRow);
var credentialSecretNewInput = $('<input type="password">').appendTo(credentialSecretNewRow).on("change keyup paste",checkFiles);
var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i> This will delete all existing credentials</div>').hide().appendTo(credentialFormRows);
var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i>' + RED._("sidebar.project.projectSettings.credentialsAlert") + '</div>').hide().appendTo(credentialFormRows);
var hideEditForm = function() {
@@ -950,13 +950,13 @@ RED.projects.settings = (function() {
}
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer);
$('<button class="editor-button">Cancel</button>')
$('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(formButtons)
.click(function(evt) {
evt.preventDefault();
hideEditForm();
});
var saveButton = $('<button class="editor-button">Save</button>')
var saveButton = $('<button class="editor-button">' + RED._("common.label.save") + '</button>')
.appendTo(formButtons)
.click(function(evt) {
evt.preventDefault();
@@ -1024,19 +1024,21 @@ RED.projects.settings = (function() {
},
}
},payload).always(function() {
RED.deploy.setDeployInflight(false);
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
});
var updateForm = function() {
if (activeProject.settings.credentialSecretInvalid) {
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-warning");
credentialStateLabel.find(".user-settings-credentials-state").text("Invalid encryption key");
credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.invalidEncryptionKey"));
} else if (activeProject.settings.credentialsEncrypted) {
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-lock");
credentialStateLabel.find(".user-settings-credentials-state").text("Encryption enabled");
credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.encryptionEnabled"));
} else {
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-unlock");
credentialStateLabel.find(".user-settings-credentials-state").text("Encryption disabled");
credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.encryptionDisabled"));
}
credentialSecretResetButton.toggleClass('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
credentialSecretResetButton.prop('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
@@ -1048,7 +1050,7 @@ RED.projects.settings = (function() {
function createLocalBranchListSection(activeProject,pane) {
var localBranchContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
$('<h4></h4>').text("Branches").appendTo(localBranchContainer);
$('<h4></h4>').text(RED._("sidebar.project.projectSettings.branches")).appendTo(localBranchContainer);
var row = $('<div class="user-settings-row projects-dialog-list"></div>').appendTo(localBranchContainer);
@@ -1061,7 +1063,7 @@ RED.projects.settings = (function() {
var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
if (entry.empty) {
container.addClass('red-ui-search-empty');
container.text("No branches");
container.text(RED._("sidebar.project.projectSettings.noBranches"));
return;
}
if (entry.current) {
@@ -1093,7 +1095,7 @@ RED.projects.settings = (function() {
.click(function(e) {
e.preventDefault();
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to delete the local branch '"+entry.name+"'? This cannot be undone.", {
var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteConfirm", { name: entry.name }), {
type: "warning",
modal: true,
fixed: true,
@@ -1121,7 +1123,7 @@ RED.projects.settings = (function() {
},
400: {
'git_delete_branch_unmerged': function(error) {
notification = RED.notify("The local branch '"+entry.name+"' has unmerged changes that will be lost. Are you sure you want to delete it?", {
notification = RED.notify(RED._("sidebar.project.projectSettings.unmergedConfirm", { name: entry.name }), {
type: "warning",
modal: true,
fixed: true,
@@ -1133,7 +1135,7 @@ RED.projects.settings = (function() {
notification.close();
}
},{
text: 'Delete unmerged branch',
text: RED._("sidebar.project.projectSettings.deleteUnmergedBranch"),
click: function() {
options.url += "?force=true";
notification.close();
@@ -1181,14 +1183,14 @@ RED.projects.settings = (function() {
}
function createRemoteRepositorySection(activeProject,pane) {
$('<h3></h3>').text("Version Control").appendTo(pane);
$('<h3></h3>').text(RED._("sidebar.project.projectSettings.versionControl")).appendTo(pane);
createLocalBranchListSection(activeProject,pane);
var repoContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
var title = $('<h4></h4>').text("Git remotes").appendTo(repoContainer);
var title = $('<h4></h4>').text(RED._("sidebar.project.projectSettings.gitRemotes")).appendTo(repoContainer);
var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right; margin-right: 10px;">add remote</button>')
var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right; margin-right: 10px;">' + RED._("sidebar.project.projectSettings.addRemote") + '</button>')
.appendTo(title)
.click(function(evt) {
editRepoButton.attr('disabled',true);
@@ -1219,7 +1221,7 @@ RED.projects.settings = (function() {
var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
if (entry.empty) {
container.addClass('red-ui-search-empty');
container.text("No remotes");
container.text(RED._("sidebar.project.projectSettings.noRemotes"));
return;
} else {
$('<span class="entry-icon"><i class="fa fa-globe"></i></span>').appendTo(container);
@@ -1238,7 +1240,7 @@ RED.projects.settings = (function() {
.click(function(e) {
e.preventDefault();
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to delete the remote '"+entry.name+"'?", {
var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteRemoteConfrim", { name: entry.name }), {
type: "warning",
modal: true,
fixed: true,
@@ -1250,9 +1252,17 @@ RED.projects.settings = (function() {
notification.close();
}
},{
text: 'Delete remote',
text: RED._("sidebar.project.projectSettings.deleteRemote"),
click: function() {
notification.close();
if (activeProject.git.branches.remote && activeProject.git.branches.remote.indexOf(entry.name+"/") === 0) {
delete activeProject.git.branches.remote;
}
if (activeProject.git.branches.remoteAlt && activeProject.git.branches.remoteAlt.indexOf(entry.name+"/") === 0) {
delete activeProject.git.branches.remoteAlt;
}
var url = "projects/"+activeProject.name+"/remotes/"+entry.name;
var options = {
url: url,
@@ -1274,6 +1284,7 @@ RED.projects.settings = (function() {
activeProject.git.remotes[name] = remote;
});
}
delete activeProject.git.branches.remoteAlt;
RED.sidebar.versionControl.refresh();
});
},
@@ -1304,10 +1315,10 @@ RED.projects.settings = (function() {
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\.git)?(?:\/?|\#[\d\w\.\-_]+?)$/.test(remoteURLInput.val());
var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) {
remoteURLLabel.text("Do not include the username/password in the url");
remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule2"));
validRepo = false;
} else {
remoteURLLabel.text("https://, ssh:// or file://");
remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule"));
}
saveButton.attr('disabled',(!validName || !validRepo))
remoteNameInput.toggleClass('input-error',remoteNameInputChanged&&!validName);
@@ -1321,22 +1332,22 @@ RED.projects.settings = (function() {
var remoteNameInputChanged = false;
var remoteURLInputChanged = false;
$('<div class="projects-dialog-list-dialog-header">').text('Add remote').appendTo(addRemoteDialog);
$('<div class="projects-dialog-list-dialog-header">').text(RED._('sidebar.project.projectSettings.addRemote2')).appendTo(addRemoteDialog);
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text('Remote name').appendTo(row);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.remoteName")).appendTo(row);
var remoteNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
remoteNameInputChanged = true;
validateForm();
});
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
$('<label class="projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.nameRule") + '</small></label>').appendTo(row).find("small");
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text('URL').appendTo(row);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.url")).appendTo(row);
var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
remoteURLInputChanged = true;
validateForm()
});
var remoteURLLabel = $('<label class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row).find("small");
var remoteURLLabel = $('<label class="projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.urlRule") +'</small></label>').appendTo(row).find("small");
var hideEditForm = function() {
editRepoButton.attr('disabled',false);
@@ -1350,13 +1361,13 @@ RED.projects.settings = (function() {
}
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>')
.appendTo(addRemoteDialog);
$('<button class="editor-button">Cancel</button>')
$('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(formButtons)
.click(function(evt) {
evt.preventDefault();
hideEditForm();
});
var saveButton = $('<button class="editor-button">Add remote</button>')
var saveButton = $('<button class="editor-button">' + RED._("sidebar.project.projectSettings.addRemote2") + '</button>')
.appendTo(formButtons)
.click(function(evt) {
evt.preventDefault();
@@ -1473,19 +1484,19 @@ RED.projects.settings = (function() {
utils = _utils;
addPane({
id:'main',
title: "Project", // TODO: nls
title: RED._("sidebar.project.name"),
get: createMainPane,
close: function() { }
});
addPane({
id:'deps',
title: "Dependencies", // TODO: nls
title: RED._("sidebar.project.dependencies"),
get: createDependenciesPane,
close: function() { }
});
addPane({
id:'settings',
title: "Settings", // TODO: nls
title: RED._("sidebar.project.settings"),
get: createSettingsPane,
close: function() {
if (popover) {

View File

@@ -24,18 +24,18 @@ RED.projects.userSettings = (function() {
var currentGitSettings = RED.settings.get('git') || {};
currentGitSettings.user = currentGitSettings.user || {};
var title = $('<h3></h3>').text("Committer Details").appendTo(pane);
var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.committerDetail")).appendTo(pane);
var gitconfigContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
$('<div style="color:#aaa;"></div>').appendTo(gitconfigContainer).text("Leave blank to use system default");
$('<div style="color:#aaa;"></div>').appendTo(gitconfigContainer).text(RED._("editor:sidebar.project.userSettings.committerTip"));
var row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer);
$('<label for=""></label>').text('Username').appendTo(row);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row);
gitUsernameInput = $('<input type="text">').appendTo(row);
gitUsernameInput.val(currentGitSettings.user.name||"");
row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer);
$('<label for=""></label>').text('Email').appendTo(row);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row);
gitEmailInput = $('<input type="text">').appendTo(row);
gitEmailInput.val(currentGitSettings.user.email||"");
}
@@ -44,10 +44,10 @@ RED.projects.userSettings = (function() {
function createSSHKeySection(pane) {
var container = $('<div class="user-settings-section"></div>').appendTo(pane);
var popover;
var title = $('<h3></h3>').text("SSH Keys").appendTo(container);
var subtitle = $('<div style="color:#aaa;"></div>').appendTo(container).text("Allows you to create secure connections to remote git repositories.");
var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.sshKeys")).appendTo(container);
var subtitle = $('<div style="color:#aaa;"></div>').appendTo(container).text(RED._("editor:sidebar.project.userSettings.sshKeysTip"));
var addKeyButton = $('<button id="user-settings-gitconfig-add-key" class="editor-button editor-button-small" style="float: right; margin-right: 10px;">add key</button>')
var addKeyButton = $('<button id="user-settings-gitconfig-add-key" class="editor-button editor-button-small" style="float: right; margin-right: 10px;">'+RED._("editor:sidebar.project.userSettings.add")+'</button>')
.appendTo(subtitle)
.click(function(evt) {
addKeyButton.attr('disabled',true);
@@ -72,9 +72,9 @@ RED.projects.userSettings = (function() {
var validPassphrase = passphrase.length === 0 || passphrase.length >= 8;
passphraseInput.toggleClass('input-error',!validPassphrase);
if (!validPassphrase) {
passphraseInputSubLabel.text("Passphrase too short");
passphraseInputSubLabel.text(RED._("editor:sidebar.project.userSettings.passphraseShort"));
} else if (passphrase.length === 0) {
passphraseInputSubLabel.text("Optional");
passphraseInputSubLabel.text(RED._("editor:sidebar.project.userSettings.optional"));
} else {
passphraseInputSubLabel.text("");
}
@@ -91,11 +91,11 @@ RED.projects.userSettings = (function() {
var row = $('<div class="user-settings-row"></div>').appendTo(container);
var addKeyDialog = $('<div class="projects-dialog-list-dialog"></div>').hide().appendTo(row);
$('<div class="projects-dialog-list-dialog-header">').text('Add SSH Key').appendTo(addKeyDialog);
$('<div class="projects-dialog-list-dialog-header">').text(RED._("editor:sidebar.project.userSettings.addSshKey")).appendTo(addKeyDialog);
var addKeyDialogBody = $('<div>').appendTo(addKeyDialog);
row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody);
$('<div style="color:#aaa;"></div>').appendTo(row).text("Generate a new public/private key pair");
$('<div style="color:#aaa;"></div>').appendTo(row).text(RED._("editor:sidebar.project.userSettings.addSshKeyTip"));
// var bg = $('<div></div>',{class:"button-group", style:"text-align: center"}).appendTo(row);
// var addLocalButton = $('<button class="editor-button toggle selected">use local key</button>').appendTo(bg);
// var uploadButton = $('<button class="editor-button toggle">upload key</button>').appendTo(bg);
@@ -125,19 +125,19 @@ RED.projects.userSettings = (function() {
row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody);
$('<label for=""></label>').text('Name').appendTo(row);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.name")).appendTo(row);
var keyNameInputChanged = false;
var keyNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
keyNameInputChanged = true;
validateForm();
});
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
$('<label class="projects-edit-form-sublabel"><small>'+RED._("editor:sidebar.project.userSettings.nameRule")+'</small></label>').appendTo(row).find("small");
var generateKeyPane = $('<div>').appendTo(addKeyDialogBody);
row = $('<div class="user-settings-row"></div>').appendTo(generateKeyPane);
$('<label for=""></label>').text('Passphrase').appendTo(row);
$('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.passphrase")).appendTo(row);
var passphraseInput = $('<input type="password">').appendTo(row).on("change keyup paste",validateForm);
var passphraseInputSubLabel = $('<label class="projects-edit-form-sublabel"><small>Optional</small></label>').appendTo(row).find("small");
var passphraseInputSubLabel = $('<label class="projects-edit-form-sublabel"><small>'+RED._("editor:sidebar.project.userSettings.optional")+'</small></label>').appendTo(row).find("small");
// var addLocalKeyPane = $('<div>').hide().appendTo(addKeyDialogBody);
// row = $('<div class="user-settings-row"></div>').appendTo(addLocalKeyPane);
@@ -179,13 +179,13 @@ RED.projects.userSettings = (function() {
}
}
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(addKeyDialog);
$('<button class="editor-button">Cancel</button>')
$('<button class="editor-button">'+RED._("editor:sidebar.project.userSettings.cancel")+'</button>')
.appendTo(formButtons)
.click(function(evt) {
evt.preventDefault();
hideEditForm();
});
var saveButton = $('<button class="editor-button">Generate key</button>')
var saveButton = $('<button class="editor-button">'+RED._("editor:sidebar.project.userSettings.generate")+'</button>')
.appendTo(formButtons)
.click(function(evt) {
evt.preventDefault();
@@ -264,7 +264,7 @@ RED.projects.userSettings = (function() {
utils.sendRequest(options);
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(row);
$('<button class="editor-button editor-button-small">Copy public key to clipboard</button>')
$('<button class="editor-button editor-button-small">'+RED._("editor:sidebar.project.userSettings.copyPublicKey")+'</button>')
.appendTo(formButtons)
.click(function(evt) {
try {
@@ -289,7 +289,7 @@ RED.projects.userSettings = (function() {
var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
if (entry.empty) {
container.addClass('red-ui-search-empty');
container.text("No SSH keys");
container.text(RED._("editor:sidebar.project.userSettings.noSshKeys"));
return;
}
var topRow = $('<div class="projects-dialog-ssh-key-header">').appendTo(container);
@@ -313,7 +313,7 @@ RED.projects.userSettings = (function() {
.click(function(e) {
e.stopPropagation();
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to delete the SSH key '"+entry.name+"'? This cannot be undone.", {
var notification = RED.notify(RED._("editor:sidebar.project.userSettings.deleteConfirm", {name:entry.name}), {
type: 'warning',
modal: true,
fixed: true,
@@ -326,7 +326,7 @@ RED.projects.userSettings = (function() {
}
},
{
text: "Delete key",
text: RED._("editor:sidebar.project.userSettings.delete"),
click: function() {
notification.close();
var url = "settings/user/keys/"+entry.name;
@@ -400,7 +400,7 @@ RED.projects.userSettings = (function() {
utils = _utils;
RED.userSettings.add({
id:'gitconfig',
title: "Git config", // TODO: nls
title: RED._("editor:sidebar.project.userSettings.gitConfig"),
get: createSettingsPane,
close: function() {
var currentGitSettings = RED.settings.get('git') || {};

File diff suppressed because it is too large Load Diff

View File

@@ -52,11 +52,11 @@ RED.sidebar.versionControl = (function() {
200: function(data) {
var title;
if (state === 'unstaged') {
title = 'Unstaged changes : '+entry.file
title = RED._("sidebar.project.versionControl.unstagedChanges")+' : '+entry.file
} else if (state === 'staged') {
title = 'Staged changes : '+entry.file
title = RED._("sidebar.project.versionControl.stagedChanges")+' : '+entry.file
} else {
title = 'Resolve conflicts : '+entry.file
title = RED._("sidebar.project.versionControl.resolveConflicts")+' : '+entry.file
}
var options = {
diff: data.diff,
@@ -65,18 +65,18 @@ RED.sidebar.versionControl = (function() {
project: activeProject
}
if (state == 'unstaged') {
options.oldRevTitle = entry.indexStatus === " "?"HEAD":"Staged";
options.newRevTitle = "Unstaged";
options.oldRevTitle = entry.indexStatus === " "?RED._("sidebar.project.versionControl.head"):RED._("sidebar.project.versionControl.staged");
options.newRevTitle = RED._("sidebar.project.versionControl.unstaged");
options.oldRev = entry.indexStatus === " "?"@":":0";
options.newRev = "_";
} else if (state === 'staged') {
options.oldRevTitle = "HEAD";
options.newRevTitle = "Staged";
options.oldRevTitle = RED._("sidebar.project.versionControl.head");
options.newRevTitle = RED._("sidebar.project.versionControl.staged");
options.oldRev = "@";
options.newRev = ":0";
} else {
options.oldRevTitle = "Local";
options.newRevTitle = "Remote";
options.oldRevTitle = RED._("sidebar.project.versionControl.local");
options.newRevTitle = RED._("sidebar.project.versionControl.remote");
options.commonRev = ":1";
options.oldRev = ":2";
options.newRev = ":3";
@@ -154,8 +154,9 @@ RED.sidebar.versionControl = (function() {
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
var spinner = utils.addSpinnerOverlay(container).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to revert the changes to '"+entry.file+"'? This cannot be undone.", {
var notification = RED.notify(RED._("sidebar.project.versionControl.revert",{file:entry.file}), {
type: "warning",
modal: true,
fixed: true,
@@ -167,7 +168,7 @@ RED.sidebar.versionControl = (function() {
notification.close();
}
},{
text: 'Revert changes',
text: RED._("sidebar.project.versionControl.revertChanges"),
click: function() {
notification.close();
var activeProject = RED.projects.getActiveProject();
@@ -188,7 +189,12 @@ RED.sidebar.versionControl = (function() {
}
}
}
utils.sendRequest(options);
RED.deploy.setDeployInflight(true);
utils.sendRequest(options).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
}
}
@@ -275,6 +281,8 @@ RED.sidebar.versionControl = (function() {
entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status);
}
var utils;
var emptyStagedItem;
var emptyMergedItem;
function init(_utils) {
utils = _utils;
@@ -306,7 +314,7 @@ RED.sidebar.versionControl = (function() {
});
localChanges = sections.add({
title: "Local Changes",
title: RED._("sidebar.project.versionControl.localChanges"),
collapsible: true
});
localChanges.expand();
@@ -320,10 +328,12 @@ RED.sidebar.versionControl = (function() {
refresh(true);
})
emptyStagedItem = { label: RED._("sidebar.project.versionControl.none") };
emptyMergedItem = { label: RED._("sidebar.project.versionControl.conflictResolve") };
var unstagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
var header = $('<div class="sidebar-version-control-change-header">Local files</div>').appendTo(unstagedContent);
stageAllButton = $('<button class="editor-button editor-button-small" style="float: right"><i class="fa fa-plus"></i> all</button>')
var header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.localFiles")+'</div>').appendTo(unstagedContent);
stageAllButton = $('<button class="editor-button editor-button-small" style="float: right"><i class="fa fa-plus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
.appendTo(header)
.click(function(evt) {
evt.preventDefault();
@@ -353,9 +363,9 @@ RED.sidebar.versionControl = (function() {
unmergedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
header = $('<div class="sidebar-version-control-change-header">Unmerged changes</div>').appendTo(unmergedContent);
header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.unmergedChanges")+'</div>').appendTo(unmergedContent);
bg = $('<div style="float: right"></div>').appendTo(header);
var abortMergeButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">abort merge</button>')
var abortMergeButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">'+RED._("sidebar.project.versionControl.abortMerge")+'</button>')
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
@@ -393,7 +403,7 @@ RED.sidebar.versionControl = (function() {
addItem: function(row,index,entry) {
if (entry === emptyMergedItem) {
entry.button = {
label: 'commit',
label: RED._("sidebar.project.versionControl.commit"),
click: function(evt) {
evt.preventDefault();
evt.stopPropagation();
@@ -417,7 +427,7 @@ RED.sidebar.versionControl = (function() {
var stagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
header = $('<div class="sidebar-version-control-change-header">Changes to commit</div>').appendTo(stagedContent);
header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.changeToCommit")+'</div>').appendTo(stagedContent);
bg = $('<div style="float: right"></div>').appendTo(header);
var showCommitBox = function() {
@@ -440,14 +450,14 @@ RED.sidebar.versionControl = (function() {
abortMergeButton.attr("disabled",true);
commitMessage.focus();
}
commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">commit</button>')
commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">'+RED._("sidebar.project.versionControl.commit")+'</button>')
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
evt.stopPropagation();
showCommitBox();
});
unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> all</button>')
unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
@@ -474,14 +484,14 @@ RED.sidebar.versionControl = (function() {
commitBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-bottom"></div>').hide().appendTo(localChanges.content);
var commitMessage = $('<textarea placeholder="Enter your commit message"></textarea>')
var commitMessage = $('<textarea placeholder='+RED._("sidebar.project.versionControl.commitPlaceholder")+'></textarea>')
.appendTo(commitBox)
.on("change keyup paste",function() {
submitCommitButton.attr('disabled',$(this).val().trim()==="");
});
var commitToolbar = $('<div class="sidebar-version-control-slide-box-toolbar button-group">').appendTo(commitBox);
var cancelCommitButton = $('<button class="editor-button">Cancel</button>')
var cancelCommitButton = $('<button class="editor-button">'+RED._("sidebar.project.versionControl.cancelCapital")+'</button>')
.appendTo(commitToolbar)
.click(function(evt) {
evt.preventDefault();
@@ -499,7 +509,7 @@ RED.sidebar.versionControl = (function() {
abortMergeButton.attr("disabled",false);
})
var submitCommitButton = $('<button class="editor-button">Commit</button>')
var submitCommitButton = $('<button class="editor-button">'+RED._("sidebar.project.versionControl.commitCapital")+'</button>')
.appendTo(commitToolbar)
.click(function(evt) {
evt.preventDefault();
@@ -535,7 +545,7 @@ RED.sidebar.versionControl = (function() {
var localHistory = sections.add({
title: "Commit History",
title: RED._("sidebar.project.versionControl.commitHistory"),
collapsible: true
});
@@ -549,7 +559,7 @@ RED.sidebar.versionControl = (function() {
var localBranchToolbar = $('<div class="sidebar-version-control-change-header" style="text-align: right;"></div>').appendTo(localHistory.content);
var localBranchButton = $('<button class="editor-button editor-button-small"><i class="fa fa-code-fork"></i> Branch: <span id="sidebar-version-control-local-branch"></span></button>')
var localBranchButton = $('<button class="editor-button editor-button-small"><i class="fa fa-code-fork"></i> '+RED._("sidebar.project.versionControl.branch")+' <span id="sidebar-version-control-local-branch"></span></button>')
.appendTo(localBranchToolbar)
.click(function(evt) {
evt.preventDefault();
@@ -586,7 +596,10 @@ RED.sidebar.versionControl = (function() {
closeBranchBox();
localCommitListShade.show();
$(this).addClass('selected');
var activeProject = RED.projects.getActiveProject();
$("#sidebar-version-control-repo-toolbar-set-upstream-row").toggle(!!activeProject.git.branches.remoteAlt);
remoteBox.show();
setTimeout(function() {
remoteBox.css("height","265px");
},100);
@@ -603,7 +616,7 @@ RED.sidebar.versionControl = (function() {
row.addClass('sidebar-version-control-commit-entry');
if (entry.url) {
row.addClass('sidebar-version-control-commit-more');
row.text("+ "+(entry.total-entry.totalKnown)+" more commit(s)");
row.text("+ "+(entry.total-entry.totalKnown)+RED._("sidebar.project.versionControl.moreCommits"));
row.click(function(e) {
e.preventDefault();
getCommits(entry.url,localCommitList,row,entry.limit,entry.before);
@@ -617,8 +630,8 @@ RED.sidebar.versionControl = (function() {
result.parents = entry.parents;
result.oldRev = entry.sha+"~1";
result.newRev = entry.sha;
result.oldRevTitle = "Commit "+entry.sha.substring(0,7)+"~1";
result.newRevTitle = "Commit "+entry.sha.substring(0,7);
result.oldRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7)+"~1";
result.newRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7);
result.date = humanizeSinceDate(parseInt(entry.date));
RED.diff.showCommitDiff(result);
});
@@ -657,10 +670,10 @@ RED.sidebar.versionControl = (function() {
}
var localBranchBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-top" style="top:30px;"></div>').hide().appendTo(localHistory.content);
$('<div class="sidebar-version-control-slide-box-header"></div>').text("Change local branch").appendTo(localBranchBox);
$('<div class="sidebar-version-control-slide-box-header"></div>').text(RED._("sidebar.project.versionControl.changeLocalBranch")).appendTo(localBranchBox);
var localBranchList = utils.createBranchList({
placeholder: "Find or create a branch",
placeholder: RED._("sidebar.project.versionControl.createBranchPlaceholder"),
container: localBranchBox,
onselect: function(body) {
if (body.current) {
@@ -692,7 +705,7 @@ RED.sidebar.versionControl = (function() {
400: {
'git_local_overwrite': function(error) {
spinner.remove();
RED.notify("You have local changes that would be overwritten by changing the branch. You must either commit or undo those changes first.",{
RED.notify(RED._("sidebar.project.versionControl.localOverwrite"),{
type:'error',
timeout: 8000
});
@@ -735,10 +748,10 @@ RED.sidebar.versionControl = (function() {
},200);
}
}
$('<div class="sidebar-version-control-slide-box-header"></div>').text("Manage remote branch").appendTo(remoteBox);
$('<div class="sidebar-version-control-slide-box-header"></div>').text(RED._("sidebar.project.versionControl.manageRemoteBranch")).appendTo(remoteBox);
var remoteBranchRow = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox);
var remoteBranchButton = $('<button id="sidebar-version-control-repo-branch" class="sidebar-version-control-repo-action editor-button"><i class="fa fa-code-fork"></i> Remote: <span id="sidebar-version-control-remote-branch"></span></button>')
var remoteBranchButton = $('<button id="sidebar-version-control-repo-branch" class="sidebar-version-control-repo-action editor-button"><i class="fa fa-code-fork"></i> '+RED._("sidebar.project.versionControl.remote")+': <span id="sidebar-version-control-remote-branch"></span></button>')
.appendTo(remoteBranchRow)
.click(function(evt) {
evt.preventDefault();
@@ -761,9 +774,9 @@ RED.sidebar.versionControl = (function() {
var errorMessage = $('<div id="sidebar-version-control-repo-toolbar-error-message" class="sidebar-version-control-slide-box-header" style="min-height: 100px;"></div>').hide().appendTo(remoteBox);
$('<div style="margin-top: 10px;"><i class="fa fa-warning"></i> Unable to access remote repository</div>').appendTo(errorMessage)
$('<div style="margin-top: 10px;"><i class="fa fa-warning"></i> '+RED._("sidebar.project.versionControl.unableToAccess")+'</div>').appendTo(errorMessage)
var buttonRow = $('<div style="margin: 10px 30px; text-align: center"></div>').appendTo(errorMessage);
$('<button class="editor-button" style="width: 80%;"><i class="fa fa-refresh"></i> Retry</button>')
$('<button class="editor-button" style="width: 80%;"><i class="fa fa-refresh"></i> '+RED._("sidebar.project.versionControl.retry")+'</button>')
.appendTo(buttonRow)
.click(function(e) {
e.preventDefault();
@@ -801,12 +814,12 @@ RED.sidebar.versionControl = (function() {
});
})
$('<div class="sidebar-version-control-slide-box-header" style="height: 20px;"><label id="sidebar-version-control-repo-toolbar-set-upstream-row" for="sidebar-version-control-repo-toolbar-set-upstream" class="hide"><input type="checkbox" id="sidebar-version-control-repo-toolbar-set-upstream"> Set as upstream branch</label></div>').appendTo(remoteBox);
$('<div class="sidebar-version-control-slide-box-header" style="height: 20px;"><label id="sidebar-version-control-repo-toolbar-set-upstream-row" for="sidebar-version-control-repo-toolbar-set-upstream" class="hide"><input type="checkbox" id="sidebar-version-control-repo-toolbar-set-upstream"> '+RED._("sidebar.project.versionControl.setUpstreamBranch")+'</label></div>').appendTo(remoteBox);
var remoteBranchSubRow = $('<div style="height: 0;overflow:hidden; transition: height 0.2s ease-in-out;"></div>').hide().appendTo(remoteBranchRow);
var remoteBranchList = utils.createBranchList({
placeholder: "Find or create a remote branch",
currentLabel: "upstream",
placeholder: RED._("sidebar.project.versionControl.createRemoteBranchPlaceholder"),
currentLabel: RED._("sidebar.project.versionControl.upstream"),
remote: function() {
var project = RED.projects.getActiveProject();
var remotes = Object.keys(project.git.remotes);
@@ -836,11 +849,11 @@ RED.sidebar.versionControl = (function() {
})
} else {
if (!activeProject.git.branches.remote) {
$('#sidebar-version-control-repo-toolbar-message').text("The created branch will be set as the tracked upstream branch.");
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.trackedUpstreamBranch"));
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked',true);
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('disabled',true);
} else {
$('#sidebar-version-control-repo-toolbar-message').text("The branch will be created. Select below to set it as the tracked upstream branch.");
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.selectUpstreamBranch"));
}
$("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',false);
@@ -852,7 +865,7 @@ RED.sidebar.versionControl = (function() {
var row = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox);
$('<button id="sidebar-version-control-repo-push" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-up"></i> <span>push</span></button>')
$('<button id="sidebar-version-control-repo-push" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-up"></i> <span data-i18n="sidebar.project.versionControl.push"></span></button>')
.appendTo(row)
.click(function(e) {
e.preventDefault();
@@ -862,7 +875,8 @@ RED.sidebar.versionControl = (function() {
if (activeProject.git.branches.remoteAlt) {
url+="/"+activeProject.git.branches.remoteAlt;
}
if ($("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')) {
var setUpstream = $("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked');
if (setUpstream) {
url+="?u=true"
}
utils.sendRequest({
@@ -874,13 +888,17 @@ RED.sidebar.versionControl = (function() {
// done(error,null);
},
200: function(data) {
if (setUpstream && activeProject.git.branches.remoteAlt) {
activeProject.git.branches.remote = activeProject.git.branches.remoteAlt;
delete activeProject.git.branches.remoteAlt;
}
refresh(true);
closeRemoteBox();
},
400: {
'git_push_failed': function(err) {
// TODO: better message + NLS
RED.notify("NLS: Push failed as the remote has more recent commits. Pull first and write a better error message!","error");
// TODO: better message
RED.notify(RED._("sidebar.project.versionControl.pushFailed"),"error");
},
'unexpected_error': function(error) {
console.log(error);
@@ -922,23 +940,27 @@ RED.sidebar.versionControl = (function() {
// done(error,null);
},
200: function(data) {
if (options.setUpstream && activeProject.git.branches.remoteAlt) {
activeProject.git.branches.remote = activeProject.git.branches.remoteAlt;
delete activeProject.git.branches.remoteAlt;
}
refresh(true);
closeRemoteBox();
},
400: {
'git_local_overwrite': function(err) {
RED.notify("<p>Unable to pull remote changes; your unstaged local changes would be overwritten.</p><p>Commit your changes and try again.</p>"+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show unstaged changes'+'</a></p>',"error",false,10000000);
RED.notify(RED._("sidebar.project.versionControl.unablePull")+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+RED._("sidebar.project.versionControl.showUnstagedChanges")+'</a></p>',"error",false,10000000);
},
'git_pull_merge_conflict': function(err) {
refresh(true);
closeRemoteBox();
},
'git_connection_failed': function(err) {
RED.notify("Could not connect to remote repository: "+err.toString(),"warning")
RED.notify(RED._("sidebar.project.versionControl.connectionFailed")+err.toString(),"warning")
},
'git_pull_unrelated_history': function(error) {
var notification = RED.notify("<p>The remote has an unrelated history of commits.</p><p>Are you sure you want to pull the changes into your local repository?</p>",{
var notification = RED.notify(RED._("sidebar.project.versionControl.pullUnrelatedHistory"),{
type: 'error',
modal: true,
fixed: true,
@@ -949,7 +971,7 @@ RED.sidebar.versionControl = (function() {
notification.close();
}
},{
text: 'Pull changes',
text: RED._("sidebar.project.versionControl.pullChanges"),
click: function() {
notification.close();
options.allowUnrelatedHistories = true;
@@ -968,7 +990,7 @@ RED.sidebar.versionControl = (function() {
spinner.remove();
});
}
$('<button id="sidebar-version-control-repo-pull" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-down"></i> <span>pull</span></button>')
$('<button id="sidebar-version-control-repo-pull" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-down"></i> <span data-i18n="sidebar.project.versionControl.pull"></span></button>')
.appendTo(row)
.click(function(e) {
e.preventDefault();
@@ -981,10 +1003,12 @@ RED.sidebar.versionControl = (function() {
RED.sidebar.addTab({
id: "version-control",
label: "history",
label: RED._("sidebar.project.versionControl.history"),
name: "Project History",
content: sidebarContent,
enableOnEdit: false,
pinned: true,
iconClass: "fa fa-code-fork",
onchange: function() {
setTimeout(function() {
sections.resize();
@@ -1001,17 +1025,17 @@ RED.sidebar.versionControl = (function() {
if (daysDelta > 30) {
return (new Date(date*1000)).toLocaleDateString();
} else if (daysDelta > 0) {
return daysDelta+" day"+(daysDelta>1?"s":"")+" ago";
return RED._("sidebar.project.versionControl.daysAgo", {count:daysDelta})
}
var hoursDelta = Math.floor(delta / (60*60));
if (hoursDelta > 0) {
return hoursDelta+" hour"+(hoursDelta>1?"s":"")+" ago";
return RED._("sidebar.project.versionControl.hoursAgo", {count:hoursDelta})
}
var minutesDelta = Math.floor(delta / 60);
if (minutesDelta > 0) {
return minutesDelta+" minute"+(minutesDelta>1?"s":"")+" ago";
return RED._("sidebar.project.versionControl.minsAgo", {count:minutesDelta})
}
return "Seconds ago";
return RED._("sidebar.project.versionControl.secondsAgo");
}
function updateBulk(files,unstaged) {
@@ -1046,9 +1070,6 @@ RED.sidebar.versionControl = (function() {
var refreshInProgress = false;
var emptyStagedItem = { label:"None" };
var emptyMergedItem = { label:"All conflicts resolved. Commit the changes to complete the merge." };
function getCommits(url,targetList,spinnerTarget,limit,before) {
var spinner = utils.addSpinnerOverlay(spinnerTarget);
var fullUrl = url+"?limit="+(limit||20);
@@ -1256,7 +1277,7 @@ RED.sidebar.versionControl = (function() {
refreshFiles(result);
$('#sidebar-version-control-local-branch').text(result.branches.local);
$('#sidebar-version-control-remote-branch').text(result.branches.remote||"none");
$('#sidebar-version-control-remote-branch').text(result.branches.remote||RED._("sidebar.project.versionControl.none"));
var commitsAhead = result.commits.ahead || 0;
var commitsBehind = result.commits.behind || 0;
@@ -1286,7 +1307,7 @@ RED.sidebar.versionControl = (function() {
$('#sidebar-version-control-commits-ahead').text("");
$('#sidebar-version-control-commits-behind').text("");
$('#sidebar-version-control-repo-toolbar-message').text("Your local branch is not currently tracking a remote branch.");
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.notTracking"));
$("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',true);
}
@@ -1312,23 +1333,26 @@ RED.sidebar.versionControl = (function() {
$('#sidebar-version-control-commits-ahead').text(commitsAhead);
$('#sidebar-version-control-commits-behind').text(commitsBehind);
if (isMerging) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository has unmerged changes. You need to fix the conflicts and commit the result.");
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.statusUnmergedChanged"));
$("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',true);
} else if (commitsAhead > 0 && commitsBehind === 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsAhead+" commit"+(commitsAhead===1?'':'s')+" ahead of the remote. You can push "+(commitsAhead===1?'this commit':'these commits')+" now.");
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.commitsAhead", {count:commitsAhead}));
$("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',false);
} else if (commitsAhead === 0 && commitsBehind > 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsBehind+" commit"+(commitsBehind===1?'':'s')+" behind of the remote. You can pull "+(commitsBehind===1?'this commit':'these commits')+" now.");
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.commitsBehind",{ count: commitsBehind }));
$("#sidebar-version-control-repo-pull").attr('disabled',false);
$("#sidebar-version-control-repo-push").attr('disabled',true);
} else if (commitsAhead > 0 && commitsBehind > 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsBehind+" commit"+(commitsBehind===1?'':'s')+" behind and "+commitsAhead+" commit"+(commitsAhead===1?'':'s')+" ahead of the remote. You must pull the remote commit"+(commitsBehind===1?'':'s')+" down before pushing.");
$('#sidebar-version-control-repo-toolbar-message').text(
RED._("sidebar.project.versionControl.commitsAheadAndBehind1",{ count:commitsBehind })+
RED._("sidebar.project.versionControl.commitsAheadAndBehind2",{ count:commitsAhead })+
RED._("sidebar.project.versionControl.commitsAheadAndBehind3",{ count:commitsBehind }));
$("#sidebar-version-control-repo-pull").attr('disabled',false);
$("#sidebar-version-control-repo-push").attr('disabled',true);
} else if (commitsAhead === 0 && commitsBehind === 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is up to date.");
$('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.repositoryUpToDate"));
$("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',true);
}

View File

@@ -174,7 +174,7 @@ RED.search = (function() {
addItem: function(container,i,object) {
var node = object.node;
if (node === undefined) {
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
$('<div>',{class:"red-ui-search-empty"}).text(RED._('search.empty')).appendTo(container);
} else {
var def = node._def;
@@ -200,12 +200,12 @@ RED.search = (function() {
} else {
workspace = "flow:"+workspace.label;
}
$('<div>',{class:"red-ui-search-result-node-flow"}).html(workspace).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-flow"}).text(workspace).appendTo(contentDiv);
}
$('<div>',{class:"red-ui-search-result-node-label"}).html(object.label || node.id).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-label"}).text(object.label || node.id).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-type"}).text(node.type).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-id"}).text(node.id).appendTo(contentDiv);
div.click(function(evt) {
evt.preventDefault();

View File

@@ -35,7 +35,8 @@ RED.sidebar = (function() {
tab.onremove.call(tab);
}
},
minimumActiveTabWidth: 70
// minimumActiveTabWidth: 70,
collapsible: true
// scrollable: true
});
@@ -59,6 +60,8 @@ RED.sidebar = (function() {
options = title;
}
delete options.closeable;
options.wrapper = $('<div>',{style:"height:100%"}).appendTo("#sidebar-content")
options.wrapper.append(options.content);
options.wrapper.hide();
@@ -82,6 +85,8 @@ RED.sidebar = (function() {
group: "sidebar-tabs"
});
options.iconClass = options.iconClass || "fa fa-square-o"
knownTabs[options.id] = options;
if (options.visible !== false) {

View File

@@ -23,5 +23,6 @@ RED.state = {
EXPORT: 6,
IMPORT: 7,
IMPORT_DRAGGING: 8,
QUICK_JOINING: 9
QUICK_JOINING: 9,
PANNING: 10
}

View File

@@ -139,7 +139,7 @@ RED.subflow = (function() {
RED.view.select();
RED.nodes.dirty(true);
RED.view.redraw();
$("#workspace-subflow-output .spinner-value").html(subflow.out.length);
$("#workspace-subflow-output .spinner-value").text(subflow.out.length);
}
function removeSubflowOutput(removedSubflowOutputs) {
@@ -216,7 +216,7 @@ RED.subflow = (function() {
$("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0);
$("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0);
$("#workspace-subflow-output .spinner-value").html(activeSubflow.out.length);
$("#workspace-subflow-output .spinner-value").text(activeSubflow.out.length);
}
}

View File

@@ -221,8 +221,7 @@ RED.sidebar.config = (function() {
name: RED._("sidebar.config.name"),
content: content,
toolbar: toolbar,
closeable: true,
visible: false,
iconClass: "fa fa-cog",
onchange: function() { refreshConfigNodeList(); }
});
RED.actions.add("core:show-config-tab",function() {RED.sidebar.show('config')});

View File

@@ -83,7 +83,9 @@ RED.sidebar.info = (function() {
id: "info",
label: RED._("sidebar.info.label"),
name: RED._("sidebar.info.name"),
iconClass: "fa fa-info",
content: content,
pinned: true,
enableOnEdit: true
});
if (tips.enabled()) {
@@ -167,24 +169,42 @@ RED.sidebar.info = (function() {
$(propRow.children()[1]).text(node.label||node.name||"");
if (node.type === "tab") {
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).html((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
$(propRow.children()[1]).text((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
} else if (node.type === "subflow") {
propRow = $('<tr class="node-info-node-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody);
var category = node.category||"subflows";
$(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category}))
}
} else {
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
if (node.type !== "subflow" && node.name) {
$('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody);
if (node.type !== "subflow" && node.type !== "unknown" && node.name) {
propRow = $('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td></td></tr>').appendTo(tableBody);
$('<span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'"></span>').text(node.name).appendTo(propRow.children()[1]);
}
if (!m) {
$('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td>"+node.type+"</td></tr>").appendTo(tableBody);
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.type")+"</td><td></td></tr>").appendTo(tableBody);
$(propRow.children()[1]).text((node.type === "unknown")?node._orig.type:node.type);
if (node.type === "unknown") {
$('<span style="float: right; font-size: 0.8em"><i class="fa fa-warning"></i></span>').prependTo($(propRow.children()[1]))
}
}
if (!m && node.type != "subflow" && node.type != "comment") {
if (node._def) {
var defaults;
if (node.type === 'unknown') {
defaults = {};
Object.keys(node._orig).forEach(function(k) {
if (k !== 'type') {
defaults[k] = {};
}
})
} else if (node._def) {
defaults = node._def.defaults;
}
if (defaults) {
var count = 0;
var defaults = node._def.defaults;
for (var n in defaults) {
if (n != "name" && defaults.hasOwnProperty(n)) {
var val = node[n];
@@ -206,7 +226,7 @@ RED.sidebar.info = (function() {
nodeDiv.css({'backgroundColor':colour, "cursor":"pointer"});
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
$('<div/>',{class:"palette_icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer);
var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).html(configLabel).appendTo(container);
var nodeContainer = $('<span></span>').css({"verticalAlign":"top","marginLeft":"6px"}).text(configLabel).appendTo(container);
nodeDiv.on('dblclick',function() {
RED.editor.editConfig("", configNode.type, configNode.id);
@@ -231,24 +251,27 @@ RED.sidebar.info = (function() {
}
}
if (m) {
propRow = $('<tr class="node-info-node-row"><td>'+RED._("subflow.category")+'</td><td></td></tr>').appendTo(tableBody);
var category = subflowNode.category||"subflows";
$(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category}))
$('<tr class="node-info-subflow-row"><td>'+RED._("sidebar.info.instances")+"</td><td>"+subflowUserCount+'</td></tr>').appendTo(tableBody);
}
var infoText = "";
if (!subflowNode && node.type !== "comment" && node.type !== "tab") {
infoSection.title.html(RED._("sidebar.info.nodeHelp"));
infoSection.title.text(RED._("sidebar.info.nodeHelp"));
var helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>');
infoText = helpText;
} else if (node.type === "tab") {
infoSection.title.html(RED._("sidebar.info.flowDesc"));
infoSection.title.text(RED._("sidebar.info.flowDesc"));
infoText = marked(node.info||"")||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>');
}
if (subflowNode) {
infoText = infoText + (marked(subflowNode.info||"")||('<span class="node-info-none">'+RED._("sidebar.info.none")+'</span>'));
infoSection.title.html(RED._("sidebar.info.subflowDesc"));
infoSection.title.text(RED._("sidebar.info.subflowDesc"));
} else if (node._def && node._def.info) {
infoSection.title.html(RED._("sidebar.info.nodeHelp"));
infoSection.title.text(RED._("sidebar.info.nodeHelp"));
var info = node._def.info;
var textInfo = (typeof info === "function" ? info.call(node) : info);
// TODO: help

View File

@@ -52,7 +52,7 @@ RED.tray = (function() {
b.attr('id',button.id);
}
if (button.text) {
b.html(button.text);
b.text(button.text);
}
if (button.click) {
b.click((function(action) {

View File

@@ -147,7 +147,7 @@ RED.typeSearch = (function() {
var label = object.label;
object.index += "|"+label.toLowerCase();
$('<div>',{class:"red-ui-search-result-node-label"}).html(label).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-label"}).text(label).appendTo(contentDiv);
div.click(function(evt) {
evt.preventDefault();

View File

@@ -26,14 +26,14 @@ RED.utils = (function() {
function buildMessageSummaryValue(value) {
var result;
if (Array.isArray(value)) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('array['+value.length+']');
} else if (value === null) {
result = $('<span class="debug-message-object-value debug-message-type-null">null</span>');
} else if (typeof value === 'object') {
if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.length+']');
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('buffer['+value.length+']');
} else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').text('array['+value.length+']');
} else {
result = $('<span class="debug-message-object-value debug-message-type-meta">object</span>');
}
@@ -304,7 +304,7 @@ RED.utils = (function() {
element.addClass('collapsed');
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
makeExpandable(header, function() {
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header);
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text(typeHint||'string').appendTo(header);
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
$('<pre class="debug-message-type-string"></pre>').text(obj).appendTo(row);
},function(state) {if (ontoggle) { ontoggle(path,state);}}, checkExpanded(strippedKey,expandPaths));
@@ -358,7 +358,7 @@ RED.utils = (function() {
element.addClass('debug-message-buffer-raw');
}
if (key) {
headerHead = $('<span class="debug-message-type-meta"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
headerHead = $('<span class="debug-message-type-meta"></span>').text(typeHint||(type+'['+originalLength+']')).appendTo(entryObj);
} else {
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
$('<span>[ </span>').appendTo(headerHead);
@@ -381,7 +381,7 @@ RED.utils = (function() {
makeExpandable(header,function() {
if (!key) {
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||(type+'['+originalLength+']')).appendTo(header);
headerHead = $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text(typeHint||(type+'['+originalLength+']')).appendTo(header);
}
if (type === 'buffer') {
var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element);
@@ -394,7 +394,7 @@ RED.utils = (function() {
}
$('<pre class="debug-message-type-string"></pre>').text(stringEncoding).appendTo(sr);
var bufferOpts = $('<span class="debug-message-buffer-opts"></span>').appendTo(headerHead);
var switchFormat = $('<a href="#"></a>').addClass('selected').html('raw').appendTo(bufferOpts).click(function(e) {
var switchFormat = $('<a href="#"></a>').addClass('selected').text('raw').appendTo(bufferOpts).click(function(e) {
e.preventDefault();
e.stopPropagation();
formatBuffer(element,$(this),sourceId,path,true);
@@ -471,7 +471,7 @@ RED.utils = (function() {
$('<i class="fa fa-caret-right debug-message-object-handle"></i> ').prependTo(header);
makeExpandable(header, function() {
if (!key) {
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html('object').appendTo(header);
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').text('object').appendTo(header);
}
for (i=0;i<keys.length;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
@@ -507,7 +507,7 @@ RED.utils = (function() {
checkExpanded(strippedKey,expandPaths));
}
if (key) {
$('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj);
$('<span class="debug-message-type-meta"></span>').text('object').appendTo(entryObj);
} else {
headerHead = $('<span class="debug-message-object-header"></span>').appendTo(entryObj);
$('<span>{ </span>').appendTo(headerHead);
@@ -708,7 +708,9 @@ RED.utils = (function() {
function getDefaultNodeIcon(def,node) {
var icon_url;
if (typeof def.icon === "function") {
if (node && node.type === "subflow") {
icon_url = "node-red/subflow.png";
} else if (typeof def.icon === "function") {
try {
icon_url = def.icon.call(node);
} catch(err) {
@@ -721,11 +723,26 @@ RED.utils = (function() {
var iconPath = separateIconPath(icon_url);
if (!iconPath.module) {
iconPath.module = def.set.module;
if (def.set) {
iconPath.module = def.set.module;
} else {
// Handle subflow instance nodes that don't have def.set
iconPath.module = "node-red";
}
}
return iconPath;
}
function isIconExists(iconPath) {
var iconSets = RED.nodes.getIconSets();
var iconFileList = iconSets[iconPath.module];
if (iconFileList && iconFileList.indexOf(iconPath.file) !== -1) {
return true;
} else {
return false;
}
}
function getNodeIcon(def,node) {
if (def.category === 'config') {
return "icons/node-red/cog.png"
@@ -733,18 +750,19 @@ RED.utils = (function() {
return "icons/node-red/subflow.png"
} else if (node && node.type === 'unknown') {
return "icons/node-red/alert.png"
} else if (node && node.type === 'subflow') {
return "icons/node-red/subflow.png"
} else if (node && node.icon) {
var iconPath = separateIconPath(node.icon);
var iconSets = RED.nodes.getIconSets();
var iconFileList = iconSets[iconPath.module];
if (iconFileList && iconFileList.indexOf(iconPath.file) !== -1) {
if (isIconExists(iconPath)) {
return "icons/" + node.icon;
}
}
var iconPath = getDefaultNodeIcon(def, node);
if (def.category === 'subflows') {
if (!isIconExists(iconPath)) {
return "icons/node-red/subflow.png";
}
}
return "icons/"+iconPath.module+"/"+iconPath.file;
}

View File

@@ -0,0 +1,164 @@
/**
* Copyright 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.view.navigator = (function() {
var nav_scale = 25;
var nav_width = 5000/nav_scale;
var nav_height = 5000/nav_scale;
var navContainer;
var navBox;
var navBorder;
var navVis;
var scrollPos;
var scaleFactor;
var chartSize;
var dimensions;
var isDragging;
var isShowing = false;
function refreshNodes() {
if (!isShowing) {
return;
}
var navNode = navVis.selectAll(".navnode").data(RED.view.getActiveNodes(),function(d){return d.id});
navNode.exit().remove();
navNode.enter().insert("rect")
.attr('class','navnode')
.attr("pointer-events", "none");
navNode.each(function(d) {
d3.select(this).attr("x",function(d) { return (d.x-d.w/2)/nav_scale })
.attr("y",function(d) { return (d.y-d.h/2)/nav_scale })
.attr("width",function(d) { return Math.max(9,d.w/nav_scale) })
.attr("height",function(d) { return Math.max(3,d.h/nav_scale) })
.attr("fill",function(d) { return d._def.color;})
});
}
function onScroll() {
if (!isDragging) {
resizeNavBorder();
}
}
function resizeNavBorder() {
if (navBorder) {
scaleFactor = RED.view.scale();
chartSize = [ $("#chart").width(), $("#chart").height()];
scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
navBorder.attr('x',scrollPos[0]/nav_scale)
.attr('y',scrollPos[1]/nav_scale)
.attr('width',chartSize[0]/nav_scale/scaleFactor)
.attr('height',chartSize[1]/nav_scale/scaleFactor)
}
}
return {
init: function() {
$(window).resize(resizeNavBorder);
RED.events.on("sidebar:resize",resizeNavBorder);
var hideTimeout;
navContainer = $('<div>').css({
"position":"absolute",
"bottom":$("#workspace-footer").height(),
"right":0,
zIndex: 1
}).appendTo("#workspace").hide();
navBox = d3.select(navContainer[0])
.append("svg:svg")
.attr("width", nav_width)
.attr("height", nav_height)
.attr("pointer-events", "all")
.style({
position: "absolute",
bottom: 0,
right:0,
zIndex: 101,
"border-left": "1px solid #ccc",
"border-top": "1px solid #ccc",
background: "rgba(245,245,245,0.5)",
"box-shadow": "-1px 0 3px rgba(0,0,0,0.1)"
});
navBox.append("rect").attr("x",0).attr("y",0).attr("width",nav_width).attr("height",nav_height).style({
fill:"none",
stroke:"none",
pointerEvents:"all"
}).on("mousedown", function() {
// Update these in case they have changed
scaleFactor = RED.view.scale();
chartSize = [ $("#chart").width(), $("#chart").height()];
dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor];
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
navBorder.attr('x',newX).attr('y',newY);
isDragging = true;
$("#chart").scrollLeft(newX*nav_scale*scaleFactor);
$("#chart").scrollTop(newY*nav_scale*scaleFactor);
}).on("mousemove", function() {
if (!isDragging) { return }
if (d3.event.buttons === 0) {
isDragging = false;
return;
}
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
navBorder.attr('x',newX).attr('y',newY);
$("#chart").scrollLeft(newX*nav_scale*scaleFactor);
$("#chart").scrollTop(newY*nav_scale*scaleFactor);
}).on("mouseup", function() {
isDragging = false;
})
navBorder = navBox.append("rect")
.attr("stroke-dasharray","5,5")
.attr("pointer-events", "none")
.style({
stroke: "#999",
strokeWidth: 1,
fill: "white",
});
navVis = navBox.append("svg:g")
$("#btn-navigate").click(function(evt) {
evt.preventDefault();
if (!isShowing) {
isShowing = true;
$("#btn-navigate").addClass("selected");
resizeNavBorder();
refreshNodes();
$("#chart").on("scroll",onScroll);
navContainer.fadeIn(200);
} else {
isShowing = false;
navContainer.fadeOut(100);
$("#chart").off("scroll",onScroll);
$("#btn-navigate").removeClass("selected");
}
})
},
refresh: refreshNodes,
resize: resizeNavBorder
}
})();

View File

@@ -58,7 +58,8 @@ RED.view = (function() {
lastClickNode = null,
dblClickPrimed = null,
clickTime = 0,
clickElapsed = 0;
clickElapsed = 0,
scroll_position;
var clipboard = "";
@@ -73,6 +74,8 @@ RED.view = (function() {
var PORT_TYPE_INPUT = 1;
var PORT_TYPE_OUTPUT = 0;
var chart = $("#chart");
var outer = d3.select("#chart")
.append("svg:svg")
.attr("width", space_width)
@@ -94,6 +97,16 @@ RED.view = (function() {
.on("mousemove", canvasMouseMove)
.on("mousedown", canvasMouseDown)
.on("mouseup", canvasMouseUp)
.on("mouseenter", function() {
if (lasso) {
if (d3.event.buttons !== 1) {
lasso.remove();
lasso = null;
}
} else if (mouse_mode === RED.state.PANNING && d3.event.buttons !== 4) {
resetMouseVars();
}
})
.on("touchend", function() {
clearTimeout(touchStartTime);
touchStartTime = null;
@@ -283,7 +296,6 @@ RED.view = (function() {
function init() {
RED.events.on("workspace:change",function(event) {
var chart = $("#chart");
if (event.old !== 0) {
workspaceScrollPositions[event.old] = {
left:chart.scrollLeft(),
@@ -320,6 +332,8 @@ RED.view = (function() {
redraw();
});
RED.view.navigator.init();
$("#btn-zoom-out").click(function() {zoomOut();});
$("#btn-zoom-zero").click(function() {zoomZero();});
$("#btn-zoom-in").click(function() {zoomIn();});
@@ -490,6 +504,7 @@ RED.view = (function() {
}
} else {
var subflow = RED.nodes.subflow(m[1]);
nn.name = "";
nn.inputs = subflow.in.length;
nn.outputs = subflow.out.length;
}
@@ -525,6 +540,15 @@ RED.view = (function() {
function canvasMouseDown() {
var point;
if (d3.event.button === 1) {
// Middle Click pan
mouse_mode = RED.state.PANNING;
mouse_position = [d3.event.pageX,d3.event.pageY]
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
return;
}
if (!mousedown_node && !mousedown_link) {
selected_link = null;
updateSelection();
@@ -643,7 +667,6 @@ RED.view = (function() {
function canvasMouseMove() {
var i;
var node;
mouse_position = d3.touches(this)[0]||d3.mouse(this);
// Prevent touch scrolling...
//if (d3.touches(this)[0]) {
// d3.event.preventDefault();
@@ -654,6 +677,22 @@ RED.view = (function() {
//if (point[0]-container.scrollLeft < 30 && container.scrollLeft > 0) { container.scrollLeft -= 15; }
//console.log(d3.mouse(this),container.offsetWidth,container.offsetHeight,container.scrollLeft,container.scrollTop);
if (mouse_mode === RED.state.PANNING) {
var pos = [d3.event.pageX,d3.event.pageY];
var deltaPos = [
mouse_position[0]-pos[0],
mouse_position[1]-pos[1]
];
chart.scrollLeft(scroll_position[0]+deltaPos[0])
chart.scrollTop(scroll_position[1]+deltaPos[1])
return
}
mouse_position = d3.touches(this)[0]||d3.mouse(this);
if (lasso) {
var ox = parseInt(lasso.attr("ox"));
var oy = parseInt(lasso.attr("oy"));
@@ -905,6 +944,10 @@ RED.view = (function() {
function canvasMouseUp() {
var i;
var historyEvent;
if (mouse_mode === RED.state.PANNING) {
resetMouseVars();
return
}
if (mouse_mode === RED.state.QUICK_JOINING) {
return;
}
@@ -1019,17 +1062,20 @@ RED.view = (function() {
function zoomIn() {
if (scaleFactor < 2) {
scaleFactor += 0.1;
RED.view.navigator.resize();
redraw();
}
}
function zoomOut() {
if (scaleFactor > 0.3) {
scaleFactor -= 0.1;
RED.view.navigator.resize();
redraw();
}
}
function zoomZero() {
scaleFactor = 1;
RED.view.navigator.resize();
redraw();
}
@@ -1651,7 +1697,9 @@ RED.view = (function() {
clickElapsed = now-clickTime;
clickTime = now;
dblClickPrimed = (lastClickNode == mousedown_node);
dblClickPrimed = (lastClickNode == mousedown_node &&
d3.event.buttons === 1 &&
!d3.event.shiftKey && !d3.event.metaKey && !d3.event.altKey && !d3.event.ctrlKey);
lastClickNode = mousedown_node;
var i;
@@ -2501,7 +2549,7 @@ RED.view = (function() {
}
).classed("link_selected", false);
}
RED.view.navigator.refresh();
if (d3.event) {
d3.event.preventDefault();
}
@@ -2775,7 +2823,9 @@ RED.view = (function() {
gridSize = Math.max(5,v);
updateGrid();
}
},
getActiveNodes: function() {
return activeNodes;
}
};
})();

View File

@@ -43,7 +43,7 @@ RED.workspaces = (function() {
return ws;
}
function deleteWorkspace(ws) {
if (workspace_tabs.count() == 1) {
if (workspaceTabCount === 1) {
return;
}
removeWorkspace(ws);
@@ -65,7 +65,7 @@ RED.workspaces = (function() {
buttons: [
{
id: "node-dialog-delete",
class: 'leftButton'+((workspace_tabs.count() == 1)?" disabled":""),
class: 'leftButton'+((workspaceTabCount === 1)?" disabled":""),
text: RED._("common.label.delete"), //'<i class="fa fa-trash"></i>',
click: function() {
deleteWorkspace(workspace);
@@ -172,12 +172,12 @@ RED.workspaces = (function() {
i.addClass('fa-toggle-on');
i.removeClass('fa-toggle-off');
$("#node-input-disabled").prop("checked",false);
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
} else {
i.addClass('fa-toggle-off');
i.removeClass('fa-toggle-on');
$("#node-input-disabled").prop("checked",true);
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
$("#node-input-disabled-label").text(RED._("editor:workspace.disabled"));
}
})
@@ -185,13 +185,13 @@ RED.workspaces = (function() {
$("#node-input-disabled").prop("checked",workspace.disabled);
if (workspace.disabled) {
dialogForm.find("#node-input-disabled-btn i").removeClass('fa-toggle-on').addClass('fa-toggle-off');
$("#node-input-disabled-label").html(RED._("editor:workspace.disabled"));
$("#node-input-disabled-label").text(RED._("editor:workspace.disabled"));
} else {
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
}
} else {
workspace.disabled = false;
$("#node-input-disabled-label").html(RED._("editor:workspace.enabled"));
$("#node-input-disabled-label").text(RED._("editor:workspace.enabled"));
}
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
@@ -214,6 +214,7 @@ RED.workspaces = (function() {
var workspace_tabs;
var workspaceTabCount = 0;
function createWorkspaceTabs() {
workspace_tabs = RED.tabs.create({
id: "workspace-tabs",
@@ -240,18 +241,24 @@ RED.workspaces = (function() {
}
},
onadd: function(tab) {
if (tab.type === "tab") {
workspaceTabCount++;
}
$('<span class="workspace-disabled-icon"><i class="fa fa-ban"></i> </span>').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label");
if (tab.disabled) {
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('workspace-disabled');
}
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() <= 1);
if (workspace_tabs.count() === 1) {
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
if (workspaceTabCount === 1) {
showWorkspace();
}
},
onremove: function(tab) {
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() <= 1);
if (workspace_tabs.count() === 0) {
if (tab.type === "tab") {
workspaceTabCount--;
}
RED.menu.setDisabled("menu-item-workspace-delete",workspaceTabCount <= 1);
if (workspaceTabCount === 0) {
hideWorkspace();
}
},
@@ -266,6 +273,7 @@ RED.workspaces = (function() {
addWorkspace();
}
});
workspaceTabCount = 0;
}
function showWorkspace() {
$("#workspace .red-ui-tabs").show()
@@ -334,7 +342,7 @@ RED.workspaces = (function() {
return workspace_tabs.contains(id);
},
count: function() {
return workspace_tabs.count();
return workspaceTabCount;
},
active: function() {
return activeWorkspace

View File

@@ -113,8 +113,8 @@
.debug-message-meta {
background: #fff;
font-size: 10px;
color: #777;
font-size: 11px;
color: #707070;
}
.debug-message-date {
padding: 1px 5px 1px 1px;
@@ -125,7 +125,7 @@
}
.debug-message-name {
padding: 1px 5px;
color: #777;
color: #707070;
}
.debug-message-tools {
position: absolute;
@@ -159,7 +159,7 @@
.debug-message-element {
color: #333;
font-family: Menlo, monospace;
font-size: 12px !important;
font-size: 13px !important;
line-height: 1.3em;
}
.debug-message-object-key {
@@ -188,11 +188,9 @@
.debug-message-element.collapsed>span>.debug-message-object-handle {
transform: rotate(0deg);
}
.debug-message-object-entry.collapsed > .debug-message-object-entry {
display:none;
}
.debug-message-element.collapsed .debug-message-object-entry {
display:none;
}
@@ -202,14 +200,13 @@
.debug-message-element.collapsed .debug-message-buffer-opts {
display: none;
}
.debug-message-element.collapsed .debug-message-object-type-header {
display:none;
}
.debug-message-object-entry pre {
font-family: Menlo, monospace;
font-size: 12px;
line-height: 1.4em;
font-size: 13px;
line-height: 1.2em;
margin: 0 0 0 -1em;
}

View File

@@ -353,3 +353,64 @@
}
}
#node-settings-icon {
margin-left: 10px;
width: calc(100% - 163px);
}
.red-ui-icon-picker {
position: absolute;
border: 1px solid $primary-border-color;
box-shadow: 0 1px 6px -3px black;
background: white;
z-Index: 21;
display: none;
select {
box-sizing: border-box;
margin: 3px;
width: calc(100% - 6px);
}
}
.red-ui-icon-list {
width: 308px;
height: 200px;
overflow-y: scroll;
line-height: 0px;
}
.red-ui-icon-list-icon {
display: inline-block;
margin: 2px;
padding: 4px;
cursor: pointer;
border-radius: 4px;
&:hover {
background: lighten($node-selected-color,20%);
}
&.selected {
background: lighten($node-selected-color,20%);
.red-ui-search-result-node {
border-color: white;
}
}
}
.red-ui-icon-list-module {
background: $palette-header-background;
font-size: 0.9em;
padding: 3px;
color: #666;
clear: both;
i {
margin-right: 5px;
}
}
.red-ui-icon-meta {
border-top: 1px solid $secondary-border-color;
span {
padding: 4px;
color: #666;
font-size: 0.9em;
}
button {
float: right;
margin: 2px;
}
}

View File

@@ -203,7 +203,7 @@
height: 25px;
line-height: 23px;
padding: 0 10px;
user-select: none;
.button-group:not(:last-child) {
margin-right: 5px;
@@ -227,6 +227,7 @@
font-size: 11px;
line-height: 17px;
height: 18px;
width: 18px;
&.text-button {
width: auto;
padding: 0 5px;

View File

@@ -49,7 +49,12 @@
.palette-module-version {
color: #aaa;
}
.palette-module-errors .fa-warning {
opacity: 0.5;
}
ul.palette-module-error-list li {
color: #aaa;
}
}
@@ -222,6 +227,20 @@
margin-left: 5px;
}
}
.palette-module-meta .fa-warning {
color: #AD1625;
}
ul.palette-module-error-list {
display: inline-block;
list-style-type: none;
margin: 0;
font-size: 0.9em;
li {
border: none;
background: none;
}
}
.palette-module-shade {
@include shade;
text-align: center;

View File

@@ -30,7 +30,6 @@
}
.red-ui-popover:after, .red-ui-popover:before {
top: 50%;
border: solid transparent;
content: " ";
height: 0;
@@ -39,12 +38,18 @@
pointer-events: none;
}
.red-ui-popover.red-ui-popover-right:after, .red-ui-popover.red-ui-popover-right:before {
top: 50%;
right: 100%;
}
.red-ui-popover.red-ui-popover-left:after, .red-ui-popover.red-ui-popover-left:before {
top: 50%;
left: 100%;
}
.red-ui-popover.red-ui-popover-bottom:after, .red-ui-popover.red-ui-popover-bottom:before {
bottom: 100%;
left: 50%;
}
.red-ui-popover.red-ui-popover-right:after {
border-color: rgba(136, 183, 213, 0);
@@ -72,6 +77,21 @@
margin-top: -11px;
}
.red-ui-popover.red-ui-popover-bottom:after {
border-color: rgba(136, 183, 213, 0);
border-bottom-color: #fff;
border-width: 10px;
margin-left: -10px;
}
.red-ui-popover.red-ui-popover-bottom:before {
border-color: rgba(194, 225, 245, 0);
border-bottom-color: $primary-border-color;
border-width: 11px;
margin-left: -11px;
}
.red-ui-popover-size-small {
font-size: 11px;
padding: 5px;
@@ -93,4 +113,12 @@
border-width: 6px;
margin-top: -6px;
}
&.red-ui-popover-bottom:after {
border-width: 5px;
margin-left: -5px;
}
&.red-ui-popover-bottom:before {
border-width: 6px;
margin-left: -6px;
}
}

View File

@@ -139,16 +139,17 @@
}
}
button.editor-button {
width: calc(50% - 40px);
width: calc(50% - 80px);
margin: 20px;
height: 175px;
height: auto;
line-height: 2em;
font-size: 1.5em !important;
padding: 10px;
border-color: #aaa;
i {
color: #ccc;
color: #aaa;
}
&:hover i {
color: #aaa;
color: #999;
}
}
.button-group {
@@ -160,7 +161,6 @@
button.projects-dialog-screen-create-type {
height: auto;
padding: 10px;
}
.button-group {
text-align: center;

View File

@@ -93,7 +93,7 @@
color: $workspace-button-color-hover;
}
}
.red-ui-tab-icon {
img.red-ui-tab-icon {
opacity: 0.2;
}
}
@@ -113,6 +113,21 @@
&.red-ui-tabs-add.red-ui-tabs-scrollable {
padding-right: 59px;
}
&.red-ui-tabs-collapsible {
li:not(.active) {
display: none;
&.red-ui-tab-pinned {
a {
padding-left: 0;
text-align: center;
}
span {
display: none;
}
width: 32px;
}
}
}
&.red-ui-tabs-vertical {
box-sizing: border-box;
@@ -157,6 +172,15 @@
}
}
}
.red-ui-tabs-select {
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
opacity: 0.4;
background: red;
}
}
.red-ui-tab-button {
position: absolute;
@@ -180,7 +204,33 @@
z-index: 2;
}
}
.red-ui-tab-link-buttons {
position: absolute;
box-sizing: border-box;
top: 0;
right: 0;
height: 35px;
background: #fff;
border-bottom: 1px solid $primary-border-color;
z-index: 2;
a {
@include workspace-button;
line-height: 26px;
height: 28px;
width: 28px;
margin: 4px 3px 3px;
border: 1px solid $primary-border-color;
z-index: 2;
&.red-ui-tab-link-button {
&:not(.active) {
background: #eee;
}
}
&.red-ui-tab-link-button-menu {
border-color: white;
}
}
}
.red-ui-tab-scroll {
width: 21px;
top: 0;
@@ -216,7 +266,7 @@
right: 38px;
}
.red-ui-tab-icon {
img.red-ui-tab-icon {
margin-left: -8px;
margin-right: 3px;
margin-top: -2px;
@@ -225,6 +275,11 @@
height: 20px;
vertical-align: middle;
}
i.red-ui-tab-icon {
opacity: 0.7;
width: 18px;
height: 20px;
}
.red-ui-tabs-badges {
position: absolute;

View File

@@ -64,9 +64,10 @@
vertical-align: middle;
color: #555;
i {
position:relative;
top:-3px;
margin-right:4px;
position: relative;
top: -3px;
margin-left: 1px;
margin-right: 2px;
margin-top: 1px;
vertical-align: middle;
&.fa-ellipsis-h {

View File

@@ -47,7 +47,9 @@
.workspace-footer-button {
@include component-footer-button;
}
.workspace-footer-button-toggle {
@include component-footer-button-toggle;
}
#workspace-footer {
@include component-footer;
}

View File

@@ -51,6 +51,7 @@
<a class="workspace-footer-button" id="btn-zoom-out" href="#"><i class="fa fa-minus"></i></a>
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
<a class="workspace-footer-button-toggle" id="btn-navigate" href="#"><i class="fa fa-map-o"></i></a>
</div>
<div id="editor-shade" class="hide"></div>
</div>
@@ -131,6 +132,10 @@
<i class="fa fa-tag"></i>
<label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name">
</div>
<div class="form-row">
<i class="fa fa-folder-o"></i>
<label for="subflow-input-category" data-i18n="editor:subflow.category"></label><select style="width: 250px;" id="subflow-input-category"></select><input style="display:none; margin-left: 10px; width:calc(100% - 250px)" type="text" id="subflow-input-custom-category">
</div>
<div class="form-row" style="margin-bottom: 0px;">
<label for="subflow-input-info" data-i18n="editor:subflow.info"></label>
<a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a>

1
editor/vendor/ace/snippets/json.js vendored Normal file
View File

@@ -0,0 +1 @@
ace.define("ace/snippets/json",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="json"})

1
editor/vendor/ace/snippets/sql.js vendored Normal file
View File

@@ -0,0 +1 @@
ace.define("ace/snippets/sql",["require","exports","module"],function(e,t,n){"use strict";t.snippetText="snippet tbl\n create table ${1:table} (\n ${2:columns}\n );\nsnippet col\n ${1:name} ${2:type} ${3:default ''} ${4:not null}\nsnippet ccol\n ${1:name} varchar2(${2:size}) ${3:default ''} ${4:not null}\nsnippet ncol\n ${1:name} number ${3:default 0} ${4:not null}\nsnippet dcol\n ${1:name} date ${3:default sysdate} ${4:not null}\nsnippet ind\n create index ${3:$1_$2} on ${1:table}(${2:column});\nsnippet uind\n create unique index ${1:name} on ${2:table}(${3:column});\nsnippet tblcom\n comment on table ${1:table} is '${2:comment}';\nsnippet colcom\n comment on column ${1:table}.${2:column} is '${3:comment}';\nsnippet addcol\n alter table ${1:table} add (${2:column} ${3:type});\nsnippet seq\n create sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\nsnippet s*\n select * from ${1:table}\n",t.scope="sql"})

1
editor/vendor/ace/snippets/swift.js vendored Normal file
View File

@@ -0,0 +1 @@
ace.define("ace/snippets/swift",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="swift"})

View File

@@ -117,6 +117,7 @@
'$contains':{ args:[ 'str', 'pattern' ]},
'$count':{ args:[ 'array' ]},
'$each':{ args:[ 'object', 'function' ]},
'$env': { args:[ 'arg' ]},
'$exists':{ args:[ 'arg' ]},
'$filter':{ args:[ 'array', 'function' ]},
'$floor':{ args:[ 'number' ]},

View File

@@ -1,57 +0,0 @@
<script type="text/x-red" data-template-name="sentiment">
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
</div>
</script>
<script type="text/x-red" data-help-name="sentiment">
<p>Analyses the chosen property, default <code>payload</code>, and adds a <code>sentiment</code> object.</p>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>sentiment <span class="property-type">object</span></dt>
<dd>contains the resulting AFINN-111 sentiment.</dd>
<dt>sentiment.score <span class="property-type">number</span></dt>
<dd>the sentiment score.</dd>
</dl>
<h3>Inputs</h3>
<dl class="message-properties">
<dt>overrides <span class="property-type">object</span></dt>
<dd>an object of word score overrides can be supplied - <code>{ word:score,... }</code>.</dd>
</dl>
<h3>Details</h3>
<p>A score greater than zero is positive and less than zero is negative.</p>
<p>The score typically ranges from -5 to +5, but can go higher and lower.</p>
<p>See <a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('sentiment',{
category: 'analysis-function',
color:"#E6E0F8",
defaults: {
name: {value:""},
property: {value:"payload",required:true}
},
inputs:1,
outputs:1,
icon: "arrow-in.png",
label: function() {
return this.name||"sentiment";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.property === undefined) {
$("#node-input-property").val("payload");
}
$("#node-input-property").typedInput({default:'msg',types:['msg']});
}
});
</script>

View File

@@ -1,23 +0,0 @@
module.exports = function(RED) {
"use strict";
var sentiment = require('sentiment');
function SentimentNode(n) {
RED.nodes.createNode(this,n);
this.property = n.property||"payload";
var node = this;
this.on("input", function(msg) {
var value = RED.util.getMessageProperty(msg,node.property);
if (value !== undefined) {
sentiment(value, msg.overrides || null, function (err, result) {
msg.sentiment = result;
node.send(msg);
});
}
else { node.send(msg); } // If no matching property - just pass it on.
});
}
RED.nodes.registerType("sentiment",SentimentNode);
}

View File

@@ -263,7 +263,7 @@ If you want every 20 minutes from now - use the <i>"interval"</i> option.</p>
$("#node-input-payload").typedInput({
default: 'str',
typeField: $("#node-input-payloadType"),
types:['flow','global','str','num','bool','json','bin','date']
types:['flow','global','str','num','bool','json','bin','date','env']
});
$("#inject-time-type-select").change(function() {

View File

@@ -154,7 +154,9 @@
name: this._("debug.sidebar.name"),
content: uiComponents.content,
toolbar: uiComponents.footer,
enableOnEdit: true
enableOnEdit: true,
pinned: true,
iconClass: "fa fa-list-alt"
});
RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); });
@@ -181,7 +183,7 @@
this.handleDebugMessage = function(t,o) {
var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
if (sourceNode) {
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name};
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name,type:sourceNode.type,_alias:o._alias};
}
RED.debug.handleDebugMessage(o);
if (subWindow) {

View File

@@ -138,7 +138,7 @@
icon: "arrow-in.png",
align: "right",
label: function() {
return this.name||this.command;
return this.name||this.command||(this.useSpawn=="true"?this._("exec.spawn"):this._("exec.exec"));
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -52,6 +52,12 @@
<p>The Catch node can also be used to handle errors. To invoke a Catch node,
pass <code>msg</code> as a second argument to <code>node.error</code>:</p>
<pre>node.error("Error",msg);</pre>
<h4>Referring Node Information</h4>
<p>In the function block, id and name of the node can be referenced using the following properties:</p>
<ul>
<li><code>node.id</code> - id of the node</li>
<li><code>node.name</code> - name of the node</li>
</ul>
</script>
<script type="text/javascript">
@@ -68,7 +74,7 @@
outputs:1,
icon: "function.png",
label: function() {
return this.name;
return this.name||this._("function.function");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -62,9 +62,13 @@ module.exports = function(RED) {
"results = (function(msg){ "+
"var __msgid__ = msg._msgid;"+
"var node = {"+
"id:__node__.id,"+
"name:__node__.name,"+
"log:__node__.log,"+
"error:__node__.error,"+
"warn:__node__.warn,"+
"debug:__node__.debug,"+
"trace:__node__.trace,"+
"on:__node__.on,"+
"status:__node__.status,"+
"send:function(msgs){ __node__.send(__msgid__,msgs);}"+
@@ -78,10 +82,13 @@ module.exports = function(RED) {
console:console,
util:util,
Buffer:Buffer,
Date: Date,
RED: {
util: RED.util
},
__node__: {
id: node.id,
name: node.name,
log: function() {
node.log.apply(node, arguments);
},
@@ -91,6 +98,12 @@ module.exports = function(RED) {
warn: function() {
node.warn.apply(node, arguments);
},
debug: function() {
node.debug.apply(node, arguments);
},
trace: function() {
node.trace.apply(node, arguments);
},
send: function(id, msgs) {
sendResults(node, id, msgs);
},
@@ -196,7 +209,14 @@ module.exports = function(RED) {
}
var context = vm.createContext(sandbox);
try {
this.script = vm.createScript(functionText);
this.script = vm.createScript(functionText, {
filename: 'Function node:'+this.id+(this.name?' ['+this.name+']':''), // filename for stack traces
displayErrors: true
// Using the following options causes node 4/6 to not include the line number
// in the stack output. So don't use them.
// lineOffset: -11, // line number offset to be used for stack traces
// columnOffset: 0, // column number offset to be used for stack traces
});
this.on("input", function(msg) {
try {
var start = process.hrtime();
@@ -211,6 +231,13 @@ module.exports = function(RED) {
this.status({fill:"yellow",shape:"dot",text:""+converted});
}
} catch(err) {
//remove unwanted part
var index = err.stack.search(/\n\s*at ContextifyScript.Script.runInContext/);
err.stack = err.stack.slice(0, index).split('\n').slice(0,-1).join('\n');
var stack = err.stack.split(/\r?\n/);
//store the error in msg to be used in flows
msg.error = err;
var line = 0;
var errorMessage;

View File

@@ -88,7 +88,7 @@
category: 'function',
defaults: {
name: {value:""},
field: {value:"payload", validate: RED.validators.typedInput("fieldType")},
field: {value:"payload", validate:RED.validators.typedInput("fieldType")},
fieldType: {value:"msg"},
format: {value:"handlebars"},
syntax: {value:"mustache"},
@@ -99,13 +99,17 @@
outputs:1,
icon: "template.png",
label: function() {
return this.name;
return this.name||this._("template.template");;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var that = this;
if (!this.field) {
this.field = 'payload';
$("#node-input-field").val("payload");
}
if (!this.fieldType) {
this.fieldType = 'msg';
}

View File

@@ -50,6 +50,7 @@ module.exports = function(RED) {
// try node context:
var dot = name.indexOf(".");
/* istanbul ignore else */
if (dot > 0) {
var contextName = name.substr(0, dot);
var variableName = name.substr(dot + 1);
@@ -61,7 +62,8 @@ module.exports = function(RED) {
return this.nodeContext.global.get(variableName);
}
}
}catch(err) {
}
catch(err) {
throw err;
}
}
@@ -87,24 +89,27 @@ module.exports = function(RED) {
* Allow template contents to be defined externally
* through inbound msg.template IFF node.template empty
*/
var template = node.template;
if (msg.hasOwnProperty("template")) {
if (node.template == "" || node.template === null) {
node.template = msg.template;
if (template == "" || template === null) {
template = msg.template;
}
}
if (node.syntax === "mustache") {
if (node.outputFormat === "json") {
value = mustache.render(node.template,new NodeContext(msg, node.context(), null, true));
value = mustache.render(template,new NodeContext(msg, node.context(), null, true));
} else {
value = mustache.render(node.template,new NodeContext(msg, node.context(), null, false));
value = mustache.render(template,new NodeContext(msg, node.context(), null, false));
}
} else {
value = node.template;
value = template;
}
/* istanbul ignore else */
if (node.outputFormat === "json") {
value = JSON.parse(value);
}
/* istanbul ignore else */
if (node.outputFormat === "yaml") {
value = yaml.load(value);
}
@@ -117,7 +122,8 @@ module.exports = function(RED) {
node.context().global.set(node.field,value);
}
node.send(msg);
} catch(err) {
}
catch(err) {
node.error(err.message);
}
});

View File

@@ -123,6 +123,7 @@ module.exports = function(RED) {
delete node.topics[topic];
node.send(msg2);
}
else { delete node.topics[topic]; }
node.status({});
}, node.duration);
}

View File

@@ -33,7 +33,7 @@
outputs:0,
icon: "comment.png",
label: function() {
return this.name||"";
return this.name||this._("comment.comment");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -222,7 +222,6 @@ RED.debug = (function() {
clearMessageList(false);
});
return {
content: content,
footer: footerToolbar
@@ -238,6 +237,9 @@ RED.debug = (function() {
workspaceOrder.forEach(function(ws,i) {
workspaceOrderMap[ws] = i;
});
candidateNodes = candidateNodes.filter(function(node) {
return workspaceOrderMap.hasOwnProperty(node.z);
})
candidateNodes.sort(function(A,B) {
var wsA = workspaceOrderMap[A.z];
var wsB = workspaceOrderMap[B.z];
@@ -339,7 +341,7 @@ RED.debug = (function() {
activeMenuMessage.clearPinned();
}},
null,
{id:"debug-message-menu-item-filter",label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
{id:"debug-message-menu-item-filter", label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
var candidateNodes = RED.nodes.filterNodes({type:'debug'});
candidateNodes.forEach(function(n) {
filteredNodes[n.id] = true;
@@ -361,6 +363,15 @@ RED.debug = (function() {
menuOptionMenu.on('mouseup', function() { $(this).hide() });
menuOptionMenu.appendTo("body");
}
var filterOptionDisabled = false;
var sourceNode = RED.nodes.node(sourceId);
if (sourceNode && sourceNode.type !== 'debug') {
filterOptionDisabled = true;
}
RED.menu.setDisabled('debug-message-menu-item-filter',filterOptionDisabled);
RED.menu.setDisabled('debug-message-menu-item-clear-filter',filterOptionDisabled);
var elementPos = button.offset();
menuOptionMenu.css({
top: elementPos.top+"px",
@@ -392,12 +403,19 @@ RED.debug = (function() {
$(msg).addClass('debug-message-hover');
if (o._source) {
config.messageMouseEnter(o._source.id);
if (o._source._alias) {
config.messageMouseEnter(o._source._alias);
}
}
};
msg.onmouseleave = function() {
$(msg).removeClass('debug-message-hover');
if (o._source) {
config.messageMouseLeave(o._source.id);
if (o._source._alias) {
config.messageMouseLeave(o._source._alias);
}
}
};
var name = sanitize(((o.name?o.name:o.id)||"").toString());

View File

@@ -6,35 +6,36 @@ module.exports = function(RED) {
var fs = require('fs');
var gpioCommand = __dirname+'/nrgpio';
var allOK = true;
try {
var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString();
if (cpuinfo.indexOf(": BCM") === -1) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); }
} catch(err) {
throw "Info : "+RED._("rpi-gpio.errors.ignorenode");
}
try {
fs.statSync("/usr/share/doc/python-rpi.gpio"); // test on Raspbian
// /usr/lib/python2.7/dist-packages/RPi/GPIO
} catch(err) {
if (cpuinfo.indexOf(": BCM") === -1) {
allOK = false;
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.ignorenode"));
}
try {
fs.statSync("/usr/lib/python2.7/site-packages/RPi/GPIO"); // test on Arch
}
catch(err) {
fs.statSync("/usr/share/doc/python-rpi.gpio"); // test on Raspbian
// /usr/lib/python2.7/dist-packages/RPi/GPIO
} catch(err) {
try {
fs.statSync("/usr/lib/python2.7/dist-packages/RPi/GPIO"); // test on Hypriot
}
catch(err) {
RED.log.warn(RED._("rpi-gpio.errors.libnotfound"));
throw "Warning : "+RED._("rpi-gpio.errors.libnotfound");
fs.statSync("/usr/lib/python2.7/site-packages/RPi/GPIO"); // test on Arch
} catch(err) {
try {
fs.statSync("/usr/lib/python2.7/dist-packages/RPi/GPIO"); // test on Hypriot
} catch(err) {
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.libnotfound"));
allOK = false;
}
}
}
}
if ( !(1 & parseInt((fs.statSync(gpioCommand).mode & parseInt("777", 8)).toString(8)[0]) )) {
RED.log.error(RED._("rpi-gpio.errors.needtobeexecutable",{command:gpioCommand}));
throw "Error : "+RED._("rpi-gpio.errors.mustbeexecutable");
if ( !(1 & parseInt((fs.statSync(gpioCommand).mode & parseInt("777", 8)).toString(8)[0]) )) {
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.needtobeexecutable",{command:gpioCommand}));
allOK = false;
}
} catch(err) {
allOK = false;
RED.log.warn("rpi-gpio : "+RED._("rpi-gpio.errors.ignorenode"));
}
// the magic to make python print stuff immediately
@@ -61,48 +62,62 @@ module.exports = function(RED) {
}
}
if (node.pin !== undefined) {
node.child = spawn(gpioCommand, ["in",node.pin,node.intype,node.debounce]);
node.running = true;
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
if (allOK === true) {
if (node.pin !== undefined) {
node.child = spawn(gpioCommand, ["in",node.pin,node.intype,node.debounce]);
node.running = true;
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
node.child.stdout.on('data', function (data) {
var d = data.toString().trim().split("\n");
for (var i = 0; i < d.length; i++) {
if (d[i] === '') { return; }
if (node.running && node.buttonState !== -1 && !isNaN(Number(d[i])) && node.buttonState !== d[i]) {
node.send({ topic:"pi/"+node.pin, payload:Number(d[i]) });
node.child.stdout.on('data', function (data) {
var d = data.toString().trim().split("\n");
for (var i = 0; i < d.length; i++) {
if (d[i] === '') { return; }
if (node.running && node.buttonState !== -1 && !isNaN(Number(d[i])) && node.buttonState !== d[i]) {
node.send({ topic:"pi/"+node.pin, payload:Number(d[i]) });
}
node.buttonState = d[i];
node.status({fill:"green",shape:"dot",text:d[i]});
if (RED.settings.verbose) { node.log("out: "+d[i]+" :"); }
}
node.buttonState = d[i];
node.status({fill:"green",shape:"dot",text:d[i]});
if (RED.settings.verbose) { node.log("out: "+d[i]+" :"); }
}
});
});
node.child.stderr.on('data', function (data) {
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
});
node.child.stderr.on('data', function (data) {
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
});
node.child.on('close', function (code) {
node.running = false;
node.child = null;
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
if (node.done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
node.done();
}
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
});
node.child.on('close', function (code) {
node.running = false;
node.child = null;
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
if (node.done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
node.done();
}
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
});
node.child.on('error', function (err) {
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
else { node.error(RED._("rpi-gpio.errors.error",{error:err.errno})) }
});
node.child.on('error', function (err) {
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
else { node.error(RED._("rpi-gpio.errors.error",{error:err.errno})) }
});
}
else {
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
}
}
else {
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
if (node.read === true) {
var val;
if (node.intype == "up") { val = 1; }
if (node.intype == "down") { val = 0; }
setTimeout(function(){
node.send({ topic:"pi/"+node.pin, payload:val });
node.status({fill:"grey",shape:"dot",text:RED._("rpi-gpio.status.na",{value:val})});
},250);
}
}
node.on("close", function(done) {
@@ -142,9 +157,9 @@ module.exports = function(RED) {
var limit = 1;
if (node.out === "pwm") { limit = 100; }
if ((out >= 0) && (out <= limit)) {
if (RED.settings.verbose) { node.log("out: "+msg.payload); }
if (RED.settings.verbose) { node.log("out: "+out); }
if (node.child !== null) {
node.child.stdin.write(msg.payload+"\n");
node.child.stdin.write(out+"\n");
node.status({fill:"green",shape:"dot",text:msg.payload.toString()});
}
else {
@@ -155,20 +170,83 @@ module.exports = function(RED) {
else { node.warn(RED._("rpi-gpio.errors.invalidinput")+": "+out); }
}
if (node.pin !== undefined) {
if (node.set && (node.out === "out")) {
node.child = spawn(gpioCommand, [node.out,node.pin,node.level]);
node.status({fill:"green",shape:"dot",text:node.level});
} else {
node.child = spawn(gpioCommand, [node.out,node.pin,node.freq]);
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
}
node.running = true;
if (allOK === true) {
if (node.pin !== undefined) {
if (node.set && (node.out === "out")) {
node.child = spawn(gpioCommand, [node.out,node.pin,node.level]);
node.status({fill:"green",shape:"dot",text:node.level});
} else {
node.child = spawn(gpioCommand, [node.out,node.pin,node.freq]);
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
}
node.running = true;
node.on("input", inputlistener);
node.on("input", inputlistener);
node.child.stdout.on('data', function (data) {
if (RED.settings.verbose) { node.log("out: "+data+" :"); }
});
node.child.stderr.on('data', function (data) {
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
});
node.child.on('close', function (code) {
node.child = null;
node.running = false;
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
if (node.done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
node.done();
}
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
});
node.child.on('error', function (err) {
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
});
}
else {
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
}
}
else {
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
node.on("input", function(msg){
node.status({fill:"grey",shape:"dot",text:RED._("rpi-gpio.status.na",{value:msg.payload.toString()})});
});
}
node.on("close", function(done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
delete pinsInUse[node.pin];
if (node.child != null) {
node.done = done;
node.child.stdin.write("close "+node.pin);
node.child.kill('SIGKILL');
}
else { done(); }
});
}
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
function PiMouseNode(n) {
RED.nodes.createNode(this,n);
this.butt = n.butt || 7;
var node = this;
if (allOK === true) {
node.child = spawn(gpioCommand+".py", ["mouse",node.butt]);
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
node.child.stdout.on('data', function (data) {
if (RED.settings.verbose) { node.log("out: "+data+" :"); }
data = Number(data);
if (data !== 0) { node.send({ topic:"pi/mouse", button:data, payload:1 }); }
else { node.send({ topic:"pi/mouse", button:data, payload:0 }); }
});
node.child.stderr.on('data', function (data) {
@@ -192,69 +270,19 @@ module.exports = function(RED) {
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
});
node.on("close", function(done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
if (node.child != null) {
node.done = done;
node.child.kill('SIGINT');
node.child = null;
}
else { done(); }
});
}
else {
node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin);
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
}
node.on("close", function(done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
delete pinsInUse[node.pin];
if (node.child != null) {
node.done = done;
node.child.stdin.write("close "+node.pin);
node.child.kill('SIGKILL');
}
else { done(); }
});
}
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
function PiMouseNode(n) {
RED.nodes.createNode(this,n);
this.butt = n.butt || 7;
var node = this;
node.child = spawn(gpioCommand+".py", ["mouse",node.butt]);
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
node.child.stdout.on('data', function (data) {
data = Number(data);
if (data === 1) { node.send({ topic:"pi/mouse", button:data, payload:1 }); }
else { node.send({ topic:"pi/mouse", button:data, payload:0 }); }
});
node.child.stderr.on('data', function (data) {
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
});
node.child.on('close', function (code) {
node.child = null;
node.running = false;
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
if (node.done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
node.done();
}
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
});
node.child.on('error', function (err) {
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
});
node.on("close", function(done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
if (node.child != null) {
node.done = done;
node.child.kill('SIGINT');
node.child = null;
}
else { done(); }
});
}
RED.nodes.registerType("rpi-mouse",PiMouseNode);
@@ -262,39 +290,40 @@ module.exports = function(RED) {
RED.nodes.createNode(this,n);
var node = this;
node.child = spawn(gpioCommand+".py", ["kbd","0"]);
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
if (allOK === true) {
node.child = spawn(gpioCommand+".py", ["kbd","0"]);
node.status({fill:"green",shape:"dot",text:"common.status.ok"});
node.child.stdout.on('data', function (data) {
var b = data.toString().trim().split(",");
var act = "up";
if (b[1] === "1") { act = "down"; }
if (b[1] === "2") { act = "repeat"; }
node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
});
node.child.stdout.on('data', function (data) {
var b = data.toString().trim().split(",");
var act = "up";
if (b[1] === "1") { act = "down"; }
if (b[1] === "2") { act = "repeat"; }
node.send({ topic:"pi/key", payload:Number(b[0]), action:act });
});
node.child.stderr.on('data', function (data) {
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
});
node.child.stderr.on('data', function (data) {
if (RED.settings.verbose) { node.log("err: "+data+" :"); }
});
node.child.on('close', function (code) {
node.running = false;
node.child = null;
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
if (node.done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
node.done();
}
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
});
node.child.on('close', function (code) {
node.running = false;
node.child = null;
if (RED.settings.verbose) { node.log(RED._("rpi-gpio.status.closed")); }
if (node.done) {
node.status({fill:"grey",shape:"ring",text:"rpi-gpio.status.closed"});
node.done();
}
else { node.status({fill:"red",shape:"ring",text:"rpi-gpio.status.stopped"}); }
});
node.child.on('error', function (err) {
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
});
node.child.on('error', function (err) {
if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); }
else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); }
else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); }
});
node.on("close", function(done) {
node.on("close", function(done) {
node.status({});
if (node.child != null) {
node.done = done;
@@ -303,24 +332,30 @@ module.exports = function(RED) {
}
else { done(); }
});
}
else {
node.status({fill:"grey",shape:"dot",text:"node-red:rpi-gpio.status.not-available"});
}
}
RED.nodes.registerType("rpi-keyboard",PiKeyboardNode);
var pitype = { type:"" };
exec(gpioCommand+" info", function(err,stdout,stderr) {
if (err) {
RED.log.info(RED._("rpi-gpio.errors.version"));
}
else {
try {
var info = JSON.parse( stdout.trim().replace(/\'/g,"\"") );
pitype.type = info["TYPE"];
if (allOK === true) {
exec(gpioCommand+" info", function(err,stdout,stderr) {
if (err) {
RED.log.info(RED._("rpi-gpio.errors.version"));
}
catch(e) {
RED.log.info(RED._("rpi-gpio.errors.sawpitype"),stdout.trim());
else {
try {
var info = JSON.parse( stdout.trim().replace(/\'/g,"\"") );
pitype.type = info["TYPE"];
}
catch(e) {
RED.log.info(RED._("rpi-gpio.errors.sawpitype"),stdout.trim());
}
}
}
});
});
}
RED.httpAdmin.get('/rpi-gpio/:id', RED.auth.needsPermission('rpi-gpio.read'), function(req,res) {
res.json(pitype);

View File

@@ -41,7 +41,7 @@
<dt>payload <span class="property-type">string | buffer</span></dt>
<dd>a string unless detected as a binary buffer.</dd>
<dt>topic <span class="property-type">string</span></dt>
<dd>the MQTT topic, uses / as a heirarchy separator.</dd>
<dd>the MQTT topic, uses / as a hierarchy separator.</dd>
<dt>qos <span class="property-type">number</span> </dt>
<dd>0, fire and forget - 1, at least once - 2, once and once only.</dd>
<dt>retain <span class="property-type">boolean</span></dt>
@@ -212,48 +212,84 @@
<input type="password" id="node-config-input-password">
</div>
</div>
<div id="mqtt-broker-tab-birth" style="display:none">
<div class="form-row">
<label for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
<div id="mqtt-broker-tab-messages" style="display:none">
<div id="mqtt-broker-section-birth">
<div class="palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.birth-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-birthRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-birthQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
</div>
</div>
<div class="form-row">
<label for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-birthQos" style="width:125px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
&nbsp;&nbsp;<i class="fa fa-history"></i>&nbsp;<span data-i18n="mqtt.retain"></span> &nbsp;<select id="node-config-input-birthRetain" style="width:125px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
<div id="mqtt-broker-section-close">
<div class="palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.close-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-closeTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closeTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.close-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-closeRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-closePayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closePayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-closeQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
</div>
</div>
<div class="form-row">
<label for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input type="text" id="node-config-input-birthPayload" data-i18n="[placeholder]common.label.payload">
</div>
</div>
<div id="mqtt-broker-tab-will" style="display:none">
<div class="form-row">
<label for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-config-input-willTopic" data-i18n="[placeholder]mqtt.placeholder.will-topic">
</div>
<div class="form-row">
<label for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-willQos" style="width:125px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
&nbsp;&nbsp;<i class="fa fa-history"></i>&nbsp;<span data-i18n="mqtt.retain"></span> &nbsp;<select id="node-config-input-willRetain" style="width:125px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input type="text" id="node-config-input-willPayload" data-i18n="[placeholder]common.label.payload">
<div id="mqtt-broker-section-will">
<div class="palette-header">
<i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.will-message"></span>
</div>
<div class="section-content" style="padding:10px 0 0 10px">
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.will-topic">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
<select id="node-config-input-willRetain" style="width:75px !important">
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<div class="form-row">
<label style="width: 100px !important;" for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
<input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
<label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-config-input-willQos" style="width:75px !important">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
</div>
</div>
</div>
</div>
@@ -269,6 +305,9 @@
<h4>Birth Message</h4>
<p>This is a message that will be published on the configured topic whenever the
connection is established.</p>
<h4>Close Message</h4>
<p>This is a message that will be published on the configured topic before the
connection is closed normally, either by re-deploying the node, or by shutting down.</p>
<h4>Will Message</h4>
<p>This is a message that will be published by the broker in the event the node
unexpectedly loses its connection.</p>
@@ -300,14 +339,18 @@
compatmode: { value: true},
keepalive: {value:60,validate:RED.validators.number()},
cleansession: {value: true},
willTopic: {value:""},
willQos: {value:"0"},
willRetain: {value:false},
willPayload: {value:""},
birthTopic: {value:""},
birthQos: {value:"0"},
birthRetain: {value:false},
birthPayload: {value:""}
birthPayload: {value:""},
closeTopic: {value:""},
closeQos: {value:"0"},
closeRetain: {value:false},
closePayload: {value:""},
willTopic: {value:""},
willQos: {value:"0"},
willRetain: {value:false},
willPayload: {value:""}
},
credentials: {
user: {type:"text"},
@@ -343,14 +386,39 @@
id: "mqtt-broker-tab-security",
label: this._("mqtt.tabs-label.security")
});
tabs.addTab({
id: "mqtt-broker-tab-birth",
label: this._("mqtt.tabs-label.birth")
});
tabs.addTab({
id: "mqtt-broker-tab-will",
label: this._("mqtt.tabs-label.will")
id: "mqtt-broker-tab-messages",
label: this._("mqtt.tabs-label.messages")
});
function setUpSection(sectionId, isExpanded) {
var birthMessageSection = $(sectionId);
var paletteHeader = birthMessageSection.find('.palette-header');
var twistie = paletteHeader.find('i');
var sectionContent = birthMessageSection.find('.section-content');
function toggleSection(expanded) {
twistie.toggleClass('expanded', expanded);
sectionContent.toggle(expanded);
}
paletteHeader.click(function(e) {
e.preventDefault();
var isExpanded = twistie.hasClass('expanded');
toggleSection(!isExpanded);
});
toggleSection(isExpanded);
}
// show first section if none are set so the user gets the idea
var showBirthSection = this.birthTopic !== ""
|| this.willTopic === ""
&& this.birthTopic === ""
&& this.closeTopic == "";
setUpSection('#mqtt-broker-section-birth', showBirthSection);
setUpSection('#mqtt-broker-section-close', this.closeTopic !== "");
setUpSection('#mqtt-broker-section-will', this.willTopic !== "");
setTimeout(function() { tabs.resize(); },0);
if (typeof this.cleansession === 'undefined') {
this.cleansession = true;
@@ -368,14 +436,18 @@
this.keepalive = 15;
$("#node-config-input-keepalive").val(this.keepalive);
}
if (typeof this.willQos === 'undefined') {
this.willQos = "0";
$("#node-config-input-willQos").val("0");
}
if (typeof this.birthQos === 'undefined') {
this.birthQos = "0";
$("#node-config-input-birthQos").val("0");
}
if (typeof this.closeQos === 'undefined') {
this.willQos = "0";
$("#node-config-input-willQos").val("0");
}
if (typeof this.willQos === 'undefined') {
this.willQos = "0";
$("#node-config-input-willQos").val("0");
}
function updateTLSOptions() {
if ($("#node-config-input-usetls").is(':checked')) {

View File

@@ -60,6 +60,15 @@ module.exports = function(RED) {
};
}
if (n.closeTopic) {
this.closeMessage = {
topic: n.closeTopic,
payload: n.closePayload || "",
qos: Number(n.closeQos||0),
retain: n.closeRetain=="true"|| n.closeRetain===true
};
}
if (this.credentials) {
this.username = this.credentials.user;
this.password = this.credentials.password;
@@ -314,6 +323,10 @@ module.exports = function(RED) {
this.on('close', function(done) {
this.closing = true;
if (this.connected) {
// Send close message
if (node.closeMessage) {
node.publish(node.closeMessage);
}
this.client.once('close', function() {
done();
});

View File

@@ -21,8 +21,6 @@ module.exports = function(RED) {
var cookieParser = require("cookie-parser");
var getBody = require('raw-body');
var cors = require('cors');
var jsonParser = bodyParser.json();
var urlencParser = bodyParser.urlencoded({extended:true});
var onHeaders = require('on-headers');
var typer = require('media-typer');
var isUtf8 = require('is-utf8');
@@ -212,6 +210,10 @@ module.exports = function(RED) {
}
}
var maxApiRequestSize = RED.settings.apiMaxLength || '5mb';
var jsonParser = bodyParser.json({limit:maxApiRequestSize});
var urlencParser = bodyParser.urlencoded({limit:maxApiRequestSize,extended:true});
var metricsHandler = function(req,res,next) { next(); }
if (this.metric()) {
metricsHandler = function(req, res, next) {

View File

@@ -86,8 +86,10 @@
<dt class="optional">payload</dt>
<dd>Sent as the body of the request.</dd>
<dt class="optional">rejectUnauthorized</dt>
<dd>If set to <code>true</code>, allows requests to be made to https sites that use
<dd>If set to <code>false</code>, allows requests to be made to https sites that use
self signed certificates.</dd>
<dt class="optional">followRedirects</dt>
<dd>If set to <code>false</code> prevent following Redirect (HTTP 301).<code>true</code> by default</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">

View File

@@ -16,9 +16,7 @@
module.exports = function(RED) {
"use strict";
var http = require("follow-redirects").http;
var https = require("follow-redirects").https;
var urllib = require("url");
var request = require("request");
var mustache = require("mustache");
var querystring = require("querystring");
var cookie = require("cookie");
@@ -78,9 +76,13 @@ module.exports = function(RED) {
if (msg.method && n.method && (n.method === "use")) {
method = msg.method.toUpperCase(); // use the msg parameter
}
var opts = urllib.parse(url);
var opts = {};
opts.url = url;
opts.timeout = node.reqTimeout;
opts.method = method;
opts.headers = {};
opts.encoding = null; // Force NodeJs to return a Buffer (instead of a string)
opts.maxRedirects = 21;
var ctSet = "Content-Type"; // set default camel case
var clSet = "Content-Length";
if (msg.headers) {
@@ -108,6 +110,9 @@ module.exports = function(RED) {
}
}
}
if (msg.hasOwnProperty('followRedirects')) {
opts.followRedirect = msg.followRedirects;
}
if (msg.cookies) {
var cookies = [];
if (opts.headers.hasOwnProperty('cookie')) {
@@ -131,7 +136,10 @@ module.exports = function(RED) {
}
}
if (this.credentials && this.credentials.user) {
opts.auth = this.credentials.user+":"+(this.credentials.password||"");
opts.auth = {
user: this.credentials.user,
pass: this.credentials.password||""
};
}
var payload = null;
@@ -157,6 +165,7 @@ module.exports = function(RED) {
opts.headers[clSet] = Buffer.byteLength(payload);
}
}
opts.body = payload;
}
// revert to user supplied Capitalisation if needed.
if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) {
@@ -167,7 +176,6 @@ module.exports = function(RED) {
opts.headers[clSet] = opts.headers['content-length'];
delete opts.headers['content-length'];
}
var urltotest = url;
var noproxy;
if (noprox) {
for (var i in noprox) {
@@ -177,22 +185,11 @@ module.exports = function(RED) {
if (prox && !noproxy) {
var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i);
if (match) {
//opts.protocol = "http:";
//opts.host = opts.hostname = match[2];
//opts.port = (match[3] != null ? match[3] : 80);
opts.headers['Host'] = opts.host;
var heads = opts.headers;
var path = opts.pathname = opts.href;
opts = urllib.parse(prox);
opts.path = opts.pathname = path;
opts.headers = heads;
opts.method = method;
urltotest = match[0];
if (opts.auth) {
opts.headers['Proxy-Authorization'] = "Basic "+new Buffer(opts.auth).toString('Base64')
}
opts.proxy = prox;
} else {
node.warn("Bad proxy url: "+ prox);
opts.proxy = null;
}
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
}
if (tlsNode) {
tlsNode.addTLSOptions(opts);
@@ -201,42 +198,37 @@ module.exports = function(RED) {
opts.rejectUnauthorized = msg.rejectUnauthorized;
}
}
var req = ((/^https/.test(urltotest))?https:http).request(opts,function(res) {
// Force NodeJs to return a Buffer (instead of a string)
// See https://github.com/nodejs/node/issues/6038
res.setEncoding(null);
delete res._readableState.decoder;
msg.statusCode = res.statusCode;
msg.headers = res.headers;
msg.responseUrl = res.responseUrl;
msg.payload = [];
if (msg.headers.hasOwnProperty('set-cookie')) {
msg.responseCookies = {};
msg.headers['set-cookie'].forEach(function(c) {
var parsedCookie = cookie.parse(c);
var eq_idx = c.indexOf('=');
var key = c.substr(0, eq_idx).trim()
parsedCookie.value = parsedCookie[key];
delete parsedCookie[key];
msg.responseCookies[key] = parsedCookie;
})
}
msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
// msg.url = url; // revert when warning above finally removed
res.on('data',function(chunk) {
if (!Buffer.isBuffer(chunk)) {
// if the 'setEncoding(null)' fix above stops working in
// a new Node.js release, throw a noisy error so we know
// about it.
throw new Error("HTTP Request data chunk not a Buffer");
request(opts, function(err, res, body) {
if(err){
if(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') {
node.error(RED._("common.notification.errors.no-response"), msg);
node.status({fill:"red", shape:"ring", text:"common.notification.errors.no-response"});
}else{
node.error(err,msg);
node.status({fill:"red", shape:"ring", text:err.code});
}
msg.payload.push(chunk);
});
res.on('end',function() {
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code;
node.send(msg);
}else{
msg.statusCode = res.statusCode;
msg.headers = res.headers;
msg.responseUrl = res.request.uri.href;
msg.payload = body;
if (msg.headers.hasOwnProperty('set-cookie')) {
msg.responseCookies = {};
msg.headers['set-cookie'].forEach(function(c) {
var parsedCookie = cookie.parse(c);
var eq_idx = c.indexOf('=');
var key = c.substr(0, eq_idx).trim()
parsedCookie.value = parsedCookie[key];
delete parsedCookie[key];
msg.responseCookies[key] = parsedCookie;
});
}
msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
// msg.url = url; // revert when warning above finally removed
if (node.metric()) {
// Calculate request time
var diff = process.hrtime(preRequestTimestamp);
@@ -248,44 +240,19 @@ module.exports = function(RED) {
}
}
// Check that msg.payload is an array - if the req error
// handler has been called, it will have been set to a string
// and the error already handled - so no further action should
// be taken. #1344
if (Array.isArray(msg.payload)) {
// Convert the payload to the required return type
msg.payload = Buffer.concat(msg.payload); // bin
if (node.ret !== "bin") {
msg.payload = msg.payload.toString('utf8'); // txt
// Convert the payload to the required return type
if (node.ret !== "bin") {
msg.payload = msg.payload.toString('utf8'); // txt
if (node.ret === "obj") {
try { msg.payload = JSON.parse(msg.payload); } // obj
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
}
if (node.ret === "obj") {
try { msg.payload = JSON.parse(msg.payload); } // obj
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
}
node.status({});
node.send(msg);
}
});
node.status({});
node.send(msg);
}
});
req.setTimeout(node.reqTimeout, function() {
node.error(RED._("common.notification.errors.no-response"),msg);
setTimeout(function() {
node.status({fill:"red",shape:"ring",text:"common.notification.errors.no-response"});
},10);
req.abort();
});
req.on('error',function(err) {
node.error(err,msg);
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code;
node.status({fill:"red",shape:"ring",text:err.code});
node.send(msg);
});
if (payload) {
req.write(payload);
}
req.end();
});
this.on("close",function() {

View File

@@ -59,7 +59,7 @@
outputs:1,
icon: "watch.png",
label: function() {
return this.name||this.files;
return this.name||this.files||this._("watch.watch");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -130,6 +130,8 @@ module.exports = function(RED) {
socket.setKeepAlive(true,120000);
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var id = (1+Math.random()*4294967295).toString(16);
var fromi;
var fromp;
connectionPool[id] = socket;
count++;
node.status({text:RED._("tcpin.status.connections",{count:count})});
@@ -155,18 +157,21 @@ module.exports = function(RED) {
msg._session = {type:"tcp",id:id};
node.send(msg);
}
} else {
}
else {
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
}
fromi = socket.remoteAddress;
fromp = socket.remotePort;
}
});
socket.on('end', function() {
if (!node.stream || (node.datatype === "utf8" && node.newline !== "")) {
if (buffer.length > 0) {
var msg = {topic:node.topic, payload:buffer, ip:socket.remoteAddress, port:socket.remotePort};
var msg = {topic:node.topic, payload:buffer, ip:fromi, port:fromp};
msg._session = {type:"tcp",id:id};
node.send(msg);
}

View File

@@ -29,7 +29,7 @@
</div>
<div class="form-row node-input-iface">
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.label.interfaceprompt">
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.placeholder.interfaceprompt">
</div>
<div class="form-row">
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.onport"></span></label>

View File

@@ -16,6 +16,7 @@
module.exports = function(RED) {
"use strict";
var os = require('os');
var dgram = require('dgram');
var udpInputPortsInUse = {};
@@ -30,6 +31,29 @@ module.exports = function(RED) {
this.ipv = n.ipv || "udp4";
var node = this;
if (node.iface && node.iface.indexOf(".") === -1) {
try {
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
if (node.ipv === "udp4") {
node.iface = (os.networkInterfaces())[node.iface][1].address;
} else {
node.iface = (os.networkInterfaces())[node.iface][0].address;
}
}
else {
if (node.ipv === "udp4") {
node.iface = (os.networkInterfaces())[node.iface][0].address;
} else {
node.iface = (os.networkInterfaces())[node.iface][1].address;
}
}
}
catch(e) {
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
node.iface = null;
}
}
var opts = {type:node.ipv, reuseAddr:true};
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
var server;
@@ -39,7 +63,7 @@ module.exports = function(RED) {
udpInputPortsInUse[this.port] = server;
}
else {
node.warn(RED._("udp.errors.alreadyused",node.port));
node.warn(RED._("udp.errors.alreadyused",{port:node.port}));
server = udpInputPortsInUse[this.port]; // re-use existing
}
@@ -121,12 +145,38 @@ module.exports = function(RED) {
this.ipv = n.ipv || "udp4";
var node = this;
if (node.iface && node.iface.indexOf(".") === -1) {
try {
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
if (node.ipv === "udp4") {
node.iface = (os.networkInterfaces())[node.iface][1].address;
} else {
node.iface = (os.networkInterfaces())[node.iface][0].address;
}
}
else {
if (node.ipv === "udp4") {
node.iface = (os.networkInterfaces())[node.iface][0].address;
} else {
node.iface = (os.networkInterfaces())[node.iface][1].address;
}
}
}
catch(e) {
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
node.iface = null;
}
}
var opts = {type:node.ipv, reuseAddr:true};
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
var sock;
if (udpInputPortsInUse[this.outport || this.port]) {
sock = udpInputPortsInUse[this.outport || this.port];
var p = this.port;
if (node.multicast != "false") { p = this.outport||"0"; }
if (udpInputPortsInUse[p]) {
sock = udpInputPortsInUse[p];
node.log(RED._("udp.status.re-use",{outport:node.outport,host:node.addr,port:node.port}));
}
else {
sock = dgram.createSocket(opts); // default to udp4
@@ -136,36 +186,35 @@ module.exports = function(RED) {
// prevent it going to the global error handler and shutting node-red
// down.
});
udpInputPortsInUse[this.outport || this.port] = sock;
}
udpInputPortsInUse[p] = sock;
if (node.multicast != "false") {
if (node.outport === "") { node.outport = node.port; }
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
sock.setBroadcast(true); // turn on broadcast
if (node.multicast == "multi") {
try {
sock.setMulticastTTL(128);
sock.addMembership(node.addr,node.iface); // Add to the multicast group
node.log(RED._("udp.status.mc-ready",{outport:node.outport,host:node.addr,port:node.port}));
} catch (e) {
if (e.errno == "EINVAL") {
node.error(RED._("udp.errors.bad-mcaddress"));
} else if (e.errno == "ENODEV") {
node.error(RED._("udp.errors.interface"));
} else {
node.error(RED._("udp.errors.error",{error:e.errno}));
if (node.multicast != "false") {
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
sock.setBroadcast(true); // turn on broadcast
if (node.multicast == "multi") {
try {
sock.setMulticastTTL(128);
sock.addMembership(node.addr,node.iface); // Add to the multicast group
node.log(RED._("udp.status.mc-ready",{iface:node.iface,outport:node.outport,host:node.addr,port:node.port}));
} catch (e) {
if (e.errno == "EINVAL") {
node.error(RED._("udp.errors.bad-mcaddress"));
} else if (e.errno == "ENODEV") {
node.error(RED._("udp.errors.interface"));
} else {
node.error(RED._("udp.errors.error",{error:e.errno}));
}
}
} else {
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
}
} else {
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
}
});
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
sock.bind(node.outport);
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
} else {
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
});
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
sock.bind(node.outport);
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
} else {
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
}
}
node.on("input", function(msg) {
@@ -198,8 +247,8 @@ module.exports = function(RED) {
});
node.on("close", function() {
if (udpInputPortsInUse.hasOwnProperty(node.outport || node.port)) {
delete udpInputPortsInUse[node.outport || node.port];
if (udpInputPortsInUse.hasOwnProperty(p)) {
delete udpInputPortsInUse[p];
}
try {
sock.close();

View File

@@ -6,7 +6,8 @@
"name": "Name",
"username": "Username",
"password": "Password",
"property": "Property"
"property": "Property",
"language": "Language"
},
"status": {
"connected": "connected",
@@ -70,8 +71,8 @@
}
},
"catch": {
"catch": "catch all",
"catchNodes": "catch (__number__)",
"catch": "catch: all",
"catchNodes": "catch: __number__",
"label": {
"source": "Catch errors from",
"node": "node",
@@ -86,8 +87,8 @@
}
},
"status": {
"status": "status (all)",
"statusNodes": "status (__number__)",
"status": "status: all",
"statusNodes": "status: __number__",
"label": {
"source": "Report status from",
"node": "node",
@@ -166,6 +167,8 @@
}
},
"exec": {
"exec": "exec",
"spawn": "spawn",
"label": {
"command": "Command",
"append": "Append",
@@ -184,6 +187,7 @@
"oldrc": "Use old style output (compatibility mode)"
},
"function": {
"function": "",
"label": {
"function": "Function",
"outputs": "Outputs"
@@ -195,6 +199,7 @@
"tip": "See the Info tab for help writing functions."
},
"template": {
"template": "template",
"label": {
"template": "Template",
"property": "Set property",
@@ -301,6 +306,7 @@
}
},
"comment": {
"comment": "comment",
"label": {
"title": "Title",
"body": "Body"
@@ -318,6 +324,7 @@
"broker": "Server",
"example": "e.g. localhost",
"qos": "QoS",
"retain": "Retain",
"clientid": "Client ID",
"port": "Port",
"keepalive": "Keep alive time (s)",
@@ -327,17 +334,22 @@
"verify-server-cert":"Verify server certificate",
"compatmode": "Use legacy MQTT 3.1 support"
},
"sections-label":{
"birth-message": "Message sent on connection (birth message)",
"will-message":"Message sent on an unexpected disconnection (will message)",
"close-message":"Message sent before disconnecting (close message)"
},
"tabs-label": {
"connection": "Connection",
"security": "Security",
"will": "Will Message",
"birth": "Birth Message"
"messages": "Messages"
},
"placeholder": {
"clientid": "Leave blank for auto generated",
"clientid-nonclean":"Must be set for non-clean sessions",
"will-topic": "Leave blank to disable will message",
"birth-topic": "Leave blank to disable birth message"
"birth-topic": "Leave blank to disable birth message",
"close-topic": "Leave blank to disable close message"
},
"state": {
"connected": "Connected to broker: __broker__",
@@ -416,6 +428,7 @@
}
},
"watch": {
"watch": "watch",
"label": {
"files": "File(s)",
"recursive": "Watch sub-directories recursively"
@@ -489,15 +502,15 @@
"using": "using",
"output": "Output",
"group": "Group",
"interface": "Local IP",
"interfaceprompt": "(optional) local ip address to bind to",
"interface": "Local IF",
"send": "Send a",
"toport": "to port",
"address": "Address",
"decode-base64": "Decode Base64 encoded payload?"
},
"placeholder": {
"interface": "(optional) ip address of eth0",
"interface": "(optional) local interface or address to bind to",
"interfaceprompt": "(optional) local interface or address to bind to",
"address": "destination ip"
},
"udpmsgs": "udp messages",
@@ -525,10 +538,11 @@
"mc-group": "udp multicast group __group__",
"listener-stopped": "udp listener stopped",
"output-stopped": "udp output stopped",
"mc-ready": "udp multicast ready: __outport__ -> __host__:__port__",
"mc-ready": "udp multicast ready: __iface__:__outport__ -> __host__:__port__",
"bc-ready": "udp broadcast ready: __outport__ -> __host__:__port__",
"ready": "udp ready: __outport__ -> __host__:__port__",
"ready-nolocal": "udp ready: __host__:__port__"
"ready-nolocal": "udp ready: __host__:__port__",
"re-use": "udp re-use socket: __outport__ -> __host__:__port__"
},
"errors": {
"access-error": "UDP access error, you may need root access for ports below 1024",
@@ -538,10 +552,12 @@
"ip-notset": "udp: ip address not set",
"port-notset": "udp: port not set",
"port-invalid": "udp: port number not valid",
"alreadyused": "udp: port already in use"
"alreadyused": "udp: port __port__ already in use",
"ifnotfound": "udp: interface __iface__ not found"
}
},
"switch": {
"switch": "switch",
"label": {
"property": "Property",
"rule": "rule",
@@ -559,6 +575,7 @@
"false":"is false",
"null":"is null",
"nnull":"is not null",
"istype":"is of type",
"head":"head",
"tail":"tail",
"index":"index between",
@@ -597,6 +614,7 @@
}
},
"range": {
"range": "range",
"label": {
"action": "Action",
"inputrange": "Map the input range",
@@ -663,7 +681,8 @@
"html": {
"label": {
"select": "Selector",
"output": "Output"
"output": "Output",
"in": "in"
},
"output": {
"html": "the html content of the elements",
@@ -763,11 +782,13 @@
"status": {
"stopped": "stopped",
"closed": "closed",
"not-running": "not running"
"not-running": "not running",
"not-available": "not available",
"na": "N/A : __value__"
},
"errors": {
"ignorenode": "Ignoring Raspberry Pi specific node",
"version": "Version command failed",
"ignorenode": "Raspberry Pi specific node set inactive",
"version": "Failed to get version from Pi",
"sawpitype": "Saw Pi Type",
"libnotfound": "Cannot find Pi RPi.GPIO python library",
"alreadyset": "GPIO pin __pin__ already set as type: __type__",
@@ -782,6 +803,7 @@
}
},
"tail": {
"tail": "tail",
"label": {
"filename": "Filename",
"type": "File type",
@@ -835,6 +857,7 @@
"tip": "Tip: The filename should be an absolute path, otherwise it will be relative to the working directory of the Node-RED process."
},
"split": {
"split": "split",
"intro":"Split <code>msg.payload</code> based on type:",
"object":"<b>Object</b>",
"objectSend":"Send a message for each key/value pair",
@@ -846,6 +869,7 @@
"addname":" Copy key to "
},
"join":{
"join": "join",
"mode":{
"mode":"Mode",
"auto":"automatic",
@@ -892,6 +916,7 @@
}
},
"sort" : {
"sort": "sort",
"target" : "Sort",
"seq" : "message sequence",
"key" : "Key",
@@ -905,6 +930,7 @@
"clear" : "clear pending message in sort node"
},
"batch" : {
"batch": "batch",
"mode": {
"label" : "Mode",
"num-msgs" : "Group by number of messages",

View File

@@ -0,0 +1,35 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="sentiment">
<p>指定したプロパティ(デフォルトは<code>payload</code>)<code>sentiment</code></p>
<h3>出力</h3>
<dl class="message-properties">
<dt>sentiment <span class="property-type">オブジェクト</span></dt>
<dd>AFINN-111による感情分析の結果</dd>
<dt>sentiment.score <span class="property-type">数値</span></dt>
<dd>感情分析スコア</dd>
</dl>
<h3>入力</h3>
<dl class="message-properties">
<dt>overrides <span class="property-type">オブジェクト</span></dt>
<dd>単語スコアの上書きをするためのオブジェクト - <code>{ word:score,... }</code></dd>
</dl>
<h3>詳細</h3>
<p>ゼロ以上のスコアはポジティブゼロ以下はネガティブを意味します</p>
<p>スコアの範囲は通常-5から+5ですがより大きかったり小さかったりすることもあります</p>
<p>詳細は<a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a></p>
</script>

View File

@@ -0,0 +1,34 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="inject">
<p>手動もしくは一定間隔でメッセージをフローに注入しますメッセージのペイロードには文字列JavaScriptオブジェクト現在の時刻などさまざまな値を指定できます</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">各種</span></dt>
<dd>指定したメッセージペイロード</dd>
<dt class="optional">topic <span class="property-type">文字列</span></dt>
<dd>任意で指定可能なプロパティ</dd>
</dl>
<h3>詳細</h3>
<p>injectードを用いることで指定したペイロード値を用いてフローを開始できますデフォルトのペイロード値は現在時刻のタイムスタンプを1970年1月1日からの経過ミリ秒で表現した値です</p>
<p>文字列数値論理値JavaScriptオブジェクトフロー/グローバルコンテキストの値などの送出も可能です</p>
<p> デフォルト設定ではエディタ内に表示されるボタンをクリックすることでノードを手動で起動できます指定間隔もしくはスケジュールに従ってメッセージを送出するように設定することも可能です</p>
<p>またフロー開始の際に一度だけメッセージを送出させることもできます</p>
<p><i>時間間隔</i>596(24)</p>
<p><b></b>:「<i>指定した時間間隔、日時</i><i>指定した日時</i>」オプションは標準的なcronシステムを内部で利用します。したがって「20分」という指定は、その時点から20分後ではなく、毎時きっかり、20分、40分を意味します。現時刻から20分毎を指定するには「<i>指定した時間間隔</i>オプションを用います</p>
<p><b></b>: function使</p>
</script>

View File

@@ -0,0 +1,36 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="catch">
<p>同じタブ内のノードが送出したエラーをキャッチします</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>error.message <span class="property-type">文字列</span></dt>
<dd>エラーメッセージ</dd>
<dt>error.source.id <span class="property-type">文字列</span></dt>
<dd>エラーを送出したードのID</dd>
<dt>error.source.type <span class="property-type">文字列</span></dt>
<dd>エラーを送出したノードの種別</dd>
<dt>error.source.name <span class="property-type">文字列</span></dt>
<dd>エラーを送出したノードの名称(設定されている場合)</dd>
</dl>
<h3>詳細</h3>
<p>メッセージの処理中にノードがエラーを送出した場合フロー実行は基本的に停止しますこのノードを使うとエラーをキャッチして対応するフローで処理させることができます</p>
<p>デフォルトでは同じタブの全てのノードが送出したエラーをキャッチします特定のノードをキャッチ対象とすることも可能です</p>
<p>エラー発生時にはマッチするすべてのcatchードがメッセージを受け取ります</p>
<p>サブフロー内でエラーが送出された場合まずサブフロー内のcatchードで処理されます対応するノードが存在しない場合にはそのサブフローが配置されたタブにエラーを伝播して処理します</p>
<p>メッセージが<code>error</code><code>error</code><code>_error</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="status">
<p>同じタブ内のノードのステータスメッセージを取得します</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>status.text <span class="property-type">文字列</span></dt>
<dd>ステータス文字列</dd>
<dt>status.source.type <span class="property-type">文字列</span></dt>
<dd>ステータスを表示したノードの種別</dd>
<dt>status.source.id <span class="property-type">文字列</span></dt>
<dd>ステータスを表示したードのID</dd>
<dt>status.source.name <span class="property-type">文字列</span></dt>
<dd>ステータスを表示したノードの名称(設定されている場合)</dd>
</dl>
<h3>詳細</h3>
<p>このノードは<code>payload</code></p>
<p>デフォルトでは同じワークスペースタブ内の全てのノードのステータスを取得します特定のノードのステータスを取得対象とすることも可能です</p>
</script>

View File

@@ -0,0 +1,26 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="debug">
<p>サイドバーのデバッグタブに選択したメッセージプロパティの値を表示します設定によりランタイムログへの出力も可能ですデフォルトの表示対象は<code>msg.payload</code></p>
<h3>詳細</h3>
<p>デバッグサイドバーは受け取ったメッセージの階層構造を表示する機能を備えますこの機能によりメッセージの構造を容易に理解できます</p>
<p>JavaScriptオブジェクトと配列は必要に応じて折り畳んだり展開したりできますバッファオブジェクトを生データとして表示したり表現可能な場合に文字列として表示することも可能です</p>
<p>メッセージを受信した時刻送信ノードメッセージの型に関する情報をデバッグサイドバーに表示されたメッセージに付随して表示します送信元ードのIDを選択するとワークスペース内の対応ノードを確認できます</p>
<p>出力の有効/無効はノード上のボタンで切り替えられますフロー上で未使用のdebugードは無効化するか削除することを推奨します</p>
<p>全てのメッセージをランタイムログに送付もしくは(32文字の)短いデータをdebugードの下のステータステキストに表示することも可能です</p>
</script>

View File

@@ -0,0 +1,31 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="link in">
<p>フロー間に仮想的なリンクを作成します</p>
<h3>詳細</h3>
<p>任意のタブ上に存在する<code>link out</code></p>
<p>linkード間のリンクはlinkードを選択した場合にのみ表示されます他のタブへのリンクがある場合には仮想的なノードを表示しますこの仮想的ノードをクリックすると対応するタブに移動できます</p>
<p><b>: </b></p>
</script>
<script type="text/x-red" data-help-name="link out">
<p>フロー間に仮想的なリンクを作成します</p>
<h3>詳細</h3>
<p>任意のタブ上に存在する<code>link in</code></p>
<p>linkード間のリンクはlinkードを選択した場合にのみ表示されます他のタブへのリンクがある場合には仮想的なノードを表示しますこの仮想的ノードをクリックすると対応するタブに移動できます</p>
<p><b>: </b></p>
</script>

View File

@@ -0,0 +1,75 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="exec">
<p>システムのコマンドを実行し出力を返します</p>
<p>コマンドの完了まで待つかコマンドが出力を行う毎にメッセージを出力するかを指定できます</p>
<p>実行対象のコマンドはノードの設定もしくは受信メッセージで指定します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">payload <span class="property-type">文字列</span></dt>
<dd>実行コマンドの最後に追加するよう設定できます</dd>
<dt class="optional">kill <span class="property-type">文字列</span></dt>
<dd>execードのプロセスに対して送るシグナルの種別を指定します</dd>
<dt class="optional">pid <span class="property-type">数値|文字列</span></dt>
<dd>シグナル送信対象のexecードのプロセスID</dd>
</dl>
<h3>出力</h3>
<ol class="node-ports">
<li>標準出力(stdout)
<dl class="message-properties">
<dt>payload <span class="property-type">文字列</span></dt>
<dd>コマンドの標準出力</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">オブジェクト</span></dt>
<dd>返却コードオブジェクト(3番目の端子でも受取り可能)のコピー(execモードのみ)</dd>
</dl>
</li>
<li>標準エラー出力(stderr)
<dl class="message-properties">
<dt>payload <span class="property-type">文字列</span></dt>
<dd>コマンドの標準エラー出力</dd>
</dl>
<dl class="message-properties">
<dt>rc <span class="property-type">オブジェクト</span></dt>
<dd>返却コードオブジェクト(3番目の端子でも受取り可能)のコピー(execモードのみ)</dd>
</dl>
</li>
<li>返却コード(return code)
<dl class="message-properties">
<dt>payload <span class="property-type">オブジェクト</span></dt>
<dd>リターンコード<code>message</code><code>signal</code>(<code>message</code><code>signal</code>)</dd>
</dl>
</li>
</ol>
<h3>詳細</h3>
<p>デフォルトでは<code>exec</code><code>{ code: 0 }</code></p>
<p><code>spawn</code>使
標準出力および標準エラー出力へ出力を返すようにすることもできますこの場合通常1行毎に値を返しますコマンドの実行が完了すると3番目の端子にオブジェクトを出力します例えばコマンドの実行が成功した場合には<code>{ code: 0 }</code></p>
<p>エラー発生時には3番目の端子の<code>msg.payload</code><code>message</code><code>signal</code></p>
<p>実行対象のコマンドはノード設定で定義します<code>msg.payload</code></p>
<p>コマンドもしくはパラメータが空白を含む場合には引用符で囲みます- <code>"This is a single parameter"</code></p>
<p>返却する<code>payload</code>は通常<i>文字列</i>ですがUTF8文字以外が存在すると<i>バッファ</i></p>
<p>ノードが実行中の場合ステータスアイコンとPIDを表示しますこの状態変化は<code>status</code></p>
<h4>プロセスの停止</h4>
<p><code>msg.kill</code><code>msg.kill</code><code>SIGINT</code><code>SIGQUIT</code><code>SIGHUP</code><code>SIGTERM</code></p>
<p>ードが1つ以上のプロセスを実行している場合<code>msg.pid</code>PID</p>
<p><code>タイムアウト</code></p>
<p>ヒント: Pythonアプリケーションを実行する場合<code>-u</code></p>
</script>

View File

@@ -0,0 +1,43 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="function">
<p>受信メッセージに対して処理を行うJavaScriptコード(関数の本体)を定義します</p>
<p>入力メッセージは<code>msg</code>JavaScript</p>
<p><code>msg</code><code>msg.payload</code></p>
<p>通常コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します何も返却しない場合にはフロー実行を停止します</p>
<h3>詳細</h3>
<p>コードの書き方の詳細については<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a></p>
<h4>メッセージの送信</h4>
<p>フロー内の次ノードにメッセージを渡すためにはメッセージを返却するか<code>node.send(messages)</code></p>
<p>返却/sendの対象は次のとおりです:</p>
<ul>
<li>単一メッセージオブジェクト - 最初の出力に接続されたノードに渡されます</li>
<li>メッセージオブジェクトの配列 - 対応する出力に接続されたノードに渡されます</li>
</ul>
<p>配列要素が配列の場合には複数のメッセージを対応する出力に送出します</p>
<p>返却方法が単一値か配列要素かにかかわらず返却値がnullの場合メッセージの送出は行いません</p>
<h4>ログ出力とエラー処理</h4>
<p>ログ情報の出力エラー出力を行うには以下の関数を用います:</p>
<ul>
<li><code>node.log("ログメッセージ")</code></li>
<li><code>node.warn("警告")</code></li>
<li><code>node.error("エラー")</code></li>
</ul>
</p>
<p>catchードを用いてエラー処理が可能ですcatchードで処理させるためには<code>msg</code><code>node.error</code>:</p>
<pre>node.error("エラー",msg);</pre>
</script>

View File

@@ -0,0 +1,47 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="template">
<p>テンプレートに基づいてプロパティを設定します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">オブジェクト</span></dt>
<dd>テンプレートを生成するための情報を含むメッセージオブジェクト</dd>
<dt class="optional">template <span class="property-type">文字列</span></dt>
<dd><code>msg.payload</code></dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>msg <span class="property-type">オブジェクト</span></dt>
<dd>指定したテンプレートと入力メッセージのプロパティから生成した値を設定したメッセージ</dd>
</dl>
<h3>詳細</h3>
<p>このノードは<i><a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache</a></i>形式をデフォルトで利用しますが使用しないようにすることもできます</p>
<p>例えば
<pre>こんにちは{{payload.name}}さん今日は{{date}}です</pre>
<p>というテンプレートに対して
<pre>{
date: "月曜日"
payload: {
name: "山田",
}
}</pre>
<p>というメッセージを受信した場合</p>
<pre>こんにちは山田さん今日は月曜日です</pre>
<p>というプロパティが生成されます</p>
<p>フローコンテキストもしくはグローバルコンテキストのプロパティ値を使うこともできますそれぞれ<code>{{flow.名前}}</code><code>{{global.}}</code></p>
<p><b>: </b>デフォルトでは、<i>mustache</i>形式は置換対象のHTML要素をエスケープしますこれを抑止するには<code>{{{三重}}}</code>使</p>
</script>

View File

@@ -0,0 +1,30 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="delay">
<p>ノードを通過するメッセージを遅延もしくは流量を制限します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">数値</span></dt>
<dd>メッセージの遅延時間をミリ秒単位で設定しますこれはノードの設定でデフォルトの遅延時間を上書きできるようノードを設定した場合にのみ適用します</dd>
<dt class="optional">reset</dt>
<dd>受信メッセージでこのプロパティを任意の値に設定するとノードが保持する全ての未送信メッセージをクリアします</dd>
</dl>
<h3>詳細</h3>
<p>メッセージを遅延させるように設定する場合遅延時間は固定値範囲内の乱数値メッセージ毎の動的な指定値のいずれかを指定できます</p>
<p>流量制御する場合メッセージは指定した時間間隔内に分散して送信しますキューに残っているメッセージ数はノードのステータスに表示されます受け取った中間メッセージを破棄することも可能です</p>
<p>流量制御は全てのメッセージに適用することも<code>msg.topic</code></p>
</script>

View File

@@ -0,0 +1,33 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="trigger">
<p>メッセージの受信すると別のメッセージの送信を行います延長もしくは初期化が指定されていない場合には2つ目のメッセージを送信することもできます</p>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">reset</dt>
<dd>このプロパティを持つメッセージを受け取ると仕掛かり中の待機や繰り返しをクリアしメッセージの送信は行いません</dd>
</dl>
<h3>詳細</h3>
<p>フロー内でタイムアウトを作成するのに利用しますメッセージを受け取るとデフォルトでは<code>payload</code><code>1</code>250ms<code>payload</code><code>0</code>2Raspberry PIGPIOLED</p>
<p>各送信メッセージのペイロードはさまざまな種類の値に設定できます再送信データなしとすることも可能です例えば再送信データを<i>なし</i>trigger</p>
<p>ペイロードに<i>文字列</i>mustache</p>
<p><code>reset</code><code>payload</code></p>
<p>受信メッセージでリセットするまで一定間隔でメッセージを再送するように指定することもできます</p>
<p><code>msg.topic</code></p>
</script>

View File

@@ -0,0 +1,21 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="comment">
<p>フローにコメントを記述するために利用します</p>
<h3>詳細</h3>
<p>編集パネルはMarkdown形式を記入可能です入力したテキストは情報サイドパネルに表示されます</p>
</script>

View File

@@ -0,0 +1,24 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="unknown">
<p>インストールされたNode-REDが認識できない種別のードです</p>
<h3>詳細</h3>
<p><i>この種別のノードをデプロイした場合設定は保持されますが足りないノードをインストールするまでフローを開始することはできません</i></p>
<p><code>メニュー - パレットの管理</code>使<b>npm install &lt;&gt;</b>Node-RED</p>
<p>この種別のノードがインストール済みであるが依存ライブラリがインストールされていないケースもありますNode-REDの起動ログを参照して不足ードに関連したエラーメッセージをチェックすると良いでしょう</p>
<p>それでも解決しない場合フローの作者に依頼して不足ノードのコピーを入手してください</p>
</script>

View File

@@ -0,0 +1,71 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="rpi-gpio in">
<p>Raspberry Piの入力ード入力ピンの状態に応じて0 または 1 の値を持つ<code>msg.payload</code></p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd>ペイロードには0 または 1 が設定されます</dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd>トピックには<code>pi/{ピン番号}</code></dd>
</dl>
<h3>詳細</h3>
<p>入力のプルアップ抵抗またはプルダウン抵抗を有効にすることもできます</p>
<p>動作にはRPi.GPIO pythonライブラリのバージョン 0.5.10 (またはそれ以上)が必要です</p>
</script>
<script type="text/x-red" data-help-name="rpi-gpio out">
<p>Raspberry Piの出力ードデジタルモードまたはPWMモードで利用できます
<h3>入力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値 | 文字列 | 真偽値</span></dt>
</dl>
<h3>詳細</h3>
<p>デジタルモード - <code>msg.payload</code> 0 1 ( true false ) </p>
<p>デプロイ時にピンの初期値として 0 または 1 を設定することもできます</p>
<p>PWMモード - 入力値に 0 から 100 の数値を指定でき小数値の指定も可能です</p>
<p>サーボの制御にPWMモードが利用でき入力に小数値も含む 10 から 20 の値が指定可能です
PWMを行うハードウェアを利用していることからPWMモードの指定にはGPIO2ピンが最も適しています
より良くサーボの制御を行いたい場合はnode-red-node-pi-gpiod ノードの利用も検討してください</p>
<p>動作にはRPi.GPIO pythonライブラリのバージョン 0.5.10 (またはそれ以上)が必要です</p>
</script>
<script type="text/x-red" data-help-name="rpi-mouse">
<p>Raspberry Pi のマウスボタンノードUSBマウスが必要です</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd>選択されたマウスのボタンが押されたまたは離された場合に 1 または 0 が設定されます</dd>
<dt>button <span class="property-type">数値</span></dt>
<dd>真ん中のボタンに応じて 1, 2, 4 が設定されボタンあるいはボタンの組み合わせに応じた処理ができます</dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd><code>pi/mouse</code></dd>
</dl>
</script>
<script type="text/x-red" data-help-name="rpi-keyboard">
<p>Raspberry Pi のキーボードを制御するノードUSBキーボードが必要です</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd>キーコードを含みます</dd>
<dt>action <span class="property-type">文字列</span></dt>
<dd>"up", "down", または "repeat" が設定されます</dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd><code>pi/key</code></dd>
</dl>
</script>

View File

@@ -0,0 +1,19 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="tls-config">
<p>TLS接続のためのオプション設定</p>
</script>

View File

@@ -0,0 +1,72 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="mqtt in">
<p>MQTTブローカに接続し指定したトピックのメッセージをサブスクライブ(購読)します</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">文字列 | バッファ</span></dt>
<dd>バイナリバッファでない場合は文字列</dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd>MQTTのトピック/を階層の区切りに使用する</dd>
<dt>qos <span class="property-type">数値</span> </dt>
<dd>0: 最大1度到着, 1: 一度以上到着, 2: 1度のみ到着</dd>
<dt>retain <span class="property-type">真偽値</span></dt>
<dd>真の場合メッセージを保持メッセージが古い値の場合があります</dd>
</dl>
<h3>詳細</h3>
<p>購読トピックにはMQTTのワイルドカード(+: 1レベル, #: 複数レベル)を含めることができます</p>
<p>このノードの利用のためにはMQTTブローカへの接続設定が必要ですこの設定は鉛筆アイコンをクリックすることで行えます</p>
<p>MQTT(inおよびout)ノードはブローカへの接続設定を必要に応じて共有できます</p>
</script>
<script type="text/x-red" data-help-name="mqtt out">
<p>MQTTブローカに接続しメッセージをパブリッシュ(発行)します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">文字列 | バッファ</span></dt>
<dd>多くの場合単純なテキスト形式のペイロードが使われますがバイナリバッファを発行することも可能です</dd>
<dt class="optional">topic <span class="property-type">文字列</span></dt>
<dd>発行対象のMQTTトピック</dd>
<dt class="optional">qos <span class="property-type">数値</span></dt>
<dd>0: 最大1度到着, 1: 一度以上到着, 2: 1度のみ到着デフォルトは0です</dd>
<dt class="optional">retain <span class="property-type">真偽値</span></dt>
<dd>真の場合メッセージをブローカに保持しますデフォルトは偽です</dd>
</dl>
<h3>詳細</h3>
<p><code>msg.payload</code>JSON</p>
<p>発行に利用するトピックはノードに設定するかもしくは<code>msg.topic</code></p>
<p>同様にQoSとretainもードの設定もしくはノードの設定が空の場合にはそれぞれ<code>msg.qos</code><code>msg.retain</code>retain</p>
<p>このノードの利用のためにはMQTTブローカへの接続設定が必要ですこの設定は鉛筆アイコンをクリックすることで行えます</p>
<p>MQTT(inおよびout)ノードはブローカへの接続設定を必要に応じて共有できます</p>
</script>
<script type="text/x-red" data-help-name="mqtt-broker">
<p>MQTTブローカへの接続設定</p>
<p>ブローカへの接続設定を作成します設定は<code>MQTT In</code><code>MQTT Out</code></p>
<p>ードにクライアントIDを設定しておらずセッションの初期化を設定している場合ランダムなクライアントIDを生成しますクライアントIDを設定する場合接続先のブローカで一意となるようにしてください</p>
<h4>Birthメッセージ</h4>
<p>接続を確立した際に設定したトピックに対して発行するメッセージ</p>
<h4>Willメッセージ</h4>
<p>予期せず接続が切断された場合にブローカが発行するメッセージ</p>
<h4>WebSocket</h4>
<p>WebSocketによる接続を行うように設定できますWebSocketを利用するにはサーバフィールドに接続先のURIを完全な形式で記述します以下に例を示します</p>
<pre>ws://example.com:4000/mqtt</pre>
</script>

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.
-->
<script type="text/x-red" data-help-name="http in">
<p>HTTPエンドポイントを作成しWebサービスを構成します</p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload</dt>
<dd>GETリクエストの場合クエリパラメータからなるオブジェクトそれ以外の場合HTTPリクエストの本体を指します</dd>
<dt>req<span class="property-type">オブジェクト</span></dt>
<dd>HTTPリクエストオブジェクトオブジェクトはリクエストの情報に関する複数のプロパティを含みます
<ul>
<li><code>body</code> - </li>
<li><code>headers</code> - HTTP</li>
<li><code>query</code> - </li>
<li><code>params</code> - </li>
<li><code>cookies</code> - </li>
<li><code>files</code> - POST</li>
</ul>
</dd>
<dt>res<span class="property-type">オブジェクト</span></dt>
<dd>HTTPレスポンスオブジェクトこのプロパティを直接利用することは推奨しませんリクエストの処理方法については<code>HTTP Response</code>response</dd>
</dl>
<h3>詳細</h3>
<p>このノードは設定で指定したパスとリクエスト種別でリクエストを待ち受けますパス指定は完全に指定する形式(: <code>/user</code>)(: <code>/user/:name</code>)<code>msg.req.params</code></p>
<p>POSTやPUTのようにリクエストボディを含むリクエストの場合リクエストの内容は<code>msg.payload</code></p>
<p>リクエストの要素タイプが識別可能な場合にはリクエストボディを適切な形式に変換します例えば<code>application/json</code>JavaScript</p>
<p><b>:</b> HTTP Response</p>
</script>
<script type="text/x-red" data-help-name="http response">
<p>HTTP Inードで受け付けたリクエストに対するレスポンスを送り返します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">文字列</span></dt>
<dd>レスポンス本体</dd>
<dt class="optional">statusCode <span class="property-type">数値</span></dt>
<dd>設定するとレスポンスのステータスコードとしますデフォルト: 200</dd>
<dt class="optional">headers <span class="property-type">オブジェクト</span></dt>
<dd>設定するとレスポンスのHTTPヘッダとします</dd>
<dt class="optional">cookies <span class="property-type">オブジェクト</span></dt>
<dd>設定するとクッキーを設定もしくは削除するために使用します</dd>
</dl>
<h3>詳細</h3>
<p><code>statusCode</code><code>headers</code>使</p>
<h4>クッキーの処理</h4>
<p><code>cookies</code>/使<p>
<p>以下の例では2つのクッキーを設定しています1つ目は<code>name</code><code>nick</code>2<code>session</code><code>1234,</code>15</p>
<pre>
msg.cookies = {
name: 'nick',
session: {
value: '1234',
maxAge: 900000
}
}</pre>
<p>有効なオプションには以下があります</p>
<ul>
<li><code>domain</code> - () </li>
<li><code>expires</code> - () GMT0</li>
<li><code>maxAge</code> - () </li>
<li><code>path</code> - (文字列) クッキーのパス。デフォルトは「/</li>
<li><code>value</code> - () </li>
</ul>
<p>クッキーを削除するには<code>value</code><code>null</code></p>
</script>

View File

@@ -0,0 +1,60 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="http request">
<p>HTTPリクエストを送信しレスポンスを返します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">url <span class="property-type">文字列</span></dt>
<dd>ノードの設定で指定していない場合このプロパティでリクエストのurlを設定します</dd>
<dt class="optional">method <span class="property-type">文字列</span></dt>
<dd>ノードの設定で指定していない場合このプロパティでリクエストに用いるHTTPメソッドを設定します<code>GET</code>, <code>PUT</code>, <code>POST</code>, <code>PATCH</code>, <code>DELETE</code></dd>
<dt class="optional">headers <span class="property-type">オブジェクト</span></dt>
<dd>リクエストのHTTPヘッダを指定します</dd>
<dt class="optional">cookies <span class="property-type">オブジェクト</span></dt>
<dd>設定するとリクエストと共にクッキーを送ることができます</dd>
<dt class="optional">payload</dt>
<dd>リクエストボディとして送るデータ</dd>
<dt class="optional">rejectUnauthorized</dt>
<dd><code>true</code>使https</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">文字列 | オブジェクト | バッファ</span></dt>
<dd>レスポンスボディ返却するボディデータを文字列JSON文字列として解釈した結果バイナリバッファのままのいずれにするかをノード設定により指定できます</dd>
<dt>statusCode <span class="property-type">数値</span></dt>
<dd>レスポンスのステータスコードもしくはリクエストが完了しなかった場合のエラーコード</dd>
<dt>headers <span class="property-type">オブジェクト</span></dt>
<dd>レスポンスヘッダを含むオブジェクト</dd>
<dt>responseUrl <span class="property-type">文字列</span></dt>
<dd>リクエストの処理時にリダイレクトが発生した場合このプロパティが最後にリダイレクトされたURLを表しますリダイレクトが起こらなかった場合最初リクエストのURLを表します</dd>
<dt>responseCookies <span class="property-type">オブジェクト</span></dt>
<dd>レスポンスがクッキーを含む場合このプロパティは各クッキーの名前/値を含むオブジェクトを表します</dd>
</dl>
<h3>詳細</h3>
<p>ードの設定でurlプロパティを指定する場合<a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache形式</a>のタグを含めることができます。これにより、URLを入力メッセージの値から構成することができます。例えば、urlが<code>example.com/{{{topic}}}</code><code>msg.topic</code>{{{...}}}使/&mustache</p>
<p><b></b>: proxy<code>http_proxy=...</code>Node-RED</p>
<h4>複数のHTTPリクエストードの利用</h4>
<p>同一フローで本ノードを複数利用するためには<code>msg.headers</code><code>msg.headers</code>2<code>msg.headers</code><code>{}</code>
<h4>クッキーの扱い</h4>
<p>ノードに<code>cookies</code>/<code>value</code><p>
<p>リクエストに対して返却されたクッキーは<code>responseCookies</code></p>
<h4>要素タイプの扱い</h4>
<p><code>msg.payload</code><code>msg.payload</code>JSON</p>
<p>リクエストをフォームデータにエンコードするには<code>msg.headers["content-type"]</code><code>application/x-www-form-urlencoded</code></p>
</script>

View File

@@ -0,0 +1,36 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="websocket in">
<p>WebSocket入力ード</p>
<p>デフォルトではWebSocketにより受信したデータは<code>msg.payload</code>JSONJSON</p>
</script>
<script type="text/x-red" data-help-name="websocket out">
<p>WebSocket出力ード</p>
<p>デフォルトでは<code>msg.payload</code>WebSocket<code>msg</code>JSONWebSocket</p>
<p>このードが受信したメッセージがWebSocket Inードが生成したものである場合メッセージはフローを起動したクライアントに送り返されますそれ以外の場合メッセージは接続している全てのクライアントにブロードキャストされます</p>
<p>WebSocket Inードが生成したメッセージをブロードキャストしたい場合にはフロー中で<code>msg._session</code></p>
</script>
<script type="text/x-red" data-help-name="websocket-listener">
<p>この設定ードはパスを指定してWebSocketサーバのエンドポイントを作成します</p>
</script>
<script type="text/x-red" data-help-name="websocket-client">
<p>この設定ードは指定したURLにWebSocketクライアントを接続します</p>
</script>

View File

@@ -0,0 +1,25 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="watch">
<p>ディレクトリもしくはファイルの変化を検知します</p>
<p>カンマ区切りでディレクトリおよびファイルのリストを指定します空白を含む場合は引用符で"..."のように囲んでください</p>
<p>Windowsでは2重バックスラッシュ\\をディレクトリ名に使用します</p>
<p>実際に変化したファイルのフルパス名を<code>msg.payload</code><code>msg.topic</code></p>
<p><code>msg.file</code><code>msg.type</code>(<i>file</i><i>directory</i>)<code>msg.size</code>()</p>
<p>Linuxではファイルとして表されるもの<i>全て</i></p>
<p><b>: </b></p>
</script>

View File

@@ -0,0 +1,35 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="tcp in">
<p>TCPからの入力を行いますリモートTCPポートに接続するか外部らからのコネクションを受け付けます</p>
<p><b>: </b>1024rootadministrator</p>
</script>
<script type="text/x-red" data-help-name="tcp out">
<p>TCPへの出力を行いますリモートTCPポートへ接続外部からのコネクションの受け付けもしくはTCP Inードで受け付けたメッセージへのリプライを行います</p>
<p><code>msg.payload</code></p>
<p><code>msg.payload</code>Base64Base64</p>
<p><code>msg._session</code><b></b></p>
<p><b>: </b>1024rootadministrator</p>
</script>
<script type="text/x-red" data-help-name="tcp request">
<p>シンプルなTCPリクエストード<code>msg.payload</code>TCP</p>
<p>サーバに接続"リクエスト"送信"レスポンス"受信を行います固定長の文字数指定文字へのマッチ最初のリプライの到着から指定した時間待つデータの到着待ちデータ送信を行いリプライを待たず接続を即時解除などから動作を選択できます</p>
<p>レスポンスはバッファ形式で<code>msg.payload</code>toString()使</p>
<p>TCPホストのポート番号設定を空にした場合<code>msg.host</code><code>msg.port</code></p>
</script>

View File

@@ -0,0 +1,28 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="udp in">
<p>UDP入力ード<code>msg.payload</code>Base64</p>
<p><code>msg.ip</code><code>msg.port</code>IP</p>
<p><b></b>: 1024rootadministrator</p>
</script>
<script type="text/x-red" data-help-name="udp out">
<p><code>msg.payload</code>UDP</p>
<p><code>msg.ip</code><code>msg.port</code></p>
<p>ブロードキャストを行うにはアドレスをローカルブロードキャストIPアドレスに設定するかグローバルブロードキャストアドレスである255.255.255.255を試してください</p>
<p><b></b>: 1024rootadministrator</p>
</script>

View File

@@ -0,0 +1,35 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="switch">
<p>プロパティの値によってメッセージの振り分けを行います</p>
<h3>詳細</h3>
<p>受信したメッセージに対し指定されたルールを順に評価しマッチしたルールに対応する出力ポートにメッセージを送出します</p>
<p>最初にルールがマッチしたところで評価を止めることも可能です</p>
<p>評価ルールにはメッセージプロパティフローコンテキスト/グローバルコンテキストのプロパティJSONata式の評価結果が利用できます</p>
<h3>ルール</h3>
<p>振り分けルールは以下の4つに分類されます</p>
<ol>
<li><b>(value)</b> - </li>
<li><b>(sequence)</b> - (split)</li>
<li><b>JSONata式</b> - </li>
<li><b>その他</b> - </li>
</ol>
<h3>メッセージ列の扱い</h3>
<p>switchードは入力メッセージの列に関する情報を保持する<code>msg.parts</code></p>
<p><b>メッセージ列の補正</b>switch<code>nodeMessageBufferMaxLength</code></p>
</script>

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