mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
149 Commits
2.1.2
...
link-effec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1a706f811 | ||
|
|
c27dd336d9 | ||
|
|
5e9ff98c49 | ||
|
|
50cb074172 | ||
|
|
510a09ecba | ||
|
|
f86e743cce | ||
|
|
cb96fb735e | ||
|
|
459a52d31d | ||
|
|
44ef9a13d6 | ||
|
|
0bb3652a63 | ||
|
|
6a82d683a9 | ||
|
|
fad708e8de | ||
|
|
c6a38b8355 | ||
|
|
ee84eb666b | ||
|
|
6d2793cac6 | ||
|
|
86d518fc2e | ||
|
|
25dba1a6d5 | ||
|
|
af949c62c2 | ||
|
|
ea20342d76 | ||
|
|
7732d52583 | ||
|
|
c801bc5e6b | ||
|
|
ea43729063 | ||
|
|
e26bae8027 | ||
|
|
555f155cad | ||
|
|
f8c47f59bc | ||
|
|
f3997128b9 | ||
|
|
154a4e23dd | ||
|
|
52e4e0e569 | ||
|
|
30f2b96c68 | ||
|
|
58c94b7773 | ||
|
|
83203d5f5d | ||
|
|
f77d161643 | ||
|
|
6580b139c0 | ||
|
|
2743c7c6ac | ||
|
|
062f76214e | ||
|
|
ce98ed98a2 | ||
|
|
dce9d93f6c | ||
|
|
f7e35a6cbe | ||
|
|
931335220f | ||
|
|
3ce35a8a4b | ||
|
|
9ac4e5cf6a | ||
|
|
bd77d7eec3 | ||
|
|
b5e48aa509 | ||
|
|
b14c42b6a4 | ||
|
|
44616c6872 | ||
|
|
aaa2b4c3db | ||
|
|
8974d8e4df | ||
|
|
699063cbb0 | ||
|
|
e76000b713 | ||
|
|
332b372e31 | ||
|
|
cb3fcb7bfa | ||
|
|
bef641609e | ||
|
|
24b52f09df | ||
|
|
942b17b807 | ||
|
|
cf19d7f3ad | ||
|
|
ebd62a4112 | ||
|
|
9af7357ca4 | ||
|
|
0dbc35c252 | ||
|
|
c9f03f1ac5 | ||
|
|
02bd292b8c | ||
|
|
e5f1029d0c | ||
|
|
cae247160f | ||
|
|
6692b1992c | ||
|
|
0937837b7f | ||
|
|
828888490a | ||
|
|
91cb6ba73b | ||
|
|
4ee4d32b2e | ||
|
|
8df630a2f5 | ||
|
|
2cad42870e | ||
|
|
43651135f3 | ||
|
|
ecaf866613 | ||
|
|
5ea3329b36 | ||
|
|
7bb7149f4c | ||
|
|
5856d043ca | ||
|
|
7cd3e49f04 | ||
|
|
173e75175e | ||
|
|
800006dd76 | ||
|
|
a824b6910a | ||
|
|
dcea382b38 | ||
|
|
d9f976baea | ||
|
|
1fa13efe19 | ||
|
|
33af5cd7c6 | ||
|
|
7cb8f97ef1 | ||
|
|
bf965a9cde | ||
|
|
17ffff685a | ||
|
|
ae76271cff | ||
|
|
8f3a96d615 | ||
|
|
30e750dfe5 | ||
|
|
682dff7c6f | ||
|
|
85415eb8a8 | ||
|
|
68a80b9244 | ||
|
|
c331da7323 | ||
|
|
04ffa06221 | ||
|
|
1f0690c6ec | ||
|
|
711467abcd | ||
|
|
9439cd0e3d | ||
|
|
314c19650d | ||
|
|
ed6afcd802 | ||
|
|
082d4fe8e1 | ||
|
|
cd23b44506 | ||
|
|
46b6b024b9 | ||
|
|
cb88cc35e5 | ||
|
|
75c0c44809 | ||
|
|
a091b82ba9 | ||
|
|
a3b8f022e6 | ||
|
|
279fcb7c51 | ||
|
|
49a9376073 | ||
|
|
96840ede56 | ||
|
|
7e7f481f99 | ||
|
|
3edbf52bc6 | ||
|
|
fba6e801fc | ||
|
|
720a163273 | ||
|
|
a9b12e5172 | ||
|
|
6ac0c0a367 | ||
|
|
300402d253 | ||
|
|
0d9bfae503 | ||
|
|
bfe0d3b8a3 | ||
|
|
5fdd9c0546 | ||
|
|
b6570a16b8 | ||
|
|
8e2d3ea16f | ||
|
|
bc2c81f058 | ||
|
|
3e0f080ea7 | ||
|
|
679e07189d | ||
|
|
a38ebef100 | ||
|
|
b8ad6475e1 | ||
|
|
0f0cb3ac6d | ||
|
|
d3efb9d7cc | ||
|
|
84a237d3f5 | ||
|
|
e6de52eede | ||
|
|
98aee964d7 | ||
|
|
570e5442e0 | ||
|
|
b77a2dc353 | ||
|
|
87af31de20 | ||
|
|
cfe201dbe1 | ||
|
|
6ccdab35e0 | ||
|
|
55b9f36b45 | ||
|
|
fbcb1130c9 | ||
|
|
d4f7a6d2bc | ||
|
|
8a19f71abe | ||
|
|
fb153757b5 | ||
|
|
4f175fc93e | ||
|
|
2d4ca7cec0 | ||
|
|
bf0ea89969 | ||
|
|
073f0c2a20 | ||
|
|
ba83be9062 | ||
|
|
2e7188ea4f | ||
|
|
5a012182d9 | ||
|
|
b55a8ef62a | ||
|
|
36f099d68b |
54
CHANGELOG.md
54
CHANGELOG.md
@@ -1,3 +1,57 @@
|
||||
#### 2.2.0-beta.1: Beta Release
|
||||
|
||||
|
||||
|
||||
#### 2.1.4: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- fix env var access using $parent for groups (#3278) @HiroyasuNishiyama
|
||||
- Add proper error handling for 404 errors when serving debug files (#3277) @knolleary
|
||||
- Add Japanese translations for Node-RED v2.1.0-beta.1 (#3179) @kazuhitoyokoi
|
||||
- Include full user object on login audit events (#3269) @knolleary
|
||||
- Remove styling from de locale files (#3237) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Change tab hide button icon to an eye and add search option (#3282) @knolleary
|
||||
- Fix i18n handling of namespaces with spaces in (#3281) @knolleary
|
||||
- Trigger change event when autoComplete fills in input (#3280) @knolleary
|
||||
- Apply CN i18n fix (#3279) @knolleary
|
||||
- fix select menu label of config node to use paletteLabel (#3273) @HiroyasuNishiyama
|
||||
- fix removed tab not to cause node conflict (#3275) @HiroyasuNishiyama
|
||||
- Group diff fix (#3239) @knolleary
|
||||
- Only toggle disabled workspace flag if on activeWorkspace (#3252) @knolleary
|
||||
- Do not show status for disabled nodes (#3253) @knolleary
|
||||
- Set dimension value for tour guide (#3265) @kazuhitoyokoi
|
||||
- Avoid redundant initialisation of TypedInput type (#3263) @knolleary
|
||||
- Don't let themes change flow port label color (#3270) @bonanitech
|
||||
- Fix treeList gutter calculation to handle floating gutters (#3238) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- Debug: Handle RegExp types in Debug sidebar (#3251) @knolleary
|
||||
- Delay: fix 2nd output when in rate limit per topic modes (#3261) @dceejay
|
||||
- Link: fix to show link target when selected (#3267) @HiroyasuNishiyama
|
||||
- Inject: Do not modify inject node props in oneditprepare (#3242) @knolleary
|
||||
- HTTP Request: HTTP Basic Auth should always add : between username and password even if empty (#3236) @hardillb
|
||||
|
||||
#### 2.1.3: Maintenance Release
|
||||
|
||||
Runtime
|
||||
|
||||
- Update gen-publish script to update 'next' tag for main releases
|
||||
- Add environment variable to enable/disable tours (#3221) @hardillb
|
||||
- Fix loading non-default language files leaving runtime in wrong locale (#3225) @knolleary
|
||||
|
||||
Editor
|
||||
|
||||
- Refresh editor settings whenever a node is added or enabled (#3227) @knolleary
|
||||
- Revert spinner css change that made it shrink in some cases (#3229) @knolleary
|
||||
- Fix import notification message when importing config nodes (#3224) @knolleary
|
||||
- Handle changing types of TypedInput repeatedly (#3223) @knolleary
|
||||
|
||||
|
||||
#### 2.1.2: Maintenance Release
|
||||
|
||||
|
||||
|
||||
26
package.json
26
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -26,9 +26,9 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"acorn": "8.5.0",
|
||||
"acorn": "8.6.0",
|
||||
"acorn-walk": "8.2.0",
|
||||
"ajv": "8.6.3",
|
||||
"ajv": "8.8.2",
|
||||
"async-mutex": "0.3.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
@@ -37,7 +37,7 @@
|
||||
"clone": "2.1.2",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.1",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
"denque": "2.0.1",
|
||||
@@ -46,11 +46,11 @@
|
||||
"form-data": "4.0.0",
|
||||
"fs-extra": "10.0.0",
|
||||
"fs.notify": "0.0.4",
|
||||
"got": "11.8.2",
|
||||
"got": "11.8.3",
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "0.1.2",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"i18next": "21.3.1",
|
||||
"i18next": "21.5.4",
|
||||
"iconv-lite": "0.6.3",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.1",
|
||||
@@ -60,22 +60,22 @@
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.6",
|
||||
"mime": "2.5.2",
|
||||
"moment-timezone": "0.5.33",
|
||||
"moment-timezone": "0.5.34",
|
||||
"mqtt": "4.2.8",
|
||||
"multer": "1.4.3",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^2.2.1",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.5.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.4.1",
|
||||
"raw-body": "2.4.2",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.11",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uglify-js": "3.14.2",
|
||||
"uglify-js": "3.14.4",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.1",
|
||||
"xml2js": "0.4.23"
|
||||
@@ -109,11 +109,11 @@
|
||||
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
|
||||
"marked": "3.0.7",
|
||||
"minami": "1.2.3",
|
||||
"mocha": "9.1.2",
|
||||
"mocha": "9.1.3",
|
||||
"node-red-node-test-helper": "^0.2.7",
|
||||
"nodemon": "2.0.13",
|
||||
"nodemon": "2.0.15",
|
||||
"proxy": "^1.0.2",
|
||||
"sass": "1.43.2",
|
||||
"sass": "1.44.0",
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.2",
|
||||
"stoppable": "^1.1.0",
|
||||
|
||||
@@ -141,7 +141,7 @@ function completeVerify(profile,done) {
|
||||
Users.authenticate(profile).then(function(user) {
|
||||
if (user) {
|
||||
Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) {
|
||||
log.audit({event: "auth.login",username:user.username,scope:user.permissions});
|
||||
log.audit({event: "auth.login",user,username:user.username,scope:user.permissions});
|
||||
user.tokens = tokens;
|
||||
done(null,user);
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ var passwordTokenExchange = function(client, username, password, scope, done) {
|
||||
return logEntry.user !== username;
|
||||
});
|
||||
Tokens.create(username,client.id,scope).then(function(tokens) {
|
||||
log.audit({event: "auth.login",username:username,client:client.id,scope:scope});
|
||||
log.audit({event: "auth.login",user,username:username,client:client.id,scope:scope});
|
||||
done(null,tokens.accessToken,null,{expires_in:tokens.expires_in});
|
||||
});
|
||||
} else {
|
||||
@@ -146,7 +146,7 @@ function authenticateUserToken(req) {
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}).catch(reject);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
@@ -163,6 +163,9 @@ TokensStrategy.prototype.authenticate = function(req) {
|
||||
authenticateUserToken(req).then(user => {
|
||||
this.success(user,{scope:user.permissions});
|
||||
}).catch(err => {
|
||||
if (err) {
|
||||
log.trace("token authentication failure: "+err.stack?err.stack:err)
|
||||
}
|
||||
this.fail(401);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,9 +48,10 @@ module.exports = {
|
||||
var prevLang = i18n.i.language;
|
||||
// Trigger a load from disk of the language if it is not the default
|
||||
i18n.i.changeLanguage(lang, function(){
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
i18n.i.changeLanguage(prevLang, function() {
|
||||
var catalog = loadResource(lang, namespace);
|
||||
res.json(catalog||{});
|
||||
});
|
||||
});
|
||||
i18n.i.changeLanguage(prevLang);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +228,11 @@ module.exports = {
|
||||
if (theme.theme) {
|
||||
themeSettings.theme = theme.theme;
|
||||
}
|
||||
|
||||
if (theme.hasOwnProperty("tours")) {
|
||||
themeSettings.tours = theme.tours;
|
||||
}
|
||||
|
||||
return themeApp;
|
||||
},
|
||||
context: async function() {
|
||||
|
||||
@@ -90,6 +90,8 @@ function init(settings,_server,storage,runtimeAPI) {
|
||||
auth.getToken,
|
||||
auth.errorHandler
|
||||
);
|
||||
} else if (settings.adminAuth.tokens) {
|
||||
adminApp.use(passport.initialize());
|
||||
}
|
||||
adminApp.post("/auth/revoke",auth.needsPermission(""),auth.revoke,apiUtil.errorHandler);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.1.2",
|
||||
"@node-red/editor-client": "2.1.2",
|
||||
"@node-red/util": "2.2.0-beta.1",
|
||||
"@node-red/editor-client": "2.2.0-beta.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.0",
|
||||
"clone": "2.1.2",
|
||||
@@ -28,7 +28,7 @@
|
||||
"mime": "2.5.2",
|
||||
"multer": "1.4.3",
|
||||
"mustache": "4.2.0",
|
||||
"oauth2orize": "1.11.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"passport": "0.5.0",
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
"hideOtherFlows": "Hide other flows",
|
||||
"showAllFlows": "Show all flows",
|
||||
"hideAllFlows": "Hide all flows",
|
||||
"hiddenFlows": "List __count__ hidden flow",
|
||||
"hiddenFlows_plural": "List __count__ hidden flows",
|
||||
"showLastHiddenFlow": "Show last hidden flow",
|
||||
"listFlows": "List flows",
|
||||
"listSubflows": "List subflows",
|
||||
@@ -90,6 +92,7 @@
|
||||
"palette": {
|
||||
"show": "Show palette"
|
||||
},
|
||||
"edit": "Edit",
|
||||
"settings": "Settings",
|
||||
"userSettings": "User Settings",
|
||||
"nodes": "Nodes",
|
||||
@@ -668,7 +671,8 @@
|
||||
"unusedConfigNodes": "Unused configuration nodes",
|
||||
"invalidNodes": "Invalid nodes",
|
||||
"uknownNodes": "Unknown nodes",
|
||||
"unusedSubflows": "Unused subflows"
|
||||
"unusedSubflows": "Unused subflows",
|
||||
"hiddenFlows": "Hidden flows"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@@ -890,6 +894,8 @@
|
||||
"addTitle": "add an item"
|
||||
},
|
||||
"search": {
|
||||
"history": "Search history",
|
||||
"clear": "clear all",
|
||||
"empty": "No matches found",
|
||||
"addNode": "add a node..."
|
||||
},
|
||||
@@ -1135,6 +1141,7 @@
|
||||
"defaultValue": "Default value"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "Take a tour",
|
||||
"start": "Start",
|
||||
"next": "Next"
|
||||
},
|
||||
|
||||
@@ -54,7 +54,16 @@
|
||||
"delete": "本当に '__label__' を削除しますか?",
|
||||
"dropFlowHere": "ここにフローをドロップしてください",
|
||||
"addFlow": "フローの追加",
|
||||
"addFlowToRight": "右側にフローを追加",
|
||||
"hideFlow": "フローを非表示",
|
||||
"hideOtherFlows": "他のフローを非表示",
|
||||
"showAllFlows": "全てのフローを表示",
|
||||
"hideAllFlows": "全てのフローを非表示",
|
||||
"hiddenFlows": "__count__ 個の非表示のフロー一覧",
|
||||
"hiddenFlows_plural": "__count__ 個の非表示のフロー一覧",
|
||||
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
|
||||
"listFlows": "フロー一覧",
|
||||
"listSubflows": "サブフロー一覧",
|
||||
"status": "状態",
|
||||
"enabled": "有効",
|
||||
"disabled": "無効",
|
||||
@@ -83,6 +92,7 @@
|
||||
"palette": {
|
||||
"show": "パレットを表示"
|
||||
},
|
||||
"edit": "編集",
|
||||
"settings": "設定",
|
||||
"userSettings": "ユーザ設定",
|
||||
"nodes": "ノード",
|
||||
@@ -105,6 +115,7 @@
|
||||
"editPalette": "パレットの管理",
|
||||
"other": "その他",
|
||||
"showTips": "ヒントを表示",
|
||||
"showWelcomeTours": "新バージョンのガイドツアーを表示",
|
||||
"help": "Node-REDウェブサイト",
|
||||
"projects": "プロジェクト",
|
||||
"projects-new": "新規",
|
||||
@@ -116,7 +127,20 @@
|
||||
"groupSelection": "選択部分をグループ化",
|
||||
"ungroupSelection": "選択部分をグループ解除",
|
||||
"groupMergeSelection": "選択部分をマージ",
|
||||
"groupRemoveSelection": "グループから削除"
|
||||
"groupRemoveSelection": "グループから削除",
|
||||
"arrange": "配置",
|
||||
"alignLeft": "左揃え",
|
||||
"alignCenter": "左右中央揃え",
|
||||
"alignRight": "右揃え",
|
||||
"alignTop": "上揃え",
|
||||
"alignMiddle": "上下中央揃え",
|
||||
"alignBottom": "下揃え",
|
||||
"distributeHorizontally": "左右に整列",
|
||||
"distributeVertically": "上下に整列",
|
||||
"moveToBack": "最背面へ移動",
|
||||
"moveToFront": "最前面へ移動",
|
||||
"moveBackwards": "背面へ移動",
|
||||
"moveForwards": "前面へ移動"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
@@ -451,7 +475,8 @@
|
||||
"global": "グローバル",
|
||||
"workspace": "ワークスペース",
|
||||
"selectAll": "全てのノードを選択",
|
||||
"selectAllConnected": "接続された全てのノードを選択",
|
||||
"selectNone": "選択を外す",
|
||||
"selectAllConnected": "接続されたノードを選択",
|
||||
"addRemoveNode": "ノードの選択、選択解除",
|
||||
"editSelected": "選択したノードを編集",
|
||||
"deleteSelected": "選択したノードや接続を削除",
|
||||
@@ -461,10 +486,13 @@
|
||||
"moveNode": "選択したノードを移動(移動量大)",
|
||||
"toggleSidebar": "サイドバーの表示/非表示",
|
||||
"togglePalette": "パレットの表示/非表示",
|
||||
"copyNode": "選択したノードをコピー",
|
||||
"cutNode": "選択したノードを切り取り",
|
||||
"copyNode": "ノードをコピー",
|
||||
"cutNode": "ノードを切り取り",
|
||||
"pasteNode": "ノードを貼り付け",
|
||||
"copyGroupStyle": "グループ様式をコピー",
|
||||
"pasteGroupStyle": "グループ様式を貼り付け",
|
||||
"undoChange": "変更操作を戻す",
|
||||
"redoChange": "変更操作をやり直し",
|
||||
"searchBox": "ノードを検索",
|
||||
"managePalette": "パレットの管理",
|
||||
"actionList": "動作一覧"
|
||||
@@ -519,7 +547,8 @@
|
||||
"nodeEnabled_plural": "ノードを有効化しました:",
|
||||
"nodeDisabled": "ノードを無効化しました:",
|
||||
"nodeDisabled_plural": "ノードを無効化しました:",
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
|
||||
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました",
|
||||
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
|
||||
},
|
||||
"editor": {
|
||||
"title": "パレットの管理",
|
||||
@@ -642,7 +671,8 @@
|
||||
"unusedConfigNodes": "未使用の設定ノード",
|
||||
"invalidNodes": "不正なノード",
|
||||
"uknownNodes": "未知のノード",
|
||||
"unusedSubflows": "未使用のサブフロー"
|
||||
"unusedSubflows": "未使用のサブフロー",
|
||||
"hiddenFlows": "非表示のフロー"
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
@@ -1108,6 +1138,11 @@
|
||||
"preview": "UIプレビュー",
|
||||
"defaultValue": "デフォルト値"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "ツアーを開始",
|
||||
"start": "開始",
|
||||
"next": "次へ"
|
||||
},
|
||||
"languages": {
|
||||
"de": "ドイツ語",
|
||||
"en-US": "英語",
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
"compact": "紧凑",
|
||||
"formatted": "已格式化",
|
||||
"copy": "导出到剪贴板",
|
||||
"export": "到处到库",
|
||||
"export": "导出到库",
|
||||
"exportAs": "导出为",
|
||||
"overwrite": "替换",
|
||||
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "2.1.2",
|
||||
"version": "2.2.0-beta.1",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -684,6 +684,13 @@ RED.history = (function() {
|
||||
peek: function() {
|
||||
return undoHistory[undoHistory.length-1];
|
||||
},
|
||||
replace: function(ev) {
|
||||
if (undoHistory.length === 0) {
|
||||
RED.history.push(ev);
|
||||
} else {
|
||||
undoHistory[undoHistory.length-1] = ev;
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
undoHistory = [];
|
||||
redoHistory = [];
|
||||
|
||||
@@ -38,6 +38,8 @@ RED.i18n = (function() {
|
||||
defaultNS: "editor",
|
||||
fallbackLng: ['en-US'],
|
||||
returnObjects: true,
|
||||
keySeparator: ".",
|
||||
nsSeparator: ":",
|
||||
interpolation: {
|
||||
unescapeSuffix: 'HTML',
|
||||
escapeValue: false,
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
},
|
||||
"red-ui-workspace": {
|
||||
"backspace": "core:delete-selection",
|
||||
"ctrl-backspace": "core:delete-selection-and-reconnect",
|
||||
"delete": "core:delete-selection",
|
||||
"ctrl-delete": "core:delete-selection-and-reconnect",
|
||||
"enter": "core:edit-selected-node",
|
||||
"ctrl-enter": "core:go-to-selection",
|
||||
"ctrl-c": "core:copy-selection-to-internal-clipboard",
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
**/
|
||||
RED.nodes = (function() {
|
||||
|
||||
var PORT_TYPE_INPUT = 1;
|
||||
var PORT_TYPE_OUTPUT = 0;
|
||||
|
||||
var node_defs = {};
|
||||
var linkTabMap = {};
|
||||
|
||||
@@ -591,7 +594,9 @@ RED.nodes = (function() {
|
||||
}
|
||||
allNodes.addNode(n);
|
||||
if (!nodeLinks[n.id]) {
|
||||
nodeLinks[n.id] = {in:[],out:[]};
|
||||
nodeLinks[n.id] = {
|
||||
inCount:[],outCount:[],in:[],out:[]
|
||||
};
|
||||
}
|
||||
}
|
||||
RED.events.emit('nodes:add',n);
|
||||
@@ -601,15 +606,19 @@ RED.nodes = (function() {
|
||||
if (l.source) {
|
||||
// Possible the node hasn't been added yet
|
||||
if (!nodeLinks[l.source.id]) {
|
||||
nodeLinks[l.source.id] = {in:[],out:[]};
|
||||
nodeLinks[l.source.id] = {inCount:[],outCount:[],in:[],out:[]};
|
||||
}
|
||||
nodeLinks[l.source.id].out.push(l);
|
||||
nodeLinks[l.source.id].outCount[l.sourcePort] = (nodeLinks[l.source.id].outCount[l.sourcePort] || 0) + 1
|
||||
l.source.dirty = true;
|
||||
}
|
||||
if (l.target) {
|
||||
if (!nodeLinks[l.target.id]) {
|
||||
nodeLinks[l.target.id] = {in:[],out:[]};
|
||||
nodeLinks[l.target.id] = {inCount:[],outCount:[],in:[],out:[]};
|
||||
}
|
||||
nodeLinks[l.target.id].in.push(l);
|
||||
nodeLinks[l.target.id].inCount[0] = (nodeLinks[l.target.id].inCount[0] || 0) + 1
|
||||
l.target.dirty = true;
|
||||
}
|
||||
if (l.source.z === l.target.z && linkTabMap[l.source.z]) {
|
||||
linkTabMap[l.source.z].push(l);
|
||||
@@ -758,15 +767,19 @@ RED.nodes = (function() {
|
||||
if (index != -1) {
|
||||
links.splice(index,1);
|
||||
if (l.source && nodeLinks[l.source.id]) {
|
||||
l.source.dirty = true;
|
||||
var sIndex = nodeLinks[l.source.id].out.indexOf(l)
|
||||
if (sIndex !== -1) {
|
||||
nodeLinks[l.source.id].out.splice(sIndex,1)
|
||||
nodeLinks[l.source.id].outCount[l.sourcePort]--
|
||||
}
|
||||
}
|
||||
if (l.target && nodeLinks[l.target.id]) {
|
||||
l.target.dirty = true;
|
||||
var tIndex = nodeLinks[l.target.id].in.indexOf(l)
|
||||
if (tIndex !== -1) {
|
||||
nodeLinks[l.target.id].in.splice(tIndex,1)
|
||||
nodeLinks[l.target.id].inCount[0]--
|
||||
}
|
||||
}
|
||||
if (l.source.z === l.target.z && linkTabMap[l.source.z]) {
|
||||
@@ -805,7 +818,6 @@ RED.nodes = (function() {
|
||||
var removedGroups = [];
|
||||
if (ws) {
|
||||
delete workspaces[id];
|
||||
allNodes.removeTab(id);
|
||||
delete linkTabMap[id];
|
||||
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
|
||||
var i;
|
||||
@@ -843,6 +855,7 @@ RED.nodes = (function() {
|
||||
for (i=removedGroups.length-1; i>=0; i--) {
|
||||
removeGroup(removedGroups[i]);
|
||||
}
|
||||
allNodes.removeTab(id);
|
||||
RED.events.emit('flows:remove',ws);
|
||||
}
|
||||
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
|
||||
@@ -1097,6 +1110,11 @@ RED.nodes = (function() {
|
||||
// Until we know how that can happen, add a filter here to remove them
|
||||
node.nodes = node.nodes.filter(function(n) { return !!n }).map(function(n) { return n.id });
|
||||
}
|
||||
if (n.type === "tab" || n.type === "group") {
|
||||
if (node.env && node.env.length === 0) {
|
||||
delete node.env;
|
||||
}
|
||||
}
|
||||
if (n._def.category != "config") {
|
||||
node.x = n.x;
|
||||
node.y = n.y;
|
||||
@@ -2453,6 +2471,144 @@ RED.nodes = (function() {
|
||||
return helpContent;
|
||||
}
|
||||
|
||||
function getNodeIslands(nodes) {
|
||||
var selectedNodes = new Set(nodes);
|
||||
// Maps node => island index
|
||||
var nodeToIslandIndex = new Map();
|
||||
// Maps island index => [nodes in island]
|
||||
var islandIndexToNodes = new Map();
|
||||
var internalLinks = new Set();
|
||||
nodes.forEach((node, index) => {
|
||||
nodeToIslandIndex.set(node,index);
|
||||
islandIndexToNodes.set(index, [node]);
|
||||
var inboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_INPUT);
|
||||
var outboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_OUTPUT);
|
||||
inboundLinks.forEach(l => {
|
||||
if (selectedNodes.has(l.source)) {
|
||||
internalLinks.add(l)
|
||||
}
|
||||
})
|
||||
outboundLinks.forEach(l => {
|
||||
if (selectedNodes.has(l.target)) {
|
||||
internalLinks.add(l)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
internalLinks.forEach(l => {
|
||||
let source = l.source;
|
||||
let target = l.target;
|
||||
if (nodeToIslandIndex.get(source) !== nodeToIslandIndex.get(target)) {
|
||||
let sourceIsland = nodeToIslandIndex.get(source);
|
||||
let islandToMove = nodeToIslandIndex.get(target);
|
||||
let nodesToMove = islandIndexToNodes.get(islandToMove);
|
||||
nodesToMove.forEach(n => {
|
||||
nodeToIslandIndex.set(n,sourceIsland);
|
||||
islandIndexToNodes.get(sourceIsland).push(n);
|
||||
})
|
||||
islandIndexToNodes.delete(islandToMove);
|
||||
}
|
||||
})
|
||||
const result = [];
|
||||
islandIndexToNodes.forEach((nodes,index) => {
|
||||
result.push(nodes);
|
||||
})
|
||||
return result;
|
||||
}
|
||||
|
||||
function detachNodes(nodes) {
|
||||
let allSelectedNodes = [];
|
||||
nodes.forEach(node => {
|
||||
if (node.type === 'group') {
|
||||
let groupNodes = RED.group.getNodes(node,true,true);
|
||||
allSelectedNodes = allSelectedNodes.concat(groupNodes);
|
||||
} else {
|
||||
allSelectedNodes.push(node);
|
||||
}
|
||||
})
|
||||
if (allSelectedNodes.length > 0 ) {
|
||||
const nodeIslands = RED.nodes.getNodeIslands(allSelectedNodes);
|
||||
let removedLinks = [];
|
||||
let newLinks = [];
|
||||
let createdLinkIds = new Set();
|
||||
|
||||
nodeIslands.forEach(nodes => {
|
||||
let selectedNodes = new Set(nodes);
|
||||
let allInboundLinks = [];
|
||||
let allOutboundLinks = [];
|
||||
// Identify links that enter or exit this island of nodes
|
||||
nodes.forEach(node => {
|
||||
var inboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_INPUT);
|
||||
var outboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_OUTPUT);
|
||||
inboundLinks.forEach(l => {
|
||||
if (!selectedNodes.has(l.source)) {
|
||||
allInboundLinks.push(l)
|
||||
}
|
||||
})
|
||||
outboundLinks.forEach(l => {
|
||||
if (!selectedNodes.has(l.target)) {
|
||||
allOutboundLinks.push(l)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// Identify the links to restore
|
||||
allInboundLinks.forEach(inLink => {
|
||||
// For Each inbound link,
|
||||
// - get source node.
|
||||
// - trace through to all outbound links
|
||||
let sourceNode = inLink.source;
|
||||
let targetNodes = new Set();
|
||||
let visited = new Set();
|
||||
let stack = [inLink.target];
|
||||
while (stack.length > 0) {
|
||||
let node = stack.pop(stack);
|
||||
visited.add(node)
|
||||
let links = RED.nodes.getNodeLinks(node, PORT_TYPE_OUTPUT);
|
||||
links.forEach(l => {
|
||||
if (visited.has(l.target)) {
|
||||
return
|
||||
}
|
||||
visited.add(l.target);
|
||||
if (selectedNodes.has(l.target)) {
|
||||
// internal link
|
||||
stack.push(l.target)
|
||||
} else {
|
||||
targetNodes.add(l.target)
|
||||
}
|
||||
})
|
||||
}
|
||||
targetNodes.forEach(target => {
|
||||
let linkId = `${sourceNode.id}[${inLink.sourcePort}] -> ${target.id}`
|
||||
if (!createdLinkIds.has(linkId)) {
|
||||
createdLinkIds.add(linkId);
|
||||
let link = {
|
||||
source: sourceNode,
|
||||
sourcePort: inLink.sourcePort,
|
||||
target: target
|
||||
}
|
||||
let existingLinks = RED.nodes.filterLinks(link)
|
||||
if (existingLinks.length === 0) {
|
||||
newLinks.push(link);
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 2. delete all those links
|
||||
allInboundLinks.forEach(l => { RED.nodes.removeLink(l); removedLinks.push(l)})
|
||||
allOutboundLinks.forEach(l => { RED.nodes.removeLink(l); removedLinks.push(l)})
|
||||
})
|
||||
|
||||
newLinks.forEach(l => RED.nodes.addLink(l));
|
||||
return {
|
||||
newLinks,
|
||||
removedLinks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.events.on("registry:node-type-added",function(type) {
|
||||
@@ -2534,7 +2690,7 @@ RED.nodes = (function() {
|
||||
add: addNode,
|
||||
remove: removeNode,
|
||||
clear: clear,
|
||||
|
||||
detachNodes: detachNodes,
|
||||
moveNodesForwards: moveNodesForwards,
|
||||
moveNodesBackwards: moveNodesBackwards,
|
||||
moveNodesToFront: moveNodesToFront,
|
||||
@@ -2546,7 +2702,34 @@ RED.nodes = (function() {
|
||||
|
||||
addLink: addLink,
|
||||
removeLink: removeLink,
|
||||
|
||||
getNodeLinks: function(id, portType) {
|
||||
if (typeof id !== 'string') {
|
||||
id = id.id;
|
||||
}
|
||||
if (nodeLinks[id]) {
|
||||
if (portType === 1) {
|
||||
// Return cloned arrays so they can be safely modified by caller
|
||||
return [].concat(nodeLinks[id].in)
|
||||
} else {
|
||||
return [].concat(nodeLinks[id].out)
|
||||
}
|
||||
}
|
||||
return [];
|
||||
},
|
||||
getNodeLinkCount: function(id,portType,index) {
|
||||
// We *could* just let callers use `getNodeLinks` and get the
|
||||
// the length for themselves. However, that function creates
|
||||
// a clone of the array - which is needless work if all you
|
||||
// want is the length
|
||||
if (nodeLinks[id]) {
|
||||
if (portType === 1) {
|
||||
return nodeLinks[id].inCount[index] || 0
|
||||
} else {
|
||||
return nodeLinks[id].outCount[index] || 0
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
addWorkspace: addWorkspace,
|
||||
removeWorkspace: removeWorkspace,
|
||||
getWorkspaceOrder: function() { return workspacesOrder },
|
||||
@@ -2620,6 +2803,7 @@ RED.nodes = (function() {
|
||||
getAllFlowNodes: getAllFlowNodes,
|
||||
getAllUpstreamNodes: getAllUpstreamNodes,
|
||||
getAllDownstreamNodes: getAllDownstreamNodes,
|
||||
getNodeIslands: getNodeIslands,
|
||||
createExportableNodeSet: createExportableNodeSet,
|
||||
createCompleteNodeSet: createCompleteNodeSet,
|
||||
updateConfigNodeUsers: updateConfigNodeUsers,
|
||||
|
||||
@@ -475,31 +475,33 @@ var RED = (function() {
|
||||
var typeList;
|
||||
var info;
|
||||
if (topic == "notification/node/added") {
|
||||
var addedTypes = [];
|
||||
msg.forEach(function(m) {
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadNodeCatalog(id, function() {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
}
|
||||
RED.settings.refreshSettings(function(err, data) {
|
||||
var addedTypes = [];
|
||||
msg.forEach(function(m) {
|
||||
var id = m.id;
|
||||
RED.nodes.addNodeSet(m);
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
RED.i18n.loadNodeCatalog(id, function() {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||
}
|
||||
loadIconList();
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
|
||||
}
|
||||
loadIconList();
|
||||
})
|
||||
} else if (topic == "notification/node/removed") {
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
@@ -512,27 +514,29 @@ var RED = (function() {
|
||||
loadIconList();
|
||||
} else if (topic == "notification/node/enabled") {
|
||||
if (msg.types) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+msg.id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.settings.refreshSettings(function(err, data) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
|
||||
} else {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'nodes/'+msg.id,
|
||||
success: function(data) {
|
||||
appendNodeConfig(data);
|
||||
typeList = "<ul><li>"+msg.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (topic == "notification/node/disabled") {
|
||||
if (msg.types) {
|
||||
@@ -586,7 +590,7 @@ var RED = (function() {
|
||||
{id:"menu-item-projects-settings",label:RED._("menu.label.projects-settings"),disabled:false,onselect:"core:show-project-settings"}
|
||||
]});
|
||||
}
|
||||
menuOptions.push({id:"menu-item-edit-menu", label:"Edit", options: [
|
||||
menuOptions.push({id:"menu-item-edit-menu", label:RED._("menu.label.edit"), options: [
|
||||
{id: "menu-item-edit-undo", label:RED._("keyboard.undoChange"), disabled: true, onselect: "core:undo"},
|
||||
{id: "menu-item-edit-redo", label:RED._("keyboard.redoChange"), disabled: true, onselect: "core:redo"},
|
||||
null,
|
||||
|
||||
@@ -125,7 +125,7 @@ RED.settings = (function () {
|
||||
load(done);
|
||||
}
|
||||
|
||||
var load = function(done) {
|
||||
var refreshSettings = function(done) {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
@@ -135,6 +135,23 @@ RED.settings = (function () {
|
||||
url: 'settings',
|
||||
success: function (data) {
|
||||
setProperties(data);
|
||||
done(null, data);
|
||||
},
|
||||
error: function(jqXHR,textStatus,errorThrown) {
|
||||
if (jqXHR.status === 401) {
|
||||
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
|
||||
window.location.search = "";
|
||||
}
|
||||
RED.user.login(function() { refreshSettings(done); });
|
||||
} else {
|
||||
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
var load = function(done) {
|
||||
refreshSettings(function(err, data) {
|
||||
if (!err) {
|
||||
if (!RED.settings.user || RED.settings.user.anonymous) {
|
||||
RED.settings.remove("auth-tokens");
|
||||
}
|
||||
@@ -147,18 +164,8 @@ RED.settings = (function () {
|
||||
console.log("D3",d3.version);
|
||||
console.groupEnd();
|
||||
loadUserSettings(done);
|
||||
},
|
||||
error: function(jqXHR,textStatus,errorThrown) {
|
||||
if (jqXHR.status === 401) {
|
||||
if (/[?&]access_token=(.*?)(?:$|&)/.test(window.location.search)) {
|
||||
window.location.search = "";
|
||||
}
|
||||
RED.user.login(function() { load(done); });
|
||||
} else {
|
||||
console.log("Unexpected error loading settings:",jqXHR.status,textStatus);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
function loadUserSettings(done) {
|
||||
@@ -234,6 +241,7 @@ RED.settings = (function () {
|
||||
init: init,
|
||||
load: load,
|
||||
loadUserSettings: loadUserSettings,
|
||||
refreshSettings: refreshSettings,
|
||||
set: set,
|
||||
get: get,
|
||||
remove: remove,
|
||||
|
||||
@@ -71,6 +71,7 @@ RED.clipboard = (function() {
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
},
|
||||
{ // red-ui-clipboard-dialog-download
|
||||
@@ -81,6 +82,7 @@ RED.clipboard = (function() {
|
||||
var data = $("#red-ui-clipboard-dialog-export-text").val();
|
||||
downloadData("flows.json", data);
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
},
|
||||
{ // red-ui-clipboard-dialog-export
|
||||
@@ -95,6 +97,7 @@ RED.clipboard = (function() {
|
||||
$( this ).dialog( "close" );
|
||||
copyText(flowData);
|
||||
RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"});
|
||||
RED.view.focus();
|
||||
} else {
|
||||
var flowToExport = $("#red-ui-clipboard-dialog-export-text").val();
|
||||
var selectedPath = activeLibraries[activeTab].getSelected();
|
||||
@@ -110,6 +113,7 @@ RED.clipboard = (function() {
|
||||
contentType: "application/json; charset=utf-8"
|
||||
}).done(function() {
|
||||
$(dialog).dialog( "close" );
|
||||
RED.view.focus();
|
||||
RED.notify(RED._("library.exportedToLibrary"),"success");
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
if (xhr.status === 401) {
|
||||
@@ -171,6 +175,7 @@ RED.clipboard = (function() {
|
||||
}
|
||||
}
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
},
|
||||
{ // red-ui-clipboard-dialog-import-conflict
|
||||
@@ -203,6 +208,7 @@ RED.clipboard = (function() {
|
||||
// console.table(pendingImportConfig.importNodes.map(function(n) { return {id:n.id,type:n.type,result:importMap[n.id]}}))
|
||||
RED.view.importNodes(newNodes, pendingImportConfig.importOptions);
|
||||
$( this ).dialog( "close" );
|
||||
RED.view.focus();
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* value: String : the value to insert if selected
|
||||
* label: String|DOM Element : the label to display in the dropdown.
|
||||
* }
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
$.widget( "nodered.autoComplete", {
|
||||
@@ -62,7 +62,7 @@
|
||||
maxHeight: 200,
|
||||
class: "red-ui-autoComplete-container",
|
||||
options: completions,
|
||||
onselect: (opt) => { this.element.val(opt.value); this.element.focus() },
|
||||
onselect: (opt) => { this.element.val(opt.value); this.element.focus(); this.element.trigger("change") },
|
||||
onclose: () => { this.completionMenuShown = false; delete this.menu; this.element.focus()}
|
||||
});
|
||||
this.menu.show({
|
||||
|
||||
@@ -117,6 +117,8 @@ RED.tabs = (function() {
|
||||
menuOptions = options.menu()
|
||||
} else if (Array.isArray(options.menu)) {
|
||||
menuOptions = options.menu;
|
||||
} else if (typeof options.menu === 'function') {
|
||||
menuOptions = options.menu();
|
||||
}
|
||||
menu = RED.menu.init({options: menuOptions});
|
||||
menu.attr("id",options.id+"-menu");
|
||||
@@ -576,7 +578,7 @@ RED.tabs = (function() {
|
||||
|
||||
function findPreviousVisibleTab(li) {
|
||||
if (!li) {
|
||||
li = ul.find("li.active").parent();
|
||||
li = ul.find("li.active");
|
||||
}
|
||||
var previous = li.prev();
|
||||
while(previous.length > 0 && previous.hasClass("hide-tab")) {
|
||||
@@ -586,9 +588,9 @@ RED.tabs = (function() {
|
||||
}
|
||||
function findNextVisibleTab(li) {
|
||||
if (!li) {
|
||||
li = ul.find("li.active").parent();
|
||||
li = ul.find("li.active");
|
||||
}
|
||||
var next = ul.find("li.active").next();
|
||||
var next = li.next();
|
||||
while(next.length > 0 && next.hasClass("hide-tab")) {
|
||||
next = next.next();
|
||||
}
|
||||
@@ -809,15 +811,18 @@ RED.tabs = (function() {
|
||||
event.preventDefault();
|
||||
removeTab(tab.id);
|
||||
});
|
||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||
}
|
||||
if (tab.hideable) {
|
||||
li.addClass("red-ui-tabs-closeable")
|
||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
|
||||
closeLink.append('<i class="fa fa-times" />');
|
||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
|
||||
closeLink.append('<i class="fa fa-eye" />');
|
||||
closeLink.append('<i class="fa fa-eye-slash" />');
|
||||
closeLink.on("click",function(event) {
|
||||
event.preventDefault();
|
||||
hideTab(tab.id);
|
||||
});
|
||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||
}
|
||||
|
||||
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
|
||||
@@ -826,7 +831,8 @@ RED.tabs = (function() {
|
||||
$('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges);
|
||||
}
|
||||
|
||||
link.attr("title",tab.label);
|
||||
// link.attr("title",tab.label);
|
||||
RED.popover.tooltip(link,function() { return tab.label})
|
||||
|
||||
if (options.onadd) {
|
||||
options.onadd(tab);
|
||||
@@ -945,7 +951,6 @@ RED.tabs = (function() {
|
||||
renameTab: function(id,label) {
|
||||
tabs[id].label = label;
|
||||
var tab = ul.find("a[href='#"+id+"']");
|
||||
tab.attr("title",label);
|
||||
tab.find("span.red-ui-text-bidi-aware").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label));
|
||||
updateTabWidths();
|
||||
},
|
||||
|
||||
@@ -340,7 +340,7 @@
|
||||
if (child.depth !== parent.depth+1) {
|
||||
child.depth = parent.depth+1;
|
||||
// var labelPaddingWidth = ((child.gutter ? child.gutter[0].offsetWidth + 2 : 0) + (child.depth * 20));
|
||||
var labelPaddingWidth = ((child.gutter?child.gutter.width()+2:0)+(child.depth*20));
|
||||
var labelPaddingWidth = (((child.gutter&&!child.gutter.hasClass("red-ui-treeList-gutter-float"))?child.gutter.width()+2:0)+(child.depth*20));
|
||||
child.treeList.labelPadding.width(labelPaddingWidth+'px');
|
||||
if (child.element) {
|
||||
$(child.element).css({
|
||||
@@ -562,8 +562,9 @@
|
||||
}).appendTo(label)
|
||||
|
||||
}
|
||||
// var labelPaddingWidth = (item.gutter?item.gutter.width()+2:0)+(depth*20);
|
||||
var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (depth * 20)
|
||||
|
||||
var labelPaddingWidth = ((item.gutter&&!item.gutter.hasClass("red-ui-treeList-gutter-float"))?item.gutter.width()+2:0)+(depth*20);
|
||||
|
||||
item.treeList.labelPadding = $('<span>').css({
|
||||
display: "inline-block",
|
||||
"flex-shrink": 0,
|
||||
|
||||
@@ -556,7 +556,7 @@
|
||||
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
|
||||
this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton);
|
||||
|
||||
this.type(this.options.default||this.typeList[0].value);
|
||||
this.type(this.typeField.val() || this.options.default||this.typeList[0].value);
|
||||
this.typeChanged = !!this.options.default;
|
||||
}catch(err) {
|
||||
console.log(err.stack);
|
||||
@@ -805,6 +805,7 @@
|
||||
var that = this;
|
||||
var currentType = this.type();
|
||||
this.typeMap = {};
|
||||
var firstCall = (this.typeList === undefined);
|
||||
this.typeList = types.map(function(opt) {
|
||||
var result;
|
||||
if (typeof opt === 'string') {
|
||||
@@ -829,10 +830,14 @@
|
||||
}
|
||||
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
|
||||
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
|
||||
this.type(this.typeList[0].value);
|
||||
if (!firstCall) {
|
||||
this.type(this.typeList[0].value);
|
||||
}
|
||||
} else {
|
||||
this.propertyType = null;
|
||||
this.type(currentType);
|
||||
if (!firstCall) {
|
||||
this.type(currentType);
|
||||
}
|
||||
}
|
||||
if (this.typeList.length === 1 && !this.typeList[0].icon && (!this.typeList[0].label || this.typeList[0].showLabel === false)) {
|
||||
this.selectTrigger.hide()
|
||||
@@ -923,7 +928,7 @@
|
||||
var previousType = this.typeMap[this.propertyType];
|
||||
previousValue = this.input.val();
|
||||
|
||||
if (this.typeChanged) {
|
||||
if (previousType && this.typeChanged) {
|
||||
if (this.options.debug) { console.log(this.identifier,"typeChanged",{previousType,previousValue}) }
|
||||
if (previousType.options && opt.hasValue !== true) {
|
||||
this.oldValues[previousType.value] = previousValue;
|
||||
|
||||
@@ -333,6 +333,16 @@ RED.deploy = (function() {
|
||||
var unknownNodes = [];
|
||||
var invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(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);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
|
||||
@@ -554,6 +554,8 @@ RED.diff = (function() {
|
||||
color: "#DDAA99",
|
||||
defaults:{name:{value:""}}
|
||||
}
|
||||
} else if (node.type === "group") {
|
||||
def = RED.group.def;
|
||||
} else {
|
||||
def = {};
|
||||
}
|
||||
@@ -763,16 +765,15 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (node.hasOwnProperty('x')) {
|
||||
if (localNode) {
|
||||
if (localNode.x !== node.x || localNode.y !== node.y) {
|
||||
if (localNode.x !== node.x || localNode.y !== node.y || localNode.w !== node.w || localNode.h !== node.h ) {
|
||||
localChanged = true;
|
||||
localChanges++;
|
||||
}
|
||||
}
|
||||
if (remoteNode) {
|
||||
if (remoteNode.x !== node.x || remoteNode.y !== node.y) {
|
||||
if (remoteNode.x !== node.x || remoteNode.y !== node.y|| remoteNode.w !== node.w || remoteNode.h !== node.h) {
|
||||
remoteChanged = true;
|
||||
remoteChanges++;
|
||||
}
|
||||
@@ -790,7 +791,12 @@ RED.diff = (function() {
|
||||
localCell.addClass("red-ui-diff-status-"+(localChanged?"changed":"unchanged"));
|
||||
$('<span class="red-ui-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
|
||||
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(localCell);
|
||||
propertyElements['local.position'] = RED.utils.createObjectElement({x:localNode.x,y:localNode.y},
|
||||
var localPosition = {x:localNode.x,y:localNode.y};
|
||||
if (localNode.hasOwnProperty('w')) {
|
||||
localPosition.w = localNode.w;
|
||||
localPosition.h = localNode.h;
|
||||
}
|
||||
propertyElements['local.position'] = RED.utils.createObjectElement(localPosition,
|
||||
{
|
||||
path: "position",
|
||||
exposeApi: true,
|
||||
@@ -811,7 +817,12 @@ RED.diff = (function() {
|
||||
if (remoteNode) {
|
||||
$('<span class="red-ui-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
|
||||
element = $('<span class="red-ui-diff-list-element"></span>').appendTo(remoteCell);
|
||||
propertyElements['remote.position'] = RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y},
|
||||
var remotePosition = {x:remoteNode.x,y:remoteNode.y};
|
||||
if (remoteNode.hasOwnProperty('w')) {
|
||||
remotePosition.w = remoteNode.w;
|
||||
remotePosition.h = remoteNode.h;
|
||||
}
|
||||
propertyElements['remote.position'] = RED.utils.createObjectElement(remotePosition,
|
||||
{
|
||||
path: "position",
|
||||
exposeApi: true,
|
||||
@@ -883,11 +894,11 @@ RED.diff = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
|
||||
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='w'&&p!=='h'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
|
||||
if (def.defaults) {
|
||||
properties = properties.concat(Object.keys(def.defaults));
|
||||
}
|
||||
if (node.type !== 'tab') {
|
||||
if (node.type !== 'tab' && node.type !== "group") {
|
||||
properties = properties.concat(['inputLabels','outputLabels']);
|
||||
}
|
||||
if ( ((localNode && localNode.hasOwnProperty('icon')) || (remoteNode && remoteNode.hasOwnProperty('icon'))) &&
|
||||
|
||||
@@ -744,7 +744,16 @@ RED.editor = (function() {
|
||||
delete cn.__label__;
|
||||
});
|
||||
|
||||
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>'+RED._("editor.addNewType", {type:type})+'</option>');
|
||||
var label = type;
|
||||
if (typeof node_def.paletteLabel !== "undefined") {
|
||||
try {
|
||||
label = RED.utils.sanitize((typeof node_def.paletteLabel === "function" ? node_def.paletteLabel.call(node_def) : node_def.paletteLabel)||type);
|
||||
} catch(err) {
|
||||
console.log("Definition error: "+type+".paletteLabel",err);
|
||||
}
|
||||
}
|
||||
|
||||
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>'+RED._("editor.addNewType", {type:label})+'</option>');
|
||||
window.setTimeout(function() { select.trigger("change");},50);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@
|
||||
clearTimeout: true,
|
||||
setInterval: true,
|
||||
clearInterval: true
|
||||
}
|
||||
},
|
||||
extraLibs: options.extraLibs
|
||||
});
|
||||
if (options.cursor) {
|
||||
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
|
||||
|
||||
@@ -55,9 +55,15 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!isSameObj(old_env, new_env)) {
|
||||
node.env = new_env;
|
||||
if (!old_env && new_env.length === 0) {
|
||||
delete node.env;
|
||||
} else if (!isSameObj(old_env, new_env)) {
|
||||
editState.changes.env = node.env;
|
||||
if (new_env.length === 0) {
|
||||
delete node.env;
|
||||
} else {
|
||||
node.env = new_env;
|
||||
}
|
||||
editState.changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,12 +590,14 @@ RED.group = (function() {
|
||||
markDirty(group);
|
||||
}
|
||||
|
||||
function getNodes(group,recursive) {
|
||||
function getNodes(group,recursive,excludeGroup) {
|
||||
var nodes = [];
|
||||
group.nodes.forEach(function(n) {
|
||||
nodes.push(n);
|
||||
if (n.type !== 'group' || !excludeGroup) {
|
||||
nodes.push(n);
|
||||
}
|
||||
if (recursive && n.type === 'group') {
|
||||
nodes = nodes.concat(getNodes(n,recursive))
|
||||
nodes = nodes.concat(getNodes(n,recursive,excludeGroup))
|
||||
}
|
||||
})
|
||||
return nodes;
|
||||
|
||||
@@ -22,6 +22,7 @@ RED.search = (function() {
|
||||
var selected = -1;
|
||||
var visible = false;
|
||||
|
||||
var searchHistory = [];
|
||||
var index = {};
|
||||
var currentResults = [];
|
||||
var previousActiveElement;
|
||||
@@ -105,6 +106,7 @@ RED.search = (function() {
|
||||
val = extractFlag(val,"unused",flags);
|
||||
val = extractFlag(val,"config",flags);
|
||||
val = extractFlag(val,"subflow",flags);
|
||||
val = extractFlag(val,"hidden",flags);
|
||||
// uses:<node-id>
|
||||
val = extractValue(val,"uses",flags);
|
||||
|
||||
@@ -150,7 +152,15 @@ RED.search = (function() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.hasOwnProperty("hidden")) {
|
||||
// Only tabs can be hidden
|
||||
if (node.node.type !== 'tab') {
|
||||
continue
|
||||
}
|
||||
if (!RED.workspaces.isHidden(node.node.id)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("unused")) {
|
||||
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
|
||||
(isConfigNode && node.node.users.length === 0)
|
||||
@@ -196,6 +206,20 @@ RED.search = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function populateSearchHistory() {
|
||||
if (searchHistory.length > 0) {
|
||||
searchResults.editableList('addItem',{
|
||||
historyHeader: true
|
||||
});
|
||||
searchHistory.forEach(function(entry) {
|
||||
searchResults.editableList('addItem',{
|
||||
history: true,
|
||||
value: entry
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
function createDialog() {
|
||||
dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#red-ui-main-container");
|
||||
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
|
||||
@@ -204,7 +228,12 @@ RED.search = (function() {
|
||||
change: function() {
|
||||
searchResults.editableList('empty');
|
||||
selected = -1;
|
||||
currentResults = search($(this).val());
|
||||
var value = $(this).val();
|
||||
if (value === "") {
|
||||
populateSearchHistory();
|
||||
return;
|
||||
}
|
||||
currentResults = search(value);
|
||||
if (currentResults.length > 0) {
|
||||
for (i=0;i<Math.min(currentResults.length,25);i++) {
|
||||
searchResults.editableList('addItem',currentResults[i])
|
||||
@@ -276,7 +305,12 @@ RED.search = (function() {
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} if ($(children[selected]).hasClass("red-ui-search-history")) {
|
||||
var object = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
|
||||
if (object) {
|
||||
searchInput.searchBox('value',object.value)
|
||||
}
|
||||
} else if (!$(children[selected]).hasClass("red-ui-search-historyHeader")) {
|
||||
if (currentResults.length > 0) {
|
||||
reveal(currentResults[Math.max(0,selected)].node);
|
||||
}
|
||||
@@ -292,7 +326,32 @@ RED.search = (function() {
|
||||
addItem: function(container,i,object) {
|
||||
var node = object.node;
|
||||
var div;
|
||||
if (object.more) {
|
||||
if (object.historyHeader) {
|
||||
container.parent().addClass("red-ui-search-historyHeader")
|
||||
$('<div>',{class:"red-ui-search-empty"}).text(RED._("search.history")).appendTo(container);
|
||||
$('<button type="button" class="red-ui-button red-ui-button-small"></button>').text(RED._("search.clear")).appendTo(container).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
searchHistory = [];
|
||||
searchResults.editableList('empty');
|
||||
});
|
||||
} else if (object.history) {
|
||||
container.parent().addClass("red-ui-search-history")
|
||||
div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
|
||||
div.text(object.value);
|
||||
div.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
searchInput.searchBox('value',object.value)
|
||||
searchInput.focus();
|
||||
})
|
||||
$('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-remove"></i></button>').appendTo(container).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var index = searchHistory.indexOf(object.value);
|
||||
searchHistory.splice(index,1);
|
||||
searchResults.editableList('removeItem', object);
|
||||
});
|
||||
|
||||
|
||||
} else if (object.more) {
|
||||
container.parent().addClass("red-ui-search-more")
|
||||
div = $('<a>',{href:'#',class:"red-ui-search-result red-ui-search-empty"}).appendTo(container);
|
||||
div.text(RED._("palette.editor.more",{count:object.more.results.length-object.more.start}));
|
||||
@@ -347,6 +406,12 @@ RED.search = (function() {
|
||||
}
|
||||
|
||||
function reveal(node) {
|
||||
var searchVal = searchInput.val();
|
||||
var existingIndex = searchHistory.indexOf(searchVal);
|
||||
if (existingIndex > -1) {
|
||||
searchHistory.splice(existingIndex,1);
|
||||
}
|
||||
searchHistory.unshift(searchInput.val());
|
||||
hide();
|
||||
RED.view.reveal(node.id);
|
||||
}
|
||||
@@ -365,9 +430,14 @@ RED.search = (function() {
|
||||
|
||||
if (dialog === null) {
|
||||
createDialog();
|
||||
} else {
|
||||
searchResults.editableList('empty');
|
||||
}
|
||||
dialog.slideDown(300);
|
||||
searchInput.searchBox('value',v)
|
||||
if (!v || v === "") {
|
||||
populateSearchHistory();
|
||||
}
|
||||
RED.events.emit("search:open");
|
||||
visible = true;
|
||||
}
|
||||
|
||||
@@ -27,5 +27,7 @@ RED.state = {
|
||||
PANNING: 10,
|
||||
SELECTING_NODE: 11,
|
||||
GROUP_DRAGGING: 12,
|
||||
GROUP_RESIZE: 13
|
||||
GROUP_RESIZE: 13,
|
||||
DETACHED_DRAGGING: 14,
|
||||
SLICING: 15
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ RED.sidebar.help = (function() {
|
||||
var currentVersionParts = RED.settings.version.split(".");
|
||||
var tourVersionParts = tour.version.split(".");
|
||||
if (tourVersionParts[0] === currentVersionParts[0] && tourVersionParts[1] === currentVersionParts[1]) {
|
||||
tourHeader = '<div><button type="button" onclick="RED.actions.invoke(\'core:show-welcome-tour\')" class="red-ui-button">Take a tour</button></div>'
|
||||
tourHeader = '<div><button type="button" onclick="RED.actions.invoke(\'core:show-welcome-tour\')" class="red-ui-button">' + RED._("tourGuide.takeATour") + '</button></div>';
|
||||
}
|
||||
}
|
||||
var aboutHeader = '<div style="text-align:center;">'+tourHeader+'</div>'
|
||||
|
||||
@@ -175,6 +175,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
n.d = true;
|
||||
}
|
||||
n.dirty = true;
|
||||
n.dirtyStatus = true;
|
||||
n.changed = true;
|
||||
RED.events.emit("nodes:change",n);
|
||||
groupHistoryEvent.events.push(historyEvent);
|
||||
@@ -203,6 +204,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
n.d = true;
|
||||
}
|
||||
n.dirty = true;
|
||||
n.dirtyStatus = true;
|
||||
n.changed = true;
|
||||
RED.events.emit("nodes:change",n);
|
||||
RED.history.push(historyEvent);
|
||||
@@ -272,6 +274,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
{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"},
|
||||
]
|
||||
});
|
||||
|
||||
@@ -563,7 +566,7 @@ RED.sidebar.info.outliner = (function() {
|
||||
}
|
||||
}
|
||||
function getGutter(n) {
|
||||
var span = $("<span>",{class:"red-ui-info-outline-gutter"});
|
||||
var span = $("<span>",{class:"red-ui-info-outline-gutter red-ui-treeList-gutter-float"});
|
||||
var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
@@ -364,6 +364,8 @@ RED.tourGuide = (function() {
|
||||
if (step.fallback) {
|
||||
focus.one("mouseenter", function(evt) {
|
||||
setTimeout(function() {
|
||||
var pos = targetElement[0].getBoundingClientRect();
|
||||
var dimension = Math.max(50, Math.max(pos.width,pos.height)*1.5);
|
||||
focus.css({
|
||||
width: (4*dimension)+"px",
|
||||
height: (4*dimension)+"px"
|
||||
|
||||
@@ -142,6 +142,8 @@ RED.utils = (function() {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>').text('function');
|
||||
} else if (value.hasOwnProperty('type') && (value.type === 'number' || value.type === 'bigint')) {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>').text(value.data);
|
||||
} else if (value.hasOwnProperty('type') && value.type === 'regexp') {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-string"></span>').text(value.data);
|
||||
} else {
|
||||
result = $('<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>');
|
||||
}
|
||||
@@ -440,6 +442,8 @@ RED.utils = (function() {
|
||||
$('<span class="red-ui-debug-msg-type-null">undefined</span>').appendTo(entryObj);
|
||||
} else if (obj.__enc__ && (obj.type === 'number' || obj.type === 'bigint')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>').text(obj.data).appendTo(entryObj);
|
||||
} else if (typeHint === "regexp" || (obj.__enc__ && obj.type === 'regexp')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>').text((typeof obj === "string")?obj:obj.data).appendTo(entryObj);
|
||||
} else if (typeHint === "function" || (obj.__enc__ && obj.type === 'function')) {
|
||||
e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("function").appendTo(entryObj);
|
||||
} else if (typeHint === "internal" || (obj.__enc__ && obj.type === 'internal')) {
|
||||
|
||||
@@ -725,6 +725,90 @@ RED.view.tools = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function wireSeriesOfNodes() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length > 1) {
|
||||
var i = 0;
|
||||
var newLinks = [];
|
||||
while (i < selection.nodes.length - 1) {
|
||||
var nodeA = selection.nodes[i];
|
||||
var nodeB = selection.nodes[i+1];
|
||||
if (nodeA.outputs > 0 && nodeB.inputs > 0) {
|
||||
var existingLinks = RED.nodes.filterLinks({
|
||||
source: nodeA,
|
||||
target: nodeB,
|
||||
sourcePort: 0
|
||||
})
|
||||
if (existingLinks.length === 0) {
|
||||
var newLink = {
|
||||
source: nodeA,
|
||||
target: nodeB,
|
||||
sourcePort: 0
|
||||
}
|
||||
RED.nodes.addLink(newLink);
|
||||
newLinks.push(newLink);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (newLinks.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'add',
|
||||
links: newLinks,
|
||||
dirty: RED.nodes.dirty()
|
||||
})
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function wireNodeToMultiple() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length > 1) {
|
||||
var sourceNode = selection.nodes[0];
|
||||
if (sourceNode.outputs === 0) {
|
||||
return;
|
||||
}
|
||||
var i = 1;
|
||||
var newLinks = [];
|
||||
while (i < selection.nodes.length) {
|
||||
var targetNode = selection.nodes[i];
|
||||
if (targetNode.inputs > 0) {
|
||||
var existingLinks = RED.nodes.filterLinks({
|
||||
source: sourceNode,
|
||||
target: targetNode,
|
||||
sourcePort: Math.min(sourceNode.outputs-1,i-1)
|
||||
})
|
||||
if (existingLinks.length === 0) {
|
||||
var newLink = {
|
||||
source: sourceNode,
|
||||
target: targetNode,
|
||||
sourcePort: Math.min(sourceNode.outputs-1,i-1)
|
||||
}
|
||||
RED.nodes.addLink(newLink);
|
||||
newLinks.push(newLink);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (newLinks.length > 0) {
|
||||
RED.history.push({
|
||||
t: 'add',
|
||||
links: newLinks,
|
||||
dirty: RED.nodes.dirty()
|
||||
})
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
||||
@@ -783,7 +867,8 @@ RED.view.tools = (function() {
|
||||
RED.actions.add("core:distribute-selection-horizontally", function() { distributeSelection('h') })
|
||||
RED.actions.add("core:distribute-selection-vertically", function() { distributeSelection('v') })
|
||||
|
||||
|
||||
RED.actions.add("core:wire-series-of-nodes", function() { wireSeriesOfNodes() })
|
||||
RED.actions.add("core:wire-node-to-multiple", function() { wireNodeToMultiple() })
|
||||
|
||||
// RED.actions.add("core:add-node", function() { addNode() })
|
||||
},
|
||||
|
||||
@@ -37,6 +37,8 @@ RED.view = (function() {
|
||||
node_height = 30,
|
||||
dblClickInterval = 650;
|
||||
|
||||
var ARROW_HEADS = false;
|
||||
|
||||
var touchLongPressTimeout = 1000,
|
||||
startTouchDistance = 0,
|
||||
startTouchCenter = [],
|
||||
@@ -63,7 +65,6 @@ RED.view = (function() {
|
||||
var activeGroups = [];
|
||||
var dirtyGroups = {};
|
||||
|
||||
var selected_link = null;
|
||||
var mousedown_link = null;
|
||||
var mousedown_node = null;
|
||||
var mousedown_group = null;
|
||||
@@ -75,6 +76,8 @@ RED.view = (function() {
|
||||
var mouse_mode = 0;
|
||||
var mousedown_group_handle = null;
|
||||
var lasso = null;
|
||||
var slicePath = null;
|
||||
var slicePathLast = null;
|
||||
var ghostNode = null;
|
||||
var showStatus = false;
|
||||
var lastClickNode = null;
|
||||
@@ -129,6 +132,14 @@ RED.view = (function() {
|
||||
if (!setIds.has(node.id)) {
|
||||
set.push({n:node});
|
||||
setIds.add(node.id);
|
||||
var links = RED.nodes.getNodeLinks(node.id,PORT_TYPE_INPUT).concat(RED.nodes.getNodeLinks(node.id,PORT_TYPE_OUTPUT))
|
||||
for (var i=0,l=links.length;i<l;i++) {
|
||||
var link = links[i]
|
||||
if (link.source === node && setIds.has(link.target.id) ||
|
||||
link.target === node && setIds.has(link.source.id)) {
|
||||
selectedLinks.add(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -145,6 +156,10 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
var links = RED.nodes.getNodeLinks(node.id,PORT_TYPE_INPUT).concat(RED.nodes.getNodeLinks(node.id,PORT_TYPE_OUTPUT))
|
||||
for (var i=0,l=links.length;i<l;i++) {
|
||||
selectedLinks.remove(links[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
clear: function() {
|
||||
@@ -159,6 +174,31 @@ RED.view = (function() {
|
||||
return api;
|
||||
})();
|
||||
|
||||
var selectedLinks = (function() {
|
||||
var links = new Set();
|
||||
return {
|
||||
add: function(link) {
|
||||
links.add(link);
|
||||
link.selected = true;
|
||||
},
|
||||
remove: function(link) {
|
||||
links.delete(link);
|
||||
link.selected = false;
|
||||
},
|
||||
clear: function() {
|
||||
links.forEach(function(link) { link.selected = false })
|
||||
links.clear();
|
||||
},
|
||||
length: function() {
|
||||
return links.size;
|
||||
},
|
||||
forEach: function(func) { links.forEach(func) },
|
||||
has: function(link) { return links.has(link) },
|
||||
toArray: function() { return Array.from(links) }
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
function init() {
|
||||
|
||||
chart = $("#red-ui-workspace-chart");
|
||||
@@ -193,6 +233,12 @@ RED.view = (function() {
|
||||
}
|
||||
} else if (mouse_mode === RED.state.PANNING && d3.event.buttons !== 4) {
|
||||
resetMouseVars();
|
||||
} else if (slicePath) {
|
||||
if (d3.event.buttons !== 2) {
|
||||
slicePath.remove();
|
||||
slicePath = null;
|
||||
resetMouseVars()
|
||||
}
|
||||
}
|
||||
})
|
||||
.on("touchend", function() {
|
||||
@@ -412,26 +458,56 @@ RED.view = (function() {
|
||||
var historyEvent = result.historyEvent;
|
||||
var nn = result.node;
|
||||
|
||||
RED.nodes.add(nn);
|
||||
|
||||
var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label");
|
||||
if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
|
||||
nn.l = showLabel;
|
||||
}
|
||||
|
||||
var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0));
|
||||
var helperWidth = ui.helper.width();
|
||||
var helperHeight = ui.helper.height();
|
||||
var mousePos = d3.touches(this)[0]||d3.mouse(this);
|
||||
|
||||
mousePos[1] += this.scrollTop + ((nn.h/2)-helperOffset[1]);
|
||||
mousePos[0] += this.scrollLeft + ((nn.w/2)-helperOffset[0]);
|
||||
try {
|
||||
var isLink = (nn.type === "link in" || nn.type === "link out")
|
||||
var hideLabel = nn.hasOwnProperty('l')?!nn.l : isLink;
|
||||
|
||||
var label = RED.utils.getNodeLabel(nn, nn.type);
|
||||
var labelParts = getLabelParts(label, "red-ui-flow-node-label");
|
||||
if (hideLabel) {
|
||||
nn.w = node_height;
|
||||
nn.h = Math.max(node_height,(nn.outputs || 0) * 15);
|
||||
} else {
|
||||
nn.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(nn._def.inputs>0?7:0))/20)) );
|
||||
nn.h = Math.max(6+24*labelParts.lines.length,(nn.outputs || 0) * 15, 30);
|
||||
}
|
||||
} catch(err) {
|
||||
}
|
||||
|
||||
mousePos[1] += this.scrollTop + ((helperHeight/2)-helperOffset[1]);
|
||||
mousePos[0] += this.scrollLeft + ((helperWidth/2)-helperOffset[0]);
|
||||
mousePos[1] /= scaleFactor;
|
||||
mousePos[0] /= scaleFactor;
|
||||
|
||||
if (snapGrid) {
|
||||
mousePos[0] = gridSize*(Math.ceil(mousePos[0]/gridSize));
|
||||
mousePos[1] = gridSize*(Math.ceil(mousePos[1]/gridSize));
|
||||
}
|
||||
nn.x = mousePos[0];
|
||||
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 spliceLink = $(ui.helper).data("splice");
|
||||
if (spliceLink) {
|
||||
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp/showQuickAddDialog
|
||||
@@ -452,7 +528,6 @@ RED.view = (function() {
|
||||
historyEvent.removedLinks = [spliceLink];
|
||||
}
|
||||
|
||||
RED.nodes.add(nn);
|
||||
|
||||
var group = $(ui.helper).data("group");
|
||||
if (group) {
|
||||
@@ -502,6 +577,8 @@ RED.view = (function() {
|
||||
RED.actions.add("core:cut-selection-to-internal-clipboard",function(){copySelection();deleteSelection();});
|
||||
RED.actions.add("core:paste-from-internal-clipboard",function(){importNodes(clipboard,{generateIds: true});});
|
||||
|
||||
RED.actions.add("core:detach-selected-nodes", function() { detachSelectedNodes() })
|
||||
|
||||
RED.events.on("view:selection-changed", function(selection) {
|
||||
var hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||
var hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||
@@ -524,6 +601,7 @@ RED.view = (function() {
|
||||
})
|
||||
|
||||
RED.actions.add("core:delete-selection",deleteSelection);
|
||||
RED.actions.add("core:delete-selection-and-reconnect",function() { deleteSelection(true) });
|
||||
RED.actions.add("core:edit-selected-node",editSelection);
|
||||
RED.actions.add("core:go-to-selection",function() {
|
||||
if (movingSet.length() > 0) {
|
||||
@@ -759,8 +837,9 @@ RED.view = (function() {
|
||||
} else {
|
||||
scale = 0.4-0.2*(Math.max(0,(node_width-Math.min(Math.abs(dx),Math.abs(dy)))/node_width));
|
||||
}
|
||||
var result;
|
||||
if (dx*sc > 0) {
|
||||
return "M "+origX+" "+origY+
|
||||
result = "M "+origX+" "+origY+
|
||||
" C "+(origX+sc*(node_width*scale))+" "+(origY+scaleY*node_height)+" "+
|
||||
(destX-sc*(scale)*node_width)+" "+(destY-scaleY*node_height)+" "+
|
||||
destX+" "+destY
|
||||
@@ -801,7 +880,7 @@ RED.view = (function() {
|
||||
}
|
||||
cp[2][0] = topX;
|
||||
}
|
||||
return "M "+origX+" "+origY+
|
||||
result = "M "+origX+" "+origY+
|
||||
" C "+
|
||||
cp[0][0]+" "+cp[0][1]+" "+
|
||||
cp[1][0]+" "+cp[1][1]+" "+
|
||||
@@ -816,6 +895,7 @@ RED.view = (function() {
|
||||
cp[4][0]+" "+cp[4][1]+" "+
|
||||
destX+" "+destY
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function addNode(type,x,y) {
|
||||
@@ -909,7 +989,7 @@ RED.view = (function() {
|
||||
return;
|
||||
}
|
||||
if (!mousedown_node && !mousedown_link && !mousedown_group) {
|
||||
selected_link = null;
|
||||
selectedLinks.clear();
|
||||
updateSelection();
|
||||
}
|
||||
if (mouse_mode === 0) {
|
||||
@@ -918,19 +998,18 @@ RED.view = (function() {
|
||||
lasso = null;
|
||||
}
|
||||
}
|
||||
if (mouse_mode === 0 || mouse_mode === RED.state.QUICK_JOINING) {
|
||||
if (d3.event.metaKey || d3.event.ctrlKey) {
|
||||
d3.event.stopPropagation();
|
||||
clearSelection();
|
||||
point = d3.mouse(this);
|
||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||
if (drag_lines.length > 0) {
|
||||
clickedGroup = clickedGroup || RED.nodes.group(drag_lines[0].node.g)
|
||||
}
|
||||
showQuickAddDialog({position:point, group:clickedGroup});
|
||||
if ((mouse_mode === 0 || mouse_mode === RED.state.QUICK_JOINING) && (d3.event.touches || d3.event.button === 0) && (d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
// Trigger quick add dialog
|
||||
d3.event.stopPropagation();
|
||||
clearSelection();
|
||||
point = d3.mouse(this);
|
||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||
if (drag_lines.length > 0) {
|
||||
clickedGroup = clickedGroup || RED.nodes.group(drag_lines[0].node.g)
|
||||
}
|
||||
}
|
||||
if (mouse_mode === 0 && !(d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
showQuickAddDialog({position:point, group:clickedGroup});
|
||||
} else if (mouse_mode === 0 && (d3.event.touches || d3.event.button === 0) && !(d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
// Tigger lasso
|
||||
if (!touchStartTime) {
|
||||
point = d3.mouse(this);
|
||||
lasso = eventLayer.append("rect")
|
||||
@@ -945,6 +1024,13 @@ 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)) {
|
||||
clearSelection();
|
||||
mouse_mode = RED.state.SLICING;
|
||||
point = d3.mouse(this);
|
||||
slicePath = eventLayer.append("path").attr("class","nr-ui-view-slice").attr("d",`M${point[0]} ${point[1]}`)
|
||||
slicePathLast = point;
|
||||
RED.view.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1341,6 +1427,17 @@ RED.view = (function() {
|
||||
.attr("height",h)
|
||||
;
|
||||
return;
|
||||
} else if (mouse_mode === RED.state.SLICING) {
|
||||
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) {
|
||||
var currentPath = slicePath.attr("d")
|
||||
currentPath += " L"+mouse_position[0]+" "+mouse_position[1]
|
||||
slicePath.attr("d",currentPath);
|
||||
slicePathLast = mouse_position
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
@@ -1348,7 +1445,7 @@ RED.view = (function() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && !mousedown_group && selected_link == null) {
|
||||
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && mouse_mode != RED.state.DETACHED_DRAGGING && !mousedown_node && !mousedown_group && selectedLinks.length() === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1372,16 +1469,18 @@ RED.view = (function() {
|
||||
// Get all the wires we need to detach.
|
||||
var links = [];
|
||||
var existingLinks = [];
|
||||
if (selected_link &&
|
||||
((mousedown_port_type === PORT_TYPE_OUTPUT &&
|
||||
selected_link.source === mousedown_node &&
|
||||
selected_link.sourcePort === mousedown_port_index
|
||||
) ||
|
||||
(mousedown_port_type === PORT_TYPE_INPUT &&
|
||||
selected_link.target === mousedown_node
|
||||
))
|
||||
) {
|
||||
existingLinks = [selected_link];
|
||||
if (selectedLinks.length() > 0) {
|
||||
selectedLinks.forEach(function(link) {
|
||||
if (((mousedown_port_type === PORT_TYPE_OUTPUT &&
|
||||
link.source === mousedown_node &&
|
||||
link.sourcePort === mousedown_port_index
|
||||
) ||
|
||||
(mousedown_port_type === PORT_TYPE_INPUT &&
|
||||
link.target === mousedown_node
|
||||
))) {
|
||||
existingLinks.push(link);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
var filter;
|
||||
if (mousedown_port_type === PORT_TYPE_OUTPUT) {
|
||||
@@ -1419,7 +1518,7 @@ RED.view = (function() {
|
||||
} else if (mousedown_node && !quickAddLink) {
|
||||
showDragLines([{node:mousedown_node,port:mousedown_port_index,portType:mousedown_port_type}]);
|
||||
}
|
||||
selected_link = null;
|
||||
selectedLinks.clear();
|
||||
}
|
||||
mousePos = mouse_position;
|
||||
for (i=0;i<drag_lines.length;i++) {
|
||||
@@ -1451,7 +1550,7 @@ RED.view = (function() {
|
||||
RED.nodes.filterLinks({ target: node.n }).length === 0;
|
||||
}
|
||||
}
|
||||
} else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING) {
|
||||
} else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING || mouse_mode == RED.state.DETACHED_DRAGGING) {
|
||||
mousePos = mouse_position;
|
||||
var minX = 0;
|
||||
var minY = 0;
|
||||
@@ -1515,8 +1614,16 @@ 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 {
|
||||
gridOffset[0] = node.n.x-(gridSize*Math.floor((node.n.x-node.n.w/2)/gridSize)+node.n.w/2);
|
||||
gridOffset[1] = node.n.y-(gridSize*Math.floor(node.n.y/gridSize));
|
||||
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);
|
||||
}
|
||||
if (gridOffset[0] !== 0 || gridOffset[1] !== 0) {
|
||||
for (i = 0; i<movingSet.length(); i++) {
|
||||
@@ -1736,6 +1843,11 @@ RED.view = (function() {
|
||||
} else if (mouse_mode == RED.state.DEFAULT && mousedown_link == null && !d3.event.ctrlKey && !d3.event.metaKey ) {
|
||||
clearSelection();
|
||||
updateSelection();
|
||||
} else if (slicePath) {
|
||||
deleteSelection();
|
||||
slicePath.remove();
|
||||
slicePath = null;
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
if (movingSet.length() > 0) {
|
||||
@@ -1807,10 +1919,30 @@ RED.view = (function() {
|
||||
// movingSet.add(mousedown_node);
|
||||
// }
|
||||
// }
|
||||
if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.DETACHED_DRAGGING) {
|
||||
// if (mousedown_node) {
|
||||
// delete mousedown_node.gSelected;
|
||||
// }
|
||||
if (mouse_mode === RED.state.DETACHED_DRAGGING) {
|
||||
var ns = [];
|
||||
for (var j=0;j<movingSet.length();j++) {
|
||||
var n = movingSet.get(j);
|
||||
if (n.ox !== n.n.x || n.oy !== n.n.y) {
|
||||
ns.push({n:n.n,ox:n.ox,oy:n.oy,moved:n.n.moved});
|
||||
n.n.dirty = true;
|
||||
n.n.moved = true;
|
||||
}
|
||||
}
|
||||
var detachEvent = RED.history.peek();
|
||||
// The last event in the stack *should* be a multi-event from
|
||||
// where the links were added/removed
|
||||
var historyEvent = {t:"move",nodes:ns,dirty:RED.nodes.dirty()}
|
||||
if (detachEvent.t === "multi") {
|
||||
detachEvent.events.push(historyEvent)
|
||||
} else {
|
||||
RED.history.push(historyEvent)
|
||||
}
|
||||
}
|
||||
for (i=0;i<movingSet.length();i++) {
|
||||
var node = movingSet.get(i);
|
||||
delete node.ox;
|
||||
@@ -1855,10 +1987,29 @@ RED.view = (function() {
|
||||
if (mouse_mode === RED.state.MOVING || mouse_mode === RED.state.MOVING_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
if (mouse_mode === RED.state.IMPORT_DRAGGING) {
|
||||
if (mouse_mode === RED.state.DETACHED_DRAGGING) {
|
||||
for (var j=0;j<movingSet.length();j++) {
|
||||
var n = movingSet.get(j);
|
||||
n.n.x = n.ox;
|
||||
n.n.y = n.oy;
|
||||
}
|
||||
clearSelection();
|
||||
RED.history.pop();
|
||||
mouse_mode = 0;
|
||||
} else if (mouse_mode === RED.state.IMPORT_DRAGGING) {
|
||||
clearSelection();
|
||||
RED.history.pop();
|
||||
mouse_mode = 0;
|
||||
} else if (mouse_mode === RED.state.SLICING) {
|
||||
if (slicePath) {
|
||||
slicePath.remove();
|
||||
slicePath = null;
|
||||
resetMouseVars()
|
||||
}
|
||||
clearSelection();
|
||||
} else if (lasso) {
|
||||
lasso.remove();
|
||||
lasso = null;
|
||||
} else if (activeGroup) {
|
||||
exitActiveGroup()
|
||||
} else {
|
||||
@@ -1870,6 +2021,7 @@ RED.view = (function() {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE && selectNodesOptions.single) {
|
||||
return;
|
||||
}
|
||||
selectedLinks.clear();
|
||||
|
||||
if (activeGroup) {
|
||||
var ag = activeGroup;
|
||||
@@ -1941,7 +2093,6 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
selected_link = null;
|
||||
if (mouse_mode !== RED.state.SELECTING_NODE) {
|
||||
updateSelection();
|
||||
}
|
||||
@@ -1956,7 +2107,7 @@ RED.view = (function() {
|
||||
n.n.selected = false;
|
||||
}
|
||||
movingSet.clear();
|
||||
selected_link = null;
|
||||
selectedLinks.clear();
|
||||
if (activeGroup) {
|
||||
activeGroup.active = false
|
||||
activeGroup.dirty = true;
|
||||
@@ -2050,12 +2201,16 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activeFlowLinks.length === 0 && selected_link !== null && selected_link.link) {
|
||||
activeLinks.push(selected_link);
|
||||
activeLinkNodes[selected_link.source.id] = selected_link.source;
|
||||
selected_link.source.dirty = true;
|
||||
activeLinkNodes[selected_link.target.id] = selected_link.target;
|
||||
selected_link.target.dirty = true;
|
||||
if (activeFlowLinks.length === 0 && selectedLinks.length() > 0) {
|
||||
selectedLinks.forEach(function(link) {
|
||||
if (link.link) {
|
||||
activeLinks.push(link);
|
||||
activeLinkNodes[link.source.id] = link.source;
|
||||
link.source.dirty = true;
|
||||
activeLinkNodes[link.target.id] = link.target;
|
||||
link.target.dirty = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
selection.flows = workspaceSelection;
|
||||
@@ -2066,6 +2221,10 @@ RED.view = (function() {
|
||||
return value.map(function(n) { return n.id })
|
||||
} else if (key === 'link') {
|
||||
return value.source.id+":"+value.sourcePort+":"+value.target.id;
|
||||
} else if (key === 'links') {
|
||||
return value.map(function(link) {
|
||||
return link.source.id+":"+link.sourcePort+":"+link.target.id;
|
||||
});
|
||||
}
|
||||
return value;
|
||||
});
|
||||
@@ -2087,7 +2246,7 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
function deleteSelection() {
|
||||
function deleteSelection(reconnectWires) {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
return;
|
||||
}
|
||||
@@ -2135,7 +2294,7 @@ RED.view = (function() {
|
||||
updateActiveNodes();
|
||||
updateSelection();
|
||||
redraw();
|
||||
} else if (movingSet.length() > 0 || selected_link != null) {
|
||||
} else if (movingSet.length() > 0 || selectedLinks.length() > 0) {
|
||||
var result;
|
||||
var node;
|
||||
var removedNodes = [];
|
||||
@@ -2145,6 +2304,16 @@ RED.view = (function() {
|
||||
var removedSubflowInputs = [];
|
||||
var removedSubflowStatus;
|
||||
var subflowInstances = [];
|
||||
var historyEvents = [];
|
||||
|
||||
if (reconnectWires) {
|
||||
var reconnectResult = RED.nodes.detachNodes(movingSet.nodes())
|
||||
var addedLinks = reconnectResult.newLinks;
|
||||
if (addedLinks.length > 0) {
|
||||
historyEvents.push({ t:'add', links: addedLinks })
|
||||
}
|
||||
removedLinks = removedLinks.concat(reconnectResult.removedLinks)
|
||||
}
|
||||
|
||||
var startDirty = RED.nodes.dirty();
|
||||
var startChanged = false;
|
||||
@@ -2234,71 +2403,71 @@ RED.view = (function() {
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
var historyEvent;
|
||||
|
||||
if (selected_link && selected_link.link) {
|
||||
var sourceId = selected_link.source.id;
|
||||
var targetId = selected_link.target.id;
|
||||
var sourceIdIndex = selected_link.target.links.indexOf(sourceId);
|
||||
var targetIdIndex = selected_link.source.links.indexOf(targetId);
|
||||
|
||||
historyEvent = {
|
||||
t:"multi",
|
||||
events: [
|
||||
{
|
||||
if (selectedLinks.length() > 0) {
|
||||
selectedLinks.forEach(function(link) {
|
||||
if (link.link) {
|
||||
var sourceId = link.source.id;
|
||||
var targetId = link.target.id;
|
||||
var sourceIdIndex = link.target.links.indexOf(sourceId);
|
||||
var targetIdIndex = link.source.links.indexOf(targetId);
|
||||
historyEvents.push({
|
||||
t: "edit",
|
||||
node: selected_link.source,
|
||||
changed: selected_link.source.changed,
|
||||
node: link.source,
|
||||
changed: link.source.changed,
|
||||
changes: {
|
||||
links: $.extend(true,{},{v:selected_link.source.links}).v
|
||||
links: $.extend(true,{},{v:link.source.links}).v
|
||||
}
|
||||
},
|
||||
{
|
||||
})
|
||||
historyEvents.push({
|
||||
t: "edit",
|
||||
node: selected_link.target,
|
||||
changed: selected_link.target.changed,
|
||||
node: link.target,
|
||||
changed: link.target.changed,
|
||||
changes: {
|
||||
links: $.extend(true,{},{v:selected_link.target.links}).v
|
||||
links: $.extend(true,{},{v:link.target.links}).v
|
||||
}
|
||||
}
|
||||
})
|
||||
link.source.changed = true;
|
||||
link.target.changed = true;
|
||||
link.target.links.splice(sourceIdIndex,1);
|
||||
link.source.links.splice(targetIdIndex,1);
|
||||
link.source.dirty = true;
|
||||
link.target.dirty = true;
|
||||
|
||||
],
|
||||
dirty:RED.nodes.dirty()
|
||||
}
|
||||
RED.nodes.dirty(true);
|
||||
selected_link.source.changed = true;
|
||||
selected_link.target.changed = true;
|
||||
selected_link.target.links.splice(sourceIdIndex,1);
|
||||
selected_link.source.links.splice(targetIdIndex,1);
|
||||
selected_link.source.dirty = true;
|
||||
selected_link.target.dirty = true;
|
||||
|
||||
} else {
|
||||
if (selected_link) {
|
||||
RED.nodes.removeLink(selected_link);
|
||||
removedLinks.push(selected_link);
|
||||
}
|
||||
RED.nodes.dirty(true);
|
||||
historyEvent = {
|
||||
t:"delete",
|
||||
nodes:removedNodes,
|
||||
links:removedLinks,
|
||||
groups: removedGroups,
|
||||
subflowOutputs:removedSubflowOutputs,
|
||||
subflowInputs:removedSubflowInputs,
|
||||
subflow: {
|
||||
id: activeSubflow?activeSubflow.id:undefined,
|
||||
instances: subflowInstances
|
||||
},
|
||||
dirty:startDirty
|
||||
};
|
||||
if (removedSubflowStatus) {
|
||||
historyEvent.subflow.status = removedSubflowStatus;
|
||||
}
|
||||
} else {
|
||||
RED.nodes.removeLink(link);
|
||||
removedLinks.push(link);
|
||||
}
|
||||
})
|
||||
}
|
||||
RED.nodes.dirty(true);
|
||||
var historyEvent = {
|
||||
t:"delete",
|
||||
nodes:removedNodes,
|
||||
links:removedLinks,
|
||||
groups: removedGroups,
|
||||
subflowOutputs:removedSubflowOutputs,
|
||||
subflowInputs:removedSubflowInputs,
|
||||
subflow: {
|
||||
id: activeSubflow?activeSubflow.id:undefined,
|
||||
instances: subflowInstances
|
||||
},
|
||||
dirty:startDirty
|
||||
};
|
||||
if (removedSubflowStatus) {
|
||||
historyEvent.subflow.status = removedSubflowStatus;
|
||||
}
|
||||
if (historyEvents.length > 0) {
|
||||
historyEvents.unshift(historyEvent);
|
||||
RED.history.push({
|
||||
t:"multi",
|
||||
events: historyEvents
|
||||
})
|
||||
} else {
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
selected_link = null;
|
||||
selectedLinks.clear();
|
||||
updateActiveNodes();
|
||||
updateSelection();
|
||||
redraw();
|
||||
@@ -2375,6 +2544,28 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function detachSelectedNodes() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
const {newLinks, removedLinks} = RED.nodes.detachNodes(selection.nodes);
|
||||
if (removedLinks.length || newLinks.length) {
|
||||
RED.history.push({
|
||||
t: "multi",
|
||||
events: [
|
||||
{ t:'delete', links: removedLinks },
|
||||
{ t:'add', links: newLinks }
|
||||
],
|
||||
dirty: RED.nodes.dirty()
|
||||
})
|
||||
RED.nodes.dirty(true)
|
||||
}
|
||||
prepareDrag([selection.nodes[0].x,selection.nodes[0].y]);
|
||||
mouse_mode = RED.state.DETACHED_DRAGGING;
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateTextWidth(str, className) {
|
||||
var result = convertLineBreakCharacter(str);
|
||||
var width = 0;
|
||||
@@ -2461,7 +2652,7 @@ RED.view = (function() {
|
||||
activeHoverGroup.hovered = false;
|
||||
activeHoverGroup = null;
|
||||
}
|
||||
d3.select(".red-ui-flow-link-splice").classed("red-ui-flow-link-splice",false);
|
||||
d3.selectAll(".red-ui-flow-link-splice").classed("red-ui-flow-link-splice",false);
|
||||
if (spliceTimer) {
|
||||
clearTimeout(spliceTimer);
|
||||
spliceTimer = null;
|
||||
@@ -2709,10 +2900,13 @@ RED.view = (function() {
|
||||
} else {
|
||||
resetMouseVars();
|
||||
}
|
||||
selected_link = select_link;
|
||||
mousedown_link = select_link;
|
||||
if (select_link) {
|
||||
selectedLinks.clear();
|
||||
selectedLinks.add(select_link);
|
||||
updateSelection();
|
||||
} else {
|
||||
selectedLinks.clear();
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
@@ -2721,7 +2915,10 @@ RED.view = (function() {
|
||||
|
||||
resetMouseVars();
|
||||
hideDragLines();
|
||||
selected_link = select_link;
|
||||
if (select_link) {
|
||||
selectedLinks.clear();
|
||||
selectedLinks.add(select_link);
|
||||
}
|
||||
mousedown_link = select_link;
|
||||
if (select_link) {
|
||||
updateSelection();
|
||||
@@ -2894,10 +3091,13 @@ RED.view = (function() {
|
||||
msn.dx = msn.n.x-mouse[0];
|
||||
msn.dy = msn.n.y-mouse[1];
|
||||
}
|
||||
|
||||
mouse_offset = d3.mouse(document.body);
|
||||
if (isNaN(mouse_offset[0])) {
|
||||
mouse_offset = d3.touches(document.body)[0];
|
||||
try {
|
||||
mouse_offset = d3.mouse(document.body);
|
||||
if (isNaN(mouse_offset[0])) {
|
||||
mouse_offset = d3.touches(document.body)[0];
|
||||
}
|
||||
} catch(err) {
|
||||
mouse_offset = [0,0]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2978,7 +3178,7 @@ RED.view = (function() {
|
||||
//var touch0 = d3.event;
|
||||
//var pos = [touch0.pageX,touch0.pageY];
|
||||
//RED.touch.radialMenu.show(d3.select(this),pos);
|
||||
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
|
||||
if (mouse_mode == RED.state.IMPORT_DRAGGING || mouse_mode == RED.state.DETACHED_DRAGGING) {
|
||||
var historyEvent = RED.history.peek();
|
||||
if (activeSpliceLink) {
|
||||
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
|
||||
@@ -3016,6 +3216,18 @@ RED.view = (function() {
|
||||
activeHoverGroup = null;
|
||||
}
|
||||
|
||||
if (mouse_mode == RED.state.DETACHED_DRAGGING) {
|
||||
var ns = [];
|
||||
for (var j=0;j<movingSet.length();j++) {
|
||||
var n = movingSet.get(j);
|
||||
if (n.ox !== n.n.x || n.oy !== n.n.y) {
|
||||
ns.push({n:n.n,ox:n.ox,oy:n.oy,moved:n.n.moved});
|
||||
n.n.dirty = true;
|
||||
n.n.moved = true;
|
||||
}
|
||||
}
|
||||
RED.history.replace({t:"multi",events:[historyEvent,{t:"move",nodes:ns}],dirty: historyEvent.dirty})
|
||||
}
|
||||
|
||||
updateSelection();
|
||||
RED.nodes.dirty(true);
|
||||
@@ -3184,7 +3396,9 @@ RED.view = (function() {
|
||||
// }
|
||||
// } else
|
||||
if (d3.event.shiftKey) {
|
||||
clearSelection();
|
||||
if (!(d3.event.ctrlKey||d3.event.metaKey)) {
|
||||
clearSelection();
|
||||
}
|
||||
var clickPosition = (d3.event.offsetX/scaleFactor - mousedown_node.x)
|
||||
var edgeDelta = (mousedown_node.w/2) - Math.abs(clickPosition);
|
||||
var cnodes;
|
||||
@@ -3212,7 +3426,7 @@ RED.view = (function() {
|
||||
mousedown_node.selected = true;
|
||||
movingSet.add(mousedown_node);
|
||||
}
|
||||
selected_link = null;
|
||||
// selectedLinks.clear();
|
||||
if (d3.event.button != 2) {
|
||||
mouse_mode = RED.state.MOVING;
|
||||
var mouse = d3.touches(this)[0]||d3.mouse(this);
|
||||
@@ -3338,19 +3552,35 @@ RED.view = (function() {
|
||||
d3.event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
mousedown_link = d;
|
||||
clearSelection();
|
||||
selected_link = mousedown_link;
|
||||
updateSelection();
|
||||
redraw();
|
||||
focusView();
|
||||
d3.event.stopPropagation();
|
||||
if (d3.event.metaKey || d3.event.ctrlKey) {
|
||||
d3.select(this).classed("red-ui-flow-link-splice",true);
|
||||
var point = d3.mouse(this);
|
||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||
showQuickAddDialog({position:point, splice:selected_link, group:clickedGroup});
|
||||
}
|
||||
if (d3.event.button === 2) {
|
||||
return
|
||||
}
|
||||
mousedown_link = d;
|
||||
|
||||
if (!(d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
clearSelection();
|
||||
}
|
||||
if (d3.event.metaKey || d3.event.ctrlKey) {
|
||||
if (!selectedLinks.has(mousedown_link)) {
|
||||
selectedLinks.add(mousedown_link);
|
||||
} else {
|
||||
if (selectedLinks.length() !== 1) {
|
||||
selectedLinks.remove(mousedown_link);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectedLinks.add(mousedown_link);
|
||||
}
|
||||
updateSelection();
|
||||
redraw();
|
||||
focusView();
|
||||
d3.event.stopPropagation();
|
||||
if (!mousedown_link.link && movingSet.length() === 0 && (d3.event.touches || d3.event.button === 0) && selectedLinks.length() === 1 && selectedLinks.has(mousedown_link) && (d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
d3.select(this).classed("red-ui-flow-link-splice",true);
|
||||
var point = d3.mouse(this);
|
||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||
showQuickAddDialog({position:point, splice:mousedown_link, group:clickedGroup});
|
||||
}
|
||||
}
|
||||
function linkTouchStart(d) {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
@@ -3359,7 +3589,8 @@ RED.view = (function() {
|
||||
}
|
||||
mousedown_link = d;
|
||||
clearSelection();
|
||||
selected_link = mousedown_link;
|
||||
selectedLinks.clear();
|
||||
selectedLinks.add(mousedown_link);
|
||||
updateSelection();
|
||||
redraw();
|
||||
focusView();
|
||||
@@ -3595,7 +3826,7 @@ RED.view = (function() {
|
||||
function showTouchMenu(obj,pos) {
|
||||
var mdn = mousedown_node;
|
||||
var options = [];
|
||||
options.push({name:"delete",disabled:(movingSet.length()===0 && selected_link === null),onselect:function() {deleteSelection();}});
|
||||
options.push({name:"delete",disabled:(movingSet.length()===0 && selectedLinks.length() === 0),onselect:function() {deleteSelection();}});
|
||||
options.push({name:"cut",disabled:(movingSet.length()===0),onselect:function() {copySelection();deleteSelection();}});
|
||||
options.push({name:"copy",disabled:(movingSet.length()===0),onselect:function() {copySelection();}});
|
||||
options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard, {generateIds: true, touchImport: true});}});
|
||||
@@ -3675,7 +3906,11 @@ RED.view = (function() {
|
||||
nodeEl = document.getElementById(d.id);
|
||||
}
|
||||
if (nodeEl) {
|
||||
if (!showStatus || !d.status) {
|
||||
// Do not show node status if:
|
||||
// - global flag set
|
||||
// - node has no status
|
||||
// - node is disabled
|
||||
if (!showStatus || !d.status || d.d === true) {
|
||||
nodeEl.__statusGroup__.style.display = "none";
|
||||
} else {
|
||||
nodeEl.__statusGroup__.style.display = "inline";
|
||||
@@ -3900,6 +4135,11 @@ RED.view = (function() {
|
||||
|
||||
}
|
||||
|
||||
node[0][0].__portGroup__ = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
node[0][0].__portGroup__.__data__ = d;
|
||||
nodeContents.appendChild(node[0][0].__portGroup__);
|
||||
|
||||
|
||||
var mainRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
mainRect.__data__ = d;
|
||||
mainRect.setAttribute("class", "red-ui-flow-node "+(d.type == "unknown"?"red-ui-flow-node-unknown":""));
|
||||
@@ -4103,7 +4343,7 @@ RED.view = (function() {
|
||||
this.__textGroup__.setAttribute("transform", "translate(38,"+yp+")");
|
||||
}
|
||||
|
||||
var inputPorts = thisNode.selectAll(".red-ui-flow-port-input");
|
||||
var inputPorts = d3.select(this.__portGroup__).selectAll(".red-ui-flow-port-input");
|
||||
if ((!isLink || (showAllLinkPorts === -1 && !activeLinkNodes[d.id])) && d.inputs === 0 && !inputPorts.empty()) {
|
||||
inputPorts.each(function(d,i) {
|
||||
RED.hooks.trigger("viewRemovePort",{
|
||||
@@ -4114,8 +4354,9 @@ RED.view = (function() {
|
||||
portIndex: 0
|
||||
})
|
||||
}).remove();
|
||||
this.__inputs__ = [];
|
||||
} else if (((isLink && (showAllLinkPorts===PORT_TYPE_INPUT||activeLinkNodes[d.id]))|| d.inputs === 1) && inputPorts.empty()) {
|
||||
var inputGroup = thisNode.append("g").attr("class","red-ui-flow-port-input");
|
||||
var inputGroup = d3.select(this.__portGroup__).append("g").attr("class","red-ui-flow-port-input");
|
||||
var inputGroupPorts;
|
||||
|
||||
if (d.type === "link in") {
|
||||
@@ -4124,7 +4365,8 @@ RED.view = (function() {
|
||||
.attr("r",5)
|
||||
.attr("class","red-ui-flow-port red-ui-flow-link-port")
|
||||
} else {
|
||||
inputGroupPorts = inputGroup.append("rect").attr("class","red-ui-flow-port").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
|
||||
inputGroupPorts = inputGroup.append("path").attr("class","red-ui-flow-port-background").attr("d","M5 -1.5 h -16 v 13 h 16 z")
|
||||
inputGroup.append("path").attr("class","red-ui-flow-port red-ui-flow-port-shape").attr("d","M5 0 h -3 c -4 0 -4 0 -4 4 v 2 c 0 4 0 4 4 4 h 3 z ")
|
||||
}
|
||||
inputGroup[0][0].__port__ = inputGroupPorts[0][0];
|
||||
inputGroupPorts[0][0].__data__ = this.__data__;
|
||||
@@ -4136,6 +4378,8 @@ RED.view = (function() {
|
||||
.on("touchend",function(d){portMouseUp(d,PORT_TYPE_INPUT,0);d3.event.preventDefault();} )
|
||||
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE_INPUT,0);})
|
||||
.on("mouseout",function(d) {portMouseOut(d3.select(this),d,PORT_TYPE_INPUT,0);});
|
||||
|
||||
this.__inputs__.push(inputGroup[0][0]);
|
||||
RED.hooks.trigger("viewAddPort",{node:d,el: this, port: inputGroup[0][0], portType: "input", portIndex: 0})
|
||||
}
|
||||
var numOutputs = d.outputs;
|
||||
@@ -4172,15 +4416,19 @@ RED.view = (function() {
|
||||
portPort.setAttribute("cy",5);
|
||||
portPort.setAttribute("r",5);
|
||||
portPort.setAttribute("class","red-ui-flow-port red-ui-flow-link-port");
|
||||
portGroup.appendChild(portPort);
|
||||
} else {
|
||||
portPort = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
portPort.setAttribute("rx",3);
|
||||
portPort.setAttribute("ry",3);
|
||||
portPort.setAttribute("width",10);
|
||||
portPort.setAttribute("height",10);
|
||||
portPort.setAttribute("class","red-ui-flow-port");
|
||||
|
||||
portPort = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
portPort.setAttribute("d","M5 -1.5 h 16 v 13 h -16 z ");
|
||||
portPort.setAttribute("class","red-ui-flow-port-background");
|
||||
portGroup.appendChild(portPort);
|
||||
|
||||
var visiblePort = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
visiblePort.setAttribute("d","M5 0 h 4 c 4 0 4 0 4 4 v 2 c 0 4 0 4 -4 4 h -4 z ");
|
||||
visiblePort.setAttribute("class","red-ui-flow-port red-ui-flow-port-shape");
|
||||
portGroup.appendChild(visiblePort);
|
||||
}
|
||||
portGroup.appendChild(portPort);
|
||||
portGroup.__port__ = portPort;
|
||||
portPort.__data__ = this.__data__;
|
||||
portPort.__portType__ = PORT_TYPE_OUTPUT;
|
||||
@@ -4192,7 +4440,7 @@ RED.view = (function() {
|
||||
portPort.addEventListener("mouseover", portMouseOverProxy);
|
||||
portPort.addEventListener("mouseout", portMouseOutProxy);
|
||||
|
||||
this.appendChild(portGroup);
|
||||
this.__portGroup__.appendChild(portGroup);
|
||||
this.__outputs__.push(portGroup);
|
||||
RED.hooks.trigger("viewAddPort",{node:d,el: this, port: portGroup, portType: "output", portIndex: portIndex})
|
||||
} else {
|
||||
@@ -4283,6 +4531,14 @@ RED.view = (function() {
|
||||
// });
|
||||
}
|
||||
|
||||
for (var i=0,l=this.__outputs__.length;i<l;i++) {
|
||||
this.__outputs__[i].classList.toggle("red-ui-flow-port-connected",RED.nodes.getNodeLinkCount(d.id,PORT_TYPE_OUTPUT,i) > 0 )
|
||||
}
|
||||
for (var i=0,l=this.__inputs__.length;i<l;i++) {
|
||||
this.__inputs__[i].classList.toggle("red-ui-flow-port-connected",RED.nodes.getNodeLinkCount(d.id,PORT_TYPE_INPUT,i) > 0 )
|
||||
}
|
||||
|
||||
|
||||
if (d.dirtyStatus) {
|
||||
redrawStatus(d,this);
|
||||
}
|
||||
@@ -4328,6 +4584,13 @@ RED.view = (function() {
|
||||
d3.select(pathBack)
|
||||
.on("mousedown",linkMouseDown)
|
||||
.on("touchstart",linkTouchStart)
|
||||
.on("mousemove", function(d) {
|
||||
if (mouse_mode === RED.state.SLICING) {
|
||||
selectedLinks.add(d)
|
||||
l.classed("red-ui-flow-link-splice",true)
|
||||
redraw()
|
||||
}
|
||||
})
|
||||
|
||||
var pathOutline = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
pathOutline.__data__ = d;
|
||||
@@ -4348,7 +4611,7 @@ RED.view = (function() {
|
||||
link.exit().remove();
|
||||
link.each(function(d) {
|
||||
var link = d3.select(this);
|
||||
if (d.added || d===selected_link || d.selected || dirtyNodes[d.source.id] || dirtyNodes[d.target.id]) {
|
||||
if (d.added || d.selected || dirtyNodes[d.source.id] || dirtyNodes[d.target.id]) {
|
||||
var numOutputs = d.source.outputs || 1;
|
||||
var sourcePort = d.sourcePort || 0;
|
||||
var y = -((numOutputs-1)/2)*13 +13*sourcePort;
|
||||
@@ -4356,22 +4619,19 @@ RED.view = (function() {
|
||||
d.y1 = d.source.y+y;
|
||||
d.x2 = d.target.x-d.target.w/2;
|
||||
d.y2 = d.target.y;
|
||||
|
||||
// return "M "+d.x1+" "+d.y1+
|
||||
// " C "+(d.x1+scale*node_width)+" "+(d.y1+scaleY*node_height)+" "+
|
||||
// (d.x2-scale*node_width)+" "+(d.y2-scaleY*node_height)+" "+
|
||||
// d.x2+" "+d.y2;
|
||||
var path = generateLinkPath(d.x1,d.y1,d.x2,d.y2,1);
|
||||
var targetOffset = ARROW_HEADS?(d.link?16:13):0
|
||||
var path = generateLinkPath(d.x1+5,d.y1,d.x2-targetOffset,d.y2,1);
|
||||
if (/NaN/.test(path)) {
|
||||
path = ""
|
||||
}
|
||||
this.__pathBack__.setAttribute("d",path);
|
||||
this.__pathOutline__.setAttribute("d",path);
|
||||
this.__pathLine__.setAttribute("d",path);
|
||||
this.__pathLine__.setAttribute("d",path + (ARROW_HEADS?"m0 0, l 0 -2 l 3 2 l -3 2 z":""));
|
||||
this.__pathLine__.classList.toggle("red-ui-flow-node-disabled",!!(d.source.d || d.target.d));
|
||||
this.__pathLine__.classList.toggle("red-ui-flow-subflow-link", !d.link && activeSubflow);
|
||||
}
|
||||
this.classList.toggle("red-ui-flow-link-selected", !!(d===selected_link||d.selected));
|
||||
|
||||
this.classList.toggle("red-ui-flow-link-selected", !!d.selected);
|
||||
|
||||
var connectedToUnknown = !!(d.target.type == "unknown" || d.source.type == "unknown");
|
||||
this.classList.toggle("red-ui-flow-link-unknown",!!(d.target.type == "unknown" || d.source.type == "unknown"))
|
||||
@@ -4421,6 +4681,9 @@ RED.view = (function() {
|
||||
n.selected = true;
|
||||
n.dirty = true;
|
||||
movingSet.add(n);
|
||||
if (targets.length === 1) {
|
||||
RED.view.reveal(n.id);
|
||||
}
|
||||
});
|
||||
updateSelection();
|
||||
redraw();
|
||||
@@ -4957,7 +5220,7 @@ RED.view = (function() {
|
||||
counts.push(RED._("clipboard.group",{count:newGroupCount}));
|
||||
}
|
||||
if (newConfigNodeCount > 0) {
|
||||
counts.push(RED._("clipboard.configNode",{count:newNodeCount}));
|
||||
counts.push(RED._("clipboard.configNode",{count:newConfigNodeCount}));
|
||||
}
|
||||
if (new_subflows.length > 0) {
|
||||
counts.push(RED._("clipboard.subflow",{count:new_subflows.length}));
|
||||
@@ -5029,6 +5292,7 @@ RED.view = (function() {
|
||||
delete node.d;
|
||||
}
|
||||
node.dirty = true;
|
||||
node.dirtyStatus = true;
|
||||
node.changed = true;
|
||||
RED.events.emit("nodes:change",node);
|
||||
}
|
||||
@@ -5075,8 +5339,9 @@ RED.view = (function() {
|
||||
if (allNodes.size > 0) {
|
||||
selection.nodes = Array.from(allNodes);
|
||||
}
|
||||
if (selected_link != null) {
|
||||
selection.link = selected_link;
|
||||
if (selectedLinks.length() > 0) {
|
||||
selection.links = selectedLinks.toArray();
|
||||
selection.link = selection.links[0];
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
|
||||
@@ -208,65 +208,84 @@ RED.workspaces = (function() {
|
||||
},
|
||||
onhide: function(tab) {
|
||||
hideStack.push(tab.id);
|
||||
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
hiddenTabs[tab.id] = true;
|
||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||
|
||||
RED.events.emit("workspace:hide",{workspace: tab.id})
|
||||
},
|
||||
onshow: function(tab) {
|
||||
removeFromHideStack(tab.id);
|
||||
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
delete hiddenTabs[tab.id];
|
||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||
|
||||
RED.events.emit("workspace:show",{workspace: tab.id})
|
||||
},
|
||||
minimumActiveTabWidth: 150,
|
||||
scrollable: true,
|
||||
addButton: "core:add-flow",
|
||||
addButtonCaption: RED._("workspace.addFlow"),
|
||||
menu: [
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-flows",
|
||||
label: RED._("workspace.listFlows"),
|
||||
onselect: "core:list-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-subflows",
|
||||
label: RED._("workspace.listSubflows"),
|
||||
onselect: "core:list-subflows"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
onselect: "core:add-flow-to-right"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-flows",
|
||||
label: RED._("workspace.hideFlow"),
|
||||
onselect: "core:hide-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-other-flows",
|
||||
label: RED._("workspace.hideOtherFlows"),
|
||||
onselect: "core:hide-other-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-show-all-flows",
|
||||
label: RED._("workspace.showAllFlows"),
|
||||
onselect: "core:show-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-all-flows",
|
||||
label: RED._("workspace.hideAllFlows"),
|
||||
onselect: "core:hide-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-show-last-flow",
|
||||
label: RED._("workspace.showLastHiddenFlow"),
|
||||
onselect: "core:show-last-hidden-flow"
|
||||
menu: function() {
|
||||
var menuItems = [
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-flows",
|
||||
label: RED._("workspace.listFlows"),
|
||||
onselect: "core:list-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-search-subflows",
|
||||
label: RED._("workspace.listSubflows"),
|
||||
onselect: "core:list-subflows"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
onselect: "core:add-flow-to-right"
|
||||
},
|
||||
null,
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-flows",
|
||||
label: RED._("workspace.hideFlow"),
|
||||
onselect: "core:hide-flow"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-other-flows",
|
||||
label: RED._("workspace.hideOtherFlows"),
|
||||
onselect: "core:hide-other-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-show-all-flows",
|
||||
label: RED._("workspace.showAllFlows"),
|
||||
onselect: "core:show-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-all-flows",
|
||||
label: RED._("workspace.hideAllFlows"),
|
||||
onselect: "core:hide-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-show-last-flow",
|
||||
label: RED._("workspace.showLastHiddenFlow"),
|
||||
onselect: "core:show-last-hidden-flow"
|
||||
}
|
||||
]
|
||||
if (hideStack.length > 0) {
|
||||
menuItems.unshift({
|
||||
label: RED._("workspace.hiddenFlows",{count: hideStack.length}),
|
||||
onselect: "core:list-hidden-flows"
|
||||
})
|
||||
}
|
||||
]
|
||||
return menuItems;
|
||||
}
|
||||
});
|
||||
workspaceTabCount = 0;
|
||||
}
|
||||
@@ -406,7 +425,9 @@ RED.workspaces = (function() {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
RED.actions.add("core:list-hidden-flows",function() {
|
||||
RED.actions.invoke("core:search","is:hidden ");
|
||||
})
|
||||
RED.actions.add("core:list-flows",function() {
|
||||
RED.actions.invoke("core:search","type:tab ");
|
||||
})
|
||||
@@ -450,7 +471,7 @@ RED.workspaces = (function() {
|
||||
var changes = { disabled: workspace.disabled };
|
||||
workspace.disabled = disabled;
|
||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
|
||||
if (id || activeWorkspace) {
|
||||
if (!id || (id === activeWorkspace)) {
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
|
||||
}
|
||||
var historyEvent = {
|
||||
@@ -531,11 +552,11 @@ RED.workspaces = (function() {
|
||||
}
|
||||
if (workspace_tabs.contains(id)) {
|
||||
workspace_tabs.hideTab(id);
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
hiddenTabs[id] = true;
|
||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||
}
|
||||
},
|
||||
isHidden: function(id) {
|
||||
return hideStack.includes(id)
|
||||
},
|
||||
show: function(id,skipStack,unhideOnly) {
|
||||
if (!workspace_tabs.contains(id)) {
|
||||
var sf = RED.nodes.subflow(id);
|
||||
@@ -558,9 +579,6 @@ RED.workspaces = (function() {
|
||||
}
|
||||
workspace_tabs.activateTab(id);
|
||||
}
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
delete hiddenTabs[id];
|
||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||
},
|
||||
refresh: function() {
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
|
||||
@@ -196,14 +196,26 @@ $view-background: $secondary-background;
|
||||
$view-select-mode-background: $secondary-background-selected;
|
||||
$view-grid-color: #eee;
|
||||
|
||||
$link-color: #999;
|
||||
$link-link-color: #aaa;
|
||||
$link-disabled-color: #ccc;
|
||||
$link-link-active-color: #ff7f0e;
|
||||
$link-unknown-color: #f00;
|
||||
|
||||
$node-label-color: #333;
|
||||
$node-port-label-color: #888;
|
||||
$node-border: #999;
|
||||
$node-border-unknown: #f33;
|
||||
$node-border-placeholder: #aaa;
|
||||
$node-background-placeholder: #eee;
|
||||
|
||||
$node-port-border: $node-border;
|
||||
$node-port-border-connected: $link-color;
|
||||
|
||||
$node-port-background: #d9d9d9;
|
||||
$node-port-background-hover: #eee;
|
||||
$node-port-background-connected: $link-color;
|
||||
|
||||
$node-icon-color: #fff;
|
||||
$node-icon-background-color: rgba(0,0,0,0.05);
|
||||
$node-icon-background-color-fill: #000;
|
||||
@@ -231,12 +243,6 @@ $node-status-colors: (
|
||||
$node-selected-color: #ff7f0e;
|
||||
$port-selected-color: #ff7f0e;
|
||||
|
||||
$link-color: #999;
|
||||
$link-link-color: #aaa;
|
||||
$link-disabled-color: #ccc;
|
||||
$link-link-active-color: #ff7f0e;
|
||||
$link-unknown-color: #f00;
|
||||
|
||||
$clipboard-textarea-background: #F3E7E7;
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
stroke-dasharray: 10 5;
|
||||
}
|
||||
|
||||
.nr-ui-view-slice {
|
||||
stroke-width: 1px;
|
||||
stroke: $view-lasso-stroke;
|
||||
fill: none;
|
||||
stroke-dasharray: 10 5;
|
||||
}
|
||||
|
||||
.node_label_italic, // deprecated: use red-ui-flow-node-label-italic
|
||||
.red-ui-flow-node-label-italic {
|
||||
font-style: italic;
|
||||
@@ -47,7 +54,7 @@
|
||||
|
||||
.red-ui-flow-port-label {
|
||||
stroke-width: 0;
|
||||
fill: $secondary-text-color;
|
||||
fill: $node-port-label-color;
|
||||
font-size: 16px;
|
||||
dominant-baseline: middle;
|
||||
text-anchor: middle;
|
||||
@@ -178,12 +185,29 @@
|
||||
}
|
||||
|
||||
.red-ui-flow-port {
|
||||
stroke: $node-border;
|
||||
stroke: $node-port-border;
|
||||
stroke-width: 1;
|
||||
fill: $node-port-background;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.red-ui-flow-port-background {
|
||||
opacity: 0;
|
||||
stroke: none;
|
||||
fill: #f00;
|
||||
cursor: crosshair;
|
||||
}
|
||||
.red-ui-flow-port-shape {
|
||||
pointer-events: none;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.red-ui-flow-port-connected .red-ui-flow-port {
|
||||
fill: $node-port-background-connected;
|
||||
stroke: $node-port-border-connected;
|
||||
}
|
||||
|
||||
|
||||
.red-ui-flow-node-error {
|
||||
fill: $node-status-error-background;
|
||||
stroke: $node-status-error-border;
|
||||
@@ -273,9 +297,10 @@ g.red-ui-flow-node-selected {
|
||||
text-anchor:start;
|
||||
}
|
||||
|
||||
.red-ui-flow-port-hovered {
|
||||
stroke: $port-selected-color;
|
||||
fill: $port-selected-color;
|
||||
.red-ui-flow-port-hovered:not(.red-ui-flow-port-background),
|
||||
.red-ui-flow-port-background.red-ui-flow-port-hovered + .red-ui-flow-port-shape {
|
||||
stroke: $port-selected-color !important;
|
||||
fill: $port-selected-color !important;
|
||||
}
|
||||
|
||||
.red-ui-flow-subflow-port {
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
ul.red-ui-menu-dropdown {
|
||||
background: $header-menu-background;
|
||||
border: 1px solid $header-menu-background;
|
||||
width: 250px !important;
|
||||
width: 260px !important;
|
||||
margin-top: 0;
|
||||
li a {
|
||||
color: $header-menu-color;
|
||||
|
||||
@@ -137,10 +137,10 @@
|
||||
padding: 0;
|
||||
border: 1px solid $form-input-border-color;
|
||||
}
|
||||
.ui-spinner input[type=text] {
|
||||
.ui-spinner input {
|
||||
background: $form-input-background;
|
||||
margin: 0 17px 0 0;
|
||||
padding: 8px;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
|
||||
@@ -204,6 +204,28 @@
|
||||
font-style: italic;
|
||||
color: $form-placeholder-color;
|
||||
}
|
||||
.red-ui-search-history {
|
||||
button {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
&:hover button {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
.red-ui-search-historyHeader {
|
||||
button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 7px;
|
||||
}
|
||||
}
|
||||
.red-ui-search-history-result {
|
||||
|
||||
}
|
||||
|
||||
.red-ui-search-result-action {
|
||||
color: $primary-text-color;
|
||||
|
||||
@@ -389,7 +389,19 @@ i.red-ui-tab-icon {
|
||||
vertical-align: top;
|
||||
|
||||
}
|
||||
|
||||
.red-ui-tab-hide {
|
||||
.fa-eye-slash {
|
||||
display: none;
|
||||
}
|
||||
&:hover {
|
||||
.fa-eye-slash {
|
||||
display: inline
|
||||
}
|
||||
.fa-eye {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-tab-close {
|
||||
display: none;
|
||||
background: $tab-background-inactive;
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
export default {
|
||||
steps: [
|
||||
{
|
||||
title: "Create your first flow",
|
||||
title: {
|
||||
'en-US': 'Create your first flow',
|
||||
'ja': 'はじめてのフローを作成'
|
||||
},
|
||||
width: 400,
|
||||
description: 'This tutorial will guide you through creating your first flow',
|
||||
description: {
|
||||
'en-US': 'This tutorial will guide you through creating your first flow',
|
||||
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。'
|
||||
},
|
||||
nextButton: 'start'
|
||||
},
|
||||
{
|
||||
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
|
||||
description: 'To add a new tab, click the <i class="fa fa-plus"></i> button',
|
||||
description: {
|
||||
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
|
||||
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。'
|
||||
},
|
||||
wait: {
|
||||
type: "dom-event",
|
||||
event: "click",
|
||||
@@ -18,7 +27,10 @@ export default {
|
||||
{
|
||||
element: '.red-ui-palette-node[data-palette-type="inject"]',
|
||||
direction: 'right',
|
||||
description: 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
|
||||
description: {
|
||||
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
|
||||
'ja': 'パレットには、利用できる全てのノードが一覧表示されます。injectノードをワークスペースにドラッグします。'
|
||||
},
|
||||
fallback: 'inset-bottom-right',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
@@ -38,7 +50,10 @@ export default {
|
||||
{
|
||||
element: '.red-ui-palette-node[data-palette-type="debug"]',
|
||||
direction: 'right',
|
||||
description: 'Next, drag a new Debug node into the workspace.',
|
||||
description: {
|
||||
'en-US': 'Next, drag a new Debug node into the workspace.',
|
||||
'ja': '次に、debugノードをワークスペースにドラッグします。'
|
||||
},
|
||||
fallback: 'inset-bottom-right',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
@@ -57,7 +72,10 @@ export default {
|
||||
},
|
||||
{
|
||||
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
|
||||
description: 'Add a wire from the output of the Inject node to the input of the Debug node',
|
||||
description: {
|
||||
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
|
||||
'ja': 'injectノードの出力から、debugノードの入力へワイヤーで接続します。'
|
||||
},
|
||||
fallback: 'inset-bottom-right',
|
||||
wait: {
|
||||
type: "nr-event",
|
||||
@@ -69,7 +87,10 @@ export default {
|
||||
},
|
||||
{
|
||||
element: "#red-ui-header-button-deploy",
|
||||
description: 'Deploy your changes so the flow is active in the runtime',
|
||||
description: {
|
||||
'en-US': 'Deploy your changes so the flow is active in the runtime',
|
||||
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。'
|
||||
},
|
||||
width: 200,
|
||||
wait: {
|
||||
type: "dom-event",
|
||||
|
||||
@@ -3,48 +3,79 @@ export default {
|
||||
steps: [
|
||||
{
|
||||
titleIcon: "fa fa-map-o",
|
||||
title: { "en-US": "Welcome to Node-RED 2.1!" },
|
||||
description: { "en-US": "Let's take a moment to discover the new features in this release." }
|
||||
title: {
|
||||
"en-US": "Welcome to Node-RED 2.1!",
|
||||
"ja": "Node-RED 2.1へようこそ!"
|
||||
},
|
||||
description: {
|
||||
"en-US": "Let's take a moment to discover the new features in this release.",
|
||||
"ja": "本リリースの新機能を見つけてみましょう。"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: { "en-US": "A new Tour Guide" },
|
||||
description: { "en-US": "<p>First, as you've already found, we now have this tour of new features. We'll only show the tour the first time you open the editor for each new version of Node-RED.</p>"+
|
||||
"<p>You can choose not to see this tour in the future by disabling it under the View tab of User Settings.</p>" }
|
||||
title: {
|
||||
"en-US": "A new Tour Guide",
|
||||
"ja": "新しいツアーガイド"
|
||||
},
|
||||
description: {
|
||||
"en-US": "<p>First, as you've already found, we now have this tour of new features. We'll only show the tour the first time you open the editor for each new version of Node-RED.</p>" +
|
||||
"<p>You can choose not to see this tour in the future by disabling it under the View tab of User Settings.</p>",
|
||||
"ja": "<p>最初に、既に見つけている様に、新機能の本ツアーがあります。本ツアーは、新バージョンのNode-REDフローエディタを初めて開いた時のみ表示されます。</p>" +
|
||||
"<p>ユーザ設定の表示タブの中で、この機能を無効化することで、本ツアーを表示しないようにすることもできます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: { "en-US": "New Edit menu" },
|
||||
title: {
|
||||
"en-US": "New Edit menu",
|
||||
"ja": "新しい編集メニュー"
|
||||
},
|
||||
prepare() {
|
||||
$("#red-ui-header-button-sidemenu").trigger("click");
|
||||
$("#menu-item-edit-menu").parent().addClass("open")
|
||||
$("#menu-item-edit-menu").parent().addClass("open");
|
||||
},
|
||||
complete() {
|
||||
$("#menu-item-edit-menu").parent().removeClass("open")
|
||||
$("#menu-item-edit-menu").parent().removeClass("open");
|
||||
},
|
||||
element: "#menu-item-edit-menu-submenu",
|
||||
interactive: false,
|
||||
direction: "left",
|
||||
description: { "en-US": "<p>The main menu has been updated with a new 'Edit' section. This includes all of the familar options, like cut/paste and undo/redo.</p>"+
|
||||
"<p>The menu now displays keyboard shortcuts for the options.</p>" }
|
||||
|
||||
description: {
|
||||
"en-US": "<p>The main menu has been updated with a new 'Edit' section. This includes all of the familar options, like cut/paste and undo/redo.</p>" +
|
||||
"<p>The menu now displays keyboard shortcuts for the options.</p>",
|
||||
"ja": "<p>メインメニューに「編集」セクションが追加されました。本セクションには、切り取り/貼り付けや、変更操作を戻す/やり直しの様な使い慣れたオプションが含まれています。</p>" +
|
||||
"<p>本メニューには、オプションのためのキーボードショートカットも表示されるようになりました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: { "en-US": "Arranging nodes" },
|
||||
title: {
|
||||
"en-US": "Arranging nodes",
|
||||
"ja": "ノードの配置"
|
||||
},
|
||||
prepare() {
|
||||
$("#red-ui-header-button-sidemenu").trigger("click");
|
||||
$("#menu-item-arrange-menu").parent().addClass("open")
|
||||
$("#menu-item-arrange-menu").parent().addClass("open");
|
||||
},
|
||||
complete() {
|
||||
$("#menu-item-arrange-menu").parent().removeClass("open")
|
||||
$("#menu-item-arrange-menu").parent().removeClass("open");
|
||||
},
|
||||
element: "#menu-item-arrange-menu-submenu",
|
||||
interactive: false,
|
||||
direction: "left",
|
||||
description: { "en-US": "<p>The new 'Arrange' section of the menu provides new options to help arrange your nodes. You can align them to a common edge, spread them out evenly or change their order.</p>" },
|
||||
description: {
|
||||
"en-US": "<p>The new 'Arrange' section of the menu provides new options to help arrange your nodes. You can align them to a common edge, spread them out evenly or change their order.</p>",
|
||||
"ja": "<p>メニューの新しい「配置」セクションには、ノードの配置を助ける新しいオプションが提供されています。ノードの端を揃えたり、均等に配置したり、表示順序を変更したりできます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: { "en-US": "Hiding tabs" },
|
||||
title: {
|
||||
"en-US": "Hiding tabs",
|
||||
"ja": "タブの非表示"
|
||||
},
|
||||
element: "#red-ui-workspace-tabs > li.active",
|
||||
description: { "en-US": '<p>Tabs can now be hidden by clicking their <i class="fa fa-times"></i> icon.</p><p>The Info Sidebar will still list all of your tabs, and tell you which ones are currently hidden.' },
|
||||
description: {
|
||||
"en-US": '<p>Tabs can now be hidden by clicking their <i class="fa fa-eye-slash"></i> icon.</p><p>The Info Sidebar will still list all of your tabs, and tell you which ones are currently hidden.',
|
||||
"ja": '<p><i class="fa fa-eye-slash"></i> アイコンをクリックすることで、タブを非表示にできます。</p><p>情報サイドバーには、全てのタブが一覧表示されており、現在非表示になっているタブを確認できます。'
|
||||
},
|
||||
interactive: false,
|
||||
prepare() {
|
||||
$("#red-ui-workspace-tabs > li.active .red-ui-tab-close").css("display","block");
|
||||
@@ -54,9 +85,15 @@ export default {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: { "en-US": "Tab menu" },
|
||||
title: {
|
||||
"en-US": "Tab menu",
|
||||
"ja": "タブメニュー"
|
||||
},
|
||||
element: "#red-ui-workspace-tabs-menu",
|
||||
description: { "en-US": '<p>The new tab menu also provides lots of new options for your tabs.</p>' },
|
||||
description: {
|
||||
"en-US": "<p>The new tab menu also provides lots of new options for your tabs.</p>",
|
||||
"ja": "<p>新しいタブメニューには、タブに関する沢山の新しいオプションが提供されています。</p>"
|
||||
},
|
||||
interactive: false,
|
||||
direction: "left",
|
||||
prepare() {
|
||||
@@ -67,10 +104,16 @@ export default {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: { "en-US": "Flow and Group level environment variables" },
|
||||
title: {
|
||||
"en-US": "Flow and Group level environment variables",
|
||||
"ja": "フローとグループの環境変数"
|
||||
},
|
||||
element: "#red-ui-workspace-tabs > li.active",
|
||||
interactive: false,
|
||||
description: { "en-US": "<p>Flows and Groups can now have their own environment variables that can be referenced by nodes inside them.</p>" },
|
||||
description: {
|
||||
"en-US": "<p>Flows and Groups can now have their own environment variables that can be referenced by nodes inside them.</p>",
|
||||
"ja": "<p>フローとグループには、内部のノードから参照できる環境変数を設定できるようになりました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
prepare(done) {
|
||||
@@ -78,20 +121,28 @@ export default {
|
||||
setTimeout(done,700);
|
||||
},
|
||||
element: "#red-ui-tab-editor-tab-envProperties-link-button",
|
||||
description: { "en-US": "<p>Their edit dialogs have a new Environment Variables section.</p>" },
|
||||
description: {
|
||||
"en-US": "<p>Their edit dialogs have a new Environment Variables section.</p>",
|
||||
"ja": "<p>編集ダイアログに環境変数セクションが追加されました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
element: ".node-input-env-container-row",
|
||||
direction: "left",
|
||||
description: { "en-US": '<p>The environment variables are listed in this table and new ones can be added by clicking the <i class="fa fa-plus"></i> button.</p>' },
|
||||
description: {
|
||||
"en-US": '<p>The environment variables are listed in this table and new ones can be added by clicking the <i class="fa fa-plus"></i> button.</p>',
|
||||
"ja": '<p>この表に環境変数が一覧表示されており、<i class="fa fa-plus"></i>ボタンをクリックすることで新しい変数を追加できます。</p>'
|
||||
},
|
||||
complete(done) {
|
||||
$("#node-dialog-cancel").trigger("click");
|
||||
setTimeout(done,500);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: {"en-US":"Link Call node added"},
|
||||
title: {
|
||||
"en-US": "Link Call node added",
|
||||
"ja": "Link Callノードを追加"
|
||||
},
|
||||
prepare(done) {
|
||||
this.paletteWasClosed = $("#red-ui-main-container").hasClass("red-ui-palette-closed");
|
||||
RED.actions.invoke("core:toggle-palette",true)
|
||||
@@ -100,22 +151,34 @@ export default {
|
||||
},
|
||||
element: '[data-palette-type="link call"]',
|
||||
direction: "right",
|
||||
description: { "en-US": '<p>The <code>Link Call</code> node lets you call another flow that begins with a <code>Link In</code> node and get the result back when the message reaches a <code>Link Out</code> node.</p>' },
|
||||
description: {
|
||||
"en-US": "<p>The <code>Link Call</code> node lets you call another flow that begins with a <code>Link In</code> node and get the result back when the message reaches a <code>Link Out</code> node.</p>",
|
||||
"ja": "<p><code>Link Call</code>ノードを用いることで、<code>Link In</code>ノードから始まるフローを呼び出し、<code>Link Out</code>ノードに到達した時に、結果を取得できます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {"en-US":"MQTT nodes support dynamic connections"},
|
||||
title: {
|
||||
"en-US": "MQTT nodes support dynamic connections",
|
||||
"ja": "MQTTノードが動的接続をサポート"
|
||||
},
|
||||
prepare(done) {
|
||||
$('[data-palette-type="mqtt out"]')[0].scrollIntoView({block:"center"})
|
||||
setTimeout(done,100);
|
||||
},
|
||||
element: '[data-palette-type="mqtt out"]',
|
||||
direction: "right",
|
||||
description: { "en-US": '<p>The <code>MQTT</code> nodes now support creating their connections and subscriptions dynamically.</p>' },
|
||||
description: {
|
||||
"en-US": '<p>The <code>MQTT</code> nodes now support creating their connections and subscriptions dynamically.</p>',
|
||||
"ja": '<p><code>MQTT</code>ノードは、動的な接続や購読ができるようになりました。</p>'
|
||||
},
|
||||
},
|
||||
{
|
||||
title: {"en-US":"File nodes renamed"},
|
||||
title: {
|
||||
"en-US": "File nodes renamed",
|
||||
"ja": "ファイルノードの名前変更"
|
||||
},
|
||||
prepare(done) {
|
||||
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"})
|
||||
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"});
|
||||
setTimeout(done,100);
|
||||
},
|
||||
complete() {
|
||||
@@ -125,13 +188,19 @@ export default {
|
||||
},
|
||||
element: '[data-palette-type="file"]',
|
||||
direction: "right",
|
||||
description: { "en-US": '<p>The file nodes have been renamed to make it clearer which node does what.</p>' },
|
||||
description: {
|
||||
"en-US": "<p>The file nodes have been renamed to make it clearer which node does what.</p>",
|
||||
"ja": "<p>fileノードの名前が変更され、どのノードが何を行うかが明確になりました。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {"en-US":"Deep copy option on Change node"},
|
||||
title: {
|
||||
"en-US": "Deep copy option on Change node",
|
||||
"ja": "Changeノードのディープコピーオプション"
|
||||
},
|
||||
prepare(done) {
|
||||
var def = RED.nodes.getType('change')
|
||||
RED.editor.edit({id:"test",type:"change",rules:[{t:'set',p:'payload',pt:'msg', tot:'msg',to:"anotherProperty"}],_def:def, _:def._})
|
||||
var def = RED.nodes.getType('change');
|
||||
RED.editor.edit({id:"test",type:"change",rules:[{t:"set",p:"payload",pt:"msg", tot:"msg",to:"anotherProperty"}],_def:def, _:def._});
|
||||
setTimeout(done,700);
|
||||
},
|
||||
complete(done) {
|
||||
@@ -139,13 +208,22 @@ export default {
|
||||
setTimeout(done,500);
|
||||
},
|
||||
element: function() {
|
||||
return $(".node-input-rule-property-deepCopy").next()
|
||||
return $(".node-input-rule-property-deepCopy").next();
|
||||
},
|
||||
description: { "en-US": '<p>The Set rule has a new option to create a deep copy of the value. This ensures a complete copy is made, rather than using a reference.</p>' },
|
||||
description: {
|
||||
"en-US": "<p>The Set rule has a new option to create a deep copy of the value. This ensures a complete copy is made, rather than using a reference.</p>",
|
||||
"ja": "<p>値を代入に、値のディープコピーを作成するオプションが追加されました。これによって参照ではなく、完全なコピーが作成されます。</p>"
|
||||
}
|
||||
},
|
||||
{
|
||||
title: { "en-US": "And that's not all..." },
|
||||
description: { "en-US": "<p>There are many more smaller changes, including:</p><ul><li>Auto-complete suggestions in the <code>msg</code> TypedInput.</li><li>Support for <code>msg.resetTimeout</code> in the <code>Join</code> node.</li><li>Pushing messages to the front of the queue in the <code>Delay</code> node's rate limiting mode.</li><li>An optional second output on the <code>Delay</code> node for rate limited messages.</li></ul>" }
|
||||
title: {
|
||||
"en-US": "And that's not all...",
|
||||
"ja": "これが全てではありません..."
|
||||
},
|
||||
description: {
|
||||
"en-US": "<p>There are many more smaller changes, including:</p><ul><li>Auto-complete suggestions in the <code>msg</code> TypedInput.</li><li>Support for <code>msg.resetTimeout</code> in the <code>Join</code> node.</li><li>Pushing messages to the front of the queue in the <code>Delay</code> node's rate limiting mode.</li><li>An optional second output on the <code>Delay</code> node for rate limited messages.</li></ul>",
|
||||
"ja": "<p>以下の様な小さな変更が沢山あります:</p><ul><li><code>msg</code> TypedInputの自動補完提案</li><li><code>Join</code>ノードで<code>msg.resetTimeout</code>のサポート</li><li><code>Delay</code>ノードの流量制御モードにおいて先頭メッセージをキューに追加</li><li><code>Delay</code>ノードで流量制限されたメッセージ向けの任意の2つ目の出力</li></ul>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -353,14 +353,16 @@
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var node = this;
|
||||
var payloadType = node.payloadType;
|
||||
|
||||
if (node.payloadType == null) {
|
||||
if (node.payload == "") {
|
||||
node.payloadType = "date";
|
||||
payloadType = "date";
|
||||
} else {
|
||||
node.payloadType = "str";
|
||||
payloadType = "str";
|
||||
}
|
||||
} else if (node.payloadType === 'string' || node.payloadType === 'none') {
|
||||
node.payloadType = "str";
|
||||
payloadType = "str";
|
||||
}
|
||||
|
||||
$("#inject-time-type-select").on("change", function() {
|
||||
@@ -557,7 +559,7 @@
|
||||
var payload = {
|
||||
p:'payload',
|
||||
v: node.payload ? node.payload : '',
|
||||
vt:node.payloadType ? node.payloadType : 'date'
|
||||
vt:payloadType ? payloadType : 'date'
|
||||
};
|
||||
var topic = {
|
||||
p:'topic',
|
||||
@@ -573,7 +575,7 @@
|
||||
if (newProp.v === undefined) {
|
||||
if (prop.p === 'payload') {
|
||||
newProp.v = node.payload ? node.payload : '';
|
||||
newProp.vt = node.payloadType ? node.payloadType : 'date';
|
||||
newProp.vt = payloadType ? payloadType : 'date';
|
||||
} else if (prop.p === 'topic' && prop.vt === "str") {
|
||||
newProp.v = node.topic ? node.topic : '';
|
||||
}
|
||||
@@ -688,9 +690,9 @@
|
||||
this.topic = "";
|
||||
var result = getProps(items, true);
|
||||
this.props = result.props;
|
||||
if(result.payloadType) { this.payloadType = result.payloadType; };
|
||||
if(result.payload) { this.payload = result.payload; };
|
||||
if(result.topic) { this.topic = result.topic; };
|
||||
if(result.hasOwnProperty('payloadType')) { this.payloadType = result.payloadType; };
|
||||
if(result.hasOwnProperty('payload')) { this.payload = result.payload; };
|
||||
if(result.hasOwnProperty('topic')) { this.topic = result.topic; };
|
||||
},
|
||||
button: {
|
||||
enabled: function() {
|
||||
|
||||
@@ -75,16 +75,12 @@ module.exports = function(RED) {
|
||||
node.repeaterSetup = function () {
|
||||
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
|
||||
this.repeat = this.repeat * 1000;
|
||||
if (RED.settings.verbose) {
|
||||
this.log(RED._("inject.repeat", this));
|
||||
}
|
||||
this.debug(RED._("inject.repeat", this));
|
||||
this.interval_id = setInterval(function() {
|
||||
node.emit("input", {});
|
||||
}, this.repeat);
|
||||
} else if (this.crontab) {
|
||||
if (RED.settings.verbose) {
|
||||
this.log(RED._("inject.crontab", this));
|
||||
}
|
||||
this.debug(RED._("inject.crontab", this));
|
||||
this.cronjob = scheduleTask(this.crontab,() => { node.emit("input", {})});
|
||||
}
|
||||
};
|
||||
@@ -148,10 +144,8 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (this.interval_id != null) {
|
||||
clearInterval(this.interval_id);
|
||||
if (RED.settings.verbose) { this.log(RED._("inject.stopped")); }
|
||||
} else if (this.cronjob != null) {
|
||||
this.cronjob.stop();
|
||||
if (RED.settings.verbose) { this.log(RED._("inject.stopped")); }
|
||||
delete this.cronjob;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -280,6 +280,18 @@ module.exports = function(RED) {
|
||||
root: path.join(__dirname,"lib","debug"),
|
||||
dotfiles: 'deny'
|
||||
};
|
||||
res.sendFile(req.params[0], options);
|
||||
try {
|
||||
res.sendFile(
|
||||
req.params[0],
|
||||
options,
|
||||
err => {
|
||||
if (err) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
}
|
||||
)
|
||||
} catch(err) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -512,6 +512,7 @@
|
||||
return function(e) {
|
||||
e.preventDefault();
|
||||
var value = editor.getValue();
|
||||
var extraLibs = that.libs || [];
|
||||
RED.editor.editJavaScript({
|
||||
value: value,
|
||||
width: "Infinity",
|
||||
@@ -523,7 +524,8 @@
|
||||
setTimeout(function() {
|
||||
editor.focus();
|
||||
},300);
|
||||
}
|
||||
},
|
||||
extraLibs: extraLibs
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,8 +234,7 @@ module.exports = function(RED) {
|
||||
},
|
||||
env: {
|
||||
get: function(envVar) {
|
||||
var flow = node._flow;
|
||||
return flow.getSetting(envVar);
|
||||
return RED.util.getSetting(node, envVar);
|
||||
}
|
||||
},
|
||||
setTimeout: function () {
|
||||
|
||||
@@ -372,6 +372,7 @@ module.exports = function(RED) {
|
||||
hit = false;
|
||||
for (var b in node.buffer) { // check if already in queue
|
||||
if (msg.topic === node.buffer[b].msg.topic) {
|
||||
if (node.outputs === 2) { send([null,node.buffer[b].msg]) }
|
||||
node.buffer[b].done();
|
||||
node.buffer[b] = {msg, send, done}; // if so - replace existing entry
|
||||
hit = true;
|
||||
|
||||
@@ -86,7 +86,7 @@ module.exports = function(RED) {
|
||||
});
|
||||
var cmd = arg.shift();
|
||||
/* istanbul ignore else */
|
||||
if (RED.settings.verbose) { node.log(cmd+" ["+arg+"]"); }
|
||||
node.debug(cmd+" ["+arg+"]");
|
||||
child = spawn(cmd,arg,node.spawnOpt);
|
||||
node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid});
|
||||
var unknownCommand = (child.pid === undefined);
|
||||
@@ -136,7 +136,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
/* istanbul ignore else */
|
||||
if (RED.settings.verbose) { node.log(arg); }
|
||||
node.debug(arg);
|
||||
child = exec(arg, node.execOpt, function (error, stdout, stderr) {
|
||||
var msg2, msg3;
|
||||
delete msg.payload;
|
||||
@@ -155,7 +155,7 @@ module.exports = function(RED) {
|
||||
if (error.signal) { msg3.payload.signal = error.signal; }
|
||||
if (error.code === null) { node.status({fill:"red",shape:"dot",text:"killed"}); }
|
||||
else { node.status({fill:"red",shape:"dot",text:"error:"+error.code}); }
|
||||
if (RED.settings.verbose) { node.log('error:' + error); }
|
||||
node.debug('error:' + error);
|
||||
}
|
||||
else if (node.oldrc === "false") {
|
||||
msg3 = RED.util.cloneMessage(msg);
|
||||
|
||||
@@ -58,7 +58,7 @@ module.exports = function(RED) {
|
||||
else {
|
||||
var n = parseFloat(value);
|
||||
if (!isNaN(n)) {
|
||||
if ((typeof node.previous[t] === 'undefined') && (this.func === "narrowband")) {
|
||||
if ((typeof node.previous[t] === 'undefined') && (this.func === "narrowband" || this.func === "narrowbandEq")) {
|
||||
if (node.start === '') { node.previous[t] = n; }
|
||||
else { node.previous[t] = node.start; }
|
||||
}
|
||||
|
||||
@@ -298,18 +298,16 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
||||
}
|
||||
if (Object.keys(this.credentials).length != 0) {
|
||||
if (this.authType === "basic") {
|
||||
// Workaround for https://github.com/sindresorhus/got/issues/1169
|
||||
var cred = ""
|
||||
if (this.credentials.user) {
|
||||
// opts.username = this.credentials.user;
|
||||
cred = this.credentials.user
|
||||
}
|
||||
if (this.credentials.password) {
|
||||
// opts.password = this.credentials.password;
|
||||
cred += ":" + this.credentials.password
|
||||
// Workaround for https://github.com/sindresorhus/got/issues/1169 (fixed in got v12)
|
||||
// var cred = ""
|
||||
if (this.credentials.user || this.credentials.password) {
|
||||
// cred = `${this.credentials.user}:${this.credentials.password}`;
|
||||
if (this.credentials.user === undefined) { this.credentials.user = ""}
|
||||
if (this.credentials.password === undefined) { this.credentials.password = ""}
|
||||
opts.headers.Authorization = "Basic " + Buffer.from(`${this.credentials.user}:${this.credentials.password}`).toString("base64");
|
||||
}
|
||||
// build own basic auth header
|
||||
opts.headers.Authorization = "Basic " + Buffer.from(cred).toString("base64");
|
||||
// opts.headers.Authorization = "Basic " + Buffer.from(cred).toString("base64");
|
||||
} else if (this.authType === "digest") {
|
||||
let digestCreds = this.credentials;
|
||||
let sentCreds = false;
|
||||
|
||||
@@ -177,7 +177,8 @@
|
||||
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/)},
|
||||
tls: {type:"tls-config",required: false},
|
||||
wholemsg: {value:"false"},
|
||||
hb: {value: "", validate: RED.validators.number(/*blank allowed*/true) }
|
||||
hb: {value: "", validate: RED.validators.number(/*blank allowed*/true) },
|
||||
subprotocol: {value:"",required: false}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:0,
|
||||
@@ -265,7 +266,10 @@
|
||||
<label for="node-config-input-tls" data-i18n="httpin.tls-config"></label>
|
||||
<input type="text" id="node-config-input-tls">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-subprotocol"><i class="fa fa-tag"></i> <span data-i18n="websocket.label.subprotocol"></span></label>
|
||||
<input type="text" id="node-config-input-subprotocol">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-wholemsg" data-i18n="websocket.sendrec"></label>
|
||||
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
|
||||
|
||||
@@ -46,6 +46,12 @@ module.exports = function(RED) {
|
||||
|
||||
// Store local copies of the node configuration (as defined in the .html)
|
||||
node.path = n.path;
|
||||
if (typeof n.subprotocol === "string") {
|
||||
// Split the string on comma and trim each result
|
||||
node.subprotocol = n.subprotocol.split(",").map(v => v.trim())
|
||||
} else {
|
||||
node.subprotocol = [];
|
||||
}
|
||||
node.wholemsg = (n.wholemsg === "true");
|
||||
|
||||
node._inputNodes = []; // collection of nodes that want to receive events
|
||||
@@ -92,7 +98,7 @@ module.exports = function(RED) {
|
||||
tlsNode.addTLSOptions(options);
|
||||
}
|
||||
}
|
||||
var socket = new ws(node.path,options);
|
||||
var socket = new ws(node.path,node.subprotocol,options);
|
||||
socket.setMaxListeners(0);
|
||||
node.server = socket; // keep for closing
|
||||
handleConnection(socket);
|
||||
|
||||
@@ -23,9 +23,17 @@
|
||||
</select>
|
||||
<span data-i18n="tcpin.label.port"></span> <input type="text" id="node-input-port" style="width:65px">
|
||||
</div>
|
||||
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
|
||||
<div class="form-row hidden" id="node-input-host-row" style="padding-left:110px;">
|
||||
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
|
||||
</div>
|
||||
<div class="form-row" id="node-input-tls-enable">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width:auto; vertical-align:top;">
|
||||
<label for="node-input-usetls" style="width:auto" data-i18n="httpin.use-tls"></label>
|
||||
<div id="node-row-tls" class="hide">
|
||||
<label style="width:auto; margin-left:20px; margin-right:10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.output"></span></label>
|
||||
@@ -42,7 +50,7 @@
|
||||
</div>
|
||||
|
||||
<div id="node-row-newline" class="form-row hidden" style="padding-left:110px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
@@ -58,17 +66,18 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp in',{
|
||||
category: 'network',
|
||||
color:"Silver",
|
||||
color: "Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
server: {value:"server",required:true},
|
||||
host: {value:"",validate:function(v) { return (this.server == "server")||v.length > 0;} },
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
server: {value:"server", required:true},
|
||||
host: {value:"", validate:function(v) { return (this.server == "server")||v.length > 0;} },
|
||||
port: {value:"", required:true, validate:RED.validators.number()},
|
||||
datamode:{value:"stream"},
|
||||
datatype:{value:"buffer"},
|
||||
newline:{value:""},
|
||||
topic: {value:""},
|
||||
base64: {/*deprecated*/ value:false,required:true}
|
||||
base64: {/*deprecated*/ value:false, required:true},
|
||||
tls: {type:"tls-config", value:'', required:false}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
@@ -77,7 +86,7 @@
|
||||
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
return this.name ? "node_label_italic" : "";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var updateOptions = function() {
|
||||
@@ -103,6 +112,27 @@
|
||||
$("#node-input-server").change(updateOptions);
|
||||
$("#node-input-datatype").change(updateOptions);
|
||||
$("#node-input-datamode").change(updateOptions);
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-input-usetls").is(':checked')) {
|
||||
$("#node-row-tls").show();
|
||||
} else {
|
||||
$("#node-row-tls").hide();
|
||||
}
|
||||
}
|
||||
if (this.tls) {
|
||||
$('#node-input-usetls').prop('checked', true);
|
||||
} else {
|
||||
$('#node-input-usetls').prop('checked', false);
|
||||
}
|
||||
updateTLSOptions();
|
||||
$("#node-input-usetls").on("click",function() {
|
||||
updateTLSOptions();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-input-usetls").is(':checked')) {
|
||||
$("#node-input-tls").val("_ADD_");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -123,6 +153,15 @@
|
||||
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" style="width: 60%;">
|
||||
</div>
|
||||
|
||||
<div class="form-row" id="node-input-tls-enable">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
|
||||
<div id="node-row-tls" class="hide">
|
||||
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row hidden" id="node-input-end-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-end" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
@@ -144,14 +183,15 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp out',{
|
||||
category: 'network',
|
||||
color:"Silver",
|
||||
color: "Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
host: {value:"",validate:function(v) { return (this.beserver != "client")||v.length > 0;} },
|
||||
port: {value:"",validate:function(v) { return (this.beserver == "reply")||RED.validators.number()(v); } },
|
||||
beserver: {value:"client",required:true},
|
||||
base64: {value:false,required:true},
|
||||
end: {value:false,required:true},
|
||||
name: {value:""}
|
||||
beserver: {value:"client", required:true},
|
||||
base64: {value:false, required:true},
|
||||
end: {value:false, required:true},
|
||||
tls: {type:"tls-config", value:'', required:false}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
@@ -170,18 +210,42 @@
|
||||
$("#node-input-port-row").hide();
|
||||
$("#node-input-host-row").hide();
|
||||
$("#node-input-end-row").hide();
|
||||
$("#node-input-tls-enable").hide();
|
||||
} else if (sockettype == "client"){
|
||||
$("#node-input-port-row").show();
|
||||
$("#node-input-host-row").show();
|
||||
$("#node-input-end-row").show();
|
||||
$("#node-input-tls-enable").show();
|
||||
} else {
|
||||
$("#node-input-port-row").show();
|
||||
$("#node-input-host-row").hide();
|
||||
$("#node-input-end-row").show();
|
||||
$("#node-input-tls-enable").show();
|
||||
}
|
||||
};
|
||||
updateOptions();
|
||||
$("#node-input-beserver").change(updateOptions);
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-input-usetls").is(':checked')) {
|
||||
$("#node-row-tls").show();
|
||||
} else {
|
||||
$("#node-row-tls").hide();
|
||||
}
|
||||
}
|
||||
if (this.tls) {
|
||||
$('#node-input-usetls').prop('checked', true);
|
||||
} else {
|
||||
$('#node-input-usetls').prop('checked', false);
|
||||
}
|
||||
updateTLSOptions();
|
||||
$("#node-input-usetls").on("click",function() {
|
||||
updateTLSOptions();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-input-usetls").is(':checked')) {
|
||||
$("#node-input-tls").val("_ADD_");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -194,15 +258,23 @@
|
||||
<span data-i18n="tcpin.label.port"></span>
|
||||
<input type="text" id="node-input-port" style="width:60px">
|
||||
</div>
|
||||
<div class="form-row" id="node-input-tls-enable">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
|
||||
<div id="node-row-tls" class="hide">
|
||||
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-out"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
|
||||
<label for="node-input-ret"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
|
||||
<select type="text" id="node-input-ret" style="width:54%;">
|
||||
<option value="buffer" data-i18n="tcpin.output.buffer"></option>
|
||||
<option value="string" data-i18n="tcpin.output.string"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-out"> </label>
|
||||
<label for="node-input-out"><i class="fa fa-sign-out fa-rotate-90"></i> <span data-i18n="tcpin.label.close"></span></label>
|
||||
<select type="text" id="node-input-out" style="width:54%;">
|
||||
<option value="time" data-i18n="tcpin.return.timeout"></option>
|
||||
<option value="char" data-i18n="tcpin.return.character"></option>
|
||||
@@ -213,6 +285,9 @@
|
||||
<input type="text" id="node-input-splitc" style="width:50px;">
|
||||
<span id="node-units"></span>
|
||||
</div>
|
||||
<div id="node-row-newline" class="form-row hidden" style="padding-left:162px;">
|
||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
@@ -222,14 +297,16 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp request',{
|
||||
category: 'network',
|
||||
color:"Silver",
|
||||
color: "Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
server: {value:""},
|
||||
port: {value:"",validate:RED.validators.regex(/^(\d*|)$/)},
|
||||
out: {value:"time",required:true},
|
||||
port: {value:"", validate:RED.validators.regex(/^(\d*|)$/)},
|
||||
out: {value:"time", required:true},
|
||||
ret: {value:"buffer"},
|
||||
splitc: {value:"0",required:true},
|
||||
name: {value:""}
|
||||
splitc: {value:"0", required:true},
|
||||
newline: {value:""},
|
||||
tls: {type:"tls-config", value:'', required:false}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
@@ -246,6 +323,14 @@
|
||||
$("#node-input-ret").val("buffer");
|
||||
this.ret = "buffer";
|
||||
}
|
||||
$("#node-input-ret").on("change", function() {
|
||||
if ($("#node-input-ret").val() === "string" && $("#node-input-out").val() === "sit") { $("#node-row-newline").show(); }
|
||||
else { $("#node-row-newline").hide(); }
|
||||
});
|
||||
$("#node-input-out").on("change", function() {
|
||||
if ($("#node-input-ret").val() === "string" && $("#node-input-out").val() === "sit") { $("#node-row-newline").show(); }
|
||||
else { $("#node-row-newline").hide(); }
|
||||
});
|
||||
$("#node-input-out").on('focus', function () { previous = this.value; }).on("change", function() {
|
||||
$("#node-input-splitc").show();
|
||||
if (previous === null) { previous = $("#node-input-out").val(); }
|
||||
@@ -272,6 +357,27 @@
|
||||
$("#node-input-splitc").hide();
|
||||
}
|
||||
});
|
||||
function updateTLSOptions() {
|
||||
if ($("#node-input-usetls").is(':checked')) {
|
||||
$("#node-row-tls").show();
|
||||
} else {
|
||||
$("#node-row-tls").hide();
|
||||
}
|
||||
}
|
||||
if (this.tls) {
|
||||
$('#node-input-usetls').prop('checked', true);
|
||||
} else {
|
||||
$('#node-input-usetls').prop('checked', false);
|
||||
}
|
||||
updateTLSOptions();
|
||||
$("#node-input-usetls").on("click",function() {
|
||||
updateTLSOptions();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-input-usetls").is(':checked')) {
|
||||
$("#node-input-tls").val("_ADD_");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -16,13 +16,46 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||
var socketTimeout = RED.settings.socketTimeout||null;
|
||||
let reconnectTime = RED.settings.socketReconnectTime || 10000;
|
||||
let socketTimeout = RED.settings.socketTimeout || null;
|
||||
const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
|
||||
const Denque = require('denque');
|
||||
var net = require('net');
|
||||
const net = require('net');
|
||||
const tls = require('tls');
|
||||
|
||||
var connectionPool = {};
|
||||
let connectionPool = {};
|
||||
|
||||
function normalizeConnectArgs(listArgs) {
|
||||
const args = net._normalizeArgs(listArgs);
|
||||
const options = args[0];
|
||||
const cb = args[1];
|
||||
|
||||
// If args[0] was options, then normalize dealt with it.
|
||||
// If args[0] is port, or args[0], args[1] is host, port, we need to
|
||||
// find the options and merge them in, normalize's options has only
|
||||
// the host/port/path args that it knows about, not the tls options.
|
||||
// This means that options.host overrides a host arg.
|
||||
if (listArgs[1] !== null && typeof listArgs[1] === 'object') {
|
||||
ObjectAssign(options, listArgs[1]);
|
||||
} else if (listArgs[2] !== null && typeof listArgs[2] === 'object') {
|
||||
ObjectAssign(options, listArgs[2]);
|
||||
}
|
||||
|
||||
return cb ? [options, cb] : [options];
|
||||
}
|
||||
|
||||
function getAllowUnauthorized() {
|
||||
const allowUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0';
|
||||
|
||||
if (allowUnauthorized) {
|
||||
process.emitWarning(
|
||||
'Setting the NODE_TLS_REJECT_UNAUTHORIZED ' +
|
||||
'environment variable to \'0\' makes TLS connections ' +
|
||||
'and HTTPS requests insecure by disabling ' +
|
||||
'certificate verification.');
|
||||
}
|
||||
return allowUnauthorized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue `item` in `queue`
|
||||
@@ -53,13 +86,14 @@ module.exports = function(RED) {
|
||||
this.topic = n.topic;
|
||||
this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
|
||||
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
|
||||
this.base64 = n.base64;
|
||||
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
||||
this.closing = false;
|
||||
this.connected = false;
|
||||
var node = this;
|
||||
var count = 0;
|
||||
if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); }
|
||||
|
||||
if (!node.server) {
|
||||
var buffer = null;
|
||||
@@ -70,13 +104,25 @@ module.exports = function(RED) {
|
||||
node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
|
||||
node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
|
||||
var id = RED.util.generateId();
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
|
||||
});
|
||||
client.setKeepAlive(true,120000);
|
||||
var connOpts = {host: node.host};
|
||||
if (n.tls) {
|
||||
var connOpts = tlsNode.addTLSOptions({host: node.host});
|
||||
client = tls.connect(node.port, connOpts, function() {
|
||||
buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("status.connected", {host: node.host, port: node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
|
||||
});
|
||||
}
|
||||
else {
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected",_session:{type:"tcp",id:id}});
|
||||
});
|
||||
}
|
||||
client.setKeepAlive(true, 120000);
|
||||
connectionPool[id] = client;
|
||||
|
||||
client.on('data', function (data) {
|
||||
@@ -89,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);
|
||||
}
|
||||
@@ -150,7 +196,13 @@ module.exports = function(RED) {
|
||||
});
|
||||
}
|
||||
else {
|
||||
var server = net.createServer(function (socket) {
|
||||
let srv = net;
|
||||
let connOpts;
|
||||
if (n.tls) {
|
||||
srv = tls;
|
||||
connOpts = tlsNode.addTLSOptions({});
|
||||
}
|
||||
var server = srv.createServer(connOpts, function (socket) {
|
||||
socket.setKeepAlive(true,120000);
|
||||
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
|
||||
var id = RED.util.generateId();
|
||||
@@ -177,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);
|
||||
}
|
||||
@@ -269,8 +321,9 @@ module.exports = function(RED) {
|
||||
this.closing = false;
|
||||
this.connected = false;
|
||||
var node = this;
|
||||
if (n.tls) { var tlsNode = RED.nodes.getNode(n.tls); }
|
||||
|
||||
if (!node.beserver||node.beserver=="client") {
|
||||
if (!node.beserver || node.beserver == "client") {
|
||||
var reconnectTimeout;
|
||||
var client = null;
|
||||
var end = false;
|
||||
@@ -278,11 +331,24 @@ module.exports = function(RED) {
|
||||
var setupTcpClient = function() {
|
||||
node.log(RED._("tcpin.status.connecting",{host:node.host,port:node.port}));
|
||||
node.status({fill:"grey",shape:"dot",text:"common.status.connecting"});
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
});
|
||||
if (n.tls) {
|
||||
// connOpts = tlsNode.addTLSOptions(connOpts);
|
||||
// client = tls.connect(connOpts, function() {
|
||||
var connOpts = tlsNode.addTLSOptions({host: node.host});
|
||||
client = tls.connect(node.port, connOpts, function() {
|
||||
// buffer = (node.datatype == 'buffer') ? Buffer.alloc(0) : "";
|
||||
node.connected = true;
|
||||
node.log(RED._("status.connected", {host: node.host, port: node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
});
|
||||
}
|
||||
else {
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
node.connected = true;
|
||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
});
|
||||
}
|
||||
client.setKeepAlive(true,120000);
|
||||
client.on('error', function (err) {
|
||||
node.log(RED._("tcpin.errors.error",{error:err.toString()}));
|
||||
@@ -368,7 +434,13 @@ module.exports = function(RED) {
|
||||
else {
|
||||
var connectedSockets = [];
|
||||
node.status({text:RED._("tcpin.status.connections",{count:0})});
|
||||
var server = net.createServer(function (socket) {
|
||||
let srv = net;
|
||||
let connOpts;
|
||||
if (n.tls) {
|
||||
srv = tls;
|
||||
connOpts = tlsNode.addTLSOptions({});
|
||||
}
|
||||
var server = srv.createServer(connOpts, function (socket) {
|
||||
socket.setKeepAlive(true,120000);
|
||||
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
|
||||
node.log(RED._("tcpin.status.connection-from",{host:socket.remoteAddress, port:socket.remotePort}));
|
||||
@@ -445,7 +517,11 @@ module.exports = function(RED) {
|
||||
this.port = Number(n.port);
|
||||
this.out = n.out;
|
||||
this.ret = n.ret || "buffer";
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
|
||||
this.splitc = n.splitc;
|
||||
if (n.tls) {
|
||||
var tlsNode = RED.nodes.getNode(n.tls);
|
||||
}
|
||||
|
||||
if (this.out === "immed") { this.splitc = -1; this.out = "time"; }
|
||||
if (this.out !== "char") { this.splitc = Number(this.splitc); }
|
||||
@@ -500,12 +576,48 @@ module.exports = function(RED) {
|
||||
}
|
||||
else { buf = Buffer.alloc(65536); } // set it to 64k... hopefully big enough for most TCP packets.... but only hopefully
|
||||
|
||||
clients[connection_id].client = net.Socket();
|
||||
var connOpts = {host:host, port:port};
|
||||
if (n.tls) {
|
||||
connOpts = tlsNode.addTLSOptions(connOpts);
|
||||
const allowUnauthorized = getAllowUnauthorized();
|
||||
|
||||
let options = {
|
||||
rejectUnauthorized: !allowUnauthorized,
|
||||
ciphers: tls.DEFAULT_CIPHERS,
|
||||
checkServerIdentity: tls.checkServerIdentity,
|
||||
minDHSize: 1024,
|
||||
...connOpts
|
||||
};
|
||||
|
||||
if (!options.keepAlive) { options.singleUse = true; }
|
||||
|
||||
const context = options.secureContext || tls.createSecureContext(options);
|
||||
|
||||
clients[connection_id].client = new tls.TLSSocket(options.socket, {
|
||||
allowHalfOpen: options.allowHalfOpen,
|
||||
pipe: !!options.path,
|
||||
secureContext: context,
|
||||
isServer: false,
|
||||
requestCert: false, // true,
|
||||
rejectUnauthorized: false, // options.rejectUnauthorized !== false,
|
||||
session: options.session,
|
||||
ALPNProtocols: options.ALPNProtocols,
|
||||
requestOCSP: options.requestOCSP,
|
||||
enableTrace: options.enableTrace,
|
||||
pskCallback: options.pskCallback,
|
||||
highWaterMark: options.highWaterMark,
|
||||
onread: options.onread,
|
||||
signal: options.signal,
|
||||
});
|
||||
}
|
||||
else {
|
||||
clients[connection_id].client = net.Socket();
|
||||
}
|
||||
if (socketTimeout !== null) { clients[connection_id].client.setTimeout(socketTimeout);}
|
||||
|
||||
if (host && port) {
|
||||
clients[connection_id].connecting = true;
|
||||
clients[connection_id].client.connect(port, host, function() {
|
||||
clients[connection_id].client.connect(connOpts, function() {
|
||||
//node.log(RED._("tcpin.errors.client-connected"));
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
if (clients[connection_id] && clients[connection_id].client) {
|
||||
@@ -528,17 +640,32 @@ module.exports = function(RED) {
|
||||
else {
|
||||
node.warn(RED._("tcpin.errors.no-host"));
|
||||
}
|
||||
|
||||
var chunk = "";
|
||||
clients[connection_id].client.on('data', function(data) {
|
||||
if (node.out === "sit") { // if we are staying connected just send the buffer
|
||||
if (clients[connection_id]) {
|
||||
const msg = clients[connection_id].lastMsg || {};
|
||||
msg.payload = RED.util.cloneMessage(data);
|
||||
if (node.ret === "string") {
|
||||
try { msg.payload = msg.payload.toString(); }
|
||||
catch(e) { node.error("Failed to create string", msg); }
|
||||
try {
|
||||
if (node.newline && node.newline !== "" ) {
|
||||
chunk += msg.payload.toString();
|
||||
let parts = chunk.split(node.newline);
|
||||
for (var p=0; p<parts.length-1; p+=1) {
|
||||
let m = RED.util.cloneMessage(msg);
|
||||
m.payload = parts[p] + node.newline.trimEnd();
|
||||
nodeSend(m);
|
||||
}
|
||||
chunk = parts[parts.length-1];
|
||||
}
|
||||
else {
|
||||
msg.payload = msg.payload.toString();
|
||||
nodeSend(msg);
|
||||
}
|
||||
}
|
||||
catch(e) { node.error(RED._("tcpin.errors.bad-string"), msg); }
|
||||
}
|
||||
nodeSend(msg);
|
||||
else { nodeSend(msg); }
|
||||
}
|
||||
}
|
||||
// else if (node.splitc === 0) {
|
||||
@@ -675,7 +802,13 @@ module.exports = function(RED) {
|
||||
//node.warn(RED._("tcpin.errors.connect-timeout"));
|
||||
if (clients[connection_id].client) {
|
||||
clients[connection_id].connecting = true;
|
||||
clients[connection_id].client.connect(port, host, function() {
|
||||
|
||||
var connOpts = {host:host, port:port};
|
||||
if (n.tls) {
|
||||
connOpts = tlsNode.addTLSOptions(connOpts);
|
||||
}
|
||||
|
||||
clients[connection_id].client.connect(connOpts, function() {
|
||||
clients[connection_id].connected = true;
|
||||
clients[connection_id].connecting = false;
|
||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||
|
||||
@@ -71,9 +71,7 @@ module.exports = function(RED) {
|
||||
node.error(RED._("file.errors.deletefail",{error:err.toString()}),msg);
|
||||
}
|
||||
else {
|
||||
if (RED.settings.verbose) {
|
||||
node.log(RED._("file.status.deletedfile",{file:filename}));
|
||||
}
|
||||
node.debug(RED._("file.status.deletedfile",{file:filename}));
|
||||
nodeSend(msg);
|
||||
}
|
||||
done();
|
||||
|
||||
156
packages/node_modules/@node-red/nodes/examples/common/link/03 - Link call.json
vendored
Normal file
156
packages/node_modules/@node-red/nodes/examples/common/link/03 - Link call.json
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
[
|
||||
{
|
||||
"id": "62ea32aa.d73aac",
|
||||
"type": "comment",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Example: Link Call Node",
|
||||
"info": "Link call node can call link in node then get result from link out node.",
|
||||
"x": 230,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "c588bc36.87fec",
|
||||
"type": "comment",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓ call link in node",
|
||||
"info": "",
|
||||
"x": 440,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "cd31efb4d2c6967e",
|
||||
"type": "link call",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"links": [
|
||||
"dbc46892c8d14c37"
|
||||
],
|
||||
"timeout": "30",
|
||||
"x": 420,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"c3db64d1d2260340"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dbc46892c8d14c37",
|
||||
"type": "link in",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"links": [],
|
||||
"x": 315,
|
||||
"y": 340,
|
||||
"wires": [
|
||||
[
|
||||
"e10575d73f2e5352"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6b61792143b3b0a3",
|
||||
"type": "inject",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
"p": "payload"
|
||||
},
|
||||
{
|
||||
"p": "topic",
|
||||
"vt": "str"
|
||||
}
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"onceDelay": 0.1,
|
||||
"topic": "",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 240,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"cd31efb4d2c6967e"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e10575d73f2e5352",
|
||||
"type": "change",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"rules": [
|
||||
{
|
||||
"t": "set",
|
||||
"p": "payload",
|
||||
"pt": "msg",
|
||||
"to": "Hello, World!",
|
||||
"tot": "str"
|
||||
}
|
||||
],
|
||||
"action": "",
|
||||
"property": "",
|
||||
"from": "",
|
||||
"to": "",
|
||||
"reg": false,
|
||||
"x": 450,
|
||||
"y": 340,
|
||||
"wires": [
|
||||
[
|
||||
"cf8438e7137bc0f0"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cf8438e7137bc0f0",
|
||||
"type": "link out",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"mode": "return",
|
||||
"links": [],
|
||||
"x": 595,
|
||||
"y": 340,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "c3db64d1d2260340",
|
||||
"type": "debug",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 600,
|
||||
"y": 260,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "6d077dfa0987febb",
|
||||
"type": "comment",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑called from link call node",
|
||||
"info": "",
|
||||
"x": 410,
|
||||
"y": 380,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "53b9a0adfd8c4217",
|
||||
"type": "comment",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑return to link call node",
|
||||
"info": "",
|
||||
"x": 680,
|
||||
"y": 380,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": "84222b92.d65d18",
|
||||
"type": "inject",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
@@ -20,8 +20,8 @@
|
||||
"topic": "",
|
||||
"payload": "Hello, World!",
|
||||
"payloadType": "str",
|
||||
"x": 230,
|
||||
"y": 220,
|
||||
"x": 190,
|
||||
"y": 180,
|
||||
"wires": [
|
||||
[
|
||||
"b4b9f603.739598"
|
||||
@@ -31,25 +31,25 @@
|
||||
{
|
||||
"id": "7b014430.dfd94c",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Write string to a file, then read from the file",
|
||||
"info": "File-in node can read string from a file.",
|
||||
"x": 260,
|
||||
"y": 140,
|
||||
"info": "Read file node can read string from a file.",
|
||||
"x": 220,
|
||||
"y": 100,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "b4b9f603.739598",
|
||||
"type": "file",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "true",
|
||||
"encoding": "none",
|
||||
"x": 420,
|
||||
"y": 220,
|
||||
"x": 380,
|
||||
"y": 180,
|
||||
"wires": [
|
||||
[
|
||||
"6dc01cac.5c4bf4"
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"id": "2587adb9.7e60f2",
|
||||
"type": "debug",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -68,22 +68,22 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 810,
|
||||
"y": 220,
|
||||
"x": 770,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "6dc01cac.5c4bf4",
|
||||
"type": "file in",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"format": "utf8",
|
||||
"chunk": false,
|
||||
"sendError": false,
|
||||
"encoding": "none",
|
||||
"x": 620,
|
||||
"y": 220,
|
||||
"x": 580,
|
||||
"y": 180,
|
||||
"wires": [
|
||||
[
|
||||
"2587adb9.7e60f2"
|
||||
@@ -93,21 +93,21 @@
|
||||
{
|
||||
"id": "f4b4309a.3b78a",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑read result from file",
|
||||
"info": "",
|
||||
"x": 630,
|
||||
"y": 260,
|
||||
"x": 590,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "672d3693.3cabd8",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓write to /tmp/hello.txt",
|
||||
"info": "",
|
||||
"x": 440,
|
||||
"y": 180,
|
||||
"x": 400,
|
||||
"y": 140,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": "8997398f.c5d628",
|
||||
"type": "inject",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
@@ -20,8 +20,8 @@
|
||||
"topic": "",
|
||||
"payload": "😀",
|
||||
"payloadType": "str",
|
||||
"x": 210,
|
||||
"y": 480,
|
||||
"x": 170,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"56e32d23.050f44"
|
||||
@@ -31,25 +31,25 @@
|
||||
{
|
||||
"id": "4e598e65.1799d",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Read data in specified encoding",
|
||||
"info": "File-in node can specify encoding of data read from a file.",
|
||||
"x": 230,
|
||||
"y": 400,
|
||||
"info": "Read file node can specify encoding of data read from a file.",
|
||||
"x": 190,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "56e32d23.050f44",
|
||||
"type": "file",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "true",
|
||||
"encoding": "none",
|
||||
"x": 380,
|
||||
"y": 480,
|
||||
"x": 340,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"38fa0579.f2cd8a"
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"id": "d28c8994.99c0a8",
|
||||
"type": "debug",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -68,22 +68,23 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 770,
|
||||
"y": 480,
|
||||
"x": 730,
|
||||
"y": 260,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "38fa0579.f2cd8a",
|
||||
"type": "file in",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"format": "utf8",
|
||||
"chunk": false,
|
||||
"sendError": false,
|
||||
"encoding": "base64",
|
||||
"x": 580,
|
||||
"y": 480,
|
||||
"allProps": false,
|
||||
"x": 540,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"d28c8994.99c0a8"
|
||||
@@ -93,21 +94,21 @@
|
||||
{
|
||||
"id": "fa22ca20.ae4528",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑read data from file as base64 string",
|
||||
"info": "",
|
||||
"x": 640,
|
||||
"y": 520,
|
||||
"x": 600,
|
||||
"y": 300,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "148e25ad.98891a",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓write to /tmp/hello.txt",
|
||||
"info": "",
|
||||
"x": 400,
|
||||
"y": 440,
|
||||
"x": 360,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": "6a0b1d03.d4cee4",
|
||||
"type": "inject",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
@@ -20,8 +20,8 @@
|
||||
"topic": "",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 220,
|
||||
"y": 740,
|
||||
"x": 160,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"d4b00cb7.a5a23"
|
||||
@@ -31,25 +31,25 @@
|
||||
{
|
||||
"id": "f17ea1d1.8ecc3",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Read data breaking lines into individual messages",
|
||||
"info": "File-in node can break read text into messages with individual lines",
|
||||
"x": 290,
|
||||
"y": 660,
|
||||
"info": "Read file node can break read text into messages with individual lines",
|
||||
"x": 230,
|
||||
"y": 140,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "99ae7806.1d6428",
|
||||
"type": "file",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "true",
|
||||
"encoding": "none",
|
||||
"x": 540,
|
||||
"y": 740,
|
||||
"x": 480,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"70d7892f.d27db8"
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"id": "7ed8282c.92b338",
|
||||
"type": "debug",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -68,22 +68,22 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 810,
|
||||
"y": 800,
|
||||
"x": 750,
|
||||
"y": 280,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "70d7892f.d27db8",
|
||||
"type": "file in",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"format": "lines",
|
||||
"chunk": false,
|
||||
"sendError": false,
|
||||
"encoding": "none",
|
||||
"x": 620,
|
||||
"y": 800,
|
||||
"x": 560,
|
||||
"y": 280,
|
||||
"wires": [
|
||||
[
|
||||
"7ed8282c.92b338"
|
||||
@@ -93,27 +93,27 @@
|
||||
{
|
||||
"id": "c1b7e05.1d94b2",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑read data from file breaking lines into messages",
|
||||
"info": "",
|
||||
"x": 720,
|
||||
"y": 840,
|
||||
"x": 660,
|
||||
"y": 320,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "a5f647b2.cf27a8",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓write to /tmp/hello.txt",
|
||||
"info": "",
|
||||
"x": 560,
|
||||
"y": 700,
|
||||
"x": 500,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "d4b00cb7.a5a23",
|
||||
"type": "template",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "data",
|
||||
"field": "payload",
|
||||
"fieldType": "msg",
|
||||
@@ -121,8 +121,8 @@
|
||||
"syntax": "plain",
|
||||
"template": "one\ntwo\nthree!",
|
||||
"output": "str",
|
||||
"x": 370,
|
||||
"y": 740,
|
||||
"x": 310,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"99ae7806.1d6428"
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": "bdd57acc.2edc48",
|
||||
"type": "inject",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
@@ -20,8 +20,8 @@
|
||||
"topic": "",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 220,
|
||||
"y": 1040,
|
||||
"x": 180,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"7a069b01.0c2324"
|
||||
@@ -31,25 +31,25 @@
|
||||
{
|
||||
"id": "1fd12220.33953e",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Creating a message stream from lines of data",
|
||||
"info": "File-in node can break read text into messages with individual lines. The messages creates a stream of messages.",
|
||||
"x": 270,
|
||||
"y": 960,
|
||||
"info": "Read file node can break read text into messages with individual lines. The messages creates a stream of messages.",
|
||||
"x": 230,
|
||||
"y": 140,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "ab6eb213.2a08d",
|
||||
"type": "file",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "true",
|
||||
"encoding": "none",
|
||||
"x": 540,
|
||||
"y": 1040,
|
||||
"x": 500,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"b7ed49b0.649fb8"
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"id": "c48d8ae0.9ff3a8",
|
||||
"type": "debug",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -68,22 +68,22 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 810,
|
||||
"y": 1140,
|
||||
"x": 770,
|
||||
"y": 320,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "b7ed49b0.649fb8",
|
||||
"type": "file in",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"format": "lines",
|
||||
"chunk": false,
|
||||
"sendError": false,
|
||||
"encoding": "none",
|
||||
"x": 280,
|
||||
"y": 1140,
|
||||
"x": 240,
|
||||
"y": 320,
|
||||
"wires": [
|
||||
[
|
||||
"83073ebe.fcce4"
|
||||
@@ -93,27 +93,27 @@
|
||||
{
|
||||
"id": "3c33e69f.6a04ba",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑read data from file breaking lines into messages",
|
||||
"info": "",
|
||||
"x": 380,
|
||||
"y": 1180,
|
||||
"x": 340,
|
||||
"y": 360,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "3598bf7d.5712a",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓write to /tmp/hello.txt",
|
||||
"info": "",
|
||||
"x": 560,
|
||||
"y": 1000,
|
||||
"x": 520,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "7a069b01.0c2324",
|
||||
"type": "template",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "data",
|
||||
"field": "payload",
|
||||
"fieldType": "msg",
|
||||
@@ -121,8 +121,8 @@
|
||||
"syntax": "plain",
|
||||
"template": "Apple\nBanana\nGrape\nOrange",
|
||||
"output": "str",
|
||||
"x": 370,
|
||||
"y": 1040,
|
||||
"x": 330,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"ab6eb213.2a08d"
|
||||
@@ -132,7 +132,7 @@
|
||||
{
|
||||
"id": "8d4ed1d0.821fe",
|
||||
"type": "join",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"mode": "auto",
|
||||
"build": "string",
|
||||
@@ -145,8 +145,8 @@
|
||||
"timeout": "",
|
||||
"count": "",
|
||||
"reduceRight": false,
|
||||
"x": 630,
|
||||
"y": 1140,
|
||||
"x": 590,
|
||||
"y": 320,
|
||||
"wires": [
|
||||
[
|
||||
"c48d8ae0.9ff3a8"
|
||||
@@ -156,7 +156,7 @@
|
||||
{
|
||||
"id": "83073ebe.fcce4",
|
||||
"type": "switch",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "< D",
|
||||
"property": "payload",
|
||||
"propertyType": "msg",
|
||||
@@ -170,8 +170,8 @@
|
||||
"checkall": "true",
|
||||
"repair": true,
|
||||
"outputs": 1,
|
||||
"x": 470,
|
||||
"y": 1140,
|
||||
"x": 430,
|
||||
"y": 320,
|
||||
"wires": [
|
||||
[
|
||||
"8d4ed1d0.821fe"
|
||||
@@ -181,21 +181,21 @@
|
||||
{
|
||||
"id": "2088e195.f7aebe",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓filter data before \"D\"",
|
||||
"info": "",
|
||||
"x": 520,
|
||||
"y": 1100,
|
||||
"x": 480,
|
||||
"y": 280,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "b848cdc7.61e06",
|
||||
"type": "comment",
|
||||
"z": "194a3e4f.a92772",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑join to single string",
|
||||
"info": "",
|
||||
"x": 670,
|
||||
"y": 1180,
|
||||
"x": 630,
|
||||
"y": 360,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": "84222b92.d65d18",
|
||||
"type": "inject",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "5132b95f037524f9",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
@@ -20,8 +20,8 @@
|
||||
"topic": "",
|
||||
"payload": "Hello, World!",
|
||||
"payloadType": "str",
|
||||
"x": 230,
|
||||
"y": 200,
|
||||
"x": 150,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"b4b9f603.739598"
|
||||
@@ -31,25 +31,25 @@
|
||||
{
|
||||
"id": "7b014430.dfd94c",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "5132b95f037524f9",
|
||||
"name": "Write string to a file, then read from the file",
|
||||
"info": "File node can write string to a file.",
|
||||
"x": 260,
|
||||
"y": 120,
|
||||
"info": "Write file node can write string from a file.",
|
||||
"x": 180,
|
||||
"y": 140,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "b4b9f603.739598",
|
||||
"type": "file",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "5132b95f037524f9",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "true",
|
||||
"encoding": "none",
|
||||
"x": 420,
|
||||
"y": 200,
|
||||
"x": 340,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"6dc01cac.5c4bf4"
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"id": "2587adb9.7e60f2",
|
||||
"type": "debug",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "5132b95f037524f9",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -68,22 +68,22 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 810,
|
||||
"y": 200,
|
||||
"x": 730,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "6dc01cac.5c4bf4",
|
||||
"type": "file in",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "5132b95f037524f9",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"format": "utf8",
|
||||
"chunk": false,
|
||||
"sendError": false,
|
||||
"encoding": "none",
|
||||
"x": 620,
|
||||
"y": 200,
|
||||
"x": 540,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"2587adb9.7e60f2"
|
||||
@@ -93,21 +93,21 @@
|
||||
{
|
||||
"id": "f4b4309a.3b78a",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "5132b95f037524f9",
|
||||
"name": "↑read result from file",
|
||||
"info": "",
|
||||
"x": 630,
|
||||
"y": 240,
|
||||
"x": 550,
|
||||
"y": 260,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "672d3693.3cabd8",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "5132b95f037524f9",
|
||||
"name": "↓write to /tmp/hello.txt",
|
||||
"info": "",
|
||||
"x": 440,
|
||||
"y": 160,
|
||||
"x": 360,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": "704479e1.399388",
|
||||
"type": "inject",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
@@ -25,8 +25,8 @@
|
||||
"topic": "",
|
||||
"payload": "Hello, World!",
|
||||
"payloadType": "str",
|
||||
"x": 230,
|
||||
"y": 400,
|
||||
"x": 190,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"402f3b7e.988014"
|
||||
@@ -36,25 +36,25 @@
|
||||
{
|
||||
"id": "8e876a75.e9beb8",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Write string to a file specied by filename property, the read from the file",
|
||||
"info": "File node can target file using `filename` property.",
|
||||
"x": 350,
|
||||
"y": 320,
|
||||
"info": "Write file node can target file using `filename` property.",
|
||||
"x": 310,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "402f3b7e.988014",
|
||||
"type": "file",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "true",
|
||||
"encoding": "none",
|
||||
"x": 390,
|
||||
"y": 400,
|
||||
"x": 350,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"26e077d6.bbcd98"
|
||||
@@ -64,7 +64,7 @@
|
||||
{
|
||||
"id": "97b6b6b2.a54b38",
|
||||
"type": "debug",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -73,22 +73,22 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 770,
|
||||
"y": 400,
|
||||
"x": 730,
|
||||
"y": 260,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "26e077d6.bbcd98",
|
||||
"type": "file in",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"format": "utf8",
|
||||
"chunk": false,
|
||||
"sendError": false,
|
||||
"encoding": "none",
|
||||
"x": 580,
|
||||
"y": 400,
|
||||
"x": 540,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"97b6b6b2.a54b38"
|
||||
@@ -98,21 +98,21 @@
|
||||
{
|
||||
"id": "85062297.da79",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑read result from file",
|
||||
"info": "",
|
||||
"x": 590,
|
||||
"y": 440,
|
||||
"x": 550,
|
||||
"y": 300,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "7316c4fc.b1dcdc",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓write to file specified by filename property",
|
||||
"info": "",
|
||||
"x": 500,
|
||||
"y": 360,
|
||||
"x": 460,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"id": "4ac00fb0.d5f52",
|
||||
"type": "inject",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"props": [
|
||||
{
|
||||
@@ -20,8 +20,8 @@
|
||||
"topic": "",
|
||||
"payload": "",
|
||||
"payloadType": "date",
|
||||
"x": 220,
|
||||
"y": 600,
|
||||
"x": 180,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"542cc2f4.92857c"
|
||||
@@ -31,25 +31,25 @@
|
||||
{
|
||||
"id": "671f8295.0e6f6c",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Delete a file",
|
||||
"info": "File node can delete a file.",
|
||||
"x": 170,
|
||||
"y": 540,
|
||||
"info": "Write file node can delete a file.",
|
||||
"x": 130,
|
||||
"y": 160,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "542cc2f4.92857c",
|
||||
"type": "file",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "delete",
|
||||
"encoding": "none",
|
||||
"x": 420,
|
||||
"y": 600,
|
||||
"x": 380,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"a24da523.5babe8"
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"id": "a24da523.5babe8",
|
||||
"type": "debug",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -68,18 +68,18 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 630,
|
||||
"y": 600,
|
||||
"x": 590,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "51157051.2f62",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓delete a file",
|
||||
"info": "",
|
||||
"x": 390,
|
||||
"y": 560,
|
||||
"x": 350,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -2,8 +2,8 @@
|
||||
{
|
||||
"id": "e4ef1f5e.7cd82",
|
||||
"type": "inject",
|
||||
"z": "4b63452d.672afc",
|
||||
"name": "",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Base64 encoded string",
|
||||
"props": [
|
||||
{
|
||||
"p": "payload"
|
||||
@@ -20,8 +20,8 @@
|
||||
"topic": "",
|
||||
"payload": "8J+YgA==",
|
||||
"payloadType": "str",
|
||||
"x": 220,
|
||||
"y": 820,
|
||||
"x": 200,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"72b37cc8.177054"
|
||||
@@ -31,25 +31,25 @@
|
||||
{
|
||||
"id": "f5997af4.5a9298",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "Specify encoding of written data",
|
||||
"info": "File node can specify encoding of data.",
|
||||
"x": 230,
|
||||
"y": 740,
|
||||
"info": "Write file node can specify encoding of data.",
|
||||
"x": 170,
|
||||
"y": 140,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "72b37cc8.177054",
|
||||
"type": "file",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"appendNewline": true,
|
||||
"createDir": false,
|
||||
"overwriteFile": "true",
|
||||
"encoding": "base64",
|
||||
"x": 400,
|
||||
"y": 820,
|
||||
"x": 420,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"2da33ec.f45cac2"
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"id": "2e814354.278c8c",
|
||||
"type": "debug",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
@@ -68,22 +68,22 @@
|
||||
"complete": "false",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 790,
|
||||
"y": 820,
|
||||
"x": 810,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "2da33ec.f45cac2",
|
||||
"type": "file in",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "",
|
||||
"filename": "/tmp/hello.txt",
|
||||
"format": "utf8",
|
||||
"chunk": false,
|
||||
"sendError": false,
|
||||
"encoding": "none",
|
||||
"x": 600,
|
||||
"y": 820,
|
||||
"x": 620,
|
||||
"y": 220,
|
||||
"wires": [
|
||||
[
|
||||
"2e814354.278c8c"
|
||||
@@ -93,21 +93,21 @@
|
||||
{
|
||||
"id": "ec754c99.84bfd",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↓write string with base64 encoding",
|
||||
"info": "",
|
||||
"x": 460,
|
||||
"y": 780,
|
||||
"x": 480,
|
||||
"y": 180,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "3e6704ff.4ce25c",
|
||||
"type": "comment",
|
||||
"z": "4b63452d.672afc",
|
||||
"z": "6312c0588348b2d4",
|
||||
"name": "↑read result from file",
|
||||
"info": "",
|
||||
"x": 610,
|
||||
"y": 860,
|
||||
"x": 630,
|
||||
"y": 260,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
@@ -25,7 +25,7 @@
|
||||
<dd>Optional nutzbare Nachrichten-Eigenschaft.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Der <span style="background-color:Gainsboro">inject</span>-Node kann einen Flow mit einstellbaren Nutzdaten (Payload) starten.
|
||||
<p>Der inject-Node kann einen Flow mit einstellbaren Nutzdaten (Payload) starten.
|
||||
Der voreingestellte Payload ist die aktuelle Zeit als Zeitstempel in Millisekunden
|
||||
seit Beginn der Unix-Zeitrechnung (1. Januar 1970 UTC).</p>
|
||||
<p>Der Node unterstützt auch die Injektion von Zeichenfolgen, Zahlenwerten, Booleschen Werten,
|
||||
@@ -34,7 +34,7 @@
|
||||
Er kann auch in regelmäßigen Intervallen oder nach einem Zeitplan injizieren.</p>
|
||||
<p>Er kann auch so eingestellt werden, dass er jedes Mal einen Wert injiziert, wenn der Flow gestartet wird.</p>
|
||||
<p>Das maximal einstellbare Intervall beträgt etwa 596 Stunden bzw. 24 Tage.
|
||||
Wenn jedoch Intervalle größer als 24h benötigt werden, sollte ein <span style="background-color:Gainsboro">scheduler</span>-Node verwendet werden,
|
||||
Wenn jedoch Intervalle größer als 24h benötigt werden, sollte ein scheduler-Node verwendet werden,
|
||||
der mit Stromausfällen und Neustarts besser umgehen kann.</p>
|
||||
<p><b>Hinweis</b>: Die Optionen <i>"Intervall zwischen Uhrzeiten"</i> und <i>"Täglicher Zeitpunkt"</i>
|
||||
verwenden das Standard-Cron-System.</p>
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
<p>JavaScript-Objekte und -Arrays können nach Bedarf ein- und ausgeblendet werden.
|
||||
Binäre Puffer-Objekte (buffer objects) können nach Möglichkeit als Rohdaten oder als Zeichenfolge (string) angezeigt werden.</p>
|
||||
<p>Neben der eigentlichen Nachricht werden im Debug-Tab auch der Empfangszeitpunkt,
|
||||
der empfangende <span style="background-color:Gainsboro">debug</span>-Node, sowie Name und Typ der Nachricht protokolliert.
|
||||
Durch Klicken auf die Node-ID wird der entsprechende <span style="background-color:Gainsboro">debug</span>-Node im Arbeitsbereich angezeigt.</p>
|
||||
<p>Die Schaltfläche des <span style="background-color:Gainsboro">debug</span>-Nodes kann verwendet werden, um die Debug-Ausgabe ein- und auszuschalten.
|
||||
Es ist empfehlenswert, alle nicht verwendeten <span style="background-color:Gainsboro">debug</span>-Nodes zu deaktivieren oder gleich zu entfernen.</p>
|
||||
<p>Der <span style="background-color:Gainsboro">debug</span>-Node kann auch so eingestellt werden, dass außerdem alle Nachrichten in der Systemkonsole ausgegeben und/oder
|
||||
als kurze Statustexte (max. 32 Zeichen) unter dem <span style="background-color:Gainsboro">debug</span>-Node angezeigt werden.</p>
|
||||
der empfangende debug-Node, sowie Name und Typ der Nachricht protokolliert.
|
||||
Durch Klicken auf die Node-ID wird der entsprechende debug-Node im Arbeitsbereich angezeigt.</p>
|
||||
<p>Die Schaltfläche des debug-Nodes kann verwendet werden, um die Debug-Ausgabe ein- und auszuschalten.
|
||||
Es ist empfehlenswert, alle nicht verwendeten debug-Nodes zu deaktivieren oder gleich zu entfernen.</p>
|
||||
<p>Der debug-Node kann auch so eingestellt werden, dass außerdem alle Nachrichten in der Systemkonsole ausgegeben und/oder
|
||||
als kurze Statustexte (max. 32 Zeichen) unter dem debug-Node angezeigt werden.</p>
|
||||
</script>
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
<p>Anstoß eines weiteren Flows, wenn ein anderer Node seine Nachrichtenbearbeitung abgeschlossen hat.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Wenn ein Node die Bearbeitung seiner Nachrichten abgeschlossen hat,
|
||||
kann der <span style="background-color:Gainsboro">complete</span>-Node dazu benutzt werden, einen weiteren Flow anzustoßen.</p>
|
||||
kann der complete-Node dazu benutzt werden, einen weiteren Flow anzustoßen.</p>
|
||||
<p>Der Node kann z.B. mit einem anderen Node ohne Ausgang verknüpft werden
|
||||
(z.B. E-Mail-Sende-Node), um den Flow fortzusetzen.</p>
|
||||
<p>Im Node werden dazu die zu überwachenden Nodes des selben Flows ausgewählt.
|
||||
Im Gegensatz zum <span style="background-color:Gainsboro">catch</span>-Node besteht hier jedoch nicht die Auswahlmöglichkeit aller Nodes des Flows.</p>
|
||||
Im Gegensatz zum catch-Node besteht hier jedoch nicht die Auswahlmöglichkeit aller Nodes des Flows.</p>
|
||||
<p>Nicht alle Nodes können diesen Node anstoßen.
|
||||
Es hängt davon ab, ob die auslösenden Knoten diese Funktion unterstützen,
|
||||
welche erst mit Node-RED 1.0 eingeführt wurde.</p>
|
||||
|
||||
@@ -29,13 +29,13 @@
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Wenn ein Node bei der Verarbeitung einer Nachricht einen Fehler verursacht, wird der Flow in der Regel angehalten.
|
||||
Der <span style="background-color:Gainsboro">catch</span>-Node kann verwendet werden, um diese Fehler abzufangen und sie mit einem dedizierten Flow zu bearbeiten.</p>
|
||||
Der catch-Node kann verwendet werden, um diese Fehler abzufangen und sie mit einem dedizierten Flow zu bearbeiten.</p>
|
||||
<p>Der Node fängt standardmäßig die Fehler aller Nodes im selben Flow ab.
|
||||
Alternativ kann er auch an bestimmte Nodes gebunden werden.</p>
|
||||
<p>Wenn ein Fehler ausgelöst wird, empfangen alle angebundenen <span style="background-color:Gainsboro">catch</span>-Nodes die Fehlermeldung.</p>
|
||||
<p>Wenn ein Fehler in einem Subflow ausgelöst wird, wird der Fehler von einem <span style="background-color:Gainsboro">catch</span>-Node
|
||||
<p>Wenn ein Fehler ausgelöst wird, empfangen alle angebundenen catch-Nodes die Fehlermeldung.</p>
|
||||
<p>Wenn ein Fehler in einem Subflow ausgelöst wird, wird der Fehler von einem catch-Node
|
||||
innerhalb des Subflows abgefangen.
|
||||
Wenn im Subflow keine <span style="background-color:Gainsboro">catch</span>-Nodes vorhanden sind, wird die Fehlermeldung eine Ebene höher zum Flow weitergereicht,
|
||||
Wenn im Subflow keine catch-Nodes vorhanden sind, wird die Fehlermeldung eine Ebene höher zum Flow weitergereicht,
|
||||
in der sich die Subflow-Instanz befindet.</p>
|
||||
<p>Wenn die Nachricht bereits über eine <code>error</code>-Eigenschaft verfügt, wird sie nach <code>_error</code> kopiert.</p>
|
||||
</script>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<script type="text/html" data-help-name="link in">
|
||||
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Der Node kann mit jedem beliebigen <span style="background-color:Gainsboro">link out</span>-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
<p>Der Node kann mit jedem beliebigen link out-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
|
||||
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
|
||||
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,
|
||||
@@ -28,7 +28,7 @@
|
||||
<script type="text/html" data-help-name="link out">
|
||||
<p>Erstellung virtueller Verbindungen (Links) zwischen Flows.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Der Node kann mit jedem beliebigen <span style="background-color:Gainsboro">link in</span>-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
<p>Der Node kann mit jedem beliebigen link in-Node in einen beliebigen Flow-Tab verlinkt werden.
|
||||
Sobald sie verlinkt sind, verhalten sie sich so, als wären sie direkt miteinander verbunden.</p>
|
||||
<p>Die Links zwischen Link-Nodes werden nur angezeigt, wenn ein Link-Node ausgewählt ist.
|
||||
Wenn Links zu anderen Flow-Tabs vorhanden sind, werden virtuelle Link-Nodes als Gegenparts angezeigt,
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<li><code>node.error("Fehlermeldungstext")</code></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>Der <span style="background-color:Gainsboro">catch</span>-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
|
||||
<p>Der catch-Node kann auch zur Bearbeitung von Fehlern verwendet werden.
|
||||
Er wird aufgerufen, indem <code>msg</code> als zweites Argument an <code>node.error</code> übergeben wird:</p>
|
||||
<pre>node.error("Fehlermeldungstext" ,msg);</pre>
|
||||
<h4><b>Zugriff auf Node-Informationen</b></h4>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<ol>
|
||||
<li><b>value rules</b>: Regeln werden hinsichtlich einer eingestellten Eigenschaft ausgewertet</li>
|
||||
<li><b>sequence rules</b>: Regeln beziehen sich auf Nachrichtensequenzen,
|
||||
wie sie beispielsweise durch den <span style="background-color:Gainsboro">split</span>-Node erzeugt werden</li>
|
||||
wie sie beispielsweise durch den split-Node erzeugt werden</li>
|
||||
<li>Ein <b>JSONata-Ausdruck</b> kann die gesamte Eingangsnachricht auswerten und einen <code>true</code>-Wert zurückliefern,
|
||||
um eine Regelerfüllung zu signalisieren</li>
|
||||
<li>Die <b>ansonsten</b>-Regel wird angewendet, wenn keine vorhergehende Regel übereinstimmt</li>
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
<dt class="optional">payload <span class="property-type">string</span></dt>
|
||||
<dd>Wird an auszuführenden Befehl angehängt, sofern im Node aktiviert.</dd>
|
||||
<dt class="optional">kill <span class="property-type">string</span></dt>
|
||||
<dd>Typ des Kill-Signals, das an den zu beendenden <span style="background-color:Gainsboro">exec</span>-Node-Prozess gesendet wird.</dd>
|
||||
<dd>Typ des Kill-Signals, das an den zu beendenden exec-Node-Prozess gesendet wird.</dd>
|
||||
<dt class="optional">pid <span class="property-type">number | string</span></dt>
|
||||
<dd>Prozess-ID des zu beendenden <span style="background-color:Gainsboro">exec</span>-Node-Prozesses.</dd>
|
||||
<dd>Prozess-ID des zu beendenden exec-Node-Prozesses.</dd>
|
||||
</dl>
|
||||
<h3>Ausgangsdaten</h3>
|
||||
<ol class="node-ports">
|
||||
@@ -75,7 +75,7 @@
|
||||
<p>Die zurückgegebenen Daten (Payload) sind in der Regel eine <i>Zeichenfolge (string)</i>,
|
||||
außer es werden nicht UTF-8-Zeichen wie bei einem <i>binären Puffer (buffer)</i> erkannt.</p>
|
||||
<p>Bei einem aktiven Node werden Status und die PID angezeigt.
|
||||
Änderungen können mittels <span style="background-color:Gainsboro">status</span>-Node gelesen werden.</p>
|
||||
Änderungen können mittels status-Node gelesen werden.</p>
|
||||
<h4><b>Prozesse beenden</b></h4>
|
||||
<p>Durch Senden von <code>msg.kill</code> wird ein einzelner aktiver Prozess beendet.
|
||||
<code>msg.kill</code> sollte als Zeichenfolge (string) den Signaltyp enthalten,
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
"label": {
|
||||
"source": "Fehler abfangen von",
|
||||
"selectAll": "Alles auswählen",
|
||||
"uncaught": "Fehler ignorieren, die von anderen <span style=\"background-color:Gainsboro\">catch</span>-Nodes behandelt wurden"
|
||||
"uncaught": "Fehler ignorieren, die von anderen catch-Nodes behandelt wurden"
|
||||
},
|
||||
"scope": {
|
||||
"all": "allen Nodes",
|
||||
@@ -475,12 +475,12 @@
|
||||
"json": "Ein parsed JSON-Objekt",
|
||||
"tip": {
|
||||
"in": "Die URL ist relativ zu ",
|
||||
"res": "Die an diesen Node gesendeten Nachrichten <b>müssen</b> von einem <span style=\"background-color:Gainsboro\">http in</span>-Node stammen",
|
||||
"res": "Die an diesen Node gesendeten Nachrichten <b>müssen</b> von einem http in-Node stammen",
|
||||
"req": "Tipp: Wenn die JSON-Syntax-Analyse fehlschlägt, wird die abgerufene Zeichenfolge zurückgegeben, wie sie ist."
|
||||
},
|
||||
"httpreq": "http request",
|
||||
"errors": {
|
||||
"not-created": "<span style=\"background-color:Gainsboro\">http in</span>-Node kann nicht erstellt werden, wenn httpNodeRoot auf 'false' gesetzt ist.",
|
||||
"not-created": "http in-Node kann nicht erstellt werden, wenn httpNodeRoot auf 'false' gesetzt ist.",
|
||||
"missing-path": "Fehlender Pfad",
|
||||
"no-response": "Kein Antwort-Objekt",
|
||||
"json-error": "JSON-Parse-Fehler",
|
||||
@@ -499,7 +499,8 @@
|
||||
"label": {
|
||||
"type": "Typ",
|
||||
"path": "Pfad",
|
||||
"url": "URL"
|
||||
"url": "URL",
|
||||
"subprotocol": "Subprotokoll"
|
||||
},
|
||||
"listenon": "Lauschen (listen on)",
|
||||
"connectto": "Verbinden mit",
|
||||
@@ -684,7 +685,7 @@
|
||||
},
|
||||
"errors": {
|
||||
"invalid-expr": "Ungültiger JSONata-Ausdruck: __error__",
|
||||
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">switch</span>-Node"
|
||||
"too-many": "Zu viele anstehende Nachrichten im switch-Node"
|
||||
}
|
||||
},
|
||||
"change": {
|
||||
@@ -851,7 +852,6 @@
|
||||
"outputas": "Ausgabe",
|
||||
"breakchunks": "In Chunks aufteilen",
|
||||
"breaklines": "In Linien aufteilen",
|
||||
"filelabel": "file",
|
||||
"sendError": "Nachricht bei Fehler senden (herkömmlicher Modus)",
|
||||
"encoding": "Kodierung",
|
||||
"deletelabel": "lösche __file__",
|
||||
@@ -940,8 +940,8 @@
|
||||
"afterTimeout": "Bei Zeitablauf nach erster Nachricht von",
|
||||
"seconds": "Sekunden",
|
||||
"complete": "Nach Nachricht mit <code>msg.complete</code>-Eigenschaft",
|
||||
"tip": "Dieser Modus setzt voraus, dass dieser Node entweder mit einem <span style=\"background-color:Gainsboro\">split</span>-Node kombiniert ist oder dass die empfangenen Nachrichten über eine ordnungsgemäß konfigurierte <code>msg.parts</code>-Eigenschaft verfügen.",
|
||||
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">join</span>-Node",
|
||||
"tip": "Dieser Modus setzt voraus, dass dieser Node entweder mit einem split-Node kombiniert ist oder dass die empfangenen Nachrichten über eine ordnungsgemäß konfigurierte <code>msg.parts</code>-Eigenschaft verfügen.",
|
||||
"too-many": "Zu viele anstehende Nachrichten im join-Node",
|
||||
"merge": {
|
||||
"topics-label": "Zusammengeführte Topics",
|
||||
"topics": "Topics",
|
||||
@@ -970,9 +970,9 @@
|
||||
"ascending": "aufsteigend",
|
||||
"descending": "absteigend",
|
||||
"as-number": "als Zahlenwert",
|
||||
"invalid-exp": "Ungültiger JSONata-Ausdruck in <span style=\"background-color:Gainsboro\">sort</span>-Node: __message__",
|
||||
"too-many": "Zu viele anstehende Nachrichten in <span style=\"background-color:Gainsboro\">sort</span>-Node",
|
||||
"clear": "Anstehende Nachricht in <span style=\"background-color:Gainsboro\">sort</span>-Node löschen"
|
||||
"invalid-exp": "Ungültiger JSONata-Ausdruck in sort-Node: __message__",
|
||||
"too-many": "Zu viele anstehende Nachrichten in sort-Node",
|
||||
"clear": "Anstehende Nachricht in sort-Node löschen"
|
||||
},
|
||||
"batch": {
|
||||
"batch": "batch",
|
||||
@@ -997,7 +997,7 @@
|
||||
"topics-label": "Topics",
|
||||
"topic": "Topic"
|
||||
},
|
||||
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">batch</span>-Node",
|
||||
"too-many": "Zu viele anstehende Nachrichten im batch-Node",
|
||||
"unexpected": "Unerwarteter Modus",
|
||||
"no-parts": "Keine parts-Eigenschaft in Nachricht"
|
||||
},
|
||||
|
||||
@@ -94,8 +94,8 @@
|
||||
<script type="text/html" data-help-name="mqtt-broker">
|
||||
<p>Konfiguration der Verbindung zu einem MQTT-Broker.</p>
|
||||
<p>Diese Konfiguration erstellt eine einzelne Verbindung zu einem Broker,
|
||||
welche anschließend von den <span style="background-color:Gainsboro">mqtt in</span>- und
|
||||
<span style="background-color:Gainsboro">mqtt out</span>-Nodes verwendet werden.</p>
|
||||
welche anschließend von den mqtt in- und
|
||||
mqtt out-Nodes verwendet werden.</p>
|
||||
<p>Der Node generiert eine beliebige Client-ID, falls sie nicht vorgegeben ist und der
|
||||
Node eine bereinigte Sitzung (clean session) verwenden soll.
|
||||
Wenn eine Client-ID vorgegeben wird, muss sie für den Broker eindeutig sein, zu dem die Verbindung hergestellt werden soll.</p>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<dt>res <span class="property-type">object</span></dt>
|
||||
<dd>HTTP-Antwortobjekt.<br/>
|
||||
Diese Eigenschaft sollte nicht direkt verwendet werden.
|
||||
Im <span style="background-color:Gainsboro">http response</span>-Node ist dokumentiert, wie auf eine Anforderung reagiert wird.
|
||||
Im http response-Node ist dokumentiert, wie auf eine Anforderung reagiert wird.
|
||||
Diese Eigenschaft muss an der Nachricht angehängt bleiben, die an den Antwort-Node übergeben wird.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
@@ -50,12 +50,12 @@
|
||||
<p>Wenn der Inhaltstyp der Anforderung ermittelt werden kann, wird der Hauptteil als passender Typ analysiert.
|
||||
Z.B. <code>application/json</code> wird zu einem JavaScript-Objekt analysiert.</p>
|
||||
<p><b>Hinweis</b>: Dieser Node sendet keine Antwort an die Anforderung.
|
||||
Der Flow muss einen <span style="background-color:Gainsboro">http response</span>-Node enthalten,
|
||||
Der Flow muss einen http response-Node enthalten,
|
||||
um die Anforderung zu vervollständigen.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="http response">
|
||||
<p>Senden von Antworten auf Anforderungen, die von einem <span style="background-color:Gainsboro">http in</span>-Node empfangen wurden.</p>
|
||||
<p>Senden von Antworten auf Anforderungen, die von einem http in-Node empfangen wurden.</p>
|
||||
<h3>Eingangsdaten</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string</span></dt>
|
||||
|
||||
@@ -34,17 +34,17 @@
|
||||
</ul>
|
||||
</dd>
|
||||
<dt>schemaError <span class="property-type">array</span></dt>
|
||||
<dd>Wenn die JSON-Schema-Validierung fehlschlägt, wird für den <span style="background-color:Gainsboro">catch</span>-Node eine <code>schemaError</code>-Eigenschaft erstellt,
|
||||
<dd>Wenn die JSON-Schema-Validierung fehlschlägt, wird für den catch-Node eine <code>schemaError</code>-Eigenschaft erstellt,
|
||||
die ein Array von Fehlern enthält.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Standardmäßig verarbeitet der Node <code>msg.payload</code>,
|
||||
kann aber auch eine beliebige Nachrichteneigenschaft konvertieren.</p>
|
||||
<p>Die Konvertierungsrichtung kann im Node auch vorgegeben werden, um eine bestimmte Ziel-Kodierung sicherzustellen.
|
||||
Dies kann z.B. zusammen mit dem <span style="background-color:Gainsboro">http in</span>-Node benutzt werden, um sicherzustellen,
|
||||
Dies kann z.B. zusammen mit dem http in-Node benutzt werden, um sicherzustellen,
|
||||
dass die Nutzdaten (Payload) ein analysiertes (parsed) Objekt ist,
|
||||
auch wenn eine eingehende Anfrage seinen Inhaltstyp nicht korrekt eingestellt hat,
|
||||
damit der <span style="background-color:Gainsboro">http in</span>-Node die Konvertierung durchführen kann.</p>
|
||||
damit der http in-Node die Konvertierung durchführen kann.</p>
|
||||
<p>Wenn der Node auf Zeichenfolgen-Eingang (string) eingestellt ist und es einen String empfängt,
|
||||
werden keine weiteren Prüfungen der Eigenschaft durchgeführt.
|
||||
Der Node prüft weder, ob die Zeichenfolge (string) ein gültiges JSON enthält, noch wird er ihn neu formatieren,
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<dl class="message-properties">
|
||||
<dt>parts <span class="property-type">object</span></dt>
|
||||
<dd>Diese Eigenschaft enthält Informationen darüber, wie die Nachricht von der ursprünglichen Nachricht abgeteilt wurde.
|
||||
Bei Übergabe an ein <span style="background-color:Gainsboro">join</span>-Node kann die Sequenz wieder zu einer einzigen Nachricht zusammengeführt werden.
|
||||
Bei Übergabe an ein join-Node kann die Sequenz wieder zu einer einzigen Nachricht zusammengeführt werden.
|
||||
Diese Eigenschaft hat die folgenden Eigenschaften:
|
||||
<ul>
|
||||
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
|
||||
@@ -48,7 +48,7 @@
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>Dieser Node macht es einfach, einen Flow zu erstellen, der gemeinsame Aktionen über eine Sequenz von Nachrichten ausführt,
|
||||
bevor die Sequenz mittels <span style="background-color:Gainsboro">join</span>-Node wieder zu einer einzigen Nachricht neu kombiniert wird.</p>
|
||||
bevor die Sequenz mittels join-Node wieder zu einer einzigen Nachricht neu kombiniert wird.</p>
|
||||
<p>Der Node verwendet die <code>msg.parts</code>-Eigenschaft, um die einzelnen Sequenzteile nachzuverfolgen.</p>
|
||||
<h4><b>Streaming-Modus</b></h4>
|
||||
<p>Der Node kann auch zum Aufbereiten eines Nachrichtenstroms verwendet werden.
|
||||
@@ -59,7 +59,7 @@
|
||||
so wird es im Node aufbewahrt und der nächsten empfangenen Nachricht vorangestellt.</p>
|
||||
<p>In diesem Modus wird die <code>msg.parts.count</code>-Eigenschaft nicht gesetzt,
|
||||
da die Anzahl der zu erwartenden Nachrichten im Stream unbekannt ist.
|
||||
Das bedeutet, dass ein nachfolgender <span style="background-color:Gainsboro">join</span>-Node nicht im Automatikmodus verwendet werden kann.</p>
|
||||
Das bedeutet, dass ein nachfolgender join-Node nicht im Automatikmodus verwendet werden kann.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="join">
|
||||
@@ -67,7 +67,7 @@
|
||||
<p>Es sind drei Modi verfügbar:</p>
|
||||
<dl>
|
||||
<dt>Automatisch</dt>
|
||||
<dd>In Kombination mit dem <span style="background-color:Gainsboro">split</span>-Node verbindet es automatisch die Nachrichten, um die zuvor durchgeführte Aufteilung rückgängig zu machen.</dd>
|
||||
<dd>In Kombination mit dem split-Node verbindet es automatisch die Nachrichten, um die zuvor durchgeführte Aufteilung rückgängig zu machen.</dd>
|
||||
<dt>Manuell</dt>
|
||||
<dd>Die Nachrichtensequenzen können auf verschiedene Weisen verbunden werden.</dd>
|
||||
<dt>Sequenz reduzieren</dt>
|
||||
@@ -77,7 +77,7 @@
|
||||
<dl class="message-properties">
|
||||
<dt class="optional">parts <span class="property-type">object</span></dt>
|
||||
<dd>Zur automatischen Verbindung einer Nachrichtensequenz sollten alle über diese Eigenschaft verfügen.
|
||||
Der <span style="background-color:Gainsboro">split</span>-Node erzeugt diese Eigenschaft, sie kann aber auch manuell erstellt werden.
|
||||
Der split-Node erzeugt diese Eigenschaft, sie kann aber auch manuell erstellt werden.
|
||||
Sie hat die folgenden Eigenschaften:
|
||||
<ul>
|
||||
<li><code>id</code>: Identifikator der Nachrichten-Gruppe</li>
|
||||
@@ -98,7 +98,7 @@
|
||||
<h4><b>Automatischer Modus</b></h4>
|
||||
<p>Der automatische Modus verwendet die <code>parts</code>-Eigenschaften der eingehenden Nachrichten,
|
||||
um die Sequenz in richtiger Reihenfolge zu verknüpften.
|
||||
Dies ermöglicht die Aufteilung des <span style="background-color:Gainsboro">split</span>-Nodes automatisch rückgängig zu machen.</p>
|
||||
Dies ermöglicht die Aufteilung des split-Nodes automatisch rückgängig zu machen.</p>
|
||||
|
||||
<h4><b>Manueller Modus</b></h4>
|
||||
<p>Im manuellen Modus werden Nachrichtensequenzen auf verschiedenen Arten zusammengefügt:</p>
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
<p>Für Zahlenwerte kann die numerische Sortierreihenfolge festgelegt werden.</p>
|
||||
<p>Der Sortierschlüssel kann ein Elementwert oder ein JSONata-Ausdruck beim Sortieren einer Nachrichteneigenschaft
|
||||
bzw. eine Nachrichteneigenschaft oder ein JSONata-Ausdruck beim Sortieren einer Nachrichtensequenz sein.<p>
|
||||
<p>Zum Sortieren einer Nachrichtensequenz benötigt der <span style="background-color:Gainsboro">sort</span>-Node die gesetzte <code>msg.parts</code>-Eigenschaft bei den empfangenen Nachrichten.
|
||||
Diese Eigenschaft wird vom <span style="background-color:Gainsboro">split</span>-Node erzeugt und kann aber auch manuell erzeugt werden.
|
||||
<p>Zum Sortieren einer Nachrichtensequenz benötigt der sort-Node die gesetzte <code>msg.parts</code>-Eigenschaft bei den empfangenen Nachrichten.
|
||||
Diese Eigenschaft wird vom split-Node erzeugt und kann aber auch manuell erzeugt werden.
|
||||
Sie hat die folgenden Eigenschaften:</p>
|
||||
<p>
|
||||
<ul>
|
||||
|
||||
@@ -58,5 +58,5 @@
|
||||
aber typischerweise 64k (Linux/Mac) oder 41k (Windows).</p>
|
||||
<p>Bei Aufteilung in mehrere Nachrichten besitzt jede eine <code>parts</code>-Eigenschaft,
|
||||
welche eine komplette Nachrichten-Sequenz bildet.</p>
|
||||
<p>Fehler sollten mittels <span style="background-color:Gainsboro">catch</span>-Nodes abgefangen und behandelt werden.</p>
|
||||
<p>Fehler sollten mittels catch-Nodes abgefangen und behandelt werden.</p>
|
||||
</script>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<dt>msg <span class="property-type">object</span></dt>
|
||||
<dd>A msg object containing information to populate the template.</dd>
|
||||
<dt class="optional">template <span class="property-type">string</span></dt>
|
||||
<dd>A template to be populated from msg.payload. If not configured in the edit panel,
|
||||
<dd>A template to be populated from <code>msg.payload</code>. If not configured in the edit panel,
|
||||
this can be set as a property of msg.</dd>
|
||||
</dl>
|
||||
<h3>Outputs</h3>
|
||||
|
||||
@@ -60,5 +60,5 @@
|
||||
for the next topic.
|
||||
</p>
|
||||
<p><b>Note</b>: In rate limit mode the maximum queue depth can be set by a property in your
|
||||
<i>settings.js</i> file. For example <code>nodeMessageBufferMaxLength: 1000,</code>
|
||||
<i>settings.js</i> file. For example <code>nodeMessageBufferMaxLength: 1000,</code></p>
|
||||
</script>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<h3>Details</h3>
|
||||
<p>In RBE mode this node will block until the <code>msg.payload</code>,
|
||||
(or selected property) value is different to the previous one.
|
||||
If required it can ignore the intial value, so as not to send anything at start.</p>
|
||||
If required it can ignore the initial value, so as not to send anything at start.</p>
|
||||
<p>The <a href="https://en.wikipedia.org/wiki/Deadband" target="_blank">Deadband</a> modes will block the incoming value
|
||||
<i>unless</i> its change is greater or greater-equal than ± the band gap away from a previous value.</p>
|
||||
<p>The Narrowband modes will block the incoming value,
|
||||
@@ -37,5 +37,5 @@
|
||||
ignoring any values out of range, or the previous input value, which resets the set point, thus allowing
|
||||
gradual drift (deadband), or a step change (narrowband).</p>
|
||||
<p><b>Note:</b> This works on a per <code>msg.topic</code> basis, though this can be changed to another property if desired.
|
||||
This means that a single rbe node can handle multiple different topics at the same time.</p>
|
||||
This means that a single filter node can handle multiple different topics at the same time.</p>
|
||||
</script>
|
||||
|
||||
@@ -530,7 +530,8 @@
|
||||
"label": {
|
||||
"type": "Type",
|
||||
"path": "Path",
|
||||
"url": "URL"
|
||||
"url": "URL",
|
||||
"subprotocol": "Subprotocol"
|
||||
},
|
||||
"listenon": "Listen on",
|
||||
"connectto": "Connect to",
|
||||
@@ -579,7 +580,9 @@
|
||||
"server": "Server",
|
||||
"return": "Return",
|
||||
"ms": "ms",
|
||||
"chars": "chars"
|
||||
"chars": "chars",
|
||||
"close": "Close",
|
||||
"optional": "(optional)"
|
||||
},
|
||||
"type": {
|
||||
"listen": "Listen on",
|
||||
@@ -596,7 +599,7 @@
|
||||
"return": {
|
||||
"timeout": "after a fixed timeout of",
|
||||
"character": "when character received is",
|
||||
"number": "a fixed number of chars",
|
||||
"number": "after a fixed number of characters",
|
||||
"never": "never - keep connection open",
|
||||
"immed": "immediately - don't wait for reply"
|
||||
},
|
||||
@@ -616,11 +619,11 @@
|
||||
"timeout": "timeout closed socket port __port__",
|
||||
"cannot-listen": "unable to listen on port __port__, error: __error__",
|
||||
"error": "error: __error__",
|
||||
|
||||
"socket-error": "socket error from __host__:__port__",
|
||||
"no-host": "Host and/or port not set",
|
||||
"connect-timeout": "connect timeout",
|
||||
"connect-fail": "connect failed"
|
||||
"connect-fail": "connect failed",
|
||||
"bad-string": "failed to convert to string"
|
||||
}
|
||||
},
|
||||
"udp": {
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<dt class="optional">topic <span class="property-type">string|object|array</span></dt>
|
||||
<dd>For the <code>"subscribe"</code> and <code>"unsubscribe"</code> actions, this property
|
||||
provides the topic. It can be set as either:<ul>
|
||||
<li>a String continaing the topic filter</li>
|
||||
<li>a String containing the topic filter</li>
|
||||
<li>an Object containing <code>topic</code> and <code>qos</code> properties</li>
|
||||
<li>an array of either strings or objects to handle multiple topics in one</li>
|
||||
</ul>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<dd>In case any redirects occurred while processing the request, this property is the final redirected url.
|
||||
Otherwise, the url of the original request.</dd>
|
||||
<dt>responseCookies <span class="property-type">object</span></dt>
|
||||
<dd>If the response includes cookies, this propery is an object of name/value pairs for each cookie.</dd>
|
||||
<dd>If the response includes cookies, this property is an object of name/value pairs for each cookie.</dd>
|
||||
<dt>redirectList <span class="property-type">array</span></dt>
|
||||
<dd>If the request was redirected one or more times, the accumulated information will be added to this property. `location` is the next redirect destination. `cookies` is the cookies returned from the redirect source.</dd>
|
||||
</dl>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
</p>
|
||||
<p>When operating in this mode, the node will not set the <code>msg.parts.count</code>
|
||||
property as it does not know how many messages to expect in the stream. This
|
||||
means it cannot be used with the <b>join</b> node in its automatic mode</p>
|
||||
means it cannot be used with the <b>join</b> node in its automatic mode.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="join">
|
||||
|
||||
@@ -29,3 +29,12 @@
|
||||
<p>linkノード間のリンクはlinkノードを選択した場合にのみ表示されます。他のタブへのリンクがある場合には、仮想的なノードを表示します。この仮想的ノードをクリックすると、対応するタブに移動できます。</p>
|
||||
<p><b>注: </b>サブフローの外から中、もしくは、中から外へのリンクを作成することはできません。</p>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="link call">
|
||||
<p><code>link in</code> で始まり、応答を返すフローを呼び出します。</p>
|
||||
<h3>詳細</h3>
|
||||
<p>本ノードは、任意のタブ内に存在する <code>link in</code> ノードに接続できます。 接続先のフローは、`返却`モードが設定された <code>link out</code> ノードで終了する必要があります。</p>
|
||||
<p>本ノードはメッセージを受信すると、メッセージを接続した <code>link in</code> ノードへ渡します。
|
||||
その後、応答を待った後にメッセージを送信します。</o>
|
||||
<p>もし、設定したタイムアウト(デフォルト30秒)以内に応答がない場合は、<code>catch</code> ノードを用いてエラーをログに記録することもできます。</p>
|
||||
</script>
|
||||
|
||||
@@ -46,4 +46,6 @@
|
||||
<code>{{global[store].名前}}</code>を用います。
|
||||
</p>
|
||||
<p><b>注: </b>デフォルトでは、<i>mustache</i>形式は置換対象のHTML要素をエスケープします。これを抑止するには<code>{{{三重}}}</code>括弧形式を使います。</p>
|
||||
<p>もし、コンテンツの中で<code>{{ }}</code>を出力する必要がある場合は、テンプレートで使われる記号文字を変えることもできます。例えば、<code>[[ ]]</code>を代わりに用いるには、テンプレートの先頭に以下の行を追加します。</p>
|
||||
<pre>{{=[[ ]]=}}</pre>
|
||||
</script>
|
||||
|
||||
@@ -25,11 +25,14 @@
|
||||
<dt class="optional">reset</dt>
|
||||
<dd>受信メッセージでこのプロパティを任意の値に設定すると、ノードが保持する全ての未送信メッセージをクリアします。</dd>
|
||||
<dt class="optional">flush</dt>
|
||||
<dd>受信メッセージでこのプロパティを任意の値に設定すると、ノードが保持する全ての未送信メッセージを直ちに送信します。</dd>
|
||||
<dd>本プロパティに数値が設定されたメッセージを受信すると、直ちに指定された数のメッセージを送信します。もし他の型(例えば真偽型)が設定されている場合は、ノードが保持している全ての未送信メッセージを直ちに送信します。</dd>
|
||||
<dt class="optional">toFront</dt>
|
||||
<dd>流量制御モードにおいて、本プロパティに真偽型<code>true</code>が設定されたメッセージを受け取ると、キューの先頭に追加され、その後に送信されます。<code>msg.flush=1</code>と組み合わせて用いると、すぐに再送信できます。</dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>メッセージを遅延させるように設定する場合、遅延時間は固定値、範囲内の乱数値、メッセージ毎の動的な指定値のいずれかを指定できます。</p>
|
||||
<p>メッセージを遅延させるように設定する場合、遅延時間は固定値、範囲内の乱数値、メッセージ毎の動的な指定値のいずれかを指定できます。各メッセージは、到着時刻に基づいて、他のメッセージとは独立して遅延されます。</p>
|
||||
<p>流量制御する場合、メッセージは指定した時間間隔内に分散して送信します。キューに残っているメッセージ数はノードのステータスに表示されます。受け取った中間メッセージを破棄することも可能です。</p>
|
||||
<p>流量値を上書きできるように設定されている場合、新しい流量値はすぐに適用されます。この流量値は、再度変更されるまで、本ノードがリセットされるまで、またはフローが再実行されるまで有効です。</p>
|
||||
<p>流量制御は全てのメッセージに適用することも、<code>msg.topic</code>値でグループ化して適用することも可能です。グループ化すると、中間メッセージは自動的に破棄されます。時間間隔毎に全てのトピックの最新メッセージを送信するか、次のトピックの最新メッセージを送信するかを指定できます。</p>
|
||||
<p><b>注</b>: 流量制御モードでは、キューの大きさの最大値を<i>settings.js</i>ファイルのプロパティに設定できます。例えば、次の様な設定です。<code>nodeMessageBufferMaxLength: 1000,</code></p>
|
||||
</script>
|
||||
|
||||
@@ -27,5 +27,5 @@
|
||||
<p>不感帯モードでは%による指定もサポートしています。入力と前の値の差分がX%より大きな場合に出力を行います。</p>
|
||||
<p>狭帯域(narrowband)モードでは、前の値に対する差分が一定値より大きな場合に入力ペイロードをブロックします。このモードは、故障したセンサから発生する外れ値を無視する時などに有用です。</p>
|
||||
<p>不感帯モードと狭帯域モードでは、以前の有効出力値、もしくは、以前の入力値との比較ができます。有効出力値を用いると範囲外の値を無視することが、入力値を用いると設定点がリセットされるため漸次的変化(不感帯モード)もしくは段階的変化(狭帯域モード)が可能です。</p>
|
||||
<p><b>注:</b> このノードは<code>msg.topic</code>毎に動作します。そのため、ひとつのrbeノードで複数の異なるトピックを同時に扱うことができます。</p>
|
||||
<p><b>注:</b> このノードは<code>msg.topic</code>毎に動作します。そのため、ひとつのfilterノードで複数の異なるトピックを同時に扱うことができます。</p>
|
||||
</script>
|
||||
|
||||
@@ -144,11 +144,16 @@
|
||||
"filterCurrent": "現在のフロー",
|
||||
"debugNodes": "debugノード",
|
||||
"clearLog": "ログを削除",
|
||||
"clearFilteredLog": "選択したメッセージを削除",
|
||||
"filterLog": "ログのフィルタリング",
|
||||
"openWindow": "新しいウィンドウで開く",
|
||||
"copyPath": "パスをコピー",
|
||||
"copyPayload": "値をコピー",
|
||||
"pinPath": "展開を固定"
|
||||
"pinPath": "展開を固定",
|
||||
"selectAll": "全てを選択",
|
||||
"selectNone": "選択を外す",
|
||||
"all": "全て",
|
||||
"filtered": "選択したメッセージ"
|
||||
},
|
||||
"messageMenu": {
|
||||
"collapseAll": "全パスを折りたたむ",
|
||||
@@ -159,7 +164,15 @@
|
||||
},
|
||||
"link": {
|
||||
"linkIn": "link in",
|
||||
"linkOut": "link out"
|
||||
"linkOut": "link out",
|
||||
"linkCall": "link call",
|
||||
"linkOutReturn": "link return",
|
||||
"outMode": "モード",
|
||||
"sendToAll": "接続された全てのlinkノードへ送信",
|
||||
"returnToCaller": "link callノードへ返却",
|
||||
"error": {
|
||||
"missingReturn": "返却するノードの情報が存在しません"
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
"tls": "TLS設定",
|
||||
@@ -282,7 +295,9 @@
|
||||
"and": "回/",
|
||||
"rate": "流量",
|
||||
"msgper": "メッセージ/",
|
||||
"queuemsg": "中間メッセージをキューに追加",
|
||||
"dropmsg": "中間メッセージを削除",
|
||||
"sendmsg": "2番目の出力で中間メッセージを送信",
|
||||
"allowrate": "msg.rate(ミリ秒単位)で流量値を上書き",
|
||||
"label": {
|
||||
"delay": "delay",
|
||||
@@ -401,7 +416,11 @@
|
||||
"maximumPacketSize": "最大パケット長",
|
||||
"receiveMaximum": "最大受信数",
|
||||
"session": "セッション",
|
||||
"delay": "遅延"
|
||||
"delay": "遅延",
|
||||
"action": "動作",
|
||||
"staticTopic": "1つのトピックを購読",
|
||||
"dynamicTopic": "動的な購読",
|
||||
"auto-connect": "自動接続"
|
||||
},
|
||||
"sections-label": {
|
||||
"birth-message": "接続時の送信メッセージ(Birthメッセージ)",
|
||||
@@ -442,7 +461,10 @@
|
||||
"invalid-topic": "不正なトピックが設定されています",
|
||||
"nonclean-missingclientid": "「セッションの初期化」使用時に、クライアントIDが設定されていません",
|
||||
"invalid-json-string": "不正なJSON文字列",
|
||||
"invalid-json-parse": "JSON文字列のパースに失敗しました"
|
||||
"invalid-json-parse": "JSON文字列のパースに失敗しました",
|
||||
"invalid-action-action": "指定された動作が不正です",
|
||||
"invalid-action-alreadyconnected": "接続する前にブローカから切断してください",
|
||||
"invalid-action-badsubscription": "msg.topicが存在しないか不正です"
|
||||
}
|
||||
},
|
||||
"httpin": {
|
||||
@@ -478,6 +500,7 @@
|
||||
"proxy-config": "プロキシ設定",
|
||||
"use-proxyauth": "プロキシ認証を使用",
|
||||
"noproxy-hosts": "例外ホスト",
|
||||
"senderr": "2xx以外の応答をcatchノードへ送信",
|
||||
"utf8": "UTF8文字列",
|
||||
"binary": "バイナリバッファ",
|
||||
"json": "JSONオブジェクト",
|
||||
@@ -507,7 +530,8 @@
|
||||
"label": {
|
||||
"type": "種類",
|
||||
"path": "パス",
|
||||
"url": "URL"
|
||||
"url": "URL",
|
||||
"subprotocol": "サブプロトコル"
|
||||
},
|
||||
"listenon": "待ち受け",
|
||||
"connectto": "接続",
|
||||
@@ -703,13 +727,15 @@
|
||||
"delete": "delete __property__",
|
||||
"move": "move __property__",
|
||||
"changeCount": "change: __count__ rules",
|
||||
"regex": "正規表現を使用"
|
||||
"regex": "正規表現を使用",
|
||||
"deepCopy": "値のディープコピー"
|
||||
},
|
||||
"action": {
|
||||
"set": "値の代入",
|
||||
"change": "値の置換",
|
||||
"delete": "値の削除",
|
||||
"move": "値の移動",
|
||||
"toValue": "対象の値",
|
||||
"to": "対象の値",
|
||||
"search": "検索する文字列",
|
||||
"replace": "置換後の文字列"
|
||||
@@ -851,6 +877,8 @@
|
||||
},
|
||||
"file": {
|
||||
"label": {
|
||||
"write": "write file",
|
||||
"read": "read file",
|
||||
"filename": "ファイル名",
|
||||
"action": "動作",
|
||||
"addnewline": "メッセージの入力のたびに改行を追加",
|
||||
@@ -858,7 +886,6 @@
|
||||
"outputas": "出力形式",
|
||||
"breakchunks": "チャンクへ分割",
|
||||
"breaklines": "行へ分割",
|
||||
"filelabel": "file",
|
||||
"sendError": "エラーメッセージを送信(互換モード)",
|
||||
"encoding": "文字コード",
|
||||
"deletelabel": "delete __file__",
|
||||
|
||||
@@ -26,11 +26,46 @@
|
||||
<dd>0: 最大1度到着, 1: 一度以上到着, 2: 1度のみ到着</dd>
|
||||
<dt>retain <span class="property-type">真偽値</span></dt>
|
||||
<dd>真の場合、メッセージを保持。メッセージが古い値の場合があります。</dd>
|
||||
<dt class="optional">responseTopic <span class="property-type">文字列</span></dt>
|
||||
<dd><b>MQTTv5</b>: メッセージのMQTT応答トピック</dd>
|
||||
<dt class="optional">correlationData <span class="property-type">バッファ</span></dt>
|
||||
<dd><b>MQTTv5</b>: メッセージの相関データ</dd>
|
||||
<dt class="optional">contentType <span class="property-type">文字列</span></dt>
|
||||
<dd><b>MQTTv5</b>: ペイロードのコンテントタイプ</dd>
|
||||
<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>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>購読トピックにはMQTTのワイルドカード(+: 1レベル, #: 複数レベル)を含めることができます。</p>
|
||||
<p>このノードの利用のためには、MQTTブローカへの接続設定が必要です。この設定は鉛筆アイコンをクリックすることで行えます。</p>
|
||||
<p>MQTT(inおよびout)ノードはブローカへの接続設定を必要に応じて共有できます。</p>
|
||||
<h4>動的購読</h4>
|
||||
本ノードは、MQTTの接続と購読を動的に制御するよう設定できます。有効にすると、本ノードの入力にメッセージを渡すことで制御できます。
|
||||
<h3>入力</h3>
|
||||
<p>これらは、動的購読が設定されている場合のみ適用されます。</p>
|
||||
<dl class="message-properties">
|
||||
<dt>action <span class="property-type">文字列</span></dt>
|
||||
<dd>本ノードが行う動作の名前。利用可能な動作は<code>"connect"</code>、<code>"disconnect"</code>、<code>"subscribe"</code>、<code>"unsubscribe"</code>です。</dd>
|
||||
<dt class="optional">topic <span class="property-type">文字列|オブジェクト|配列</span></dt>
|
||||
<dd><code>"subscribe"</code>と<code>"unsubscribe"</code>の動作に対して、本プロパティはトピックを提供します。次のいずれかを設定できます:<ul>
|
||||
<li>トピックフィルターを含む文字列</li>
|
||||
<li><code>topic</code>と<code>qos</code>プロパティを持つオブジェクト</li>
|
||||
<li>複数のトピックを扱う文字列やオブジェクトの配列</li>
|
||||
</ul>
|
||||
</dd>
|
||||
<dt class="optional">broker <span class="property-type">broker</span> </dt>
|
||||
<dd><code>"connect"</code>の動作に対して、本プロパティは次の様な個々のブローカ設定を上書きします: <ul>
|
||||
<li><code>broker</code></li>
|
||||
<li><code>port</code></li>
|
||||
<li><code>url</code> - 完全な接続URLを提供するために、brokerとportを上書き</li>
|
||||
<li><code>username</code></li>
|
||||
<li><code>password</code></li>
|
||||
</ul>
|
||||
<p>本プロパティが設定され既にブローカが接続されている場合、<code>force</code>プロパティを設定しない限り、エラーがログに記録されます。設定された場合はブローカから切断され、新しい設定を適用して再接続します。</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="mqtt out">
|
||||
@@ -39,15 +74,24 @@
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">文字列 | バッファ</span></dt>
|
||||
<dd>発行するペイロード。プロパティが設定されていない場合には、メッセージは送信されません。空のメッセージを送信するには、プロパティに空文字列を設定します。</dd>
|
||||
|
||||
<dt class="optional">topic <span class="property-type">文字列</span></dt>
|
||||
<dd>発行対象のMQTTトピック</dd>
|
||||
|
||||
<dt class="optional">qos <span class="property-type">数値</span></dt>
|
||||
<dd>0: 最大一度到着, 1: 一度以上到着, 2: 一度のみ到着。デフォルトは0です。</dd>
|
||||
|
||||
<dt class="optional">retain <span class="property-type">真偽値</span></dt>
|
||||
<dd>真の場合、メッセージをブローカに保持します。デフォルトは偽です。</dd>
|
||||
<dt class="optional">responseTopic <span class="property-type">文字列</span></dt>
|
||||
<dd><b>MQTTv5</b>: メッセージのMQTT応答トピック</dd>
|
||||
<dt class="optional">correlationData <span class="property-type">バッファ</span></dt>
|
||||
<dd><b>MQTTv5</b>: メッセージの相関データ</dd>
|
||||
<dt class="optional">contentType <span class="property-type">文字列</span></dt>
|
||||
<dd><b>MQTTv5</b>: ペイロードのコンテントタイプ</dd>
|
||||
<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>
|
||||
<dt class="optional">topicAlias <span class="property-type">数値</span></dt>
|
||||
<dd><b>MQTTv5</b>: 使用するMQTTトピックエイリアス</dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p><code>msg.payload</code>を発行するメッセージのペイロードとして用います。ペイロードがオブジェクトの場合、送信の際にJSON文字列に変換します。ペイロードがバイナリバッファの場合、そのまま送信します。</p>
|
||||
@@ -55,6 +99,24 @@
|
||||
<p>同様に、QoSとretainもノードの設定、もしくは、ノードの設定が空の場合には、それぞれ<code>msg.qos</code>および<code>msg.retain</code>で指定できます。以前ブローカに保存したトピックをクリアするには、retainフラグを設定して当該トピックに空のメッセージを発行します。</p>
|
||||
<p>このノードの利用のためには、MQTTブローカへの接続設定が必要です。この設定は鉛筆アイコンをクリックすることで行えます。</p>
|
||||
<p>MQTT(inおよびout)ノードはブローカへの接続設定を必要に応じて共有できます。</p>
|
||||
|
||||
<h4>動的制御</h4>
|
||||
本ノードによって接続を動的に制御できます。本ノードが以下の制御メッセージのいずれかを受け取った際は、ペイロードと同じ様にパブリッシュされることはありません。
|
||||
<h3>入力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>action <span class="property-type">文字列</span></dt>
|
||||
<dd>本ノードが行う動作の名前。利用可能な動作は<code>"connect"</code>、<code>"disconnect"</code>、<code>"subscribe"</code>、<code>"unsubscribe"</code>です。</dd>
|
||||
<dt class="optional">broker <span class="property-type">broker</span> </dt>
|
||||
<dd><code>"connect"</code>の動作に対して、本プロパティは次の様な個々のブローカ設定を上書きします: <ul>
|
||||
<li><code>broker</code></li>
|
||||
<li><code>port</code></li>
|
||||
<li><code>url</code> - 完全な接続URLを提供するために、brokerとportを上書き</li>
|
||||
<li><code>username</code></li>
|
||||
<li><code>password</code></li>
|
||||
</ul>
|
||||
<p>本プロパティが設定され既にブローカが接続されている場合、<code>force</code>プロパティを設定しない限り、エラーがログに記録されます。設定された場合はブローカから切断され、新しい設定を適用して再接続します。</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="mqtt-broker">
|
||||
@@ -70,5 +132,4 @@
|
||||
<h4>WebSocket</h4>
|
||||
<p>WebSocketによる接続を行うように設定できます。WebSocketを利用するには、サーバフィールドに接続先のURIを完全な形式で記述します。以下に例を示します。</p>
|
||||
<pre>ws://example.com:4000/mqtt</pre>
|
||||
|
||||
</script>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<h3>詳細</h3>
|
||||
<p>「列名」にカラム名のリストを指定することができます。CSVからオブジェクトに変換を行う際、カラム名をプロパティ名として使用します。「列名」の代わりに、CSVデータの1行目にカラム名を含めることもできます。</p>
|
||||
<p>CSVへの変換を行う際には、オブジェクトから取り出すべきプロパティとその順序を「列名」を参照して決めます。</p>
|
||||
<p>列名がない場合、本ノードは<code>msg.columns</code>プロパティの単純なコンマ区切りリストを使用して、何を抽出するかを決定します。もしそれが存在しない場合、すべてのオブジェクトプロパティを見つけた順序で出力します。</p>
|
||||
<p>列名がない場合、本ノードは<code>msg.columns</code>プロパティの単純なコンマ区切りリストを使用して、何をどの順序で抽出するかを決定します。もし存在しない場合、すべてのオブジェクトプロパティを見つけた順序で出力します。</p>
|
||||
<p>入力が配列の場合には、「列名」はカラム名を表す行の出力指定がされた場合だけ用います。</p>
|
||||
<p>「数値を変換する」オプションがチェックされている場合、文字列型の数値が数値として返されます。つまり「1,"1.5",2」の真ん中の値が数値になります。</p>
|
||||
<p>「空の文字を含む」オプションがチェックされている場合、空の文字列が結果に返されます。つまり「"1","",3」の真ん中の値が空の文字列になります。</p>
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
<p>このモードで処理する際には、メッセージ数を予め知ることができないため、<code>msg.parts.count</code>プロパティは設定されません。従って、<b>join</b>ノードの「自動モード」と組み合わせることはできません。</p>
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/html" data-help-name="join">
|
||||
<p>メッセージ列を結合して一つのメッセージにします。</p>
|
||||
<p>メッセージの結合には次の3つのモードが利用できます。</p>
|
||||
@@ -80,6 +79,10 @@
|
||||
</dd>
|
||||
<dt class="optional">complete</dt>
|
||||
<dd>設定されている場合、本ノードはペイロードを追加し、保持しているメッセージを送信します。ペイロードを追加したくない場合は、msgから削除してください。</dd>
|
||||
<dt class="optional">reset</dt>
|
||||
<dd>設定されている場合、本ノードは部分的に完成したメッセージを送信せず、削除します。</dd>
|
||||
<dt class="optional">restartTimeout</dt>
|
||||
<dd>設定されている場合、本ノードにタイムアウトが設定され、そのタイムアウトを用いて処理が再開されます。</dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
|
||||
@@ -96,7 +99,7 @@
|
||||
</ul>
|
||||
<p>出力メッセージのその他のプロパティはメッセージを送信する直前のメッセージをコピーします。</p>
|
||||
<p>「<i>合計値</i>」には出力メッセージを送信する前に受信すべきメッセージ数を指定します。オブジェクト出力の場合、この合計値に達すると後続メッセージの到着毎にメッセージを出力するように設定することもできます。</p>
|
||||
<p>「<i>秒</i>」には新規メッセージを送信するまでの経過時間を設定します。</p>
|
||||
<p>「<i>秒</i>」には新規メッセージを送信するまでの経過時間を設定します。<code>msg.restartTimeout</code>プロパティを設定したメッセージを渡すことで、指定した時間で再開できます。</p>
|
||||
<p><code>msg.complete</code>プロパティを設定したメッセージを受信すると、出力メッセージを送信します。この時、メッセージ列の数をリセットします。</p>
|
||||
<p><code>msg.reset</code>プロパティを設定したメッセージを受信すると、部分的に受信済みのメッセージを破棄します。これらのメッセージは送信されません。この時、メッセージ列の数をリセットします。</p>
|
||||
|
||||
|
||||
@@ -433,7 +433,8 @@
|
||||
"label": {
|
||||
"type": "종류",
|
||||
"path": "패스",
|
||||
"url": "URL"
|
||||
"url": "URL",
|
||||
"subprotocol": "서브 프로토콜"
|
||||
},
|
||||
"listenon": "대기",
|
||||
"connectto": "접속",
|
||||
@@ -771,7 +772,6 @@
|
||||
"outputas": "출력형식",
|
||||
"breakchunks": "청크로 분할",
|
||||
"breaklines": "행으로 분할",
|
||||
"filelabel": "file",
|
||||
"sendError": "에러메세지를 송신(호환모드)",
|
||||
"deletelabel": "delete __file__",
|
||||
"utf8String": "UTF8문자열",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user