Compare commits

..

1 Commits

Author SHA1 Message Date
Dave Conway-Jones
260ac94dc7 set node width dependent on gridsize
(up to 50 - then use half sizes or quarters etc)
2021-11-11 14:56:09 +00:00
107 changed files with 3587 additions and 2394 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "2.2.0-beta.1",
"version": "2.1.3",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -26,31 +26,31 @@
}
],
"dependencies": {
"acorn": "8.7.0",
"acorn": "8.5.0",
"acorn-walk": "8.2.0",
"ajv": "8.8.2",
"ajv": "8.6.3",
"async-mutex": "0.3.2",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.19.1",
"body-parser": "1.19.0",
"cheerio": "1.0.0-rc.10",
"clone": "2.1.2",
"content-type": "1.0.4",
"cookie": "0.4.1",
"cookie-parser": "1.4.6",
"cookie-parser": "1.4.5",
"cors": "2.8.5",
"cronosjs": "1.7.1",
"denque": "2.0.1",
"express": "4.17.2",
"express": "4.17.1",
"express-session": "1.17.2",
"form-data": "4.0.0",
"fs-extra": "10.0.0",
"fs.notify": "0.0.4",
"got": "11.8.3",
"got": "11.8.2",
"hash-sum": "2.0.0",
"hpagent": "0.1.2",
"https-proxy-agent": "5.0.0",
"i18next": "21.6.6",
"i18next": "21.3.1",
"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.34",
"mqtt": "4.3.4",
"moment-timezone": "0.5.33",
"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.1",
"oauth2orize": "1.11.0",
"on-headers": "1.0.2",
"passport": "0.5.2",
"passport": "0.5.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"raw-body": "2.4.2",
"raw-body": "2.4.1",
"semver": "7.3.5",
"tar": "6.1.11",
"tough-cookie": "4.0.0",
"uglify-js": "3.14.5",
"uglify-js": "3.14.2",
"uuid": "8.3.2",
"ws": "7.5.1",
"xml2js": "0.4.23"
@@ -84,7 +84,7 @@
"bcrypt": "5.0.1"
},
"devDependencies": {
"dompurify": "2.3.4",
"dompurify": "2.3.3",
"grunt": "1.4.1",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.4.3",
@@ -109,15 +109,15 @@
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "3.0.7",
"minami": "1.2.3",
"mocha": "9.1.3",
"mocha": "9.1.2",
"node-red-node-test-helper": "^0.2.7",
"nodemon": "2.0.15",
"nodemon": "2.0.13",
"proxy": "^1.0.2",
"sass": "1.48.0",
"sass": "1.43.2",
"should": "13.2.3",
"sinon": "11.1.2",
"stoppable": "^1.1.0",
"supertest": "6.2.1"
"supertest": "6.1.6"
},
"engines": {
"node": ">=12"

View File

@@ -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",user,username:user.username,scope:user.permissions});
log.audit({event: "auth.login",username:user.username,scope:user.permissions});
user.tokens = tokens;
done(null,user);
});

View File

@@ -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",user,username:username,client:client.id,scope:scope});
log.audit({event: "auth.login",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,9 +163,6 @@ 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);
});
}

View File

@@ -90,8 +90,6 @@ 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);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "2.2.0-beta.1",
"version": "2.1.3",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,22 +16,22 @@
}
],
"dependencies": {
"@node-red/util": "2.2.0-beta.1",
"@node-red/editor-client": "2.2.0-beta.1",
"@node-red/util": "2.1.3",
"@node-red/editor-client": "2.1.3",
"bcryptjs": "2.4.3",
"body-parser": "1.19.1",
"body-parser": "1.19.0",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.17.2",
"express": "4.17.2",
"express": "4.17.1",
"memorystore": "1.6.6",
"mime": "2.5.2",
"multer": "1.4.3",
"mustache": "4.2.0",
"oauth2orize": "1.11.1",
"oauth2orize": "1.11.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
"passport": "0.5.2",
"passport": "0.5.0",
"ws": "7.5.1"
},
"optionalDependencies": {

View File

@@ -59,8 +59,6 @@
"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",
@@ -92,7 +90,6 @@
"palette": {
"show": "Show palette"
},
"edit": "Edit",
"settings": "Settings",
"userSettings": "User Settings",
"nodes": "Nodes",
@@ -671,8 +668,7 @@
"unusedConfigNodes": "Unused configuration nodes",
"invalidNodes": "Invalid nodes",
"uknownNodes": "Unknown nodes",
"unusedSubflows": "Unused subflows",
"hiddenFlows": "Hidden flows"
"unusedSubflows": "Unused subflows"
}
},
"help": {
@@ -894,8 +890,6 @@
"addTitle": "add an item"
},
"search": {
"history": "Search history",
"clear": "clear all",
"empty": "No matches found",
"addNode": "add a node..."
},
@@ -1141,7 +1135,6 @@
"defaultValue": "Default value"
},
"tourGuide": {
"takeATour": "Take a tour",
"start": "Start",
"next": "Next"
},

View File

@@ -54,16 +54,7 @@
"delete": "本当に '__label__' を削除しますか?",
"dropFlowHere": "ここにフローをドロップしてください",
"addFlow": "フローの追加",
"addFlowToRight": "右側にフローを追加",
"hideFlow": "フローを非表示",
"hideOtherFlows": "他のフローを非表示",
"showAllFlows": "全てのフローを表示",
"hideAllFlows": "全てのフローを非表示",
"hiddenFlows": "__count__ 個の非表示のフロー一覧",
"hiddenFlows_plural": "__count__ 個の非表示のフロー一覧",
"showLastHiddenFlow": "最後に非表示にしたフローを表示",
"listFlows": "フロー一覧",
"listSubflows": "サブフロー一覧",
"status": "状態",
"enabled": "有効",
"disabled": "無効",
@@ -92,7 +83,6 @@
"palette": {
"show": "パレットを表示"
},
"edit": "編集",
"settings": "設定",
"userSettings": "ユーザ設定",
"nodes": "ノード",
@@ -115,7 +105,6 @@
"editPalette": "パレットの管理",
"other": "その他",
"showTips": "ヒントを表示",
"showWelcomeTours": "新バージョンのガイドツアーを表示",
"help": "Node-REDウェブサイト",
"projects": "プロジェクト",
"projects-new": "新規",
@@ -127,20 +116,7 @@
"groupSelection": "選択部分をグループ化",
"ungroupSelection": "選択部分をグループ解除",
"groupMergeSelection": "選択部分をマージ",
"groupRemoveSelection": "グループから削除",
"arrange": "配置",
"alignLeft": "左揃え",
"alignCenter": "左右中央揃え",
"alignRight": "右揃え",
"alignTop": "上揃え",
"alignMiddle": "上下中央揃え",
"alignBottom": "下揃え",
"distributeHorizontally": "左右に整列",
"distributeVertically": "上下に整列",
"moveToBack": "最背面へ移動",
"moveToFront": "最前面へ移動",
"moveBackwards": "背面へ移動",
"moveForwards": "前面へ移動"
"groupRemoveSelection": "グループから削除"
}
},
"actions": {
@@ -475,8 +451,7 @@
"global": "グローバル",
"workspace": "ワークスペース",
"selectAll": "全てのノードを選択",
"selectNone": "選択を外す",
"selectAllConnected": "接続されたノードを選択",
"selectAllConnected": "接続された全てのノードを選択",
"addRemoveNode": "ノードの選択、選択解除",
"editSelected": "選択したノードを編集",
"deleteSelected": "選択したノードや接続を削除",
@@ -486,13 +461,10 @@
"moveNode": "選択したノードを移動(移動量大)",
"toggleSidebar": "サイドバーの表示/非表示",
"togglePalette": "パレットの表示/非表示",
"copyNode": "ノードをコピー",
"cutNode": "ノードを切り取り",
"copyNode": "選択したノードをコピー",
"cutNode": "選択したノードを切り取り",
"pasteNode": "ノードを貼り付け",
"copyGroupStyle": "グループ様式をコピー",
"pasteGroupStyle": "グループ様式を貼り付け",
"undoChange": "変更操作を戻す",
"redoChange": "変更操作をやり直し",
"searchBox": "ノードを検索",
"managePalette": "パレットの管理",
"actionList": "動作一覧"
@@ -547,8 +519,7 @@
"nodeEnabled_plural": "ノードを有効化しました:",
"nodeDisabled": "ノードを無効化しました:",
"nodeDisabled_plural": "ノードを無効化しました:",
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました",
"unknownNodeRegistered": "ノードの読み込みエラー: <ul><li>__type__<br>__error__</li></ul>"
"nodeUpgraded": "ノードモジュール __module__ をバージョン __version__ へ更新しました"
},
"editor": {
"title": "パレットの管理",
@@ -671,8 +642,7 @@
"unusedConfigNodes": "未使用の設定ノード",
"invalidNodes": "不正なノード",
"uknownNodes": "未知のノード",
"unusedSubflows": "未使用のサブフロー",
"hiddenFlows": "非表示のフロー"
"unusedSubflows": "未使用のサブフロー"
}
},
"help": {
@@ -1138,11 +1108,6 @@
"preview": "UIプレビュー",
"defaultValue": "デフォルト値"
},
"tourGuide": {
"takeATour": "ツアーを開始",
"start": "開始",
"next": "次へ"
},
"languages": {
"de": "ドイツ語",
"en-US": "英語",

View File

@@ -225,7 +225,7 @@
"compact": "紧凑",
"formatted": "已格式化",
"copy": "导出到剪贴板",
"export": "导出到库",
"export": "到处到库",
"exportAs": "导出为",
"overwrite": "替换",
"exists": "<p><b>\"__file__\"</b>已存在</p><p>是否要替换它?</p>"

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "2.2.0-beta.1",
"version": "2.1.3",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -684,13 +684,6 @@ 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 = [];

View File

@@ -38,8 +38,6 @@ RED.i18n = (function() {
defaultNS: "editor",
fallbackLng: ['en-US'],
returnObjects: true,
keySeparator: ".",
nsSeparator: ":",
interpolation: {
unescapeSuffix: 'HTML',
escapeValue: false,

View File

@@ -38,9 +38,7 @@
},
"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",

View File

@@ -15,9 +15,6 @@
**/
RED.nodes = (function() {
var PORT_TYPE_INPUT = 1;
var PORT_TYPE_OUTPUT = 0;
var node_defs = {};
var linkTabMap = {};
@@ -808,6 +805,7 @@ RED.nodes = (function() {
var removedGroups = [];
if (ws) {
delete workspaces[id];
allNodes.removeTab(id);
delete linkTabMap[id];
workspacesOrder.splice(workspacesOrder.indexOf(id),1);
var i;
@@ -845,7 +843,6 @@ 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};
@@ -1100,11 +1097,6 @@ 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;
@@ -2461,144 +2453,6 @@ 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) {
@@ -2680,7 +2534,7 @@ RED.nodes = (function() {
add: addNode,
remove: removeNode,
clear: clear,
detachNodes: detachNodes,
moveNodesForwards: moveNodesForwards,
moveNodesBackwards: moveNodesBackwards,
moveNodesToFront: moveNodesToFront,
@@ -2692,20 +2546,7 @@ 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 [];
},
addWorkspace: addWorkspace,
removeWorkspace: removeWorkspace,
getWorkspaceOrder: function() { return workspacesOrder },
@@ -2779,7 +2620,6 @@ RED.nodes = (function() {
getAllFlowNodes: getAllFlowNodes,
getAllUpstreamNodes: getAllUpstreamNodes,
getAllDownstreamNodes: getAllDownstreamNodes,
getNodeIslands: getNodeIslands,
createExportableNodeSet: createExportableNodeSet,
createCompleteNodeSet: createCompleteNodeSet,
updateConfigNodeUsers: updateConfigNodeUsers,

View File

@@ -590,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:RED._("menu.label.edit"), options: [
menuOptions.push({id:"menu-item-edit-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,

View File

@@ -71,7 +71,6 @@ RED.clipboard = (function() {
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
RED.view.focus();
}
},
{ // red-ui-clipboard-dialog-download
@@ -82,7 +81,6 @@ 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
@@ -97,7 +95,6 @@ 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();
@@ -113,7 +110,6 @@ 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) {
@@ -175,7 +171,6 @@ RED.clipboard = (function() {
}
}
$( this ).dialog( "close" );
RED.view.focus();
}
},
{ // red-ui-clipboard-dialog-import-conflict
@@ -208,7 +203,6 @@ 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();
}
}
],
@@ -946,25 +940,28 @@ RED.clipboard = (function() {
if (truncated) {
msg += "_truncated";
}
navigator.clipboard.writeText(value).then(function () {
if (element) {
var popover = RED.popover.create({
target: element,
direction: 'left',
size: 'small',
content: RED._(msg)
});
setTimeout(function() {
popover.close();
},1000);
popover.open();
}
if (currentFocus) {
$(currentFocus).focus();
}
}).catch(err => { console.error("Failed to copy:",err) });
$("#red-ui-clipboard-hidden").val(value).focus().select();
var result = document.execCommand("copy");
if (result && element) {
var popover = RED.popover.create({
target: element,
direction: 'left',
size: 'small',
content: RED._(msg)
});
setTimeout(function() {
popover.close();
},1000);
popover.open();
}
$("#red-ui-clipboard-hidden").val("");
if (currentFocus) {
$(currentFocus).focus();
}
return result;
}
function importNodes(nodesStr,addFlow) {
var newNodes = nodesStr;
if (typeof nodesStr === 'string') {
@@ -1239,6 +1236,8 @@ RED.clipboard = (function() {
init: function() {
setupDialogs();
$('<textarea type="text" id="red-ui-clipboard-hidden" tabIndex="-1">').appendTo("#red-ui-editor");
RED.actions.add("core:show-export-dialog",showExportNodes);
RED.actions.add("core:show-import-dialog",showImportNodes);

View File

@@ -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(); this.element.trigger("change") },
onselect: (opt) => { this.element.val(opt.value); this.element.focus() },
onclose: () => { this.completionMenuShown = false; delete this.menu; this.element.focus()}
});
this.menu.show({

View File

@@ -117,8 +117,6 @@ 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");
@@ -578,7 +576,7 @@ RED.tabs = (function() {
function findPreviousVisibleTab(li) {
if (!li) {
li = ul.find("li.active");
li = ul.find("li.active").parent();
}
var previous = li.prev();
while(previous.length > 0 && previous.hasClass("hide-tab")) {
@@ -588,9 +586,9 @@ RED.tabs = (function() {
}
function findNextVisibleTab(li) {
if (!li) {
li = ul.find("li.active");
li = ul.find("li.active").parent();
}
var next = li.next();
var next = ul.find("li.active").next();
while(next.length > 0 && next.hasClass("hide-tab")) {
next = next.next();
}
@@ -811,18 +809,15 @@ 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 red-ui-tab-hide"}).appendTo(li);
closeLink.append('<i class="fa fa-eye" />');
closeLink.append('<i class="fa fa-eye-slash" />');
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close"}).appendTo(li);
closeLink.append('<i class="fa fa-times" />');
closeLink.on("click",function(event) {
event.preventDefault();
hideTab(tab.id);
});
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
}
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
@@ -831,8 +826,7 @@ RED.tabs = (function() {
$('<i class="red-ui-tabs-badge-selected fa fa-check-circle"></i>').appendTo(badges);
}
// link.attr("title",tab.label);
RED.popover.tooltip(link,function() { return tab.label})
link.attr("title",tab.label);
if (options.onadd) {
options.onadd(tab);
@@ -951,6 +945,7 @@ 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();
},

View File

@@ -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.typeField.val() || this.options.default||this.typeList[0].value);
this.type(this.options.default||this.typeList[0].value);
this.typeChanged = !!this.options.default;
}catch(err) {
console.log(err.stack);
@@ -805,7 +805,6 @@
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') {
@@ -830,14 +829,10 @@
}
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
if (!firstCall) {
this.type(this.typeList[0].value);
}
this.type(this.typeList[0].value);
} else {
this.propertyType = null;
if (!firstCall) {
this.type(currentType);
}
this.type(currentType);
}
if (this.typeList.length === 1 && !this.typeList[0].icon && (!this.typeList[0].label || this.typeList[0].showLabel === false)) {
this.selectTrigger.hide()

View File

@@ -333,16 +333,6 @@ 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));

View File

@@ -554,8 +554,6 @@ RED.diff = (function() {
color: "#DDAA99",
defaults:{name:{value:""}}
}
} else if (node.type === "group") {
def = RED.group.def;
} else {
def = {};
}
@@ -765,15 +763,16 @@ RED.diff = (function() {
}
}
if (node.hasOwnProperty('x')) {
if (localNode) {
if (localNode.x !== node.x || localNode.y !== node.y || localNode.w !== node.w || localNode.h !== node.h ) {
if (localNode.x !== node.x || localNode.y !== node.y) {
localChanged = true;
localChanges++;
}
}
if (remoteNode) {
if (remoteNode.x !== node.x || remoteNode.y !== node.y|| remoteNode.w !== node.w || remoteNode.h !== node.h) {
if (remoteNode.x !== node.x || remoteNode.y !== node.y) {
remoteChanged = true;
remoteChanges++;
}
@@ -791,12 +790,7 @@ 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);
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,
propertyElements['local.position'] = RED.utils.createObjectElement({x:localNode.x,y:localNode.y},
{
path: "position",
exposeApi: true,
@@ -817,12 +811,7 @@ 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);
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,
propertyElements['remote.position'] = RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y},
{
path: "position",
exposeApi: true,
@@ -894,11 +883,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!=='w'&&p!=='h'&&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!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
if (def.defaults) {
properties = properties.concat(Object.keys(def.defaults));
}
if (node.type !== 'tab' && node.type !== "group") {
if (node.type !== 'tab') {
properties = properties.concat(['inputLabels','outputLabels']);
}
if ( ((localNode && localNode.hasOwnProperty('icon')) || (remoteNode && remoteNode.hasOwnProperty('icon'))) &&

View File

@@ -744,16 +744,7 @@ RED.editor = (function() {
delete cn.__label__;
});
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>');
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>'+RED._("editor.addNewType", {type:type})+'</option>');
window.setTimeout(function() { select.trigger("change");},50);
}
}

View File

@@ -247,7 +247,7 @@
var currentExpression = expressionEditor.getValue();
var expr;
var usesContext = false;
var legacyMode = /(^|[^a-zA-Z0-9_'".])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
var legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
$(".red-ui-editor-type-expression-legacy").toggle(legacyMode);
try {
expr = jsonata(currentExpression);

View File

@@ -81,8 +81,7 @@
clearTimeout: true,
setInterval: true,
clearInterval: true
},
extraLibs: options.extraLibs
}
});
if (options.cursor) {
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);

View File

@@ -55,15 +55,9 @@
}
});
}
if (!old_env && new_env.length === 0) {
delete node.env;
} else if (!isSameObj(old_env, new_env)) {
if (!isSameObj(old_env, new_env)) {
node.env = new_env;
editState.changes.env = node.env;
if (new_env.length === 0) {
delete node.env;
} else {
node.env = new_env;
}
editState.changed = true;
}
}

View File

@@ -590,14 +590,12 @@ RED.group = (function() {
markDirty(group);
}
function getNodes(group,recursive,excludeGroup) {
function getNodes(group,recursive) {
var nodes = [];
group.nodes.forEach(function(n) {
if (n.type !== 'group' || !excludeGroup) {
nodes.push(n);
}
nodes.push(n);
if (recursive && n.type === 'group') {
nodes = nodes.concat(getNodes(n,recursive,excludeGroup))
nodes = nodes.concat(getNodes(n,recursive))
}
})
return nodes;

View File

@@ -22,7 +22,6 @@ RED.search = (function() {
var selected = -1;
var visible = false;
var searchHistory = [];
var index = {};
var currentResults = [];
var previousActiveElement;
@@ -106,7 +105,6 @@ 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);
@@ -152,15 +150,7 @@ 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)
@@ -206,20 +196,6 @@ 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);
@@ -228,12 +204,7 @@ RED.search = (function() {
change: function() {
searchResults.editableList('empty');
selected = -1;
var value = $(this).val();
if (value === "") {
populateSearchHistory();
return;
}
currentResults = search(value);
currentResults = search($(this).val());
if (currentResults.length > 0) {
for (i=0;i<Math.min(currentResults.length,25);i++) {
searchResults.editableList('addItem',currentResults[i])
@@ -305,12 +276,7 @@ RED.search = (function() {
})
}
}
} 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")) {
} else {
if (currentResults.length > 0) {
reveal(currentResults[Math.max(0,selected)].node);
}
@@ -326,32 +292,7 @@ RED.search = (function() {
addItem: function(container,i,object) {
var node = object.node;
var div;
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) {
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}));
@@ -406,12 +347,6 @@ 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);
}
@@ -430,14 +365,9 @@ 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;
}

View File

@@ -27,7 +27,5 @@ RED.state = {
PANNING: 10,
SELECTING_NODE: 11,
GROUP_DRAGGING: 12,
GROUP_RESIZE: 13,
DETACHED_DRAGGING: 14,
SLICING: 15
GROUP_RESIZE: 13
}

View File

@@ -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">' + RED._("tourGuide.takeATour") + '</button></div>';
tourHeader = '<div><button type="button" onclick="RED.actions.invoke(\'core:show-welcome-tour\')" class="red-ui-button">Take a tour</button></div>'
}
}
var aboutHeader = '<div style="text-align:center;">'+tourHeader+'</div>'

View File

@@ -175,7 +175,6 @@ 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);
@@ -204,7 +203,6 @@ 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);
@@ -274,7 +272,6 @@ 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"},
]
});

View File

@@ -256,10 +256,6 @@ RED.tourGuide = (function() {
}
$('<div>').css("text-align","left").html(getLocaleText(step.description)).appendTo(stepDescription);
if (step.image) {
$(`<img src="red/tours/${step.image}" />`).appendTo(stepDescription)
}
var stepToolbar = $('<div>',{class:"red-ui-tourGuide-toolbar"}).appendTo(stepContent);
// var breadcrumbs = $('<div>',{class:"red-ui-tourGuide-breadcrumbs"}).appendTo(stepToolbar);
@@ -368,8 +364,6 @@ 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"

View File

@@ -142,8 +142,6 @@ 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>');
}
@@ -442,8 +440,6 @@ 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')) {

View File

@@ -725,90 +725,6 @@ 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); })
@@ -867,8 +783,7 @@ 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() })
},

View File

@@ -46,6 +46,7 @@ RED.view = (function() {
var workspaceScrollPositions = {};
var gridSize = 20;
var widthSize = 20;
var snapGrid = false;
var activeSpliceLink;
@@ -63,6 +64,7 @@ RED.view = (function() {
var activeGroups = [];
var dirtyGroups = {};
var selected_link = null;
var mousedown_link = null;
var mousedown_node = null;
var mousedown_group = null;
@@ -74,8 +76,6 @@ 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;
@@ -130,14 +130,6 @@ 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)
}
}
}
}
},
@@ -154,10 +146,6 @@ 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() {
@@ -172,31 +160,6 @@ 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");
@@ -231,12 +194,6 @@ 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() {
@@ -456,56 +413,26 @@ 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);
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] += this.scrollTop + ((nn.h/2)-helperOffset[1]);
mousePos[0] += this.scrollLeft + ((nn.w/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
@@ -526,6 +453,7 @@ RED.view = (function() {
historyEvent.removedLinks = [spliceLink];
}
RED.nodes.add(nn);
var group = $(ui.helper).data("group");
if (group) {
@@ -575,8 +503,6 @@ 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;
@@ -599,7 +525,6 @@ 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) {
@@ -985,7 +910,7 @@ RED.view = (function() {
return;
}
if (!mousedown_node && !mousedown_link && !mousedown_group) {
selectedLinks.clear();
selected_link = null;
updateSelection();
}
if (mouse_mode === 0) {
@@ -994,18 +919,19 @@ RED.view = (function() {
lasso = null;
}
}
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 || 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});
}
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 (mouse_mode === 0 && !(d3.event.metaKey || d3.event.ctrlKey)) {
if (!touchStartTime) {
point = d3.mouse(this);
lasso = eventLayer.append("rect")
@@ -1020,13 +946,6 @@ 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();
}
}
@@ -1423,17 +1342,6 @@ 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) {
@@ -1441,7 +1349,7 @@ RED.view = (function() {
return;
}
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) {
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && !mousedown_group && selected_link == null) {
return;
}
@@ -1465,18 +1373,16 @@ RED.view = (function() {
// Get all the wires we need to detach.
var links = [];
var existingLinks = [];
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);
}
})
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];
} else {
var filter;
if (mousedown_port_type === PORT_TYPE_OUTPUT) {
@@ -1514,7 +1420,7 @@ RED.view = (function() {
} else if (mousedown_node && !quickAddLink) {
showDragLines([{node:mousedown_node,port:mousedown_port_index,portType:mousedown_port_type}]);
}
selectedLinks.clear();
selected_link = null;
}
mousePos = mouse_position;
for (i=0;i<drag_lines.length;i++) {
@@ -1546,7 +1452,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 || mouse_mode == RED.state.DETACHED_DRAGGING) {
} else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING) {
mousePos = mouse_position;
var minX = 0;
var minY = 0;
@@ -1610,16 +1516,8 @@ RED.view = (function() {
gridOffset[0] = node.n.x-(gridSize*Math.floor(node.n.x/gridSize))-gridSize/2;
gridOffset[1] = node.n.y-(gridSize*Math.floor(node.n.y/gridSize))-gridSize/2;
} else {
var offsetLeft = node.n.x-(gridSize*Math.round((node.n.x-node.n.w/2)/gridSize)+node.n.w/2);
var offsetRight = node.n.x-(gridSize*Math.round((node.n.x+node.n.w/2)/gridSize)-node.n.w/2);
// gridOffset[0] = node.n.x-(gridSize*Math.floor((node.n.x-node.n.w/2)/gridSize)+node.n.w/2);
if (Math.abs(offsetLeft) < Math.abs(offsetRight)) {
gridOffset[0] = offsetLeft
} else {
gridOffset[0] = offsetRight
}
gridOffset[1] = node.n.y-(gridSize*Math.round(node.n.y/gridSize));
// console.log(offsetLeft, offsetRight);
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));
}
if (gridOffset[0] !== 0 || gridOffset[1] !== 0) {
for (i = 0; i<movingSet.length(); i++) {
@@ -1839,11 +1737,6 @@ 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) {
@@ -1915,30 +1808,10 @@ RED.view = (function() {
// movingSet.add(mousedown_node);
// }
// }
if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.DETACHED_DRAGGING) {
if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE) {
// 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;
@@ -1983,29 +1856,10 @@ RED.view = (function() {
if (mouse_mode === RED.state.MOVING || mouse_mode === RED.state.MOVING_ACTIVE) {
return;
}
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;
}
if (mouse_mode === RED.state.IMPORT_DRAGGING) {
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 {
@@ -2017,7 +1871,6 @@ RED.view = (function() {
if (mouse_mode === RED.state.SELECTING_NODE && selectNodesOptions.single) {
return;
}
selectedLinks.clear();
if (activeGroup) {
var ag = activeGroup;
@@ -2089,6 +1942,7 @@ RED.view = (function() {
}
}
}
selected_link = null;
if (mouse_mode !== RED.state.SELECTING_NODE) {
updateSelection();
}
@@ -2103,7 +1957,7 @@ RED.view = (function() {
n.n.selected = false;
}
movingSet.clear();
selectedLinks.clear();
selected_link = null;
if (activeGroup) {
activeGroup.active = false
activeGroup.dirty = true;
@@ -2197,16 +2051,12 @@ RED.view = (function() {
}
}
}
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;
}
})
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;
}
} else {
selection.flows = workspaceSelection;
@@ -2217,10 +2067,6 @@ 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;
});
@@ -2242,7 +2088,7 @@ RED.view = (function() {
}
}
}
function deleteSelection(reconnectWires) {
function deleteSelection() {
if (mouse_mode === RED.state.SELECTING_NODE) {
return;
}
@@ -2290,7 +2136,7 @@ RED.view = (function() {
updateActiveNodes();
updateSelection();
redraw();
} else if (movingSet.length() > 0 || selectedLinks.length() > 0) {
} else if (movingSet.length() > 0 || selected_link != null) {
var result;
var node;
var removedNodes = [];
@@ -2300,16 +2146,6 @@ 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;
@@ -2399,71 +2235,71 @@ RED.view = (function() {
RED.nodes.dirty(true);
}
}
var historyEvent;
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: link.source,
changed: link.source.changed,
changes: {
links: $.extend(true,{},{v:link.source.links}).v
}
})
historyEvents.push({
t: "edit",
node: link.target,
changed: link.target.changed,
changes: {
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;
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);
} 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({
historyEvent = {
t:"multi",
events: historyEvents
})
} else {
RED.history.push(historyEvent);
}
events: [
{
t: "edit",
node: selected_link.source,
changed: selected_link.source.changed,
changes: {
links: $.extend(true,{},{v:selected_link.source.links}).v
}
},
{
t: "edit",
node: selected_link.target,
changed: selected_link.target.changed,
changes: {
links: $.extend(true,{},{v:selected_link.target.links}).v
}
}
selectedLinks.clear();
],
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;
}
}
RED.history.push(historyEvent);
selected_link = null;
updateActiveNodes();
updateSelection();
redraw();
@@ -2540,28 +2376,6 @@ 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;
@@ -2648,7 +2462,7 @@ RED.view = (function() {
activeHoverGroup.hovered = false;
activeHoverGroup = null;
}
d3.selectAll(".red-ui-flow-link-splice").classed("red-ui-flow-link-splice",false);
d3.select(".red-ui-flow-link-splice").classed("red-ui-flow-link-splice",false);
if (spliceTimer) {
clearTimeout(spliceTimer);
spliceTimer = null;
@@ -2896,13 +2710,10 @@ 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();
@@ -2911,10 +2722,7 @@ RED.view = (function() {
resetMouseVars();
hideDragLines();
if (select_link) {
selectedLinks.clear();
selectedLinks.add(select_link);
}
selected_link = select_link;
mousedown_link = select_link;
if (select_link) {
updateSelection();
@@ -3087,13 +2895,10 @@ RED.view = (function() {
msn.dx = msn.n.x-mouse[0];
msn.dy = msn.n.y-mouse[1];
}
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]
mouse_offset = d3.mouse(document.body);
if (isNaN(mouse_offset[0])) {
mouse_offset = d3.touches(document.body)[0];
}
}
@@ -3174,7 +2979,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 || mouse_mode == RED.state.DETACHED_DRAGGING) {
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
var historyEvent = RED.history.peek();
if (activeSpliceLink) {
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
@@ -3212,18 +3017,6 @@ 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);
@@ -3392,9 +3185,7 @@ RED.view = (function() {
// }
// } else
if (d3.event.shiftKey) {
if (!(d3.event.ctrlKey||d3.event.metaKey)) {
clearSelection();
}
clearSelection();
var clickPosition = (d3.event.offsetX/scaleFactor - mousedown_node.x)
var edgeDelta = (mousedown_node.w/2) - Math.abs(clickPosition);
var cnodes;
@@ -3422,7 +3213,7 @@ RED.view = (function() {
mousedown_node.selected = true;
movingSet.add(mousedown_node);
}
// selectedLinks.clear();
selected_link = null;
if (d3.event.button != 2) {
mouse_mode = RED.state.MOVING;
var mouse = d3.touches(this)[0]||d3.mouse(this);
@@ -3548,35 +3339,19 @@ RED.view = (function() {
d3.event.stopPropagation();
return;
}
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});
}
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});
}
}
function linkTouchStart(d) {
if (mouse_mode === RED.state.SELECTING_NODE) {
@@ -3585,8 +3360,7 @@ RED.view = (function() {
}
mousedown_link = d;
clearSelection();
selectedLinks.clear();
selectedLinks.add(mousedown_link);
selected_link = mousedown_link;
updateSelection();
redraw();
focusView();
@@ -3822,7 +3596,7 @@ RED.view = (function() {
function showTouchMenu(obj,pos) {
var mdn = mousedown_node;
var options = [];
options.push({name:"delete",disabled:(movingSet.length()===0 && selectedLinks.length() === 0),onselect:function() {deleteSelection();}});
options.push({name:"delete",disabled:(movingSet.length()===0 && selected_link === null),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});}});
@@ -3902,11 +3676,7 @@ RED.view = (function() {
nodeEl = document.getElementById(d.id);
}
if (nodeEl) {
// Do not show node status if:
// - global flag set
// - node has no status
// - node is disabled
if (!showStatus || !d.status || d.d === true) {
if (!showStatus || !d.status) {
nodeEl.__statusGroup__.style.display = "none";
} else {
nodeEl.__statusGroup__.style.display = "inline";
@@ -4256,7 +4026,7 @@ RED.view = (function() {
if (hideLabel) {
d.w = node_height;
} else {
d.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(d._def.inputs>0?7:0))/20)) );
d.w = Math.max(node_width,widthSize*(Math.ceil((labelParts.width+50+(d._def.inputs>0?7:0))/widthSize)) );
}
if (ow !== undefined) {
d.x += (d.w-ow)/2;
@@ -4559,13 +4329,6 @@ 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;
@@ -4586,7 +4349,7 @@ RED.view = (function() {
link.exit().remove();
link.each(function(d) {
var link = d3.select(this);
if (d.added || d.selected || dirtyNodes[d.source.id] || dirtyNodes[d.target.id]) {
if (d.added || d===selected_link || 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;
@@ -4609,8 +4372,7 @@ RED.view = (function() {
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);
this.classList.toggle("red-ui-flow-link-selected", !!(d===selected_link||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"))
@@ -4660,9 +4422,6 @@ RED.view = (function() {
n.selected = true;
n.dirty = true;
movingSet.add(n);
if (targets.length === 1) {
RED.view.reveal(n.id);
}
});
updateSelection();
redraw();
@@ -4814,9 +4573,9 @@ RED.view = (function() {
d.nodes.forEach(function(n) {
groupOpCount++
if (n.type !== "group") {
minX = Math.min(minX,n.x-n.w/2-margin-((n._def.button && n._def.align!=="right")?20:0));
minX = Math.min(minX,n.x-n.w/2-margin-((n._def.button && n._def.align!=="right")?widthSize:0));
minY = Math.min(minY,n.y-n.h/2-margin);
maxX = Math.max(maxX,n.x+n.w/2+margin+((n._def.button && n._def.align=="right")?20:0));
maxX = Math.max(maxX,n.x+n.w/2+margin+((n._def.button && n._def.align=="right")?widthSize:0));
maxY = Math.max(maxY,n.y+n.h/2+margin);
} else {
minX = Math.min(minX,n.x-margin)
@@ -5271,7 +5030,6 @@ RED.view = (function() {
delete node.d;
}
node.dirty = true;
node.dirtyStatus = true;
node.changed = true;
RED.events.emit("nodes:change",node);
}
@@ -5318,9 +5076,8 @@ RED.view = (function() {
if (allNodes.size > 0) {
selection.nodes = Array.from(allNodes);
}
if (selectedLinks.length() > 0) {
selection.links = selectedLinks.toArray();
selection.link = selection.links[0];
if (selected_link != null) {
selection.link = selected_link;
}
return selection;
}
@@ -5328,23 +5085,23 @@ RED.view = (function() {
function calculateNodeDimensions(node) {
var result = [node_width,node_height];
try {
var isLink = (node.type === "link in" || node.type === "link out")
var hideLabel = node.hasOwnProperty('l')?!node.l : isLink;
var label = RED.utils.getNodeLabel(node, node.type);
var labelParts = getLabelParts(label, "red-ui-flow-node-label");
if (hideLabel) {
result[1] = Math.max(node_height,(node.outputs || 0) * 15);
} else {
result[1] = Math.max(6+24*labelParts.lines.length,(node.outputs || 0) * 15, 30);
var isLink = (node.type === "link in" || node.type === "link out")
var hideLabel = node.hasOwnProperty('l')?!node.l : isLink;
var label = RED.utils.getNodeLabel(node, node.type);
var labelParts = getLabelParts(label, "red-ui-flow-node-label");
if (hideLabel) {
result[1] = Math.max(node_height,(node.outputs || 0) * 15);
} else {
result[1] = Math.max(6+24*labelParts.lines.length,(node.outputs || 0) * 15, 30);
}
if (hideLabel) {
result[0] = node_height;
} else {
result[0] = Math.max(node_width,widthSize*(Math.ceil((labelParts.width+50+(node._def.inputs>0?7:0))/widthSize)) );
}
} catch(err) {
console.log("Error",node);
}
if (hideLabel) {
result[0] = node_height;
} else {
result[0] = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(node._def.inputs>0?7:0))/20)) );
}
}catch(err) {
console.log("Error",node);
}
return result;
}
@@ -5485,6 +5242,8 @@ RED.view = (function() {
return gridSize;
} else {
gridSize = Math.max(5,v);
widthSize = gridSize;
while (widthSize > 50) { widthSize = Math.round(widthSize/2); }
updateGrid();
}
},

View File

@@ -66,7 +66,7 @@ RED.workspaces = (function() {
var tabId = RED.nodes.id();
do {
workspaceIndex += 1;
} while ($("#red-ui-workspace-tabs li[flowname='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
} while ($("#red-ui-workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
ws = {
type: "tab",
@@ -79,15 +79,12 @@ RED.workspaces = (function() {
};
RED.nodes.addWorkspace(ws,targetIndex);
workspace_tabs.addTab(ws,targetIndex);
workspace_tabs.activateTab(tabId);
if (!skipHistoryEntry) {
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
RED.nodes.dirty(true);
}
}
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
RED.view.focus();
return ws;
}
@@ -211,84 +208,65 @@ 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: 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"
})
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"
}
return menuItems;
}
]
});
workspaceTabCount = 0;
}
@@ -428,9 +406,7 @@ 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 ");
})
@@ -474,7 +450,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 || (id === activeWorkspace)) {
if (id || activeWorkspace) {
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
}
var historyEvent = {
@@ -555,11 +531,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);
@@ -582,11 +558,14 @@ 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) {
workspace_tabs.renameTab(ws.id,ws.label);
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
})
RED.nodes.eachSubflow(function(sf) {
if (workspace_tabs.contains(sf.id)) {

View File

@@ -197,7 +197,6 @@ $view-select-mode-background: $secondary-background-selected;
$view-grid-color: #eee;
$node-label-color: #333;
$node-port-label-color: #888;
$node-border: #999;
$node-border-unknown: #f33;
$node-border-placeholder: #aaa;

View File

@@ -356,6 +356,10 @@ button.red-ui-button-small
background: $secondary-background;
}
#red-ui-clipboard-hidden {
position: absolute;
top: -3000px;
}
.form-row .red-ui-editor-node-label-form-row {
margin: 5px 0 0 50px;
label {

View File

@@ -21,13 +21,6 @@
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;
@@ -54,7 +47,7 @@
.red-ui-flow-port-label {
stroke-width: 0;
fill: $node-port-label-color;
fill: $secondary-text-color;
font-size: 16px;
dominant-baseline: middle;
text-anchor: middle;

View File

@@ -187,7 +187,7 @@
ul.red-ui-menu-dropdown {
background: $header-menu-background;
border: 1px solid $header-menu-background;
width: 260px !important;
width: 250px !important;
margin-top: 0;
li a {
color: $header-menu-color;

View File

@@ -204,28 +204,6 @@
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;

View File

@@ -389,19 +389,7 @@ 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;

View File

@@ -1,23 +1,14 @@
export default {
steps: [
{
title: {
'en-US': 'Create your first flow',
'ja': 'はじめてのフローを作成'
},
title: "Create your first flow",
width: 400,
description: {
'en-US': 'This tutorial will guide you through creating your first flow',
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。'
},
description: 'This tutorial will guide you through creating your first flow',
nextButton: 'start'
},
{
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
description: {
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。'
},
description: 'To add a new tab, click the <i class="fa fa-plus"></i> button',
wait: {
type: "dom-event",
event: "click",
@@ -27,10 +18,7 @@ export default {
{
element: '.red-ui-palette-node[data-palette-type="inject"]',
direction: 'right',
description: {
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
'ja': 'パレットには、利用できる全てのードが一覧表示されます。injectードをワークスペースにドラッグします。'
},
description: 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
fallback: 'inset-bottom-right',
wait: {
type: "nr-event",
@@ -50,10 +38,7 @@ export default {
{
element: '.red-ui-palette-node[data-palette-type="debug"]',
direction: 'right',
description: {
'en-US': 'Next, drag a new Debug node into the workspace.',
'ja': '次に、debugードをワークスペースにドラッグします。'
},
description: 'Next, drag a new Debug node into the workspace.',
fallback: 'inset-bottom-right',
wait: {
type: "nr-event",
@@ -72,10 +57,7 @@ export default {
},
{
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
description: {
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
'ja': 'injectードの出力から、debugードの入力へワイヤーで接続します。'
},
description: 'Add a wire from the output of the Inject node to the input of the Debug node',
fallback: 'inset-bottom-right',
wait: {
type: "nr-event",
@@ -87,10 +69,7 @@ export default {
},
{
element: "#red-ui-header-button-deploy",
description: {
'en-US': 'Deploy your changes so the flow is active in the runtime',
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。'
},
description: 'Deploy your changes so the flow is active in the runtime',
width: 200,
wait: {
type: "dom-event",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -1,98 +1,151 @@
export default {
version: "2.2.0",
version: "2.1.0",
steps: [
{
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 2.2!",
"ja": "Node-RED 2.2へようこそ!"
},
description: {
"en-US": "Let's take a moment to discover the new features in this release.",
"ja": "本リリースの新機能を見つけてみましょう。"
}
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": "Search history",
},
description: {
"en-US": "<p>The Search dialog now keeps a history of your searches, making it easier to go back to a previous search.</p>"
},
element: "#red-ui-search .red-ui-searchBox-form",
prepare(done) {
RED.search.show();
setTimeout(done,400);
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": "New Edit menu" },
prepare() {
$("#red-ui-header-button-sidemenu").trigger("click");
$("#menu-item-edit-menu").parent().addClass("open")
},
complete() {
RED.search.hide();
$("#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>" }
},
{
title: {
"en-US": "New wiring actions",
title: { "en-US": "Arranging nodes" },
prepare() {
$("#red-ui-header-button-sidemenu").trigger("click");
$("#menu-item-arrange-menu").parent().addClass("open")
},
// image: "images/",
description: {
"en-US": `<p>A pair of new actions have been added to help with wiring nodes together:</p>
<ul>
<li><b><code>Wire Series Of Nodes</code></b> - adds a wire (if necessary) between each pair of nodes in the order they were selected.</li>
<li><b><code>Wire Node To Multiple</code></b> - wires the first node selected to all of the other selected nodes.</li>
</ul>
<p>Actions can be accessed from the Action List in the main menu.</p>`
complete() {
$("#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>" },
},
{
title: {
"en-US": "Deleting nodes and reconnecting wires",
title: { "en-US": "Hiding tabs" },
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.' },
interactive: false,
prepare() {
$("#red-ui-workspace-tabs > li.active .red-ui-tab-close").css("display","block");
},
image: "images/delete-repair.gif",
description: {
"en-US": `<p>It is now possible to delete a selection of nodes and automatically repair the wiring behind them.</p>
<p>This is really useful if you want to remove a node from the middle of the flow.</p>
<p>Hold the Ctrl (or Cmd) key when you press Delete and the nodes will be gone and the wires repaired.</p>
`
complete() {
$("#red-ui-workspace-tabs > li.active .red-ui-tab-close").css("display","");
}
},
{
title: {
"en-US": "Detaching nodes from a flow",
title: { "en-US": "Tab menu" },
element: "#red-ui-workspace-tabs-menu",
description: { "en-US": '<p>The new tab menu also provides lots of new options for your tabs.</p>' },
interactive: false,
direction: "left",
prepare() {
$("#red-ui-workspace > .red-ui-tabs > .red-ui-tabs-menu a").trigger("click");
},
image: "images/detach-repair.gif",
description: {
"en-US": `<p>If you want to remove a node from a flow without deleting it,
you can use the <b><code>Detach Selected Nodes</code></b> action.</p>
<p>The nodes will be removed from their flow, the wiring repaired behind them, and then attached to the mouse
so you can drop them wherever you want in the workspace.</p>
<p>There isn't a default keyboard shortcut assigned for this new action, but
you can add your own via the Keyboard pane of the main Settings dialog.</p>`
complete() {
$(document).trigger("click");
}
},
{
title: {
"en-US": "More wiring tricks",
},
image: "images/slice.gif",
description: {
"en-US": `<p>A couple more wiring tricks to share.</p>
<p>You can now select multiple wires by holding the Ctrl (or Cmd) key
when clicking on a wire. This makes it easier to delete multiple wires in one go.</p>
<p>If you hold the Ctrl (or Cmd) key, then click and drag with the right-hand mouse button,
you can slice through wires to remove them.</p>`
}
title: { "en-US": "Flow and Group level environment variables" },
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>" },
},
{
title: {
"en-US": "Node Updates",
prepare(done) {
RED.editor.editFlow(RED.nodes.workspace(RED.workspaces.active()),"editor-tab-envProperties");
setTimeout(done,700);
},
// image: "images/",
description: {
"en-US": `<ul>
<li>The JSON node will now handle parsing Buffer payloads</li>
<li>The TCP Client nodes support TLS connections</li>
<li>The WebSocket node allows you to specify a sub-protocol when connecting</li>
</ul>`
element: "#red-ui-tab-editor-tab-envProperties-link-button",
description: { "en-US": "<p>Their edit dialogs have a new Environment Variables section.</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>' },
complete(done) {
$("#node-dialog-cancel").trigger("click");
setTimeout(done,500);
}
},
{
title: {"en-US":"Link Call node added"},
prepare(done) {
this.paletteWasClosed = $("#red-ui-main-container").hasClass("red-ui-palette-closed");
RED.actions.invoke("core:toggle-palette",true)
$('[data-palette-type="link call"]')[0].scrollIntoView({block:"center"})
setTimeout(done,100);
},
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>' },
},
{
title: {"en-US":"MQTT nodes support dynamic connections"},
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>' },
},
{
title: {"en-US":"File nodes renamed"},
prepare(done) {
$('[data-palette-type="file"]')[0].scrollIntoView({block:"center"})
setTimeout(done,100);
},
complete() {
if (this.paletteWasClosed) {
RED.actions.invoke("core:toggle-palette",false)
}
},
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>' },
},
{
title: {"en-US":"Deep copy option on Change node"},
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._})
setTimeout(done,700);
},
complete(done) {
$("#node-dialog-cancel").trigger("click");
setTimeout(done,500);
},
element: function() {
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>' },
},
{
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>" }
}
]
}

View File

@@ -690,9 +690,9 @@
this.topic = "";
var result = getProps(items, true);
this.props = result.props;
if(result.hasOwnProperty('payloadType')) { this.payloadType = result.payloadType; };
if(result.hasOwnProperty('payload')) { this.payload = result.payload; };
if(result.hasOwnProperty('topic')) { this.topic = result.topic; };
if(result.payloadType) { this.payloadType = result.payloadType; };
if(result.payload) { this.payload = result.payload; };
if(result.topic) { this.topic = result.topic; };
},
button: {
enabled: function() {

View File

@@ -75,12 +75,16 @@ module.exports = function(RED) {
node.repeaterSetup = function () {
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000;
this.debug(RED._("inject.repeat", this));
if (RED.settings.verbose) {
this.log(RED._("inject.repeat", this));
}
this.interval_id = setInterval(function() {
node.emit("input", {});
}, this.repeat);
} else if (this.crontab) {
this.debug(RED._("inject.crontab", this));
if (RED.settings.verbose) {
this.log(RED._("inject.crontab", this));
}
this.cronjob = scheduleTask(this.crontab,() => { node.emit("input", {})});
}
};
@@ -144,8 +148,10 @@ 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;
}
};

View File

@@ -280,18 +280,6 @@ module.exports = function(RED) {
root: path.join(__dirname,"lib","debug"),
dotfiles: 'deny'
};
try {
res.sendFile(
req.params[0],
options,
err => {
if (err) {
res.sendStatus(404);
}
}
)
} catch(err) {
res.sendStatus(404);
}
res.sendFile(req.params[0], options);
});
};

View File

@@ -91,21 +91,21 @@
<div id="func-tab-init" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-init-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 5;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-body" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 220px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 5;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
<div id="func-tab-finalize" style="display:none">
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 5;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
</div>
</div>
@@ -512,7 +512,6 @@
return function(e) {
e.preventDefault();
var value = editor.getValue();
var extraLibs = that.libs || [];
RED.editor.editJavaScript({
value: value,
width: "Infinity",
@@ -524,8 +523,7 @@
setTimeout(function() {
editor.focus();
},300);
},
extraLibs: extraLibs
}
})
}
}

View File

@@ -234,7 +234,8 @@ module.exports = function(RED) {
},
env: {
get: function(envVar) {
return RED.util.getSetting(node, envVar);
var flow = node._flow;
return flow.getSetting(envVar);
}
},
setTimeout: function () {

View File

@@ -372,7 +372,6 @@ 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;

View File

@@ -86,7 +86,7 @@ module.exports = function(RED) {
});
var cmd = arg.shift();
/* istanbul ignore else */
node.debug(cmd+" ["+arg+"]");
if (RED.settings.verbose) { node.log(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 */
node.debug(arg);
if (RED.settings.verbose) { node.log(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}); }
node.debug('error:' + error);
if (RED.settings.verbose) { node.log('error:' + error); }
}
else if (node.oldrc === "false") {
msg3 = RED.util.cloneMessage(msg);

View File

@@ -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" || this.func === "narrowbandEq")) {
if ((typeof node.previous[t] === 'undefined') && (this.func === "narrowband")) {
if (node.start === '') { node.previous[t] = n; }
else { node.previous[t] = node.start; }
}

View File

@@ -302,8 +302,6 @@ in your Node-RED user directory (${RED.settings.userDir}).
// 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

View File

@@ -177,8 +177,7 @@
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) },
subprotocol: {value:"",required: false}
hb: {value: "", validate: RED.validators.number(/*blank allowed*/true) }
},
inputs:0,
outputs:0,
@@ -266,10 +265,7 @@
<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%;">

View File

@@ -46,12 +46,6 @@ 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
@@ -98,7 +92,7 @@ module.exports = function(RED) {
tlsNode.addTLSOptions(options);
}
}
var socket = new ws(node.path,node.subprotocol,options);
var socket = new ws(node.path,options);
socket.setMaxListeners(0);
node.server = socket; // keep for closing
handleConnection(socket);
@@ -111,24 +105,22 @@ module.exports = function(RED) {
if (node.isServer) {
node._clients[id] = socket;
node.emit('opened',{count:Object.keys(node._clients).length,id:id});
} else {
if (node.heartbeat) {
node.heartbeatInterval = setInterval(function() {
if (socket.nrPendingHeartbeat) {
// No pong received
socket.terminate();
socket.nrErrorHandler(new Error("timeout"));
return;
}
socket.nrPendingHeartbeat = true;
socket.ping();
},node.heartbeat);
}
}
socket.on('open',function() {
if (!node.isServer) {
if (node.heartbeat) {
clearInterval(node.heartbeatInterval);
node.heartbeatInterval = setInterval(function() {
if (socket.nrPendingHeartbeat) {
// No pong received
socket.terminate();
socket.nrErrorHandler(new Error("timeout"));
return;
}
socket.nrPendingHeartbeat = true;
try {
socket.ping();
} catch(err) {}
},node.heartbeat);
}
node.emit('opened',{count:'',id:id});
}
});

View File

@@ -23,17 +23,9 @@
</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>
@@ -50,7 +42,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;" data-i18n="[placeholder]tcpin.label.optional">
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;">
</div>
<div class="form-row">
@@ -66,18 +58,17 @@
<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},
tls: {type:"tls-config", value:'', required:false}
base64: {/*deprecated*/ value:false,required:true}
},
inputs:0,
outputs:1,
@@ -86,7 +77,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() {
@@ -112,27 +103,6 @@
$("#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>
@@ -153,15 +123,6 @@
<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>&nbsp;</label>
<input type="checkbox" id="node-input-end" style="display: inline-block; width: auto; vertical-align: top;">
@@ -183,15 +144,14 @@
<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},
tls: {type:"tls-config", value:'', required:false}
beserver: {value:"client",required:true},
base64: {value:false,required:true},
end: {value:false,required:true},
name: {value:""}
},
inputs:1,
outputs:0,
@@ -210,42 +170,18 @@
$("#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>
@@ -258,23 +194,15 @@
<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-ret"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
<label for="node-input-out"><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"><i class="fa fa-sign-out fa-rotate-90"></i> <span data-i18n="tcpin.label.close"></span></label>
<label for="node-input-out"> </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>
@@ -285,9 +213,6 @@
<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">
@@ -297,16 +222,14 @@
<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},
newline: {value:""},
tls: {type:"tls-config", value:'', required:false}
splitc: {value:"0",required:true},
name: {value:""}
},
inputs:1,
outputs:1,
@@ -323,14 +246,6 @@
$("#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(); }
@@ -357,27 +272,6 @@
$("#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>

View File

@@ -16,46 +16,13 @@
module.exports = function(RED) {
"use strict";
let reconnectTime = RED.settings.socketReconnectTime || 10000;
let socketTimeout = RED.settings.socketTimeout || null;
var reconnectTime = RED.settings.socketReconnectTime||10000;
var socketTimeout = RED.settings.socketTimeout||null;
const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
const Denque = require('denque');
const net = require('net');
const tls = require('tls');
var net = require('net');
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;
}
var connectionPool = {};
/**
* Enqueue `item` in `queue`
@@ -86,14 +53,13 @@ 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").replace("\\t","\t");
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
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;
@@ -104,25 +70,13 @@ 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();
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);
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) {
@@ -135,7 +89,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] + node.newline.trimEnd()};
msg = {topic:node.topic, payload:parts[i]};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
@@ -196,13 +150,7 @@ module.exports = function(RED) {
});
}
else {
let srv = net;
let connOpts;
if (n.tls) {
srv = tls;
connOpts = tlsNode.addTLSOptions({});
}
var server = srv.createServer(connOpts, function (socket) {
var server = net.createServer(function (socket) {
socket.setKeepAlive(true,120000);
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var id = RED.util.generateId();
@@ -229,7 +177,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] + node.newline.trimEnd(), ip:socket.remoteAddress, port:socket.remotePort};
msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
@@ -321,9 +269,8 @@ 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;
@@ -331,24 +278,11 @@ 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"});
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 = 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()}));
@@ -434,13 +368,7 @@ module.exports = function(RED) {
else {
var connectedSockets = [];
node.status({text:RED._("tcpin.status.connections",{count:0})});
let srv = net;
let connOpts;
if (n.tls) {
srv = tls;
connOpts = tlsNode.addTLSOptions({});
}
var server = srv.createServer(connOpts, function (socket) {
var server = net.createServer(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}));
@@ -517,11 +445,7 @@ 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); }
@@ -576,48 +500,12 @@ module.exports = function(RED) {
}
else { buf = Buffer.alloc(65536); } // set it to 64k... hopefully big enough for most TCP packets.... but only hopefully
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();
}
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(connOpts, function() {
clients[connection_id].client.connect(port, host, 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) {
@@ -640,32 +528,17 @@ 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 {
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); }
try { msg.payload = msg.payload.toString(); }
catch(e) { node.error("Failed to create string", msg); }
}
else { nodeSend(msg); }
nodeSend(msg);
}
}
// else if (node.splitc === 0) {
@@ -802,13 +675,7 @@ module.exports = function(RED) {
//node.warn(RED._("tcpin.errors.connect-timeout"));
if (clients[connection_id].client) {
clients[connection_id].connecting = true;
var connOpts = {host:host, port:port};
if (n.tls) {
connOpts = tlsNode.addTLSOptions(connOpts);
}
clients[connection_id].client.connect(connOpts, function() {
clients[connection_id].client.connect(port, host, function() {
clients[connection_id].connected = true;
clients[connection_id].connecting = false;
node.status({fill:"green",shape:"dot",text:"common.status.connected"});

View File

@@ -49,11 +49,7 @@ module.exports = function(RED) {
}
var value = RED.util.getMessageProperty(msg,node.property);
if (value !== undefined) {
if (typeof value === "string" || Buffer.isBuffer(value)) {
// if (Buffer.isBuffer(value) && node.action !== "obj") {
// node.warn(RED._("json.errors.dropped")); done();
// }
// else
if (typeof value === "string") {
if (node.action === "" || node.action === "obj") {
try {
RED.util.setMessageProperty(msg,node.property,JSON.parse(value));

View File

@@ -71,7 +71,9 @@ module.exports = function(RED) {
node.error(RED._("file.errors.deletefail",{error:err.toString()}),msg);
}
else {
node.debug(RED._("file.status.deletedfile",{file:filename}));
if (RED.settings.verbose) {
node.log(RED._("file.status.deletedfile",{file:filename}));
}
nodeSend(msg);
}
done();

View File

@@ -1,156 +0,0 @@
[
{
"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": []
}
]

View File

@@ -2,7 +2,7 @@
{
"id": "84222b92.d65d18",
"type": "inject",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"props": [
{
@@ -20,8 +20,8 @@
"topic": "",
"payload": "Hello, World!",
"payloadType": "str",
"x": 190,
"y": 180,
"x": 230,
"y": 220,
"wires": [
[
"b4b9f603.739598"
@@ -31,25 +31,25 @@
{
"id": "7b014430.dfd94c",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "Write string to a file, then read from the file",
"info": "Read file node can read string from a file.",
"x": 220,
"y": 100,
"info": "File-in node can read string from a file.",
"x": 260,
"y": 140,
"wires": []
},
{
"id": "b4b9f603.739598",
"type": "file",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "true",
"encoding": "none",
"x": 380,
"y": 180,
"x": 420,
"y": 220,
"wires": [
[
"6dc01cac.5c4bf4"
@@ -59,7 +59,7 @@
{
"id": "2587adb9.7e60f2",
"type": "debug",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"active": true,
"tosidebar": true,
@@ -68,22 +68,22 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 770,
"y": 180,
"x": 810,
"y": 220,
"wires": []
},
{
"id": "6dc01cac.5c4bf4",
"type": "file in",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "none",
"x": 580,
"y": 180,
"x": 620,
"y": 220,
"wires": [
[
"2587adb9.7e60f2"
@@ -93,21 +93,21 @@
{
"id": "f4b4309a.3b78a",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↑read result from file",
"info": "",
"x": 590,
"y": 220,
"x": 630,
"y": 260,
"wires": []
},
{
"id": "672d3693.3cabd8",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↓write to /tmp/hello.txt",
"info": "",
"x": 400,
"y": 140,
"x": 440,
"y": 180,
"wires": []
}
]

View File

@@ -2,7 +2,7 @@
{
"id": "8997398f.c5d628",
"type": "inject",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"props": [
{
@@ -20,8 +20,8 @@
"topic": "",
"payload": "😀",
"payloadType": "str",
"x": 170,
"y": 260,
"x": 210,
"y": 480,
"wires": [
[
"56e32d23.050f44"
@@ -31,25 +31,25 @@
{
"id": "4e598e65.1799d",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "Read data in specified encoding",
"info": "Read file node can specify encoding of data read from a file.",
"x": 190,
"y": 180,
"info": "File-in node can specify encoding of data read from a file.",
"x": 230,
"y": 400,
"wires": []
},
{
"id": "56e32d23.050f44",
"type": "file",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "true",
"encoding": "none",
"x": 340,
"y": 260,
"x": 380,
"y": 480,
"wires": [
[
"38fa0579.f2cd8a"
@@ -59,7 +59,7 @@
{
"id": "d28c8994.99c0a8",
"type": "debug",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"active": true,
"tosidebar": true,
@@ -68,23 +68,22 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 730,
"y": 260,
"x": 770,
"y": 480,
"wires": []
},
{
"id": "38fa0579.f2cd8a",
"type": "file in",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "base64",
"allProps": false,
"x": 540,
"y": 260,
"x": 580,
"y": 480,
"wires": [
[
"d28c8994.99c0a8"
@@ -94,21 +93,21 @@
{
"id": "fa22ca20.ae4528",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↑read data from file as base64 string",
"info": "",
"x": 600,
"y": 300,
"x": 640,
"y": 520,
"wires": []
},
{
"id": "148e25ad.98891a",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↓write to /tmp/hello.txt",
"info": "",
"x": 360,
"y": 220,
"x": 400,
"y": 440,
"wires": []
}
]

View File

@@ -2,7 +2,7 @@
{
"id": "6a0b1d03.d4cee4",
"type": "inject",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"props": [
{
@@ -20,8 +20,8 @@
"topic": "",
"payload": "",
"payloadType": "date",
"x": 160,
"y": 220,
"x": 220,
"y": 740,
"wires": [
[
"d4b00cb7.a5a23"
@@ -31,25 +31,25 @@
{
"id": "f17ea1d1.8ecc3",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "Read data breaking lines into individual messages",
"info": "Read file node can break read text into messages with individual lines",
"x": 230,
"y": 140,
"info": "File-in node can break read text into messages with individual lines",
"x": 290,
"y": 660,
"wires": []
},
{
"id": "99ae7806.1d6428",
"type": "file",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "true",
"encoding": "none",
"x": 480,
"y": 220,
"x": 540,
"y": 740,
"wires": [
[
"70d7892f.d27db8"
@@ -59,7 +59,7 @@
{
"id": "7ed8282c.92b338",
"type": "debug",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"active": true,
"tosidebar": true,
@@ -68,22 +68,22 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 750,
"y": 280,
"x": 810,
"y": 800,
"wires": []
},
{
"id": "70d7892f.d27db8",
"type": "file in",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"format": "lines",
"chunk": false,
"sendError": false,
"encoding": "none",
"x": 560,
"y": 280,
"x": 620,
"y": 800,
"wires": [
[
"7ed8282c.92b338"
@@ -93,27 +93,27 @@
{
"id": "c1b7e05.1d94b2",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↑read data from file breaking lines into messages",
"info": "",
"x": 660,
"y": 320,
"x": 720,
"y": 840,
"wires": []
},
{
"id": "a5f647b2.cf27a8",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↓write to /tmp/hello.txt",
"info": "",
"x": 500,
"y": 180,
"x": 560,
"y": 700,
"wires": []
},
{
"id": "d4b00cb7.a5a23",
"type": "template",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "data",
"field": "payload",
"fieldType": "msg",
@@ -121,8 +121,8 @@
"syntax": "plain",
"template": "one\ntwo\nthree!",
"output": "str",
"x": 310,
"y": 220,
"x": 370,
"y": 740,
"wires": [
[
"99ae7806.1d6428"

View File

@@ -2,7 +2,7 @@
{
"id": "bdd57acc.2edc48",
"type": "inject",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"props": [
{
@@ -20,8 +20,8 @@
"topic": "",
"payload": "",
"payloadType": "date",
"x": 180,
"y": 220,
"x": 220,
"y": 1040,
"wires": [
[
"7a069b01.0c2324"
@@ -31,25 +31,25 @@
{
"id": "1fd12220.33953e",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "Creating a message stream from lines of data",
"info": "Read file node can break read text into messages with individual lines. The messages creates a stream of messages.",
"x": 230,
"y": 140,
"info": "File-in node can break read text into messages with individual lines. The messages creates a stream of messages.",
"x": 270,
"y": 960,
"wires": []
},
{
"id": "ab6eb213.2a08d",
"type": "file",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "true",
"encoding": "none",
"x": 500,
"y": 220,
"x": 540,
"y": 1040,
"wires": [
[
"b7ed49b0.649fb8"
@@ -59,7 +59,7 @@
{
"id": "c48d8ae0.9ff3a8",
"type": "debug",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"active": true,
"tosidebar": true,
@@ -68,22 +68,22 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 770,
"y": 320,
"x": 810,
"y": 1140,
"wires": []
},
{
"id": "b7ed49b0.649fb8",
"type": "file in",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"filename": "/tmp/hello.txt",
"format": "lines",
"chunk": false,
"sendError": false,
"encoding": "none",
"x": 240,
"y": 320,
"x": 280,
"y": 1140,
"wires": [
[
"83073ebe.fcce4"
@@ -93,27 +93,27 @@
{
"id": "3c33e69f.6a04ba",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↑read data from file breaking lines into messages",
"info": "",
"x": 340,
"y": 360,
"x": 380,
"y": 1180,
"wires": []
},
{
"id": "3598bf7d.5712a",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↓write to /tmp/hello.txt",
"info": "",
"x": 520,
"y": 180,
"x": 560,
"y": 1000,
"wires": []
},
{
"id": "7a069b01.0c2324",
"type": "template",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "data",
"field": "payload",
"fieldType": "msg",
@@ -121,8 +121,8 @@
"syntax": "plain",
"template": "Apple\nBanana\nGrape\nOrange",
"output": "str",
"x": 330,
"y": 220,
"x": 370,
"y": 1040,
"wires": [
[
"ab6eb213.2a08d"
@@ -132,7 +132,7 @@
{
"id": "8d4ed1d0.821fe",
"type": "join",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "",
"mode": "auto",
"build": "string",
@@ -145,8 +145,8 @@
"timeout": "",
"count": "",
"reduceRight": false,
"x": 590,
"y": 320,
"x": 630,
"y": 1140,
"wires": [
[
"c48d8ae0.9ff3a8"
@@ -156,7 +156,7 @@
{
"id": "83073ebe.fcce4",
"type": "switch",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "< D",
"property": "payload",
"propertyType": "msg",
@@ -170,8 +170,8 @@
"checkall": "true",
"repair": true,
"outputs": 1,
"x": 430,
"y": 320,
"x": 470,
"y": 1140,
"wires": [
[
"8d4ed1d0.821fe"
@@ -181,21 +181,21 @@
{
"id": "2088e195.f7aebe",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↓filter data before \"D\"",
"info": "",
"x": 480,
"y": 280,
"x": 520,
"y": 1100,
"wires": []
},
{
"id": "b848cdc7.61e06",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "194a3e4f.a92772",
"name": "↑join to single string",
"info": "",
"x": 630,
"y": 360,
"x": 670,
"y": 1180,
"wires": []
}
]

View File

@@ -2,7 +2,7 @@
{
"id": "84222b92.d65d18",
"type": "inject",
"z": "5132b95f037524f9",
"z": "4b63452d.672afc",
"name": "",
"props": [
{
@@ -20,8 +20,8 @@
"topic": "",
"payload": "Hello, World!",
"payloadType": "str",
"x": 150,
"y": 220,
"x": 230,
"y": 200,
"wires": [
[
"b4b9f603.739598"
@@ -31,25 +31,25 @@
{
"id": "7b014430.dfd94c",
"type": "comment",
"z": "5132b95f037524f9",
"z": "4b63452d.672afc",
"name": "Write string to a file, then read from the file",
"info": "Write file node can write string from a file.",
"x": 180,
"y": 140,
"info": "File node can write string to a file.",
"x": 260,
"y": 120,
"wires": []
},
{
"id": "b4b9f603.739598",
"type": "file",
"z": "5132b95f037524f9",
"z": "4b63452d.672afc",
"name": "",
"filename": "/tmp/hello.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "true",
"encoding": "none",
"x": 340,
"y": 220,
"x": 420,
"y": 200,
"wires": [
[
"6dc01cac.5c4bf4"
@@ -59,7 +59,7 @@
{
"id": "2587adb9.7e60f2",
"type": "debug",
"z": "5132b95f037524f9",
"z": "4b63452d.672afc",
"name": "",
"active": true,
"tosidebar": true,
@@ -68,22 +68,22 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 730,
"y": 220,
"x": 810,
"y": 200,
"wires": []
},
{
"id": "6dc01cac.5c4bf4",
"type": "file in",
"z": "5132b95f037524f9",
"z": "4b63452d.672afc",
"name": "",
"filename": "/tmp/hello.txt",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "none",
"x": 540,
"y": 220,
"x": 620,
"y": 200,
"wires": [
[
"2587adb9.7e60f2"
@@ -93,21 +93,21 @@
{
"id": "f4b4309a.3b78a",
"type": "comment",
"z": "5132b95f037524f9",
"z": "4b63452d.672afc",
"name": "↑read result from file",
"info": "",
"x": 550,
"y": 260,
"x": 630,
"y": 240,
"wires": []
},
{
"id": "672d3693.3cabd8",
"type": "comment",
"z": "5132b95f037524f9",
"z": "4b63452d.672afc",
"name": "↓write to /tmp/hello.txt",
"info": "",
"x": 360,
"y": 180,
"x": 440,
"y": 160,
"wires": []
}
]

View File

@@ -2,7 +2,7 @@
{
"id": "704479e1.399388",
"type": "inject",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"props": [
{
@@ -25,8 +25,8 @@
"topic": "",
"payload": "Hello, World!",
"payloadType": "str",
"x": 190,
"y": 260,
"x": 230,
"y": 400,
"wires": [
[
"402f3b7e.988014"
@@ -36,25 +36,25 @@
{
"id": "8e876a75.e9beb8",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "Write string to a file specied by filename property, the read from the file",
"info": "Write file node can target file using `filename` property.",
"x": 310,
"y": 180,
"info": "File node can target file using `filename` property.",
"x": 350,
"y": 320,
"wires": []
},
{
"id": "402f3b7e.988014",
"type": "file",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"filename": "",
"appendNewline": true,
"createDir": false,
"overwriteFile": "true",
"encoding": "none",
"x": 350,
"y": 260,
"x": 390,
"y": 400,
"wires": [
[
"26e077d6.bbcd98"
@@ -64,7 +64,7 @@
{
"id": "97b6b6b2.a54b38",
"type": "debug",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"active": true,
"tosidebar": true,
@@ -73,22 +73,22 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 730,
"y": 260,
"x": 770,
"y": 400,
"wires": []
},
{
"id": "26e077d6.bbcd98",
"type": "file in",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"filename": "/tmp/hello.txt",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "none",
"x": 540,
"y": 260,
"x": 580,
"y": 400,
"wires": [
[
"97b6b6b2.a54b38"
@@ -98,21 +98,21 @@
{
"id": "85062297.da79",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "↑read result from file",
"info": "",
"x": 550,
"y": 300,
"x": 590,
"y": 440,
"wires": []
},
{
"id": "7316c4fc.b1dcdc",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "↓write to file specified by filename property",
"info": "",
"x": 460,
"y": 220,
"x": 500,
"y": 360,
"wires": []
}
]

View File

@@ -2,7 +2,7 @@
{
"id": "4ac00fb0.d5f52",
"type": "inject",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"props": [
{
@@ -20,8 +20,8 @@
"topic": "",
"payload": "",
"payloadType": "date",
"x": 180,
"y": 220,
"x": 220,
"y": 600,
"wires": [
[
"542cc2f4.92857c"
@@ -31,25 +31,25 @@
{
"id": "671f8295.0e6f6c",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "Delete a file",
"info": "Write file node can delete a file.",
"x": 130,
"y": 160,
"info": "File node can delete a file.",
"x": 170,
"y": 540,
"wires": []
},
{
"id": "542cc2f4.92857c",
"type": "file",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"filename": "/tmp/hello.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "delete",
"encoding": "none",
"x": 380,
"y": 220,
"x": 420,
"y": 600,
"wires": [
[
"a24da523.5babe8"
@@ -59,7 +59,7 @@
{
"id": "a24da523.5babe8",
"type": "debug",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"active": true,
"tosidebar": true,
@@ -68,18 +68,18 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 590,
"y": 220,
"x": 630,
"y": 600,
"wires": []
},
{
"id": "51157051.2f62",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "↓delete a file",
"info": "",
"x": 350,
"y": 180,
"x": 390,
"y": 560,
"wires": []
}
]

View File

@@ -2,8 +2,8 @@
{
"id": "e4ef1f5e.7cd82",
"type": "inject",
"z": "6312c0588348b2d4",
"name": "Base64 encoded string",
"z": "4b63452d.672afc",
"name": "",
"props": [
{
"p": "payload"
@@ -20,8 +20,8 @@
"topic": "",
"payload": "8J+YgA==",
"payloadType": "str",
"x": 200,
"y": 220,
"x": 220,
"y": 820,
"wires": [
[
"72b37cc8.177054"
@@ -31,25 +31,25 @@
{
"id": "f5997af4.5a9298",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "Specify encoding of written data",
"info": "Write file node can specify encoding of data.",
"x": 170,
"y": 140,
"info": "File node can specify encoding of data.",
"x": 230,
"y": 740,
"wires": []
},
{
"id": "72b37cc8.177054",
"type": "file",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"filename": "/tmp/hello.txt",
"appendNewline": true,
"createDir": false,
"overwriteFile": "true",
"encoding": "base64",
"x": 420,
"y": 220,
"x": 400,
"y": 820,
"wires": [
[
"2da33ec.f45cac2"
@@ -59,7 +59,7 @@
{
"id": "2e814354.278c8c",
"type": "debug",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"active": true,
"tosidebar": true,
@@ -68,22 +68,22 @@
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 810,
"y": 220,
"x": 790,
"y": 820,
"wires": []
},
{
"id": "2da33ec.f45cac2",
"type": "file in",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "",
"filename": "/tmp/hello.txt",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "none",
"x": 620,
"y": 220,
"x": 600,
"y": 820,
"wires": [
[
"2e814354.278c8c"
@@ -93,21 +93,21 @@
{
"id": "ec754c99.84bfd",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "↓write string with base64 encoding",
"info": "",
"x": 480,
"y": 180,
"x": 460,
"y": 780,
"wires": []
},
{
"id": "3e6704ff.4ce25c",
"type": "comment",
"z": "6312c0588348b2d4",
"z": "4b63452d.672afc",
"name": "↑read result from file",
"info": "",
"x": 630,
"y": 260,
"x": 610,
"y": 860,
"wires": []
}
]

View File

@@ -499,8 +499,7 @@
"label": {
"type": "Typ",
"path": "Pfad",
"url": "URL",
"subprotocol": "Subprotokoll"
"url": "URL"
},
"listenon": "Lauschen (listen on)",
"connectto": "Verbinden mit",
@@ -852,6 +851,7 @@
"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__",

View File

@@ -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 <code>msg.payload</code>. If not configured in the edit panel,
<dd>A template to be populated from msg.payload. If not configured in the edit panel,
this can be set as a property of msg.</dd>
</dl>
<h3>Outputs</h3>

View File

@@ -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></p>
<i>settings.js</i> file. For example <code>nodeMessageBufferMaxLength: 1000,</code>
</script>

View File

@@ -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 initial value, so as not to send anything at start.</p>
If required it can ignore the intial 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 &plusmn; 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 filter node can handle multiple different topics at the same time.</p>
This means that a single rbe node can handle multiple different topics at the same time.</p>
</script>

View File

@@ -530,8 +530,7 @@
"label": {
"type": "Type",
"path": "Path",
"url": "URL",
"subprotocol": "Subprotocol"
"url": "URL"
},
"listenon": "Listen on",
"connectto": "Connect to",
@@ -580,9 +579,7 @@
"server": "Server",
"return": "Return",
"ms": "ms",
"chars": "chars",
"close": "Close",
"optional": "(optional)"
"chars": "chars"
},
"type": {
"listen": "Listen on",
@@ -599,7 +596,7 @@
"return": {
"timeout": "after a fixed timeout of",
"character": "when character received is",
"number": "after a fixed number of characters",
"number": "a fixed number of chars",
"never": "never - keep connection open",
"immed": "immediately - don't wait for reply"
},
@@ -619,11 +616,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",
"bad-string": "failed to convert to string"
"connect-fail": "connect failed"
}
},
"udp": {

View File

@@ -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 containing the topic filter</li>
<li>a String continaing 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>

View File

@@ -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 property is an object of name/value pairs for each cookie.</dd>
<dd>If the response includes cookies, this propery 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>

View File

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

View File

@@ -29,12 +29,3 @@
<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>

View File

@@ -46,6 +46,4 @@
<code>{{global[store].名前}}</code>
</p>
<p><b>: </b>デフォルトでは、<i>mustache</i>形式は置換対象のHTML要素をエスケープしますこれを抑止するには<code>{{{三重}}}</code>使</p>
<p>もしコンテンツの中で<code>{{ }}</code>使<code>[[ ]]</code></p>
<pre>{{=[[ ]]=}}</pre>
</script>

View File

@@ -25,14 +25,11 @@
<dt class="optional">reset</dt>
<dd>受信メッセージでこのプロパティを任意の値に設定するとノードが保持する全ての未送信メッセージをクリアします</dd>
<dt class="optional">flush</dt>
<dd>本プロパティに数値が設定されたメッセージを受信すると直ちに指定された数のメッセージを送信しますもし他の型(例えば真偽型)が設定されている場合はノードが保持している全ての未送信メッセージを直ちに送信します</dd>
<dt class="optional">toFront</dt>
<dd>流量制御モードにおいて本プロパティに真偽型<code>true</code><code>msg.flush=1</code></dd>
<dd>受信メッセージでこのプロパティを任意の値に設定するとノードが保持る全ての未送信メッセージを直ちに送信します</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>

View File

@@ -27,5 +27,5 @@
<p>不感帯モードでは%による指定もサポートしています入力と前の値の差分がX%より大きな場合に出力を行います</p>
<p>狭帯域(narrowband)モードでは前の値に対する差分が一定値より大きな場合に入力ペイロードをブロックしますこのモードは故障したセンサから発生する外れ値を無視する時などに有用です</p>
<p>不感帯モードと狭帯域モードでは以前の有効出力値もしくは以前の入力値との比較ができます有効出力値を用いると範囲外の値を無視することが入力値を用いると設定点がリセットされるため漸次的変化(不感帯モード)もしくは段階的変化(狭帯域モード)が可能です</p>
<p><b>:</b> <code>msg.topic</code>filter</p>
<p><b>:</b> <code>msg.topic</code>rbe</p>
</script>

View File

@@ -144,16 +144,11 @@
"filterCurrent": "現在のフロー",
"debugNodes": "debugード",
"clearLog": "ログを削除",
"clearFilteredLog": "選択したメッセージを削除",
"filterLog": "ログのフィルタリング",
"openWindow": "新しいウィンドウで開く",
"copyPath": "パスをコピー",
"copyPayload": "値をコピー",
"pinPath": "展開を固定",
"selectAll": "全てを選択",
"selectNone": "選択を外す",
"all": "全て",
"filtered": "選択したメッセージ"
"pinPath": "展開を固定"
},
"messageMenu": {
"collapseAll": "全パスを折りたたむ",
@@ -164,15 +159,7 @@
},
"link": {
"linkIn": "link in",
"linkOut": "link out",
"linkCall": "link call",
"linkOutReturn": "link return",
"outMode": "モード",
"sendToAll": "接続された全てのlinkードへ送信",
"returnToCaller": "link callードへ返却",
"error": {
"missingReturn": "返却するノードの情報が存在しません"
}
"linkOut": "link out"
},
"tls": {
"tls": "TLS設定",
@@ -295,9 +282,7 @@
"and": "回/",
"rate": "流量",
"msgper": "メッセージ/",
"queuemsg": "中間メッセージをキューに追加",
"dropmsg": "中間メッセージを削除",
"sendmsg": "2番目の出力で中間メッセージを送信",
"allowrate": "msg.rate(ミリ秒単位)で流量値を上書き",
"label": {
"delay": "delay",
@@ -416,11 +401,7 @@
"maximumPacketSize": "最大パケット長",
"receiveMaximum": "最大受信数",
"session": "セッション",
"delay": "遅延",
"action": "動作",
"staticTopic": "1つのトピックを購読",
"dynamicTopic": "動的な購読",
"auto-connect": "自動接続"
"delay": "遅延"
},
"sections-label": {
"birth-message": "接続時の送信メッセージ(Birthメッセージ)",
@@ -461,10 +442,7 @@
"invalid-topic": "不正なトピックが設定されています",
"nonclean-missingclientid": "「セッションの初期化」使用時に、クライアントIDが設定されていません",
"invalid-json-string": "不正なJSON文字列",
"invalid-json-parse": "JSON文字列のパースに失敗しました",
"invalid-action-action": "指定された動作が不正です",
"invalid-action-alreadyconnected": "接続する前にブローカから切断してください",
"invalid-action-badsubscription": "msg.topicが存在しないか不正です"
"invalid-json-parse": "JSON文字列のパースに失敗しました"
}
},
"httpin": {
@@ -500,7 +478,6 @@
"proxy-config": "プロキシ設定",
"use-proxyauth": "プロキシ認証を使用",
"noproxy-hosts": "例外ホスト",
"senderr": "2xx以外の応答をcatchードへ送信",
"utf8": "UTF8文字列",
"binary": "バイナリバッファ",
"json": "JSONオブジェクト",
@@ -530,8 +507,7 @@
"label": {
"type": "種類",
"path": "パス",
"url": "URL",
"subprotocol": "サブプロトコル"
"url": "URL"
},
"listenon": "待ち受け",
"connectto": "接続",
@@ -727,15 +703,13 @@
"delete": "delete __property__",
"move": "move __property__",
"changeCount": "change: __count__ rules",
"regex": "正規表現を使用",
"deepCopy": "値のディープコピー"
"regex": "正規表現を使用"
},
"action": {
"set": "値の代入",
"change": "値の置換",
"delete": "値の削除",
"move": "値の移動",
"toValue": "対象の値",
"to": "対象の値",
"search": "検索する文字列",
"replace": "置換後の文字列"
@@ -877,8 +851,6 @@
},
"file": {
"label": {
"write": "write file",
"read": "read file",
"filename": "ファイル名",
"action": "動作",
"addnewline": "メッセージの入力のたびに改行を追加",
@@ -886,6 +858,7 @@
"outputas": "出力形式",
"breakchunks": "チャンクへ分割",
"breaklines": "行へ分割",
"filelabel": "file",
"sendError": "エラーメッセージを送信(互換モード)",
"encoding": "文字コード",
"deletelabel": "delete __file__",

View File

@@ -26,46 +26,11 @@
<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> - URLbrokerport</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">
@@ -74,24 +39,15 @@
<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>
@@ -99,24 +55,6 @@
<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> - URLbrokerport</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">
@@ -132,4 +70,5 @@
<h4>WebSocket</h4>
<p>WebSocketによる接続を行うように設定できますWebSocketを利用するにはサーバフィールドに接続先のURIを完全な形式で記述します以下に例を示します</p>
<pre>ws://example.com:4000/mqtt</pre>
</script>

View File

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

View File

@@ -52,6 +52,7 @@
<p>このモードで処理する際にはメッセージ数を予め知ることができないため<code>msg.parts.count</code><b>join</b></p>
</script>
<script type="text/html" data-help-name="join">
<p>メッセージ列を結合して一つのメッセージにします</p>
<p>メッセージの結合には次の3つのモードが利用できます</p>
@@ -79,10 +80,6 @@
</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>
@@ -99,7 +96,7 @@
</ul>
<p>出力メッセージのその他のプロパティはメッセージを送信する直前のメッセージをコピーします</p>
<p><i>合計値</i></p>
<p><i></i><code>msg.restartTimeout</code></p>
<p><i></i></p>
<p><code>msg.complete</code></p>
<p><code>msg.reset</code></p>

View File

@@ -433,8 +433,7 @@
"label": {
"type": "종류",
"path": "패스",
"url": "URL",
"subprotocol": "서브 프로토콜"
"url": "URL"
},
"listenon": "대기",
"connectto": "접속",
@@ -772,6 +771,7 @@
"outputas": "출력형식",
"breakchunks": "청크로 분할",
"breaklines": "행으로 분할",
"filelabel": "file",
"sendError": "에러메세지를 송신(호환모드)",
"deletelabel": "delete __file__",
"utf8String": "UTF8문자열",

View File

@@ -461,8 +461,7 @@
"label": {
"type": "Тип",
"path": "Путь",
"url": "URL",
"subprotocol": "Подпротокол"
"url": "URL"
},
"listenon": "Слушать на ...",
"connectto": "Присоединиться к ...",
@@ -817,6 +816,7 @@
"outputas": "Выход",
"breakchunks": "Разбить файл на части",
"breaklines": "Разбить на строки",
"filelabel": "файл",
"sendError": "Отправлять сообщение при ошибке (устаревший режим)",
"encoding": "Кодировка",
"deletelabel": "удалить __file__",

View File

@@ -454,8 +454,7 @@
"label": {
"type": "类型",
"path": "路径",
"url": "URL",
"subprotocol": "子协议"
"url": "URL"
},
"listenon": "监听",
"connectto": "连接",
@@ -805,6 +804,7 @@
"outputas": "输出",
"breakchunks": "分拆成块",
"breaklines": "分拆成行",
"filelabel": "文件",
"sendError": "发生错误时发送消息(传统模式)",
"encoding": "编码",
"deletelabel": "删除 __file__",

View File

@@ -458,8 +458,7 @@
"label": {
"type": "類型",
"path": "路徑",
"url": "URL",
"subprotocol": "子协议"
"url": "URL"
},
"listenon": "監聽",
"connectto": "連接",
@@ -810,6 +809,7 @@
"outputas": "輸出",
"breakchunks": "分拆成塊",
"breaklines": "分拆成行",
"filelabel": "文件",
"sendError": "發生錯誤時發送消息(傳統模式)",
"encoding": "編碼",
"deletelabel": "刪除 __file__",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "2.2.0-beta.1",
"version": "2.1.3",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -15,13 +15,13 @@
}
],
"dependencies": {
"acorn": "8.7.0",
"acorn": "8.5.0",
"acorn-walk": "8.2.0",
"ajv": "8.8.2",
"body-parser": "1.19.1",
"ajv": "8.6.3",
"body-parser": "1.19.0",
"cheerio": "1.0.0-rc.10",
"content-type": "1.0.4",
"cookie-parser": "1.4.6",
"cookie-parser": "1.4.5",
"cookie": "0.4.1",
"cors": "2.8.5",
"cronosjs": "1.7.1",
@@ -29,18 +29,18 @@
"form-data": "4.0.0",
"fs-extra": "10.0.0",
"fs.notify": "0.0.4",
"got": "11.8.3",
"got": "11.8.2",
"hash-sum": "2.0.0",
"hpagent": "0.1.2",
"https-proxy-agent": "5.0.0",
"is-utf8": "0.2.1",
"js-yaml": "3.14.1",
"media-typer": "1.1.0",
"mqtt": "4.3.4",
"mqtt": "4.2.8",
"multer": "1.4.3",
"mustache": "4.2.0",
"on-headers": "1.0.2",
"raw-body": "2.4.2",
"raw-body": "2.4.1",
"tough-cookie": "4.0.0",
"uuid": "8.3.2",
"ws": "7.5.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/registry",
"version": "2.2.0-beta.1",
"version": "2.1.3",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,11 +16,11 @@
}
],
"dependencies": {
"@node-red/util": "2.2.0-beta.1",
"@node-red/util": "2.1.3",
"clone": "2.1.2",
"fs-extra": "10.0.0",
"semver": "7.3.5",
"tar": "6.1.11",
"uglify-js": "3.14.5"
"uglify-js": "3.14.2"
}
}

View File

@@ -439,6 +439,8 @@ class Flow {
}
}
return [env.name, env];
return [env.name, env];
});
group._env = Object.fromEntries(entries);
}
@@ -455,24 +457,24 @@ class Flow {
const val
= ((value === "true") ||
(value === true));
return [{
return {
val: val
}, null];
};
}
if (type === "cred") {
return [{
return {
val: value
}, null];
};
}
try {
var val = redUtil.evaluateNodeProperty(value, type, node, null, null);
return [{
return {
val: val
}, null];
};
}
catch (e) {
this.error(e);
return [null, null];
return null;
}
}
}
@@ -486,7 +488,7 @@ class Flow {
return this.getGroupEnvSetting(node, parent, name);
}
}
return [null, name];
return null;
}
@@ -543,9 +545,6 @@ class Flow {
}
}
}
else {
key = key.substring(8);
}
}
return this.parent.getSetting(key);
}

View File

@@ -373,11 +373,10 @@ class Subflow extends Flow {
const node = this.subflowInstance;
if (node.g) {
const group = this.getGroupNode(node.g);
const [result, newName] = this.getGroupEnvSetting(node, group, name);
const result = this.getGroupEnvSetting(node, group, name);
if (result) {
return result.val;
}
name = newName;
}

View File

@@ -83,7 +83,6 @@ function createNode(flow,config) {
}
}
try {
Object.defineProperty(conf,'_module', {value: typeRegistry.getNodeInfo(type), enumerable: false, writable: true })
Object.defineProperty(conf,'_flow', {value: flow, enumerable: false, writable: true })
newNode = new nodeTypeConstructor(conf);
} catch (err) {

View File

@@ -59,9 +59,6 @@ function Node(n) {
// which we can tolerate as they are the same object.
Object.defineProperty(this,'_flow', {value: n._flow, enumerable: false, writable: true })
}
if (n._module) {
Object.defineProperty(this,'_module', {value: n._module, enumerable: false, writable: true })
}
this.updateWires(n.wires);
}
@@ -499,12 +496,7 @@ function log_helper(self, level, msg) {
if (self.name) {
o.name = self.name;
}
// See https://github.com/node-red/node-red/issues/3327
try {
self._flow.log(o);
} catch(err) {
logUnexpectedError(self, err)
}
self._flow.log(o);
}
/**
* Log an INFO level message
@@ -584,59 +576,4 @@ Node.prototype.status = function(status) {
this._flow.handleStatus(this,status);
};
function inspectObject(flow) {
try {
let properties = new Set()
let currentObj = flow
do {
if (!Object.getPrototypeOf(currentObj)) { break }
Object.getOwnPropertyNames(currentObj).map(item => properties.add(item))
} while ((currentObj = Object.getPrototypeOf(currentObj)))
let propList = [...properties.keys()].map(item => `${item}[${(typeof flow[item])[0]}]`)
propList.sort();
let result = [];
let line = "";
while (propList.length > 0) {
let prop = propList.shift()
if (line.length+prop.length > 80) {
result.push(line)
line = "";
} else {
line += " "+prop
}
}
if (line.length > 0) {
result.push(line);
}
return result.join("\n ")
} catch(err) {
return "Failed to capture object properties: "+err.toString()
}
}
function logUnexpectedError(node, error) {
let moduleInfo = node._module?`${node._module.module}@${node._module.version}`:"undefined"
Log.error(`
********************************************************************
Unexpected Node Error
${error.stack}
Node:
Type: ${node.type}
Module: ${moduleInfo}
ID: ${node._alias||node.id}
Properties:
${inspectObject(node)}
Flow: ${node._flow?node._flow.path:'undefined'}
Type: ${node._flow?node._flow.TYPE:'undefined'}
Properties:
${node._flow?inspectObject(node._flow):'undefined'}
Please report this issue, including the information logged above:
https://github.com/node-red/node-red/issues/
********************************************************************
`)
}
module.exports = Node;

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "2.2.0-beta.1",
"version": "2.1.3",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,11 +16,11 @@
}
],
"dependencies": {
"@node-red/registry": "2.2.0-beta.1",
"@node-red/util": "2.2.0-beta.1",
"@node-red/registry": "2.1.3",
"@node-red/util": "2.1.3",
"async-mutex": "0.3.2",
"clone": "2.1.2",
"express": "4.17.2",
"express": "4.17.1",
"fs-extra": "10.0.0",
"json-stringify-safe": "5.0.1"
}

View File

@@ -32,14 +32,8 @@ function wrapEventFunction(obj,func) {
return function(eventName, listener) {
if (deprecatedEvents.hasOwnProperty(eventName)) {
const log = require("@node-red/util").log;
const stack = (new Error().stack).split("\n");
let location = "(unknown)"
// See https://github.com/node-red/node-red/issues/3292
if (stack.length > 2) {
location = stack[2].split("(")[1].slice(0,-1);
}
log.warn(`[RED.events] Deprecated use of "${eventName}" event from "${location}". Use "${deprecatedEvents[eventName]}" instead.`)
const stack = (new Error().stack).split("\n")[2].split("(")[1].slice(0,-1);
log.warn(`[RED.events] Deprecated use of "${eventName}" event from "${stack}". Use "${deprecatedEvents[eventName]}" instead.`)
}
return events["_"+func].call(events,eventName,listener)
}

View File

@@ -136,6 +136,8 @@ function getCurrentLocale() {
function init(settings) {
if (!initPromise) {
// Keep this as a 'when' promise as top-level red.js uses 'otherwise'
// and embedded users of NR may have copied that.
initPromise = new Promise((resolve,reject) => {
i18n.use(MessageFileLoader);
var opt = {
@@ -144,8 +146,6 @@ function init(settings) {
defaultNS: "runtime",
ns: [],
fallbackLng: defaultLang,
keySeparator: ".",
nsSeparator: ":",
interpolation: {
unescapeSuffix: 'HTML',
escapeValue: false,

View File

@@ -526,11 +526,10 @@ function getSetting(node, name, flow_) {
if (flow) {
if (node && node.g) {
const group = flow.getGroupNode(node.g);
const [result, newName] = flow.getGroupEnvSetting(node, group, name);
const result = flow.getGroupEnvSetting(node, group, name);
if (result) {
return result.val;
}
name = newName;
}
return flow.getSetting(name);
}
@@ -686,7 +685,7 @@ function prepareJSONataExpression(value,node) {
return moment(arg1, arg2, arg3, arg4);
});
expr.registerFunction('clone', cloneMessage, '<(oa)-:o>');
expr._legacyMode = /(^|[^a-zA-Z0-9_'".])msg([^a-zA-Z0-9_'"]|$)/.test(value);
expr._legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(value);
expr._node = node;
return expr;
}
@@ -843,9 +842,6 @@ function encodeObject(msg,opts) {
length: msg.msg.size
}
needsStringify = true;
} else if (msg.msg && msg.msg.constructor.name === "RegExp") {
msg.format = 'regexp';
msg.msg = msg.msg.toString();
}
if (needsStringify || (msg.format === "Object")) {
msg.msg = safeJSONStringify(msg.msg, function(key, value) {
@@ -911,12 +907,6 @@ function encodeObject(msg,opts) {
data: Object.fromEntries(Array.from(value.entries()).slice(0,debuglength)),
length: value.size
}
} else if (value.constructor.name === "RegExp") {
value = {
__enc__: true,
type: "regexp",
data: value.toString()
}
}
} else if (value === undefined) {
value = {

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