Compare commits

...

198 Commits

Author SHA1 Message Date
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
Nick O'Leary
50ae815ceb Update changelog 2018-02-14 13:53:55 +00:00
Nick O'Leary
1a4389c90d Fix offset calculation when dragging node from palette 2018-02-14 13:37:24 +00:00
Nick O'Leary
fdaa5ce1da Merge pull request #1624 from node-red/library-extra-element
let library createUi accept elements other than node-input-name
2018-02-14 13:16:39 +00:00
Nick O'Leary
09d9936aed Change remote-diff shortcut and add it to keymap
Fixes #1628
2018-02-14 09:54:07 +00:00
Nick O'Leary
b3f6109b1c Update changelog and bump package 2018-02-13 23:51:16 +00:00
Nick O'Leary
5fb3ffc240 Merge pull request #1627 from node-red-hitachi/fix-batch-concat-mode-msg-modification
fixed message modificcation of concat mode of BATCH node
2018-02-13 23:45:19 +00:00
Nick O'Leary
360db252bb Merge pull request #1626 from node-red-hitachi/fix-typo-in-jp-message-catalog
fix typo in Japanese message catalog
2018-02-13 23:44:48 +00:00
Nick O'Leary
0b6e290271 Merge pull request #1625 from node-red-hitachi/fix-typo-in-info-text
Fix typo in info text
2018-02-13 23:44:35 +00:00
Nick O'Leary
7f0174e6db Merge pull request #1617 from node-red-hitachi/fix-backquote-in-info
Fix backquote in info text
2018-02-13 23:43:56 +00:00
Nick O'Leary
a25dad6c2e Ensure debug tools show for 'complete msg object' 2018-02-13 23:42:22 +00:00
Nick O'Leary
6191a49ed3 Use flow-diff to resolve merge conflicts 2018-02-13 23:09:51 +00:00
Hiroyasu Nishiyama
6252b075bc fixed message modificcation of concat mode of BATCH node 2018-02-13 20:55:03 +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
b9e256adfa fix typo in Japanese message catalog 2018-02-11 02:11:29 +09:00
Hiroyasu Nishiyama
3b7bf04e22 fix typo in info text of DELAY node 2018-02-11 02:07:51 +09:00
Hiroyasu Nishiyama
43408a724c fix unmatched tag in info text of BATCH node 2018-02-11 02:06:28 +09:00
Dave Conway-Jones
5fbd5bf9e2 handle other fields in library - by only changing prefix
(rather than whole property  - so ...-name is still the name required)
2018-02-10 16:49:47 +00:00
Dave Conway-Jones
5e87828b29 let library createUi accept elements other than node-input-name 2018-02-10 16:16:49 +00:00
Nick O'Leary
9066cedc29 Better merge-conflict commit button layout 2018-02-09 09:35:47 +00:00
Nick O'Leary
aa1cf0b228 Avoid git fetch when refreshing local status 2018-02-08 23:30:07 +00:00
Nick O'Leary
06a6a4408f Handle allow-unrelated-histories option on pull 2018-02-08 23:21:14 +00:00
Nick O'Leary
d5619d2b9d Fix up merge conflict handling 2018-02-08 22:22:58 +00:00
Nick O'Leary
2f6ac42efe Add comment blocks to GitHub templates to reduce clutter 2018-02-08 14:39:58 +00:00
Hiroyasu Nishiyama
0bba3dd83d merge upstream/master 2018-02-08 23:22:00 +09:00
Hiroyasu Nishiyama
abe60b62e6 change backquote in info text to <code>...</code> 2018-02-08 23:20:53 +09:00
Nick O'Leary
555b7df986 Handle more git 2.1 differences 2018-02-07 13:47:09 +00:00
Nick O'Leary
b3786700e6 Handle changing case of git error messages between versions 2018-02-07 13:10:04 +00: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
Nick O'Leary
4a5cb7f2f5 Ensure commit list has a refs object even if empty 2018-02-07 11:33:07 +00:00
Nick O'Leary
42a7e902e6 Handle host key verification as auth error 2018-02-07 11:32:50 +00:00
Nick O'Leary
aebe080e85 Add support for GIT_SSH on older levels of git 2018-02-07 10:50:32 +00:00
Kazuki-Nakanishi
c316284924 Fix the problem that the last flow tab can be deleted 2018-02-07 14:19:18 +09:00
Nick O'Leary
8d98b228ab Bump 0.18.2 2018-02-06 15:28:43 +00:00
Nick O'Leary
5b4c42ff05 Update changelog 2018-02-06 14:30:31 +00:00
Dave Conway-Jones
a596a4551a undo exec node change (investigate test fail) 2018-02-06 11:42:33 +00:00
Dave Conway-Jones
0968f96982 add a default keepalive to tcp client mode
to address #1469
2018-02-06 11:36:14 +00:00
Dave Conway-Jones
5931e13b9c move node.send in exec and httprequest nodes
just in case
2018-02-06 11:36:13 +00:00
Nick O'Leary
415c768ae4 Filter out %D from git log command for older git versions 2018-02-06 11:00:11 +00:00
Nick O'Leary
b4c8bf21d5 Ensure projects are created as logged in user 2018-02-06 10:38:41 +00:00
Nick O'Leary
5fe5db603d Better error handling/reporting in project creation 2018-02-05 15:59:11 +00:00
Nick O'Leary
9f7dd7f5d4 Add Project Settings menu option 2018-02-05 10:58:09 +00:00
Nick O'Leary
e6d32aab7b Refresh vc sidebar on remote add/remove 2018-02-05 10:10:26 +00:00
Dave Conway-Jones
08bd6d963c Ensure send is last thing trigger does 2018-02-04 21:25:25 +00:00
Dave Conway-Jones
ff05fb14a6 ensure trigger doesn't set two simultaneous timeouts 2018-02-04 20:17:43 +00:00
Nick O'Leary
22d942b705 Fix auth prompt for ssh repos 2018-02-03 23:44:19 +00:00
Nick O'Leary
0526372f28 Bump rbe dependency 2018-02-03 20:48:43 +00:00
Dave Conway-Jones
f99051906a add missing property select var to HTML node 2018-02-02 23:40:01 +00:00
Nick O'Leary
d1f7fd8bfd Prevent http git urls from including username/pword 2018-02-02 22:43:29 +00:00
Nick O'Leary
fc1436a96d Fix fetch auth handling on non-default remote 2018-02-02 16:26:55 +00:00
Nick O'Leary
d21568497b Avoid exception if git not installed 2018-02-02 13:46:22 +00:00
Nick O'Leary
df4beef060 Check version of git client on startup 2018-02-02 11:37:18 +00:00
Dave Conway-Jones
a52f195d41 undo dumb non-fix to trigger. 2018-02-02 10:28:22 +00:00
Dave Conway-Jones
419019a656 add check for property to trigger (temporary fix for debug) 2018-02-02 10:23:28 +00:00
182 changed files with 6118 additions and 2067 deletions

View File

@@ -1,3 +1,4 @@
<!--
## Before you hit that Submit button....
This issue tracker is for problems with the Node-RED runtime, the editor or the core nodes.
@@ -7,13 +8,16 @@ 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.
## So you have a real issue to raise...
To help us understand the issue, please fill-in as much of the following information as you can:
-->
### What are the steps to reproduce?

View File

@@ -1,3 +1,4 @@
<!--
## Before you hit that Submit button....
Please read our [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
@@ -6,23 +7,26 @@ before submitting a pull-request.
## Types of changes
What types of changes does your code introduce?
_Put an `x` in the boxes that apply_
Put an `x` in the boxes that apply
-->
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
<!--
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.
-->
## Proposed changes
Describe the nature of this change. What problem does it address?
<!-- Describe the nature of this change. What problem does it address? -->
## Checklist
_Put an `x` in the boxes that apply_
<!-- Put an `x` in the boxes that apply -->
- [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
- [ ] For non-bugfix PRs, I have discussed this change on the mailing list/slack team.

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:
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && 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,150 @@
#### 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
- Fix permissions on git/ssh scripts
- Add support for GIT_SSH on older levels of git
- Handle host key verification as auth error
- Ensure commit list has a refs object even if empty
- Make git error detection case-insensitive
- Fix up merge conflict handling
- Use flow-diff when looking at flow file changes
Node Fixes
- Ensure debug tools show for 'complete msg object'
- Fix msg.parts handling in concat mode of Batch node
Editor Fixes
- Fix offset calculation when dragging node from palette
- Allow a library entry to use non-default node-input- prefixes
- Change remote-diff shortcut and add it to keymap Fixes #1628
#### 0.18.2: Maintenance Release
Projects
- Filter out %D from git log command for older git versions
- Ensure projects are created as logged in user
- Better error handling/reporting in project creation
- Add Project Settings menu option
- Refresh vc sidebar on remote add/remove
- Fix auth prompt for ssh repos
- Prevent http git urls from including username/pword
- Fix fetch auth handling on non-default remote
- Avoid exception if git not installed
- Check version of git client on startup
- Fix pull/push when no tracked branch
- Add git_pull_unrelated_history handling
- Handle delete of last remote in project settings
Node Fixes
- Fix and Add some Chinese translations
- Update sort/batch docs
- Don't assume node has defaults when exporting icon property
- Ensure send is last thing trigger does
- Ensure trigger doesn't set two simultaneous timeouts
- Add missing property select var to HTML node
- Add a default keepalive to tcp client mode
- Move node.send in exec and httprequest nodes
#### 0.18.1: 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

@@ -392,9 +392,9 @@ module.exports = function(grunt) {
mode: '755'
},
release: {
// Target-specific file/dir lists and/or options go here.
src: [
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*')
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*'),
path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/red/runtime/storage/localfilesystem/projects/git/node-red-*sh')
]
}
},

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

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

@@ -14,7 +14,7 @@
"ctrl-i": "core:show-import-dialog",
"ctrl-space": "core:toggle-sidebar",
"ctrl-,": "core:show-user-settings",
"ctrl-alt-r": "core:show-remote-diff",
"ctrl-alt-n": "core:new-project",
"ctrl-alt-o": "core:open-project",
"ctrl-g v": "core:show-version-control-tab"

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");
@@ -67,6 +90,7 @@
if (!activeProject) {
// Projects enabled but no active project
RED.menu.setDisabled('menu-item-projects-open',true);
RED.menu.setDisabled('menu-item-projects-settings',true);
if (activeProject === false) {
// User previously decline the migration to projects.
} else { // null/undefined
@@ -130,11 +154,12 @@
var project = RED.projects.getActiveProject();
var message = {
"change-branch":"Change to local branch '"+project.git.branches.local+"'",
"abort-merge":"Git merge aborted",
"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"
"revert": "Project '"+msg.project+"' reloaded",
"merge-complete":"Git merge completed"
}[msg.action];
RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh()
@@ -177,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: "Setup credentials",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showCredentialsPrompt();
}
}
]
}
} else {
options.buttons = [
{
text: "Setup credentials",
text: "Close",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.showCredentialsPrompt();
}
}
]
@@ -200,6 +237,18 @@
}
]
}
} else if (msg.error === "missing_package_file") {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: "Create default package file",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.projects.createDefaultPackageFile();
}
}
]
}
} else if (msg.error === "project_empty") {
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
@@ -218,6 +267,20 @@
}
]
}
} else if (msg.error === "git_merge_conflict") {
RED.nodes.clear();
RED.sidebar.versionControl.refresh(true);
if (RED.user.hasPermission("projects.write")) {
options.buttons = [
{
text: "Show merge conflicts",
click: function() {
persistentNotifications[notificationId].hideNotification();
RED.sidebar.versionControl.showLocalChanges();
}
}
]
}
}
}
if (!persistentNotifications.hasOwnProperty(notificationId)) {
@@ -256,7 +319,7 @@
addedTypes = addedTypes.concat(m.types);
RED.i18n.loadCatalog(id, function() {
$.get('nodes/'+id, function(data) {
$("body").append(data);
appendNodeConfig(data);
});
});
});
@@ -284,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");
});
@@ -320,8 +383,9 @@
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-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"}
]});
}

View File

@@ -355,7 +355,7 @@ RED.nodes = (function() {
RED.nodes.registerType("subflow:"+sf.id, {
defaults:{name:{value:""}},
info: sf.info,
icon:"subflow.png",
icon: function() { return sf.icon||"subflow.png" },
category: "subflows",
inputs: sf.in.length,
outputs: sf.out.length,
@@ -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);
}
}
}
@@ -550,7 +552,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 +755,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 +1014,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) {
@@ -1022,6 +1035,11 @@ RED.nodes = (function() {
if (node._def.category != "config") {
node.inputs = n.inputs||node._def.inputs;
node.outputs = n.outputs||node._def.outputs;
// If 'wires' is longer than outputs, clip wires
if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) {
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);
}
for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) {
node[d] = n[d];
@@ -1043,7 +1061,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

@@ -116,7 +116,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

@@ -9,29 +9,30 @@ RED.diff = (function() {
// RED.actions.add("core:show-current-diff",showLocalDiff);
RED.actions.add("core:show-remote-diff",showRemoteDiff);
// RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff");
RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff");
// RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff");
RED.actions.add("core:show-test-flow-diff-1",function(){showTestFlowDiff(1)});
RED.keyboard.add("*","ctrl-shift-f 1","core:show-test-flow-diff-1");
RED.actions.add("core:show-test-flow-diff-2",function(){showTestFlowDiff(2)});
RED.keyboard.add("*","ctrl-shift-f 2","core:show-test-flow-diff-2");
RED.actions.add("core:show-test-flow-diff-3",function(){showTestFlowDiff(3)});
RED.keyboard.add("*","ctrl-shift-f 3","core:show-test-flow-diff-3");
// RED.actions.add("core:show-test-flow-diff-1",function(){showTestFlowDiff(1)});
// RED.keyboard.add("*","ctrl-shift-f 1","core:show-test-flow-diff-1");
//
// RED.actions.add("core:show-test-flow-diff-2",function(){showTestFlowDiff(2)});
// RED.keyboard.add("*","ctrl-shift-f 2","core:show-test-flow-diff-2");
// RED.actions.add("core:show-test-flow-diff-3",function(){showTestFlowDiff(3)});
// RED.keyboard.add("*","ctrl-shift-f 3","core:show-test-flow-diff-3");
}
function createDiffTable(container) {
function createDiffTable(container,CurrentDiff) {
var diffList = $('<ol class="node-dialog-view-diff-diff"></ol>').appendTo(container);
diffList.editableList({
addButton: false,
height: "auto",
scrollOnAdd: false,
addItem: function(container,i,object) {
var localDiff = object.diff;
var remoteDiff = object.remoteDiff;
var tab = object.tab.n;
var def = object.def;
var conflicts = currentDiff.conflicts;
var conflicts = CurrentDiff.conflicts;
var tabDiv = $('<div>',{class:"node-diff-tab"}).appendTo(container);
tabDiv.addClass('collapsed');
@@ -50,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: {
@@ -130,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();
@@ -150,10 +151,10 @@ RED.diff = (function() {
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
selectState = CurrentDiff.resolutions[tab.id];
}
// Tab properties row
createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!conflicts[tab.id],selectState);
createNodeConflictRadioBoxes(tab,div,localNodeDiv,remoteNodeDiv,true,!conflicts[tab.id],selectState,CurrentDiff);
}
}
// var stats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(titleRow);
@@ -162,14 +163,14 @@ RED.diff = (function() {
var seen = {};
object.tab.nodes.forEach(function(node) {
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
createNodeDiffRow(node,flowStats,CurrentDiff).appendTo(nodesDiv)
});
if (object.newTab) {
localNodeCount = object.newTab.nodes.length;
object.newTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
seen[node.id] = true;
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
createNodeDiffRow(node,flowStats,CurrentDiff).appendTo(nodesDiv)
}
});
}
@@ -177,7 +178,7 @@ RED.diff = (function() {
remoteNodeCount = object.remoteTab.nodes.length;
object.remoteTab.nodes.forEach(function(node) {
if (!seen[node.id]) {
createNodeDiffRow(node,flowStats).appendTo(nodesDiv)
createNodeDiffRow(node,flowStats,CurrentDiff).appendTo(nodesDiv)
}
});
}
@@ -205,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);
@@ -244,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) {
@@ -269,12 +270,12 @@ RED.diff = (function() {
if (flowStats.conflicts > 0) {
titleRow.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[tab.id];
selectState = CurrentDiff.resolutions[tab.id];
}
if (tab.id) {
var hide = !(flowStats.conflicts > 0 &&(localDiff.deleted[tab.id] || remoteDiff.deleted[tab.id]));
// Tab parent row
createNodeConflictRadioBoxes(tab,titleRow,localCell,remoteCell, false, hide, selectState);
createNodeConflictRadioBoxes(tab,titleRow,localCell,remoteCell, false, hide, selectState, CurrentDiff);
}
}
@@ -291,11 +292,8 @@ RED.diff = (function() {
var diffHeaders = $('<div class="node-dialog-view-diff-headers"></div>').appendTo(diffPanel);
if (options.mode === "merge") {
diffPanel.addClass("node-dialog-view-diff-panel-merge");
var toolbar = $('<div class="node-diff-toolbar">'+
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
'</div>').prependTo(diffPanel);
}
var diffList = createDiffTable(diffPanel);
var diffList = createDiffTable(diffPanel, diff);
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
@@ -466,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++;
@@ -476,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);
}
@@ -509,13 +507,13 @@ 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) {
var localDiff = currentDiff.localDiff;
var remoteDiff = currentDiff.remoteDiff;
var conflicted = currentDiff.conflicts[node.id];
function createNodeDiffRow(node,stats,CurrentDiff) {
var localDiff = CurrentDiff.localDiff;
var remoteDiff = CurrentDiff.remoteDiff;
var conflicted = CurrentDiff.conflicts[node.id];
var hasChanges = false; // exists in original and local/remote but with changes
var unChanged = true; // existing in original,local,remote unchanged
@@ -703,10 +701,10 @@ RED.diff = (function() {
}
div.addClass("node-diff-node-entry-conflict");
} else {
selectState = currentDiff.resolutions[node.id];
selectState = CurrentDiff.resolutions[node.id];
}
// Node row
createNodeConflictRadioBoxes(node,div,localNodeDiv,remoteNodeDiv,false,!conflicted,selectState);
createNodeConflictRadioBoxes(node,div,localNodeDiv,remoteNodeDiv,false,!conflicted,selectState,CurrentDiff);
row.click(function(evt) {
$(this).parent().toggleClass('collapsed');
});
@@ -741,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");
@@ -784,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"));
@@ -852,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) {
@@ -919,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) {
@@ -982,7 +980,7 @@ RED.diff = (function() {
});
return nodePropertiesDiv;
}
function createNodeConflictRadioBoxes(node,row,localDiv,remoteDiv,propertiesTable,hide,state) {
function createNodeConflictRadioBoxes(node,row,localDiv,remoteDiv,propertiesTable,hide,state,diff) {
var safeNodeId = "node-diff-selectbox-"+node.id.replace(/\./g,'-')+(propertiesTable?"-props":"");
var className = "";
if (node.z||propertiesTable) {
@@ -1019,7 +1017,7 @@ RED.diff = (function() {
row.addClass("node-diff-select-remote");
row.removeClass("node-diff-select-local");
}
refreshConflictHeader();
refreshConflictHeader(diff);
}
var localSelectDiv = $('<label>',{class:"node-diff-selectbox",for:safeNodeId+"-local"}).click(function(e) { e.stopPropagation();}).appendTo(localDiv);
@@ -1037,7 +1035,7 @@ RED.diff = (function() {
}
}
function refreshConflictHeader() {
function refreshConflictHeader(currentDiff) {
var resolutionCount = 0;
$(".node-diff-selectbox>input:checked").each(function() {
if (currentDiff.conflicts[$(this).data('node-id')]) {
@@ -1053,6 +1051,7 @@ RED.diff = (function() {
}
if (conflictCount === resolutionCount) {
$("#node-diff-view-diff-merge").removeClass('disabled');
$("#node-diff-view-resolve-diff").removeClass('disabled');
}
}
function getRemoteDiff(callback) {
@@ -1231,7 +1230,7 @@ RED.diff = (function() {
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
var conflicts = diff.conflicts;
currentDiff = diff;
// currentDiff = diff;
var trayOptions = {
title: options.title||"Review Changes", //TODO: nls
@@ -1250,7 +1249,11 @@ RED.diff = (function() {
},
open: function(tray) {
var trayBody = tray.find('.editor-tray-body');
var diffTable = buildDiffPanel(trayBody,diff,options);
var toolbar = $('<div class="node-diff-toolbar">'+
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
'</div>').prependTo(trayBody);
var diffContainer = $('<div class="node-diff-container"></div>').appendTo(trayBody);
var diffTable = buildDiffPanel(diffContainer,diff,options);
diffTable.list.hide();
if (remoteDiff) {
$("#node-diff-view-diff-merge").show();
@@ -1262,7 +1265,7 @@ RED.diff = (function() {
} else {
$("#node-diff-view-diff-merge").hide();
}
refreshConflictHeader();
refreshConflictHeader(diff);
// console.log("--------------");
// console.log(localDiff);
// console.log(remoteDiff);
@@ -1290,8 +1293,8 @@ RED.diff = (function() {
class: "primary disabled",
click: function() {
if (!$("#node-diff-view-diff-merge").hasClass('disabled')) {
refreshConflictHeader();
mergeDiff(currentDiff);
refreshConflictHeader(diff);
mergeDiff(diff);
RED.tray.close();
}
}
@@ -1302,7 +1305,7 @@ RED.diff = (function() {
RED.tray.show(trayOptions);
}
function mergeDiff(diff) {
function applyDiff(diff) {
var currentConfig = diff.localDiff.currentConfig;
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
@@ -1356,6 +1359,20 @@ RED.diff = (function() {
}
}
}
return {
config: newConfig,
nodeChangedStates: nodeChangedStates,
localChangedStates: localChangedStates
}
}
function mergeDiff(diff) {
var appliedDiff = applyDiff(diff);
var newConfig = appliedDiff.config;
var nodeChangedStates = appliedDiff.nodeChangedStates;
var localChangedStates = appliedDiff.localChangedStates;
var historyEvent = {
t:"replace",
config: RED.nodes.createCompleteNodeSet(),
@@ -1374,7 +1391,7 @@ RED.diff = (function() {
}
})
RED.nodes.version(remoteDiff.rev);
RED.nodes.version(diff.remoteDiff.rev);
RED.view.redraw(true);
RED.palette.refresh();
@@ -1417,7 +1434,7 @@ RED.diff = (function() {
var trayBody = tray.find('.editor-tray-body');
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
var codeTable = $("<table>").appendTo(diffPanel);
var codeTable = $("<table>",{class:"node-text-diff-content"}).appendTo(diffPanel);
$('<colgroup><col width="50"><col width="50%"><col width="50"><col width="50%"></colgroup>').appendTo(codeTable);
var codeBody = $('<tbody>').appendTo(codeTable);
var diffSummary = diffText(textA||"",textB||"");
@@ -1681,7 +1698,7 @@ RED.diff = (function() {
files.forEach(function(file) {
var hunks = file.hunks;
var isBinary = file.binary;
var codeTable = $("<table>").appendTo(diffPanel);
var codeTable = $("<table>",{class:"node-text-diff-content"}).appendTo(diffPanel);
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
var codeBody = $('<tbody>').appendTo(codeTable);
@@ -1700,49 +1717,82 @@ RED.diff = (function() {
var unresolvedConflicts = 0;
var resolvedConflicts = 0;
var conflictResolutions = {};
if (commitOptions.project.files && commitOptions.project.files.flow === file.file) {
if (commitOptions.unmerged) {
$('<span style="float: right;"><span id="node-diff-toolbar-resolved-conflicts"></span></span>').appendTo(content);
}
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
var flowDiffContent = $('<td class="flow-diff" colspan="3"></td>').appendTo(diffRow);
if (!commitOptions.unmerged && commitOptions.project.files && commitOptions.project.files.flow === file.file) {
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 oldVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.oldRev+"/"+filename;
var newVersionUrl = "/projects/"+projectName+"/files/"+commitOptions.newRev+"/"+filename;
$.when($.getJSON(oldVersionUrl),$.getJSON(newVersionUrl)).done(function(oldVersion,newVersion) {
var oldFlow;
var newFlow;
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 = [$.Deferred(),$.Deferred(),$.Deferred()];
if (commitOptions.commonRev) {
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);
}
$.ajax({dataType: "json",url: oldVersionUrl}).then(function(data) { promises[1].resolve(data); }).fail(function() { promises[1].resolve({content:"[]"});})
$.ajax({dataType: "json",url: newVersionUrl}).then(function(data) { promises[2].resolve(data); }).fail(function() { promises[2].resolve({content:"[]"});})
$.when.apply($,promises).always(function(commonVersion, oldVersion,newVersion) {
var commonFlow;
var oldFlow;
var newFlow;
if (commonVersion) {
try {
oldFlow = JSON.parse(oldVersion[0].content||"[]");
commonFlow = JSON.parse(commonVersion.content||"[]");
} catch(err) {
console.log("Old Version doesn't contain valid JSON:",oldVersionUrl);
console.log("Common Version doesn't contain valid JSON:",commonVersionUrl);
console.log(err);
return;
}
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(oldFlow,oldFlow);
var remoteDiff = generateDiff(oldFlow,newFlow);
var diff = resolveDiffs(localDiff,remoteDiff);
showDiff(diff,{
title: filename,
mode: '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();
}
try {
oldFlow = JSON.parse(oldVersion.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.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);
commitOptions.currentDiff = resolveDiffs(localDiff,remoteDiff);
var diffTable = buildDiffPanel(flowDiffContent,commitOptions.currentDiff,{
title: filename,
mode: commitOptions.commonRev?'merge':'view',
oldRevTitle: commitOptions.oldRevTitle,
newRevTitle: commitOptions.newRevTitle
});
})
}
diffTable.list.hide();
refreshConflictHeader(commitOptions.currentDiff);
setTimeout(function() {
diffTable.finish();
diffTable.list.show();
},300);
// var flowDiffRow = $("<tr>").insertAfter(diffRow);
// var content = $('<td colspan="3"></td>').appendTo(flowDiffRow);
// currentDiff = diff;
// var diffTable = buildDiffPanel(content,diff,{mode:"view"}).finish();
});
} else
if (isBinary) {
var diffBinaryRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
@@ -1750,6 +1800,9 @@ RED.diff = (function() {
$('<span></span>').text("Cannot show binary file contents").appendTo(binaryContent);
} else {
if (commitOptions.unmerged) {
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content);
}
hunks.forEach(function(hunk) {
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
var content = $('<td colspan="3"></td>').appendTo(diffRow);
@@ -1768,7 +1821,7 @@ RED.diff = (function() {
// }
var actualLineNumber = hunk.diffStart + lineNumber;
var isMergeHeader = isConflict && /^..(<<<<<<<|=======$|>>>>>>>)/.test(lineText);
var isMergeHeader = isConflict && /^\+\+(<<<<<<<|=======$|>>>>>>>)/.test(lineText);
var diffRow = $('<tr>').appendTo(codeBody);
var localLineNo = $('<td class="lineno">').appendTo(diffRow);
var remoteLineNo;
@@ -1827,7 +1880,7 @@ RED.diff = (function() {
$('<span>').text(lineText.substring(prefixEnd)).appendTo(line);
} else {
diffRow.addClass("mergeHeader");
var isSeparator = /^..(=======$)/.test(lineText);
var isSeparator = /^\+\+=======$/.test(lineText);
if (!isSeparator) {
var isOurs = /^..<<<<<<</.test(lineText);
if (isOurs) {
@@ -1886,9 +1939,6 @@ RED.diff = (function() {
});
});
}
if (commitOptions.unmerged) {
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content);
}
});
return diffPanel;
}
@@ -1914,7 +1964,7 @@ RED.diff = (function() {
var trayBody = tray.find('.editor-tray-body');
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
var codeTable = $("<table>").appendTo(diffPanel);
var codeTable = $("<table>",{class:"node-text-diff-content"}).appendTo(diffPanel);
$('<colgroup><col width="50"><col width="50"><col width="100%"></colgroup>').appendTo(codeTable);
var codeBody = $('<tbody>').appendTo(codeTable);
@@ -1957,7 +2007,6 @@ RED.diff = (function() {
}
}
var trayOptions = {
title: title||"Compare Changes", //TODO: nls
width: Infinity,
@@ -1996,6 +2045,15 @@ RED.diff = (function() {
class: "primary disabled",
click: function() {
if (!$("#node-diff-view-resolve-diff").hasClass('disabled')) {
if (options.currentDiff) {
// This is a flow file. Need to apply the diff
// and generate the new flow.
var result = applyDiff(options.currentDiff);
currentResolution = {
resolutions:{}
};
currentResolution.resolutions[options.project.files.flow] = JSON.stringify(result.config,"",4);
}
if (options.onresolve) {
options.onresolve(currentResolution);
}
@@ -2047,7 +2105,7 @@ RED.diff = (function() {
} else {
lines = diff.split("\n");
}
var diffHeader = /^diff --git a\/(.*) b\/(.*)$/;
var diffHeader = /^diff (?:(?:--git a\/(.*) b\/(.*))|(?:--cc (.*)))$/;
var fileHeader = /^\+\+\+ b\/(.*)\t?/;
var binaryFile = /^Binary files /;
var hunkHeader = /^@@ -((\d+)(,(\d+))?) \+((\d+)(,(\d+))?) @@ ?(.*)$/;
@@ -2066,7 +2124,7 @@ RED.diff = (function() {
}
currentHunk = null;
currentFile = {
file: diffLine[1],
file: diffLine[1]||diffLine[3],
hunks: []
}
} else if (binaryFile.test(line)) {

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);
@@ -170,6 +170,10 @@ RED.editor = (function() {
}
}
}
validateIcon(node);
}
function validateIcon(node) {
if (node._def.hasOwnProperty("defaults") && !node._def.defaults.hasOwnProperty("icon") && node.icon) {
var iconPath = RED.utils.separateIconPath(node.icon);
var iconSets = RED.nodes.getIconSets();
@@ -188,6 +192,7 @@ RED.editor = (function() {
}
}
}
function validateNodeEditorProperty(node,defaults,property,prefix) {
var input = $("#"+prefix+"-"+property);
if (input.length > 0) {
@@ -655,7 +660,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 +696,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) {
@@ -742,7 +747,7 @@ RED.editor = (function() {
buildLabelRow().appendTo(outputsDiv);
}
if (!node._def.defaults.hasOwnProperty("icon")) {
if ((!node._def.defaults || !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);
@@ -816,9 +821,51 @@ RED.editor = (function() {
});
}
selectIconFile.prop("disabled", !iconFileList);
selectIconFile.removeClass("input-error");
selectIconModule.removeClass("input-error");
}
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;
}
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;
changed = true;
}
return changed;
}
function showEditDialog(node) {
var editing_node = node;
var isDefaultIcon;
@@ -1034,44 +1081,11 @@ 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")) {
if (!editing_node._def.defaults || !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 : "";
@@ -1352,7 +1366,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 +1689,25 @@ 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 iconModule = $("#node-settings-icon-module-hidden").val();
var iconFile = $("#node-settings-icon-file-hidden").val();
var icon = (iconModule && iconFile) ? iconModule+"/"+iconFile : "";
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;
}
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 +1718,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',
@@ -1783,9 +1796,10 @@ 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);
validateIcon(subflow);
trayBody.i18n();
},
close: function() {
@@ -1839,7 +1853,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

@@ -15,8 +15,8 @@
**/
RED.library = (function() {
var exportToLibraryDialog;
var elementPrefix = "node-input-";
function loadFlowLibrary() {
$.getJSON("library/flows",function(data) {
@@ -86,6 +86,7 @@ RED.library = (function() {
var libraryData = {};
var selectedLibraryItem = null;
var libraryEditor = null;
elementPrefix = options.elementPrefix || "node-input-";
// Orion editor has set/getText
// ACE editor has set/getValue
@@ -157,8 +158,8 @@ RED.library = (function() {
return ul;
}
$('#node-input-name').css("width","66%").after(
'<div class="btn-group" style="margin-left: 5px;">'+
$('#'+elementPrefix+"name").css("width","calc(100% - 52px)").after(
'<div class="btn-group" style="margin-left:5px;">'+
'<a id="node-input-'+options.type+'-lookup" class="editor-button" data-toggle="dropdown"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></a>'+
'<ul class="dropdown-menu pull-right" role="menu">'+
'<li><a id="node-input-'+options.type+'-menu-open-library" tabindex="-1" href="#">'+RED._("library.openLibrary")+'</a></li>'+
@@ -187,7 +188,7 @@ RED.library = (function() {
$('#node-input-'+options.type+'-menu-save-library').click(function(e) {
//var found = false;
var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
var name = $("#"+elementPrefix+"name").val().replace(/(^\s*)|(\s*$)/g,"");
//var buildPathList = function(data,root) {
// var paths = [];
@@ -264,7 +265,7 @@ RED.library = (function() {
if (selectedLibraryItem) {
for (var i=0; i<options.fields.length; i++) {
var field = options.fields[i];
$("#node-input-"+field).val(selectedLibraryItem[field]);
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
}
options.editor.setValue(libraryEditor.getValue(),-1);
}
@@ -286,7 +287,7 @@ RED.library = (function() {
});
function saveToLibrary(overwrite) {
var name = $("#node-input-name").val().replace(/(^\s*)|(\s*$)/g,"");
var name = $("#"+elementPrefix+"name").val().replace(/(^\s*)|(\s*$)/g,"");
if (name === "") {
name = RED._("library.unnamedType",{type:options.type});
}
@@ -330,7 +331,7 @@ RED.library = (function() {
if (field == "name") {
data.name = name;
} else {
data[field] = $("#node-input-"+field).val();
data[field] = $("#"+elementPrefix+field).val();
}
}

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

@@ -116,6 +116,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(":","_");
}
@@ -219,13 +225,19 @@ RED.palette = (function() {
var mouseX;
var mouseY;
var spliceTimer;
var paletteWidth;
var paletteTop;
$(d).draggable({
helper: 'clone',
appendTo: 'body',
revert: true,
revertDuration: 50,
containment:'#main-container',
start: function() {RED.view.focus();},
start: function() {
paletteWidth = $("#palette").width();
paletteTop = $("#palette").parent().position().top + $("#palette-container").position().top;
RED.view.focus();
},
stop: function() { d3.select('.link_splice').classed('link_splice',false); if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null;}},
drag: function(e,ui) {
@@ -235,9 +247,8 @@ RED.palette = (function() {
ui.position.left += 17.5;
if (def.inputs > 0 && def.outputs > 0) {
mouseX = ui.position.left+(ui.helper.width()/2) - chartOffset.left + chart.scrollLeft();
mouseY = ui.position.top+(ui.helper.height()/2) - chartOffset.top + chart.scrollTop();
mouseX = ui.position.left-paletteWidth+(ui.helper.width()/2) - chartOffset.left + chart.scrollLeft();
mouseY = ui.position.top-paletteTop+(ui.helper.height()/2) - chartOffset.top + chart.scrollTop();
if (!spliceTimer) {
spliceTimer = setTimeout(function() {
var nodes = [];
@@ -259,6 +270,7 @@ RED.palette = (function() {
mouseY /= RED.view.scale();
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
}
for (var i=0;i<nodes.length;i++) {
if (d3.select(nodes[i]).classed('link_background')) {
var length = nodes[i].getTotalLength();
@@ -369,6 +381,7 @@ RED.palette = (function() {
portOutput.remove();
}
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,marked(sf.info||""));
setIcon(paletteNode,sf);
});
}

View File

@@ -49,7 +49,7 @@ RED.projects.settings = (function() {
var tabContainer;
var trayOptions = {
title: "Project Information",// RED._("menu.label.userSettings"),, // TODO: nls
title: "Project Settings",// RED._("menu.label.userSettings"),, // TODO: nls
buttons: [
{
id: "node-dialog-ok",
@@ -143,7 +143,8 @@ RED.projects.settings = (function() {
RED.sidebar.versionControl.refresh(true);
},
400: {
'unexpected_error': function(error) {
'*': function(error) {
utils.reportUnexpectedError(error);
done(error,null);
}
},
@@ -208,7 +209,8 @@ RED.projects.settings = (function() {
done(null,data);
},
400: {
'unexpected_error': function(error) {
'*': function(error) {
utils.reportUnexpectedError(error);
done(error,null);
}
},
@@ -442,9 +444,9 @@ 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")) {
@@ -962,7 +964,7 @@ RED.projects.settings = (function() {
var done = function(err) {
spinner.remove();
if (err) {
console.log(err);
utils.reportUnexpectedError(err);
return;
}
flowFileLabelText.text(flowFileInput.val());
@@ -1005,10 +1007,6 @@ RED.projects.settings = (function() {
'credentials_load_failed': function(error) {
done(error);
},
'unexpected_error': function(error) {
console.log(error);
done(error);
},
'missing_current_credential_key': function(error) {
credentialSecretExistingInput.addClass("input-error");
popover = RED.popover.create({
@@ -1019,11 +1017,16 @@ RED.projects.settings = (function() {
autoClose: 3000
}).open();
done(error);
},
'*': function(error) {
done(error);
}
},
}
},payload).always(function() {
RED.deploy.setDeployInflight(false);
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
});
var updateForm = function() {
@@ -1142,8 +1145,8 @@ RED.projects.settings = (function() {
]
});
},
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
spinner.remove();
}
},
@@ -1193,12 +1196,19 @@ RED.projects.settings = (function() {
editRepoButton.attr('disabled',true);
addRemoteDialog.slideDown(200, function() {
addRemoteDialog[0].scrollIntoView();
if (isEmpty) {
remoteNameInput.val('origin');
remoteURLInput.focus();
} else {
remoteNameInput.focus();
}
validateForm();
});
});
var emptyItem = { empty: true };
var isEmpty = true;
var row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
var addRemoteDialog = $('<div class="projects-dialog-list-dialog"></div>').hide().appendTo(row);
row = $('<div class="user-settings-row projects-dialog-list"></div>').appendTo(repoContainer);
@@ -1245,6 +1255,14 @@ RED.projects.settings = (function() {
text: 'Delete remote',
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,
@@ -1256,6 +1274,7 @@ RED.projects.settings = (function() {
setTimeout(spinner.remove, 100);
if (data.remotes.length === 0) {
delete activeProject.git.remotes;
isEmpty = true;
remotesList.editableList('addItem',emptyItem);
} else {
activeProject.git.remotes = {};
@@ -1265,11 +1284,13 @@ RED.projects.settings = (function() {
activeProject.git.remotes[name] = remote;
});
}
delete activeProject.git.branches.remoteAlt;
RED.sidebar.versionControl.refresh();
});
},
400: {
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
spinner.remove();
}
},
@@ -1290,16 +1311,26 @@ RED.projects.settings = (function() {
var validateForm = function() {
var validName = /^[a-zA-Z0-9\-_]+$/.test(remoteNameInput.val());
var repo = remoteURLInput.val();
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\.git)?(?:\/?|\#[\d\w\.\-_]+?)$/.test(remoteURLInput.val());
var validRepo = !/\s/.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");
validRepo = false;
} else {
remoteURLLabel.text("https://, ssh:// or file://");
}
saveButton.attr('disabled',(!validName || !validRepo))
remoteNameInput.toggleClass('input-error',remoteNameInputChanged&&!validName);
remoteURLInput.toggleClass('input-error',remoteURLInputChanged&&!validRepo);
if (popover) {
popover.close();
popover = null;
}
};
var popover;
var remoteNameInputChanged = false;
var remoteURLInputChanged = false;
$('<div class="projects-dialog-list-dialog-header">').text('Add remote').appendTo(addRemoteDialog);
@@ -1309,11 +1340,14 @@ RED.projects.settings = (function() {
remoteNameInputChanged = true;
validateForm();
});
var remoteNameInputChanged = false;
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text('URL').appendTo(row);
var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",validateForm);
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 hideEditForm = function() {
editRepoButton.attr('disabled',false);
@@ -1367,6 +1401,7 @@ RED.projects.settings = (function() {
activeProject.git.remotes[name] = remote;
});
updateForm();
RED.sidebar.versionControl.refresh();
done();
},
400: {
@@ -1381,14 +1416,15 @@ RED.projects.settings = (function() {
remoteNameInput.addClass('input-error');
done(error);
},
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
done(error);
}
},
}
},payload);
});
var updateForm = function() {
remotesList.editableList('empty');
var count = 0;
@@ -1400,7 +1436,8 @@ RED.projects.settings = (function() {
}
}
}
if (count === 0) {
isEmpty = (count === 0);
if (isEmpty) {
remotesList.editableList('addItem',emptyItem);
}
}

View File

@@ -19,7 +19,45 @@ RED.projects = (function() {
var dialogBody;
var activeProject;
function reportUnexpectedError(error) {
var notification;
if (error.error === 'git_missing_user') {
notification = RED.notify("<p>You Git client is not configured with a username/email.</p>",{
fixed: true,
type:'error',
buttons: [
{
text: "Cancel",
click: function() {
notification.close();
}
},
{
text: "Configure Git client",
click: function() {
RED.userSettings.show('gitconfig');
notification.close();
}
}
]
})
} else {
console.log(error);
notification = RED.notify("<p>An unexpected error occurred:</p><p>"+error.message+"</p><small>code: "+error.error+"</small>",{
fixed: true,
modal: true,
type: 'error',
buttons: [
{
text: "Close",
click: function() {
notification.close();
}
}
]
})
}
}
var screens = {};
function initScreens() {
var migrateProjectHeader = $('<div class="projects-dialog-screen-start-hero"></div>');
@@ -39,8 +77,28 @@ RED.projects = (function() {
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Hello! We have introduced 'projects' to Node-RED.").appendTo(body);
$('<p>').text("This is a new way for you to manage your flow files and includes version control of your flows.").appendTo(body);
$('<p>').text("To get started you can create your first project using your current flow files in a few easy steps.").appendTo(body);
$('<p>').text("If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu option at any time.").appendTo(body);
$('<p>').text("To get started you can create your first project or clone an existing project from a git repository.").appendTo(body);
$('<p>').text("If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.").appendTo(body);
var row = $('<div style="text-align: center"></div>').appendTo(body);
var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>Create Project</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>Clone Repository</button>').appendTo(row);
createAsEmpty.click(function(e) {
e.preventDefault();
createProjectOptions = {
action: "create"
}
show('git-config');
})
createAsClone.click(function(e) {
e.preventDefault();
createProjectOptions = {
action: "clone"
}
show('git-config');
})
return container;
},
@@ -52,13 +110,6 @@ RED.projects = (function() {
createProjectOptions = {};
$( this ).dialog( "close" );
}
},
{
text: "Create your first project", // TODO: nls
class: "primary",
click: function() {
show('git-config');
}
}
]
},
@@ -132,7 +183,11 @@ RED.projects = (function() {
currentGitSettings.user.name = gitUsernameInput.val();
currentGitSettings.user.email = gitEmailInput.val();
RED.settings.set('git', currentGitSettings);
show('project-details');
if (createProjectOptions.action === "create") {
show('project-details');
} else if (createProjectOptions.action === "clone") {
show('clone-project');
}
}
}
]
@@ -265,6 +320,366 @@ RED.projects = (function() {
}
};
})(),
'clone-project': (function() {
var projectNameInput;
var projectSummaryInput;
var projectFlowFileInput;
var projectSecretInput;
var projectSecretSelect;
var copyProject;
var projectRepoInput;
var projectCloneSecret;
var emptyProjectCredentialInput;
var projectRepoUserInput;
var projectRepoPasswordInput;
var projectNameSublabel;
var projectRepoSSHKeySelect;
var projectRepoPassphrase;
var projectRepoRemoteName
var projectRepoBranch;
var selectedProject;
return {
content: function(options) {
var container = $('<div class="projects-dialog-screen-start"></div>');
migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Clone a project").appendTo(body);
$('<p>').text("If you already have a git repository containing a project, you can clone it to get started.").appendTo(body);
var projectList = null;
var pendingFormValidation = false;
$.getJSON("projects", function(data) {
projectList = {};
data.projects.forEach(function(p) {
projectList[p] = true;
if (pendingFormValidation) {
pendingFormValidation = false;
validateForm();
}
})
});
var validateForm = function() {
var projectName = projectNameInput.val();
var valid = true;
if (projectNameInputChanged) {
if (projectList === null) {
pendingFormValidation = true;
return;
}
projectNameStatus.empty();
if (!/^[a-zA-Z0-9\-_]+$/.test(projectName) || projectList[projectName]) {
projectNameInput.addClass("input-error");
$('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>').appendTo(projectNameStatus);
projectNameValid = false;
valid = false;
if (projectList[projectName]) {
projectNameSublabel.text("Project already exists");
} else {
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
}
} else {
projectNameInput.removeClass("input-error");
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
projectNameValid = true;
}
projectNameLastChecked = projectName;
}
valid = projectNameValid;
var repo = projectRepoInput.val();
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) {
$("#projects-dialog-screen-create-project-repo-label small").text("Do not include the username/password in the url");
validRepo = false;
}
if (!validRepo) {
if (projectRepoChanged) {
projectRepoInput.addClass("input-error");
}
valid = false;
} else {
projectRepoInput.removeClass("input-error");
}
if (/^https?:\/\//.test(repo)) {
$(".projects-dialog-screen-create-row-creds").show();
$(".projects-dialog-screen-create-row-sshkey").hide();
} else if (/^(?:ssh|[\S]+?@[\S]+?):(?:\/\/)?/.test(repo)) {
$(".projects-dialog-screen-create-row-creds").hide();
$(".projects-dialog-screen-create-row-sshkey").show();
// if ( !getSelectedSSHKey(projectRepoSSHKeySelect) ) {
// valid = false;
// }
} else {
$(".projects-dialog-screen-create-row-creds").hide();
$(".projects-dialog-screen-create-row-sshkey").hide();
}
$("#projects-dialog-clone-project").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
}
var row;
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty projects-dialog-screen-create-row-clone"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-name">Project name</label>').appendTo(row);
var subrow = $('<div style="position:relative;"></div>').appendTo(row);
projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').appendTo(subrow);
var projectNameStatus = $('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
var projectNameInputChanged = false;
var projectNameLastChecked = "";
var projectNameValid;
var checkProjectName;
var autoInsertedName = "";
projectNameInput.on("change keyup paste",function() {
projectNameInputChanged = (projectNameInput.val() !== projectNameLastChecked);
if (checkProjectName) {
clearTimeout(checkProjectName);
} else if (projectNameInputChanged) {
projectNameStatus.empty();
$('<img src="red/images/spin.svg"/>').appendTo(projectNameStatus);
if (projectNameInput.val() === '') {
validateForm();
return;
}
}
checkProjectName = setTimeout(function() {
validateForm();
checkProjectName = null;
},300)
});
projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small");
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-repo">Git repository URL</label>').appendTo(row);
projectRepoInput = $('<input id="projects-dialog-screen-create-project-repo" type="text" placeholder="https://git.example.com/path/my-project.git"></input>').appendTo(row);
$('<label id="projects-dialog-screen-create-project-repo-label" class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row);
var projectRepoChanged = false;
var lastProjectRepo = "";
projectRepoInput.on("change keyup paste",function() {
projectRepoChanged = true;
var repo = $(this).val();
if (lastProjectRepo !== repo) {
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://");
}
lastProjectRepo = repo;
var m = /\/([^/]+?)(?:\.git)?$/.exec(repo);
if (m) {
var projectName = projectNameInput.val();
if (projectName === "" || projectName === autoInsertedName) {
autoInsertedName = m[1];
projectNameInput.val(autoInsertedName);
projectNameInput.change();
}
}
validateForm();
});
var cloneAuthRows = $('<div class="projects-dialog-screen-create-row"></div>').appendTo(body);
row = $('<div class="form-row projects-dialog-screen-create-row-auth-error"></div>').hide().appendTo(cloneAuthRows);
$('<div><i class="fa fa-warning"></i> Authentication failed</div>').appendTo(row);
// Repo credentials - username/password ----------------
row = $('<div class="hide form-row projects-dialog-screen-create-row-creds"></div>').hide().appendTo(cloneAuthRows);
var subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-user">Username</label>').appendTo(subrow);
projectRepoUserInput = $('<input id="projects-dialog-screen-create-project-repo-user" type="text"></input>').appendTo(subrow);
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-pass">Password</label>').appendTo(subrow);
projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
// -----------------------------------------------------
// Repo credentials - key/passphrase -------------------
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(cloneAuthRows);
subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH Key</label>').appendTo(subrow);
projectRepoSSHKeySelect = $("<select>",{style:"width: 100%"}).appendTo(subrow);
$.getJSON("settings/user/keys", function(data) {
var count = 0;
data.keys.forEach(function(key) {
projectRepoSSHKeySelect.append($("<option></option>").val(key.name).text(key.name));
count++;
});
if (count === 0) {
projectRepoSSHKeySelect.addClass("input-error");
projectRepoSSHKeySelect.attr("disabled",true);
sshwarningRow.show();
} else {
projectRepoSSHKeySelect.removeClass("input-error");
projectRepoSSHKeySelect.attr("disabled",false);
sshwarningRow.hide();
}
});
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-passphrase">Passphrase</label>').appendTo(subrow);
projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
subrow = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
var sshwarningRow = $('<div class="projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> Before you can clone a repository over ssh you must add an SSH key to access it.</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="editor-button">Add an ssh key</button>').appendTo(subrow).click(function(e) {
e.preventDefault();
$('#projects-dialog-cancel').click();
RED.userSettings.show('gitconfig');
setTimeout(function() {
$("#user-settings-gitconfig-add-key").click();
},500);
});
// -----------------------------------------------------
// Secret - clone
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body);
$('<label>Credentials encryption key</label>').appendTo(row);
projectSecretInput = $('<input type="password"></input>').appendTo(row);
return container;
},
buttons: function(options) {
return [
{
text: "Back",
click: function() {
show('git-config');
}
},
{
id: "projects-dialog-clone-project",
disabled: true,
text: "Clone project", // TODO: nls
class: "primary disabled",
click: function() {
var projectType = $(".projects-dialog-screen-create-type.selected").data('type');
var projectData = {
name: projectNameInput.val(),
}
projectData.credentialSecret = projectSecretInput.val();
var repoUrl = projectRepoInput.val();
var metaData = {};
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(repoUrl)) {
var selected = projectRepoSSHKeySelect.val();//false;//getSelectedSSHKey(projectRepoSSHKeySelect);
if ( selected ) {
projectData.git = {
remotes: {
'origin': {
url: repoUrl,
keyFile: selected,
passphrase: projectRepoPassphrase.val()
}
}
};
}
else {
console.log("Error! Can't get selected SSH key path.");
return;
}
}
else {
projectData.git = {
remotes: {
'origin': {
url: repoUrl,
username: projectRepoUserInput.val(),
password: projectRepoPasswordInput.val()
}
}
};
}
$(".projects-dialog-screen-create-row-auth-error").hide();
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://");
projectRepoUserInput.removeClass("input-error");
projectRepoPasswordInput.removeClass("input-error");
projectRepoSSHKeySelect.removeClass("input-error");
projectRepoPassphrase.removeClass("input-error");
RED.deploy.setDeployInflight(true);
RED.projects.settings.switchProject(projectData.name);
sendRequest({
url: "projects",
type: "POST",
handleAuthFail: false,
responses: {
200: function(data) {
dialog.dialog( "close" );
},
400: {
'project_exists': function(error) {
console.log("already exists");
},
'git_error': function(error) {
console.log("git error",error);
},
'git_connection_failed': function(error) {
projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Connection failed");
},
'git_not_a_repository': function(error) {
projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Not a git repository");
},
'git_repository_not_found': function(error) {
projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Repository not found");
},
'git_auth_failed': function(error) {
$(".projects-dialog-screen-create-row-auth-error").show();
projectRepoUserInput.addClass("input-error");
projectRepoPasswordInput.addClass("input-error");
// getRepoAuthDetails(req);
projectRepoSSHKeySelect.addClass("input-error");
projectRepoPassphrase.addClass("input-error");
},
'missing_flow_file': function(error) {
// This is handled via a runtime notification.
dialog.dialog("close");
},
'project_empty': function(error) {
// This is handled via a runtime notification.
dialog.dialog("close");
},
'credentials_load_failed': function(error) {
// This is handled via a runtime notification.
dialog.dialog("close");
},
'*': function(error) {
reportUnexpectedError(error);
$( dialog ).dialog( "close" );
}
}
}
},projectData).then(function() {
RED.events.emit("project:change", {name:name});
}).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
})
}
}
]
}
}
})(),
'default-files': (function() {
var projectFlowFileInput;
var projectCredentialFileInput;
@@ -275,9 +690,9 @@ RED.projects = (function() {
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Create your project files").appendTo(body);
$('<p>').text("A project contains your flow files, a README file, a package.json file and a settings file.").appendTo(body);
$('<p>').text("A project contains your flow files, a README file and a package.json file.").appendTo(body);
$('<p>').text("It can contain any other files you want to maintain in the Git repository.").appendTo(body);
if (!options.existingProject) {
if (!options.existingProject && RED.settings.files) {
$('<p>').text("Your existing flow and credential files will be copied into the project.").appendTo(body);
}
@@ -311,14 +726,14 @@ RED.projects = (function() {
var row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-file">Flow file</label>').appendTo(row);
var subrow = $('<div style="position:relative;"></div>').appendTo(row);
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || RED.settings.files.flow||"flow.json";
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || (RED.settings.files && RED.settings.files.flow)||"flow.json";
projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val(defaultFlowFile)
.on("change keyup paste",validateForm)
.appendTo(subrow);
$('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
$('<label class="projects-edit-form-sublabel"><small>*.json</small></label>').appendTo(row);
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || RED.settings.files.credentials||"flow_cred.json";
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || (RED.settings.files && RED.settings.files.credentials)||"flow_cred.json";
row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-credfile">Credentials file</label>').appendTo(row);
subrow = $('<div style="position:relative;"></div>').appendTo(row);
@@ -546,6 +961,7 @@ RED.projects = (function() {
} else {
show('create-success');
RED.menu.setDisabled('menu-item-projects-open',false);
RED.menu.setDisabled('menu-item-projects-settings',false);
}
},
400: {
@@ -564,8 +980,9 @@ RED.projects = (function() {
// getRepoAuthDetails(req);
console.log("git auth error",error);
},
'unexpected_error': function(error) {
console.log("unexpected_error",error)
'*': function(error) {
reportUnexpectedError(error);
$( dialog ).dialog( "close" );
}
}
}
@@ -614,6 +1031,7 @@ RED.projects = (function() {
var projectSecretSelect;
var copyProject;
var projectRepoInput;
var projectCloneSecret;
var emptyProjectCredentialInput;
var projectRepoUserInput;
var projectRepoPasswordInput;
@@ -682,7 +1100,11 @@ RED.projects = (function() {
var repo = projectRepoInput.val();
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
var validRepo = !/\s/.test(repo);
var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) {
$("#projects-dialog-screen-create-project-repo-label small").text("Do not include the username/password in the url");
validRepo = false;
}
if (!validRepo) {
if (projectRepoChanged) {
projectRepoInput.addClass("input-error");
@@ -691,15 +1113,15 @@ RED.projects = (function() {
} else {
projectRepoInput.removeClass("input-error");
}
if (/^(?:ssh|[\S]+?@[\S]+?):(?:\/\/)?/.test(repo)) {
if (/^https?:\/\//.test(repo)) {
$(".projects-dialog-screen-create-row-creds").show();
$(".projects-dialog-screen-create-row-sshkey").hide();
} else if (/^(?:ssh|[\S]+?@[\S]+?):(?:\/\/)?/.test(repo)) {
$(".projects-dialog-screen-create-row-creds").hide();
$(".projects-dialog-screen-create-row-sshkey").show();
// if ( !getSelectedSSHKey(projectRepoSSHKeySelect) ) {
// valid = false;
// }
} else if (/^https?:\/\//.test(repo)) {
$(".projects-dialog-screen-create-row-creds").show();
$(".projects-dialog-screen-create-row-sshkey").hide();
} else {
$(".projects-dialog-screen-create-row-creds").hide();
$(".projects-dialog-screen-create-row-sshkey").hide();
@@ -769,7 +1191,11 @@ RED.projects = (function() {
validateForm();
},
delete: function(project) {
if (projectList) {
delete projectList[project.name];
}
selectedProject = null;
validateForm();
}
}).appendTo(row);
@@ -971,10 +1397,12 @@ RED.projects = (function() {
// -----------------------------------------------------
// // Secret - clone
// row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
// $('<label>Credentials encryption key</label>').appendTo(row);
// projectSecretInput = $('<input type="text"></input>').appendTo(row);
// Secret - clone
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
$('<label>Credentials encryption key</label>').appendTo(row);
projectSecretInput = $('<input type="password"></input>').appendTo(row);
switch(options.screen||"empty") {
case "empty": createAsEmpty.click(); break;
case "open": openProject.click(); break;
@@ -1032,7 +1460,7 @@ RED.projects = (function() {
} else if (projectType === 'copy') {
projectData.copy = copyProject.name;
} else if (projectType === 'clone') {
// projectData.credentialSecret = projectSecretInput.val();
projectData.credentialSecret = projectSecretInput.val();
var repoUrl = projectRepoInput.val();
var metaData = {};
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(repoUrl)) {
@@ -1076,13 +1504,13 @@ RED.projects = (function() {
}
$(".projects-dialog-screen-create-row-auth-error").hide();
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://");
projectRepoUserInput.removeClass("input-error");
projectRepoPasswordInput.removeClass("input-error");
projectRepoSSHKeySelect.removeClass("input-error");
projectRepoPassphrase.removeClass("input-error");
RED.deploy.setDeployInflight(true);
RED.projects.settings.switchProject(projectData.name);
@@ -1122,6 +1550,10 @@ RED.projects = (function() {
projectRepoSSHKeySelect.addClass("input-error");
projectRepoPassphrase.addClass("input-error");
},
'missing_flow_file': function(error) {
// This is handled via a runtime notification.
dialog.dialog("close");
},
'project_empty': function(error) {
// This is handled via a runtime notification.
dialog.dialog("close");
@@ -1130,8 +1562,9 @@ RED.projects = (function() {
// This is handled via a runtime notification.
dialog.dialog("close");
},
'unexpected_error': function(error) {
console.log("unexpected_error",error)
'*': function(error) {
reportUnexpectedError(error);
$( dialog ).dialog( "close" );
}
}
}
@@ -1509,7 +1942,7 @@ RED.projects = (function() {
resultCallbackArgs = {error:responses.statusText};
return;
} else if (options.handleAuthFail !== false && xhr.responseJSON.error === 'git_auth_failed') {
var url = activeProject.git.remotes[options.remote||'origin'].fetch;
var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch;
var message = $('<div>'+
'<div class="form-row">Authentication required for repository:</div>'+
@@ -1517,7 +1950,10 @@ RED.projects = (function() {
'</div>');
var isSSH = false;
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
if (/^https?:\/\//.test(url)) {
$('<div class="form-row"><label for="projects-user-auth-username">Username</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">Password</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
isSSH = true;
var row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-key">SSH Key</label>').appendTo(row);
@@ -1535,9 +1971,6 @@ RED.projects = (function() {
row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-passphrase">Passphrase</label>').appendTo(row);
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
} else {
$('<div class="form-row"><label for="projects-user-auth-username">Username</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">Password</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
}
var notification = RED.notify(message,{
@@ -1575,7 +2008,7 @@ RED.projects = (function() {
}
sendRequest({
url: "projects/"+activeProject.name+"/remotes/"+(options.remote||'origin'),
url: "projects/"+activeProject.name+"/remotes/"+(xhr.responseJSON.remote||options.remote||'origin'),
type: "PUT",
responses: {
0: function(error) {
@@ -1738,8 +2171,17 @@ RED.projects = (function() {
},Math.max(300-(Date.now() - start),0));
},
400: {
'git_connection_failed': function(error) {
RED.notify(error.message,'error');
},
'git_not_a_repository': function(error) {
RED.notify(error.message,'error');
},
'git_repository_not_found': function(error) {
RED.notify(error.message,'error');
},
'unexpected_error': function(error) {
console.log(error);
reportUnexpectedError(error);
}
}
}
@@ -1782,11 +2224,12 @@ RED.projects = (function() {
RED.actions.add("core:new-project",RED.projects.newProject);
RED.actions.add("core:open-project",RED.projects.selectProject);
RED.actions.add("core:show-project-settings",RED.projects.settings.show);
var projectsAPI = {
sendRequest:sendRequest,
createBranchList:createBranchList,
addSpinnerOverlay:addSpinnerOverlay
addSpinnerOverlay:addSpinnerOverlay,
reportUnexpectedError:reportUnexpectedError
};
RED.projects.settings.init(projectsAPI);
RED.projects.userSettings.init(projectsAPI);
@@ -1808,6 +2251,43 @@ RED.projects = (function() {
createProjectOptions = {};
show('default-files',{existingProject: true});
}
function createDefaultPackageFile() {
RED.deploy.setDeployInflight(true);
RED.projects.settings.switchProject(activeProject.name);
var method = "PUT";
var url = "projects/"+activeProject.name;
var createProjectOptions = {
initialise: true
};
sendRequest({
url: url,
type: method,
requireCleanWorkspace: true,
handleAuthFail: false,
responses: {
200: function(data) { },
400: {
'git_error': function(error) {
console.log("git error",error);
},
'missing_flow_file': function(error) {
// This is a natural next error - but let the runtime event
// trigger the dialog rather than double-report it.
$( dialog ).dialog( "close" );
},
'*': function(error) {
reportUnexpectedError(error);
$( dialog ).dialog( "close" );
}
}
}
},createProjectOptions).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
})
}
function refresh(done) {
$.getJSON("projects",function(data) {
@@ -1887,6 +2367,7 @@ RED.projects = (function() {
RED.projects.settings.show('deps');
},
createDefaultFileSet: createDefaultFileSet,
createDefaultPackageFile: createDefaultPackageFile,
// showSidebar: showSidebar,
refresh: refresh,
editProject: function() {

View File

@@ -30,7 +30,6 @@ RED.sidebar.versionControl = (function() {
var unmergedContent;
var unmergedChangesList;
var commitButton;
var mergeConflictNotification;
var localChanges;
var localCommitList;
@@ -51,10 +50,6 @@ RED.sidebar.versionControl = (function() {
// done(error,null);
},
200: function(data) {
if (mergeConflictNotification) {
mergeConflictNotification.close();
mergeConflictNotification = null;
}
var title;
if (state === 'unstaged') {
title = 'Unstaged changes : '+entry.file
@@ -80,6 +75,11 @@ RED.sidebar.versionControl = (function() {
options.oldRev = "@";
options.newRev = ":0";
} else {
options.oldRevTitle = "Local";
options.newRevTitle = "Remote";
options.commonRev = ":1";
options.oldRev = ":2";
options.newRev = ":3";
options.onresolve = function(resolution) {
utils.sendRequest({
url: "projects/"+activeProject.name+"/resolve/"+encodeURIComponent(entry.file),
@@ -102,9 +102,7 @@ RED.sidebar.versionControl = (function() {
},{resolutions:resolution.resolutions[entry.file]});
}
}
options.oncancel = showMergeConflictNotification;
RED.diff.showUnifiedDiff(options);
// console.log(data.diff);
},
400: {
'unexpected_error': function(error) {
@@ -122,6 +120,18 @@ RED.sidebar.versionControl = (function() {
if (entry.label) {
row.addClass('node-info-none');
container.text(entry.label);
if (entry.button) {
container.css({
display: "inline-block",
maxWidth: "300px",
textAlign: "left"
})
var toolbar = $('<div style="float: right; margin: 5px; height: 50px;"></div>').appendTo(container);
$('<button class="editor-button editor-button-small"></button>').text(entry.button.label)
.appendTo(toolbar)
.click(entry.button.click);
}
return;
}
@@ -144,6 +154,7 @@ 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.", {
type: "warning",
@@ -178,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);
});
}
}
@@ -352,6 +368,7 @@ RED.sidebar.versionControl = (function() {
evt.stopPropagation();
var spinner = utils.addSpinnerOverlay(unmergedContent);
var activeProject = RED.projects.getActiveProject();
RED.deploy.setDeployInflight(true);
utils.sendRequest({
url: "projects/"+activeProject.name+"/merge",
type: "DELETE",
@@ -369,6 +386,10 @@ RED.sidebar.versionControl = (function() {
}
},
}
}).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
});
unmergedChangesList = $("<ol>",{style:"position: absolute; top: 30px; bottom: 0; right:0; left:0;"}).appendTo(unmergedContent);
@@ -376,6 +397,16 @@ RED.sidebar.versionControl = (function() {
addButton: false,
scrollOnAdd: false,
addItem: function(row,index,entry) {
if (entry === emptyMergedItem) {
entry.button = {
label: 'commit',
click: function(evt) {
evt.preventDefault();
evt.stopPropagation();
showCommitBox();
}
}
}
createChangeEntry(row,entry,entry.treeStatus,'unmerged');
},
sort: function(A,B) {
@@ -395,28 +426,32 @@ RED.sidebar.versionControl = (function() {
header = $('<div class="sidebar-version-control-change-header">Changes to commit</div>').appendTo(stagedContent);
bg = $('<div style="float: right"></div>').appendTo(header);
var showCommitBox = function() {
commitMessage.val("");
submitCommitButton.attr("disabled",true);
unstagedContent.css("height","30px");
if (unmergedContent.is(":visible")) {
unmergedContent.css("height","30px");
stagedContent.css("height","calc(100% - 60px - 175px)");
} else {
stagedContent.css("height","calc(100% - 30px - 175px)");
}
commitBox.show();
setTimeout(function() {
commitBox.css("height","175px");
},10);
stageAllButton.attr("disabled",true);
unstageAllButton.attr("disabled",true);
commitButton.attr("disabled",true);
abortMergeButton.attr("disabled",true);
commitMessage.focus();
}
commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">commit</button>')
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
evt.stopPropagation();
commitMessage.val("");
submitCommitButton.attr("disabled",true);
unstagedContent.css("height","30px");
if (unmergedContent.is(":visible")) {
unmergedContent.css("height","30px");
stagedContent.css("height","calc(100% - 60px - 175px)");
} else {
stagedContent.css("height","calc(100% - 30px - 175px)");
}
commitBox.show();
setTimeout(function() {
commitBox.css("height","175px");
},10);
stageAllButton.attr("disabled",true);
unstageAllButton.attr("disabled",true);
commitButton.attr("disabled",true);
commitMessage.focus();
showCommitBox();
});
unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> all</button>')
.appendTo(bg)
@@ -445,7 +480,7 @@ 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>')
var commitMessage = $('<textarea placeholder="Enter your commit message"></textarea>')
.appendTo(commitBox)
.on("change keyup paste",function() {
submitCommitButton.attr('disabled',$(this).val().trim()==="");
@@ -467,6 +502,8 @@ RED.sidebar.versionControl = (function() {
stageAllButton.attr("disabled",false);
unstageAllButton.attr("disabled",false);
commitButton.attr("disabled",false);
abortMergeButton.attr("disabled",false);
})
var submitCommitButton = $('<button class="editor-button">Commit</button>')
.appendTo(commitToolbar)
@@ -474,6 +511,7 @@ RED.sidebar.versionControl = (function() {
evt.preventDefault();
var spinner = utils.addSpinnerOverlay(submitCommitButton).addClass('projects-dialog-spinner-sidebar');
var activeProject = RED.projects.getActiveProject();
RED.deploy.setDeployInflight(true);
utils.sendRequest({
url: "projects/"+activeProject.name+"/commit",
type: "POST",
@@ -487,17 +525,18 @@ RED.sidebar.versionControl = (function() {
refresh(true);
},
400: {
'unexpected_error': function(error) {
console.log(error);
'*': function(error) {
utils.reportUnexpectedError(error);
}
},
}
},{
message:commitMessage.val()
});
}).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
})
})
@@ -511,7 +550,7 @@ RED.sidebar.versionControl = (function() {
.appendTo(bg)
.click(function(evt) {
evt.preventDefault();
refresh(true);
refresh(true,true);
})
var localBranchToolbar = $('<div class="sidebar-version-control-change-header" style="text-align: right;"></div>').appendTo(localHistory.content);
@@ -553,7 +592,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);
@@ -749,7 +791,13 @@ RED.sidebar.versionControl = (function() {
},
400: {
'git_connection_failed': function(error) {
RED.notify(error.message);
RED.notify(error.message,'error');
},
'git_not_a_repository': function(error) {
RED.notify(error.message,'error');
},
'git_repository_not_found': function(error) {
RED.notify(error.message,'error');
},
'unexpected_error': function(error) {
console.log(error);
@@ -823,7 +871,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({
@@ -835,6 +884,10 @@ 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();
},
@@ -854,54 +907,91 @@ RED.sidebar.versionControl = (function() {
});
});
var pullRemote = function(options) {
options = options || {};
var spinner = utils.addSpinnerOverlay(remoteBox).addClass("projects-dialog-spinner-contain");
var activeProject = RED.projects.getActiveProject();
var url = "projects/"+activeProject.name+"/pull";
if (activeProject.git.branches.remoteAlt) {
url+="/"+activeProject.git.branches.remoteAlt;
}
if (options.setUpstream || options.allowUnrelatedHistories) {
url+="?";
}
if (options.setUpstream) {
url += "setUpstream=true"
if (options.allowUnrelatedHistories) {
url += "&";
}
}
if (options.allowUnrelatedHistories) {
url += "allowUnrelatedHistories=true"
}
utils.sendRequest({
url: url,
type: "POST",
responses: {
0: function(error) {
console.log(error);
// 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);
},
'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")
},
'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>",{
type: 'error',
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
notification.close();
}
},{
text: 'Pull changes',
click: function() {
notification.close();
options.allowUnrelatedHistories = true;
pullRemote(options)
}
}
]
});
},
'*': function(error) {
utils.reportUnexpectedError(error);
}
},
}
},{}).always(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>')
.appendTo(row)
.click(function(e) {
e.preventDefault();
var spinner = utils.addSpinnerOverlay(remoteBox).addClass("projects-dialog-spinner-contain");
var activeProject = RED.projects.getActiveProject();
var url = "projects/"+activeProject.name+"/pull";
if (activeProject.git.branches.remoteAlt) {
url+="/"+activeProject.git.branches.remoteAlt;
}
if ($("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')) {
url+="?u=true"
}
utils.sendRequest({
url: url,
type: "POST",
responses: {
0: function(error) {
console.log(error);
// done(error,null);
},
200: function(data) {
refresh(true);
closeRemoteBox();
},
400: {
'git_local_overwrite': function(err) {
RED.notify("Unable to pull remote changes; your unstaged local changes would be overwritten. Commit your changes and try again."+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show unstaged changes'+'</a></p>',"error",false,10000000);
},
'git_pull_merge_conflict': function(err) {
refresh(true);
},
'git_connection_failed': function(err) {
RED.notify("Could not connect to remote repository: "+err.toString(),"warning")
},
'unexpected_error': function(error) {
console.log(error);
// done(error,null);
},
'git_pull_unrelated_history': function(error) {
RED.notify("Unable to pull remote changes; refusing to merge unrelated histories.","error");
}
},
}
},{}).always(function() {
spinner.remove();
pullRemote({
setUpstream: $("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')
});
});
@@ -1039,16 +1129,6 @@ RED.sidebar.versionControl = (function() {
// }
// }
function showMergeConflictNotification() {
if (isMerging) {
mergeConflictNotification = RED.notify("NLS: Automatic merging of remote changes failed. Fix the unmerged conflicts then commit the results."+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show merge conflicts'+'</a></p>',"error",true);
}
}
function refreshFiles(result) {
var files = result.files;
if (bulkChangeSpinner) {
@@ -1057,16 +1137,9 @@ RED.sidebar.versionControl = (function() {
}
isMerging = !!result.merging;
if (isMerging) {
if (!mergeConflictNotification) {
showMergeConflictNotification();
}
sidebarContent.addClass("sidebar-version-control-merging");
unmergedContent.show();
} else {
if (mergeConflictNotification) {
mergeConflictNotification.close();
mergeConflictNotification = null;
}
sidebarContent.removeClass("sidebar-version-control-merging");
unmergedContent.hide();
}
@@ -1173,7 +1246,7 @@ RED.sidebar.versionControl = (function() {
}
}
function refresh(full) {
function refresh(full, includeRemote) {
if (refreshInProgress) {
return;
}
@@ -1193,7 +1266,11 @@ RED.sidebar.versionControl = (function() {
var activeProject = RED.projects.getActiveProject();
if (activeProject) {
$.getJSON("projects/"+activeProject.name+"/status",function(result) {
var url = "projects/"+activeProject.name+"/status";
if (includeRemote) {
url += "?remote=true"
}
$.getJSON(url,function(result) {
refreshFiles(result);
$('#sidebar-version-control-local-branch').text(result.branches.local);
@@ -1237,6 +1314,8 @@ RED.sidebar.versionControl = (function() {
}
refreshInProgress = false;
$('.sidebar-version-control-shade').hide();
}).fail(function() {
refreshInProgress = false;
});
} else {
$('.sidebar-version-control-shade').show();

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

@@ -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

@@ -167,7 +167,7 @@ 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 {
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.node")+"</td><td></td></tr>").appendTo(tableBody);
@@ -175,10 +175,12 @@ RED.sidebar.info = (function() {
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);
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);
}
if (!m && node.type != "subflow" && node.type != "comment") {
@@ -206,7 +208,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);
@@ -236,19 +238,19 @@ RED.sidebar.info = (function() {
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,12 +471,12 @@ 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);
var newPath = path;
if (newPath) {
if (newPath !== undefined) {
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(keys[i])) {
newPath += (newPath.length > 0?".":"")+keys[i];
} else {
@@ -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

@@ -490,6 +490,7 @@ RED.view = (function() {
}
} else {
var subflow = RED.nodes.subflow(m[1]);
nn.name = "";
nn.inputs = subflow.in.length;
nn.outputs = subflow.out.length;
}

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

@@ -16,17 +16,16 @@
.node-dialog-view-diff-panel {
padding: 5px;
padding-top: 30px;
position: relative;
.red-ui-editableList-container {
border-radius:1px;
padding:0;
background: #f9f9f9;
}
.node-dialog-view-diff-diff {
position: absolute;
top:30px;
bottom:10px;
left:10px;
right:10px;
li {
background: #f9f9f9;
padding: 0px;
@@ -38,21 +37,20 @@
padding: 5px;
// padding-bottom: 5px;
}
&.node-dialog-view-diff-panel-merge {
.node-dialog-view-diff-diff {
top: 80px
}
.node-dialog-view-diff-headers {
top: 55px;
}
}
}
.node-diff-container {
position: absolute;
top: 40px;
right:0;
bottom: 0;
left: 0;
overflow-y: scroll;
}
.node-dialog-view-diff-headers {
position: absolute;
left:237px;
right:18px;
left:232px;
right:12px;
top: 5px;
height: 25px;
div {
@@ -76,11 +74,6 @@
}
.node-diff-toolbar {
position:absolute;
top:0;
left:0;
right:0;
height: 43px;
box-sizing: border-box;
color: #666;
text-align: right;
@@ -555,129 +548,129 @@ ul.node-dialog-configm-deploy-list {
.node-text-diff {
height: 100%;
overflow-y:auto;
table {
table.node-text-diff-content {
margin: 10px;
border: 1px solid $secondary-border-color;
border-radius: 3px;
table-layout: fixed;
width: calc(100% - 20px);
}
td {
vertical-align: top;
word-wrap: break-word;
}
td.lineno {
font-family: monospace;
text-align: right;
color: #aaa;
background: #f6f6f6;
padding: 1px 5px;
}
td.lineno:nth-child(3) {
border-left: 1px solid $secondary-border-color;
}
td.linetext {
font-family: monospace;
white-space: pre-wrap;
padding: 1px 5px;
span.prefix {
width: 30px;
display: inline-block;
text-align: center;
color: #999;
td {
vertical-align: top;
word-wrap: break-word;
}
}
td.blank {
background: #f6f6f6;
}
td.added {
background: #eefaee;
}
td.removed {
background: #fadddd;
}
tr.mergeHeader td {
color: #800080;
background: #e5f9ff;
height: 26px;
vertical-align: middle;
}
tr.mergeHeader-separator td {
color: #800080;
background: darken(#e5f9ff, 10%);
height: 0px;
}
tr.mergeHeader-ours td {
border-top: 2px solid darken(#e5f9ff, 10%);
}
tr.mergeHeader-theirs td {
border-bottom: 2px solid darken(#e5f9ff, 10%);
}
td.unchanged {
color: #999;
}
tr.unchanged {
background: #fefefe;
}
tr.start-block {
border-top: 1px solid #f0f0f0;
}
tr.end-block {
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-file-header td {
.filename {
td.lineno {
font-family: monospace;
text-align: right;
color: #aaa;
background: #f6f6f6;
padding: 1px 5px;
}
background: #f3f3f3;
padding: 5px 10px 5px 0;
color: #333;
cursor: pointer;
i.node-diff-chevron {
width: 30px;
td.lineno:nth-child(3) {
border-left: 1px solid $secondary-border-color;
}
}
tr.node-text-diff-file-header.collapsed {
td i.node-diff-chevron {
transform: rotate(-90deg);
td.linetext {
font-family: monospace;
white-space: pre-wrap;
padding: 1px 5px;
span.prefix {
width: 30px;
display: inline-block;
text-align: center;
color: #999;
}
}
}
tr.node-text-diff-commit-header td {
background: #f3f3f3;
padding: 5px 10px;
color: #333;
h3 {
font-size: 1.4em;
margin: 0;
td.blank {
background: #f6f6f6;
}
.commit-summary {
border-top: 1px solid $secondary-border-color;
padding-top: 5px;
td.added {
background: #eefaee;
}
td.removed {
background: #fadddd;
}
tr.mergeHeader td {
color: #800080;
background: #e5f9ff;
height: 26px;
vertical-align: middle;
}
tr.mergeHeader-separator td {
color: #800080;
background: darken(#e5f9ff, 10%);
height: 0px;
}
tr.mergeHeader-ours td {
border-top: 2px solid darken(#e5f9ff, 10%);
}
tr.mergeHeader-theirs td {
border-bottom: 2px solid darken(#e5f9ff, 10%);
}
td.unchanged {
color: #999;
}
.commit-body {
margin-bottom:15px;
white-space: pre;
line-height: 1.2em;
tr.unchanged {
background: #fefefe;
}
tr.start-block {
border-top: 1px solid #f0f0f0;
}
tr.end-block {
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-file-header td {
.filename {
font-family: monospace;
}
background: #f3f3f3;
padding: 5px 10px 5px 0;
color: #333;
cursor: pointer;
i.node-diff-chevron {
width: 30px;
}
}
tr.node-text-diff-file-header.collapsed {
td i.node-diff-chevron {
transform: rotate(-90deg);
}
}
tr.node-text-diff-commit-header td {
background: #f3f3f3;
padding: 5px 10px;
color: #333;
h3 {
font-size: 1.4em;
margin: 0;
}
.commit-summary {
border-top: 1px solid $secondary-border-color;
padding-top: 5px;
color: #999;
}
.commit-body {
margin-bottom:15px;
white-space: pre;
line-height: 1.2em;
}
}
tr.node-text-diff-header > td:not(.flow-diff) {
font-family: monospace;
padding: 5px 10px;
text-align: left;
color: #666;
background: #ffd;
height: 30px;
vertical-align: middle;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-expand td {
cursor: pointer;
&:hover {
background: #ffc;
}
}
}
tr.node-text-diff-header td {
font-family: monospace;
padding: 5px 10px;
text-align: left;
color: #666;
background: #ffd;
height: 30px;
vertical-align: middle;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
}
tr.node-text-diff-expand td {
cursor: pointer;
&:hover {
background: #ffc;
}
}
}

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

@@ -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;
@@ -501,9 +501,9 @@
top: 4px;
right: 4px;
display: none;
}
button {
width: 24px;
button {
width: 24px;
}
}
&:hover {

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 {

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

@@ -181,7 +181,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

@@ -68,7 +68,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

@@ -65,6 +65,8 @@ module.exports = function(RED) {
"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);}"+
@@ -91,6 +93,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 +204,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 +226,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

@@ -108,7 +108,7 @@
outstanding messages held by the node are cleared without being sent.</dd>
</dl>
<h3>Details</h3>
<p>When configured to delay messages, the delay interval can be a fixed value
<p>When configured to delay messages, the delay interval can be a fixed value,
a random value within a range or dynamically set for each message.</p>
<p>When configured to rate limit messages, their delivery is spread across
the configured time period. The status shows the number of messages currently in the queue.

View File

@@ -100,8 +100,6 @@ module.exports = function(RED) {
msg.payload = RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg);
}
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
if (node.duration === 0) { node.topics[topic].tout = 0; }
else if (node.loop === true) {
/* istanbul ignore else */
@@ -113,21 +111,25 @@ module.exports = function(RED) {
}
}
else {
node.topics[topic].tout = setTimeout(function() {
var msg2 = null;
if (node.op2type !== "nul") {
msg2 = RED.util.cloneMessage(msg);
if (node.op2type === "flow" || node.op2type === "global") {
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
if (!node.topics[topic].tout) {
node.topics[topic].tout = setTimeout(function() {
var msg2 = null;
if (node.op2type !== "nul") {
msg2 = RED.util.cloneMessage(msg);
if (node.op2type === "flow" || node.op2type === "global") {
node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
}
msg2.payload = node.topics[topic].m2;
delete node.topics[topic];
node.send(msg2);
}
msg2.payload = node.topics[topic].m2;
}
delete node.topics[topic];
node.status({});
node.send(msg2);
}, node.duration);
else { delete node.topics[topic]; }
node.status({});
}, node.duration);
}
}
node.status({fill:"blue",shape:"dot",text:" "});
if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
}
else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) {
/* istanbul ignore else */

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

@@ -179,7 +179,7 @@
<dt>payload <span class="property-type">number</span></dt>
<dd>the payload will be a 1 or a 0.</dd>
<dt>topic <span class="property-type">string</span></dt>
<dd>the topic will be set to `pi/{the pin number}`.</dd>
<dd>the topic will be set to <code>pi/{the pin number}</code>.</dd>
</dl>
<h3>Details</h3>
<p>You may also enable the input pullup resistor or the pulldown resistor.</p>

View File

@@ -142,9 +142,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 {

View File

@@ -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

@@ -75,7 +75,7 @@
<p>The node will listen on the configured path for requests of a particular type.
The path can be fully specified, such as <code>/user</code>, or include
named parameters that accept any value, such as <code>/user/:name</code>.
When named parameters are used, their actual value in a request can be accessed under `msg.req.params`.</p>
When named parameters are used, their actual value in a request can be accessed under <code>msg.req.params</code>.</p>
<p>For requests that include a body, such as a POST or PUT, the contents of
the request is made available as <code>msg.payload</code>.</p>
<p>If the content type of the request can be determined, the body will be parsed to

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">
@@ -117,7 +119,7 @@
the response headers. The next node will then use those headers for its request - this
is not usually the right thing to do. If <code>msg.headers</code> property is left unchanged
between nodes, it will be ignored by the second node. To set custom headers, <code>msg.headers</code>
should first be deleted or reset to an empty object: `{}`.
should first be deleted or reset to an empty object: <code>{}</code>.
<h4>Cookie handling</h4>
<p>The <code>cookies</code> property passed to the node must be an object of name/value pairs.
The value can be either a string to set the value of the cookie or it can be an

View File

@@ -108,6 +108,9 @@ module.exports = function(RED) {
}
}
}
if (msg.hasOwnProperty('followRedirects')) {
opts.followRedirects = msg.followRedirects;
}
if (msg.cookies) {
var cookies = [];
if (opts.headers.hasOwnProperty('cookie')) {
@@ -263,9 +266,8 @@ module.exports = function(RED) {
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
}
}
node.send(msg);
node.status({});
node.send(msg);
}
});
});
@@ -280,8 +282,8 @@ module.exports = function(RED) {
node.error(err,msg);
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code;
node.send(msg);
node.status({fill:"red",shape:"ring",text:err.code});
node.send(msg);
});
if (payload) {
req.write(payload);

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

@@ -52,6 +52,7 @@ module.exports = function(RED) {
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
});
client.setKeepAlive(true,120000);
connectionPool[id] = client;
client.on('data', function (data) {
@@ -123,7 +124,8 @@ module.exports = function(RED) {
clearTimeout(reconnectTimeout);
if (!node.connected) { done(); }
});
} else {
}
else {
var server = net.createServer(function (socket) {
socket.setKeepAlive(true,120000);
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
@@ -184,6 +186,7 @@ module.exports = function(RED) {
node.log(err);
});
});
server.on('error', function(err) {
if (err) {
node.error(RED._("tcpin.errors.cannot-listen",{port:node.port,error:err.toString()}));
@@ -237,6 +240,7 @@ module.exports = function(RED) {
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
});
client.setKeepAlive(true,120000);
client.on('error', function (err) {
node.log(RED._("tcpin.errors.error",{error:err.toString()}));
});
@@ -288,7 +292,8 @@ module.exports = function(RED) {
if (!node.connected) { done(); }
});
} else if (node.beserver == "reply") {
}
else if (node.beserver == "reply") {
node.on("input",function(msg) {
if (msg._session && msg._session.type == "tcp") {
var client = connectionPool[msg._session.id];
@@ -314,7 +319,8 @@ module.exports = function(RED) {
}
}
});
} else {
}
else {
var connectedSockets = [];
node.status({text:RED._("tcpin.status.connections",{count:0})});
var server = net.createServer(function (socket) {

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

@@ -70,8 +70,8 @@
}
},
"catch": {
"catch": "catch all",
"catchNodes": "catch (__number__)",
"catch": "catch: all",
"catchNodes": "catch: __number__",
"label": {
"source": "Catch errors from",
"node": "node",
@@ -86,8 +86,8 @@
}
},
"status": {
"status": "status (all)",
"statusNodes": "status (__number__)",
"status": "status: all",
"statusNodes": "status: __number__",
"label": {
"source": "Report status from",
"node": "node",
@@ -166,6 +166,8 @@
}
},
"exec": {
"exec": "exec",
"spawn": "spawn",
"label": {
"command": "Command",
"append": "Append",
@@ -184,6 +186,7 @@
"oldrc": "Use old style output (compatibility mode)"
},
"function": {
"function": "",
"label": {
"function": "Function",
"outputs": "Outputs"
@@ -195,6 +198,7 @@
"tip": "See the Info tab for help writing functions."
},
"template": {
"template": "template",
"label": {
"template": "Template",
"property": "Set property",
@@ -301,6 +305,7 @@
}
},
"comment": {
"comment": "comment",
"label": {
"title": "Title",
"body": "Body"
@@ -318,6 +323,7 @@
"broker": "Server",
"example": "e.g. localhost",
"qos": "QoS",
"retain": "Retain",
"clientid": "Client ID",
"port": "Port",
"keepalive": "Keep alive time (s)",
@@ -327,17 +333,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 +427,7 @@
}
},
"watch": {
"watch": "watch",
"label": {
"files": "File(s)",
"recursive": "Watch sub-directories recursively"
@@ -489,15 +501,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 +537,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 +551,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 +574,7 @@
"false":"is false",
"null":"is null",
"nnull":"is not null",
"istype":"is of type",
"head":"head",
"tail":"tail",
"index":"index between",
@@ -597,6 +613,7 @@
}
},
"range": {
"range": "range",
"label": {
"action": "Action",
"inputrange": "Map the input range",
@@ -663,7 +680,8 @@
"html": {
"label": {
"select": "Selector",
"output": "Output"
"output": "Output",
"in": "in"
},
"output": {
"html": "the html content of the elements",
@@ -763,7 +781,9 @@
"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",
@@ -782,6 +802,7 @@
}
},
"tail": {
"tail": "tail",
"label": {
"filename": "Filename",
"type": "File type",
@@ -835,6 +856,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 +868,7 @@
"addname":" Copy key to "
},
"join":{
"join": "join",
"mode":{
"mode":"Mode",
"auto":"automatic",
@@ -892,6 +915,7 @@
}
},
"sort" : {
"sort": "sort",
"target" : "Sort",
"seq" : "message sequence",
"key" : "Key",
@@ -905,6 +929,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>

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="change">
<p>メッセージフローコンテキストグローバルコンテキストのプロパティを変更削除移動します</p>
<p>ルールを複数指定した場合定義した順に適用します</p>
<h3>詳細</h3>
<p>利用可能な処理</p>
<dl class="message-properties">
<dt>代入</dt>
<dd>プロパティをセットします設定値にはさまざまな型の値メッセージやコンテキストの既存プロパティを利用できます<dd>
<dt>置換</dt>
<dd>プロパティに対して検索と置換を行います正規表現を指定した場合置換後の文字列には<code>$1</code></dd>
<dt>削除</dt>
<dd>プロパティを削除します</dd>
<dt>移動</dt>
<dd>プロパティの移動または名前の変更を行います</dd>
</dl>
<p>expressionには<a href="http://jsonata.org/" target="_new">JSONata</a></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="range">
<p>数値を異なる範囲の値に変換します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">数値</span></dt>
<dd>数値以外の場合は数値に変換します変換不能な場合はラーとなります</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd>新しい範囲に変換した結果の値</dd>
</dl>
<h3>詳細</h3>
<p>このノードは受け取った数値を線形スケーリングしますデフォルトでは結果の値はノードに設定した範囲内に限定しません</p>
<p><i>入力値の範囲外の値を最小値/最大値として拡大/縮小</i></p>
<p><i>入力値の範囲外の値を範囲幅で割った余りとし拡大/縮小</i></p>
</script>

View File

@@ -0,0 +1,137 @@
<!--
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="split">
<p>メッセージをメッセージ列に分割します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列 | 配列 | バッファ</span></dt>
<dd><code>msg.payload</code>
<ul>
<li><b>文字列</b>/<b>バッファ</b> - (: <code>\n</code>)</li>
<li><b>配列</b> - </li>
<li><b>オブジェクト</b> - /</li>
</ul>
</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>parts<span class="property-type">オブジェクト</span></dt>
<dd>元のメッセージをどのように分割したかに関する情報をこのプロパティに保持します例えば<b>join</b><code>parts</code>
<ul>
<li><code>id</code> - </li>
<li><code>index</code> - </li>
<li><code>count</code> - </li>
<li><code>type</code> - - ///</li>
<li><code>ch</code> - </li>
<li><code>key</code> -
ノードの設定によりキーを<code>msg.topic</code></li>
<li><code>len</code> - </li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>このノードはメッセージ列を構成するメッセージに対して共通処理を行い<b>join</b></p>
<p><code>msg.parts</code></p>
<h4>ストリームモード</h4>
<p>このノードはメッセージ列を再構成して送信する際にも有用です例えば改行終端のコマンドを送信するようなシリアルデバイスではメッセージの最後のコマンド部分が途切れたメッセージを送出する場合がありますストリームモードを用いることで完結した個別コマンドにメッセージを分割することができます入力メッセージの最後に未完部分がある場合<b>split</b></p>
<p>このモードで処理する際にはメッセージ数を予め知ることができないため<code>msg.parts.count</code><b>join</b></p>
</script>
<script type="text/x-red" data-help-name="join">
<p>メッセージ列を結合して一つのメッセージにします</p>
<p>メッセージの結合には次の3つのモードが利用できます</p>
<dl>
<dt>自動</dt>
<dd><b>split</b>split</dd>
<dt>手動</dt>
<dd>メッセージ列をさまざまな方法で結合します</dd>
<dt>列の集約</dt>
<dd>メッセージ列に対して指定した式を適用し1つのメッセージに集約します</dd>
</dl>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">parts<span class="property-type">オブジェクト</span></dt>
<dd>自動的にメッセージ列を結合するには全メッセージがこのプロパティを持っていなければなりません<b>split</b><code>parts</code>
<ul>
<li><code>id</code> - </li>
<li><code>index</code> - </li>
<li><code>count</code> - </li>
<li><code>type</code> - - string/array/object/buffer</li>
<li><code>ch</code> - </li>
<li><code>key</code> - </li>
<li><code>len</code> - </li>
</ul>
</dd>
<dt class="optional">complete</dt>
<dd>設定されている場合保持しているメッセージを結合して送信します</dd>
</dl>
<h3>詳細</h3>
<h4>自動モード</h4>
<p>自動モードでは入力メッセージの<code>parts</code><b>split</b></p>
<h4>手動モード</h4>
<p>手動モードではメッセージ列をさまざまな結果に結合できます</p>
<ul>
<li><b>文字列</b><b></b> - </li>
<li><b>配列</b> - </li>
<li><b>key/valueオブジェクト</b> - </li>
<li><b>統合オブジェクト</b> - </li>
</ul>
<p>出力メッセージのその他のプロパティはメッセージを送信する直前のメッセージをコピーします</p>
<p><i>合計値</i></p>
<p><i></i></p>
<p><code>msg.complete</code></p>
<h4>列の集約モード</h4>
<p>列の集約モードを選択するとメッセージ列を構成する各々のメッセージに対して式を適用し集約した値を用いて一つのメッセージを構成します</p>
<dl class="message-properties">
<dt>初期値</dt>
<dd>
集約の初期値(<code>$A</code>)
</dd>
<dt>集約式</dt>
<dd>メッセージグループを構成する各メッセージに適用するJSONata式
式の評価結果は次回の呼び出しの際に集約値として渡します
<ul>
<li><code>$A</code> </li>
<li><code>$I</code> </li>
<li><code>$N</code> </li>
</ul>
</dd>
<dt>最終調整式</dt>
<dd>メッセージグループの集約が完了した後で適用されるJSONata式任意で指定可能です式中では以下の特殊変数を参照できます
<ul>
<li><code>$A</code> </li>
<li><code>$N</code> </li>
</ul>
</dd>
<p>メッセージグループのメッセージに対しデフォルトでは集約式は最初のメッセージから最後のメッセージに対し順に適用します指定により適用を逆順にすることも可能です</p>
</dl>
<p><b>:</b>
<ul>
<li><b>集約式</b>: <code>$A+payload</code></li>
<li><b>初期値</b>: <code>0</code></li>
<li><b>最終調整式</b>: <code>$A/$N</code></li>
</ul>
</p>
<h4>メッセージの蓄積</h4>
<p>このノードの処理ではメッセージ列の処理のためメッセージを内部に蓄積します<code>nodeMessageBufferMaxLength</code></p>
</script>

View File

@@ -0,0 +1,40 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-help-name="sort">
<p>メッセージ列もしくは配列型のペイロードをソートします</p>
<p><b>split</b></p>
<p>ソート順序は以下が指定可能です</p>
<ul>
<li><b>昇順</b></li>
<li><b>降順</b></li>
</ul>
<p>数値による並べ替えを選択することもできます</p>
<p>メッセージの並べ替えを行うためのソートキーは<code>payload</code>JSONataJSONata</p>
<p>sortードの処理では受信したメッセージが<code>msg.parts</code>split<code>parts</code></p>
<p>
<ul>
<li><code>id</code> - </li>
<li><code>index</code> - </li>
<li><code>count</code> - </li>
</ul>
</p>
<p><b>:</b> 使
<ul>
<li><b>settings.js</b><code>nodeMessageBufferMaxLength</code></li>
</ul>
</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="batch">
<p>指定したルールによりメッセージ列を生成します</p>
<h3>詳細</h3>
<p>メッセージ列の生成には以下の3つのモードが利用できます</p>
<dl>
<dt>入力メッセージ数でグループ化</dt>
<dd>入力メッセージを指定した長さのメッセージ列にグループ化しますメッセージ列の最後の部分を次のメッセージ列の先頭で繰り返すメッセージ数を<b>オーバラップ</b></dd>
<dt>入力間隔()でグループ化</dt>
<dd>指定時間間隔内に受信した入力メッセージをメッセージ列にグループ化します指定した時間内にメッセージを受信しない場合に空のメッセージを送信するように設定することもできます</dd>
<dt>メッセージグループの結合</dt>
<dd>入力メッセージ列を結合し1つのメッセージ列にしますメッセージ列の識別のため各メッセージは<code>msg.topic</code><code>msg.parts</code><code>topic</code>batch
</dd>
</dl>
<h4>メッセージの蓄積</h4>
<p>このノードの処理ではメッセージ列の処理のためメッセージを内部に蓄積します<code>nodeMessageBufferMaxLength</code></p>
</script>

View File

@@ -234,7 +234,7 @@
"and": "回/",
"rate": "流量",
"msgper": "メッセージ/",
"dropmsg": "仲介メッセージを削除",
"dropmsg": "中間メッセージを削除",
"label": {
"delay": "delay",
"variable": "variable",
@@ -327,17 +327,22 @@
"verify-server-cert": "サーバの証明書を確認",
"compatmode": "旧MQTT 3.1のサポート"
},
"sections-label":{
"birth-message": "接続時の送信メッセージ(Birthメッセージ)",
"will-message":"予期しない切断時の送信メッセージ(Willメッセージ)",
"close-message":"切断前の送信メッセージ(Closeメッセージ)"
},
"tabs-label": {
"connection": "接続",
"security": "セキュリティ",
"will": "Willメッセージ",
"birth": "Birthメッセージ"
"messages": "メッセージ"
},
"placeholder": {
"clientid": "IDを自動生成する場合は、無記入にしてください",
"clientid-nonclean": "新規ではないセッションを設定してください",
"will-topic": "Willメッセージを無効化する場合は、無記入にしてください",
"birth-topic": "Birthメッセージを無効化する場合は、無記入にしてください"
"birth-topic": "Birthメッセージを無効化する場合は、無記入にしてください",
"close-topic": "Closeメッセージを無効化する場合は、無記入にしてください"
},
"state": {
"connected": "ブローカへ接続しました: __broker__",
@@ -488,14 +493,14 @@
"output": "出力",
"group": "グループ",
"interface": "ローカルIP",
"interfaceprompt": "(任意) 使用するローカルIPアドレス",
"send": "送信",
"toport": "ポート",
"address": "アドレス",
"decode-base64": "Base64形式のペイロードを復号"
},
"placeholder": {
"interface": "(任意) eth0のIPアドレス",
"interface": "(任意) 使用するローカルインターフェイスもしくはアドレス",
"interfaceprompt": "(任意) 使用するローカルインターフェイスもしくはアドレス",
"address": "宛先IPアドレス"
},
"udpmsgs": "UDPメッセージ",
@@ -523,10 +528,11 @@
"mc-group": "udpードがグループ __group__ へマルチキャストしました",
"listener-stopped": "udpードが待ち受けを停止しました",
"output-stopped": "udpードが出力を停止しました",
"mc-ready": "udpードはマルチキャストの準備ができています: __outport__ -> __host__:__port__",
"mc-ready": "udpードはマルチキャストの準備ができています: __iface__:__outport__ -> __host__:__port__",
"bc-ready": "udpードはブロードキャストの準備ができています: __outport__ -> __host__:__port__",
"ready": "udpードは準備ができています: __outport__ -> __host__:__port__",
"ready-nolocal": "udpードは準備ができています: __host__:__port__"
"ready-nolocal": "udpードは準備ができています: __host__:__port__",
"re-use": "udp再利用ソケット: __outport__ -> __host__:__port__"
},
"errors": {
"access-error": "UDP接続エラー 管理者権限で1024未満のポート番号にアクセスできる必要があります",
@@ -536,6 +542,8 @@
"ip-notset": "udp: IPアドレスが設定されていません",
"port-notset": "udp: ポートが設定されていません",
"port-invalid": "udp: ポート番号が不正です",
"alreadyused": "udp: 既に__port__番ポートが使用されています",
"ifnotfound": "udp: インターフェイス __iface__ がありません",
"alreadyused": "udp: 既にポートが使用されています"
}
},
@@ -661,7 +669,8 @@
"html": {
"label": {
"select": "抽出する要素",
"output": "出力"
"output": "出力",
"in": "対象:"
},
"output": {
"html": "要素内のHTML",
@@ -761,7 +770,9 @@
"status": {
"stopped": "停止",
"closed": "切断",
"not-running": "停止中"
"not-running": "停止中",
"not-available": "利用不可",
"na": "N/A : __value__"
},
"errors": {
"ignorenode": "Raspberry Pi固有のードを無視しました",

View File

@@ -0,0 +1,44 @@
<!--
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="csv">
<p>CSV形式の文字列とそのJavaScriptオブジェクト表現の間で双方向の変換を行います</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 配列 | 文字列</span></dt>
<dd>JavaScriptオブジェクト配列CSV文字列のいずれか</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 配列 | 文字列</span></dt>
<dd>
<ul>
<li>入力が文字列の場合CSVとして解釈しCSVの各行をキー/バリューとしたJavaScriptオブジェクトを生成します
各行毎にメッセージを送信するかオブジェクトの配列からなる一つのメッセージを送信するかを選択できます</li>
<li>入力がJavaScriptオブジェクトの場合CSV文字列への変換を行います</li>
<li>入力が基本型の配列の場合1行のCSV文字列へ変換します</li>
<li>入力が配列の配列もしくはオブジェクトの配列の場合複数行のCSV文字列へ変換します</li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>列名にカラム名のリストを指定することができますCSVからオブジェクトに変換を行う際カラム名をプロパティ名として使用します列名の代わりにCSVデータの1行目にカラム名を含めることもできます</p>
<p>CSVへの変換を行う際にはオブジェクトから取り出すべきプロパティとその順序を列名を参照して決めます</p>
<p>入力が配列の場合には列名はカラム名を表す行の出力指定がされた場合だけ用います</p>
<p><code>parts</code></p>
<p>CSVを複数のメッセージに変換して出力する場合出力がメッセージ列となるよう<code>parts</code></p>
<p><b>:</b> </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="html">
<p><code>msg.payload</code>HTMLCSS使</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">文字列</span></dt>
<dd>要素を取り出すHTML文字列</dd>
<dt class="optional">select <span class="property-type">文字列</span></dt>
<dd>編集パネルでセレクタを指定していない場合メッセージのプロパティとして設定できます</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">配列 | 文字列</span></dt>
<dd>結果はペイロードにマッチした要素の配列を含む単一メッセージもしくはマッチした要素毎のメッセージのいずれかを選択できます複数メッセージを送信する場合メッセージには<code>parts</code></dd>
</dl>
<h3>詳細</h3>
<p>このードはCSSおよびjQueryセレクタの組み合わせをサポートします利用可能な構文の詳細については<a href="https://github.com/fb55/CSSselect#user-content-supported-selectors" target="_blank">css-select documentation</a></p>
</script>

View File

@@ -0,0 +1,38 @@
<!--
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="json">
<p>JSON文字列とJavaScriptオブジェクトとの間で相互変換を行います</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>JavaScriptオブジェクトもしくはJSON文字列</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>
<ul>
<li>入力が文字列の場合JSONとして解釈しJavaScriptオブジェクトに変換します</li>
<li>入力がJavaScriptオブジェクトの場合JSON文字列に変換しますJSON文字列は整形することも可能です</li>
</ul>
</dd>
</dl>
<h3>詳細</h3>
<p>デフォルトの変換対象は<code>msg.payload</code></p>
<p>双方向の変換を自動選択するのではなく特定の変換のみ行うように設定できますこの機能は例えば<code>HTTP In</code>content-typeJSONJavaScript</p>
<p>JSON文字列への変換が指定されている場合受信した文字列に対してさらなるチェックは行いませんすなわち文字列がJSONとして正しいかどうかの検査や整形オプションを指定していたとしても整形処理を実施しません</p>
</script>

View File

@@ -0,0 +1,49 @@
<!--
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="xml">
<p>XML文字列とJavaScriptオブジェクトとの間で相互変換を行います</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>JavaScriptオブジェクトもしくはXML文字列</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>
<ul>
<li>入力が文字列の場合XMLとして解釈しJavaScriptオブジェクトに変換します</li>
<li>入力がJavaScriptオブジェクトの場合XML文字列に変換します</li>
</ul>
</dd>
<dt class="optional">options <span class="property-type">オブジェクト</span></dt>
<dd>内部で用いているXMLへの変換ライブラリに対してオプションを渡すことができます詳しくは<a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md#options" target="_blank">the xml2js docs</a></dd>
</dl>
<h3>詳細</h3>
<p>XMLとオブジェクトの間での変換を行う場合デフォルトではXML属性は<code>$</code>
テキストの内容は<code>_</code></p>
<p>例として以下のXMLの変換結果を示します</p>
<pre>&lt;p class="tag"&gt;Hello World&lt;/p&gt;</pre>
<pre>{
"p": {
"$": {
"class": "tag"
},
"_": "Hello World"
}
}</pre>
</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="yaml">
<p>YAML形式の文字列とJavaScriptオブジェクトの間で相互変換を行います</p>
<h3>入力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>JavaScriptオブジェクトもしくはYAML形式文字列</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">オブジェクト | 文字列</span></dt>
<dd>
<ul>
<li>入力がYAML形式の文字列の場合JavaScriptオブジェクトに変換します</li>
<li>入力がJavaScriptオブジェクトの場合YAML形式の文字列に変換します</li>
</ul>
</dd>
</dl>
</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="tail">
<p>設定したファイルの末尾を出力(追加されたデータを監視)します(Linux/Macのみ)</p>
<p>このノードは<b>tail -F</b>Windows</p>
<h3>出力</h3>
<ul>
<li>(UTF-8形式の)テキストファイルは文字列を返却</li>
<li>バイナルファイルはバッファオブジェクトを返却</li>
</ul>
</script>

View File

@@ -0,0 +1,55 @@
<!--
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="file">
<p><code>msg.payload</code></p>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">文字列</span></dt>
<dd>対象ファイル名をノードに設定していない場合このプロパティでファイルを指定できます</dd>
</dl>
<h3>詳細</h3>
<p>入力メッセージのペイロードをファイルの最後に追記します改行(\n)を各データの最後に追加することもできます</p>
<p><code>msg.filename</code>使</p>
<p>追記を行う代わりにファイル全体を上書きするように設定することもできます例えば画像のようなバイナリデータをファイルに書き出す場合はこのオプションを指定し改行を追記するオプションを指定しないようにします</p>
<p>この他ファイルの削除を行うことも可能です</p>
</script>
<script type="text/x-red" data-help-name="file in">
<p>ファイルの内容を文字列もしくはバイナリバッファとして読み出します</p>
<h3>入力</h3>
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">文字列</span></dt>
<dd>読み出し対象のファイル名をノードに設定していない場合このプロパティでファイルを指定できます</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">文字列 | バッファ</span></dt>
<dd>ファイルの内容を文字列もしくはバッファで表現します</dd>
<dt class="optional">filename <span class="property-type">文字列</span></dt>
<dd>読み出し対象のファイル名をノードに設定していない場合このプロパティでファイルを指定します</dd>
<dt class="optional">error <span class="property-type">オブジェクト</span></dt>
<dd><i>非推奨</i>: <code>payload</code><code>error</code></dd>
</dl>
<h3>詳細</h3>
<p>ファイルネームは絶対パスでの指定を推奨します絶対パスを指定しない場合はNode-REDプロセスのワーキングディレクトリからの相対パスとして扱います</p>
<p>Windowsではパスの区切り文字を(例えば<code>\\ユーザー\\名前</code>)</p>
<p>テキストファイルの場合行毎に分割して各々メッセージを送信することができますまたバイナリファイルの場合小さな塊のバッファに分割して送信できますバッファの分割単位はオペレーティングシステム依存ですが一般に64k(Linux/Mac)もしくは41k(Windows)です</p>
<p>複数のメッセージに分割する場合各メッセージには<code>parts</code></p>
<h4>旧式のエラー処理</h4>
<p>Node-RED 0.17より前の版ではファイルの読み込み時にエラーが発生すると<code>payload</code><code>error</code></p>
<p>エラーはcatchードで補足して処理することを推奨します</p>
</script>

View File

@@ -5,7 +5,8 @@
"topic": "主题",
"name": "名称",
"username": "用户名",
"password": "密码"
"password": "密码",
"property": "属性"
},
"status": {
"connected": "已连接",
@@ -13,7 +14,7 @@
"disconnected": "已断开",
"connecting": "连接中",
"error": "错误",
"ok": "确"
"ok": "确"
},
"notification": {
"error": "<strong>错误</strong>: __message__",
@@ -37,17 +38,17 @@
"repeat": "重复"
},
"timestamp": "时间戳",
"none": "空白",
"interval": "间隔",
"interval-time": "定时间内间隔",
"time": "定时间",
"none": "",
"interval": "周期性执行",
"interval-time": "定时间段周期性执行",
"time": "定时间",
"seconds": "秒",
"minutes": "分钟",
"hours": "小时",
"between": "介于",
"previous": "之前数值",
"at": "在",
"and": "之间",
"and": "",
"every": "每隔",
"days": [
"星期一",
@@ -59,18 +60,20 @@
"星期天"
],
"on": "在",
"onstart": "运行时注入?",
"tip": "<b>注意:</b> \"特定时间内间隔\" 和 \"特定时间\" 会使用cron系统.<br/> 详情查看信息页.",
"onstart": "立刻执行于",
"onceDelay": "秒后, 此后",
"tip": "<b>注意:</b> \"指定时间段周期性执行\" 和 \"指定时间\" 会使用cron系统.<br/> 详情查看信息页.",
"success": "成功注入: __label__",
"errors": {
"failed": "注入失败, 请查看日志"
"failed": "注入失败, 请查看日志",
"toolong": "周期过长"
}
},
"catch": {
"catch": "检测异常",
"catchNodes": "检测到 (__number__)",
"catch": "监测所有节点",
"catchNodes": "监测__number__个节点",
"label": {
"source": "检测错误来自",
"source": "监测范围",
"node": "节点",
"type": "类型",
"selectAll": "全选",
@@ -79,14 +82,14 @@
},
"scope": {
"all": "所有节点",
"selected": "已选节点"
"selected": "指定节点"
}
},
"status": {
"status": "状态 (所有)",
"statusNodes": "状态显示 (__number__)",
"status": "报告所有节点状态",
"statusNodes": "报告__number__个节点状态",
"label": {
"source": "状态报告来自",
"source": "报告状态范围",
"node": "节点",
"type": "类型",
"selectAll": "全选",
@@ -95,7 +98,7 @@
},
"scope": {
"all": "所有节点",
"selected": "已选节点"
"selected": "指定节点"
}
},
"debug": {
@@ -104,7 +107,11 @@
"msgobj": "完整信息",
"to": "目标",
"debtab": "调试窗口",
"tabcon": "调试窗口及终端控制台",
"tabcon": "调试窗口及Console",
"toSidebar": "调试窗口",
"toConsole": "Console",
"toStatus": "节点状态 (32位字符)",
"severity": "级别",
"notification": {
"activated": "成功激活: __label__",
"deactivated": "成功取消: __label__"
@@ -114,21 +121,21 @@
"name": "名称",
"filterAll": "所有节点",
"filterSelected": "已选节点",
"filterCurrent": "前流程",
"filterCurrent": "前流程",
"debugNodes": "调试节点",
"clearLog": "清日志",
"clearLog": "清日志",
"openWindow": "在新窗口打开"
},
"messageMenu": {
"collapseAll": "折叠所有路径",
"clearPinned": "清已固定路径",
"clearPinned": "清已固定路径",
"filterNode": "过滤此节点",
"clearFilter": "清除已设过滤"
"clearFilter": "清空过滤条件"
}
},
"link": {
"linkIn": "连接入口",
"linkOut": "连接出口",
"linkIn": "输入",
"linkOut": "输出",
"label": {
"event": "事件名称",
"node": "节点名称",
@@ -144,16 +151,18 @@
"upload": "上传",
"cert": "证书",
"key": "私钥",
"passphrase": "密码",
"ca": "CA证书",
"verify-server-cert":"验证服务器证书"
},
"placeholder": {
"cert":"证书路径 (PEM 格式)",
"key":"私路径 (PEM 格式)",
"ca":"CA证书路径 (PEM 格式)"
"key":"私路径 (PEM 格式)",
"ca":"CA证书路径 (PEM 格式)",
"passphrase":"私钥密码 (可选)"
},
"error": {
"missing-file": "证书/密文件提供"
"missing-file": "未提供证书/密文件"
}
},
"exec": {
@@ -169,10 +178,10 @@
"extraparams": "额外的输入参数"
},
"opt": {
"exec": "当命令任务完成时 - exec 模式",
"spawn": "当命令任务进行时 - spawn 模式"
"exec": "当命令完成时 - exec模式",
"spawn": "当命令进行时 - spawn模式"
},
"oldrc": "使用旧式输出模式 (传统模式)"
"oldrc": "使用旧式输出 (兼容模式)"
},
"function": {
"label": {
@@ -180,7 +189,7 @@
"outputs": "输出"
},
"error": {
"inputListener":"无法在函数里面加入对‘注入事件的监视",
"inputListener":"无法在函数中监听对'注入'事件",
"non-message-returned":"函数节点尝试返回类型为 __type__ 的信息"
},
"tip": "可从信息页面查看更多关于如何编写函数的帮助"
@@ -194,7 +203,8 @@
"output": "输出为",
"mustache": "Mustache 模版",
"plain": "纯文本",
"json": "解析JSON",
"json": "JSON",
"yaml": "YAML",
"none": "无"
},
"templatevalue": "This is the payload: {{payload}} !"
@@ -204,13 +214,13 @@
"for": "时长",
"delaymsg": "延迟每一条信息",
"delayfixed": "固定延迟时间",
"delayvarmsg": "msg.delay写延迟时长",
"delayvarmsg": "允许msg.delay写延迟时长",
"randomdelay": "随机延迟",
"limitrate": "信息速度限制",
"limitrate": "限制信息速",
"limitall": "所有信息",
"limittopic": "每一个 msg.topic",
"fairqueue": "轮流发每一个主题",
"timedqueue": "发所有主题",
"limittopic": "每一个msg.topic",
"fairqueue": "依次发送每一个topic",
"timedqueue": "发所有topic",
"milisecs": "毫秒",
"secs": "秒",
"sec": "秒",
@@ -218,10 +228,10 @@
"min": "分",
"hours": "小时",
"hour": "小时",
"days": "",
"day": "",
"days": "",
"day": "",
"between": "介于",
"and": "",
"and": "",
"rate": "速度",
"msgper": "信息 每",
"dropmsg": "不传输中间信息",
@@ -245,14 +255,14 @@
"singular": "小时"
},
"day": {
"plural" : "",
"singular": ""
"plural" : "",
"singular": ""
}
}
},
"error": {
"buffer": "缓冲超过 1000 条信息",
"buffer1": "缓冲超过 10000 条信息"
"buffer": "缓冲超过 1000 条信息",
"buffer1": "缓冲超过 10000 条信息"
}
},
"trigger": {
@@ -267,9 +277,9 @@
"latest": "最新信息对象",
"nothing": "无"
},
"wait-reset": "等待重置",
"wait-reset": "等待重置",
"wait-for": "等待",
"wait-loop": "重发",
"wait-loop": "周期性重发",
"duration": {
"ms": "毫秒",
"s": "秒",
@@ -279,11 +289,11 @@
"extend": " 如有新信息,延长延迟",
"label": {
"trigger": "触发",
"trigger-block": "发并阻止",
"trigger-loop": "重发",
"trigger-block": "发并阻止",
"trigger-loop": "周期性重发",
"reset": "重置触发节点条件 如果:",
"resetMessage":"msg.reset 已设置",
"resetPayload":"msg.payload 等于",
"resetMessage":"msg.reset已设置",
"resetPayload":"msg.payload等于",
"resetprompt": "可选填"
}
},
@@ -292,7 +302,7 @@
"title": "标题",
"body": "主体"
},
"tip": "提示: 主题内容可以添加格式化为 <a href=\"https://help.github.com/articles/markdown-basics/\" target=\"_blank\">Github 风格 Markdown</a>"
"tip": "提示: 主题内容可格式化为 <a href=\"https://help.github.com/articles/markdown-basics/\" target=\"_blank\">Github风格Markdown</a>"
},
"unknown": {
"label": {
@@ -307,24 +317,24 @@
"qos": "QoS",
"clientid": "客户端ID",
"port": "端口",
"keepalive": "存货定时器(秒)",
"keepalive": "Keepalive计时(秒)",
"cleansession": "使用新的会话",
"use-tls": "使用安全连接 (SSL/TLS)",
"tls-config":"TLS 设置",
"verify-server-cert":"验证服务器证书",
"compatmode": "使用旧式 MQTT 3.1 支持"
"compatmode": "使用旧式MQTT 3.1支持"
},
"tabs-label": {
"connection": "连接",
"security": "安全",
"will": "终结信息",
"birth": "初始信息"
"will": "Will信息",
"birth": "Birth信息"
},
"placeholder": {
"clientid": "留空白将会自动生成",
"clientid": "留白则自动生成",
"clientid-nonclean":"如非新会话必须设置客户端ID",
"will-topic": "留白将禁止终止信息",
"birth-topic": "留白将禁止初始信息"
"will-topic": "留白将禁止Will信息",
"birth-topic": "留白将禁止Birth信息"
},
"state": {
"connected": "已连接到服务端: __broker__",
@@ -334,7 +344,7 @@
"retain": "保留",
"true": "是",
"false": "否",
"tip": "提示: 如果你想用msg属性来设置主题qos 或者是否保存,请将这几个区域留空",
"tip": "提示: 若希望通过msg属性对topic(信息), qos及retain(保留)进行设置, 则将上述项留白",
"errors": {
"not-defined": "主题未设置",
"missing-config": "未设置服务端",
@@ -344,13 +354,13 @@
},
"httpin": {
"label": {
"method": "方法",
"method": "请求方式",
"url": "URL",
"doc": "文档",
"return": "返回",
"upload": "接受文件上传?",
"status": "状态码",
"headers": "头子段",
"headers": "Header",
"other": "其他"
},
"setby": "- 用 msg.method 设定 -",
@@ -358,21 +368,21 @@
"use-tls": "使用安全连接 (SSL/TLS) ",
"tls-config":"TLS 设置",
"utf8": "UTF-8 字符串",
"binary": "二进制缓冲模块",
"json": "解析JSON对象",
"binary": "二进制数据",
"json": "JSON对象",
"tip": {
"in": "相对URL",
"res": "发送到此节点的消息<b>必须</b>来自 <i>http input</i> 节点",
"res": "发送到此节点的消息<b>必须</b>来自<i>http input</i>节点",
"req": "提示如果JSON解析失败则获取的字符串将按原样返回."
},
"httpreq": "http 请求",
"errors": {
"not-created": "当httpNodeRoot为否时无法创建 http-in 节点",
"not-created": "当httpNodeRoot为否时无法创建http-in节点",
"missing-path": "无路径",
"no-response": "无响应对象",
"json-error": "JSON 解析错误",
"no-url": "未设定 URL",
"deprecated-call":"__method__ 方法已弃用",
"deprecated-call":"__method__方法已弃用",
"invalid-transport":"非HTTP传输请求"
},
"status": {
@@ -387,13 +397,14 @@
},
"listenon": "监听",
"connectto": "连接",
"payload": "发送/接受 有效载荷",
"message": "发送/接受 完整信息",
"sendrec": "发送/接受",
"payload": "有效载荷",
"message": "完整信息",
"tip": {
"path1": "默认情况下,<code> payload </code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.",
"path1": "默认情况下,<code>payload</code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.",
"path2": "这条路径将相对于 ",
"url1": "URL 应该使用 ws:&#47;&#47; 或者 wss:&#47;&#47; 方案并指向现有的websocket侦听器.",
"url2": "默认情况下,<code> payload </code>将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象."
"url1": "URL 应该使用ws:&#47;&#47;或者wss:&#47;&#47;方案并指向现有的websocket侦听器.",
"url2": "默认情况下,<code>payload</code> 将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象."
},
"errors": {
"connect-error": "ws连接发生了错误: ",
@@ -403,8 +414,8 @@
},
"watch": {
"label": {
"files": "文件(s)",
"recursive": "递归查看文件夹"
"files": "文件",
"recursive": "递归所有子文件夹"
},
"placeholder": {
"files": "逗号分开文件或文件夹"
@@ -416,8 +427,8 @@
"type": "类型",
"output": "输出",
"port": "端口",
"host": "主服务器",
"payload": "有效载荷(s)",
"host": "主机地址",
"payload": "有效载荷",
"delimited": "分隔符号",
"close-connection": "是否在成功发送每条信息后断开连接?",
"decode-base64": "用 Base64 解码信息?",
@@ -429,19 +440,19 @@
"type": {
"listen": "监听",
"connect": "连接",
"reply": "回应到 TCP"
"reply": "响应 TCP"
},
"output": {
"stream": "字串流",
"single": "单一",
"buffer": "缓冲模块",
"buffer": "Buffer",
"string": "字符串",
"base64": "Base64 字符串"
},
"return": {
"timeout": "在固定时间超时后",
"character": "当收到某个字符",
"number": "固定数目的字符",
"timeout": "定时间后",
"character": "当收到某个字符",
"number": "指定字符",
"never": "永不 - 保持连接",
"immed": "马上 - 不需要等待回复"
},
@@ -452,8 +463,8 @@
"stopped-listening": "已停止监听端口",
"connection-from": "连接来自 __host__:__port__",
"connection-closed": "连接已关闭 __host__:__port__",
"connections": "__count__ 连接",
"connections_plural": "__count__ 连接"
"connections": "__count__ 连接",
"connections_plural": "__count__ 连接"
},
"errors": {
@@ -463,7 +474,7 @@
"error": "错误: __error__",
"socket-error": "套接字连接错误来自 __host__:__port__",
"no-host": "主服务器和/或者端口未设定",
"no-host": "主机地址或端口未设定",
"connect-timeout": "连接超时",
"connect-fail": "连接失败"
}
@@ -476,23 +487,23 @@
"output": "输出",
"group": "组",
"interface": "本地IP",
"interfaceprompt": "(可选)本地 IP 绑定到",
"interfaceprompt": "(可选)本地 IP 绑定到",
"send": "发送一个",
"toport": "到端口",
"address": "地址",
"decode-base64": "是否解码编码为Base64的信息?"
"decode-base64": "是否解码Base64编码的信息?"
},
"placeholder": {
"interface": "(可选eth0 的 ip 地址",
"address": "目的地 ip 地址"
"interface": "可选eth0的IP地址",
"address": "目标IP地址"
},
"udpmsgs": "udp 信息",
"udpmsgs": "udp信息",
"mcmsgs": "组播信息",
"udpmsg": "udp 信息",
"udpmsg": "udp信息",
"bcmsg": "广播信息",
"mcmsg": "组播信息",
"output": {
"buffer": "缓冲模块",
"buffer": "Buffer",
"string": "字符串",
"base64": "Base64编码字符串"
},
@@ -503,8 +514,8 @@
},
"tip": {
"in": "提示:确保您的防火墙将允许数据进入",
"out": "提示:如果要使用<code> msg.ip </code>和<code> msg.port </code>设置,请将地址和端口留空",
"port": "端口已在使用: "
"out": "提示:如果要使用<code>msg.ip</code>和<code>msg.port</code>设置,请将地址和端口留空",
"port": "在使用端口: "
},
"status": {
"listener-at": "udp 监听器正在监听 __host__:__port__",
@@ -514,72 +525,79 @@
"mc-ready": "udp 组播已准备好: __outport__ -> __host__:__port__",
"bc-ready": "udp 广播已准备好: __outport__ -> __host__:__port__",
"ready": "udp 已准备好: __outport__ -> __host__:__port__",
"ready-nolocal": "udp 已准备好: __host__:__port__"
"ready-nolocal": "udp 已准备好: __host__:__port__",
"re-use": "udp 重用套接字: __outport__ -> __host__:__port__"
},
"errors": {
"access-error": "UDP 访问错误, 你可能需要root权限才能接入1024以下的端口",
"error": "错误: __error__",
"bad-mcaddress": "无效的组播地址",
"interface": "必须是需要接口的 ip 地址",
"ip-notset": "udp: ip 地址未设定",
"interface": "必须是指定接口的IP地址",
"ip-notset": "udp: IP地址未设定",
"port-notset": "udp: 端口未设定",
"port-invalid": "udp: 无效端口号码",
"alreadyused": "udp: 端口已经在使用"
"alreadyused": "udp: 端口已被占用"
}
},
"switch": {
"label": {
"property": "属性",
"rule": "规"
"rule": "规",
"repair" : "重建信息队列"
},
"and": "",
"and": "",
"checkall": "全选所有规则",
"stopfirst": "接受第一条匹配信息后停止",
"ignorecase": "忽大小写",
"ignorecase": "忽大小写",
"rules": {
"btwn":"在之间",
"cont":"包含",
"regex":"匹配正则表达式",
"true":"为真",
"false":"为假",
"null":"为空",
"nnull":"非空",
"null":"为空",
"nnull":"非空",
"head":"head",
"tail":"tail",
"index":"index between",
"exp":"JSONata表达式",
"else":"除此以外"
},
"errors": {
"invalid-expr": "无效 JSONata 表达: __error__"
"invalid-expr": "无效JSONata表达: __error__",
"too-many" : "Switch节点中有太多待定信息"
}
},
"change": {
"label": {
"rules": "规",
"rule": "规",
"rules": "规",
"rule": "规",
"set": "设定 __property__",
"change": "改 __property__",
"change": "改 __property__",
"delete": "删除 __property__",
"move": "移动 __property__",
"changeCount": "改: __count__ 条规矩",
"regex": "用正则表达式"
"changeCount": "改: __count__条规矩",
"regex": "使用正则表达式"
},
"action": {
"set": "设定",
"change": "改",
"change": "改",
"delete": "删除",
"move": "转移",
"to": "到",
"search": "搜索",
"replace": "更改为"
"replace": "替代为"
},
"errors": {
"invalid-from": "无效来源 from 属性: __error__",
"invalid-json": "无效 to 属性",
"invalid-expr": "无效 JSONata 表示: __error__"
"invalid-from": "无效的'from'属性: __error__",
"invalid-json": "无效的'to'JSON 属性",
"invalid-expr": "无效JSONata表达式: __error__"
}
},
"range": {
"label": {
"action": "行为作用",
"inputrange": "映射输入数据范围",
"action": "操作",
"inputrange": "映射输入数据",
"resultrange": "至目标范围",
"from": "从",
"to": "到",
@@ -591,26 +609,28 @@
"maxout": "e.g. 255"
},
"scale": {
"payload": "按比例 msg.payload",
"payload": "按比例msg.payload",
"limit": "按比例并设定界限至目标范围",
"wrap": "按比例并包含在目标范围内"
},
"tip": "提示: 此节点仅对数字有效",
"errors": {
"notnumber": "不是一个数"
"notnumber": "不是一个数"
}
},
"csv": {
"label": {
"columns": "列",
"separator": "分隔符",
"c2o": "CSV 至对象选项",
"o2c": "对象至 to CSV 选项",
"separator": "分隔符",
"c2o": "CSV至对象",
"o2c": "对象至CSV",
"input": "输入",
"skip-s": "忽略前",
"skip-e": "行",
"firstrow": "第一行包含列名",
"output": "输出",
"includerow": "包含列名行",
"newline": "新的一行"
"newline": "换行符"
},
"placeholder": {
"columns": "用逗号分割列名"
@@ -625,8 +645,8 @@
"other": "其他..."
},
"output": {
"row": "每行包含一条信息",
"array": "一条单独信息 [数组]"
"row": "每行一条信息",
"array": "一条信息 [数组]"
},
"newline": {
"linux": "Linux (\\n)",
@@ -634,8 +654,8 @@
"windows": "Windows (\\r\\n)"
},
"errors": {
"csv_js": "此节点仅处理 CSV 字符串或 js 对象",
"obj_csv": "对象 -> CSV 转换未设定列模版"
"csv_js": "此节点仅处理CSV字符串或JS对象",
"obj_csv": "对象->CSV转换未设定列模版"
}
},
"html": {
@@ -644,13 +664,13 @@
"output": "输出"
},
"output": {
"html": "选定元素的 html 内容",
"html": "选定元素的html内容",
"text": "选定元素的纯文本内容",
"attr": "选定元素的所有属性对象"
"attr": "包含选定元素的所有属性对象"
},
"format": {
"single": "由一个单独信息包含一个数组",
"multi": "多条信息,每一条包含一个元素"
"single": "一条信息 [数组]",
"multi": "多条信息,每一个元素"
}
},
"json": {
@@ -660,8 +680,15 @@
"dropped-error": "转换有效负载失败"
},
"label": {
"o2j": "对象至 JSON 选项",
"pretty": "格式化 JSON 字符串"
"o2j": "对象至JSON",
"pretty": "格式化JSON字符串",
"action": "操作",
"property": "属性",
"actions": {
"toggle": "JSON字符串与对象互转",
"str":"总是转为JSON字符串",
"obj":"总是转为JS对象"
}
}
},
"yaml": {
@@ -687,14 +714,14 @@
"gpiopin": "GPIO",
"selectpin": "选择引脚",
"resistor": "电阻?",
"readinitial": "在部署/重新启动时读取引脚的初始状态?",
"readinitial": "在部署/重时读取引脚的初始状态?",
"type": "类型",
"initpin": "初始化引脚状态?",
"debounce": "去抖动",
"freq": "频率",
"button": "按钮",
"pimouse": "Pi 鼠标",
"pikeyboard": "Pi 键盘",
"pimouse": "Pi鼠标",
"pikeyboard": "Pi键盘",
"left": "左",
"right": "右",
"middle": "中"
@@ -705,21 +732,21 @@
"pulldown": "下拉电阻"
},
"digout": "数字输出",
"pwmout": "PWM 输出",
"pwmout": "PWM输出",
"servo": "伺服输出",
"initpin0": "初始引脚电平 - 低 (0)",
"initpin1": "初始引脚电平 - 高 (1)",
"initpin0": "初始引脚电平 - 低(0)",
"initpin1": "初始引脚电平 - 高(1)",
"left": "左",
"right": "右",
"middle": "中",
"any": "任何",
"pinname": "引脚",
"alreadyuse": "已经在用",
"alreadyset": "已经设定为",
"alreadyuse": "已被使用",
"alreadyset": "已被设为",
"tip": {
"pin": "<b>引脚在使用</b>: ",
"in": "提示: 仅接受数字输入 - 输出必须为 0 或 1.",
"dig": "提示: 如用数字输出 - 输入必须为 0 或 1.",
"pin": "<b>在使用引脚</b>: ",
"in": "提示: 仅接受数字输入 - 输出必须为0或1.",
"dig": "提示: 如用数字输出 - 输入必须为0或1.",
"pwm": "提示: 如用PWM输出 - 输入必须为0至100之间; 如用高频率可能会比预期占用更多CPU资源.",
"ser": "<b>提示</b>: 如用伺服输出 - 输入必须为0至100之间. 50为中间值."
},
@@ -728,7 +755,7 @@
"input": "输入",
"pullup": "含有上拉电阻的输入",
"pulldown": "含有下拉电阻的输入",
"pwmout": "PWM 输出",
"pwmout": "PWM输出",
"servo": "伺服输出"
},
"status": {
@@ -740,27 +767,27 @@
"ignorenode": "忽略树莓派的特定节点",
"version": "版本命令失败",
"sawpitype": "查看Pi类型",
"libnotfound": "找不到树莓派 RPi.GPIO python库",
"alreadyset": "GPIO 引脚 __pin__ 已经被设定为类型: __type__",
"invalidpin": "无效 GPIO 引脚",
"libnotfound": "找不到树莓派RPi.GPIOpython库",
"alreadyset": "GPIO引脚 __pin__ 已经被设定为类型: __type__",
"invalidpin": "无效GPIO引脚",
"invalidinput": "无效输入",
"needtobeexecutable": "__command__ 需要为可运行命令",
"mustbeexecutable": "nrgpio 需要为可运行",
"commandnotfound": "nrgpio 命令不存在",
"commandnotexecutable": "nrgpio 命令无法运行",
"needtobeexecutable": "__command__为可运行命令",
"mustbeexecutable": "nrgpio为可运行",
"commandnotfound": "nrgpio命令不存在",
"commandnotexecutable": "nrgpio命令不可运行",
"error": "错误: __error__",
"pythoncommandnotfound": "nrpgio python 命令不运行"
"pythoncommandnotfound": "nrpgio python命令未处于运行状态"
}
},
"tail": {
"label": {
"filename": "文件名",
"type": "文件类型",
"splitlines": "拆分线 \\n?"
"splitlines": "以\\n来拆分行?"
},
"action": {
"text": "文本 - 返回字符串",
"binary": "二进制 - 返回缓冲区"
"binary": "二进制 - 返回Buffer"
},
"errors": {
"windowsnotsupport": "Windows目前不支持."
@@ -770,7 +797,7 @@
"label": {
"filename": "文件名",
"action": "行为",
"addnewline": "向每个有效载荷添加换行符(\\ n?",
"addnewline": "向每个有效载荷添加换行符(\\n?",
"createdir": "创建目录(如果不存在)?",
"outputas": "输出",
"breakchunks": "分拆成块",
@@ -781,14 +808,14 @@
},
"action": {
"append": "追加至文件",
"overwrite": "写文件",
"overwrite": "写文件",
"delete": "删除文件"
},
"output": {
"utf8": "一条单独 utf8 字符串",
"buffer": "一条单独缓冲区对象",
"utf8": "一utf8字符串",
"buffer": "一个Buffer对象",
"lines": "每行一条信息",
"stream": "缓冲区流"
"stream": "一个Buffer流"
},
"status": {
"wrotefile": "写入至文件: __file__",
@@ -806,41 +833,99 @@
"tip": "提示: 文件名应该是绝对路径否则它将相对于Node-RED进程的工作目录。"
},
"split": {
"intro":"分<code>msg.payload</code> 基于类型:",
"intro":"基于以下类型拆分<code>msg.payload</code>:",
"object":"<b>对象</b>",
"objectSend":"发送每个键/值对的消息",
"strBuff":"<b>字符串</b> / <b>缓冲区</b>",
"objectSend":"每个键值对作为单个消息发送",
"strBuff":"<b>字符串</b> / <b>Buffer</b>",
"array":"<b>数组</b>",
"splitUsing":"拆分使用",
"splitLength":"固定长度",
"stream":"处理为消息流",
"stream":"为消息流处理",
"addname":" 复制键到 "
},
"join":{
"mode":{
"mode":"模式",
"auto":"自动",
"merge":"合并序列",
"reduce":"缩减序列",
"custom":"手动"
},
"combine":"结合每一个",
"create":"创建输出",
"combine":"合并每个",
"create":"输出",
"type":{
"string":"字符串",
"array":"数组",
"buffer":"缓冲区",
"object":"键/值对象",
"buffer":"Buffer",
"object":"键值对象",
"merged":"合并对象"
},
"using":"使用值",
"key":"作键",
"using":"使用值",
"key":"作键",
"joinedUsing":"合并符号",
"send":"发送信息:",
"afterCount":"达到一定数的信息部件时",
"count":"数",
"afterCount":"达到一定数的信息时",
"count":"数",
"subsequent":"和每个后续的消息",
"afterTimeout":"第一条消息的超时后",
"afterTimeout":"第一条消息的若干时间后",
"seconds":"秒",
"complete":"在使用<code> msg.complete </ code>属性设置的消息后",
"tip":"此模式假定此节点与 <i>split</i> 或者接收到的消息将具有正确配置的 <code>msg.parts</code> 属性."
"complete":"在收到存在<code>msg.complete</code>的消息后",
"tip":"此模式假定此节点与<i>split</i>相连, 或者接收到的消息有正确配置的<code>msg.parts</code>属性.",
"too-many" : "join节点中有太多待定信息",
"merge": {
"topics-label":"合并主题",
"topics":"主题",
"topic" : "主题",
"on-change":"当收到一个新主题时发送已合并信息"
},
"reduce": {
"exp": "Reduce表达式",
"exp-value": "exp",
"init": "初始值",
"right": "反向求值(从后往前)",
"fixup": "Fix-up exp"
},
"errors": {
"invalid-expr": "无效的JSONata表达式: __error__"
}
},
"sort" : {
"target" : "排序属性",
"seq" : "信息队列",
"key" : "键值",
"elem" : "元素值",
"order" : "顺序",
"ascending" : "升序",
"descending" : "降序",
"as-number" : "作为数值",
"invalid-exp" : "sort节点中存在无效的JSONata表达式",
"too-many" : "sort节点中有太多待定信息",
"clear" : "清空sort节点中的待定信息"
},
"batch" : {
"mode": {
"label" : "模式",
"num-msgs" : "按指定数量分组",
"interval" : "按时间间隔分组",
"concat" : "按主题分组"
},
"count": {
"label" : "分组数量",
"overlap" : "队末队首重叠数量",
"count" : "数量",
"invalid" : "无效的分组数量或重叠数量"
},
"interval": {
"label" : "时间间隔",
"seconds" : "秒",
"empty" : "无数据到达时发送空信息"
},
"concat": {
"topics-label": "主题",
"topic" : "主题"
},
"too-many" : "batch节点中有太多待定信息",
"unexpected" : "未知模式",
"no-parts" : "信息中没有parts属性"
}
}

View File

@@ -65,7 +65,7 @@
that are part of a sequence.</p>
<p>The <b>recreate message sequences</b> option can be enabled to generate new message sequences
for each rule that matches. In this mode, the node will buffer the entire incoming
sequence before sending the new sequences on. The runtime setting `nodeMessageBufferMaxLength`
sequence before sending the new sequences on. The runtime setting <code>nodeMessageBufferMaxLength</code>
can be used to limit how many messages nodes will buffer.</p>
</script>
@@ -85,6 +85,7 @@
{v:"false",t:"switch.rules.false",kind:'V'},
{v:"null",t:"switch.rules.null",kind:'V'},
{v:"nnull",t:"switch.rules.nnull",kind:'V'},
{v:"istype",t:"switch.rules.istype",kind:'V'},
{v:"head",t:"switch.rules.head",kind:'S'},
{v:"index",t:"switch.rules.index",kind:'S'},
{v:"tail",t:"switch.rules.tail",kind:'S'},
@@ -140,7 +141,7 @@
},
icon: "switch.png",
label: function() {
return this.name||"switch";
return this.name||this._("switch.switch");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
@@ -160,6 +161,7 @@
var selectField = rule.find("select");
var type = selectField.val()||"";
var valueField = rule.find(".node-input-rule-value");
var typeField = rule.find(".node-input-rule-type-value");
var numField = rule.find(".node-input-rule-num-value");
var expField = rule.find(".node-input-rule-exp-value");
var btwnField1 = rule.find(".node-input-rule-btwn-value");
@@ -180,6 +182,8 @@
numField.typedInput("width",(newWidth-selectWidth-70));
} else if (type === "jsonata_exp") {
expField.typedInput("width",(newWidth-selectWidth-70));
} else if (type === "istype") {
typeField.typedInput("width",(newWidth-selectWidth-70));
} else {
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
// valueField.hide();
@@ -199,7 +203,7 @@
rule.t = 'eq';
}
if (!opt.hasOwnProperty('i')) {
opt._i = Math.floor((0x99999-0x10000)*Math.random()).toString(16);
opt._i = Math.floor((0x99999-0x10000)*Math.random()).toString();
}
container.css({
overflow: 'hidden',
@@ -232,6 +236,18 @@
var btwnValueField = $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
var btwnAndLabel = $('<span/>',{class:"node-input-rule-btwn-label"}).text(" "+andLabel+" ").appendTo(row3);
var btwnValue2Field = $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"margin-left:2px;"}).appendTo(row3).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
var typeValueField = $('<input/>',{class:"node-input-rule-type-value",type:"text",style:"margin-left: 5px;"}).appendTo(row)
.typedInput({default:'string',types:[
{value:"string",label:"string",hasValue:false},
{value:"number",label:"number",hasValue:false},
{value:"boolean",label:"boolean",hasValue:false},
{value:"array",label:"array",hasValue:false},
{value:"buffer",label:"buffer",hasValue:false},
{value:"object",label:"object",hasValue:false},
{value:"json",label:"JSON string",hasValue:false},
{value:"undefined",label:"undefined",hasValue:false},
{value:"null",label:"null",hasValue:false}
]});
var finalspan = $('<span/>',{style:"float: right;margin-top: 6px;"}).appendTo(row);
finalspan.append(' &#8594; <span class="node-input-rule-index">'+(i+1)+'</span> ');
var caseSensitive = $('<input/>',{id:"node-input-rule-case-"+i,class:"node-input-rule-case",type:"checkbox",style:"width:auto;vertical-align:top"}).appendTo(row2);
@@ -243,26 +259,39 @@
valueField.typedInput('hide');
expValueField.typedInput('hide');
numValueField.typedInput('hide');
typeValueField.typedInput('hide');
btwnValueField.typedInput('show');
} else if ((type === "head") || (type === "tail")) {
btwnValueField.typedInput('hide');
btwnValue2Field.typedInput('hide');
expValueField.typedInput('hide');
numValueField.typedInput('show');
typeValueField.typedInput('hide');
valueField.typedInput('hide');
} else if (type === "jsonata_exp") {
btwnValueField.typedInput('hide');
btwnValue2Field.typedInput('hide');
expValueField.typedInput('show');
numValueField.typedInput('hide');
typeValueField.typedInput('hide');
valueField.typedInput('hide');
} else {
btwnValueField.typedInput('hide');
expValueField.typedInput('hide');
numValueField.typedInput('hide');
typeValueField.typedInput('hide');
valueField.typedInput('hide');
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
valueField.typedInput('hide');
} else {
typeValueField.typedInput('hide');
}
else
if (type === "istype") {
valueField.typedInput('hide');
typeValueField.typedInput('show');
}
else {
typeValueField.typedInput('hide');
valueField.typedInput('show');
}
}
@@ -287,6 +316,9 @@
} else if ((rule.t === "head") || (rule.t === "tail")) {
numValueField.typedInput('value',rule.v);
numValueField.typedInput('type',rule.vt||'num');
} else if (rule.t === "istype") {
typeValueField.typedInput('value',rule.vt);
typeValueField.typedInput('type',rule.vt);
} else if (rule.t === "jsonata_exp") {
expValueField.typedInput('value',rule.v);
expValueField.typedInput('type',rule.vt||'jsonata');
@@ -359,6 +391,9 @@
} else if ((type === "head") || (type === "tail")) {
r.v = rule.find(".node-input-rule-num-value").typedInput('value');
r.vt = rule.find(".node-input-rule-num-value").typedInput('type');
} else if (type === "istype") {
r.v = rule.find(".node-input-rule-type-value").typedInput('type');
r.vt = rule.find(".node-input-rule-type-value").typedInput('type');
} else if (type === "jsonata_exp") {
r.v = rule.find(".node-input-rule-exp-value").typedInput('value');
r.vt = rule.find(".node-input-rule-exp-value").typedInput('type');

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