mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
33 Commits
2.2.3
...
fontawesom
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd2462135b | ||
|
|
3649f10600 | ||
|
|
a0acc89fcb | ||
|
|
64d1a82920 | ||
|
|
2396e28479 | ||
|
|
db1ad0df63 | ||
|
|
3c0b74005b | ||
|
|
93ff667df1 | ||
|
|
99d824a999 | ||
|
|
97d2b5df15 | ||
|
|
6a5c50ff77 | ||
|
|
c948573c2d | ||
|
|
5233bc501c | ||
|
|
ad96c6f838 | ||
|
|
0e92f68b4a | ||
|
|
08295eb807 | ||
|
|
fce4f0c116 | ||
|
|
94e8fce40a | ||
|
|
c75bebfc90 | ||
|
|
3e102ef760 | ||
|
|
c07eddbd97 | ||
|
|
0533c08438 | ||
|
|
fba95e6a42 | ||
|
|
95d3a8cc22 | ||
|
|
63ebadc526 | ||
|
|
fe47b07229 | ||
|
|
62315fd478 | ||
|
|
c6104195f6 | ||
|
|
56b85e4194 | ||
|
|
6431c43d0e | ||
|
|
a62107fbd1 | ||
|
|
2f66915a9f | ||
|
|
a508177e21 |
60
CHANGELOG.md
60
CHANGELOG.md
@@ -1,63 +1,3 @@
|
||||
#### 2.2.3: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix storing subflow credential type when input has multiple types (backport to v2.x) (#3828) @Steve-Mcl
|
||||
- Fix markdown editor to mark up orderedlists correctly
|
||||
- Ensure 'hidden flow' count doesn't include subflows (backport to v2.x) (#3823) @Steve-Mcl
|
||||
- Fix credential type input item of subflow template (backport to v2.x) (#3822) @Steve-Mcl
|
||||
- Fix to extend escaped subflow category characters (backport #3647 to v2.x) (#3665) @Steve-Mcl
|
||||
- Reset mouse state when switching tabs (Backport #3643 to v2.x) (#3664) @Steve-Mcl
|
||||
- Fix to sanitize tab name (Backport #3646 to v2.x) (#3663) @Steve-Mcl
|
||||
- fix new folder menu of save to library dialog (backport #3633 to v2.x) (#3661) @Steve-Mcl
|
||||
- Ensure ACE worker options are set (Backport 3611 to v2.x) (#3657) @Steve-Mcl
|
||||
- Fix browser console error Uncaught TypeError when searching certain terms (Backport #3548 to v2.x) (#3656) @Steve-Mcl
|
||||
- Remove duplicate history add of ungroup event (backport #3581to v2.x) (#3655) @Steve-Mcl
|
||||
- Don't let themes change node config colors (#3564) @bonanitech
|
||||
- Fix gap between typedInput containers borders (#3560) @bonanitech
|
||||
- Fix recording removed links in edit history (#3547) @knolleary
|
||||
- Remove unused SASS vars (#3536) @bonanitech
|
||||
- Add custom style for jQuery widgets borders (#3537) @bonanitech
|
||||
- fix out of scope reference of hasUnusedConfig variable (#3535) @HiroyasuNishiyama
|
||||
- correct "non string" check parenthesis (#3524) @Steve-Mcl
|
||||
- Ensure i18n of scoped package name (#3516) @Steve-Mcl
|
||||
- Prevent shortcut deploy when deploy button shaded (#3517) @Steve-Mcl
|
||||
- Fix: Sidebar "Configuration" filter button tooltip (#3500) @ralphwetzel
|
||||
- Add the ability to customize diff colors even more (#3499) @bonanitech
|
||||
- do JSON comparison of old value/new value (#3481) @Steve-Mcl
|
||||
- fix nodes losing their wires when in an iframe (#3484) @zettca
|
||||
- Improve scroll into view (#3468) @Steve-Mcl
|
||||
- Dont show 1st tab if hidden when loading (#3464) @Steve-Mcl
|
||||
|
||||
Runtime
|
||||
|
||||
- Do not remove unknown credentials of Subflow Modules (backport to v2.x) (#3826) @Steve-Mcl
|
||||
- Backports to v2.x (#3735) @kazuhitoyokoi
|
||||
- Backports to v2.x (#3705) @kazuhitoyokoi
|
||||
- fix buffer parse error message of evaluateNodeProperty (backports #3624 for v2.x) (#3659) @Steve-Mcl
|
||||
- Don't start if user has no home directory (#3540) @hardillb
|
||||
- Error on invalid encrypted credentials (#3498) @sammachin
|
||||
|
||||
Nodes
|
||||
|
||||
- Allow HTTP Headers not in spec (backport to v2.x) (#3829) @Steve-Mcl
|
||||
- Fix change node, not handling from field properly when using context (backport to v2.x) (#3827) @Steve-Mcl
|
||||
- undo regression to tcp-in node
|
||||
- Fix CSV node to handle when outputting text fields (backport to v2.x) (#3825) @Steve-Mcl
|
||||
- Fix delay rate limit last timing when empty (backport to v2.x) (#3824) @Steve-Mcl
|
||||
- Join-reduce keep existing msg properties (backport to v2.x) (#3821) @Steve-Mcl
|
||||
- Fix ESM module loading in Function node (Backport #3645 to v2.x) (#3662) @Steve-Mcl
|
||||
- Fix JSONata evaluation of inject button (Backport 3632 to v2.x) (#3660) @Steve-Mcl
|
||||
- Dont delete TCP socket twice (backport Backport: #3630 to v2.x) (#3658) @Steve-Mcl
|
||||
- Mqtt fixes in v3 for v2.x (backports #3563 #3594 #3626 to v2.x) (#3654) @Steve-Mcl
|
||||
- MQTT Node - save and restore v5 config user props (#3562) @Steve-Mcl
|
||||
- Fix incorrect MQTT status (#3552) @Steve-Mcl
|
||||
- fix reference error of msg.status in debug node (#3526) @HiroyasuNishiyama
|
||||
- call done after ws disconnects (#3531) @Steve-Mcl
|
||||
- Add unit tests for MQTT nodes (#3497) @Steve-Mcl
|
||||
- fix typo of will properties (properies) (#3502) @Steve-Mcl
|
||||
- fix: ensure mqtt v5 props can be set false (#3472) @Steve-Mcl
|
||||
|
||||
#### 2.2.2: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.2",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -84,8 +84,8 @@
|
||||
"bcrypt": "5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dompurify": "2.3.6",
|
||||
"grunt": "1.5.2",
|
||||
"dompurify": "2.3.5",
|
||||
"grunt": "1.4.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.4.3",
|
||||
"grunt-concurrent": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.2.3",
|
||||
"@node-red/editor-client": "2.2.3",
|
||||
"@node-red/util": "2.2.2",
|
||||
"@node-red/editor-client": "2.2.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.1",
|
||||
"clone": "2.1.2",
|
||||
|
||||
@@ -634,14 +634,7 @@
|
||||
"empty": "leer",
|
||||
"globalConfig": "Globale Konfigurations-Nodes",
|
||||
"triggerAction": "Auslösen",
|
||||
"find": "Suche im Arbeitsbereich",
|
||||
"search": {
|
||||
"configNodes": "Konfigurations-Nodes",
|
||||
"unusedConfigNodes": "Unbenutzte Konfigurations-Nodes",
|
||||
"invalidNodes": "Ungültige Nodes",
|
||||
"uknownNodes": "Unbekannte Nodes",
|
||||
"unusedSubflows": "Unbenutzte Subflows"
|
||||
}
|
||||
"find": "Suche im Arbeitsbereich"
|
||||
},
|
||||
"help": {
|
||||
"name": "Hilfe",
|
||||
@@ -863,7 +856,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "Keine Übereinstimmungen gefunden",
|
||||
"addNode": "Node hinzufügen ..."
|
||||
"addNode": "Node hinzufügen ...",
|
||||
"options": {
|
||||
"configNodes": "Konfigurations-Nodes",
|
||||
"unusedConfigNodes": "Unbenutzte Konfigurations-Nodes",
|
||||
"invalidNodes": "Ungültige Nodes",
|
||||
"uknownNodes": "Unbekannte Nodes",
|
||||
"unusedSubflows": "Unbenutzte Subflows"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "Funktionen",
|
||||
|
||||
@@ -149,7 +149,11 @@
|
||||
"toggle-navigator": "Toggle navigator",
|
||||
"zoom-out": "Zoom out",
|
||||
"zoom-reset": "Reset zoom",
|
||||
"zoom-in": "Zoom in"
|
||||
"zoom-in": "Zoom in",
|
||||
"search-flows": "Search flows",
|
||||
"search-prev": "Previous",
|
||||
"search-next": "Next",
|
||||
"search-counter": "\"__term__\" __result__ of __count__"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "Logged in as __name__",
|
||||
@@ -497,7 +501,8 @@
|
||||
"redoChange": "Redo",
|
||||
"searchBox": "Open search box",
|
||||
"managePalette": "Manage palette",
|
||||
"actionList":"Action list"
|
||||
"actionList": "Action list",
|
||||
"splitWiresWithLinks": "Split selection with Link nodes"
|
||||
},
|
||||
"library": {
|
||||
"library": "Library",
|
||||
@@ -667,15 +672,7 @@
|
||||
"empty": "empty",
|
||||
"globalConfig": "Global Configuration Nodes",
|
||||
"triggerAction": "Trigger action",
|
||||
"find": "Find in workspace",
|
||||
"search": {
|
||||
"configNodes": "Configuration nodes",
|
||||
"unusedConfigNodes": "Unused configuration nodes",
|
||||
"invalidNodes": "Invalid nodes",
|
||||
"uknownNodes": "Unknown nodes",
|
||||
"unusedSubflows": "Unused subflows",
|
||||
"hiddenFlows": "Hidden flows"
|
||||
}
|
||||
"find": "Find in workspace"
|
||||
},
|
||||
"help": {
|
||||
"name": "Help",
|
||||
@@ -899,7 +896,16 @@
|
||||
"history": "Search history",
|
||||
"clear": "clear all",
|
||||
"empty": "No matches found",
|
||||
"addNode": "add a node..."
|
||||
"addNode": "add a node...",
|
||||
"options": {
|
||||
"configNodes": "Configuration nodes",
|
||||
"unusedConfigNodes": "Unused configuration nodes",
|
||||
"invalidNodes": "Invalid nodes",
|
||||
"uknownNodes": "Unknown nodes",
|
||||
"unusedSubflows": "Unused subflows",
|
||||
"hiddenFlows": "Hidden flows",
|
||||
"modifiedNodes": "Modified nodes and flows"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "Functions",
|
||||
|
||||
@@ -667,15 +667,7 @@
|
||||
"empty": "空",
|
||||
"globalConfig": "グローバル設定ノード",
|
||||
"triggerAction": "アクションを実行",
|
||||
"find": "ワークスペース内を検索",
|
||||
"search": {
|
||||
"configNodes": "設定ノード",
|
||||
"unusedConfigNodes": "未使用の設定ノード",
|
||||
"invalidNodes": "不正なノード",
|
||||
"uknownNodes": "未知のノード",
|
||||
"unusedSubflows": "未使用のサブフロー",
|
||||
"hiddenFlows": "非表示のフロー"
|
||||
}
|
||||
"find": "ワークスペース内を検索"
|
||||
},
|
||||
"help": {
|
||||
"name": "ヘルプ",
|
||||
@@ -845,7 +837,7 @@
|
||||
"pushFailed": "リモートに新しいコミットがあるため、プッシュに失敗しました。プルしてマージしてから、再度プッシュしてください。",
|
||||
"push": "プッシュ",
|
||||
"pull": "プル",
|
||||
"unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更が上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>",
|
||||
"unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更を上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>",
|
||||
"showUnstagedChanges": "ステージングされていない変更を表示",
|
||||
"connectionFailed": "リモートリポジトリに接続できません: ",
|
||||
"pullUnrelatedHistory": "<p>リモートに関連のないコミット履歴があります。</p><p>本当に変更をプルしてローカルリポジトリに反映しますか?</p>",
|
||||
@@ -899,7 +891,15 @@
|
||||
"history": "検索履歴",
|
||||
"clear": "全て削除",
|
||||
"empty": "一致したものが見つかりませんでした",
|
||||
"addNode": "ノードを追加..."
|
||||
"addNode": "ノードを追加...",
|
||||
"options": {
|
||||
"configNodes": "設定ノード",
|
||||
"unusedConfigNodes": "未使用の設定ノード",
|
||||
"invalidNodes": "不正なノード",
|
||||
"uknownNodes": "未知のノード",
|
||||
"unusedSubflows": "未使用のサブフロー",
|
||||
"hiddenFlows": "非表示のフロー"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "関数",
|
||||
@@ -1287,10 +1287,6 @@
|
||||
"zoom-in": "ズームイン",
|
||||
"zoom-out": "ズームアウト",
|
||||
"zoom-reset": "ズームリセット",
|
||||
"toggle-navigator": "ナビゲータ表示切替",
|
||||
"new-project": "新しいプロジェクト",
|
||||
"open-project": "プロジェクトを開く",
|
||||
"show-project-settings": "プロジェクト設定を表示",
|
||||
"show-version-control-tab": "バージョンコントロールタブを表示"
|
||||
"toggle-navigator": "ナビゲータ表示切替"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"tip14": "[shift] を押しながらノードを [click] すると、接続された全てのノードを選択できます。",
|
||||
"tip15": "[ctrl] を押しながらノードを [click] すると、選択/非選択を切り替えできます。",
|
||||
"tip16": "{{core:show-previous-tab}} や {{core:show-next-tab}} で、タブの切り替えができます。",
|
||||
"tip17": "ノードのプロパティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
|
||||
"tip17": "ノードのプロバティ設定画面にて {{core:confirm-edit-tray}} を押すと、変更を確定できます。また、 {{core:cancel-edit-tray}} を押すと、変更を取り消せます。",
|
||||
"tip18": "ノードを選択し、 {{core:edit-selected-node}} を押すとプロパティ設定画面が表示されます。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,14 +650,7 @@
|
||||
"empty": "пусто",
|
||||
"globalConfig": "Глобальные конфиг узлы",
|
||||
"triggerAction": "Вызвать действие",
|
||||
"find": "Найти в рабочей области",
|
||||
"search": {
|
||||
"configNodes": "Узлы конфигурации",
|
||||
"unusedConfigNodes": "Неиспользуемые узлы конфигурации",
|
||||
"invalidNodes": "Недействительные узлы",
|
||||
"uknownNodes": "Неизвестные узлы",
|
||||
"unusedSubflows": "Неиспользуемые подпотоки"
|
||||
}
|
||||
"find": "Найти в рабочей области"
|
||||
},
|
||||
"help": {
|
||||
"name": "Справка",
|
||||
@@ -888,7 +881,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "Ничего не найдено",
|
||||
"addNode": "добавить узел..."
|
||||
"addNode": "добавить узел...",
|
||||
"options": {
|
||||
"configNodes": "Узлы конфигурации",
|
||||
"unusedConfigNodes": "Неиспользуемые узлы конфигурации",
|
||||
"invalidNodes": "Недействительные узлы",
|
||||
"uknownNodes": "Неизвестные узлы",
|
||||
"unusedSubflows": "Неиспользуемые подпотоки"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "Функции",
|
||||
|
||||
@@ -614,14 +614,7 @@
|
||||
"empty": "空的",
|
||||
"globalConfig": "全局配置节点",
|
||||
"triggerAction": "触发动作",
|
||||
"find": "在工作区中查找",
|
||||
"search": {
|
||||
"configNodes": "配置节点",
|
||||
"unusedConfigNodes": "未使用的配置节点",
|
||||
"invalidNodes": "无效的节点",
|
||||
"uknownNodes": "未知的节点",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
"find": "在工作区中查找"
|
||||
},
|
||||
"help": {
|
||||
"name": "帮助",
|
||||
@@ -842,7 +835,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "找不到匹配",
|
||||
"addNode": "添加一个节点..."
|
||||
"addNode": "添加一个节点...",
|
||||
"options": {
|
||||
"configNodes": "配置节点",
|
||||
"unusedConfigNodes": "未使用的配置节点",
|
||||
"invalidNodes": "无效的节点",
|
||||
"uknownNodes": "未知的节点",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "功能",
|
||||
|
||||
@@ -614,14 +614,7 @@
|
||||
"empty": "空的",
|
||||
"globalConfig": "全局配置節點",
|
||||
"triggerAction": "觸發動作",
|
||||
"find": "在工作區中查找",
|
||||
"search": {
|
||||
"configNodes": "配置節點",
|
||||
"unusedConfigNodes": "未使用的配置節點",
|
||||
"invalidNodes": "無效的節點",
|
||||
"uknownNodes": "未知的節點",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
"find": "在工作區中查找"
|
||||
},
|
||||
"help": {
|
||||
"name": "幫助",
|
||||
@@ -842,7 +835,14 @@
|
||||
},
|
||||
"search": {
|
||||
"empty": "找不到匹配",
|
||||
"addNode": "添加一個節點..."
|
||||
"addNode": "添加一個節點...",
|
||||
"options": {
|
||||
"configNodes": "配置節點",
|
||||
"unusedConfigNodes": "未使用的配置節點",
|
||||
"invalidNodes": "無效的節點",
|
||||
"uknownNodes": "未知的節點",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "功能",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -98,7 +98,7 @@ oop.inherits(NRJavaScriptWorker, Mirror);
|
||||
if (options) {
|
||||
for (var opt in options) {
|
||||
if (options.hasOwnProperty(opt)) {
|
||||
this.options[opt] = options[opt];
|
||||
this.options[opt] = options.opt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
/**
|
||||
* An API for undo / redo history buffer
|
||||
* @namespace RED.history
|
||||
*/
|
||||
RED.history = (function() {
|
||||
var undoHistory = [];
|
||||
var redoHistory = [];
|
||||
@@ -101,6 +106,23 @@ RED.history = (function() {
|
||||
RED.nodes.removeLink(ev.links[i]);
|
||||
}
|
||||
}
|
||||
if (ev.junctions) {
|
||||
inverseEv.junctions = [];
|
||||
for (i=0;i<ev.junctions.length;i++) {
|
||||
inverseEv.junctions.push(ev.junctions[i]);
|
||||
RED.nodes.removeJunction(ev.junctions[i]);
|
||||
if (ev.junctions[i].g) {
|
||||
var group = RED.nodes.group(ev.junctions[i].g);
|
||||
var index = group.nodes.indexOf(ev.junctions[i]);
|
||||
if (index !== -1) {
|
||||
group.nodes.splice(index,1);
|
||||
RED.group.markDirty(group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if (ev.groups) {
|
||||
inverseEv.groups = [];
|
||||
for (i = ev.groups.length - 1;i>=0;i--) {
|
||||
@@ -267,6 +289,21 @@ RED.history = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ev.junctions) {
|
||||
inverseEv.junctions = [];
|
||||
for (i=0;i<ev.junctions.length;i++) {
|
||||
inverseEv.junctions.push(ev.junctions[i]);
|
||||
RED.nodes.addJunction(ev.junctions[i]);
|
||||
if (ev.junctions[i].g) {
|
||||
group = RED.nodes.group(ev.junctions[i].g);
|
||||
if (group.nodes.indexOf(ev.junctions[i]) === -1) {
|
||||
group.nodes.push(ev.junctions[i]);
|
||||
}
|
||||
RED.group.markDirty(group)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (ev.links) {
|
||||
inverseEv.links = [];
|
||||
for (i=0;i<ev.links.length;i++) {
|
||||
|
||||
@@ -90,6 +90,10 @@
|
||||
"alt-a m": "core:align-selection-to-middle",
|
||||
"alt-a c": "core:align-selection-to-center",
|
||||
"alt-a h": "core:distribute-selection-horizontally",
|
||||
"alt-a v": "core:distribute-selection-vertically"
|
||||
"alt-a v": "core:distribute-selection-vertically",
|
||||
"shift-f": "core:search-previous",
|
||||
"f": "core:search-next",
|
||||
"alt-l l": "core:split-wire-with-link-nodes"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
/**
|
||||
* An Interface to nodes and utility functions for creating/adding/deleting nodes and links
|
||||
* @namespace RED.nodes
|
||||
*/
|
||||
RED.nodes = (function() {
|
||||
|
||||
var PORT_TYPE_INPUT = 1;
|
||||
@@ -33,6 +38,9 @@ RED.nodes = (function() {
|
||||
var groups = {};
|
||||
var groupsByZ = {};
|
||||
|
||||
var junctions = {};
|
||||
var junctionsByZ = {};
|
||||
|
||||
var initialLoad;
|
||||
|
||||
var dirty = false;
|
||||
@@ -814,6 +822,7 @@ RED.nodes = (function() {
|
||||
var removedNodes = [];
|
||||
var removedLinks = [];
|
||||
var removedGroups = [];
|
||||
var removedJunctions = [];
|
||||
if (ws) {
|
||||
delete workspaces[id];
|
||||
delete linkTabMap[id];
|
||||
@@ -822,7 +831,14 @@ RED.nodes = (function() {
|
||||
var node;
|
||||
|
||||
if (allNodes.hasTab(id)) {
|
||||
removedNodes = allNodes.getNodes(id).slice()
|
||||
removedNodes = allNodes.getNodes(id).filter(n => {
|
||||
if (n.type === 'junction') {
|
||||
removedJunctions.push(n)
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
for (i in configNodes) {
|
||||
if (configNodes.hasOwnProperty(i)) {
|
||||
@@ -837,6 +853,10 @@ RED.nodes = (function() {
|
||||
var result = removeNode(removedNodes[i].id);
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
}
|
||||
for (i=0;i<removedJunctions.length;i++) {
|
||||
var result = removeJunction(removedJunctions[i])
|
||||
removedLinks = removedLinks.concat(result.links)
|
||||
}
|
||||
|
||||
// Must get 'removedGroups' in the right order.
|
||||
// - start with the top-most groups
|
||||
@@ -856,7 +876,7 @@ RED.nodes = (function() {
|
||||
allNodes.removeTab(id);
|
||||
RED.events.emit('flows:remove',ws);
|
||||
}
|
||||
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
|
||||
return {nodes:removedNodes,links:removedLinks, groups: removedGroups, junctions: removedJunctions};
|
||||
}
|
||||
|
||||
function addSubflow(sf, createNewIds) {
|
||||
@@ -1113,7 +1133,7 @@ RED.nodes = (function() {
|
||||
delete node.env;
|
||||
}
|
||||
}
|
||||
if (n._def.category != "config") {
|
||||
if (n._def.category != "config" || n.type === 'junction') {
|
||||
node.x = n.x;
|
||||
node.y = n.y;
|
||||
if (exportDimensions) {
|
||||
@@ -1376,6 +1396,11 @@ RED.nodes = (function() {
|
||||
nns.push(convertNode(groups[i], opts));
|
||||
}
|
||||
}
|
||||
for (i in junctions) {
|
||||
if (junctions.hasOwnProperty(i)) {
|
||||
nns.push(convertNode(junctions[i], opts));
|
||||
}
|
||||
}
|
||||
for (i in configNodes) {
|
||||
if (configNodes.hasOwnProperty(i)) {
|
||||
nns.push(convertNode(configNodes[i], opts));
|
||||
@@ -1457,6 +1482,7 @@ RED.nodes = (function() {
|
||||
tabs: {},
|
||||
subflows: {},
|
||||
groups: {},
|
||||
junctions: {},
|
||||
configs: {},
|
||||
nodes: {},
|
||||
all: [],
|
||||
@@ -1472,6 +1498,8 @@ RED.nodes = (function() {
|
||||
imported.subflows[n.id] = n;
|
||||
} else if (n.type === "group") {
|
||||
imported.groups[n.id] = n;
|
||||
} else if (n.type === "junction") {
|
||||
imported.junctions[n.id] = n;
|
||||
} else if (n.hasOwnProperty("x") && n.hasOwnProperty("y")) {
|
||||
imported.nodes[n.id] = n;
|
||||
} else {
|
||||
@@ -1480,7 +1508,7 @@ RED.nodes = (function() {
|
||||
var nodeZ = n.z || "__global__";
|
||||
imported.zMap[nodeZ] = imported.zMap[nodeZ] || [];
|
||||
imported.zMap[nodeZ].push(n)
|
||||
if (allNodes.hasNode(n.id) || configNodes[n.id] || workspaces[n.id] || subflows[n.id] || groups[n.id]) {
|
||||
if (allNodes.hasNode(n.id) || configNodes[n.id] || workspaces[n.id] || subflows[n.id] || groups[n.id] || junctions[n.id]) {
|
||||
imported.conflicted[n.id] = n;
|
||||
}
|
||||
})
|
||||
@@ -1646,7 +1674,7 @@ RED.nodes = (function() {
|
||||
if (!options.generateIds) {
|
||||
if (!options.importMap[id]) {
|
||||
// No conflict resolution for this node
|
||||
var existing = allNodes.getNode(id) || configNodes[id] || workspaces[id] || subflows[id] || groups[id];
|
||||
var existing = allNodes.getNode(id) || configNodes[id] || workspaces[id] || subflows[id] || groups[id] || junctions[id];
|
||||
if (existing) {
|
||||
existingNodes.push({existing:existing, imported:n});
|
||||
}
|
||||
@@ -1700,6 +1728,7 @@ RED.nodes = (function() {
|
||||
n.type != "tab" &&
|
||||
n.type != "subflow" &&
|
||||
n.type != "group" &&
|
||||
n.type != 'junction' &&
|
||||
!registry.getNodeType(n.type) &&
|
||||
n.type.substring(0,8) != "subflow:" &&
|
||||
unknownTypes.indexOf(n.type)==-1) {
|
||||
@@ -1772,6 +1801,7 @@ RED.nodes = (function() {
|
||||
var new_nodes = [];
|
||||
var new_links = [];
|
||||
var new_groups = [];
|
||||
var new_junctions = [];
|
||||
var new_group_set = new Set();
|
||||
var nid;
|
||||
var def;
|
||||
@@ -1963,12 +1993,15 @@ RED.nodes = (function() {
|
||||
changed:false,
|
||||
_config:{}
|
||||
}
|
||||
if (n.type !== "group") {
|
||||
if (n.type !== "group" && n.type !== 'junction') {
|
||||
node.wires = n.wires||[];
|
||||
node.inputLabels = n.inputLabels;
|
||||
node.outputLabels = n.outputLabels;
|
||||
node.icon = n.icon;
|
||||
}
|
||||
if (n.type === 'junction') {
|
||||
node.wires = n.wires||[];
|
||||
}
|
||||
if (n.hasOwnProperty('l')) {
|
||||
node.l = n.l;
|
||||
}
|
||||
@@ -2037,6 +2070,15 @@ RED.nodes = (function() {
|
||||
node.outputs = subflow.out.length;
|
||||
node.inputs = subflow.in.length;
|
||||
node.env = n.env;
|
||||
} else if (n.type === 'junction') {
|
||||
node._def = {defaults:{}}
|
||||
node._config.x = node.x
|
||||
node._config.y = node.y
|
||||
node.inputs = 1
|
||||
node.outputs = 1
|
||||
node.w = 0;
|
||||
node.h = 0;
|
||||
|
||||
} else {
|
||||
if (!node._def) {
|
||||
if (node.x && node.y) {
|
||||
@@ -2120,7 +2162,9 @@ RED.nodes = (function() {
|
||||
node_map[n.id] = node;
|
||||
// If an 'unknown' config node, it will not have been caught by the
|
||||
// proper config node handling, so needs adding to new_nodes here
|
||||
if (node.type === "unknown" || node._def.category !== "config") {
|
||||
if (node.type === 'junction') {
|
||||
new_junctions.push(node)
|
||||
} else if (node.type === "unknown" || node._def.category !== "config") {
|
||||
new_nodes.push(node);
|
||||
} else if (node.type === "group") {
|
||||
new_groups.push(node);
|
||||
@@ -2131,11 +2175,15 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
// Remap all wires and config node references
|
||||
for (i=0;i<new_nodes.length;i++) {
|
||||
n = new_nodes[i];
|
||||
for (i=0;i<new_nodes.length+new_junctions.length;i++) {
|
||||
if (i<new_nodes.length) {
|
||||
n = new_nodes[i];
|
||||
} else {
|
||||
n = new_junctions[i - new_nodes.length]
|
||||
}
|
||||
if (n.wires) {
|
||||
for (var w1=0;w1<n.wires.length;w1++) {
|
||||
var wires = (Array.isArray(n.wires[w1]))?n.wires[w1]:[n.wires[w1]];
|
||||
var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]];
|
||||
for (var w2=0;w2<wires.length;w2++) {
|
||||
if (node_map.hasOwnProperty(wires[w2])) {
|
||||
if (n.z === node_map[wires[w2]].z) {
|
||||
@@ -2271,6 +2319,12 @@ RED.nodes = (function() {
|
||||
addGroup(n);
|
||||
}
|
||||
|
||||
for (i=0;i<new_junctions.length;i++) {
|
||||
var junction = new_junctions[i];
|
||||
addJunction(junction);
|
||||
}
|
||||
|
||||
|
||||
// Now the nodes have been fully updated, add them.
|
||||
for (i=0;i<new_nodes.length;i++) {
|
||||
var node = new_nodes[i];
|
||||
@@ -2301,6 +2355,7 @@ RED.nodes = (function() {
|
||||
nodes:new_nodes,
|
||||
links:new_links,
|
||||
groups:new_groups,
|
||||
junctions: new_junctions,
|
||||
workspaces:new_workspaces,
|
||||
subflows:new_subflows,
|
||||
missingWorkspace: missingWorkspace,
|
||||
@@ -2456,6 +2511,30 @@ RED.nodes = (function() {
|
||||
RED.events.emit("groups:remove",group);
|
||||
}
|
||||
|
||||
function addJunction(junction) {
|
||||
junctionsByZ[junction.z] = junctionsByZ[junction.z] || []
|
||||
junctionsByZ[junction.z].push(junction)
|
||||
junctions[junction.id] = junction;
|
||||
if (!nodeLinks[junction.id]) {
|
||||
nodeLinks[junction.id] = {in:[],out:[]};
|
||||
}
|
||||
RED.events.emit("junctions:add", junction)
|
||||
}
|
||||
function removeJunction(junction) {
|
||||
var i = junctionsByZ[junction.z].indexOf(junction)
|
||||
junctionsByZ[junction.z].splice(i, 1)
|
||||
if (junctionsByZ[junction.z].length === 0) {
|
||||
delete junctionsByZ[junction.z]
|
||||
}
|
||||
delete junctions[junction.id]
|
||||
delete nodeLinks[junction.id];
|
||||
RED.events.emit("junctions:remove", junction)
|
||||
|
||||
var removedLinks = links.filter(function(l) { return (l.source === junction) || (l.target === junction); });
|
||||
removedLinks.forEach(removeLink);
|
||||
return { links: removedLinks }
|
||||
}
|
||||
|
||||
function getNodeHelp(type) {
|
||||
var helpContent = "";
|
||||
var helpElement = $("script[data-help-name='"+type+"']");
|
||||
@@ -2684,7 +2763,6 @@ RED.nodes = (function() {
|
||||
getType: registry.getNodeType,
|
||||
getNodeHelp: getNodeHelp,
|
||||
convertNode: convertNode,
|
||||
|
||||
add: addNode,
|
||||
remove: removeNode,
|
||||
clear: clear,
|
||||
@@ -2730,6 +2808,11 @@ RED.nodes = (function() {
|
||||
group: function(id) { return groups[id] },
|
||||
groups: function(z) { return groupsByZ[z]?groupsByZ[z].slice():[] },
|
||||
|
||||
addJunction: addJunction,
|
||||
removeJunction: removeJunction,
|
||||
junction: function(id) { return junctions[id] },
|
||||
junctions: function(z) { return junctionsByZ[z]?junctionsByZ[z].slice():[] },
|
||||
|
||||
eachNode: function(cb) {
|
||||
allNodes.eachNode(cb);
|
||||
},
|
||||
|
||||
@@ -252,21 +252,8 @@ var RED = (function() {
|
||||
if (/^#flow\/.+$/.test(currentHash)) {
|
||||
RED.workspaces.show(currentHash.substring(6),true);
|
||||
}
|
||||
if (RED.workspaces.count() > 0) {
|
||||
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
const workspaces = RED.nodes.getWorkspaceOrder();
|
||||
if (RED.workspaces.active() === 0) {
|
||||
for (let index = 0; index < workspaces.length; index++) {
|
||||
const ws = workspaces[index];
|
||||
if (!hiddenTabs[ws]) {
|
||||
RED.workspaces.show(ws);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RED.workspaces.active() === 0) {
|
||||
RED.workspaces.show(workspaces[0]);
|
||||
}
|
||||
if (RED.workspaces.active() === 0 && RED.workspaces.count() > 0) {
|
||||
RED.workspaces.show(RED.nodes.getWorkspaceOrder()[0])
|
||||
}
|
||||
} catch(err) {
|
||||
console.warn(err);
|
||||
@@ -474,7 +461,7 @@ var RED = (function() {
|
||||
var parts = topic.split("/");
|
||||
var node = RED.nodes.node(parts[1]);
|
||||
if (node) {
|
||||
if (msg.hasOwnProperty("text") && msg.text !== null && /^[@a-zA-Z]/.test(msg.text)) {
|
||||
if (msg.hasOwnProperty("text") && msg.text !== null && /^[a-zA-Z]/.test(msg.text)) {
|
||||
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
|
||||
}
|
||||
node.status = msg;
|
||||
@@ -615,7 +602,10 @@ var RED = (function() {
|
||||
null,
|
||||
{id: "menu-item-edit-select-all", label:RED._("keyboard.selectAll"), onselect: "core:select-all-nodes"},
|
||||
{id: "menu-item-edit-select-connected", label:RED._("keyboard.selectAllConnected"), onselect: "core:select-connected-nodes"},
|
||||
{id: "menu-item-edit-select-none", label:RED._("keyboard.selectNone"), onselect: "core:select-none"}
|
||||
{id: "menu-item-edit-select-none", label:RED._("keyboard.selectNone"), onselect: "core:select-none"},
|
||||
null,
|
||||
{id: "menu-item-edit-split-wire-with-links", label:RED._("keyboard.splitWireWithLinks"), onselect: "core:split-wire-with-link-nodes"},
|
||||
|
||||
]});
|
||||
|
||||
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
|
||||
|
||||
@@ -987,6 +987,7 @@ RED.clipboard = (function() {
|
||||
try {
|
||||
RED.view.importNodes(newNodes, importOptions);
|
||||
} catch(error) {
|
||||
console.log(error.importConfig)
|
||||
// Thrown for import_conflict
|
||||
confirmImport(error.importConfig, newNodes, importOptions);
|
||||
}
|
||||
|
||||
@@ -828,7 +828,7 @@ RED.tabs = (function() {
|
||||
}
|
||||
|
||||
// link.attr("title",tab.label);
|
||||
RED.popover.tooltip(link,function() { return RED.utils.sanitize(tab.label); });
|
||||
RED.popover.tooltip(link,function() { return tab.label})
|
||||
|
||||
if (options.onadd) {
|
||||
options.onadd(tab);
|
||||
|
||||
@@ -319,208 +319,205 @@ RED.deploy = (function() {
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
function save(skipValidation, force) {
|
||||
if ($("#red-ui-header-button-deploy").hasClass("disabled")) {
|
||||
return; //deploy is disabled
|
||||
}
|
||||
if ($("#red-ui-header-shade").is(":visible")) {
|
||||
return; //deploy is shaded
|
||||
}
|
||||
if (!RED.user.hasPermission("flows.write")) {
|
||||
RED.notify(RED._("user.errors.deploy"), "error");
|
||||
return;
|
||||
}
|
||||
let hasUnusedConfig = false;
|
||||
if (!skipValidation) {
|
||||
let hasUnknown = false;
|
||||
let hasInvalid = false;
|
||||
const unknownNodes = [];
|
||||
const invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(function (node) {
|
||||
if (node.valid === undefined) {
|
||||
RED.editor.validateNode(node);
|
||||
}
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.nodes.eachNode(function (node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
hasInvalid = invalidNodes.length > 0;
|
||||
|
||||
const unusedConfigNodes = [];
|
||||
RED.nodes.eachConfig(function (node) {
|
||||
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
|
||||
unusedConfigNodes.push(getNodeInfo(node));
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
let showWarning = false;
|
||||
let notificationMessage;
|
||||
let notificationButtons = [];
|
||||
let notification;
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
notificationMessage = "<p>" + RED._('deploy.confirm.unknown') + "</p>" +
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(unknownNodes).map(function (n) { return sanitize(n) }).join("</li><li>") + "</li></ul><p>" +
|
||||
RED._('deploy.confirm.confirm') +
|
||||
"</p>";
|
||||
|
||||
notificationButtons = [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function () {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
|
||||
notificationMessage = "<p>" + RED._('deploy.confirm.improperlyConfigured') + "</p>" +
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(invalidNodes.map(function (A) { return sanitize((A.tab ? "[" + A.tab + "] " : "") + A.label + " (" + A.type + ")") })).join("</li><li>") + "</li></ul><p>" +
|
||||
RED._('deploy.confirm.confirm') +
|
||||
"</p>";
|
||||
notificationButtons = [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function () {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
if (showWarning) {
|
||||
notificationButtons.unshift(
|
||||
{
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function () {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
notification = RED.notify(notificationMessage, {
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons: notificationButtons
|
||||
});
|
||||
function save(skipValidation,force) {
|
||||
if (!$("#red-ui-header-button-deploy").hasClass("disabled")) {
|
||||
if (!RED.user.hasPermission("flows.write")) {
|
||||
RED.notify(RED._("user.errors.deploy"),"error");
|
||||
return;
|
||||
}
|
||||
if (!skipValidation) {
|
||||
var hasUnknown = false;
|
||||
var hasInvalid = false;
|
||||
var hasUnusedConfig = false;
|
||||
|
||||
var unknownNodes = [];
|
||||
var invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if (node.valid === undefined) {
|
||||
RED.editor.validateNode(node);
|
||||
}
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
hasInvalid = invalidNodes.length > 0;
|
||||
|
||||
var unusedConfigNodes = [];
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
|
||||
unusedConfigNodes.push(getNodeInfo(node));
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
var showWarning = false;
|
||||
var notificationMessage;
|
||||
var notificationButtons = [];
|
||||
var notification;
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.unknown')+"</p>"+
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(unknownNodes).map(function(n) { return sanitize(n) }).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
|
||||
notificationButtons= [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.improperlyConfigured')+"</p>"+
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(invalidNodes.map(function(A) { return sanitize( (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")")})).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
notificationButtons= [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
if (showWarning) {
|
||||
notificationButtons.unshift(
|
||||
{
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
notification = RED.notify(notificationMessage,{
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons:notificationButtons
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
|
||||
var startTime = Date.now();
|
||||
$(".red-ui-deploy-button-content").css('opacity',0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
|
||||
var data = {flows:nns};
|
||||
|
||||
if (!force) {
|
||||
data.rev = RED.nodes.version();
|
||||
}
|
||||
|
||||
deployInflight = true;
|
||||
$("#red-ui-header-shade").show();
|
||||
$("#red-ui-editor-shade").show();
|
||||
$("#red-ui-palette-shade").show();
|
||||
$("#red-ui-sidebar-shade").show();
|
||||
$.ajax({
|
||||
url:"flows",
|
||||
type: "POST",
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
headers: {
|
||||
"Node-RED-Deployment-Type":deploymentType
|
||||
}
|
||||
}).done(function(data,textStatus,xhr) {
|
||||
RED.nodes.dirty(false);
|
||||
RED.nodes.version(data.rev);
|
||||
RED.nodes.originalFlow(nns);
|
||||
if (hasUnusedConfig) {
|
||||
RED.notify(
|
||||
'<p>'+RED._("deploy.successfulDeploy")+'</p>'+
|
||||
'<p>'+RED._("deploy.unusedConfigNodes")+' <a href="#" onclick="RED.sidebar.config.show(true); return false;">'+RED._("deploy.unusedConfigNodesLink")+'</a></p>',"success",false,6000);
|
||||
} else {
|
||||
RED.notify('<p>'+RED._("deploy.successfulDeploy")+'</p>',"success");
|
||||
}
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if (node.moved) {
|
||||
node.dirty = true;
|
||||
node.moved = false;
|
||||
}
|
||||
if(node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.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();
|
||||
RED.events.emit("deploy");
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
RED.nodes.dirty(true);
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
if (xhr.status === 401) {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
|
||||
} else if (xhr.status === 409) {
|
||||
resolveConflict(nns, true);
|
||||
} else if (xhr.responseText) {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
|
||||
} else {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
|
||||
}
|
||||
}).always(function() {
|
||||
deployInflight = false;
|
||||
var delta = Math.max(0,300-(Date.now()-startTime));
|
||||
setTimeout(function() {
|
||||
$(".red-ui-deploy-button-content").css('opacity',1);
|
||||
$(".red-ui-deploy-button-spinner").hide();
|
||||
$("#red-ui-header-shade").hide();
|
||||
$("#red-ui-editor-shade").hide();
|
||||
$("#red-ui-palette-shade").hide();
|
||||
$("#red-ui-sidebar-shade").hide();
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
|
||||
const nns = RED.nodes.createCompleteNodeSet();
|
||||
const startTime = Date.now();
|
||||
|
||||
$(".red-ui-deploy-button-content").css('opacity', 0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
|
||||
const data = { flows: nns };
|
||||
|
||||
if (!force) {
|
||||
data.rev = RED.nodes.version();
|
||||
}
|
||||
|
||||
deployInflight = true;
|
||||
$("#red-ui-header-shade").show();
|
||||
$("#red-ui-editor-shade").show();
|
||||
$("#red-ui-palette-shade").show();
|
||||
$("#red-ui-sidebar-shade").show();
|
||||
$.ajax({
|
||||
url: "flows",
|
||||
type: "POST",
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
headers: {
|
||||
"Node-RED-Deployment-Type": deploymentType
|
||||
}
|
||||
}).done(function (data, textStatus, xhr) {
|
||||
RED.nodes.dirty(false);
|
||||
RED.nodes.version(data.rev);
|
||||
RED.nodes.originalFlow(nns);
|
||||
if (hasUnusedConfig) {
|
||||
RED.notify(
|
||||
'<p>' + RED._("deploy.successfulDeploy") + '</p>' +
|
||||
'<p>' + RED._("deploy.unusedConfigNodes") + ' <a href="#" onclick="RED.sidebar.config.show(true); return false;">' + RED._("deploy.unusedConfigNodesLink") + '</a></p>', "success", false, 6000);
|
||||
} else {
|
||||
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
|
||||
}
|
||||
RED.nodes.eachNode(function (node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if (node.moved) {
|
||||
node.dirty = true;
|
||||
node.moved = false;
|
||||
}
|
||||
if (node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.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();
|
||||
RED.events.emit("deploy");
|
||||
}).fail(function (xhr, textStatus, err) {
|
||||
RED.nodes.dirty(true);
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
if (xhr.status === 401) {
|
||||
RED.notify(RED._("deploy.deployFailed", { message: RED._("user.notAuthorized") }), "error");
|
||||
} else if (xhr.status === 409) {
|
||||
resolveConflict(nns, true);
|
||||
} else if (xhr.responseText) {
|
||||
RED.notify(RED._("deploy.deployFailed", { message: xhr.responseText }), "error");
|
||||
} else {
|
||||
RED.notify(RED._("deploy.deployFailed", { message: RED._("deploy.errors.noResponse") }), "error");
|
||||
}
|
||||
}).always(function () {
|
||||
deployInflight = false;
|
||||
const delta = Math.max(0, 300 - (Date.now() - startTime));
|
||||
setTimeout(function () {
|
||||
$(".red-ui-deploy-button-content").css('opacity', 1);
|
||||
$(".red-ui-deploy-button-spinner").hide();
|
||||
$("#red-ui-header-shade").hide();
|
||||
$("#red-ui-editor-shade").hide();
|
||||
$("#red-ui-palette-shade").hide();
|
||||
$("#red-ui-sidebar-shade").hide();
|
||||
}, delta);
|
||||
});
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
|
||||
@@ -41,12 +41,8 @@ RED.editor.envVarList = (function() {
|
||||
style: "width:100%",
|
||||
class: "node-input-env-value",
|
||||
type: "text",
|
||||
}).attr("autocomplete","disable").appendTo(envRow);
|
||||
var types = (opt.ui && opt.ui.opts && opt.ui.opts.types);
|
||||
if (!types) {
|
||||
types = isTemplateNode ? DEFAULT_ENV_TYPE_LIST : DEFAULT_ENV_TYPE_LIST_INC_CRED;
|
||||
}
|
||||
valueField.typedInput({default:'str',types:types});
|
||||
}).attr("autocomplete","disable").appendTo(envRow)
|
||||
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
|
||||
valueField.typedInput('type', opt.type);
|
||||
if (opt.type === "cred") {
|
||||
if (opt.value) {
|
||||
@@ -98,11 +94,6 @@ RED.editor.envVarList = (function() {
|
||||
}
|
||||
opt.ui.label = opt.ui.label || {};
|
||||
opt.ui.type = opt.ui.type || "input";
|
||||
if ((opt.ui.type === "cred") &&
|
||||
opt.ui.opts &&
|
||||
opt.ui.opts.types) {
|
||||
opt.ui.type = "input";
|
||||
}
|
||||
|
||||
var uiRow = $('<div/>').appendTo(container).hide();
|
||||
// save current info for reverting on cancel
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
'b': { before:"**", after: "**", tooltip: RED._("markdownEditor.bold")},
|
||||
'i': { before:"_", after: "_", tooltip: RED._("markdownEditor.italic")},
|
||||
'code': { before:"`", after: "`", tooltip: RED._("markdownEditor.code")},
|
||||
'ol': { before:" 1. ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
|
||||
'ol': { before:" * ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
|
||||
'ul': { before:" - ", newline: true, tooltip: RED._("markdownEditor.unordered-list")},
|
||||
'bq': { before:"> ", newline: true, tooltip: RED._("markdownEditor.quote")},
|
||||
'link': { before:"[", after: "]()", tooltip: RED._("markdownEditor.link")},
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
if (!node._def.defaults || !node._def.defaults.hasOwnProperty("icon")) {
|
||||
var icon = $("#red-ui-editor-node-icon").val()||"";
|
||||
if (!this.isDefaultIcon) {
|
||||
if ((node.icon && icon !== node.icon) || (!node.icon && icon !== "")) {
|
||||
if ((icon !== node.icon) &&
|
||||
(icon !== "")) {
|
||||
editState.changes.icon = node.icon;
|
||||
node.icon = icon;
|
||||
editState.changed = true;
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
newValue = "";
|
||||
}
|
||||
}
|
||||
if (!isEqual(node[d], newValue)) {
|
||||
if (node[d] != newValue) {
|
||||
if (node._def.defaults[d].type) {
|
||||
// Change to a related config node
|
||||
var configNode = RED.nodes.node(node[d]);
|
||||
@@ -139,23 +139,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Compares `newValue` with `originalValue` for equality.
|
||||
* @param {*} originalValue Original value
|
||||
* @param {*} newValue New value
|
||||
* @returns {boolean} true if originalValue equals newValue, otherwise false
|
||||
*/
|
||||
function isEqual(originalValue, newValue) {
|
||||
try {
|
||||
if(originalValue == newValue) {
|
||||
return true;
|
||||
}
|
||||
return JSON.stringify(originalValue) === JSON.stringify(newValue);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the node credentials from the edit form
|
||||
* @param node - the node containing the credentials
|
||||
|
||||
@@ -323,6 +323,9 @@ RED.group = (function() {
|
||||
groups: [ ],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
|
||||
groups.forEach(function(g) {
|
||||
newSelection = newSelection.concat(ungroup(g))
|
||||
historyEvent.groups.push(g);
|
||||
@@ -349,8 +352,10 @@ RED.group = (function() {
|
||||
}
|
||||
if (n.type === 'group') {
|
||||
RED.events.emit("groups:change",n)
|
||||
} else {
|
||||
} else if (n.type !== 'junction') {
|
||||
RED.events.emit("nodes:change",n)
|
||||
} else {
|
||||
RED.events.emit("junctions:change",n)
|
||||
}
|
||||
})
|
||||
RED.nodes.removeGroup(g);
|
||||
@@ -544,8 +549,10 @@ RED.group = (function() {
|
||||
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
|
||||
if (n.type === 'group') {
|
||||
RED.events.emit("groups:change",n)
|
||||
} else {
|
||||
} else if (n.type !== 'junction') {
|
||||
RED.events.emit("nodes:change",n)
|
||||
} else {
|
||||
RED.events.emit("junctions:change",n)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,8 +587,10 @@ RED.group = (function() {
|
||||
}
|
||||
if (n.type === 'group') {
|
||||
RED.events.emit("groups:change",n)
|
||||
} else {
|
||||
} else if (n.type !== 'junction') {
|
||||
RED.events.emit("nodes:change",n)
|
||||
} else {
|
||||
RED.events.emit("junctions:change",n)
|
||||
}
|
||||
}
|
||||
markDirty(group);
|
||||
|
||||
@@ -363,112 +363,106 @@ RED.library = (function() {
|
||||
options.onconfirm(item);
|
||||
}
|
||||
});
|
||||
var itemTools = null;
|
||||
var itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
|
||||
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
var elementPos = menuButton.offset();
|
||||
|
||||
var menuOptionMenu = RED.menu.init({id:"red-ui-library-browser-menu",
|
||||
options: [
|
||||
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
|
||||
var defaultFolderName = "new-folder";
|
||||
var defaultFolderNameMatches = {};
|
||||
|
||||
var selected = dirList.treeList('selected');
|
||||
if (!selected.children) {
|
||||
selected = selected.parent;
|
||||
}
|
||||
var complete = function() {
|
||||
selected.children.forEach(function(c) {
|
||||
if (/^new-folder/.test(c.label)) {
|
||||
defaultFolderNameMatches[c.label] = true
|
||||
}
|
||||
});
|
||||
var folderIndex = 2;
|
||||
while(defaultFolderNameMatches[defaultFolderName]) {
|
||||
defaultFolderName = "new-folder-"+(folderIndex++)
|
||||
}
|
||||
|
||||
selected.treeList.expand();
|
||||
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
|
||||
var newItem = {
|
||||
icon: "fa fa-folder-o",
|
||||
children:[],
|
||||
path: selected.path,
|
||||
element: input
|
||||
}
|
||||
var confirmAdd = function() {
|
||||
var val = input.val().trim();
|
||||
if (val === "") {
|
||||
cancelAdd();
|
||||
return;
|
||||
} else {
|
||||
for (var i=0;i<selected.children.length;i++) {
|
||||
if (selected.children[i].label === val) {
|
||||
cancelAdd();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newItem.treeList.remove();
|
||||
var finalItem = {
|
||||
library: selected.library,
|
||||
type: selected.type,
|
||||
icon: "fa fa-folder",
|
||||
children:[],
|
||||
label: val,
|
||||
path: newItem.path+val+"/"
|
||||
}
|
||||
selected.treeList.addChild(finalItem,true);
|
||||
}
|
||||
var cancelAdd = function() {
|
||||
newItem.treeList.remove();
|
||||
}
|
||||
input.on('keydown', function(evt) {
|
||||
evt.stopPropagation();
|
||||
if (evt.keyCode === 13) {
|
||||
confirmAdd();
|
||||
} else if (evt.keyCode === 27) {
|
||||
cancelAdd();
|
||||
}
|
||||
})
|
||||
input.on("blur", function() {
|
||||
confirmAdd();
|
||||
})
|
||||
selected.treeList.addChild(newItem);
|
||||
setTimeout(function() {
|
||||
input.trigger("focus");
|
||||
input.select();
|
||||
},400);
|
||||
}
|
||||
selected.treeList.expand(complete);
|
||||
|
||||
} },
|
||||
// null,
|
||||
// {id:"red-ui-library-browser-menu-rename",label:"Rename", onselect: function() {} },
|
||||
// {id:"red-ui-library-browser-menu-delete",label:"Delete", onselect: function() {} }
|
||||
]
|
||||
}).on('mouseleave', function(){ $(this).remove(); dirList.focus() })
|
||||
.on('mouseup', function() { var self = $(this);self.hide(); dirList.focus(); setTimeout(function() { self.remove() },100)})
|
||||
.appendTo("body");
|
||||
menuOptionMenu.css({
|
||||
position: "absolute",
|
||||
top: elementPos.top+"px",
|
||||
left: (elementPos.left - menuOptionMenu.width() + 20)+"px"
|
||||
}).show();
|
||||
|
||||
}).appendTo(itemTools);
|
||||
if (options.folderTools) {
|
||||
dirList.on('treelistselect', function(event, item) {
|
||||
if (item.writable !== false && item.treeList) {
|
||||
if (itemTools) {
|
||||
itemTools.remove();
|
||||
}
|
||||
itemTools = $("<div>").css({position: "absolute",bottom:"6px",right:"8px"});
|
||||
var menuButton = $('<button class="red-ui-button red-ui-button-small" type="button"><i class="fa fa-ellipsis-h"></i></button>')
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
var elementPos = menuButton.offset();
|
||||
|
||||
var menuOptionMenu
|
||||
= RED.menu.init({id:"red-ui-library-browser-menu",
|
||||
options: [
|
||||
{id:"red-ui-library-browser-menu-addFolder",label:RED._("library.newFolder"), onselect: function() {
|
||||
var defaultFolderName = "new-folder";
|
||||
var defaultFolderNameMatches = {};
|
||||
|
||||
var selected = dirList.treeList('selected');
|
||||
if (!selected.children) {
|
||||
selected = selected.parent;
|
||||
}
|
||||
var complete = function() {
|
||||
selected.children.forEach(function(c) {
|
||||
if (/^new-folder/.test(c.label)) {
|
||||
defaultFolderNameMatches[c.label] = true
|
||||
}
|
||||
});
|
||||
var folderIndex = 2;
|
||||
while(defaultFolderNameMatches[defaultFolderName]) {
|
||||
defaultFolderName = "new-folder-"+(folderIndex++)
|
||||
}
|
||||
|
||||
selected.treeList.expand();
|
||||
var input = $('<input type="text" class="red-ui-treeList-input">').val(defaultFolderName);
|
||||
var newItem = {
|
||||
icon: "fa fa-folder-o",
|
||||
children:[],
|
||||
path: selected.path,
|
||||
element: input
|
||||
}
|
||||
var confirmAdd = function() {
|
||||
var val = input.val().trim();
|
||||
if (val === "") {
|
||||
cancelAdd();
|
||||
return;
|
||||
} else {
|
||||
for (var i=0;i<selected.children.length;i++) {
|
||||
if (selected.children[i].label === val) {
|
||||
cancelAdd();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newItem.treeList.remove();
|
||||
var finalItem = {
|
||||
library: selected.library,
|
||||
type: selected.type,
|
||||
icon: "fa fa-folder",
|
||||
children:[],
|
||||
label: val,
|
||||
path: newItem.path+val+"/"
|
||||
}
|
||||
selected.treeList.addChild(finalItem,true);
|
||||
}
|
||||
var cancelAdd = function() {
|
||||
newItem.treeList.remove();
|
||||
}
|
||||
input.on('keydown', function(evt) {
|
||||
evt.stopPropagation();
|
||||
if (evt.keyCode === 13) {
|
||||
confirmAdd();
|
||||
} else if (evt.keyCode === 27) {
|
||||
cancelAdd();
|
||||
}
|
||||
})
|
||||
input.on("blur", function() {
|
||||
confirmAdd();
|
||||
})
|
||||
selected.treeList.addChild(newItem);
|
||||
setTimeout(function() {
|
||||
input.trigger("focus");
|
||||
input.select();
|
||||
},400);
|
||||
}
|
||||
selected.treeList.expand(complete);
|
||||
|
||||
} },
|
||||
// null,
|
||||
// {id:"red-ui-library-browser-menu-rename",label:"Rename", onselect: function() {} },
|
||||
// {id:"red-ui-library-browser-menu-delete",label:"Delete", onselect: function() {} }
|
||||
]
|
||||
}).on('mouseleave', function(){ $(this).remove(); dirList.focus() })
|
||||
.on('mouseup', function() { var self = $(this);self.hide(); dirList.focus(); setTimeout(function() { self.remove() },100)})
|
||||
.appendTo("body");
|
||||
menuOptionMenu.css({
|
||||
position: "absolute",
|
||||
top: elementPos.top+"px",
|
||||
left: (elementPos.left - menuOptionMenu.width() + 20)+"px"
|
||||
}).show();
|
||||
|
||||
}).appendTo(itemTools);
|
||||
|
||||
itemTools.appendTo(item.treeList.label);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -208,7 +208,7 @@ RED.palette = (function() {
|
||||
}
|
||||
|
||||
function escapeCategory(category) {
|
||||
return category.replace(/[\x00-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]/g,"_");
|
||||
return category.replace(/[ /.]/g,"_");
|
||||
}
|
||||
function addNodeType(nt,def) {
|
||||
if (getPaletteNode(nt).length) {
|
||||
@@ -224,14 +224,7 @@ RED.palette = (function() {
|
||||
|
||||
var d = $('<div>',{class:"red-ui-palette-node"}).attr("data-palette-type",nt).data('category',rootCategory);
|
||||
|
||||
var label = nt;///^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
|
||||
if (typeof def.paletteLabel !== "undefined") {
|
||||
try {
|
||||
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+nt+".paletteLabel",err);
|
||||
}
|
||||
}
|
||||
var label = RED.utils.getPaletteLabel(nt, def);///^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
|
||||
|
||||
$('<div/>', {
|
||||
class: "red-ui-palette-label"+(((!def.align && def.inputs !== 0 && def.outputs === 0) || "right" === def.align) ? " red-ui-palette-label-right" : "")
|
||||
|
||||
@@ -25,6 +25,8 @@ RED.search = (function() {
|
||||
var searchHistory = [];
|
||||
var index = {};
|
||||
var currentResults = [];
|
||||
var activeResults = [];
|
||||
var currentIndex = 0;
|
||||
var previousActiveElement;
|
||||
|
||||
function indexProperty(node,label,property) {
|
||||
@@ -119,6 +121,7 @@ RED.search = (function() {
|
||||
val = extractFlag(val,"config",flags);
|
||||
val = extractFlag(val,"subflow",flags);
|
||||
val = extractFlag(val,"hidden",flags);
|
||||
val = extractFlag(val,"modified",flags);
|
||||
// uses:<node-id>
|
||||
val = extractValue(val,"uses",flags);
|
||||
|
||||
@@ -141,7 +144,7 @@ RED.search = (function() {
|
||||
var key = keys[i];
|
||||
var kpos = keys[i].indexOf(val);
|
||||
if (kpos > -1) {
|
||||
var ids = Object.keys(index[key]||{});
|
||||
var ids = Object.keys(index[key]);
|
||||
for (j=0;j<ids.length;j++) {
|
||||
var node = index[key][ids[j]];
|
||||
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
|
||||
@@ -164,6 +167,11 @@ RED.search = (function() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("modified")) {
|
||||
if (!node.node.changed && !node.node.moved) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("hidden")) {
|
||||
// Only tabs can be hidden
|
||||
if (node.node.type !== 'tab') {
|
||||
@@ -247,7 +255,7 @@ RED.search = (function() {
|
||||
}
|
||||
currentResults = search(value);
|
||||
if (currentResults.length > 0) {
|
||||
for (let i=0;i<Math.min(currentResults.length,25);i++) {
|
||||
for (i=0;i<Math.min(currentResults.length,25);i++) {
|
||||
searchResults.editableList('addItem',currentResults[i])
|
||||
}
|
||||
if (currentResults.length > 25) {
|
||||
@@ -261,9 +269,8 @@ RED.search = (function() {
|
||||
} else {
|
||||
searchResults.editableList('addItem',{});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
options: getSearchOptions()
|
||||
});
|
||||
var copySearchContainer = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-caret-right"></button>').appendTo(searchDiv).on('click', function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -324,7 +331,8 @@ RED.search = (function() {
|
||||
}
|
||||
} else if (!$(children[selected]).hasClass("red-ui-search-historyHeader")) {
|
||||
if (currentResults.length > 0) {
|
||||
reveal(currentResults[Math.max(0,selected)].node);
|
||||
currentIndex = Math.max(0,selected);
|
||||
reveal(currentResults[currentIndex].node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,6 +416,7 @@ RED.search = (function() {
|
||||
|
||||
div.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
currentIndex = i;
|
||||
reveal(node);
|
||||
});
|
||||
}
|
||||
@@ -423,13 +432,59 @@ RED.search = (function() {
|
||||
if (existingIndex > -1) {
|
||||
searchHistory.splice(existingIndex,1);
|
||||
}
|
||||
searchHistory.unshift(searchInput.val());
|
||||
hide();
|
||||
searchHistory.unshift(searchVal);
|
||||
$("#red-ui-view-searchtools-search").data("term", searchVal);
|
||||
activeResults = Object.assign([], currentResults);
|
||||
hide(null, activeResults.length > 0);
|
||||
RED.view.reveal(node.id);
|
||||
}
|
||||
|
||||
function revealPrev() {
|
||||
if (disabled) {
|
||||
updateSearchToolbar();
|
||||
return;
|
||||
}
|
||||
if (!searchResults || !activeResults.length) {
|
||||
show();
|
||||
return;
|
||||
}
|
||||
if (currentIndex > 0) {
|
||||
currentIndex--;
|
||||
} else {
|
||||
currentIndex = activeResults.length - 1;
|
||||
}
|
||||
const n = activeResults[currentIndex];
|
||||
if (n && n.node && n.node.id) {
|
||||
RED.view.reveal(n.node.id);
|
||||
$("#red-ui-view-searchtools-prev").trigger("focus");
|
||||
}
|
||||
updateSearchToolbar();
|
||||
}
|
||||
function revealNext() {
|
||||
if (disabled) {
|
||||
updateSearchToolbar();
|
||||
return;
|
||||
}
|
||||
if (!searchResults || !activeResults.length) {
|
||||
show();
|
||||
return;
|
||||
}
|
||||
if (currentIndex < activeResults.length - 1) {
|
||||
currentIndex++
|
||||
} else {
|
||||
currentIndex = 0;
|
||||
}
|
||||
const n = activeResults[currentIndex];
|
||||
if (n && n.node && n.node.id) {
|
||||
RED.view.reveal(n.node.id);
|
||||
$("#red-ui-view-searchtools-next").trigger("focus");
|
||||
}
|
||||
updateSearchToolbar();
|
||||
}
|
||||
|
||||
function show(v) {
|
||||
if (disabled) {
|
||||
updateSearchToolbar();
|
||||
return;
|
||||
}
|
||||
if (!visible) {
|
||||
@@ -456,7 +511,7 @@ RED.search = (function() {
|
||||
searchInput.trigger("focus");
|
||||
}
|
||||
|
||||
function hide() {
|
||||
function hide(el, keepSearchToolbar) {
|
||||
if (visible) {
|
||||
visible = false;
|
||||
$("#red-ui-header-shade").hide();
|
||||
@@ -470,13 +525,37 @@ RED.search = (function() {
|
||||
});
|
||||
}
|
||||
RED.events.emit("search:close");
|
||||
if (previousActiveElement) {
|
||||
if (previousActiveElement && (!keepSearchToolbar || !activeResults.length)) {
|
||||
$(previousActiveElement).trigger("focus");
|
||||
previousActiveElement = null;
|
||||
}
|
||||
previousActiveElement = null;
|
||||
}
|
||||
if(!keepSearchToolbar) {
|
||||
clearActiveSearch();
|
||||
}
|
||||
updateSearchToolbar();
|
||||
if(keepSearchToolbar && activeResults.length) {
|
||||
$("#red-ui-view-searchtools-next").trigger("focus");
|
||||
}
|
||||
}
|
||||
function updateSearchToolbar() {
|
||||
if (!disabled && currentIndex >= 0 && activeResults && activeResults.length) {
|
||||
let term = $("#red-ui-view-searchtools-search").data("term") || "";
|
||||
if (term.length > 16) {
|
||||
term = term.substring(0, 12) + "..."
|
||||
}
|
||||
const i18nSearchCounterData = {
|
||||
term: term,
|
||||
result: (currentIndex + 1),
|
||||
count: activeResults.length
|
||||
}
|
||||
$("#red-ui-view-searchtools-counter").text(RED._('actions.search-counter', i18nSearchCounterData));
|
||||
$("#view-search-tools > :not(:first-child)").show(); //show other tools
|
||||
} else {
|
||||
clearActiveSearch();
|
||||
$("#view-search-tools > :not(:first-child)").hide(); //hide all but search button
|
||||
}
|
||||
}
|
||||
|
||||
function clearIndex() {
|
||||
index = {};
|
||||
}
|
||||
@@ -498,9 +577,29 @@ RED.search = (function() {
|
||||
addItemToIndex(item);
|
||||
}
|
||||
|
||||
function clearActiveSearch() {
|
||||
activeResults = [];
|
||||
currentIndex = 0;
|
||||
$("#red-ui-view-searchtools-search").data("term", "");
|
||||
}
|
||||
|
||||
function getSearchOptions() {
|
||||
return [
|
||||
{label:RED._("search.options.configNodes"), value:"is:config"},
|
||||
{label:RED._("search.options.unusedConfigNodes"), value:"is:config is:unused"},
|
||||
{label:RED._("search.options.modifiedNodes"), value:"is:modified"},
|
||||
{label:RED._("search.options.invalidNodes"), value: "is:invalid"},
|
||||
{label:RED._("search.options.uknownNodes"), value: "type:unknown"},
|
||||
{label:RED._("search.options.unusedSubflows"), value:"is:subflow is:unused"},
|
||||
{label:RED._("search.options.hiddenFlows"), value:"is:hidden"},
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
function init() {
|
||||
RED.actions.add("core:search",show);
|
||||
RED.actions.add("core:search-previous",revealPrev);
|
||||
RED.actions.add("core:search-next",revealNext);
|
||||
|
||||
RED.events.on("editor:open",function() { disabled = true; });
|
||||
RED.events.on("editor:close",function() { disabled = false; });
|
||||
@@ -511,11 +610,21 @@ RED.search = (function() {
|
||||
|
||||
RED.keyboard.add("red-ui-search","escape",hide);
|
||||
|
||||
RED.keyboard.add("view-search-tools","escape",function() {
|
||||
clearActiveSearch();
|
||||
updateSearchToolbar();
|
||||
});
|
||||
|
||||
$("#red-ui-header-shade").on('mousedown',hide);
|
||||
$("#red-ui-editor-shade").on('mousedown',hide);
|
||||
$("#red-ui-palette-shade").on('mousedown',hide);
|
||||
$("#red-ui-sidebar-shade").on('mousedown',hide);
|
||||
|
||||
$("#red-ui-view-searchtools-close").on("click", function close() {
|
||||
clearActiveSearch();
|
||||
updateSearchToolbar();
|
||||
});
|
||||
$("#red-ui-view-searchtools-close").trigger("click");
|
||||
|
||||
RED.events.on("workspace:clear", clearIndex);
|
||||
|
||||
@@ -541,7 +650,8 @@ RED.search = (function() {
|
||||
init: init,
|
||||
show: show,
|
||||
hide: hide,
|
||||
search: search
|
||||
search: search,
|
||||
getSearchOptions: getSearchOptions
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -29,5 +29,6 @@ RED.state = {
|
||||
GROUP_DRAGGING: 12,
|
||||
GROUP_RESIZE: 13,
|
||||
DETACHED_DRAGGING: 14,
|
||||
SLICING: 15
|
||||
SLICING: 15,
|
||||
SLICING_JUNCTION: 16
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ RED.statusBar = (function() {
|
||||
function addWidget(options) {
|
||||
widgets[options.id] = options;
|
||||
var el = $('<span class="red-ui-statusbar-widget"></span>');
|
||||
el.prop('id', options.id);
|
||||
options.element.appendTo(el);
|
||||
if (options.align === 'left') {
|
||||
leftBucket.append(el);
|
||||
|
||||
@@ -983,17 +983,6 @@ RED.subflow = (function() {
|
||||
default: inputType
|
||||
})
|
||||
input.typedInput('value',val.value)
|
||||
if (inputType === 'cred') {
|
||||
if (node.credentials) {
|
||||
if (node.credentials[tenv.name]) {
|
||||
input.typedInput('value', node.credentials[tenv.name]);
|
||||
} else if (node.credentials['has_'+tenv.name]) {
|
||||
input.typedInput('value', "__PWRD__")
|
||||
} else {
|
||||
input.typedInput('value', "");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
input.val(val.value)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
**/
|
||||
RED.sidebar.config = (function() {
|
||||
|
||||
let flashingConfigNode;
|
||||
let flashingConfigNodeTimer;
|
||||
|
||||
var content = document.createElement("div");
|
||||
content.className = "red-ui-sidebar-node-config";
|
||||
@@ -145,6 +147,7 @@ RED.sidebar.config = (function() {
|
||||
var entry = $('<li class="red-ui-palette-node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list);
|
||||
var nodeDiv = $('<div class="red-ui-palette-node-config red-ui-palette-node"></div>').appendTo(entry);
|
||||
entry.data('node',node.id);
|
||||
nodeDiv.data('node',node.id);
|
||||
var label = $('<div class="red-ui-palette-label"></div>').text(label).appendTo(nodeDiv);
|
||||
if (node.d) {
|
||||
nodeDiv.addClass("red-ui-palette-node-config-disabled");
|
||||
@@ -346,10 +349,36 @@ RED.sidebar.config = (function() {
|
||||
refreshConfigNodeList();
|
||||
}
|
||||
});
|
||||
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllConfigNodes"));
|
||||
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllUnusedConfigNodes"));
|
||||
RED.popover.tooltip($('#red-ui-sidebar-config-filter-unused'), RED._("sidebar.config.showAllUnusedConfigNodes"));
|
||||
|
||||
}
|
||||
|
||||
function flashConfigNode(el) {
|
||||
if(flashingConfigNode && flashingConfigNode.length) {
|
||||
//cancel current flashing node before flashing new node
|
||||
clearInterval(flashingConfigNodeTimer);
|
||||
flashingConfigNodeTimer = null;
|
||||
flashingConfigNode.children("div").removeClass('highlighted');
|
||||
flashingConfigNode = null;
|
||||
}
|
||||
if(!el || !el.children("div").length) { return; }
|
||||
|
||||
flashingConfigNodeTimer = setInterval(function(flashEndTime) {
|
||||
if (flashEndTime >= Date.now()) {
|
||||
const highlighted = el.children("div").hasClass("highlighted");
|
||||
el.children("div").toggleClass('highlighted', !highlighted)
|
||||
} else {
|
||||
clearInterval(flashingConfigNodeTimer);
|
||||
flashingConfigNodeTimer = null;
|
||||
flashingConfigNode = null;
|
||||
el.children("div").removeClass('highlighted');
|
||||
}
|
||||
}, 100, Date.now() + 2200);
|
||||
flashingConfigNode = el;
|
||||
el.children("div").addClass('highlighted');
|
||||
}
|
||||
|
||||
function show(id) {
|
||||
if (typeof id === 'boolean') {
|
||||
if (id) {
|
||||
@@ -374,19 +403,7 @@ RED.sidebar.config = (function() {
|
||||
} else if (y<0) {
|
||||
scrollWindow.animate({scrollTop: '+='+(y-10)},150);
|
||||
}
|
||||
var flash = 21;
|
||||
var flashFunc = function() {
|
||||
if ((flash%2)===0) {
|
||||
node.removeClass('node_highlighted');
|
||||
} else {
|
||||
node.addClass('node_highlighted');
|
||||
}
|
||||
flash--;
|
||||
if (flash >= 0) {
|
||||
setTimeout(flashFunc,100);
|
||||
}
|
||||
}
|
||||
flashFunc();
|
||||
flashConfigNode(node, id);
|
||||
},100);
|
||||
}
|
||||
RED.sidebar.show("config");
|
||||
|
||||
@@ -370,7 +370,7 @@ RED.sidebar.help = (function() {
|
||||
var node = selection.nodes[0];
|
||||
if (node.type === "subflow" && node.direction) {
|
||||
// ignore subflow virtual ports
|
||||
} else if (node.type !== 'group'){
|
||||
} else if (node.type !== 'group' && node.type !== 'junction'){
|
||||
showNodeTypeHelp(node.type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,14 +268,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
|
||||
}
|
||||
},
|
||||
options: [
|
||||
{label:RED._("sidebar.info.search.configNodes"), value:"is:config"},
|
||||
{label:RED._("sidebar.info.search.unusedConfigNodes"), value:"is:config is:unused"},
|
||||
{label:RED._("sidebar.info.search.invalidNodes"), value: "is:invalid"},
|
||||
{label:RED._("sidebar.info.search.uknownNodes"), value: "type:unknown"},
|
||||
{label:RED._("sidebar.info.search.unusedSubflows"), value:"is:subflow is:unused"},
|
||||
{label:RED._("sidebar.info.search.hiddenFlows"), value:"is:hidden"},
|
||||
]
|
||||
options: RED.search.getSearchOptions()
|
||||
});
|
||||
|
||||
projectInfo = $('<div class="red-ui-treeList-label red-ui-info-outline-project"><span class="red-ui-treeList-icon"><i class="fa fa-archive"></i></span></div>').hide().appendTo(container)
|
||||
@@ -287,15 +280,18 @@ RED.sidebar.info.outliner = (function() {
|
||||
data:getFlowData()
|
||||
})
|
||||
treeList.on('treelistselect', function(e,item) {
|
||||
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id);
|
||||
var node = RED.nodes.node(item.id) || RED.nodes.group(item.id) || RED.nodes.workspace(item.id) || RED.nodes.subflow(item.id);
|
||||
if (node) {
|
||||
if (node.type === 'group' || node._def.category !== "config") {
|
||||
// RED.view.select({nodes:[node]})
|
||||
} else if (node._def.category === "config") {
|
||||
RED.sidebar.info.refresh(node);
|
||||
} else {
|
||||
// RED.view.select({nodes:[]})
|
||||
}
|
||||
RED.sidebar.info.refresh(node);
|
||||
// if (node.type === 'group' || node._def.category !== "config") {
|
||||
// // RED.view.select({nodes:[node]})
|
||||
// } else if (node._def.category === "config") {
|
||||
// RED.sidebar.info.refresh(node);
|
||||
// } else {
|
||||
// // RED.view.select({nodes:[]})
|
||||
// }
|
||||
} else {
|
||||
RED.sidebar.info.refresh(null);
|
||||
}
|
||||
})
|
||||
treeList.on('treelistconfirm', function(e,item) {
|
||||
|
||||
@@ -163,6 +163,7 @@ RED.sidebar.info = (function() {
|
||||
});
|
||||
return el;
|
||||
}
|
||||
|
||||
function refresh(node) {
|
||||
if (node === undefined) {
|
||||
refreshSelection();
|
||||
@@ -271,7 +272,7 @@ RED.sidebar.info = (function() {
|
||||
objectType = "group";
|
||||
}
|
||||
$(propRow.children()[0]).text(RED._("sidebar.info."+objectType))
|
||||
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
|
||||
RED.utils.createObjectElement(node.id,{sourceId: node.id}).appendTo(propRow.children()[1]);
|
||||
|
||||
if (node.type === "tab" || node.type === "subflow") {
|
||||
// If nothing is selected, but we're on a flow or subflow tab.
|
||||
@@ -301,8 +302,8 @@ RED.sidebar.info = (function() {
|
||||
if (typeCounts.groups > 0) {
|
||||
$('<div>').text(RED._("clipboard.group",{count:typeCounts.groups})).appendTo(counts);
|
||||
}
|
||||
|
||||
|
||||
} else if (node.type === 'junction') {
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
} else {
|
||||
propertiesPanelHeaderHelp.show();
|
||||
|
||||
@@ -365,7 +366,7 @@ RED.sidebar.info = (function() {
|
||||
|
||||
}
|
||||
} else {
|
||||
RED.utils.createObjectElement(val).appendTo(propRow.children()[1]);
|
||||
RED.utils.createObjectElement(val,{sourceId: node.id}).appendTo(propRow.children()[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,6 +432,7 @@ RED.sidebar.info = (function() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
function setInfoText(infoText,target) {
|
||||
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
|
||||
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
|
||||
@@ -447,6 +449,7 @@ RED.sidebar.info = (function() {
|
||||
$(this).toggleClass('expanded',!isExpanded);
|
||||
})
|
||||
}
|
||||
|
||||
var tips = (function() {
|
||||
var enabled = true;
|
||||
var startDelay = 1000;
|
||||
|
||||
@@ -171,17 +171,21 @@ RED.typeSearch = (function() {
|
||||
var div = $('<div>',{class:"red-ui-search-result"}).appendTo(container);
|
||||
|
||||
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
|
||||
var colour = RED.utils.getNodeColor(object.type,def);
|
||||
if (object.type === "junction") {
|
||||
nodeDiv.addClass("red-ui-palette-icon-junction");
|
||||
} else {
|
||||
var colour = RED.utils.getNodeColor(object.type,def);
|
||||
nodeDiv.css('backgroundColor',colour);
|
||||
}
|
||||
var icon_url = RED.utils.getNodeIcon(def);
|
||||
nodeDiv.css('backgroundColor',colour);
|
||||
|
||||
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
||||
RED.utils.createIconElement(icon_url, iconContainer, false);
|
||||
|
||||
if (def.inputs > 0) {
|
||||
if (object.type !== "junction" && def.inputs > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
|
||||
}
|
||||
if (def.outputs > 0) {
|
||||
if (object.type !== "junction" && def.outputs > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
|
||||
}
|
||||
|
||||
@@ -313,8 +317,8 @@ RED.typeSearch = (function() {
|
||||
return !filter ||
|
||||
(
|
||||
(!filter.type || type === filter.type) &&
|
||||
(!filter.input || def.inputs > 0) &&
|
||||
(!filter.output || def.outputs > 0)
|
||||
(!filter.input || type === 'junction' || def.inputs > 0) &&
|
||||
(!filter.output || type === 'junction' || def.outputs > 0)
|
||||
)
|
||||
}
|
||||
function refreshTypeList(opts) {
|
||||
@@ -323,7 +327,7 @@ RED.typeSearch = (function() {
|
||||
searchInput.searchBox('value','').focus();
|
||||
selected = -1;
|
||||
var common = [
|
||||
'inject','debug','function','change','switch'
|
||||
'inject','debug','function','change','switch','junction'
|
||||
].filter(function(t) { return applyFilter(opts.filter,t,RED.nodes.getType(t)); });
|
||||
|
||||
var recentlyUsed = Object.keys(typesUsed);
|
||||
@@ -348,6 +352,9 @@ RED.typeSearch = (function() {
|
||||
var index = 0;
|
||||
for(i=0;i<common.length;i++) {
|
||||
var itemDef = RED.nodes.getType(common[i]);
|
||||
if (common[i] === 'junction') {
|
||||
itemDef = { inputs:1, outputs: 1, label: 'junction', type: 'junction'}
|
||||
}
|
||||
if (itemDef) {
|
||||
item = {
|
||||
type: common[i],
|
||||
|
||||
@@ -365,7 +365,16 @@ RED.utils = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function buildMessageElement(obj,options) {
|
||||
/**
|
||||
* Create a DOM element representation of obj - as used by Debug sidebar etc
|
||||
*
|
||||
* @params obj - the data to display
|
||||
* @params options - a bag of options
|
||||
*
|
||||
* - If you want the Copy Value button, then set `sourceId`
|
||||
* - If you want the Copy Path button, also set `path` to the value to be copied
|
||||
*/
|
||||
function createObjectElement(obj,options) {
|
||||
options = options || {};
|
||||
var key = options.key;
|
||||
var typeHint = options.typeHint;
|
||||
@@ -555,7 +564,7 @@ RED.utils = (function() {
|
||||
if (fullLength <= 10) {
|
||||
for (i=0;i<fullLength;i++) {
|
||||
row = $('<div class="red-ui-debug-msg-object-entry collapsed"></div>').appendTo(arrayRows);
|
||||
subElements[path+"["+i+"]"] = buildMessageElement(
|
||||
subElements[path+"["+i+"]"] = createObjectElement(
|
||||
data[i],
|
||||
{
|
||||
key: ""+i,
|
||||
@@ -585,7 +594,7 @@ RED.utils = (function() {
|
||||
return function() {
|
||||
for (var i=min;i<=max;i++) {
|
||||
var row = $('<div class="red-ui-debug-msg-object-entry collapsed"></div>').appendTo(parent);
|
||||
subElements[path+"["+i+"]"] = buildMessageElement(
|
||||
subElements[path+"["+i+"]"] = createObjectElement(
|
||||
data[i],
|
||||
{
|
||||
key: ""+i,
|
||||
@@ -641,7 +650,7 @@ RED.utils = (function() {
|
||||
newPath += "[\""+keys[i].replace(/"/,"\\\"")+"\"]"
|
||||
}
|
||||
}
|
||||
subElements[newPath] = buildMessageElement(
|
||||
subElements[newPath] = createObjectElement(
|
||||
data[keys[i]],
|
||||
{
|
||||
key: keys[i],
|
||||
@@ -1019,6 +1028,8 @@ RED.utils = (function() {
|
||||
return "font-awesome/fa-object-ungroup";
|
||||
} else if (node && node.type === 'group') {
|
||||
return "font-awesome/fa-object-group"
|
||||
} else if ((node && node.type === 'junction') || (def.type === "junction") ) {
|
||||
return "font-awesome/fa-circle-o"
|
||||
} else if (def.category === 'config') {
|
||||
return RED.settings.apiRootUrl+"icons/node-red/cog.svg"
|
||||
} else if (node && node.type === 'tab') {
|
||||
@@ -1084,6 +1095,8 @@ RED.utils = (function() {
|
||||
l = node.label || defaultLabel
|
||||
} else if (node.type === 'group') {
|
||||
l = node.name || defaultLabel
|
||||
} else if (node.type === 'junction') {
|
||||
l = 'junction'
|
||||
} else {
|
||||
l = node._def.label;
|
||||
try {
|
||||
@@ -1096,6 +1109,18 @@ RED.utils = (function() {
|
||||
return RED.text.bidi.enforceTextDirectionWithUCC(l);
|
||||
}
|
||||
|
||||
function getPaletteLabel(nodeType, def) {
|
||||
var label = nodeType;
|
||||
if (typeof def.paletteLabel !== "undefined") {
|
||||
try {
|
||||
label = (typeof def.paletteLabel === "function" ? def.paletteLabel.call(def) : def.paletteLabel)||"";
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+nodeType+".paletteLabel",err);
|
||||
}
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
var nodeColorCache = {};
|
||||
function clearNodeColorCache() {
|
||||
nodeColorCache = {};
|
||||
@@ -1238,6 +1263,8 @@ RED.utils = (function() {
|
||||
nodeDiv.addClass("red-ui-palette-icon-selection");
|
||||
} else if (node.type === "group") {
|
||||
nodeDiv.addClass("red-ui-palette-icon-group");
|
||||
} else if (node.type === "junction") {
|
||||
nodeDiv.addClass("red-ui-palette-icon-junction");
|
||||
} else if (node.type === 'tab') {
|
||||
nodeDiv.addClass("red-ui-palette-icon-flow");
|
||||
} else {
|
||||
@@ -1369,7 +1396,7 @@ RED.utils = (function() {
|
||||
}
|
||||
|
||||
return {
|
||||
createObjectElement: buildMessageElement,
|
||||
createObjectElement: createObjectElement,
|
||||
getMessageProperty: getMessageProperty,
|
||||
setMessageProperty: setMessageProperty,
|
||||
normalisePropertyExpression: normalisePropertyExpression,
|
||||
@@ -1379,6 +1406,7 @@ RED.utils = (function() {
|
||||
getNodeIcon: getNodeIcon,
|
||||
getNodeLabel: getNodeLabel,
|
||||
getNodeColor: getNodeColor,
|
||||
getPaletteLabel: getPaletteLabel,
|
||||
clearNodeColorCache: clearNodeColorCache,
|
||||
addSpinnerOverlay: addSpinnerOverlay,
|
||||
decodeObject: decodeObject,
|
||||
|
||||
@@ -809,6 +809,231 @@ RED.view.tools = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits selected wires and re-joins them with link-out+link-in
|
||||
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
|
||||
*/
|
||||
function splitWiresWithLinkNodes(wires) {
|
||||
let wiresToSplit = wires || RED.view.selection().links;
|
||||
if (!Array.isArray(wiresToSplit)) {
|
||||
wiresToSplit = [wiresToSplit];
|
||||
}
|
||||
if (wiresToSplit.length < 1) {
|
||||
return; //nothing selected
|
||||
}
|
||||
|
||||
const history = {
|
||||
t: 'multi',
|
||||
events: [],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
const nodeSrcMap = {};
|
||||
const nodeTrgMap = {};
|
||||
const _gridSize = RED.view.gridSize();
|
||||
|
||||
for (let wireIdx = 0; wireIdx < wiresToSplit.length; wireIdx++) {
|
||||
const wire = wiresToSplit[wireIdx];
|
||||
|
||||
//get source and target nodes of this wire link
|
||||
const nSrc = wire.source;
|
||||
const nTrg = wire.target;
|
||||
|
||||
var updateNewNodePosXY = function (origNode, newNode, alignLeft, snap, yOffset) {
|
||||
const nnSize = RED.view.calculateNodeDimensions(newNode);
|
||||
newNode.w = nnSize[0];
|
||||
newNode.h = nnSize[1];
|
||||
const coords = { x: origNode.x || 0, y: origNode.y || 0, w: origNode.w || RED.view.node_width, h: origNode.h || RED.view.node_height };
|
||||
const x = coords.x - (coords.w/2.0);
|
||||
if (alignLeft) {
|
||||
coords.x = x - _gridSize - (newNode.w/2.0);
|
||||
} else {
|
||||
coords.x = x + coords.w + _gridSize + (newNode.w/2.0);
|
||||
}
|
||||
newNode.x = coords.x;
|
||||
newNode.y = coords.y;
|
||||
if (snap !== false) {
|
||||
const offsets = RED.view.tools.calculateGridSnapOffsets(newNode);
|
||||
newNode.x -= offsets.x;
|
||||
newNode.y -= offsets.y;
|
||||
}
|
||||
newNode.y += (yOffset || 0);
|
||||
}
|
||||
const srcPort = (wire.sourcePort || 0);
|
||||
let linkOutMapId = nSrc.id + ':' + srcPort;
|
||||
let nnLinkOut = nodeSrcMap[linkOutMapId];
|
||||
//Create a Link Out if one is not already present
|
||||
if(!nnLinkOut) {
|
||||
const nLinkOut = RED.view.createNode("link out"); //create link node
|
||||
nnLinkOut = nLinkOut.node;
|
||||
nodeSrcMap[linkOutMapId] = nnLinkOut;
|
||||
let yOffset = 0;
|
||||
if(nSrc.outputs > 1) {
|
||||
|
||||
const CENTER_PORT = (((nSrc.outputs-1) / 2) + 1);
|
||||
const offsetCount = Math.abs(CENTER_PORT - (srcPort + 1));
|
||||
yOffset = (_gridSize * 2 * offsetCount);
|
||||
if((srcPort + 1) < CENTER_PORT) {
|
||||
yOffset = -yOffset;
|
||||
}
|
||||
updateNewNodePosXY(nSrc, nnLinkOut, false, false, yOffset);
|
||||
} else {
|
||||
updateNewNodePosXY(nSrc, nnLinkOut, false, RED.view.snapGrid, yOffset);
|
||||
}
|
||||
//add created node
|
||||
RED.nodes.add(nnLinkOut);
|
||||
RED.editor.validateNode(nnLinkOut);
|
||||
history.events.push(nLinkOut.historyEvent);
|
||||
//connect node to link node
|
||||
const link = {
|
||||
source: nSrc,
|
||||
sourcePort: wire.sourcePort || 0,
|
||||
target: nnLinkOut
|
||||
};
|
||||
RED.nodes.addLink(link);
|
||||
history.events.push({
|
||||
t: 'add',
|
||||
links: [link],
|
||||
});
|
||||
}
|
||||
|
||||
let nnLinkIn = nodeTrgMap[nTrg.id];
|
||||
//Create a Link In if one is not already present
|
||||
if(!nnLinkIn) {
|
||||
const nLinkIn = RED.view.createNode("link in"); //create link node
|
||||
nnLinkIn = nLinkIn.node;
|
||||
nodeTrgMap[nTrg.id] = nnLinkIn;
|
||||
updateNewNodePosXY(nTrg, nnLinkIn, true, RED.view.snapGrid, 0);
|
||||
//add created node
|
||||
RED.nodes.add(nnLinkIn);
|
||||
RED.editor.validateNode(nnLinkIn);
|
||||
history.events.push(nLinkIn.historyEvent);
|
||||
//connect node to link node
|
||||
const link = {
|
||||
source: nnLinkIn,
|
||||
sourcePort: 0,
|
||||
target: nTrg
|
||||
};
|
||||
RED.nodes.addLink(link);
|
||||
history.events.push({
|
||||
t: 'add',
|
||||
links: [link],
|
||||
});
|
||||
}
|
||||
|
||||
//connect the link out/link in virtual wires
|
||||
if(nnLinkIn.links.indexOf(nnLinkOut.id) == -1) {
|
||||
nnLinkIn.links.push(nnLinkOut.id);
|
||||
}
|
||||
if(nnLinkOut.links.indexOf(nnLinkIn.id) == -1) {
|
||||
nnLinkOut.links.push(nnLinkIn.id);
|
||||
}
|
||||
|
||||
//delete the original wire
|
||||
RED.nodes.removeLink(wire);
|
||||
history.events.push({
|
||||
t: "delete",
|
||||
links: [wire]
|
||||
});
|
||||
}
|
||||
//add all history events to stack
|
||||
RED.history.push(history);
|
||||
|
||||
//select all downstream of new link-in nodes so user can drag to new location
|
||||
RED.view.clearSelection();
|
||||
RED.view.select({nodes: Object.values(nodeTrgMap) });
|
||||
selectConnected("down");
|
||||
|
||||
//update the view
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the required offsets to snap a node
|
||||
* @param {Object} node The node to calculate grid snap offsets for
|
||||
* @param {Object} [options] Options: `align` can be "nearest", "left" or "right"
|
||||
* @returns `{x:number, y:number}` as the offsets to deduct from `x` and `y`
|
||||
*/
|
||||
function calculateGridSnapOffsets(node, options) {
|
||||
options = options || { align: "nearest" };
|
||||
const gridOffset = { x: 0, y: 0 };
|
||||
const gridSize = RED.view.gridSize();
|
||||
const offsetLeft = node.x - (gridSize * Math.round((node.x - node.w / 2) / gridSize) + node.w / 2);
|
||||
const offsetRight = node.x - (gridSize * Math.round((node.x + node.w / 2) / gridSize) - node.w / 2);
|
||||
gridOffset.x = offsetRight;
|
||||
if (options.align === "right") {
|
||||
//skip - already set to right
|
||||
} else if (options.align === "left" || Math.abs(offsetLeft) < Math.abs(offsetRight)) {
|
||||
gridOffset.x = offsetLeft;
|
||||
}
|
||||
gridOffset.y = node.y - (gridSize * Math.round(node.y / gridSize));
|
||||
return gridOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate names for the select nodes.
|
||||
* - it only sets the name if it is currently blank
|
||||
* - it uses `<paletteLabel> <N>` - where N is the next available integer that
|
||||
* doesn't clash with any existing nodes of that type
|
||||
* @param {Object} node The node to set the name of - if not provided, uses current selection
|
||||
*/
|
||||
function generateNodeNames(node) {
|
||||
const nodes = node?[node]:RED.view.selection().nodes;
|
||||
if (nodes && nodes.length > 0) {
|
||||
// Generate history event if using the workspace selection,
|
||||
// or if the provided node already exists
|
||||
const generateHistory = !node || !!RED.nodes.node(node.id)
|
||||
const historyEvents = []
|
||||
const typeIndex = {}
|
||||
let changed = false;
|
||||
nodes.forEach(n => {
|
||||
if (n._def && n._def.defaults && n._def.defaults.name) {
|
||||
const paletteLabel = RED.utils.getPaletteLabel(n.type, n._def)
|
||||
const defaultNodeNameRE = new RegExp('^'+paletteLabel+' (\\d+)$')
|
||||
if (!typeIndex.hasOwnProperty(n.type)) {
|
||||
const existingNodes = RED.nodes.filterNodes({type: n.type})
|
||||
let maxNameNumber = 0;
|
||||
existingNodes.forEach(n => {
|
||||
let match = defaultNodeNameRE.exec(n.name)
|
||||
if (match) {
|
||||
let nodeNumber = parseInt(match[1])
|
||||
if (nodeNumber > maxNameNumber) {
|
||||
maxNameNumber = nodeNumber
|
||||
}
|
||||
}
|
||||
})
|
||||
typeIndex[n.type] = maxNameNumber + 1
|
||||
}
|
||||
if (n.name === '') {
|
||||
if (generateHistory) {
|
||||
historyEvents.push({
|
||||
t:'edit',
|
||||
node: n,
|
||||
changes: { name: n.name },
|
||||
dirty: RED.nodes.dirty(),
|
||||
changed: n.changed
|
||||
})
|
||||
}
|
||||
n.name = paletteLabel+" "+typeIndex[n.type]
|
||||
n.dirty = true
|
||||
typeIndex[n.type]++
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
})
|
||||
if (changed) {
|
||||
if (historyEvents.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'multi',
|
||||
events: historyEvents
|
||||
})
|
||||
}
|
||||
RED.nodes.dirty(true)
|
||||
RED.view.redraw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
||||
@@ -870,6 +1095,10 @@ RED.view.tools = (function() {
|
||||
RED.actions.add("core:wire-series-of-nodes", function() { wireSeriesOfNodes() })
|
||||
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
|
||||
|
||||
RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
|
||||
|
||||
RED.actions.add("core:generate-node-names", generateNodeNames )
|
||||
|
||||
// RED.actions.add("core:add-node", function() { addNode() })
|
||||
},
|
||||
/**
|
||||
@@ -881,7 +1110,8 @@ RED.view.tools = (function() {
|
||||
* @param {Number} dx
|
||||
* @param {Number} dy
|
||||
*/
|
||||
moveSelection: moveSelection
|
||||
moveSelection: moveSelection,
|
||||
calculateGridSnapOffsets: calculateGridSnapOffsets
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
* |- <g> "groupLayer"
|
||||
* |- <g> "groupSelectLayer"
|
||||
* |- <g> "linkLayer"
|
||||
* |- <g> "junctionLayer"
|
||||
* |- <g> "dragGroupLayer"
|
||||
* |- <g> "nodeLayer"
|
||||
*/
|
||||
@@ -56,6 +57,7 @@ RED.view = (function() {
|
||||
var activeSubflow = null;
|
||||
var activeNodes = [];
|
||||
var activeLinks = [];
|
||||
var activeJunctions = [];
|
||||
var activeFlowLinks = [];
|
||||
var activeLinkNodes = {};
|
||||
var activeGroup = null;
|
||||
@@ -90,6 +92,9 @@ RED.view = (function() {
|
||||
var lastClickPosition = [];
|
||||
var selectNodesOptions;
|
||||
|
||||
let flashingNodeId;
|
||||
let flashingNodeTimer;
|
||||
|
||||
var clipboard = "";
|
||||
|
||||
// Note: these are the permitted status colour aliases. The actual RGB values
|
||||
@@ -111,6 +116,7 @@ RED.view = (function() {
|
||||
var eventLayer;
|
||||
var gridLayer;
|
||||
var linkLayer;
|
||||
var junctionLayer;
|
||||
var dragGroupLayer;
|
||||
var groupSelectLayer;
|
||||
var nodeLayer;
|
||||
@@ -199,6 +205,11 @@ RED.view = (function() {
|
||||
|
||||
function init() {
|
||||
|
||||
// setTimeout(function() {
|
||||
// function snap(p) { return RED.view.gridSize() * Math.round(p/RED.view.gridSize())}; for (var i = 0;i<10;i++) {
|
||||
// RED.nodes.addJunction({_def:{defaults:{}}, type:'junction', z:"0ccdc1d81f2729cc",id:RED.nodes.id(),x:snap(Math.floor(Math.random()*600)),y:snap(Math.floor(Math.random()*600)), w:0,h:0})
|
||||
// } ; RED.view.redraw(true)
|
||||
// },2000)
|
||||
chart = $("#red-ui-workspace-chart");
|
||||
|
||||
outer = d3.select("#red-ui-workspace-chart")
|
||||
@@ -224,7 +235,6 @@ RED.view = (function() {
|
||||
.on("mousedown", canvasMouseDown)
|
||||
.on("mouseup", canvasMouseUp)
|
||||
.on("mouseenter", function() {
|
||||
d3.select(document).on('mouseup.red-ui-workspace-tracker', null)
|
||||
if (lasso) {
|
||||
if (d3.event.buttons !== 1) {
|
||||
lasso.remove();
|
||||
@@ -240,7 +250,6 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
})
|
||||
.on("mouseleave", canvasMouseLeave)
|
||||
.on("touchend", function() {
|
||||
d3.event.preventDefault();
|
||||
clearTimeout(touchStartTime);
|
||||
@@ -375,14 +384,12 @@ RED.view = (function() {
|
||||
groupSelectLayer = eventLayer.append("g");
|
||||
linkLayer = eventLayer.append("g");
|
||||
dragGroupLayer = eventLayer.append("g");
|
||||
junctionLayer = eventLayer.append("g");
|
||||
nodeLayer = eventLayer.append("g");
|
||||
|
||||
drag_lines = [];
|
||||
|
||||
RED.events.on("workspace:change",function(event) {
|
||||
// Just in case the mouse left the workspace whilst doing an action,
|
||||
// put us back into default mode so the refresh works
|
||||
mouse_mode = 0
|
||||
if (event.old !== 0) {
|
||||
workspaceScrollPositions[event.old] = {
|
||||
left:chart.scrollLeft(),
|
||||
@@ -448,13 +455,40 @@ RED.view = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
//add search to status-toolbar
|
||||
RED.statusBar.add({
|
||||
id: "view-search-tools",
|
||||
align: "left",
|
||||
hidden: false,
|
||||
element: $('<span class="button-group">'+
|
||||
'<button class="red-ui-footer-button" id="red-ui-view-searchtools-search"><i class="fa fa-search"></i></button>' +
|
||||
'</span>' +
|
||||
'<span class="button-group search-counter">' +
|
||||
'<span class="red-ui-footer-button" id="red-ui-view-searchtools-counter">? of ?</span>' +
|
||||
'</span>' +
|
||||
'<span class="button-group">' +
|
||||
'<button class="red-ui-footer-button" id="red-ui-view-searchtools-prev"><i class="fa fa-chevron-left"></i></button>' +
|
||||
'<button class="red-ui-footer-button" id="red-ui-view-searchtools-next"><i class="fa fa-chevron-right"></i></button>' +
|
||||
'</span>' +
|
||||
'<span class="button-group">' +
|
||||
'<button class="red-ui-footer-button" id="red-ui-view-searchtools-close"><i class="fa fa-close"></i></button>' +
|
||||
'</span>')
|
||||
})
|
||||
$("#red-ui-view-searchtools-search").on("click", searchFlows);
|
||||
RED.popover.tooltip($("#red-ui-view-searchtools-search"),RED._('actions.search-flows'),'core:search');
|
||||
$("#red-ui-view-searchtools-prev").on("click", searchPrev);
|
||||
RED.popover.tooltip($("#red-ui-view-searchtools-prev"),RED._('actions.search-prev'),'core:search-previous');
|
||||
$("#red-ui-view-searchtools-next").on("click", searchNext);
|
||||
RED.popover.tooltip($("#red-ui-view-searchtools-next"),RED._('actions.search-next'),'core:search-next');
|
||||
RED.popover.tooltip($("#red-ui-view-searchtools-close"),RED._('common.label.close'));
|
||||
|
||||
// Handle nodes dragged from the palette
|
||||
chart.droppable({
|
||||
accept:".red-ui-palette-node",
|
||||
drop: function( event, ui ) {
|
||||
d3.event = event;
|
||||
var selected_tool = $(ui.draggable[0]).attr("data-palette-type");
|
||||
var result = addNode(selected_tool);
|
||||
var result = createNode(selected_tool);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
@@ -498,17 +532,9 @@ RED.view = (function() {
|
||||
nn.y = mousePos[1];
|
||||
|
||||
if (snapGrid) {
|
||||
var gridOffset = [0,0];
|
||||
var offsetLeft = nn.x-(gridSize*Math.round((nn.x-nn.w/2)/gridSize)+nn.w/2);
|
||||
var offsetRight = nn.x-(gridSize*Math.round((nn.x+nn.w/2)/gridSize)-nn.w/2);
|
||||
if (Math.abs(offsetLeft) < Math.abs(offsetRight)) {
|
||||
gridOffset[0] = offsetLeft
|
||||
} else {
|
||||
gridOffset[0] = offsetRight
|
||||
}
|
||||
gridOffset[1] = nn.y-(gridSize*Math.round(nn.y/gridSize));
|
||||
nn.x -= gridOffset[0];
|
||||
nn.y -= gridOffset[1];
|
||||
var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn);
|
||||
nn.x -= gridOffset.x;
|
||||
nn.y -= gridOffset.y;
|
||||
}
|
||||
|
||||
var spliceLink = $(ui.helper).data("splice");
|
||||
@@ -798,7 +824,7 @@ RED.view = (function() {
|
||||
source:{z:activeWorkspace},
|
||||
target:{z:activeWorkspace}
|
||||
});
|
||||
|
||||
activeJunctions = RED.nodes.junctions(activeWorkspace) || [];
|
||||
activeGroups = RED.nodes.groups(activeWorkspace)||[];
|
||||
activeGroups.forEach(function(g, i) {
|
||||
g._index = i;
|
||||
@@ -813,6 +839,7 @@ RED.view = (function() {
|
||||
} else {
|
||||
activeNodes = [];
|
||||
activeLinks = [];
|
||||
activeJunctions = [];
|
||||
activeGroups = [];
|
||||
}
|
||||
|
||||
@@ -932,81 +959,6 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function addNode(type,x,y) {
|
||||
var m = /^subflow:(.+)$/.exec(type);
|
||||
|
||||
if (activeSubflow && m) {
|
||||
var subflowId = m[1];
|
||||
if (subflowId === activeSubflow.id) {
|
||||
RED.notify(RED._("notification.error",{message: RED._("notification.errors.cannotAddSubflowToItself")}),"error");
|
||||
return;
|
||||
}
|
||||
if (RED.nodes.subflowContains(m[1],activeSubflow.id)) {
|
||||
RED.notify(RED._("notification.error",{message: RED._("notification.errors.cannotAddCircularReference")}),"error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var nn = { id:RED.nodes.id(),z:RED.workspaces.active()};
|
||||
|
||||
nn.type = type;
|
||||
nn._def = RED.nodes.getType(nn.type);
|
||||
|
||||
if (!m) {
|
||||
nn.inputs = nn._def.inputs || 0;
|
||||
nn.outputs = nn._def.outputs;
|
||||
|
||||
for (var d in nn._def.defaults) {
|
||||
if (nn._def.defaults.hasOwnProperty(d)) {
|
||||
if (nn._def.defaults[d].value !== undefined) {
|
||||
nn[d] = JSON.parse(JSON.stringify(nn._def.defaults[d].value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nn._def.onadd) {
|
||||
try {
|
||||
nn._def.onadd.call(nn);
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+nn.type+".onadd:",err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var subflow = RED.nodes.subflow(m[1]);
|
||||
nn.name = "";
|
||||
nn.inputs = subflow.in.length;
|
||||
nn.outputs = subflow.out.length;
|
||||
}
|
||||
|
||||
nn.changed = true;
|
||||
nn.moved = true;
|
||||
|
||||
nn.w = node_width;
|
||||
nn.h = Math.max(node_height,(nn.outputs||0) * 15);
|
||||
nn.resize = true;
|
||||
|
||||
var historyEvent = {
|
||||
t:"add",
|
||||
nodes:[nn.id],
|
||||
dirty:RED.nodes.dirty()
|
||||
}
|
||||
if (activeSubflow) {
|
||||
var subflowRefresh = RED.subflow.refresh(true);
|
||||
if (subflowRefresh) {
|
||||
historyEvent.subflow = {
|
||||
id:activeSubflow.id,
|
||||
changed: activeSubflow.changed,
|
||||
instances: subflowRefresh.instances
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
node: nn,
|
||||
historyEvent: historyEvent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function canvasMouseDown() {
|
||||
if (RED.view.DEBUG) { console.warn("canvasMouseDown", mouse_mode); }
|
||||
var point;
|
||||
@@ -1058,9 +1010,9 @@ RED.view = (function() {
|
||||
.attr("class","nr-ui-view-lasso");
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
} else if (mouse_mode === 0 && d3.event.button === 2 && (d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
} else if (mouse_mode === 0 && d3.event.button === 2 && (d3.event.metaKey || d3.event.ctrlKey || d3.event.shiftKey)) {
|
||||
clearSelection();
|
||||
mouse_mode = RED.state.SLICING;
|
||||
mouse_mode = (d3.event.metaKey || d3.event.ctrlKey)?RED.state.SLICING : RED.state.SLICING_JUNCTION;
|
||||
point = d3.mouse(this);
|
||||
slicePath = eventLayer.append("path").attr("class","nr-ui-view-slice").attr("d",`M${point[0]} ${point[1]}`)
|
||||
slicePathLast = point;
|
||||
@@ -1195,16 +1147,38 @@ RED.view = (function() {
|
||||
keepAdding = false;
|
||||
resetMouseVars();
|
||||
}
|
||||
var result = addNode(type);
|
||||
if (!result) {
|
||||
return;
|
||||
|
||||
var nn;
|
||||
var historyEvent;
|
||||
if (type === 'junction') {
|
||||
nn = {
|
||||
_def: {defaults:{}},
|
||||
type: 'junction',
|
||||
z: RED.workspaces.active(),
|
||||
id: RED.nodes.id(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0, h: 0,
|
||||
outputs: 1,
|
||||
inputs: 1,
|
||||
dirty: true
|
||||
}
|
||||
historyEvent = {
|
||||
t:'add',
|
||||
junctions:[nn]
|
||||
}
|
||||
} else {
|
||||
var result = createNode(type);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
nn = result.node;
|
||||
historyEvent = result.historyEvent;
|
||||
}
|
||||
if (keepAdding) {
|
||||
mouse_mode = RED.state.QUICK_JOINING;
|
||||
}
|
||||
|
||||
var nn = result.node;
|
||||
var historyEvent = result.historyEvent;
|
||||
nn.x = point[0];
|
||||
nn.y = point[1];
|
||||
var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label");
|
||||
@@ -1313,8 +1287,11 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.add(nn);
|
||||
if (nn.type === 'junction') {
|
||||
RED.nodes.addJunction(nn);
|
||||
} else {
|
||||
RED.nodes.add(nn);
|
||||
}
|
||||
RED.editor.validateNode(nn);
|
||||
|
||||
if (targetGroup) {
|
||||
@@ -1461,7 +1438,7 @@ RED.view = (function() {
|
||||
.attr("height",h)
|
||||
;
|
||||
return;
|
||||
} else if (mouse_mode === RED.state.SLICING) {
|
||||
} else if (mouse_mode === RED.state.SLICING || mouse_mode === RED.state.SLICING_JUNCTION) {
|
||||
if (slicePath) {
|
||||
var delta = Math.max(1,Math.abs(slicePathLast[0]-mouse_position[0]))*Math.max(1,Math.abs(slicePathLast[1]-mouse_position[1]))
|
||||
if (delta > 20) {
|
||||
@@ -1648,16 +1625,9 @@ RED.view = (function() {
|
||||
gridOffset[0] = node.n.x-(gridSize*Math.floor(node.n.x/gridSize))-gridSize/2;
|
||||
gridOffset[1] = node.n.y-(gridSize*Math.floor(node.n.y/gridSize))-gridSize/2;
|
||||
} else {
|
||||
var offsetLeft = node.n.x-(gridSize*Math.round((node.n.x-node.n.w/2)/gridSize)+node.n.w/2);
|
||||
var offsetRight = node.n.x-(gridSize*Math.round((node.n.x+node.n.w/2)/gridSize)-node.n.w/2);
|
||||
// gridOffset[0] = node.n.x-(gridSize*Math.floor((node.n.x-node.n.w/2)/gridSize)+node.n.w/2);
|
||||
if (Math.abs(offsetLeft) < Math.abs(offsetRight)) {
|
||||
gridOffset[0] = offsetLeft
|
||||
} else {
|
||||
gridOffset[0] = offsetRight
|
||||
}
|
||||
gridOffset[1] = node.n.y-(gridSize*Math.round(node.n.y/gridSize));
|
||||
// console.log(offsetLeft, offsetRight);
|
||||
const snapOffsets = RED.view.tools.calculateGridSnapOffsets(node.n);
|
||||
gridOffset[0] = snapOffsets.x;
|
||||
gridOffset[1] = snapOffsets.y;
|
||||
}
|
||||
if (gridOffset[0] !== 0 || gridOffset[1] !== 0) {
|
||||
for (i = 0; i<movingSet.length(); i++) {
|
||||
@@ -1746,19 +1716,10 @@ RED.view = (function() {
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
function canvasMouseLeave() {
|
||||
if (mouse_mode !== 0 && d3.event.buttons !== 0) {
|
||||
d3.select(document).on('mouseup.red-ui-workspace-tracker', function() {
|
||||
d3.select(document).on('mouseup.red-ui-workspace-tracker', null)
|
||||
canvasMouseUp.call(this)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function canvasMouseUp() {
|
||||
lastClickPosition = [d3.event.offsetX/scaleFactor,d3.event.offsetY/scaleFactor];
|
||||
if (RED.view.DEBUG) {
|
||||
console.warn("canvasMouseUp", { mouse_mode, point: d3.mouse(this), event: d3.event });
|
||||
}
|
||||
if (RED.view.DEBUG) { console.warn("canvasMouseUp", mouse_mode); }
|
||||
var i;
|
||||
var historyEvent;
|
||||
if (mouse_mode === RED.state.PANNING) {
|
||||
@@ -1843,6 +1804,15 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
activeJunctions.forEach(function(n) {
|
||||
if (!n.selected) {
|
||||
if (n.x > x && n.x < x2 && n.y > y && n.y < y2) {
|
||||
n.selected = true;
|
||||
n.dirty = true;
|
||||
movingSet.add(n);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1886,11 +1856,92 @@ RED.view = (function() {
|
||||
} else if (mouse_mode == RED.state.DEFAULT && mousedown_link == null && !d3.event.ctrlKey && !d3.event.metaKey ) {
|
||||
clearSelection();
|
||||
updateSelection();
|
||||
} else if (slicePath) {
|
||||
} else if (mouse_mode == RED.state.SLICING) {
|
||||
deleteSelection();
|
||||
slicePath.remove();
|
||||
slicePath = null;
|
||||
RED.view.redraw(true);
|
||||
} else if (mouse_mode == RED.state.SLICING_JUNCTION) {
|
||||
var removedLinks = []
|
||||
var addedLinks = []
|
||||
var addedJunctions = []
|
||||
|
||||
var groupedLinks = {}
|
||||
selectedLinks.forEach(function(l) {
|
||||
var sourceId = l.source.id+":"+l.sourcePort
|
||||
groupedLinks[sourceId] = groupedLinks[sourceId] || []
|
||||
groupedLinks[sourceId].push(l)
|
||||
});
|
||||
var linkGroups = Object.keys(groupedLinks)
|
||||
linkGroups.forEach(function(gid) {
|
||||
var links = groupedLinks[gid]
|
||||
var junction = {
|
||||
_def: {defaults:{}},
|
||||
type: 'junction',
|
||||
z: RED.workspaces.active(),
|
||||
id: RED.nodes.id(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0, h: 0,
|
||||
outputs: 1,
|
||||
inputs: 1,
|
||||
dirty: true
|
||||
}
|
||||
links.forEach(function(l) {
|
||||
junction.x += l._sliceLocation.x
|
||||
junction.y += l._sliceLocation.y
|
||||
})
|
||||
junction.x = Math.round(junction.x/links.length)
|
||||
junction.y = Math.round(junction.y/links.length)
|
||||
if (snapGrid) {
|
||||
junction.x = (gridSize*Math.round(junction.x/gridSize));
|
||||
junction.y = (gridSize*Math.round(junction.y/gridSize));
|
||||
}
|
||||
|
||||
var nodeGroups = new Set()
|
||||
|
||||
RED.nodes.addJunction(junction)
|
||||
addedJunctions.push(junction)
|
||||
var newLink = {
|
||||
source: links[0].source,
|
||||
sourcePort: links[0].sourcePort,
|
||||
target: junction
|
||||
}
|
||||
addedLinks.push(newLink)
|
||||
RED.nodes.addLink(newLink)
|
||||
links.forEach(function(l) {
|
||||
removedLinks.push(l)
|
||||
RED.nodes.removeLink(l)
|
||||
var newLink = {
|
||||
source: junction,
|
||||
sourcePort: 0,
|
||||
target: l.target
|
||||
}
|
||||
addedLinks.push(newLink)
|
||||
RED.nodes.addLink(newLink)
|
||||
nodeGroups.add(l.source.g || "__NONE__")
|
||||
nodeGroups.add(l.target.g || "__NONE__")
|
||||
})
|
||||
if (nodeGroups.size === 1) {
|
||||
var group = nodeGroups.values().next().value
|
||||
if (group !== "__NONE__") {
|
||||
RED.group.addToGroup(RED.nodes.group(group), junction)
|
||||
}
|
||||
}
|
||||
})
|
||||
slicePath.remove();
|
||||
slicePath = null;
|
||||
|
||||
if (addedJunctions.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'add',
|
||||
links: addedLinks,
|
||||
junctions: addedJunctions,
|
||||
removedLinks: removedLinks
|
||||
})
|
||||
RED.nodes.dirty(true)
|
||||
}
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
if (movingSet.length() > 0) {
|
||||
@@ -2011,6 +2062,9 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
function zoomZero() { zoomView(1); }
|
||||
function searchFlows() { RED.actions.invoke("core:search", $(this).data("term")); }
|
||||
function searchPrev() { RED.actions.invoke("core:search-previous"); }
|
||||
function searchNext() { RED.actions.invoke("core:search-next"); }
|
||||
|
||||
|
||||
function zoomView(factor) {
|
||||
@@ -2047,7 +2101,7 @@ RED.view = (function() {
|
||||
clearSelection();
|
||||
RED.history.pop();
|
||||
mouse_mode = 0;
|
||||
} else if (mouse_mode === RED.state.SLICING) {
|
||||
} else if (mouse_mode === RED.state.SLICING || mouse_mode === RED.state.SLICING_JUNCTION) {
|
||||
if (slicePath) {
|
||||
slicePath.remove();
|
||||
slicePath = null;
|
||||
@@ -2116,6 +2170,14 @@ RED.view = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
activeJunctions.forEach(function(n) {
|
||||
if (!n.selected) {
|
||||
n.selected = true;
|
||||
n.dirty = true;
|
||||
movingSet.add(n);
|
||||
}
|
||||
})
|
||||
|
||||
if (mouse_mode !== RED.state.SELECTING_NODE && activeSubflow) {
|
||||
activeSubflow.in.forEach(function(n) {
|
||||
if (!n.selected) {
|
||||
@@ -2315,6 +2377,7 @@ RED.view = (function() {
|
||||
nodes: [],
|
||||
links: [],
|
||||
groups: [],
|
||||
junctions: [],
|
||||
workspaces: [],
|
||||
subflows: []
|
||||
}
|
||||
@@ -2335,6 +2398,7 @@ RED.view = (function() {
|
||||
historyEvent.nodes = historyEvent.nodes.concat(subEvent.nodes);
|
||||
historyEvent.links = historyEvent.links.concat(subEvent.links);
|
||||
historyEvent.groups = historyEvent.groups.concat(subEvent.groups);
|
||||
historyEvent.junctions = historyEvent.junctions.concat(subEvent.junctions);
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
@@ -2347,6 +2411,7 @@ RED.view = (function() {
|
||||
var removedNodes = [];
|
||||
var removedLinks = [];
|
||||
var removedGroups = [];
|
||||
var removedJunctions = [];
|
||||
var removedSubflowOutputs = [];
|
||||
var removedSubflowInputs = [];
|
||||
var removedSubflowStatus;
|
||||
@@ -2391,14 +2456,14 @@ RED.view = (function() {
|
||||
for (var i=0;i<movingSet.length();i++) {
|
||||
node = movingSet.get(i).n;
|
||||
node.selected = false;
|
||||
if (node.type !== "group" && node.type !== "subflow") {
|
||||
if (node.type !== "group" && node.type !== "subflow" && node.type !== 'junction') {
|
||||
if (node.x < 0) {
|
||||
node.x = 25
|
||||
}
|
||||
var removedEntities = RED.nodes.remove(node.id);
|
||||
removedNodes.push(node);
|
||||
removedNodes = removedNodes.concat(removedEntities.nodes);
|
||||
addToRemovedLinks(removedEntities.links);
|
||||
addToRemovedLinks(removedNodes.removedLinks);
|
||||
if (node.g) {
|
||||
var group = RED.nodes.group(node.g);
|
||||
if (selectedGroups.indexOf(group) === -1) {
|
||||
@@ -2409,6 +2474,10 @@ RED.view = (function() {
|
||||
RED.group.markDirty(group);
|
||||
}
|
||||
}
|
||||
} else if (node.type === 'junction') {
|
||||
var result = RED.nodes.removeJunction(node)
|
||||
removedJunctions.push(node);
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
} else {
|
||||
if (node.direction === "out") {
|
||||
removedSubflowOutputs.push(node);
|
||||
@@ -2453,7 +2522,7 @@ RED.view = (function() {
|
||||
subflowInstances = instances.instances;
|
||||
}
|
||||
movingSet.clear();
|
||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus || removedGroups.length > 0) {
|
||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus || removedGroups.length > 0 || removedJunctions.length > 0) {
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
@@ -2500,6 +2569,7 @@ RED.view = (function() {
|
||||
nodes:removedNodes,
|
||||
links:removedLinks,
|
||||
groups: removedGroups,
|
||||
junctions: removedJunctions,
|
||||
subflowOutputs:removedSubflowOutputs,
|
||||
subflowInputs:removedSubflowInputs,
|
||||
subflow: {
|
||||
@@ -2559,6 +2629,7 @@ RED.view = (function() {
|
||||
var nns = [];
|
||||
var nodeCount = 0;
|
||||
var groupCount = 0;
|
||||
var junctionCount = 0;
|
||||
var handled = {};
|
||||
for (var n=0;n<nodes.length;n++) {
|
||||
var node = nodes[n];
|
||||
@@ -2571,6 +2642,8 @@ RED.view = (function() {
|
||||
if (node.type != "subflow") {
|
||||
if (node.type === "group") {
|
||||
groupCount++;
|
||||
} else if (node.type === 'junction') {
|
||||
junctionCount++;
|
||||
} else {
|
||||
nodeCount++;
|
||||
}
|
||||
@@ -2753,6 +2826,7 @@ RED.view = (function() {
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
function portMouseUp(d,portType,portIndex,evt) {
|
||||
if (RED.view.DEBUG) { console.warn("portMouseUp", mouse_mode,d,portType,portIndex); }
|
||||
evt = evt || d3.event;
|
||||
@@ -3135,6 +3209,52 @@ RED.view = (function() {
|
||||
port.classed("red-ui-flow-port-hovered",false);
|
||||
}
|
||||
|
||||
function junctionMouseOver(junction, d) {
|
||||
junction.classed("red-ui-flow-junction-hovered",true);
|
||||
}
|
||||
function junctionMouseOut(junction, d) {
|
||||
junction.classed("red-ui-flow-junction-hovered",false);
|
||||
}
|
||||
|
||||
function junctionMouseDown(junction, d, evt) {
|
||||
if (RED.view.DEBUG) { console.warn("junctionMouseDown", d); }
|
||||
evt = evt || d3.event;
|
||||
d3.event = evt
|
||||
if (evt === 1) {
|
||||
return;
|
||||
}
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
evt.stopPropagation();
|
||||
return;
|
||||
}
|
||||
if (mouse_mode == RED.state.QUICK_JOINING) {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
// mousedown_node = d;
|
||||
// mousedown_port_type = portType;
|
||||
// mousedown_port_index = portIndex || 0;
|
||||
if (mouse_mode !== RED.state.QUICK_JOINING && (evt.ctrlKey || evt.metaKey)) {
|
||||
mouse_mode = RED.state.QUICK_JOINING;
|
||||
document.body.style.cursor = "crosshair";
|
||||
showDragLines([{node:d,port:0,portType: PORT_TYPE_OUTPUT}]);
|
||||
$(window).on('keyup',disableQuickJoinEventHandler);
|
||||
} else if (event.button != 2) {
|
||||
nodeMouseDown.call(junction[0][0],d)
|
||||
// clearSelection();
|
||||
// movingSet.add(d);
|
||||
// mousedown_node = d;
|
||||
// mouse_mode = RED.state.MOVING;
|
||||
// var mouse = d3.touches(junction[0][0])[0]||d3.mouse(junction[0][0]);
|
||||
// mouse[0] += d.x-d.w/2;
|
||||
// mouse[1] += d.y-d.h/2;
|
||||
// prepareDrag(mouse);
|
||||
}
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
function prepareDrag(mouse) {
|
||||
mouse_mode = RED.state.MOVING;
|
||||
// Called when movingSet should be prepared to be dragged
|
||||
@@ -3327,8 +3447,6 @@ RED.view = (function() {
|
||||
)
|
||||
lastClickNode = mousedown_node;
|
||||
|
||||
var i;
|
||||
|
||||
if (!d.selected && d.g /*&& !RED.nodes.group(d.g).selected*/) {
|
||||
var nodeGroup = RED.nodes.group(d.g);
|
||||
|
||||
@@ -3601,10 +3719,12 @@ RED.view = (function() {
|
||||
function portMouseOverProxy(e) { portMouseOver(d3.select(this), this.__data__,this.__portType__,this.__portIndex__, e); }
|
||||
function portMouseOutProxy(e) { portMouseOut(d3.select(this), this.__data__,this.__portType__,this.__portIndex__, e); }
|
||||
|
||||
function junctionMouseOverProxy(e) { junctionMouseOver(d3.select(this), this.__data__) }
|
||||
function junctionMouseOutProxy(e) { junctionMouseOut(d3.select(this), this.__data__) }
|
||||
function junctionMouseDownProxy(e) { junctionMouseDown(d3.select(this), this.__data__, e) }
|
||||
function junctionMouseUpProxy(e) { junctionMouseUp(d3.select(this), this.__data__) }
|
||||
|
||||
function linkMouseDown(d) {
|
||||
if (RED.view.DEBUG) {
|
||||
console.warn("linkMouseDown", { mouse_mode, point: d3.mouse(this), event: d3.event });
|
||||
}
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
@@ -4738,6 +4858,62 @@ RED.view = (function() {
|
||||
})
|
||||
}
|
||||
|
||||
var junction = junctionLayer.selectAll(".red-ui-flow-junction").data(
|
||||
activeJunctions,
|
||||
d => d.id
|
||||
)
|
||||
var junctionEnter = junction.enter().insert("svg:g").attr("class","red-ui-flow-junction")
|
||||
junctionEnter.each(function(d,i) {
|
||||
var junction = d3.select(this);
|
||||
var contents = document.createDocumentFragment();
|
||||
// d.added = true;
|
||||
var junctionBack = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
junctionBack.setAttribute("class","red-ui-flow-junction-background");
|
||||
junctionBack.setAttribute("x",-5);
|
||||
junctionBack.setAttribute("y",-5);
|
||||
junctionBack.setAttribute("width",10);
|
||||
junctionBack.setAttribute("height",10);
|
||||
junctionBack.setAttribute("rx",5);
|
||||
junctionBack.setAttribute("ry",5);
|
||||
junctionBack.__data__ = d;
|
||||
this.__junctionBack__ = junctionBack;
|
||||
contents.appendChild(junctionBack);
|
||||
|
||||
junctionBack.addEventListener("mouseover", junctionMouseOverProxy);
|
||||
junctionBack.addEventListener("mouseout", junctionMouseOutProxy);
|
||||
junctionBack.addEventListener("mouseup", portMouseUpProxy);
|
||||
junctionBack.addEventListener("mousedown", junctionMouseDownProxy);
|
||||
|
||||
// d3.select(junctionBack).on("mousedown", nodeMouseDown);
|
||||
|
||||
this.__portType__ = PORT_TYPE_INPUT
|
||||
this.__portIndex__ = 0
|
||||
// function portMouseUpProxy(e) { portMouseUp(this.__data__,this.__portType__,this.__portIndex__, e); }
|
||||
|
||||
junction[0][0].appendChild(contents);
|
||||
})
|
||||
junction.exit().remove();
|
||||
junction.each(function(d) {
|
||||
var junction = d3.select(this);
|
||||
this.setAttribute("transform", "translate(" + (d.x) + "," + (d.y) + ")");
|
||||
if (d.dirty) {
|
||||
junction.classed("selected", !!d.selected)
|
||||
dirtyNodes[d.id] = d;
|
||||
|
||||
if (d.g) {
|
||||
if (!dirtyGroups[d.g]) {
|
||||
var gg = d.g;
|
||||
while (gg && !dirtyGroups[gg]) {
|
||||
dirtyGroups[gg] = RED.nodes.group(gg);
|
||||
gg = dirtyGroups[gg].g;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
var link = linkLayer.selectAll(".red-ui-flow-link").data(
|
||||
activeLinks,
|
||||
function(d) {
|
||||
@@ -4764,6 +4940,27 @@ RED.view = (function() {
|
||||
selectedLinks.add(d)
|
||||
l.classed("red-ui-flow-link-splice",true)
|
||||
redraw()
|
||||
} else if (mouse_mode === RED.state.SLICING_JUNCTION) {
|
||||
if (!l.classed("red-ui-flow-link-splice")) {
|
||||
// Find intersection point
|
||||
var lineLength = pathLine.getTotalLength();
|
||||
var pos;
|
||||
var delta = Infinity;
|
||||
for (var i = 0; i < lineLength; i++) {
|
||||
var linePos = pathLine.getPointAtLength(i);
|
||||
var posDeltaX = Math.abs(linePos.x-d3.event.offsetX)
|
||||
var posDeltaY = Math.abs(linePos.y-d3.event.offsetY)
|
||||
var posDelta = posDeltaX*posDeltaX + posDeltaY*posDeltaY
|
||||
if (posDelta < delta) {
|
||||
pos = linePos
|
||||
delta = posDelta
|
||||
}
|
||||
}
|
||||
d._sliceLocation = pos
|
||||
selectedLinks.add(d)
|
||||
l.classed("red-ui-flow-link-splice",true)
|
||||
redraw()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -4790,9 +4987,9 @@ RED.view = (function() {
|
||||
var numOutputs = d.source.outputs || 1;
|
||||
var sourcePort = d.sourcePort || 0;
|
||||
var y = -((numOutputs-1)/2)*13 +13*sourcePort;
|
||||
d.x1 = d.source.x+d.source.w/2;
|
||||
d.x1 = d.source.x+(d.source.w/2||0);
|
||||
d.y1 = d.source.y+y;
|
||||
d.x2 = d.target.x-d.target.w/2;
|
||||
d.x2 = d.target.x-(d.target.w/2||0);
|
||||
d.y2 = d.target.y;
|
||||
|
||||
// return "M "+d.x1+" "+d.y1+
|
||||
@@ -5251,6 +5448,7 @@ RED.view = (function() {
|
||||
var new_nodes = result.nodes;
|
||||
var new_links = result.links;
|
||||
var new_groups = result.groups;
|
||||
var new_junctions = result.junctions;
|
||||
var new_workspaces = result.workspaces;
|
||||
var new_subflows = result.subflows;
|
||||
var removedNodes = result.removedNodes;
|
||||
@@ -5260,6 +5458,7 @@ RED.view = (function() {
|
||||
}
|
||||
var new_ms = new_nodes.filter(function(n) { return n.hasOwnProperty("x") && n.hasOwnProperty("y") && n.z == RED.workspaces.active() });
|
||||
new_ms = new_ms.concat(new_groups.filter(function(g) { return g.z === RED.workspaces.active()}))
|
||||
new_ms = new_ms.concat(new_junctions.filter(function(j) { return j.z === RED.workspaces.active()}))
|
||||
var new_node_ids = new_nodes.map(function(n){ n.changed = true; return n.id; });
|
||||
|
||||
clearSelection();
|
||||
@@ -5293,9 +5492,11 @@ RED.view = (function() {
|
||||
node.n.moved = true;
|
||||
node.n.x -= dx - mouse_position[0];
|
||||
node.n.y -= dy - mouse_position[1];
|
||||
node.n.w = node_width;
|
||||
node.n.h = node_height;
|
||||
node.n.resize = true;
|
||||
if (node.n.type !== 'junction') {
|
||||
node.n.w = node_width;
|
||||
node.n.h = node_height;
|
||||
node.n.resize = true;
|
||||
}
|
||||
node.dx = node.n.x - mouse_position[0];
|
||||
node.dy = node.n.y - mouse_position[1];
|
||||
if (node.n.type === "group") {
|
||||
@@ -5342,6 +5543,7 @@ RED.view = (function() {
|
||||
nodes:new_node_ids,
|
||||
links:new_links,
|
||||
groups:new_groups,
|
||||
junctions: new_junctions,
|
||||
workspaces:new_workspaces,
|
||||
subflows:new_subflows,
|
||||
dirty:RED.nodes.dirty()
|
||||
@@ -5389,6 +5591,7 @@ RED.view = (function() {
|
||||
}
|
||||
})
|
||||
var newGroupCount = new_groups.length;
|
||||
var newJunctionCount = new_junctions.length;
|
||||
if (new_workspaces.length > 0) {
|
||||
counts.push(RED._("clipboard.flow",{count:new_workspaces.length}));
|
||||
}
|
||||
@@ -5525,6 +5728,93 @@ RED.view = (function() {
|
||||
return selection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a node from a type string.
|
||||
* **NOTE:** Can throw on error - use `try` `catch` block when calling
|
||||
* @param {string} type The node type to create
|
||||
* @param {number} [x] (optional) The horizontal position on the workspace
|
||||
* @param {number} [y] (optional)The vertical on the workspace
|
||||
* @param {string} [z] (optional) The flow tab this node will belong to. Defaults to active workspace.
|
||||
* @returns An object containing the `node` and a `historyEvent`
|
||||
* @private
|
||||
*/
|
||||
function createNode(type, x, y, z) {
|
||||
var m = /^subflow:(.+)$/.exec(type);
|
||||
var activeSubflow = z ? RED.nodes.subflow(z) : null;
|
||||
if (activeSubflow && m) {
|
||||
var subflowId = m[1];
|
||||
if (subflowId === activeSubflow.id) {
|
||||
throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddSubflowToItself") }))
|
||||
}
|
||||
if (RED.nodes.subflowContains(m[1], activeSubflow.id)) {
|
||||
throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddCircularReference") }))
|
||||
}
|
||||
}
|
||||
|
||||
var nn = { id: RED.nodes.id(), z: z || RED.workspaces.active() };
|
||||
|
||||
nn.type = type;
|
||||
nn._def = RED.nodes.getType(nn.type);
|
||||
|
||||
if (!m) {
|
||||
nn.inputs = nn._def.inputs || 0;
|
||||
nn.outputs = nn._def.outputs;
|
||||
|
||||
for (var d in nn._def.defaults) {
|
||||
if (nn._def.defaults.hasOwnProperty(d)) {
|
||||
if (nn._def.defaults[d].value !== undefined) {
|
||||
nn[d] = JSON.parse(JSON.stringify(nn._def.defaults[d].value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nn._def.onadd) {
|
||||
try {
|
||||
nn._def.onadd.call(nn);
|
||||
} catch (err) {
|
||||
console.log("Definition error: " + nn.type + ".onadd:", err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var subflow = RED.nodes.subflow(m[1]);
|
||||
nn.name = "";
|
||||
nn.inputs = subflow.in.length;
|
||||
nn.outputs = subflow.out.length;
|
||||
}
|
||||
|
||||
nn.changed = true;
|
||||
nn.moved = true;
|
||||
|
||||
nn.w = RED.view.node_width;
|
||||
nn.h = Math.max(RED.view.node_height, (nn.outputs || 0) * 15);
|
||||
nn.resize = true;
|
||||
if (x != null && typeof x == "number" && x >= 0) {
|
||||
nn.x = x;
|
||||
}
|
||||
if (y != null && typeof y == "number" && y >= 0) {
|
||||
nn.y = y;
|
||||
}
|
||||
var historyEvent = {
|
||||
t: "add",
|
||||
nodes: [nn.id],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
if (activeSubflow) {
|
||||
var subflowRefresh = RED.subflow.refresh(true);
|
||||
if (subflowRefresh) {
|
||||
historyEvent.subflow = {
|
||||
id: activeSubflow.id,
|
||||
changed: activeSubflow.changed,
|
||||
instances: subflowRefresh.instances
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
node: nn,
|
||||
historyEvent: historyEvent
|
||||
}
|
||||
}
|
||||
|
||||
function calculateNodeDimensions(node) {
|
||||
var result = [node_width,node_height];
|
||||
try {
|
||||
@@ -5548,6 +5838,37 @@ RED.view = (function() {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function flashNode(n) {
|
||||
let node = n;
|
||||
if(typeof node === "string") { node = RED.nodes.node(n); }
|
||||
if(!node) { return; }
|
||||
|
||||
const flashingNode = flashingNodeTimer && flashingNodeId && RED.nodes.node(flashingNodeId);
|
||||
if(flashingNode) {
|
||||
//cancel current flashing node before flashing new node
|
||||
clearInterval(flashingNodeTimer);
|
||||
flashingNodeTimer = null;
|
||||
flashingNode.dirty = true;
|
||||
flashingNode.highlighted = false;
|
||||
}
|
||||
|
||||
flashingNodeTimer = setInterval(function(flashEndTime) {
|
||||
node.dirty = true;
|
||||
if (flashEndTime >= Date.now()) {
|
||||
node.highlighted = !node.highlighted;
|
||||
} else {
|
||||
clearInterval(flashingNodeTimer);
|
||||
flashingNodeTimer = null;
|
||||
node.highlighted = false;
|
||||
flashingNodeId = null;
|
||||
}
|
||||
RED.view.redraw();
|
||||
}, 100, Date.now() + 2200)
|
||||
flashingNodeId = node.id;
|
||||
node.highlighted = true;
|
||||
RED.view.redraw();
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
state:function(state) {
|
||||
@@ -5608,7 +5929,21 @@ RED.view = (function() {
|
||||
redraw(true);
|
||||
},
|
||||
selection: getSelection,
|
||||
|
||||
clearSelection: clearSelection,
|
||||
createNode: createNode,
|
||||
/** default node width */
|
||||
get node_width() {
|
||||
return node_width;
|
||||
},
|
||||
/** default node height */
|
||||
get node_height() {
|
||||
return node_height;
|
||||
},
|
||||
/** snap to grid option state */
|
||||
get snapGrid() {
|
||||
return snapGrid;
|
||||
},
|
||||
/** gets the current scale factor */
|
||||
scale: function() {
|
||||
return scaleFactor;
|
||||
},
|
||||
@@ -5630,7 +5965,7 @@ RED.view = (function() {
|
||||
getActiveGroup: function() { return activeGroup },
|
||||
reveal: function(id,triggerHighlight) {
|
||||
if (RED.nodes.workspace(id) || RED.nodes.subflow(id)) {
|
||||
RED.workspaces.show(id);
|
||||
RED.workspaces.show(id, null, null, true);
|
||||
} else {
|
||||
var node = RED.nodes.node(id) || RED.nodes.group(id);
|
||||
if (node) {
|
||||
@@ -5638,7 +5973,7 @@ RED.view = (function() {
|
||||
node.dirty = true;
|
||||
RED.workspaces.show(node.z);
|
||||
|
||||
var screenSize = [chart[0].clientWidth/scaleFactor,chart[0].clientHeight/scaleFactor];
|
||||
var screenSize = [chart.width()/scaleFactor,chart.height()/scaleFactor];
|
||||
var scrollPos = [chart.scrollLeft()/scaleFactor,chart.scrollTop()/scaleFactor];
|
||||
var cx = node.x;
|
||||
var cy = node.y;
|
||||
@@ -5655,24 +5990,7 @@ RED.view = (function() {
|
||||
},200);
|
||||
}
|
||||
if (triggerHighlight !== false) {
|
||||
node.highlighted = true;
|
||||
if (!node._flashing) {
|
||||
node._flashing = true;
|
||||
var flash = 22;
|
||||
var flashFunc = function() {
|
||||
flash--;
|
||||
node.dirty = true;
|
||||
if (flash >= 0) {
|
||||
node.highlighted = !node.highlighted;
|
||||
setTimeout(flashFunc,100);
|
||||
} else {
|
||||
node.highlighted = false;
|
||||
delete node._flashing;
|
||||
}
|
||||
RED.view.redraw();
|
||||
}
|
||||
flashFunc();
|
||||
}
|
||||
flashNode(node);
|
||||
}
|
||||
} else if (node._def.category === 'config') {
|
||||
RED.sidebar.config.show(id);
|
||||
|
||||
@@ -24,6 +24,9 @@ RED.workspaces = (function() {
|
||||
var hideStack = [];
|
||||
var viewStackPos = 0;
|
||||
|
||||
let flashingTab;
|
||||
let flashingTabTimer;
|
||||
|
||||
function addToViewStack(id) {
|
||||
if (viewStackPos !== viewStack.length) {
|
||||
viewStack.splice(viewStackPos);
|
||||
@@ -281,22 +284,9 @@ RED.workspaces = (function() {
|
||||
onselect: "core:show-last-hidden-flow"
|
||||
}
|
||||
]
|
||||
let hiddenFlows = new Set()
|
||||
for (let i = 0; i < hideStack.length; i++) {
|
||||
let ids = hideStack[i]
|
||||
if (!Array.isArray(ids)) {
|
||||
ids = [ids]
|
||||
}
|
||||
ids.forEach(id => {
|
||||
if (RED.nodes.workspace(id)) {
|
||||
hiddenFlows.add(id)
|
||||
}
|
||||
})
|
||||
}
|
||||
const flowCount = hiddenFlows.size;
|
||||
if (flowCount > 0) {
|
||||
if (hideStack.length > 0) {
|
||||
menuItems.unshift({
|
||||
label: RED._("workspace.hiddenFlows",{count: flowCount}),
|
||||
label: RED._("workspace.hiddenFlows",{count: hideStack.length}),
|
||||
onselect: "core:list-hidden-flows"
|
||||
})
|
||||
}
|
||||
@@ -441,6 +431,9 @@ RED.workspaces = (function() {
|
||||
}
|
||||
}
|
||||
})
|
||||
RED.actions.add("core:list-modified-nodes",function() {
|
||||
RED.actions.invoke("core:search","is:modified ");
|
||||
})
|
||||
RED.actions.add("core:list-hidden-flows",function() {
|
||||
RED.actions.invoke("core:search","is:hidden ");
|
||||
})
|
||||
@@ -541,6 +534,31 @@ RED.workspaces = (function() {
|
||||
workspace_tabs.order(order);
|
||||
}
|
||||
|
||||
function flashTab(tabId) {
|
||||
if(flashingTab && flashingTab.length) {
|
||||
//cancel current flashing node before flashing new node
|
||||
clearInterval(flashingTabTimer);
|
||||
flashingTabTimer = null;
|
||||
flashingTab.removeClass('highlighted');
|
||||
flashingTab = null;
|
||||
}
|
||||
let tab = $("#red-ui-tab-" + tabId);
|
||||
if(!tab || !tab.length) { return; }
|
||||
|
||||
flashingTabTimer = setInterval(function(flashEndTime) {
|
||||
if (flashEndTime >= Date.now()) {
|
||||
const highlighted = tab.hasClass("highlighted");
|
||||
tab.toggleClass('highlighted', !highlighted)
|
||||
} else {
|
||||
clearInterval(flashingTabTimer);
|
||||
flashingTabTimer = null;
|
||||
flashingTab = null;
|
||||
tab.removeClass('highlighted');
|
||||
}
|
||||
}, 100, Date.now() + 2200);
|
||||
flashingTab = tab;
|
||||
tab.addClass('highlighted');
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
add: addWorkspace,
|
||||
@@ -573,7 +591,7 @@ RED.workspaces = (function() {
|
||||
isHidden: function(id) {
|
||||
return hideStack.includes(id)
|
||||
},
|
||||
show: function(id,skipStack,unhideOnly) {
|
||||
show: function(id,skipStack,unhideOnly,flash) {
|
||||
if (!workspace_tabs.contains(id)) {
|
||||
var sf = RED.nodes.subflow(id);
|
||||
if (sf) {
|
||||
@@ -595,6 +613,9 @@ RED.workspaces = (function() {
|
||||
}
|
||||
workspace_tabs.activateTab(id);
|
||||
}
|
||||
if(flash) {
|
||||
flashTab(id.replace(".","-"))
|
||||
}
|
||||
},
|
||||
refresh: function() {
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
|
||||
@@ -150,8 +150,7 @@ $popover-button-border-color-hover: #666;
|
||||
|
||||
$diff-text-header-color: $secondary-text-color;
|
||||
$diff-text-header-background: #ffd;
|
||||
$diff-state-color: $primary-text-color;
|
||||
$diff-state-prefix-color: $secondary-text-color;
|
||||
$diff-text-header-background-hover: #ffc;
|
||||
$diff-state-added: #009900;
|
||||
$diff-state-deleted: #f80000;
|
||||
$diff-state-changed: #f89406;
|
||||
@@ -194,6 +193,7 @@ $view-lasso-stroke: #ff7f0e;
|
||||
$view-lasso-fill: rgba(20,125,255,0.1);
|
||||
|
||||
$view-background: $secondary-background;
|
||||
$view-select-mode-background: $secondary-background-selected;
|
||||
$view-grid-color: #eee;
|
||||
|
||||
$node-label-color: #333;
|
||||
@@ -212,7 +212,6 @@ $node-icon-background-color-opacity: 0.05;
|
||||
$node-icon-border-color: #000;
|
||||
$node-icon-border-color-opacity: 0.1;
|
||||
|
||||
$node-config-background: #f3f3f3;
|
||||
|
||||
$node-link-port-background: #eee;
|
||||
|
||||
|
||||
@@ -562,7 +562,7 @@ ul.red-ui-deploy-dialog-confirm-list {
|
||||
width: 30px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
color: $diff-state-prefix-color;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
&.added {
|
||||
@@ -577,11 +577,9 @@ ul.red-ui-deploy-dialog-confirm-list {
|
||||
}
|
||||
td.added {
|
||||
background: $diff-state-added-background;
|
||||
color: $diff-state-color;
|
||||
}
|
||||
td.removed {
|
||||
background: $diff-state-deleted-background;
|
||||
color: $diff-state-color;
|
||||
}
|
||||
tr.mergeHeader td {
|
||||
color: $diff-merge-header-color;
|
||||
@@ -654,7 +652,7 @@ ul.red-ui-deploy-dialog-confirm-list {
|
||||
font-family: $monospace-font;
|
||||
padding: 5px 10px;
|
||||
text-align: left;
|
||||
color: $diff-text-header-color;
|
||||
color: $secondary-text-color;
|
||||
background: $diff-text-header-background;
|
||||
height: 30px;
|
||||
vertical-align: middle;
|
||||
|
||||
@@ -379,3 +379,17 @@ g.red-ui-flow-link-unknown path.red-ui-flow-link-line {
|
||||
white-space: pre;
|
||||
@include disable-selection;
|
||||
}
|
||||
.red-ui-flow-junction-background {
|
||||
stroke: $node-border;
|
||||
stroke-width: 1;
|
||||
fill: $node-port-background;
|
||||
cursor: crosshair;
|
||||
}
|
||||
.red-ui-flow-junction-hovered {
|
||||
stroke: $port-selected-color;
|
||||
fill: $port-selected-color;
|
||||
}
|
||||
.red-ui-flow-junction.selected .red-ui-flow-junction-background {
|
||||
stroke: $port-selected-color;
|
||||
// fill: $port-selected-color;
|
||||
}
|
||||
|
||||
@@ -26,13 +26,6 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ui-widget.ui-widget-content {
|
||||
border: 1px solid $tertiary-border-color;
|
||||
}
|
||||
.ui-widget-content {
|
||||
border: 1px solid $secondary-border-color;
|
||||
}
|
||||
|
||||
.ui-widget-header {
|
||||
color: $header-text-color;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ button.red-ui-palette-editor-upload-button {
|
||||
padding: 2px 8px;
|
||||
}
|
||||
form {
|
||||
width: 0;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
.red-ui-palette-editor-upload {
|
||||
|
||||
@@ -189,6 +189,7 @@
|
||||
.red-ui-search-result-node {
|
||||
&.red-ui-palette-icon-flow,
|
||||
&.red-ui-palette-icon-group,
|
||||
&.red-ui-palette-icon-junction,
|
||||
&.red-ui-palette-icon-selection {
|
||||
background: none;
|
||||
border-color: transparent;
|
||||
@@ -268,6 +269,7 @@
|
||||
|
||||
&.red-ui-palette-icon-flow,
|
||||
&.red-ui-palette-icon-group,
|
||||
&.red-ui-palette-icon-junction,
|
||||
&.red-ui-palette-icon-selection {
|
||||
background: none;
|
||||
border-color: transparent;
|
||||
@@ -303,6 +305,7 @@
|
||||
&.red-ui-palette-icon-flow {
|
||||
margin-top: -2px;
|
||||
}
|
||||
&.red-ui-palette-icon-junction .red-ui-palette-icon-fa,
|
||||
&.red-ui-palette-icon-group .red-ui-palette-icon-fa {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -66,8 +66,9 @@
|
||||
border-left-width: 3px;
|
||||
border-right-width: 3px;
|
||||
.red-ui-palette-icon-fa {
|
||||
font-size: 11px;
|
||||
position: relative;
|
||||
top: -2.5px;
|
||||
top: -3px;
|
||||
left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@ ul.red-ui-sidebar-node-config-list {
|
||||
border-color: transparent;
|
||||
box-shadow: 0 0 0 2px $node-selected-color;
|
||||
}
|
||||
&.highlighted {
|
||||
border-color: transparent;
|
||||
outline: dashed $node-selected-color 4px;
|
||||
}
|
||||
}
|
||||
.red-ui-palette-label {
|
||||
margin-left: 8px;
|
||||
@@ -54,7 +58,7 @@ ul.red-ui-sidebar-node-config-list {
|
||||
.red-ui-palette-icon-container {
|
||||
font-size: 12px;
|
||||
line-height: 30px;
|
||||
background-color: $node-icon-background-color;
|
||||
background-color: $secondary-background-selected;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
a {
|
||||
@@ -63,10 +67,10 @@ ul.red-ui-sidebar-node-config-list {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
color: $node-port-label-color;
|
||||
color: $secondary-text-color;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
background: $node-port-background-hover;
|
||||
background: $secondary-background-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +78,7 @@ ul.red-ui-sidebar-node-config-list {
|
||||
.red-ui-palette-node-config {
|
||||
width: 160px;
|
||||
height: 30px;
|
||||
background: $node-config-background;
|
||||
background: $primary-background;
|
||||
color: $primary-text-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
&:not(.active) a:hover+a.red-ui-tab-close {
|
||||
background: $tab-background-hover;
|
||||
}
|
||||
&.highlighted {
|
||||
box-shadow: 0px 0px 4px 2px $node-selected-color;
|
||||
border: dashed 1px $node-selected-color;
|
||||
}
|
||||
&.active {
|
||||
background: $tab-background-active;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
.red-ui-typedInput-container {
|
||||
border: 1px solid $form-input-border-color;
|
||||
border-radius: 5px;
|
||||
border-radius: 4px;
|
||||
height: 34px;
|
||||
line-height: 14px;
|
||||
display: inline-flex;
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
.red-ui-workspace-select-mode {
|
||||
.red-ui-workspace-chart-background {
|
||||
opacity: 0.7;
|
||||
// fill: $view-select-mode-background;
|
||||
}
|
||||
.red-ui-workspace-chart-grid line {
|
||||
opacity: 0.8;
|
||||
@@ -134,6 +135,13 @@
|
||||
margin-top: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.search-counter {
|
||||
display: inline-block;
|
||||
font-size: smaller;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
a.red-ui-footer-button,
|
||||
|
||||
6
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/css/all.min.css
vendored
Normal file
6
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/css/all.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2022 Fonticons, Inc.
|
||||
*/
|
||||
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f250,u+f252,u+f27a}
|
||||
6
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/css/v4-shims.min.css
vendored
Normal file
6
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/css/v4-shims.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-brands-400.ttf
vendored
Normal file
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-brands-400.ttf
vendored
Normal file
Binary file not shown.
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-brands-400.woff2
vendored
Normal file
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-brands-400.woff2
vendored
Normal file
Binary file not shown.
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-regular-400.ttf
vendored
Normal file
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-regular-400.ttf
vendored
Normal file
Binary file not shown.
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-regular-400.woff2
vendored
Normal file
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-regular-400.woff2
vendored
Normal file
Binary file not shown.
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-solid-900.ttf
vendored
Normal file
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-solid-900.ttf
vendored
Normal file
Binary file not shown.
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-solid-900.woff2
vendored
Normal file
BIN
packages/node_modules/@node-red/editor-client/src/vendor/font-awesome/webfonts/fa-solid-900.woff2
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -25,7 +25,8 @@
|
||||
<link rel="icon" type="image/png" href="{{ page.favicon }}">
|
||||
<link rel="mask-icon" href="{{ page.tabicon.icon }}" color="{{ page.tabicon.colour }}">
|
||||
<link rel="stylesheet" href="vendor/jquery/css/base/jquery-ui.min.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/all.min.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/v4-shims.min.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="red/style.min.css?v={{ page.version }}">
|
||||
{{#page.css}}
|
||||
<link rel="stylesheet" href="{{.}}">
|
||||
|
||||
5
packages/node_modules/@node-red/nodes/core/common/05-junction.html
vendored
Normal file
5
packages/node_modules/@node-red/nodes/core/common/05-junction.html
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
<!--
|
||||
05-junction.html
|
||||
This file exists so that the runtime loads the Junction node into the registry,
|
||||
but it is empty so it doesn't appear in the editor palette
|
||||
-->
|
||||
12
packages/node_modules/@node-red/nodes/core/common/05-junction.js
vendored
Normal file
12
packages/node_modules/@node-red/nodes/core/common/05-junction.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
function JunctionNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.on("input",function(msg, send, done) {
|
||||
send(msg);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("junction",JunctionNode);
|
||||
}
|
||||
@@ -109,10 +109,9 @@ module.exports = function(RED) {
|
||||
if (!property) return;
|
||||
|
||||
if (valueType === "jsonata") {
|
||||
if (p.v) {
|
||||
if (p.exp) {
|
||||
try {
|
||||
var exp = RED.util.prepareJSONataExpression(p.v, node);
|
||||
var val = RED.util.evaluateJSONataExpression(exp, msg);
|
||||
var val = RED.util.evaluateJSONataExpression(p.exp, msg);
|
||||
RED.util.setMessageProperty(msg, property, val, true);
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
@@ -507,6 +507,9 @@
|
||||
$("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
|
||||
}
|
||||
$("#node-input-statusVal").val($("#node-input-typed-status").typedInput('value'));
|
||||
},
|
||||
onadd: function() {
|
||||
RED.actions.invoke("core:generate-node-names",this)
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -108,9 +108,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
})
|
||||
this.on("input", function(msg, send, done) {
|
||||
if (hasOwnProperty.call(msg, "status") && msg.status &&
|
||||
hasOwnProperty.call(msg.status, "source") && msg.status.source &&
|
||||
hasOwnProperty.call(msg.status.source, "id") && (msg.status.source.id === node.id)) {
|
||||
if (hasOwnProperty.call(msg, "status") && hasOwnProperty.call(msg.status, "source") && hasOwnProperty.call(msg.status.source, "id") && (msg.status.source.id === node.id)) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
@@ -131,8 +129,7 @@ module.exports = function(RED) {
|
||||
fill = "red";
|
||||
st = msg.error.message;
|
||||
}
|
||||
if (hasOwnProperty.call(msg, "status") &&
|
||||
msg.status) {
|
||||
if (hasOwnProperty.call(msg, "status")) {
|
||||
fill = msg.status.fill || "grey";
|
||||
shape = msg.status.shape || "ring";
|
||||
st = msg.status.text || "";
|
||||
|
||||
@@ -209,6 +209,8 @@
|
||||
}
|
||||
|
||||
function onAdd() {
|
||||
RED.actions.invoke("core:generate-node-names",this)
|
||||
|
||||
for (var i=0;i<this.links.length;i++) {
|
||||
var n = RED.nodes.node(this.links[i]);
|
||||
if (n && n.links.indexOf(this.id) === -1) {
|
||||
@@ -286,7 +288,10 @@
|
||||
oneditsave: function() {
|
||||
onEditSave(this);
|
||||
},
|
||||
oneditresize: resizeNodeList
|
||||
oneditresize: resizeNodeList,
|
||||
onadd: function() {
|
||||
RED.actions.invoke("core:generate-node-names",this)
|
||||
}
|
||||
});
|
||||
|
||||
RED.nodes.registerType('link out',{
|
||||
|
||||
@@ -399,7 +399,7 @@
|
||||
$("#func-tabs-content").children().hide();
|
||||
$("#" + tab.id).show();
|
||||
let editor = $("#" + tab.id).find('.monaco-editor').first();
|
||||
if(editor.length) {
|
||||
if(editor.length) {
|
||||
if(that.editor.nodered && that.editor.type == "monaco") {
|
||||
that.editor.nodered.refreshModuleLibs(getLibsList());
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ module.exports = function(RED) {
|
||||
catch(e) { return false;}
|
||||
}
|
||||
else if (b === "null") { return a === null; }
|
||||
else if (b === "number") { return typeof a === b && !isNaN(a) }
|
||||
else { return typeof a === b && !Array.isArray(a) && !Buffer.isBuffer(a) && a !== null; }
|
||||
},
|
||||
'head': function(a, b, c, d, parts) {
|
||||
|
||||
@@ -168,9 +168,9 @@ module.exports = function(RED) {
|
||||
return getFromValueType(RED.util.getMessageProperty(msg,rule.from),done);
|
||||
} else if (rule.fromt === 'flow' || rule.fromt === 'global') {
|
||||
var contextKey = RED.util.parseContextStore(rule.from);
|
||||
if (/\[msg\./.test(contextKey.key)) {
|
||||
if (/\[msg\./.test(context.key)) {
|
||||
// The key has a nest msg. reference to evaluate first
|
||||
contextKey.key = RED.util.normalisePropertyExpression(contextKey.key,msg,true);
|
||||
context.key = RED.util.normalisePropertyExpression(contextKey.key,msg,true);
|
||||
}
|
||||
node.context()[rule.fromt].get(contextKey.key, contextKey.store, (err,fromValue) => {
|
||||
if (err) {
|
||||
|
||||
@@ -275,22 +275,18 @@ module.exports = function(RED) {
|
||||
if (msg.hasOwnProperty("flush")) {
|
||||
var len = node.buffer.length;
|
||||
if (typeof(msg.flush) == 'number') { len = Math.min(Math.floor(msg.flush),len); }
|
||||
if (len === 0) {
|
||||
while (len > 0) {
|
||||
const msgInfo = node.buffer.shift();
|
||||
if (Object.keys(msgInfo.msg).length > 1) {
|
||||
node.send(msgInfo.msg);
|
||||
msgInfo.done();
|
||||
}
|
||||
len = len - 1;
|
||||
}
|
||||
if (node.buffer.length === 0) {
|
||||
clearInterval(node.intervalID);
|
||||
node.intervalID = -1;
|
||||
}
|
||||
else {
|
||||
while (len > 0) {
|
||||
const msgInfo = node.buffer.shift();
|
||||
if (Object.keys(msgInfo.msg).length > 1) {
|
||||
node.send(msgInfo.msg);
|
||||
msgInfo.done();
|
||||
}
|
||||
len = len - 1;
|
||||
}
|
||||
clearInterval(node.intervalID);
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
}
|
||||
node.status({fill:"blue",shape:"dot",text:node.buffer.length});
|
||||
done();
|
||||
}
|
||||
|
||||
@@ -442,17 +442,7 @@
|
||||
}
|
||||
return defaultContentType || 'none'
|
||||
}
|
||||
/**
|
||||
* Test a topic string is valid for publishing
|
||||
* @param {string} topic
|
||||
* @returns `true` if it is a valid topic
|
||||
*/
|
||||
function validateMQTTPublishTopic(topic, opts) {
|
||||
if(!topic || topic == "" || !/[\+#\b\f\n\r\t\v\0]/.test(topic)) {
|
||||
return true;
|
||||
}
|
||||
return RED._("node-red:mqtt.errors.invalid-topic");
|
||||
}
|
||||
|
||||
RED.nodes.registerType('mqtt-broker',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
@@ -490,7 +480,6 @@
|
||||
willRetain: {value:false},
|
||||
willPayload: {value:""},
|
||||
willMsg: { value: {}},
|
||||
userProps: { value: ""},
|
||||
sessionExpiry: {value:0}
|
||||
},
|
||||
credentials: {
|
||||
@@ -620,7 +609,6 @@
|
||||
default: !this.userProps ? 'none':'json',
|
||||
types: [typedInputNoneOpt, 'json']
|
||||
});
|
||||
$("#node-config-input-userProps").typedInput('value',this.userProps);
|
||||
if (typeof this.keepalive === 'undefined') {
|
||||
this.keepalive = 15;
|
||||
$("#node-config-input-keepalive").val(this.keepalive);
|
||||
@@ -730,14 +718,6 @@
|
||||
}
|
||||
|
||||
if (v5) {
|
||||
this.userProps = "";
|
||||
const userPropsType = $("#node-config-input-userProps").typedInput("type");
|
||||
if(userPropsType == "json") {
|
||||
const userProps = $("#node-config-input-userProps").val();
|
||||
if (userProps && typeof userProps === "string") {
|
||||
this.userProps = userProps.trim();
|
||||
}
|
||||
}
|
||||
this.birthMsg = saveV5Message("birth");
|
||||
this.closeMsg = saveV5Message("close");
|
||||
this.willMsg = saveV5Message("will");
|
||||
|
||||
@@ -68,21 +68,12 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a topic string is valid for subscription
|
||||
* Test a topic string is valid
|
||||
* @param {string} topic
|
||||
* @returns `true` if it is a valid topic
|
||||
*/
|
||||
function isValidSubscriptionTopic(topic) {
|
||||
return /^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/.test(topic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a topic string is valid for publishing
|
||||
* @param {string} topic
|
||||
* @returns `true` if it is a valid topic
|
||||
*/
|
||||
function isValidPublishTopic(topic) {
|
||||
return !/[\+#\b\f\n\r\t\v\0]/.test(topic);
|
||||
return /^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/.test(topic)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +103,7 @@ module.exports = function(RED) {
|
||||
if(src[propName] === "true" || src[propName] === true) {
|
||||
dst[propName] = true;
|
||||
} else if(src[propName] === "false" || src[propName] === false) {
|
||||
dst[propName] = false;
|
||||
dst[propName] = true;
|
||||
}
|
||||
} else {
|
||||
if(def != undefined) dst[propName] = def;
|
||||
@@ -297,7 +288,7 @@ module.exports = function(RED) {
|
||||
//TODO: delete msg.responseTopic - to prevent it being resent?
|
||||
}
|
||||
}
|
||||
topicOK = topicOK && isValidPublishTopic(msg.topic);
|
||||
topicOK = topicOK && !/[\+#\b\f\n\r\t\v\0]/.test(msg.topic);
|
||||
|
||||
if (topicOK) {
|
||||
node.brokerConn.publish(msg, done); // send the message
|
||||
@@ -400,7 +391,6 @@ module.exports = function(RED) {
|
||||
node.options = {};
|
||||
node.queue = [];
|
||||
node.subscriptions = {};
|
||||
node.clientListeners = []
|
||||
/** @type {mqtt.MqttClient}*/ this.client;
|
||||
node.setOptions = function(opts, init) {
|
||||
if(!opts || typeof opts !== "object") {
|
||||
@@ -425,12 +415,8 @@ module.exports = function(RED) {
|
||||
setIfHasProperty(opts, node, "topicAliasMaximum", init);
|
||||
setIfHasProperty(opts, node, "maximumPacketSize", init);
|
||||
setIfHasProperty(opts, node, "receiveMaximum", init);
|
||||
//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116
|
||||
if (hasProperty(opts, "userProperties")) {
|
||||
node.userProperties = opts.userProperties;
|
||||
} else if (hasProperty(opts, "userProps")) {
|
||||
node.userProperties = opts.userProps;
|
||||
}
|
||||
setIfHasProperty(opts, node, "userProperties", init);//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116
|
||||
setIfHasProperty(opts, node, "userPropertiesType", init);
|
||||
|
||||
function createLWT(topic, payload, qos, retain, v5opts, v5SubPropName) {
|
||||
let message = undefined;
|
||||
@@ -479,7 +465,7 @@ module.exports = function(RED) {
|
||||
};
|
||||
if(hasProperty(opts, "willTopic")) {
|
||||
//will v5 properties must be set in the "properties" sub object
|
||||
node.options.will = createLWT(opts.willTopic, opts.willPayload, opts.willQos, opts.willRetain, opts.willMsg, "properties");
|
||||
node.options.will = createLWT(opts.willTopic, opts.willPayload, opts.willQos, opts.willRetain, opts.willMsg, "properies");
|
||||
};
|
||||
} else {
|
||||
//update options
|
||||
@@ -539,7 +525,7 @@ module.exports = function(RED) {
|
||||
// Only for ws or wss, check if proxy env var for additional configuration
|
||||
if (node.brokerurl.indexOf("wss://") > -1 || node.brokerurl.indexOf("ws://") > -1) {
|
||||
// check if proxy is set in env
|
||||
let prox, noprox, noproxy;
|
||||
let prox, noprox;
|
||||
if (process.env.http_proxy) { prox = process.env.http_proxy; }
|
||||
if (process.env.HTTP_PROXY) { prox = process.env.HTTP_PROXY; }
|
||||
if (process.env.no_proxy) { noprox = process.env.no_proxy.split(","); }
|
||||
@@ -666,16 +652,11 @@ module.exports = function(RED) {
|
||||
setStatusConnecting(node, true);
|
||||
try {
|
||||
node.serverProperties = {};
|
||||
if(node.client) {
|
||||
//belt and braces to avoid left over clients
|
||||
node.client.end(true);
|
||||
node._clientRemoveListeners();
|
||||
}
|
||||
node.client = mqtt.connect(node.brokerurl, node.options);
|
||||
node.client.setMaxListeners(0);
|
||||
let callbackDone = false; //prevent re-connects causing node._clientOn('connect' firing callback multiple times
|
||||
let callbackDone = false; //prevent re-connects causing node.client.on('connect' firing callback multiple times
|
||||
// Register successful connect or reconnect handler
|
||||
node._clientOn('connect', function (connack) {
|
||||
node.client.on('connect', function (connack) {
|
||||
node.closing = false;
|
||||
node.connecting = false;
|
||||
node.connected = true;
|
||||
@@ -707,7 +688,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
setStatusConnected(node, true);
|
||||
// Remove any existing listeners before resubscribing to avoid duplicates in the event of a re-connection
|
||||
node._clientRemoveListeners('message');
|
||||
node.client.removeAllListeners('message');
|
||||
|
||||
// Re-subscribe to stored topics
|
||||
for (var s in node.subscriptions) {
|
||||
@@ -719,7 +700,7 @@ module.exports = function(RED) {
|
||||
if (node.subscriptions[s].hasOwnProperty(r)) {
|
||||
qos = Math.max(qos,node.subscriptions[s][r].qos);
|
||||
_options = node.subscriptions[s][r].options;
|
||||
node._clientOn('message',node.subscriptions[s][r].handler);
|
||||
node.client.on('message',node.subscriptions[s][r].handler);
|
||||
}
|
||||
}
|
||||
_options.qos = _options.qos || qos;
|
||||
@@ -732,11 +713,11 @@ module.exports = function(RED) {
|
||||
node.publish(node.birthMessage);
|
||||
}
|
||||
});
|
||||
node._clientOn("reconnect", function() {
|
||||
node.client.on("reconnect", function() {
|
||||
setStatusConnecting(node, true);
|
||||
});
|
||||
//Broker Disconnect - V5 event
|
||||
node._clientOn("disconnect", function(packet) {
|
||||
node.client.on("disconnect", function(packet) {
|
||||
//Emitted after receiving disconnect packet from broker. MQTT 5.0 feature.
|
||||
const rc = (packet && packet.properties && packet.reasonCode) || packet.reasonCode;
|
||||
const rs = packet && packet.properties && packet.properties.reasonString || "";
|
||||
@@ -750,7 +731,7 @@ module.exports = function(RED) {
|
||||
setStatusDisconnected(node, true);
|
||||
});
|
||||
// Register disconnect handlers
|
||||
node._clientOn('close', function () {
|
||||
node.client.on('close', function () {
|
||||
if (node.connected) {
|
||||
node.connected = false;
|
||||
node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
|
||||
@@ -762,59 +743,39 @@ module.exports = function(RED) {
|
||||
|
||||
// Register connect error handler
|
||||
// The client's own reconnect logic will take care of errors
|
||||
node._clientOn('error', function (error) {
|
||||
node.client.on('error', function (error) {
|
||||
});
|
||||
}catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
node.disconnect = function (callback) {
|
||||
const _callback = function () {
|
||||
if(node.connected || node.connecting) {
|
||||
setStatusDisconnected(node, true);
|
||||
const _callback = function (resetNodeConnectedState) {
|
||||
setStatusDisconnected(node, true);
|
||||
if(resetNodeConnectedState) {
|
||||
node.closing = true;
|
||||
node.connecting = false;
|
||||
node.connected = false;
|
||||
}
|
||||
if(node.client) { node._clientRemoveListeners(); }
|
||||
node.connecting = false;
|
||||
node.connected = false;
|
||||
callback && typeof callback == "function" && callback();
|
||||
};
|
||||
if(!node.client) { return _callback(); }
|
||||
if(node.closing) { return _callback(); }
|
||||
|
||||
let waitEnd = (client, ms) => {
|
||||
return new Promise( (resolve, reject) => {
|
||||
node.closing = true;
|
||||
if(!client) {
|
||||
resolve();
|
||||
} else {
|
||||
const t = setTimeout(() => {
|
||||
//clean end() has exceeded WAIT_END, lets force end!
|
||||
client && client.end(true);
|
||||
reject();
|
||||
}, ms);
|
||||
client.end(() => {
|
||||
clearTimeout(t);
|
||||
resolve()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
if(node.closing) {
|
||||
return _callback(false);
|
||||
}
|
||||
var endCallBack = function endCallBack() {
|
||||
}
|
||||
if(node.connected && node.closeMessage) {
|
||||
node.publish(node.closeMessage, function (err) {
|
||||
waitEnd(node.client, 2000).then(() => {
|
||||
_callback();
|
||||
}).catch((e) => {
|
||||
_callback();
|
||||
})
|
||||
node.client.end(endCallBack);
|
||||
_callback(true);
|
||||
});
|
||||
} else if(node.connected) {
|
||||
node.client.end(endCallBack);
|
||||
_callback(true);
|
||||
} else {
|
||||
waitEnd(node.client, 2000).then(() => {
|
||||
_callback();
|
||||
}).catch((e) => {
|
||||
_callback();
|
||||
})
|
||||
_callback(false);
|
||||
}
|
||||
}
|
||||
node.subscriptionIds = {};
|
||||
@@ -851,7 +812,7 @@ module.exports = function(RED) {
|
||||
};
|
||||
node.subscriptions[topic][ref] = sub;
|
||||
if (node.connected) {
|
||||
node._clientOn('message',sub.handler);
|
||||
node.client.on('message',sub.handler);
|
||||
node.client.subscribe(topic, options);
|
||||
}
|
||||
};
|
||||
@@ -862,7 +823,7 @@ module.exports = function(RED) {
|
||||
if (sub) {
|
||||
if (sub[ref]) {
|
||||
if(node.client) {
|
||||
node._clientRemoveListeners('message',sub[ref].handler);
|
||||
node.client.removeListener('message',sub[ref].handler);
|
||||
}
|
||||
delete sub[ref];
|
||||
}
|
||||
@@ -896,18 +857,8 @@ module.exports = function(RED) {
|
||||
qos: msg.qos || 0,
|
||||
retain: msg.retain || false
|
||||
};
|
||||
let topicOK = hasProperty(msg, "topic") && (typeof msg.topic === "string") && (isValidPublishTopic(msg.topic));
|
||||
//https://github.com/mqttjs/MQTT.js/blob/master/README.md#mqttclientpublishtopic-message-options-callback
|
||||
if(node.options.protocolVersion == 5) {
|
||||
const bsp = node.serverProperties || {};
|
||||
if (msg.userProperties && typeof msg.userProperties !== "object") {
|
||||
delete msg.userProperties;
|
||||
}
|
||||
if (hasProperty(msg, "topicAlias") && !isNaN(Number(msg.topicAlias))) {
|
||||
msg.topicAlias = parseInt(msg.topicAlias);
|
||||
} else {
|
||||
delete msg.topicAlias;
|
||||
}
|
||||
options.properties = options.properties || {};
|
||||
setStrProp(msg, options.properties, "responseTopic");
|
||||
setBufferProp(msg, options.properties, "correlationData");
|
||||
@@ -917,75 +868,31 @@ module.exports = function(RED) {
|
||||
setIntProp(msg, options.properties, "topicAlias", 1, node.serverProperties.topicAliasMaximum || 0);
|
||||
setBoolProp(msg, options.properties, "payloadFormatIndicator");
|
||||
//FUTURE setIntProp(msg, options.properties, "subscriptionIdentifier", 1, 268435455);
|
||||
|
||||
//check & sanitise topic
|
||||
if (topicOK && options.properties.topicAlias) {
|
||||
let aliasValid = (bsp.topicAliasMaximum && bsp.topicAliasMaximum >= options.properties.topicAlias);
|
||||
if (!aliasValid) {
|
||||
if (options.properties.topicAlias) {
|
||||
if (!node.topicAliases.hasOwnProperty(options.properties.topicAlias) && msg.topic == "") {
|
||||
done("Invalid topicAlias");
|
||||
return
|
||||
}
|
||||
if (node.topicAliases[options.properties.topicAlias] === msg.topic) {
|
||||
msg.topic = "";
|
||||
msg.topic = ""
|
||||
} else {
|
||||
node.topicAliases[options.properties.topicAlias] = msg.topic;
|
||||
node.topicAliases[options.properties.topicAlias] = msg.topic
|
||||
}
|
||||
} else if (!msg.topic && options.properties.responseTopic) {
|
||||
msg.topic = msg.responseTopic;
|
||||
topicOK = isValidPublishTopic(msg.topic);
|
||||
delete msg.responseTopic; //prevent responseTopic being resent?
|
||||
}
|
||||
}
|
||||
|
||||
if (topicOK) {
|
||||
node.client.publish(msg.topic, msg.payload, options, function(err) {
|
||||
done && done(err);
|
||||
return
|
||||
});
|
||||
} else {
|
||||
const error = new Error(RED._("mqtt.errors.invalid-topic"));
|
||||
error.warn = true;
|
||||
done(error);
|
||||
}
|
||||
node.client.publish(msg.topic, msg.payload, options, function(err) {
|
||||
done && done(err);
|
||||
return
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
node.on('close', function(done) {
|
||||
node.disconnect(function() {
|
||||
done();
|
||||
});
|
||||
node.closing = true;
|
||||
node.disconnect(done);
|
||||
});
|
||||
|
||||
/**
|
||||
* Add event handlers to the MQTT.js client and track them so that
|
||||
* we do not remove any handlers that the MQTT client uses internally.
|
||||
* Use {@link node._clientRemoveListeners `node._clientRemoveListeners`} to remove handlers
|
||||
* @param {string} event The name of the event
|
||||
* @param {function} handler The handler for this event
|
||||
*/
|
||||
node._clientOn = function(event, handler) {
|
||||
node.clientListeners.push({event, handler})
|
||||
node.client.on(event, handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove event handlers from the MQTT.js client & only the events
|
||||
* that we attached in {@link node._clientOn `node._clientOn`}.
|
||||
* * If `event` is omitted, then all events matching `handler` are removed
|
||||
* * If `handler` is omitted, then all events named `event` are removed
|
||||
* * If both parameters are omitted, then all events are removed
|
||||
* @param {string} [event] The name of the event (optional)
|
||||
* @param {function} [handler] The handler for this event (optional)
|
||||
*/
|
||||
node._clientRemoveListeners = function(event, handler) {
|
||||
node.clientListeners = node.clientListeners.filter((l) => {
|
||||
if (event && event !== l.event) { return true; }
|
||||
if (handler && handler !== l.handler) { return true; }
|
||||
node.client.removeListener(l.event, l.handler)
|
||||
return false; //found and removed, filter out this one
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RED.nodes.registerType("mqtt-broker",MQTTBrokerNode,{
|
||||
@@ -1160,7 +1067,6 @@ module.exports = function(RED) {
|
||||
node.brokerConn.unsubscribe(node.topic,node.id, removed);
|
||||
}
|
||||
node.brokerConn.deregister(node, done);
|
||||
node.brokerConn = null;
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
@@ -1225,7 +1131,6 @@ module.exports = function(RED) {
|
||||
node.on('close', function(done) {
|
||||
if (node.brokerConn) {
|
||||
node.brokerConn.deregister(node,done);
|
||||
node.brokerConn = null;
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
|
||||
@@ -91,11 +91,6 @@
|
||||
<label for="node-input-senderr" style="width: auto" data-i18n="httpin.senderr"></label>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-input-insecureHTTPParser" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-insecureHTTPParser", style="width: auto;" data-i18n="httpin.insecureHTTPParser"></label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
|
||||
@@ -125,7 +120,6 @@
|
||||
tls: {type:"tls-config",required: false},
|
||||
persist: {value:false},
|
||||
proxy: {type:"http proxy",required: false},
|
||||
insecureHTTPParser: {value: false},
|
||||
authType: {value: ""},
|
||||
senderr: {value: false}
|
||||
},
|
||||
@@ -230,12 +224,6 @@
|
||||
} else {
|
||||
$("#node-input-useProxy").prop("checked", false);
|
||||
}
|
||||
|
||||
if (node.insecureHTTPParser) {
|
||||
$("node-intput-insecureHTTPParser").prop("checked", true)
|
||||
} else {
|
||||
$("node-intput-insecureHTTPParser").prop("checked", false)
|
||||
}
|
||||
updateProxyOptions();
|
||||
$("#node-input-useProxy").on("click", function() {
|
||||
updateProxyOptions();
|
||||
|
||||
@@ -214,10 +214,6 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
||||
delete options.headers[h];
|
||||
}
|
||||
})
|
||||
|
||||
if (node.insecureHTTPParser) {
|
||||
options.insecureHTTPParser = true
|
||||
}
|
||||
}
|
||||
],
|
||||
beforeRedirect: [
|
||||
|
||||
@@ -35,6 +35,8 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
var listenerNodes = {};
|
||||
var activeListenerNodes = 0;
|
||||
|
||||
|
||||
// A node red node that sets up a local websocket server
|
||||
function WebSocketListenerNode(n) {
|
||||
@@ -164,6 +166,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
if (node.isServer) {
|
||||
activeListenerNodes++;
|
||||
if (!serverUpgradeAdded) {
|
||||
RED.server.on('upgrade', handleServerUpgrade);
|
||||
serverUpgradeAdded = true
|
||||
@@ -207,7 +210,7 @@ module.exports = function(RED) {
|
||||
startconn(); // start outbound connection
|
||||
}
|
||||
|
||||
node.on("close", function(done) {
|
||||
node.on("close", function() {
|
||||
if (node.heartbeatInterval) {
|
||||
clearInterval(node.heartbeatInterval);
|
||||
}
|
||||
@@ -215,25 +218,19 @@ module.exports = function(RED) {
|
||||
delete listenerNodes[node.fullPath];
|
||||
node.server.close();
|
||||
node._inputNodes = [];
|
||||
activeListenerNodes--;
|
||||
// if (activeListenerNodes === 0 && serverUpgradeAdded) {
|
||||
// RED.server.removeListener('upgrade', handleServerUpgrade);
|
||||
// serverUpgradeAdded = false;
|
||||
// }
|
||||
}
|
||||
else {
|
||||
node.closing = true;
|
||||
node.server.close();
|
||||
//wait 20*50 (1000ms max) for ws to close.
|
||||
//call done when readyState === ws.CLOSED (or 1000ms, whichever comes fist)
|
||||
const closeMonitorInterval = 20;
|
||||
let closeMonitorCount = 50;
|
||||
let si = setInterval(() => {
|
||||
if(node.server.readyState === ws.CLOSED || closeMonitorCount <= 0) {
|
||||
if (node.tout) {
|
||||
clearTimeout(node.tout);
|
||||
node.tout = null;
|
||||
}
|
||||
clearInterval(si);
|
||||
return done();
|
||||
}
|
||||
closeMonitorCount--;
|
||||
}, closeMonitorInterval);
|
||||
if (node.tout) {
|
||||
clearTimeout(node.tout);
|
||||
node.tout = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ module.exports = function(RED) {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0; i<parts.length-1; i+=1) {
|
||||
msg = {topic:node.topic, payload:parts[i]};
|
||||
msg = {topic:node.topic, payload:parts[i] + node.newline.trimEnd()};
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
@@ -229,7 +229,7 @@ module.exports = function(RED) {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0; i<parts.length-1; i+=1) {
|
||||
msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
|
||||
msg = {topic:node.topic, payload:parts[i] + node.newline.trimEnd(), ip:socket.remoteAddress, port:socket.remotePort};
|
||||
msg._session = {type:"tcp",id:id};
|
||||
node.send(msg);
|
||||
}
|
||||
@@ -432,7 +432,7 @@ module.exports = function(RED) {
|
||||
});
|
||||
}
|
||||
else {
|
||||
const connectedSockets = new Set();
|
||||
var connectedSockets = [];
|
||||
node.status({text:RED._("tcpin.status.connections",{count:0})});
|
||||
let srv = net;
|
||||
let connOpts;
|
||||
@@ -453,16 +453,16 @@ module.exports = function(RED) {
|
||||
});
|
||||
socket.on('close',function() {
|
||||
node.log(RED._("tcpin.status.connection-closed",{host:socket.remoteAddress, port:socket.remotePort}));
|
||||
connectedSockets.delete(socket);
|
||||
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
||||
connectedSockets.splice(connectedSockets.indexOf(socket),1);
|
||||
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
|
||||
});
|
||||
socket.on('error',function() {
|
||||
node.log(RED._("tcpin.errors.socket-error",{host:socket.remoteAddress, port:socket.remotePort}));
|
||||
connectedSockets.delete(socket);
|
||||
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
||||
connectedSockets.splice(connectedSockets.indexOf(socket),1);
|
||||
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
|
||||
});
|
||||
connectedSockets.add(socket);
|
||||
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
||||
connectedSockets.push(socket);
|
||||
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.length})});
|
||||
});
|
||||
|
||||
node.on("input", function(msg, nodeSend, nodeDone) {
|
||||
@@ -475,10 +475,10 @@ module.exports = function(RED) {
|
||||
} else {
|
||||
buffer = Buffer.from(""+msg.payload);
|
||||
}
|
||||
connectedSockets.forEach(soc => {
|
||||
if (node.doend === true) { soc.end(buffer); }
|
||||
else { soc.write(buffer); }
|
||||
})
|
||||
for (var i = 0; i < connectedSockets.length; i += 1) {
|
||||
if (node.doend === true) { connectedSockets[i].end(buffer); }
|
||||
else { connectedSockets[i].write(buffer); }
|
||||
}
|
||||
}
|
||||
nodeDone();
|
||||
});
|
||||
@@ -495,10 +495,12 @@ module.exports = function(RED) {
|
||||
} else {
|
||||
node.log(RED._("tcpin.status.listening-port",{port:node.port}));
|
||||
node.on('close', function() {
|
||||
connectedSockets.forEach(soc => {
|
||||
soc.end();
|
||||
soc.unref();
|
||||
})
|
||||
for (var c in connectedSockets) {
|
||||
if (connectedSockets.hasOwnProperty(c)) {
|
||||
connectedSockets[c].end();
|
||||
connectedSockets[c].unref();
|
||||
}
|
||||
}
|
||||
server.close();
|
||||
node.log(RED._("tcpin.status.stopped-listening",{port:node.port}));
|
||||
});
|
||||
|
||||
@@ -89,9 +89,6 @@ module.exports = function(RED) {
|
||||
else if (msg.payload[s][t].toString().indexOf(node.sep) !== -1) { // add quotes if any "commas"
|
||||
msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
|
||||
}
|
||||
else if (msg.payload[s][t].toString().indexOf("\n") !== -1) { // add quotes if any "\n"
|
||||
msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
|
||||
}
|
||||
}
|
||||
ou += msg.payload[s].join(node.sep) + node.ret;
|
||||
}
|
||||
@@ -115,7 +112,7 @@ module.exports = function(RED) {
|
||||
q = q.replace(/"/g, '""');
|
||||
ou += node.quo + q + node.quo + node.sep;
|
||||
}
|
||||
else if (q.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
|
||||
else if (q.indexOf(node.sep) !== -1) { // add quotes if any "commas"
|
||||
ou += node.quo + q + node.quo + node.sep;
|
||||
}
|
||||
else { ou += q + node.sep; } // otherwise just add
|
||||
@@ -137,7 +134,7 @@ module.exports = function(RED) {
|
||||
p = p.replace(/"/g, '""');
|
||||
ou += node.quo + p + node.quo + node.sep;
|
||||
}
|
||||
else if (p.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
|
||||
else if (p.indexOf(node.sep) !== -1) { // add quotes if any "commas"
|
||||
ou += node.quo + p + node.quo + node.sep;
|
||||
}
|
||||
else { ou += p + node.sep; } // otherwise just add
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<label style="width:100%;"><span data-i18n="json.label.o2j"></span></label>
|
||||
</div>
|
||||
<div class="form-row node-json-to-json-options" style="padding-left: 20px;">
|
||||
<input style="width:20px; vertical-align:top; margin-right: 5px;" type="checkbox" id="node-input-pretty"><label style="width: auto;" for="node-input-pretty" data-i18n="json.label.pretty"></label>
|
||||
<input style="width:20px; vertical-align:top; margin-right: 5px;" type="checkbox" id="node-input-pretty"><label style="width: auto;" for="node-input-pretty" data-i18n="json.label.pretty"></span>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
@@ -314,13 +314,11 @@ module.exports = function(RED) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
msgInfo.msg.payload = result;
|
||||
msgInfo.send(msgInfo.msg);
|
||||
msgInfo.send({payload: result});
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
msgInfo.msg.payload = result;
|
||||
msgInfo.send(msgInfo.msg);
|
||||
msgInfo.send({payload: result});
|
||||
done();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-input-allowEmptySequence" style="margin-left:20px; margin-right: 10px; vertical-align:top; width:auto;">
|
||||
<label for="node-input-allowEmptySequence" style="width:auto;" data-i18n="batch.interval.empty"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="node-row-msg-concat">
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": "48d660b3a4109400",
|
||||
"type": "inject",
|
||||
"z": "9e5f48c16729e4f0",
|
||||
"name": "inject",
|
||||
"props": [
|
||||
{
|
||||
"p": "payload"
|
||||
}
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"onceDelay": 0.1,
|
||||
"topic": "",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 185,
|
||||
"y": 795,
|
||||
"wires": [
|
||||
[
|
||||
"e0f9e206681f3504"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e0f9e206681f3504",
|
||||
"type": "delay",
|
||||
"z": "9e5f48c16729e4f0",
|
||||
"name": "",
|
||||
"pauseType": "rate",
|
||||
"timeout": "5",
|
||||
"timeoutUnits": "seconds",
|
||||
"rate": "1",
|
||||
"nbRateUnits": "30",
|
||||
"rateUnits": "second",
|
||||
"randomFirst": "1",
|
||||
"randomLast": "5",
|
||||
"randomUnits": "seconds",
|
||||
"drop": false,
|
||||
"allowrate": false,
|
||||
"outputs": 1,
|
||||
"x": 430,
|
||||
"y": 795,
|
||||
"wires": [
|
||||
[
|
||||
"e470f1d794e1bef9",
|
||||
"af7cea1dfb797a75"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "943543cf7a1958e4",
|
||||
"type": "change",
|
||||
"z": "9e5f48c16729e4f0",
|
||||
"name": "set flush to 1",
|
||||
"rules": [
|
||||
{
|
||||
"t": "set",
|
||||
"p": "flush",
|
||||
"pt": "msg",
|
||||
"to": "1",
|
||||
"tot": "num"
|
||||
},
|
||||
{
|
||||
"t": "delete",
|
||||
"p": "payload",
|
||||
"pt": "msg"
|
||||
}
|
||||
],
|
||||
"action": "",
|
||||
"property": "",
|
||||
"from": "",
|
||||
"to": "",
|
||||
"reg": false,
|
||||
"x": 510,
|
||||
"y": 915,
|
||||
"wires": [
|
||||
[
|
||||
"e0f9e206681f3504"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e470f1d794e1bef9",
|
||||
"type": "function",
|
||||
"z": "9e5f48c16729e4f0",
|
||||
"name": "Do something that takes a few seconds",
|
||||
"func": "\n//send on the message between 3 and 6 seconds later\nsetTimeout(\n function() { \n node.send(msg) \n }, \n Math.random() * 3000 + 3000\n);\nreturn null;",
|
||||
"outputs": 1,
|
||||
"noerr": 0,
|
||||
"initialize": "",
|
||||
"finalize": "",
|
||||
"libs": [],
|
||||
"x": 760,
|
||||
"y": 795,
|
||||
"wires": [
|
||||
[
|
||||
"943543cf7a1958e4",
|
||||
"859258551b8389b7"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "af7cea1dfb797a75",
|
||||
"type": "debug",
|
||||
"z": "9e5f48c16729e4f0",
|
||||
"name": "IN",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"targetType": "msg",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 710,
|
||||
"y": 735,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "859258551b8389b7",
|
||||
"type": "debug",
|
||||
"z": "9e5f48c16729e4f0",
|
||||
"name": "OUT",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"targetType": "msg",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 895,
|
||||
"y": 735,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "ecaaf26326da10ee",
|
||||
"type": "comment",
|
||||
"z": "9e5f48c16729e4f0",
|
||||
"name": "Simple Queue with release",
|
||||
"info": "This example shows how to use a delay node set to rate limit mode as a simple queue to feed a\nprocess that may take some time to complete. Once that process completes the feedback is then\nset to flush out the next message - thus running the \"loop\" as fast as possible with no overlaps.\n\n**Note**: only the `msg.flush` property msut be set - otherwise the other properties that are fed \nback will be added as another new message to the queue.",
|
||||
"x": 235,
|
||||
"y": 915,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -525,8 +525,7 @@
|
||||
},
|
||||
"status": {
|
||||
"requesting": "requesting"
|
||||
},
|
||||
"insecureHTTPParser": "Disable strict HTTP parsing"
|
||||
}
|
||||
},
|
||||
"websocket": {
|
||||
"label": {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<p>返却/sendの対象は次のとおりです:</p>
|
||||
<ul>
|
||||
<li>単一メッセージオブジェクト - 最初の出力に接続されたノードに渡されます</li>
|
||||
<li>メッセージオブジェクトの配列 - 対応する出力に接続されたノードに渡されます</li>
|
||||
<li>メッセージオブジェクトの配列 - 対応する出力に接続されたノードに渡されます</li>
|
||||
</ul>
|
||||
<p>注: 初期化処理の実行はノードの初期化中に行われます。そのため、初期化処理タブにsendを記述した場合に後続ノードでメッセージを受け取れないことがあります。</p>
|
||||
<p>配列要素が配列の場合には、複数のメッセージを対応する出力に送出します。</p>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
<dt class="optional">userProperties <span class="property-type">オブジェクト</span></dt>
|
||||
<dd><b>MQTTv5</b>: メッセージのユーザプロパティ</dd>
|
||||
<dt class="optional">messageExpiryInterval <span class="property-type">数値</span></dt>
|
||||
<dd><b>MQTTv5</b>: 秒単位のメッセージの有効期限</dd>
|
||||
<dd><b>MQTTv5</b>: 秒単位のメッセージの有効期限</dd>
|
||||
<dt class="optional">topicAlias <span class="property-type">数値</span></dt>
|
||||
<dd><b>MQTTv5</b>: 使用するMQTTトピックエイリアス</dd>
|
||||
</dl>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -11,7 +11,6 @@ const exec = require("@node-red/util").exec;
|
||||
const log = require("@node-red/util").log;
|
||||
const hooks = require("@node-red/util").hooks;
|
||||
const url = require("url");
|
||||
const { createRequire } = require("module");
|
||||
|
||||
const BUILTIN_MODULES = require('module').builtinModules;
|
||||
|
||||
@@ -140,15 +139,10 @@ function importModule(module) {
|
||||
}
|
||||
const externalModuleDir = getInstallDir();
|
||||
const moduleDir = path.join(externalModuleDir,"node_modules",module);
|
||||
// To handle both CJS and ESM we need to resolve the module to the
|
||||
// specific file that is loaded when the module is required/imported
|
||||
// As this won't be on the natural module search path, we use createRequire
|
||||
// to access the module
|
||||
const modulePath = createRequire(moduleDir).resolve(module)
|
||||
// Import needs the full path to the module's main .js file
|
||||
// It also needs to be a file:// url for Windows
|
||||
const moduleUrl = url.pathToFileURL(modulePath);
|
||||
return import(moduleUrl);
|
||||
const moduleFile = url.pathToFileURL(require.resolve(moduleDir));
|
||||
return import(moduleFile);
|
||||
}
|
||||
|
||||
function parseModuleName(module) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.2.3",
|
||||
"@node-red/util": "2.2.2",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "10.0.0",
|
||||
"semver": "7.3.5",
|
||||
|
||||
@@ -582,7 +582,7 @@ class Flow {
|
||||
reportingNode = node;
|
||||
}
|
||||
if (!muteStatusEvent) {
|
||||
if (statusMessage.hasOwnProperty("text") && typeof statusMessage.text !== "string") {
|
||||
if (statusMessage.hasOwnProperty("text") && typeof(statusMessage.text !== "string")) {
|
||||
try {
|
||||
statusMessage.text = statusMessage.text.toString();
|
||||
}
|
||||
|
||||
@@ -390,6 +390,7 @@ class Subflow extends Flow {
|
||||
}
|
||||
name = newName;
|
||||
}
|
||||
|
||||
|
||||
var parent = this.parent;
|
||||
if (parent) {
|
||||
|
||||
@@ -239,15 +239,7 @@ var api = module.exports = {
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
if (encryptionEnabled) {
|
||||
// Our config expects the credentials to be encrypted but the encrypted object is not found
|
||||
log.warn(log._("nodes.credentials.encryptedNotFound"))
|
||||
credentialCache = credentials;
|
||||
} else {
|
||||
// credentialSecret is set to False
|
||||
log.warn(log._("nodes.credentials.unencrypted"))
|
||||
credentialCache = credentials;
|
||||
}
|
||||
credentialCache = credentials;
|
||||
}
|
||||
if (clearInvalidFlag) {
|
||||
// TODO: this delves too deep into Project structure
|
||||
@@ -373,13 +365,11 @@ var api = module.exports = {
|
||||
|
||||
}
|
||||
}
|
||||
if (/^subflow(:|$)/.test(nodeType)) {
|
||||
for (cred in savedCredentials) {
|
||||
if (savedCredentials.hasOwnProperty(cred)) {
|
||||
if (!newCreds.hasOwnProperty(cred)) {
|
||||
delete savedCredentials[cred];
|
||||
dirty = true;
|
||||
}
|
||||
for (cred in savedCredentials) {
|
||||
if (savedCredentials.hasOwnProperty(cred)) {
|
||||
if (!newCreds.hasOwnProperty(cred)) {
|
||||
delete savedCredentials[cred];
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,7 @@
|
||||
"error":"Error loading credentials: __message__",
|
||||
"error-saving":"Error saving credentials: __message__",
|
||||
"not-registered": "Credential type '__type__' is not registered",
|
||||
"system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n",
|
||||
"unencrypted" : "Using unencrypted credentials",
|
||||
"encryptedNotFound" : "Encrypted credentials not found"
|
||||
"system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n"
|
||||
},
|
||||
"flows": {
|
||||
"safe-mode": "Flows stopped in safe mode. Deploy to start.",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user