mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
27 Commits
warn-inval
...
group-cont
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c71dfab7e3 | ||
|
|
42d0aa5d73 | ||
|
|
5b0be986c6 | ||
|
|
8af81280d9 | ||
|
|
6bd67ae68c | ||
|
|
f28bc1bff7 | ||
|
|
de8a5ea262 | ||
|
|
11ad03b21e | ||
|
|
9cb474ea9c | ||
|
|
fe9c630572 | ||
|
|
ce94226c3c | ||
|
|
f12d36b5ed | ||
|
|
3cb5259494 | ||
|
|
a351cd9d9f | ||
|
|
d8e01584f3 | ||
|
|
fb499be979 | ||
|
|
7da3773f7f | ||
|
|
fc657ecc71 | ||
|
|
313bab37e2 | ||
|
|
0caa308757 | ||
|
|
1fa8f30550 | ||
|
|
44300dbb34 | ||
|
|
1ddbeaa50f | ||
|
|
93a88a83a8 | ||
|
|
30ea300f65 | ||
|
|
04f4d5274d | ||
|
|
1f9695abd7 |
@@ -15,5 +15,5 @@
|
||||
"shadow": true, // allow variable shadowing (re-use of names...)
|
||||
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
||||
"proto": true, // allow setting of __proto__ in node < v0.12,
|
||||
"esversion": 6 // allow es6
|
||||
"esversion": 11 // allow es11(ES2020)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.0.0",
|
||||
"@node-red/editor-client": "3.0.0",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"@node-red/editor-client": "3.1.0-beta.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.20.0",
|
||||
"clone": "2.1.2",
|
||||
|
||||
@@ -57,18 +57,24 @@
|
||||
"addFlowToRight": "Add flow to the right",
|
||||
"hideFlow": "Hide flow",
|
||||
"hideOtherFlows": "Hide other flows",
|
||||
"showAllFlows": "Show all flows",
|
||||
"showAllFlows": "Show all flows (__count__ hidden)",
|
||||
"hideAllFlows": "Hide all flows",
|
||||
"hiddenFlows": "List __count__ hidden flow",
|
||||
"hiddenFlows_plural": "List __count__ hidden flows",
|
||||
"showLastHiddenFlow": "Show last hidden flow",
|
||||
"showLastHiddenFlow": "Reopen hidden flow",
|
||||
"listFlows": "List flows",
|
||||
"listSubflows": "List subflows",
|
||||
"status": "Status",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"info": "Description",
|
||||
"selectNodes": "Click nodes to select"
|
||||
"selectNodes": "Click nodes to select",
|
||||
"enableFlow": "Enable flow",
|
||||
"disableFlow": "Disable flow",
|
||||
"lockFlow": "Lock flow",
|
||||
"unlockFlow": "Unlock flow",
|
||||
"moveToStart": "Move flow to start",
|
||||
"moveToEnd": "Move flow to end"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
@@ -683,7 +689,9 @@
|
||||
"empty": "empty",
|
||||
"globalConfig": "Global Configuration Nodes",
|
||||
"triggerAction": "Trigger action",
|
||||
"find": "Find in workspace"
|
||||
"find": "Find in workspace",
|
||||
"copyItemUrl": "Copy item url",
|
||||
"copyURL2Clipboard": "Copied url to clipboard"
|
||||
},
|
||||
"help": {
|
||||
"name": "Help",
|
||||
|
||||
@@ -683,7 +683,8 @@
|
||||
"empty": "空",
|
||||
"globalConfig": "グローバル設定ノード",
|
||||
"triggerAction": "アクションを実行",
|
||||
"find": "ワークスペース内を検索"
|
||||
"find": "ワークスペース内を検索",
|
||||
"copyURL2Clipboard": "URLをクリップボードにコピーしました"
|
||||
},
|
||||
"help": {
|
||||
"name": "ヘルプ",
|
||||
@@ -1348,6 +1349,8 @@
|
||||
"show-project-settings": "プロジェクト設定を表示",
|
||||
"show-version-control-tab": "バージョンコントロールタブを表示",
|
||||
"start-flows": "フローを開始",
|
||||
"stop-flows": "フローを停止"
|
||||
"stop-flows": "フローを停止",
|
||||
"copy-item-url": "要素のURLをコピー",
|
||||
"copy-item-edit-url": "要素の編集URLをコピー"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
/**
|
||||
/**
|
||||
* An API for undo / redo history buffer
|
||||
* @namespace RED.history
|
||||
*/
|
||||
@@ -434,7 +434,9 @@ RED.history = (function() {
|
||||
|
||||
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) {
|
||||
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled);
|
||||
}
|
||||
if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('locked')) {
|
||||
$("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!ev.node.locked);
|
||||
}
|
||||
if (ev.subflow) {
|
||||
inverseEv.subflow = {};
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
* @namespace RED.nodes
|
||||
*/
|
||||
RED.nodes = (function() {
|
||||
|
||||
var PORT_TYPE_INPUT = 1;
|
||||
var PORT_TYPE_OUTPUT = 0;
|
||||
|
||||
@@ -63,6 +62,7 @@ RED.nodes = (function() {
|
||||
defaults: {
|
||||
label: {value:""},
|
||||
disabled: {value: false},
|
||||
locked: {value: false},
|
||||
info: {value: ""},
|
||||
env: {value: []}
|
||||
}
|
||||
@@ -575,15 +575,48 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
const nodeProxyHandler = {
|
||||
get(node, prop) {
|
||||
if (prop === '__isProxy__') {
|
||||
return true
|
||||
} else if (prop == '__node__') {
|
||||
return node
|
||||
}
|
||||
return node[prop]
|
||||
},
|
||||
set(node, prop, value) {
|
||||
if (node.z && (RED.nodes.workspace(node.z)?.locked || RED.nodes.subflow(node.z)?.locked)) {
|
||||
if (
|
||||
node._def.defaults[prop] ||
|
||||
prop === 'z' ||
|
||||
prop === 'l' ||
|
||||
prop === 'd' ||
|
||||
(prop === 'changed' && (!!node.changed) !== (!!value)) || // jshint ignore:line
|
||||
((prop === 'x' || prop === 'y') && !node.resize && node.type !== 'group')
|
||||
) {
|
||||
throw new Error(`Cannot modified property '${prop}' of locked object '${node.type}:${node.id}'`)
|
||||
}
|
||||
}
|
||||
node[prop] = value;
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function addNode(n) {
|
||||
let newNode
|
||||
if (!n.__isProxy__) {
|
||||
newNode = new Proxy(n, nodeProxyHandler)
|
||||
} else {
|
||||
newNode = n
|
||||
}
|
||||
|
||||
if (n.type.indexOf("subflow") !== 0) {
|
||||
n["_"] = n._def._;
|
||||
} else {
|
||||
var subflowId = n.type.substring(8);
|
||||
var sf = RED.nodes.subflow(subflowId);
|
||||
if (sf) {
|
||||
sf.instances.push(sf);
|
||||
sf.instances.push(newNode);
|
||||
}
|
||||
n["_"] = RED._;
|
||||
}
|
||||
@@ -600,12 +633,13 @@ RED.nodes = (function() {
|
||||
});
|
||||
n.i = nextId+1;
|
||||
}
|
||||
allNodes.addNode(n);
|
||||
allNodes.addNode(newNode);
|
||||
if (!nodeLinks[n.id]) {
|
||||
nodeLinks[n.id] = {in:[],out:[]};
|
||||
}
|
||||
}
|
||||
RED.events.emit('nodes:add',n);
|
||||
RED.events.emit('nodes:add',newNode);
|
||||
return newNode
|
||||
}
|
||||
function addLink(l) {
|
||||
if (nodeLinks[l.source.id]) {
|
||||
@@ -1052,6 +1086,9 @@ RED.nodes = (function() {
|
||||
node.type = n.type;
|
||||
for (var d in n._def.defaults) {
|
||||
if (n._def.defaults.hasOwnProperty(d)) {
|
||||
if (d === 'locked' && !n.locked) {
|
||||
continue
|
||||
}
|
||||
node[d] = n[d];
|
||||
}
|
||||
}
|
||||
@@ -1331,7 +1368,6 @@ RED.nodes = (function() {
|
||||
} else {
|
||||
nodeSet = [sf];
|
||||
}
|
||||
console.log(nodeSet);
|
||||
return createExportableNodeSet(nodeSet);
|
||||
}
|
||||
/**
|
||||
@@ -2318,19 +2354,6 @@ RED.nodes = (function() {
|
||||
if (n.g && !new_group_set.has(n.g)) {
|
||||
delete n.g;
|
||||
}
|
||||
n.nodes = n.nodes.map(function(id) {
|
||||
return node_map[id];
|
||||
})
|
||||
// Just in case the group references a node that doesn't exist for some reason
|
||||
n.nodes = n.nodes.filter(function(v) {
|
||||
if (v) {
|
||||
// Repair any nodes that have forgotten they are in this group
|
||||
if (v.g !== n.id) {
|
||||
v.g = n.id;
|
||||
}
|
||||
}
|
||||
return !!v
|
||||
});
|
||||
if (!n.g) {
|
||||
groupDepthMap[n.id] = 0;
|
||||
}
|
||||
@@ -2353,21 +2376,22 @@ RED.nodes = (function() {
|
||||
return groupDepthMap[A.id] - groupDepthMap[B.id];
|
||||
});
|
||||
for (i=0;i<new_groups.length;i++) {
|
||||
n = new_groups[i];
|
||||
addGroup(n);
|
||||
new_groups[i] = addGroup(new_groups[i]);
|
||||
node_map[new_groups[i].id] = new_groups[i]
|
||||
}
|
||||
|
||||
for (i=0;i<new_junctions.length;i++) {
|
||||
var junction = new_junctions[i];
|
||||
addJunction(junction);
|
||||
new_junctions[i] = addJunction(new_junctions[i]);
|
||||
node_map[new_junctions[i].id] = new_junctions[i]
|
||||
}
|
||||
|
||||
|
||||
// Now the nodes have been fully updated, add them.
|
||||
for (i=0;i<new_nodes.length;i++) {
|
||||
var node = new_nodes[i];
|
||||
addNode(node);
|
||||
new_nodes[i] = addNode(new_nodes[i])
|
||||
node_map[new_nodes[i].id] = new_nodes[i]
|
||||
}
|
||||
|
||||
// Finally validate them all.
|
||||
// This has to be done after everything is added so that any checks for
|
||||
// dependent config nodes will pass
|
||||
@@ -2375,6 +2399,39 @@ RED.nodes = (function() {
|
||||
var node = new_nodes[i];
|
||||
RED.editor.validateNode(node);
|
||||
}
|
||||
const lookupNode = (id) => {
|
||||
const mappedNode = node_map[id]
|
||||
if (!mappedNode) {
|
||||
return null
|
||||
}
|
||||
if (mappedNode.__isProxy__) {
|
||||
return mappedNode
|
||||
} else {
|
||||
return node_map[mappedNode.id]
|
||||
}
|
||||
}
|
||||
// Update groups to reference proxy node objects
|
||||
for (i=0;i<new_groups.length;i++) {
|
||||
n = new_groups[i];
|
||||
// bypass the proxy in case the flow is locked
|
||||
n.__node__.nodes = n.nodes.map(lookupNode)
|
||||
// Just in case the group references a node that doesn't exist for some reason
|
||||
n.__node__.nodes = n.nodes.filter(function(v) {
|
||||
if (v) {
|
||||
// Repair any nodes that have forgotten they are in this group
|
||||
if (v.g !== n.id) {
|
||||
v.g = n.id;
|
||||
}
|
||||
}
|
||||
return !!v
|
||||
});
|
||||
}
|
||||
|
||||
// Update links to use proxy node objects
|
||||
for (i=0;i<new_links.length;i++) {
|
||||
new_links[i].source = lookupNode(new_links[i].source.id) || new_links[i].source
|
||||
new_links[i].target = lookupNode(new_links[i].target.id) || new_links[i].target
|
||||
}
|
||||
|
||||
RED.workspaces.refresh();
|
||||
|
||||
@@ -2528,10 +2585,14 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
function addGroup(group) {
|
||||
if (!group.__isProxy__) {
|
||||
group = new Proxy(group, nodeProxyHandler)
|
||||
}
|
||||
groupsByZ[group.z] = groupsByZ[group.z] || [];
|
||||
groupsByZ[group.z].push(group);
|
||||
groups[group.id] = group;
|
||||
RED.events.emit("groups:add",group);
|
||||
return group
|
||||
}
|
||||
function removeGroup(group) {
|
||||
var i = groupsByZ[group.z].indexOf(group);
|
||||
@@ -2552,6 +2613,9 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
function addJunction(junction) {
|
||||
if (!junction.__isProxy__) {
|
||||
junction = new Proxy(junction, nodeProxyHandler)
|
||||
}
|
||||
junctionsByZ[junction.z] = junctionsByZ[junction.z] || []
|
||||
junctionsByZ[junction.z].push(junction)
|
||||
junctions[junction.id] = junction;
|
||||
@@ -2559,6 +2623,7 @@ RED.nodes = (function() {
|
||||
nodeLinks[junction.id] = {in:[],out:[]};
|
||||
}
|
||||
RED.events.emit("junctions:add", junction)
|
||||
return junction
|
||||
}
|
||||
function removeJunction(junction) {
|
||||
var i = junctionsByZ[junction.z].indexOf(junction)
|
||||
@@ -2834,7 +2899,7 @@ RED.nodes = (function() {
|
||||
},
|
||||
addWorkspace: addWorkspace,
|
||||
removeWorkspace: removeWorkspace,
|
||||
getWorkspaceOrder: function() { return workspacesOrder },
|
||||
getWorkspaceOrder: function() { return [...workspacesOrder] },
|
||||
setWorkspaceOrder: function(order) { workspacesOrder = order; },
|
||||
workspace: getWorkspace,
|
||||
|
||||
|
||||
@@ -249,8 +249,35 @@ var RED = (function() {
|
||||
RED.nodes.import(nodes.flows);
|
||||
RED.nodes.dirty(false);
|
||||
RED.view.redraw(true);
|
||||
if (/^#flow\/.+$/.test(currentHash)) {
|
||||
RED.workspaces.show(currentHash.substring(6),true);
|
||||
if (/^#(flow|node|group)\/.+$/.test(currentHash)) {
|
||||
const hashParts = currentHash.split('/')
|
||||
const showEditDialog = hashParts.length > 2 && hashParts[2] === 'edit'
|
||||
if (hashParts[0] === '#flow') {
|
||||
RED.workspaces.show(hashParts[1], true);
|
||||
if (showEditDialog) {
|
||||
RED.workspaces.edit()
|
||||
}
|
||||
} else if (hashParts[0] === '#node') {
|
||||
const nodeToShow = RED.nodes.node(hashParts[1])
|
||||
if (nodeToShow) {
|
||||
setTimeout(() => {
|
||||
RED.view.reveal(nodeToShow.id)
|
||||
window.location.hash = currentHash
|
||||
if (showEditDialog) {
|
||||
RED.editor.edit(nodeToShow)
|
||||
}
|
||||
}, 50)
|
||||
}
|
||||
} else if (hashParts[0] === '#group') {
|
||||
const nodeToShow = RED.nodes.group(hashParts[1])
|
||||
if (nodeToShow) {
|
||||
RED.view.reveal(nodeToShow.id)
|
||||
window.location.hash = currentHash
|
||||
if (showEditDialog) {
|
||||
RED.editor.editGroup(nodeToShow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RED.workspaces.count() > 0) {
|
||||
const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
@@ -641,11 +668,6 @@ var RED = (function() {
|
||||
]});
|
||||
|
||||
menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [
|
||||
{id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"},
|
||||
{id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"},
|
||||
{id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"},
|
||||
{id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"},
|
||||
null,
|
||||
{id: "menu-item-view-tools-align-left", label:RED._("menu.label.alignLeft"), disabled: true, onselect: "core:align-selection-to-left"},
|
||||
{id: "menu-item-view-tools-align-center", label:RED._("menu.label.alignCenter"), disabled: true, onselect: "core:align-selection-to-center"},
|
||||
{id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"},
|
||||
@@ -655,7 +677,12 @@ var RED = (function() {
|
||||
{id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"},
|
||||
null,
|
||||
{id: "menu-item-view-tools-distribute-horizontally", label:RED._("menu.label.distributeHorizontally"), disabled: true, onselect: "core:distribute-selection-horizontally"},
|
||||
{id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"}
|
||||
{id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"},
|
||||
null,
|
||||
{id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"},
|
||||
{id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"},
|
||||
{id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"},
|
||||
{id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"}
|
||||
]});
|
||||
|
||||
menuOptions.push(null);
|
||||
|
||||
@@ -423,11 +423,10 @@ RED.clipboard = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function showImportNodes(mode) {
|
||||
function showImportNodes(library = 'clipboard') {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
mode = mode || "clipboard";
|
||||
|
||||
dialogContainer.empty();
|
||||
dialogContainer.append($(importNodesDialog));
|
||||
@@ -504,7 +503,7 @@ RED.clipboard = (function() {
|
||||
$("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport);
|
||||
$("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
|
||||
|
||||
if (RED.workspaces.active() === 0) {
|
||||
if (RED.workspaces.active() === 0 || RED.workspaces.isActiveLocked()) {
|
||||
$("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected");
|
||||
$("#red-ui-clipboard-dialog-import-opt-new").addClass("selected");
|
||||
} else {
|
||||
@@ -533,8 +532,8 @@ RED.clipboard = (function() {
|
||||
$("#red-ui-clipboard-dialog-import-file-upload").trigger("click");
|
||||
})
|
||||
|
||||
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode);
|
||||
if (mode === 'clipboard') {
|
||||
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+library);
|
||||
if (library === 'clipboard') {
|
||||
setTimeout(function() {
|
||||
$("#red-ui-clipboard-dialog-import-text").trigger("focus");
|
||||
},100)
|
||||
@@ -558,13 +557,16 @@ RED.clipboard = (function() {
|
||||
});
|
||||
}
|
||||
|
||||
function showExportNodes(mode) {
|
||||
/**
|
||||
* Show the export dialog
|
||||
* @params library which export destination to show
|
||||
* @params mode whether to default to 'auto' (default) or 'flow'
|
||||
**/
|
||||
function showExportNodes(library = 'clipboard', mode = 'auto' ) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mode = mode || "clipboard";
|
||||
|
||||
dialogContainer.empty();
|
||||
dialogContainer.append($(exportNodesDialog));
|
||||
|
||||
@@ -766,12 +768,15 @@ RED.clipboard = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode === 'flow' && !$("#red-ui-clipboard-dialog-export-rng-flow").hasClass('disabled')) {
|
||||
$("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
|
||||
}
|
||||
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
|
||||
$("#red-ui-clipboard-dialog-export-fmt-full").trigger("click");
|
||||
} else {
|
||||
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
|
||||
}
|
||||
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);
|
||||
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+library);
|
||||
|
||||
var dialogHeight = 400;
|
||||
var winHeight = $(window).height();
|
||||
@@ -1266,15 +1271,17 @@ RED.clipboard = (function() {
|
||||
RED.keyboard.add("#red-ui-drop-target", "escape" ,hideDropTarget);
|
||||
|
||||
$('#red-ui-workspace-chart').on("dragenter",function(event) {
|
||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
|
||||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
||||
if (!RED.workspaces.isActiveLocked() && (
|
||||
$.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
|
||||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1)) {
|
||||
$("#red-ui-drop-target").css({display:'table'}).focus();
|
||||
}
|
||||
});
|
||||
|
||||
$('#red-ui-drop-target').on("dragover",function(event) {
|
||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 ||
|
||||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
||||
$.inArray("Files",event.originalEvent.dataTransfer.types) != -1 ||
|
||||
RED.workspaces.isActiveLocked()) {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
@@ -1282,27 +1289,29 @@ RED.clipboard = (function() {
|
||||
hideDropTarget();
|
||||
})
|
||||
.on("drop",function(event) {
|
||||
try {
|
||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
||||
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
||||
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
|
||||
importNodes(data);
|
||||
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
||||
var files = event.originalEvent.dataTransfer.files;
|
||||
if (files.length === 1) {
|
||||
var file = files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = (function(theFile) {
|
||||
return function(e) {
|
||||
importNodes(e.target.result);
|
||||
};
|
||||
})(file);
|
||||
reader.readAsText(file);
|
||||
if (!RED.workspaces.isActiveLocked()) {
|
||||
try {
|
||||
if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) {
|
||||
var data = event.originalEvent.dataTransfer.getData("text/plain");
|
||||
data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1);
|
||||
importNodes(data);
|
||||
} else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) {
|
||||
var files = event.originalEvent.dataTransfer.files;
|
||||
if (files.length === 1) {
|
||||
var file = files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = (function(theFile) {
|
||||
return function(e) {
|
||||
importNodes(e.target.result);
|
||||
};
|
||||
})(file);
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
// Ensure any errors throw above doesn't stop the drop target from
|
||||
// being hidden.
|
||||
}
|
||||
} catch(err) {
|
||||
// Ensure any errors throw above doesn't stop the drop target from
|
||||
// being hidden.
|
||||
}
|
||||
hideDropTarget();
|
||||
event.preventDefault();
|
||||
|
||||
@@ -94,8 +94,8 @@ RED.menu = (function() {
|
||||
|
||||
var link = $(linkContent).appendTo(item);
|
||||
opt.link = link;
|
||||
if (typeof opt.onselect === 'string') {
|
||||
var shortcut = RED.keyboard.getShortcut(opt.onselect);
|
||||
if (typeof opt.onselect === 'string' || opt.shortcut) {
|
||||
var shortcut = opt.shortcut || RED.keyboard.getShortcut(opt.onselect);
|
||||
if (shortcut && shortcut.key) {
|
||||
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(link.find(".red-ui-menu-label"));
|
||||
}
|
||||
|
||||
@@ -141,7 +141,29 @@ RED.tabs = (function() {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if (options.contextmenu) {
|
||||
wrapper.on('contextmenu', function(evt) {
|
||||
let clickedTab
|
||||
let target = evt.target
|
||||
while(target.nodeName !== 'A' && target.nodeName !== 'UL' && target.nodeName !== 'BODY') {
|
||||
target = target.parentNode
|
||||
}
|
||||
if (target.nodeName === 'A') {
|
||||
const href = target.getAttribute('href')
|
||||
if (href) {
|
||||
clickedTab = tabs[href.slice(1)]
|
||||
}
|
||||
}
|
||||
evt.preventDefault()
|
||||
evt.stopPropagation()
|
||||
RED.contextMenu.show({
|
||||
x:evt.clientX-5,
|
||||
y:evt.clientY-5,
|
||||
options: options.contextmenu(clickedTab)
|
||||
})
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
var scrollLeft;
|
||||
var scrollRight;
|
||||
@@ -809,17 +831,17 @@ RED.tabs = (function() {
|
||||
});
|
||||
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" />');
|
||||
closeLink.on("click",function(event) {
|
||||
event.preventDefault();
|
||||
hideTab(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" />');
|
||||
// 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);
|
||||
if (options.onselect) {
|
||||
@@ -938,6 +960,9 @@ RED.tabs = (function() {
|
||||
activeIndex: function() {
|
||||
return ul.find("li.active").index()
|
||||
},
|
||||
getTabIndex: function (id) {
|
||||
return ul.find("a[href='#"+id+"']").parent().index()
|
||||
},
|
||||
contains: function(id) {
|
||||
return ul.find("a[href='#"+id+"']").length > 0;
|
||||
},
|
||||
|
||||
@@ -1,21 +1,6 @@
|
||||
RED.contextMenu = (function () {
|
||||
|
||||
let menu;
|
||||
function createMenu() {
|
||||
// menu = RED.popover.menu({
|
||||
// options: [
|
||||
// {
|
||||
// label: 'delete selection',
|
||||
// onselect: function() {
|
||||
// RED.actions.invoke('core:delete-selection')
|
||||
// RED.view.focus()
|
||||
// }
|
||||
// },
|
||||
// { label: 'world' }
|
||||
// ],
|
||||
// width: 200,
|
||||
// })
|
||||
}
|
||||
|
||||
function disposeMenu() {
|
||||
$(document).off("mousedown.red-ui-workspace-context-menu");
|
||||
@@ -28,114 +13,164 @@ RED.contextMenu = (function () {
|
||||
if (menu) {
|
||||
menu.remove()
|
||||
}
|
||||
let menuItems = []
|
||||
if (options.options) {
|
||||
menuItems = options.options
|
||||
} else if (options.type === 'workspace') {
|
||||
const selection = RED.view.selection()
|
||||
const noSelection = !selection || Object.keys(selection).length === 0
|
||||
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||
const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || [];
|
||||
const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || [];
|
||||
const hasLinks = wireLinks.length > 0;
|
||||
const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1
|
||||
const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1
|
||||
const canDelete = hasSelection || hasLinks
|
||||
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
|
||||
const canEdit = !RED.workspaces.isActiveLocked()
|
||||
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
|
||||
const isAllGroups = hasSelection && selection.nodes.filter(n => n.type !== 'group').length === 0
|
||||
const hasGroup = hasSelection && selection.nodes.filter(n => n.type === 'group' ).length > 0
|
||||
const offset = $("#red-ui-workspace-chart").offset()
|
||||
|
||||
const selection = RED.view.selection()
|
||||
const noSelection = !selection || Object.keys(selection).length === 0
|
||||
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||
const hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||
const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || [];
|
||||
const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || [];
|
||||
const hasLinks = wireLinks.length > 0;
|
||||
const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1
|
||||
const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1
|
||||
const canDelete = hasSelection || hasLinks
|
||||
const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group'
|
||||
|
||||
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
|
||||
const offset = $("#red-ui-workspace-chart").offset()
|
||||
|
||||
let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()
|
||||
let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()
|
||||
|
||||
if (RED.view.snapGrid) {
|
||||
const gridSize = RED.view.gridSize()
|
||||
addX = gridSize * Math.floor(addX / gridSize)
|
||||
addY = gridSize * Math.floor(addY / gridSize)
|
||||
}
|
||||
|
||||
const menuItems = [
|
||||
{ onselect: 'core:show-action-list', onpostselect: function () { } },
|
||||
{
|
||||
label: RED._("contextMenu.insert"),
|
||||
options: [
|
||||
{
|
||||
label: RED._("contextMenu.node"),
|
||||
onselect: function () {
|
||||
RED.view.showQuickAddDialog({
|
||||
position: [addX, addY],
|
||||
touchTrigger: true,
|
||||
splice: isSingleLink ? selection.links[0] : undefined,
|
||||
// spliceMultiple: isMultipleLinks
|
||||
})
|
||||
}
|
||||
},
|
||||
(hasLinks) ? { // has least 1 wire selected
|
||||
label: RED._("contextMenu.junction"),
|
||||
onselect: 'core:split-wires-with-junctions',
|
||||
disabled: !hasLinks
|
||||
} : {
|
||||
label: RED._("contextMenu.junction"),
|
||||
onselect: function () {
|
||||
const nn = {
|
||||
_def: { defaults: {} },
|
||||
type: 'junction',
|
||||
z: RED.workspaces.active(),
|
||||
id: RED.nodes.id(),
|
||||
x: addX,
|
||||
y: addY,
|
||||
w: 0, h: 0,
|
||||
outputs: 1,
|
||||
inputs: 1,
|
||||
dirty: true
|
||||
}
|
||||
const historyEvent = {
|
||||
dirty: RED.nodes.dirty(),
|
||||
t: 'add',
|
||||
junctions: [nn]
|
||||
}
|
||||
RED.nodes.addJunction(nn);
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.select({nodes: [nn] });
|
||||
RED.view.redraw(true)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: RED._("contextMenu.linkNodes"),
|
||||
onselect: 'core:split-wire-with-link-nodes',
|
||||
disabled: !hasLinks
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()
|
||||
let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()
|
||||
|
||||
if (RED.view.snapGrid) {
|
||||
const gridSize = RED.view.gridSize()
|
||||
addX = gridSize * Math.floor(addX / gridSize)
|
||||
addY = gridSize * Math.floor(addY / gridSize)
|
||||
}
|
||||
|
||||
menuItems.push(
|
||||
{ onselect: 'core:show-action-list', onpostselect: function () { } }
|
||||
)
|
||||
|
||||
const insertOptions = []
|
||||
menuItems.push({ label: RED._("contextMenu.insert"), options: insertOptions })
|
||||
insertOptions.push(
|
||||
{
|
||||
label: RED._("contextMenu.node"),
|
||||
onselect: function () {
|
||||
RED.view.showQuickAddDialog({
|
||||
position: [addX, addY],
|
||||
touchTrigger: true,
|
||||
splice: isSingleLink ? selection.links[0] : undefined,
|
||||
// spliceMultiple: isMultipleLinks
|
||||
})
|
||||
},
|
||||
disabled: !canEdit
|
||||
},
|
||||
(hasLinks) ? { // has least 1 wire selected
|
||||
label: RED._("contextMenu.junction"),
|
||||
onselect: 'core:split-wires-with-junctions',
|
||||
disabled: !canEdit || !hasLinks
|
||||
} : {
|
||||
label: RED._("contextMenu.junction"),
|
||||
onselect: function () {
|
||||
const nn = {
|
||||
_def: { defaults: {} },
|
||||
type: 'junction',
|
||||
z: RED.workspaces.active(),
|
||||
id: RED.nodes.id(),
|
||||
x: addX,
|
||||
y: addY,
|
||||
w: 0, h: 0,
|
||||
outputs: 1,
|
||||
inputs: 1,
|
||||
dirty: true
|
||||
}
|
||||
const historyEvent = {
|
||||
dirty: RED.nodes.dirty(),
|
||||
t: 'add',
|
||||
junctions: [nn]
|
||||
}
|
||||
RED.nodes.addJunction(nn);
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.select({nodes: [nn] });
|
||||
RED.view.redraw(true)
|
||||
},
|
||||
disabled: !canEdit
|
||||
},
|
||||
{
|
||||
label: RED._("contextMenu.linkNodes"),
|
||||
onselect: 'core:split-wire-with-link-nodes',
|
||||
disabled: !canEdit || !hasLinks
|
||||
},
|
||||
null,
|
||||
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
|
||||
{ onselect: 'core:show-examples-import-dialog', label: 'Import Example Flow' }
|
||||
)
|
||||
if (hasSelection && canEdit) {
|
||||
const nodeOptions = []
|
||||
if (!hasMultipleSelection && !isGroup) {
|
||||
nodeOptions.push(
|
||||
{ onselect: 'core:show-node-help' },
|
||||
null
|
||||
)
|
||||
}
|
||||
nodeOptions.push(
|
||||
{ onselect: 'core:enable-selected-nodes' },
|
||||
{ onselect: 'core:disable-selected-nodes' },
|
||||
null,
|
||||
{ onselect: 'core:show-selected-node-labels' },
|
||||
{ onselect: 'core:hide-selected-node-labels' }
|
||||
)
|
||||
menuItems.push({
|
||||
label: 'Node',
|
||||
options: nodeOptions
|
||||
})
|
||||
menuItems.push({
|
||||
label: 'Group',
|
||||
options: [
|
||||
{ onselect: 'core:group-selection' },
|
||||
{ onselect: 'core:ungroup-selection', disabled: !hasGroup },
|
||||
null,
|
||||
{ onselect: 'core:copy-group-style', disabled: !hasGroup },
|
||||
{ onselect: 'core:paste-group-style', disabled: !hasGroup}
|
||||
]
|
||||
})
|
||||
if (canRemoveFromGroup) {
|
||||
menuItems[menuItems.length - 1].options.push(
|
||||
null,
|
||||
{ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") }
|
||||
)
|
||||
}
|
||||
}
|
||||
if (canEdit && hasMultipleSelection) {
|
||||
menuItems.push({
|
||||
label: 'Arrange',
|
||||
options: [
|
||||
{ label:RED._("menu.label.alignLeft"), onselect: "core:align-selection-to-left"},
|
||||
{ label:RED._("menu.label.alignCenter"), onselect: "core:align-selection-to-center"},
|
||||
{ label:RED._("menu.label.alignRight"), onselect: "core:align-selection-to-right"},
|
||||
null,
|
||||
{ label:RED._("menu.label.alignTop"), onselect: "core:align-selection-to-top"},
|
||||
{ label:RED._("menu.label.alignMiddle"), onselect: "core:align-selection-to-middle"},
|
||||
{ label:RED._("menu.label.alignBottom"), onselect: "core:align-selection-to-bottom"},
|
||||
null,
|
||||
{ label:RED._("menu.label.distributeHorizontally"), onselect: "core:distribute-selection-horizontally"},
|
||||
{ label:RED._("menu.label.distributeVertically"), onselect: "core:distribute-selection-vertically"}
|
||||
]
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
menuItems.push(
|
||||
null,
|
||||
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
|
||||
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
|
||||
null,
|
||||
{ onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection },
|
||||
{ onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection },
|
||||
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() },
|
||||
{ onselect: 'core:delete-selection', disabled: !canDelete },
|
||||
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
|
||||
{ onselect: 'core:select-all-nodes' }
|
||||
)
|
||||
|
||||
if (hasSelection) {
|
||||
menuItems.push(
|
||||
null,
|
||||
isGroup ?
|
||||
{ onselect: 'core:ungroup-selection', disabled: !isGroup }
|
||||
: { onselect: 'core:group-selection', disabled: !hasSelection }
|
||||
{ onselect: 'core:undo', disabled: RED.history.list().length === 0 },
|
||||
{ onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 },
|
||||
null,
|
||||
{ onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !canEdit || !hasSelection },
|
||||
{ onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection },
|
||||
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() },
|
||||
{ onselect: 'core:delete-selection', disabled: !canEdit || !canDelete },
|
||||
{ onselect: 'core:delete-selection-and-reconnect', label: 'Delete and Reconnect', disabled: !canEdit || !canDelete },
|
||||
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
|
||||
{ onselect: 'core:select-all-nodes' },
|
||||
)
|
||||
if (canRemoveFromGroup) {
|
||||
menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var direction = "right";
|
||||
@@ -144,7 +179,7 @@ RED.contextMenu = (function () {
|
||||
($(window).width() -MENU_WIDTH)) {
|
||||
direction = "left";
|
||||
}
|
||||
|
||||
|
||||
menu = RED.menu.init({
|
||||
direction: direction,
|
||||
onpreselect: function() {
|
||||
|
||||
@@ -558,6 +558,11 @@ RED.deploy = (function() {
|
||||
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
|
||||
}
|
||||
RED.nodes.eachNode(function (node) {
|
||||
const flow = node.z && (RED.nodes.workspace(node.z) || RED.nodes.subflow(node.z) || null);
|
||||
const isLocked = flow ? flow.locked : false;
|
||||
if (flow && isLocked) {
|
||||
flow.locked = false;
|
||||
}
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
@@ -569,6 +574,9 @@ RED.deploy = (function() {
|
||||
if (node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
if (flow && isLocked) {
|
||||
flow.locked = isLocked;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
|
||||
@@ -1847,11 +1847,15 @@ RED.editor = (function() {
|
||||
workspace.disabled = disabled;
|
||||
|
||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled);
|
||||
if (workspace.id === RED.workspaces.active()) {
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
|
||||
}
|
||||
}
|
||||
|
||||
var locked = $("#node-input-locked").prop("checked");
|
||||
if (workspace.locked !== locked) {
|
||||
editState.changes.locked = workspace.locked;
|
||||
editState.changed = true;
|
||||
workspace.locked = locked;
|
||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked);
|
||||
}
|
||||
if (editState.changed) {
|
||||
var historyEvent = {
|
||||
t: "edit",
|
||||
@@ -1892,6 +1896,7 @@ RED.editor = (function() {
|
||||
var trayBody = tray.find('.red-ui-tray-body');
|
||||
trayBody.parent().css('overflow','hidden');
|
||||
var trayFooterLeft = $('<div class="red-ui-tray-footer-left"></div>').appendTo(trayFooter)
|
||||
var trayFooterRight = $('<div class="red-ui-tray-footer-right"></div>').appendTo(trayFooter)
|
||||
|
||||
var nodeEditPanes = [
|
||||
'editor-tab-flow-properties',
|
||||
@@ -1906,6 +1911,18 @@ RED.editor = (function() {
|
||||
disabledIcon: "fa-ban",
|
||||
invertState: true
|
||||
})
|
||||
|
||||
if (!workspace.hasOwnProperty("locked")) {
|
||||
workspace.locked = false;
|
||||
}
|
||||
$('<input id="node-input-locked" type="checkbox">').prop("checked",workspace.locked).appendTo(trayFooterRight).toggleButton({
|
||||
enabledLabel: 'Unlocked',
|
||||
enabledIcon: "fa-unlock-alt",
|
||||
disabledLabel: 'Locked',
|
||||
disabledIcon: "fa-lock",
|
||||
invertState: true
|
||||
})
|
||||
|
||||
prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) {
|
||||
activeEditPanes = _activeEditPanes;
|
||||
trayBody.i18n();
|
||||
|
||||
@@ -2,7 +2,7 @@ RED.editor.envVarList = (function() {
|
||||
|
||||
var currentLocale = 'en-US';
|
||||
var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
||||
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred'];
|
||||
var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred','jsonata'];
|
||||
|
||||
/**
|
||||
* Create env var edit interface
|
||||
|
||||
@@ -52,8 +52,6 @@
|
||||
node.info = info;
|
||||
}
|
||||
$("#red-ui-tab-"+(node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!node.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!node.disabled);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -185,6 +185,8 @@ RED.group = (function() {
|
||||
var activateMerge = false;
|
||||
var activateRemove = false;
|
||||
var singleGroupSelected = false;
|
||||
var locked = RED.workspaces.isActiveLocked()
|
||||
|
||||
if (activateGroup) {
|
||||
singleGroupSelected = selection.nodes.length === 1 && selection.nodes[0].type === 'group';
|
||||
selection.nodes.forEach(function (n) {
|
||||
@@ -199,12 +201,12 @@ RED.group = (function() {
|
||||
activateMerge = (selection.nodes.length > 1);
|
||||
}
|
||||
}
|
||||
RED.menu.setDisabled("menu-item-group-group", !activateGroup);
|
||||
RED.menu.setDisabled("menu-item-group-ungroup", !activateUngroup);
|
||||
RED.menu.setDisabled("menu-item-group-merge", !activateMerge);
|
||||
RED.menu.setDisabled("menu-item-group-remove", !activateRemove);
|
||||
RED.menu.setDisabled("menu-item-group-group", locked || !activateGroup);
|
||||
RED.menu.setDisabled("menu-item-group-ungroup", locked || !activateUngroup);
|
||||
RED.menu.setDisabled("menu-item-group-merge", locked || !activateMerge);
|
||||
RED.menu.setDisabled("menu-item-group-remove", locked || !activateRemove);
|
||||
RED.menu.setDisabled("menu-item-edit-copy-group-style", !singleGroupSelected);
|
||||
RED.menu.setDisabled("menu-item-edit-paste-group-style", !activateUngroup);
|
||||
RED.menu.setDisabled("menu-item-edit-paste-group-style", locked || !activateUngroup);
|
||||
});
|
||||
|
||||
RED.actions.add("core:group-selection", function() { groupSelection() })
|
||||
@@ -261,6 +263,7 @@ RED.group = (function() {
|
||||
}
|
||||
}
|
||||
function pasteGroupStyle() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
if (groupStyleClipboard) {
|
||||
var selection = RED.view.selection();
|
||||
@@ -295,6 +298,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
function groupSelection() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
@@ -313,6 +317,7 @@ RED.group = (function() {
|
||||
}
|
||||
}
|
||||
function ungroupSelection() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
@@ -336,6 +341,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
function ungroup(g) {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
var nodes = [];
|
||||
var parentGroup = RED.nodes.group(g.g);
|
||||
g.nodes.forEach(function(n) {
|
||||
@@ -362,6 +368,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
function mergeSelection() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
@@ -431,6 +438,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
function removeSelection() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (RED.view.state() !== RED.state.DEFAULT) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
@@ -458,6 +466,7 @@ RED.group = (function() {
|
||||
}
|
||||
}
|
||||
function createGroup(nodes) {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -480,7 +489,7 @@ RED.group = (function() {
|
||||
}
|
||||
|
||||
group.z = nodes[0].z;
|
||||
RED.nodes.addGroup(group);
|
||||
group = RED.nodes.addGroup(group);
|
||||
|
||||
try {
|
||||
addToGroup(group,nodes);
|
||||
@@ -563,6 +572,7 @@ RED.group = (function() {
|
||||
markDirty(group);
|
||||
}
|
||||
function removeFromGroup(group, nodes, reparent) {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (!Array.isArray(nodes)) {
|
||||
nodes = [nodes];
|
||||
}
|
||||
|
||||
@@ -282,6 +282,7 @@ RED.palette = (function() {
|
||||
var hoverGroup;
|
||||
var paletteWidth;
|
||||
var paletteTop;
|
||||
var dropEnabled;
|
||||
$(d).draggable({
|
||||
helper: 'clone',
|
||||
appendTo: '#red-ui-editor',
|
||||
@@ -289,6 +290,7 @@ RED.palette = (function() {
|
||||
revertDuration: 200,
|
||||
containment:'#red-ui-main-container',
|
||||
start: function() {
|
||||
dropEnabled = !RED.nodes.workspace(RED.workspaces.active()).locked;
|
||||
paletteWidth = $("#red-ui-palette").width();
|
||||
paletteTop = $("#red-ui-palette").parent().position().top + $("#red-ui-palette-container").position().top;
|
||||
hoverGroup = null;
|
||||
@@ -299,96 +301,100 @@ RED.palette = (function() {
|
||||
RED.view.focus();
|
||||
},
|
||||
stop: function() {
|
||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||
if (hoverGroup) {
|
||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||
if (dropEnabled) {
|
||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||
if (hoverGroup) {
|
||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||
}
|
||||
if (activeGroup) {
|
||||
document.getElementById("group_select_"+activeGroup.id).classList.remove("red-ui-flow-group-active-hovered");
|
||||
}
|
||||
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
|
||||
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
|
||||
}
|
||||
if (activeGroup) {
|
||||
document.getElementById("group_select_"+activeGroup.id).classList.remove("red-ui-flow-group-active-hovered");
|
||||
}
|
||||
if (spliceTimer) { clearTimeout(spliceTimer); spliceTimer = null; }
|
||||
if (groupTimer) { clearTimeout(groupTimer); groupTimer = null; }
|
||||
},
|
||||
drag: function(e,ui) {
|
||||
var paletteNode = getPaletteNode(nt);
|
||||
ui.originalPosition.left = paletteNode.offset().left;
|
||||
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
||||
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
|
||||
if (!groupTimer) {
|
||||
groupTimer = setTimeout(function() {
|
||||
var mx = mouseX / RED.view.scale();
|
||||
var my = mouseY / RED.view.scale();
|
||||
var group = RED.view.getGroupAtPoint(mx,my);
|
||||
if (group !== hoverGroup) {
|
||||
if (hoverGroup) {
|
||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||
}
|
||||
if (group) {
|
||||
document.getElementById("group_select_"+group.id).classList.add("red-ui-flow-group-hovered");
|
||||
}
|
||||
hoverGroup = group;
|
||||
if (hoverGroup) {
|
||||
$(ui.helper).data('group',hoverGroup);
|
||||
} else {
|
||||
$(ui.helper).removeData('group');
|
||||
}
|
||||
}
|
||||
groupTimer = null;
|
||||
|
||||
},200)
|
||||
}
|
||||
if (def.inputs > 0 && def.outputs > 0) {
|
||||
if (!spliceTimer) {
|
||||
spliceTimer = setTimeout(function() {
|
||||
var nodes = [];
|
||||
var bestDistance = Infinity;
|
||||
var bestLink = null;
|
||||
if (chartSVG.getIntersectionList) {
|
||||
var svgRect = chartSVG.createSVGRect();
|
||||
svgRect.x = mouseX;
|
||||
svgRect.y = mouseY;
|
||||
svgRect.width = 1;
|
||||
svgRect.height = 1;
|
||||
nodes = chartSVG.getIntersectionList(svgRect,chartSVG);
|
||||
} else {
|
||||
// Firefox doesn't do getIntersectionList and that
|
||||
// makes us sad
|
||||
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
|
||||
}
|
||||
if (dropEnabled) {
|
||||
mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
|
||||
mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
|
||||
if (!groupTimer) {
|
||||
groupTimer = setTimeout(function() {
|
||||
var mx = mouseX / RED.view.scale();
|
||||
var my = mouseY / RED.view.scale();
|
||||
for (var i=0;i<nodes.length;i++) {
|
||||
var node = d3.select(nodes[i]);
|
||||
if (node.classed('red-ui-flow-link-background') && !node.classed('red-ui-flow-link-link')) {
|
||||
var length = nodes[i].getTotalLength();
|
||||
for (var j=0;j<length;j+=10) {
|
||||
var p = nodes[i].getPointAtLength(j);
|
||||
var d2 = ((p.x-mx)*(p.x-mx))+((p.y-my)*(p.y-my));
|
||||
if (d2 < 200 && d2 < bestDistance) {
|
||||
bestDistance = d2;
|
||||
bestLink = nodes[i];
|
||||
var group = RED.view.getGroupAtPoint(mx,my);
|
||||
if (group !== hoverGroup) {
|
||||
if (hoverGroup) {
|
||||
document.getElementById("group_select_"+hoverGroup.id).classList.remove("red-ui-flow-group-hovered");
|
||||
}
|
||||
if (group) {
|
||||
document.getElementById("group_select_"+group.id).classList.add("red-ui-flow-group-hovered");
|
||||
}
|
||||
hoverGroup = group;
|
||||
if (hoverGroup) {
|
||||
$(ui.helper).data('group',hoverGroup);
|
||||
} else {
|
||||
$(ui.helper).removeData('group');
|
||||
}
|
||||
}
|
||||
groupTimer = null;
|
||||
|
||||
},200)
|
||||
}
|
||||
if (def.inputs > 0 && def.outputs > 0) {
|
||||
if (!spliceTimer) {
|
||||
spliceTimer = setTimeout(function() {
|
||||
var nodes = [];
|
||||
var bestDistance = Infinity;
|
||||
var bestLink = null;
|
||||
if (chartSVG.getIntersectionList) {
|
||||
var svgRect = chartSVG.createSVGRect();
|
||||
svgRect.x = mouseX;
|
||||
svgRect.y = mouseY;
|
||||
svgRect.width = 1;
|
||||
svgRect.height = 1;
|
||||
nodes = chartSVG.getIntersectionList(svgRect,chartSVG);
|
||||
} else {
|
||||
// Firefox doesn't do getIntersectionList and that
|
||||
// makes us sad
|
||||
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
|
||||
}
|
||||
var mx = mouseX / RED.view.scale();
|
||||
var my = mouseY / RED.view.scale();
|
||||
for (var i=0;i<nodes.length;i++) {
|
||||
var node = d3.select(nodes[i]);
|
||||
if (node.classed('red-ui-flow-link-background') && !node.classed('red-ui-flow-link-link')) {
|
||||
var length = nodes[i].getTotalLength();
|
||||
for (var j=0;j<length;j+=10) {
|
||||
var p = nodes[i].getPointAtLength(j);
|
||||
var d2 = ((p.x-mx)*(p.x-mx))+((p.y-my)*(p.y-my));
|
||||
if (d2 < 200 && d2 < bestDistance) {
|
||||
bestDistance = d2;
|
||||
bestLink = nodes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activeSpliceLink && activeSpliceLink !== bestLink) {
|
||||
d3.select(activeSpliceLink.parentNode).classed('red-ui-flow-link-splice',false);
|
||||
}
|
||||
if (bestLink) {
|
||||
d3.select(bestLink.parentNode).classed('red-ui-flow-link-splice',true)
|
||||
} else {
|
||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||
}
|
||||
if (activeSpliceLink !== bestLink) {
|
||||
if (bestLink) {
|
||||
$(ui.helper).data('splice',d3.select(bestLink).data()[0]);
|
||||
} else {
|
||||
$(ui.helper).removeData('splice');
|
||||
if (activeSpliceLink && activeSpliceLink !== bestLink) {
|
||||
d3.select(activeSpliceLink.parentNode).classed('red-ui-flow-link-splice',false);
|
||||
}
|
||||
}
|
||||
activeSpliceLink = bestLink;
|
||||
spliceTimer = null;
|
||||
},200);
|
||||
if (bestLink) {
|
||||
d3.select(bestLink.parentNode).classed('red-ui-flow-link-splice',true)
|
||||
} else {
|
||||
d3.select('.red-ui-flow-link-splice').classed('red-ui-flow-link-splice',false);
|
||||
}
|
||||
if (activeSpliceLink !== bestLink) {
|
||||
if (bestLink) {
|
||||
$(ui.helper).data('splice',d3.select(bestLink).data()[0]);
|
||||
} else {
|
||||
$(ui.helper).removeData('splice');
|
||||
}
|
||||
}
|
||||
activeSpliceLink = bestLink;
|
||||
spliceTimer = null;
|
||||
},200);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,44 +431,7 @@ RED.subflow = (function() {
|
||||
|
||||
$("#red-ui-subflow-delete").on("click", function(event) {
|
||||
event.preventDefault();
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
if (subflow.instances.length > 0) {
|
||||
var msg = $('<div>')
|
||||
$('<p>').text(RED._("subflow.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
|
||||
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
|
||||
var confirmDeleteNotification = RED.notify(msg, {
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._('common.label.cancel'),
|
||||
click: function() {
|
||||
confirmDeleteNotification.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: RED._('workspace.confirmDelete'),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
confirmDeleteNotification.close();
|
||||
completeDelete();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
return;
|
||||
} else {
|
||||
completeDelete();
|
||||
}
|
||||
function completeDelete() {
|
||||
var startDirty = RED.nodes.dirty();
|
||||
var historyEvent = removeSubflow(RED.workspaces.active());
|
||||
historyEvent.t = 'delete';
|
||||
historyEvent.dirty = startDirty;
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
|
||||
RED.subflow.delete(RED.workspaces.active())
|
||||
});
|
||||
|
||||
refreshToolbar(activeSubflow);
|
||||
@@ -481,7 +444,51 @@ RED.subflow = (function() {
|
||||
$("#red-ui-workspace-toolbar").hide().empty();
|
||||
$("#red-ui-workspace-chart").css({"margin-top": "0"});
|
||||
}
|
||||
function deleteSubflow(id) {
|
||||
const subflow = RED.nodes.subflow(id || RED.workspaces.active());
|
||||
if (!subflow) {
|
||||
return
|
||||
}
|
||||
if (subflow.instances.length > 0) {
|
||||
if (subflow.instances.some(sf => { const ws = RED.nodes.workspace(sf.z); return ws?ws.locked:false })) {
|
||||
return
|
||||
}
|
||||
const msg = $('<div>')
|
||||
$('<p>').text(RED._("subflow.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
|
||||
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
|
||||
const confirmDeleteNotification = RED.notify(msg, {
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons: [
|
||||
{
|
||||
text: RED._('common.label.cancel'),
|
||||
click: function() {
|
||||
confirmDeleteNotification.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: RED._('workspace.confirmDelete'),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
confirmDeleteNotification.close();
|
||||
completeDelete();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
return;
|
||||
} else {
|
||||
completeDelete();
|
||||
}
|
||||
function completeDelete() {
|
||||
const startDirty = RED.nodes.dirty();
|
||||
const historyEvent = removeSubflow(subflow.id);
|
||||
historyEvent.t = 'delete';
|
||||
historyEvent.dirty = startDirty;
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
}
|
||||
function removeSubflow(id, keepInstanceNodes) {
|
||||
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
|
||||
var removedNodes = [];
|
||||
@@ -550,7 +557,7 @@ RED.subflow = (function() {
|
||||
}
|
||||
});
|
||||
RED.events.on("view:selection-changed",function(selection) {
|
||||
if (!selection.nodes) {
|
||||
if (!selection.nodes || RED.workspaces.isActiveLocked()) {
|
||||
RED.menu.setDisabled("menu-item-subflow-convert",true);
|
||||
} else {
|
||||
RED.menu.setDisabled("menu-item-subflow-convert",false);
|
||||
@@ -613,6 +620,9 @@ RED.subflow = (function() {
|
||||
}
|
||||
|
||||
function convertToSubflow() {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
if (!selection.nodes) {
|
||||
RED.notify(RED._("subflow.errors.noNodesSelected"),"error");
|
||||
@@ -768,7 +778,7 @@ RED.subflow = (function() {
|
||||
}
|
||||
subflowInstance._def = RED.nodes.getType(subflowInstance.type);
|
||||
RED.editor.validateNode(subflowInstance);
|
||||
RED.nodes.add(subflowInstance);
|
||||
subflowInstance = RED.nodes.add(subflowInstance);
|
||||
|
||||
if (containingGroup) {
|
||||
RED.group.addToGroup(containingGroup, subflowInstance);
|
||||
@@ -1323,7 +1333,10 @@ RED.subflow = (function() {
|
||||
init: init,
|
||||
createSubflow: createSubflow,
|
||||
convertToSubflow: convertToSubflow,
|
||||
// removeSubflow: Internal function to remove subflow
|
||||
removeSubflow: removeSubflow,
|
||||
// delete: Prompt user for confirmation
|
||||
delete: deleteSubflow,
|
||||
refresh: refresh,
|
||||
removeInput: removeSubflowInput,
|
||||
removeOutput: removeSubflowOutput,
|
||||
|
||||
@@ -43,12 +43,15 @@ RED.sidebar.config = (function() {
|
||||
|
||||
var categories = {};
|
||||
|
||||
function getOrCreateCategory(name,parent,label) {
|
||||
function getOrCreateCategory(name,parent,label,isLocked) {
|
||||
name = name.replace(/\./i,"-");
|
||||
if (!categories[name]) {
|
||||
var container = $('<div class="red-ui-palette-category red-ui-sidebar-config-category" id="red-ui-sidebar-config-category-'+name+'"></div>').appendTo(parent);
|
||||
var header = $('<div class="red-ui-sidebar-config-tray-header red-ui-palette-header"><i class="fa fa-angle-down expanded"></i></div>').appendTo(container);
|
||||
let lockIcon
|
||||
if (label) {
|
||||
lockIcon = $('<span style="margin-right: 5px"><i class="fa fa-lock"/></span>').appendTo(header)
|
||||
lockIcon.toggle(!!isLocked)
|
||||
$('<span class="red-ui-palette-node-config-label"/>').text(label).appendTo(header);
|
||||
} else {
|
||||
$('<span class="red-ui-palette-node-config-label" data-i18n="sidebar.config.'+name+'">').appendTo(header);
|
||||
@@ -62,6 +65,7 @@ RED.sidebar.config = (function() {
|
||||
var icon = header.find("i");
|
||||
var result = {
|
||||
label: label,
|
||||
lockIcon,
|
||||
list: category,
|
||||
size: function() {
|
||||
return result.list.find("li:not(.red-ui-palette-node-config-none)").length
|
||||
@@ -100,6 +104,9 @@ RED.sidebar.config = (function() {
|
||||
});
|
||||
categories[name] = result;
|
||||
} else {
|
||||
if (isLocked !== undefined && categories[name].lockIcon) {
|
||||
categories[name].lockIcon.toggle(!!isLocked)
|
||||
}
|
||||
if (categories[name].label !== label) {
|
||||
categories[name].list.parent().find('.red-ui-palette-node-config-label').text(label);
|
||||
categories[name].label = label;
|
||||
@@ -216,7 +223,7 @@ RED.sidebar.config = (function() {
|
||||
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
validList[ws.id.replace(/\./g,"-")] = true;
|
||||
getOrCreateCategory(ws.id,flowCategories,ws.label);
|
||||
getOrCreateCategory(ws.id,flowCategories,ws.label, ws.locked);
|
||||
})
|
||||
RED.nodes.eachSubflow(function(sf) {
|
||||
validList[sf.id.replace(/\./g,"-")] = true;
|
||||
@@ -274,6 +281,15 @@ RED.sidebar.config = (function() {
|
||||
changes: {},
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
for (let i = 0; i < selectedNodes.length; i++) {
|
||||
let node = RED.nodes.node(selectedNodes[i])
|
||||
if (node.z) {
|
||||
let ws = RED.nodes.workspace(node.z)
|
||||
if (ws && ws.locked) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
selectedNodes.forEach(function(id) {
|
||||
var node = RED.nodes.node(id);
|
||||
try {
|
||||
|
||||
@@ -141,7 +141,8 @@ RED.sidebar.help = (function() {
|
||||
RED.events.on('registry:node-type-removed', queueRefresh);
|
||||
RED.events.on('subflows:change', refreshSubflow);
|
||||
|
||||
RED.actions.add("core:show-help-tab",show);
|
||||
RED.actions.add("core:show-help-tab", show);
|
||||
RED.actions.add("core:show-node-help", showNodeHelp)
|
||||
|
||||
}
|
||||
|
||||
@@ -338,6 +339,19 @@ RED.sidebar.help = (function() {
|
||||
resizeStack();
|
||||
}
|
||||
|
||||
function showNodeHelp(node) {
|
||||
if (!node) {
|
||||
const selection = RED.view.selection()
|
||||
if (selection.nodes && selection.nodes.length > 0) {
|
||||
node = selection.nodes.find(n => n.type !== 'group' && n.type !== 'junction')
|
||||
}
|
||||
}
|
||||
if (node) {
|
||||
show(node.type, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: DRY - projects.js
|
||||
function addTargetToExternalLinks(el) {
|
||||
$(el).find("a").each(function(el) {
|
||||
|
||||
@@ -221,6 +221,22 @@ RED.sidebar.info.outliner = (function() {
|
||||
} else {
|
||||
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
|
||||
}
|
||||
if (n.type === 'tab') {
|
||||
var lockToggleButton = $('<button type="button" class="red-ui-info-outline-item-control-lock red-ui-button red-ui-button-small"><i class="fa fa-unlock-alt"></i><i class="fa fa-lock"></i></button>').appendTo(controls).on("click",function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if (n.locked) {
|
||||
RED.workspaces.unlock(n.id)
|
||||
} else {
|
||||
RED.workspaces.lock(n.id)
|
||||
}
|
||||
})
|
||||
RED.popover.tooltip(lockToggleButton,function() {
|
||||
return RED._("common.label."+(n.locked?"unlock":"lock"));
|
||||
});
|
||||
} else {
|
||||
$('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
|
||||
}
|
||||
controls.find("button").on("dblclick", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
@@ -364,6 +380,8 @@ RED.sidebar.info.outliner = (function() {
|
||||
flowList.treeList.addChild(objects[ws.id])
|
||||
objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
|
||||
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled)
|
||||
objects[ws.id].element.toggleClass("red-ui-info-outline-item-locked", !!ws.locked)
|
||||
objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-locked", !!ws.locked)
|
||||
updateSearch();
|
||||
|
||||
}
|
||||
@@ -378,6 +396,8 @@ RED.sidebar.info.outliner = (function() {
|
||||
existingObject.element.find(".red-ui-info-outline-item-label").text(label);
|
||||
existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
|
||||
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled)
|
||||
existingObject.element.toggleClass("red-ui-info-outline-item-locked", !!n.locked)
|
||||
existingObject.treeList.container.toggleClass("red-ui-info-outline-item-locked", !!n.locked)
|
||||
updateSearch();
|
||||
}
|
||||
function onFlowsReorder(order) {
|
||||
|
||||
@@ -25,6 +25,7 @@ RED.sidebar.info = (function() {
|
||||
var propertiesPanelHeaderLabel;
|
||||
var propertiesPanelHeaderReveal;
|
||||
var propertiesPanelHeaderHelp;
|
||||
var propertiesPanelHeaderCopyLink;
|
||||
|
||||
var selectedObject;
|
||||
|
||||
@@ -67,10 +68,20 @@ RED.sidebar.info = (function() {
|
||||
|
||||
propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
|
||||
propertiesPanelHeaderLabel = $("<span>").appendTo(propertiesPanelHeader);
|
||||
propertiesPanelHeaderHelp = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
|
||||
|
||||
propertiesPanelHeaderCopyLink = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-link"></button>').css({
|
||||
position: 'absolute',
|
||||
top: '12px',
|
||||
right: '32px'
|
||||
}).on("click", function(evt) {
|
||||
RED.actions.invoke('core:copy-item-url',selectedObject)
|
||||
}).appendTo(propertiesPanelHeader);
|
||||
RED.popover.tooltip(propertiesPanelHeaderCopyLink,RED._("sidebar.info.copyItemUrl"));
|
||||
|
||||
propertiesPanelHeaderHelp = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
|
||||
position: 'absolute',
|
||||
top: '12px',
|
||||
right: '56px'
|
||||
}).on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
@@ -80,8 +91,7 @@ RED.sidebar.info = (function() {
|
||||
}).appendTo(propertiesPanelHeader);
|
||||
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
|
||||
|
||||
|
||||
propertiesPanelHeaderReveal = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
|
||||
propertiesPanelHeaderReveal = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
|
||||
position: 'absolute',
|
||||
top: '12px',
|
||||
right: '8px'
|
||||
@@ -185,6 +195,7 @@ RED.sidebar.info = (function() {
|
||||
propertiesPanelHeaderLabel.text("");
|
||||
propertiesPanelHeaderReveal.hide();
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
propertiesPanelHeaderCopyLink.hide();
|
||||
return;
|
||||
} else if (Array.isArray(node)) {
|
||||
// Multiple things selected
|
||||
@@ -196,6 +207,7 @@ RED.sidebar.info = (function() {
|
||||
propertiesPanelHeaderLabel.text("Selection");
|
||||
propertiesPanelHeaderReveal.hide();
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
propertiesPanelHeaderCopyLink.hide();
|
||||
selectedObject = null;
|
||||
|
||||
var types = {
|
||||
@@ -277,9 +289,11 @@ RED.sidebar.info = (function() {
|
||||
if (node.type === "tab" || node.type === "subflow") {
|
||||
// If nothing is selected, but we're on a flow or subflow tab.
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
propertiesPanelHeaderCopyLink.show();
|
||||
|
||||
} else if (node.type === "group") {
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
propertiesPanelHeaderCopyLink.show();
|
||||
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td> </td><td></td></tr>').appendTo(tableBody);
|
||||
|
||||
@@ -304,8 +318,10 @@ RED.sidebar.info = (function() {
|
||||
}
|
||||
} else if (node.type === 'junction') {
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
propertiesPanelHeaderCopyLink.hide();
|
||||
} else {
|
||||
propertiesPanelHeaderHelp.show();
|
||||
propertiesPanelHeaderCopyLink.show();
|
||||
|
||||
if (!subflowRegex) {
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("sidebar.info.type")+'</td><td></td></tr>').appendTo(tableBody);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
**/
|
||||
|
||||
RED.view.tools = (function() {
|
||||
|
||||
'use strict';
|
||||
function selectConnected(type) {
|
||||
var selection = RED.view.selection();
|
||||
var visited = new Set();
|
||||
@@ -39,6 +39,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function alignToGrid() {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var changedNodes = [];
|
||||
@@ -87,6 +90,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function moveSelection(dx,dy) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
if (moving_set === null) {
|
||||
moving_set = [];
|
||||
var selection = RED.view.selection();
|
||||
@@ -153,6 +159,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function setSelectedNodeLabelState(labelShown) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
var historyEvents = [];
|
||||
var nodes = [];
|
||||
@@ -439,6 +448,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function alignSelectionToEdge(direction) {
|
||||
// if (RED.workspaces.isActiveLocked()) {
|
||||
// return
|
||||
// }
|
||||
var selection = RED.view.selection();
|
||||
|
||||
if (selection.nodes && selection.nodes.length > 1) {
|
||||
@@ -539,8 +551,10 @@ RED.view.tools = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function distributeSelection(direction) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
|
||||
if (selection.nodes && selection.nodes.length > 2) {
|
||||
@@ -699,6 +713,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function reorderSelection(dir) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nodesToMove = [];
|
||||
@@ -734,8 +751,10 @@ RED.view.tools = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function wireSeriesOfNodes() {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length > 1) {
|
||||
@@ -776,6 +795,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function wireNodeToMultiple() {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
if (selection.nodes.length > 1) {
|
||||
@@ -823,6 +845,9 @@ RED.view.tools = (function() {
|
||||
* @param {Object || Object[]} wires The wire(s) to split and replace with link-out, link-in nodes.
|
||||
*/
|
||||
function splitWiresWithLinkNodes(wires) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
@@ -877,7 +902,6 @@ RED.view.tools = (function() {
|
||||
if(!nnLinkOut) {
|
||||
const nLinkOut = RED.view.createNode("link out"); //create link node
|
||||
nnLinkOut = nLinkOut.node;
|
||||
nodeSrcMap[linkOutMapId] = nnLinkOut;
|
||||
let yOffset = 0;
|
||||
if(nSrc.outputs > 1) {
|
||||
|
||||
@@ -892,7 +916,8 @@ RED.view.tools = (function() {
|
||||
updateNewNodePosXY(nSrc, nnLinkOut, false, RED.view.snapGrid, yOffset);
|
||||
}
|
||||
//add created node
|
||||
RED.nodes.add(nnLinkOut);
|
||||
nnLinkOut = RED.nodes.add(nnLinkOut);
|
||||
nodeSrcMap[linkOutMapId] = nnLinkOut;
|
||||
RED.editor.validateNode(nnLinkOut);
|
||||
history.events.push(nLinkOut.historyEvent);
|
||||
//connect node to link node
|
||||
@@ -913,10 +938,10 @@ RED.view.tools = (function() {
|
||||
if(!nnLinkIn) {
|
||||
const nLinkIn = RED.view.createNode("link in"); //create link node
|
||||
nnLinkIn = nLinkIn.node;
|
||||
nodeTrgMap[nTrg.id] = nnLinkIn;
|
||||
updateNewNodePosXY(nTrg, nnLinkIn, true, RED.view.snapGrid, 0);
|
||||
//add created node
|
||||
RED.nodes.add(nnLinkIn);
|
||||
nnLinkIn = RED.nodes.add(nnLinkIn);
|
||||
nodeTrgMap[nTrg.id] = nnLinkIn;
|
||||
RED.editor.validateNode(nnLinkIn);
|
||||
history.events.push(nLinkIn.historyEvent);
|
||||
//connect node to link node
|
||||
@@ -991,6 +1016,9 @@ RED.view.tools = (function() {
|
||||
* @param {{ renameBlank: boolean, renameClash: boolean, generateHistory: boolean }} options Possible options are `renameBlank`, `renameClash` and `generateHistory`
|
||||
*/
|
||||
function generateNodeNames(node, options) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
options = Object.assign({
|
||||
renameBlank: true,
|
||||
renameClash: true,
|
||||
@@ -1061,6 +1089,9 @@ RED.view.tools = (function() {
|
||||
}
|
||||
|
||||
function addJunctionsToWires(wires) {
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
||||
if (!wiresToSplit) {
|
||||
return
|
||||
@@ -1131,7 +1162,7 @@ RED.view.tools = (function() {
|
||||
|
||||
var nodeGroups = new Set()
|
||||
|
||||
RED.nodes.addJunction(junction)
|
||||
junction = RED.nodes.addJunction(junction)
|
||||
addedJunctions.push(junction)
|
||||
let newLink
|
||||
if (gid === links[0].source.id+":"+links[0].sourcePort) {
|
||||
@@ -1192,6 +1223,30 @@ RED.view.tools = (function() {
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
function copyItemUrl(node, isEdit) {
|
||||
if (!node) {
|
||||
const selection = RED.view.selection();
|
||||
if (selection.nodes && selection.nodes.length > 0) {
|
||||
node = selection.nodes[0]
|
||||
}
|
||||
}
|
||||
if (node) {
|
||||
let thingType = 'node'
|
||||
if (node.type === 'group') {
|
||||
thingType = 'group'
|
||||
} else if (node.type === 'tab' || node.type === 'subflow') {
|
||||
thingType = 'flow'
|
||||
}
|
||||
let url = `${window.location.origin}${window.location.pathname}#${thingType}/${node.id}`
|
||||
if (isEdit) {
|
||||
url += '/edit'
|
||||
}
|
||||
if (RED.clipboard.copyText(url)) {
|
||||
RED.notify(RED._("sidebar.info.copyURL2Clipboard"), { timeout: 2000 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: function() {
|
||||
RED.actions.add("core:show-selected-node-labels", function() { setSelectedNodeLabelState(true); })
|
||||
@@ -1258,6 +1313,9 @@ RED.view.tools = (function() {
|
||||
|
||||
RED.actions.add("core:generate-node-names", generateNodeNames )
|
||||
|
||||
RED.actions.add("core:copy-item-url", function (node) { copyItemUrl(node) })
|
||||
RED.actions.add("core:copy-item-edit-url", function (node) { copyItemUrl(node, true) })
|
||||
|
||||
// RED.actions.add("core:add-node", function() { addNode() })
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -54,6 +54,7 @@ RED.view = (function() {
|
||||
var spliceTimer;
|
||||
var groupHoverTimer;
|
||||
|
||||
var activeFlowLocked = false;
|
||||
var activeSubflow = null;
|
||||
var activeNodes = [];
|
||||
var activeLinks = [];
|
||||
@@ -211,6 +212,7 @@ RED.view = (function() {
|
||||
evt.preventDefault()
|
||||
evt.stopPropagation()
|
||||
RED.contextMenu.show({
|
||||
type: 'workspace',
|
||||
x:evt.clientX-5,
|
||||
y:evt.clientY-5
|
||||
})
|
||||
@@ -410,8 +412,19 @@ RED.view = (function() {
|
||||
|
||||
activeSubflow = RED.nodes.subflow(event.workspace);
|
||||
|
||||
RED.menu.setDisabled("menu-item-workspace-edit", activeSubflow || event.workspace === 0);
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",event.workspace === 0 || RED.workspaces.count() == 1 || activeSubflow);
|
||||
if (activeSubflow) {
|
||||
activeFlowLocked = activeSubflow.locked
|
||||
} else {
|
||||
var activeWorkspace = RED.nodes.workspace(event.workspace)
|
||||
if (activeWorkspace) {
|
||||
activeFlowLocked = activeWorkspace.locked
|
||||
} else {
|
||||
activeFlowLocked = true
|
||||
}
|
||||
}
|
||||
|
||||
RED.menu.setDisabled("menu-item-workspace-edit", activeFlowLocked || activeSubflow || event.workspace === 0);
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",activeFlowLocked || event.workspace === 0 || RED.workspaces.count() == 1 || activeSubflow);
|
||||
|
||||
if (workspaceScrollPositions[event.workspace]) {
|
||||
chart.scrollLeft(workspaceScrollPositions[event.workspace].left);
|
||||
@@ -438,6 +451,15 @@ RED.view = (function() {
|
||||
redraw();
|
||||
});
|
||||
|
||||
RED.events.on("flows:change", function(workspace) {
|
||||
if (workspace.id === RED.workspaces.active()) {
|
||||
activeFlowLocked = !!workspace.locked
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked",!!workspace.locked);
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
RED.statusBar.add({
|
||||
id: "view-zoom-controls",
|
||||
align: "right",
|
||||
@@ -495,6 +517,9 @@ RED.view = (function() {
|
||||
chart.droppable({
|
||||
accept:".red-ui-palette-node",
|
||||
drop: function( event, ui ) {
|
||||
if (activeFlowLocked) {
|
||||
return
|
||||
}
|
||||
d3.event = event;
|
||||
var selected_tool = $(ui.draggable[0]).attr("data-palette-type");
|
||||
var result = createNode(selected_tool);
|
||||
@@ -502,9 +527,7 @@ RED.view = (function() {
|
||||
return;
|
||||
}
|
||||
var historyEvent = result.historyEvent;
|
||||
var nn = result.node;
|
||||
|
||||
RED.nodes.add(nn);
|
||||
var nn = RED.nodes.add(result.node);
|
||||
|
||||
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")) {
|
||||
@@ -631,6 +654,9 @@ RED.view = (function() {
|
||||
RED.actions.add("core:copy-selection-to-internal-clipboard",copySelection);
|
||||
RED.actions.add("core:cut-selection-to-internal-clipboard",function(){copySelection(true);deleteSelection();});
|
||||
RED.actions.add("core:paste-from-internal-clipboard",function(){
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
return
|
||||
}
|
||||
importNodes(clipboard,{generateIds: clipboardSource === 'copy', generateDefaultNames: clipboardSource === 'copy'});
|
||||
});
|
||||
|
||||
@@ -639,22 +665,27 @@ RED.view = (function() {
|
||||
RED.events.on("view:selection-changed", function(selection) {
|
||||
var hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||
var hasMultipleSelection = hasSelection && selection.nodes.length > 1;
|
||||
RED.menu.setDisabled("menu-item-edit-cut",!hasSelection);
|
||||
RED.menu.setDisabled("menu-item-edit-copy",!hasSelection);
|
||||
RED.menu.setDisabled("menu-item-edit-select-connected",!hasSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-to-back",!hasSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-to-front",!hasSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-backwards",!hasSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-forwards",!hasSelection);
|
||||
var hasLinkSelected = selection.links && selection.links.length > 0;
|
||||
var canEdit = !activeFlowLocked && hasSelection
|
||||
var canEditMultiple = !activeFlowLocked && hasMultipleSelection
|
||||
RED.menu.setDisabled("menu-item-edit-cut", !canEdit);
|
||||
RED.menu.setDisabled("menu-item-edit-copy", !hasSelection);
|
||||
RED.menu.setDisabled("menu-item-edit-select-connected", !hasSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-to-back", !canEdit);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-to-front", !canEdit);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-backwards", !canEdit);
|
||||
RED.menu.setDisabled("menu-item-view-tools-move-forwards", !canEdit);
|
||||
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-left",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-center",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-right",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-top",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-middle",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-bottom",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-distribute-horizontally",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-distribute-veritcally",!hasMultipleSelection);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-left", !canEditMultiple);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-center", !canEditMultiple);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-right", !canEditMultiple);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-top", !canEditMultiple);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-middle", !canEditMultiple);
|
||||
RED.menu.setDisabled("menu-item-view-tools-align-bottom", !canEditMultiple);
|
||||
RED.menu.setDisabled("menu-item-view-tools-distribute-horizontally", !canEditMultiple);
|
||||
RED.menu.setDisabled("menu-item-view-tools-distribute-veritcally", !canEditMultiple);
|
||||
|
||||
RED.menu.setDisabled("menu-item-edit-split-wire-with-links", activeFlowLocked || !hasLinkSelected);
|
||||
})
|
||||
|
||||
RED.actions.add("core:delete-selection",deleteSelection);
|
||||
@@ -1044,7 +1075,7 @@ RED.view = (function() {
|
||||
.attr("class", "nr-ui-view-lasso");
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
} else if (d3.event.altKey) {
|
||||
} else if (d3.event.altKey && !activeFlowLocked) {
|
||||
//Alt [+shift] held - Begin slicing
|
||||
clearSelection();
|
||||
mouse_mode = (d3.event.shiftKey) ? RED.state.SLICING_JUNCTION : RED.state.SLICING;
|
||||
@@ -1058,6 +1089,9 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function showQuickAddDialog(options) {
|
||||
if (activeFlowLocked) {
|
||||
return
|
||||
}
|
||||
options = options || {};
|
||||
var point = options.position || lastClickPosition;
|
||||
var spliceLink = options.splice;
|
||||
@@ -1237,6 +1271,11 @@ RED.view = (function() {
|
||||
if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
|
||||
nn.l = showLabel;
|
||||
}
|
||||
if (nn.type === 'junction') {
|
||||
nn = RED.nodes.addJunction(nn);
|
||||
} else {
|
||||
nn = RED.nodes.add(nn);
|
||||
}
|
||||
if (quickAddLink) {
|
||||
var drag_line = quickAddLink;
|
||||
var src = null,dst,src_port;
|
||||
@@ -1339,11 +1378,7 @@ RED.view = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nn.type === 'junction') {
|
||||
RED.nodes.addJunction(nn);
|
||||
} else {
|
||||
RED.nodes.add(nn);
|
||||
}
|
||||
|
||||
RED.editor.validateNode(nn);
|
||||
|
||||
if (targetGroup) {
|
||||
@@ -1601,16 +1636,18 @@ RED.view = (function() {
|
||||
}
|
||||
var d = (mouse_offset[0]-mousePos[0])*(mouse_offset[0]-mousePos[0]) + (mouse_offset[1]-mousePos[1])*(mouse_offset[1]-mousePos[1]);
|
||||
if ((d > 3 && !dblClickPrimed) || (dblClickPrimed && d > 10)) {
|
||||
mouse_mode = RED.state.MOVING_ACTIVE;
|
||||
clickElapsed = 0;
|
||||
spliceActive = false;
|
||||
if (movingSet.length() === 1) {
|
||||
node = movingSet.get(0);
|
||||
spliceActive = node.n.hasOwnProperty("_def") &&
|
||||
((node.n.hasOwnProperty("inputs") && node.n.inputs > 0) || (!node.n.hasOwnProperty("inputs") && node.n._def.inputs > 0)) &&
|
||||
((node.n.hasOwnProperty("outputs") && node.n.outputs > 0) || (!node.n.hasOwnProperty("outputs") && node.n._def.outputs > 0)) &&
|
||||
RED.nodes.filterLinks({ source: node.n }).length === 0 &&
|
||||
RED.nodes.filterLinks({ target: node.n }).length === 0;
|
||||
if (!activeFlowLocked) {
|
||||
mouse_mode = RED.state.MOVING_ACTIVE;
|
||||
spliceActive = false;
|
||||
if (movingSet.length() === 1) {
|
||||
node = movingSet.get(0);
|
||||
spliceActive = node.n.hasOwnProperty("_def") &&
|
||||
((node.n.hasOwnProperty("inputs") && node.n.inputs > 0) || (!node.n.hasOwnProperty("inputs") && node.n._def.inputs > 0)) &&
|
||||
((node.n.hasOwnProperty("outputs") && node.n.outputs > 0) || (!node.n.hasOwnProperty("outputs") && node.n._def.outputs > 0)) &&
|
||||
RED.nodes.filterLinks({ source: node.n }).length === 0 &&
|
||||
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) {
|
||||
@@ -2455,6 +2492,7 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function editSelection() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (movingSet.length() > 0) {
|
||||
var node = movingSet.get(0).n;
|
||||
if (node.type === "subflow") {
|
||||
@@ -2470,6 +2508,9 @@ RED.view = (function() {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
return;
|
||||
}
|
||||
if (activeFlowLocked) {
|
||||
return
|
||||
}
|
||||
if (portLabelHover) {
|
||||
portLabelHover.remove();
|
||||
portLabelHover = null;
|
||||
@@ -2785,6 +2826,7 @@ RED.view = (function() {
|
||||
|
||||
|
||||
function detachSelectedNodes() {
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
const {newLinks, removedLinks} = RED.nodes.detachNodes(selection.nodes);
|
||||
@@ -2926,7 +2968,7 @@ RED.view = (function() {
|
||||
mousedown_node = d;
|
||||
mousedown_port_type = portType;
|
||||
mousedown_port_index = portIndex || 0;
|
||||
if (mouse_mode !== RED.state.QUICK_JOINING) {
|
||||
if (mouse_mode !== RED.state.QUICK_JOINING && !activeFlowLocked) {
|
||||
mouse_mode = RED.state.JOINING;
|
||||
document.body.style.cursor = "crosshair";
|
||||
if (evt.ctrlKey || evt.metaKey) {
|
||||
@@ -3366,6 +3408,11 @@ RED.view = (function() {
|
||||
}
|
||||
if (dblClickPrimed && mousedown_node == d && clickElapsed > 0 && clickElapsed < dblClickInterval) {
|
||||
mouse_mode = RED.state.DEFAULT;
|
||||
if (RED.workspaces.isActiveLocked()) {
|
||||
clickElapsed = 0;
|
||||
d3.event.stopPropagation();
|
||||
return
|
||||
}
|
||||
if (d.type != "subflow") {
|
||||
if (/^subflow:/.test(d.type) && (d3.event.ctrlKey || d3.event.metaKey)) {
|
||||
RED.workspaces.show(d.type.substring(8));
|
||||
@@ -3689,7 +3736,6 @@ RED.view = (function() {
|
||||
}
|
||||
// selectedLinks.clear();
|
||||
if (d3.event.button != 2) {
|
||||
mouse_mode = RED.state.MOVING;
|
||||
var mouse = d3.touches(this)[0]||d3.mouse(this);
|
||||
mouse[0] += d.x-d.w/2;
|
||||
mouse[1] += d.y-d.h/2;
|
||||
@@ -3882,6 +3928,7 @@ RED.view = (function() {
|
||||
if (RED.view.DEBUG) {
|
||||
console.warn("groupMouseUp", { mouse_mode, event: d3.event });
|
||||
}
|
||||
if (RED.workspaces.isActiveLocked()) { return }
|
||||
if (dblClickPrimed && mousedown_group == g && clickElapsed > 0 && clickElapsed < dblClickInterval) {
|
||||
mouse_mode = RED.state.DEFAULT;
|
||||
RED.editor.editGroup(g);
|
||||
@@ -4052,7 +4099,7 @@ RED.view = (function() {
|
||||
function isButtonEnabled(d) {
|
||||
var buttonEnabled = true;
|
||||
var ws = RED.nodes.workspace(RED.workspaces.active());
|
||||
if (ws && !ws.disabled && !d.d) {
|
||||
if (ws && !ws.disabled && !d.d && !ws.locked) {
|
||||
if (d._def.button.hasOwnProperty('enabled')) {
|
||||
if (typeof d._def.button.enabled === "function") {
|
||||
buttonEnabled = d._def.button.enabled.call(d);
|
||||
@@ -4075,7 +4122,7 @@ RED.view = (function() {
|
||||
}
|
||||
var activeWorkspace = RED.workspaces.active();
|
||||
var ws = RED.nodes.workspace(activeWorkspace);
|
||||
if (ws && !ws.disabled && !d.d) {
|
||||
if (ws && !ws.disabled && !d.d && !ws.locked) {
|
||||
if (d._def.button.toggle) {
|
||||
d[d._def.button.toggle] = !d[d._def.button.toggle];
|
||||
d.dirty = true;
|
||||
@@ -4090,7 +4137,7 @@ RED.view = (function() {
|
||||
if (d.dirty) {
|
||||
redraw();
|
||||
}
|
||||
} else {
|
||||
} else if (!ws || !ws.locked){
|
||||
if (activeSubflow) {
|
||||
RED.notify(RED._("notification.warning", {message:RED._("notification.warnings.nodeActionDisabledSubflow")}),"warning");
|
||||
} else {
|
||||
@@ -4105,14 +4152,15 @@ 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:"cut",disabled:(movingSet.length()===0),onselect:function() {copySelection(true);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});}});
|
||||
options.push({name:"edit",disabled:(movingSet.length() != 1),onselect:function() { RED.editor.edit(mdn);}});
|
||||
const isActiveLocked = RED.workspaces.isActiveLocked()
|
||||
options.push({name:"delete",disabled:(isActiveLocked || movingSet.length()===0 && selectedLinks.length() === 0),onselect:function() {deleteSelection();}});
|
||||
options.push({name:"cut",disabled:(isActiveLocked || movingSet.length()===0),onselect:function() {copySelection(true);deleteSelection();}});
|
||||
options.push({name:"copy",disabled:(isActiveLocked || movingSet.length()===0),onselect:function() {copySelection();}});
|
||||
options.push({name:"paste",disabled:(isActiveLocked || clipboard.length===0),onselect:function() {importNodes(clipboard, {generateIds: true, touchImport: true});}});
|
||||
options.push({name:"edit",disabled:(isActiveLocked || movingSet.length() != 1),onselect:function() { RED.editor.edit(mdn);}});
|
||||
options.push({name:"select",onselect:function() {selectAll();}});
|
||||
options.push({name:"undo",disabled:(RED.history.depth() === 0),onselect:function() {RED.history.pop();}});
|
||||
options.push({name:"add",onselect:function() {
|
||||
options.push({name:"add",disabled:isActiveLocked, onselect:function() {
|
||||
chartPos = chart.offset();
|
||||
showQuickAddDialog({
|
||||
position:[pos[0]-chartPos.left+chart.scrollLeft(),pos[1]-chartPos.top+chart.scrollTop()],
|
||||
@@ -5810,6 +5858,9 @@ RED.view = (function() {
|
||||
if (mouse_mode === RED.state.SELECTING_NODE) {
|
||||
return;
|
||||
}
|
||||
if (activeFlowLocked) {
|
||||
return
|
||||
}
|
||||
var workspaceSelection = RED.workspaces.selection();
|
||||
var changed = false;
|
||||
if (workspaceSelection.length > 0) {
|
||||
@@ -6137,7 +6188,9 @@ RED.view = (function() {
|
||||
if (node.z && (node.type === "group" || node._def.category !== 'config')) {
|
||||
node.dirty = true;
|
||||
RED.workspaces.show(node.z);
|
||||
|
||||
if (node.type === "group" && !node.w && !node.h) {
|
||||
_redraw();
|
||||
}
|
||||
var screenSize = [chart[0].clientWidth/scaleFactor,chart[0].clientHeight/scaleFactor];
|
||||
var scrollPos = [chart.scrollLeft()/scaleFactor,chart.scrollTop()/scaleFactor];
|
||||
var cx = node.x;
|
||||
|
||||
@@ -58,6 +58,9 @@ RED.workspaces = (function() {
|
||||
if (!ws.closeable) {
|
||||
ws.hideable = true;
|
||||
}
|
||||
if (!ws.hasOwnProperty('locked')) {
|
||||
ws.locked = false
|
||||
}
|
||||
workspace_tabs.addTab(ws,targetIndex);
|
||||
|
||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||
@@ -75,6 +78,7 @@ RED.workspaces = (function() {
|
||||
type: "tab",
|
||||
id: tabId,
|
||||
disabled: false,
|
||||
locked: false,
|
||||
info: "",
|
||||
label: RED._('workspace.defaultName',{number:workspaceIndex}),
|
||||
env: [],
|
||||
@@ -99,6 +103,9 @@ RED.workspaces = (function() {
|
||||
if (workspaceTabCount === 1) {
|
||||
return;
|
||||
}
|
||||
if (ws.locked) {
|
||||
return
|
||||
}
|
||||
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
||||
ws._index = workspaceOrder.indexOf(ws.id);
|
||||
removeWorkspace(ws);
|
||||
@@ -119,13 +126,198 @@ RED.workspaces = (function() {
|
||||
RED.editor.editSubflow(subflow);
|
||||
}
|
||||
} else {
|
||||
RED.editor.editFlow(workspace);
|
||||
if (!workspace.locked) {
|
||||
RED.editor.editFlow(workspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var workspace_tabs;
|
||||
var workspaceTabCount = 0;
|
||||
|
||||
function getMenuItems(isMenuButton, tab) {
|
||||
let hiddenFlows = new Set()
|
||||
for (let i = 0; i < hideStack.length; i++) {
|
||||
let ids = hideStack[i]
|
||||
if (!Array.isArray(ids)) {
|
||||
ids = [ids]
|
||||
}
|
||||
ids.forEach(id => {
|
||||
if (RED.nodes.workspace(id)) {
|
||||
hiddenFlows.add(id)
|
||||
}
|
||||
})
|
||||
}
|
||||
const hiddenflowCount = hiddenFlows.size;
|
||||
let activeWorkspace = tab || RED.nodes.workspace(RED.workspaces.active()) || RED.nodes.subflow(RED.workspaces.active())
|
||||
let isFlowDisabled = activeWorkspace ? activeWorkspace.disabled : false
|
||||
|
||||
let isCurrentLocked = RED.workspaces.isActiveLocked()
|
||||
if (tab) {
|
||||
isCurrentLocked = tab.locked
|
||||
}
|
||||
|
||||
var menuItems = []
|
||||
if (isMenuButton) {
|
||||
menuItems.push({
|
||||
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)
|
||||
}
|
||||
menuItems.push(
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
}
|
||||
)
|
||||
if (isMenuButton || !!tab) {
|
||||
menuItems.push(
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:add-flow-to-right", tab)
|
||||
}
|
||||
},
|
||||
null
|
||||
)
|
||||
if (activeWorkspace && activeWorkspace.type === 'tab') {
|
||||
menuItems.push(
|
||||
isFlowDisabled ? {
|
||||
label: RED._("workspace.enableFlow"),
|
||||
shortcut: RED.keyboard.getShortcut("core:enable-flow"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:enable-flow", tab?tab.id:undefined)
|
||||
},
|
||||
disabled: isCurrentLocked
|
||||
} : {
|
||||
label: RED._("workspace.disableFlow"),
|
||||
shortcut: RED.keyboard.getShortcut("core:disable-flow"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:disable-flow", tab?tab.id:undefined)
|
||||
},
|
||||
disabled: isCurrentLocked
|
||||
},
|
||||
isCurrentLocked? {
|
||||
label: RED._("workspace.unlockFlow"),
|
||||
shortcut: RED.keyboard.getShortcut("core:unlock-flow"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke('core:unlock-flow', tab?tab.id:undefined)
|
||||
}
|
||||
} : {
|
||||
label: RED._("workspace.lockFlow"),
|
||||
shortcut: RED.keyboard.getShortcut("core:lock-flow"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke('core:lock-flow', tab?tab.id:undefined)
|
||||
}
|
||||
},
|
||||
null
|
||||
)
|
||||
}
|
||||
const currentTabs = workspace_tabs.listTabs()
|
||||
const activeIndex = currentTabs.findIndex(id => id === activeWorkspace.id)
|
||||
menuItems.push(
|
||||
{
|
||||
label: RED._("workspace.moveToStart"),
|
||||
shortcut: RED.keyboard.getShortcut("core:move-flow-to-start"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:move-flow-to-start", tab?tab.id:undefined)
|
||||
},
|
||||
disabled: activeIndex === 0
|
||||
},
|
||||
{
|
||||
label: RED._("workspace.moveToEnd"),
|
||||
shortcut: RED.keyboard.getShortcut("core:move-flow-to-end"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:move-flow-to-end", tab?tab.id:undefined)
|
||||
},
|
||||
disabled: activeIndex === currentTabs.length - 1
|
||||
}
|
||||
)
|
||||
}
|
||||
menuItems.push(null)
|
||||
if (isMenuButton || !!tab) {
|
||||
menuItems.push(
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-flows",
|
||||
label: RED._("workspace.hideFlow"),
|
||||
shortcut: RED.keyboard.getShortcut("core:hide-flow"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:hide-flow", tab)
|
||||
}
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-hide-other-flows",
|
||||
label: RED._("workspace.hideOtherFlows"),
|
||||
shortcut: RED.keyboard.getShortcut("core:hide-other-flows"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:hide-other-flows", tab)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
menuItems.push(
|
||||
{
|
||||
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-all-flows",
|
||||
disabled: hiddenflowCount === 0,
|
||||
label: RED._("workspace.showAllFlows", { count: hiddenflowCount }),
|
||||
onselect: "core:show-all-flows"
|
||||
},
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-show-last-flow",
|
||||
disabled: hideStack.length === 0,
|
||||
label: RED._("workspace.showLastHiddenFlow"),
|
||||
onselect: "core:show-last-hidden-flow"
|
||||
}
|
||||
)
|
||||
if (tab) {
|
||||
menuItems.push(
|
||||
null,
|
||||
{
|
||||
label: RED._("common.label.delete"),
|
||||
disabled: isCurrentLocked,
|
||||
onselect: function() {
|
||||
if (tab.type === 'tab') {
|
||||
RED.workspaces.delete(tab)
|
||||
} else if (tab.type === 'subflow') {
|
||||
RED.subflow.delete(tab.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: RED._("menu.label.export"),
|
||||
shortcut: RED.keyboard.getShortcut("core:show-export-dialog"),
|
||||
onselect: function() {
|
||||
RED.workspaces.show(tab.id)
|
||||
RED.actions.invoke('core:show-export-dialog', null, 'flow')
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
// if (isMenuButton && hiddenflowCount > 0) {
|
||||
// menuItems.unshift({
|
||||
// label: RED._("workspace.hiddenFlows",{count: hiddenflowCount}),
|
||||
// onselect: "core:list-hidden-flows"
|
||||
// })
|
||||
// }
|
||||
return menuItems;
|
||||
}
|
||||
function createWorkspaceTabs() {
|
||||
workspace_tabs = RED.tabs.create({
|
||||
id: "red-ui-workspace-tabs",
|
||||
@@ -137,8 +329,9 @@ RED.workspaces = (function() {
|
||||
$("#red-ui-workspace-chart").show();
|
||||
activeWorkspace = tab.id;
|
||||
window.location.hash = 'flow/'+tab.id;
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!tab.disabled);
|
||||
} else {
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled", !!tab.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked", !!tab.locked);
|
||||
} else {
|
||||
$("#red-ui-workspace-chart").hide();
|
||||
activeWorkspace = 0;
|
||||
window.location.hash = '';
|
||||
@@ -169,6 +362,12 @@ RED.workspaces = (function() {
|
||||
if (tab.disabled) {
|
||||
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-disabled');
|
||||
}
|
||||
$('<span class="red-ui-workspace-locked-icon"><i class="fa fa-lock"></i> </span>').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label");
|
||||
if (tab.locked) {
|
||||
$("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-locked');
|
||||
}
|
||||
|
||||
|
||||
RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1);
|
||||
if (workspaceTabCount === 1) {
|
||||
showWorkspace();
|
||||
@@ -189,13 +388,19 @@ RED.workspaces = (function() {
|
||||
RED.history.push({
|
||||
t:'reorder',
|
||||
workspaces: {
|
||||
from:oldOrder,
|
||||
to:newOrder
|
||||
from: oldOrder,
|
||||
to: newOrder
|
||||
},
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
setWorkspaceOrder(newOrder);
|
||||
// Only mark flows dirty if flow-order has changed (excluding subflows)
|
||||
const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id))
|
||||
const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id))
|
||||
|
||||
if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) {
|
||||
RED.nodes.dirty(true);
|
||||
setWorkspaceOrder(newOrder);
|
||||
}
|
||||
},
|
||||
onselect: function(selectedTabs) {
|
||||
RED.view.select(false)
|
||||
@@ -214,12 +419,12 @@ 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})
|
||||
if (tab.type === "tab") {
|
||||
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);
|
||||
@@ -234,77 +439,8 @@ RED.workspaces = (function() {
|
||||
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"
|
||||
}
|
||||
]
|
||||
let hiddenFlows = new Set()
|
||||
for (let i = 0; i < hideStack.length; i++) {
|
||||
let ids = hideStack[i]
|
||||
if (!Array.isArray(ids)) {
|
||||
ids = [ids]
|
||||
}
|
||||
ids.forEach(id => {
|
||||
if (RED.nodes.workspace(id)) {
|
||||
hiddenFlows.add(id)
|
||||
}
|
||||
})
|
||||
}
|
||||
const flowCount = hiddenFlows.size;
|
||||
if (flowCount > 0) {
|
||||
menuItems.unshift({
|
||||
label: RED._("workspace.hiddenFlows",{count: flowCount}),
|
||||
onselect: "core:list-hidden-flows"
|
||||
})
|
||||
}
|
||||
return menuItems;
|
||||
}
|
||||
menu: function() { return getMenuItems(true) },
|
||||
contextmenu: function(tab) { return getMenuItems(false, tab) }
|
||||
});
|
||||
workspaceTabCount = 0;
|
||||
}
|
||||
@@ -355,16 +491,33 @@ RED.workspaces = (function() {
|
||||
});
|
||||
|
||||
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
|
||||
RED.actions.add("core:add-flow-to-right",function(opts) { addWorkspace(undefined,undefined,workspace_tabs.activeIndex()+1)});
|
||||
RED.actions.add("core:add-flow-to-right",function(workspace) {
|
||||
let index
|
||||
if (workspace) {
|
||||
index = workspace_tabs.getTabIndex(workspace.id)+1
|
||||
} else {
|
||||
index = workspace_tabs.activeIndex()+1
|
||||
}
|
||||
addWorkspace(undefined,undefined,index)
|
||||
});
|
||||
RED.actions.add("core:edit-flow",editWorkspace);
|
||||
RED.actions.add("core:remove-flow",removeWorkspace);
|
||||
RED.actions.add("core:enable-flow",enableWorkspace);
|
||||
RED.actions.add("core:disable-flow",disableWorkspace);
|
||||
RED.actions.add("core:lock-flow",lockWorkspace);
|
||||
RED.actions.add("core:unlock-flow",unlockWorkspace);
|
||||
RED.actions.add("core:move-flow-to-start", function(id) { moveWorkspace(id, 'start') });
|
||||
RED.actions.add("core:move-flow-to-end", function(id) { moveWorkspace(id, 'end') });
|
||||
|
||||
RED.actions.add("core:hide-flow", function() {
|
||||
var selection = workspace_tabs.selection();
|
||||
if (selection.length === 0) {
|
||||
selection = [{id:activeWorkspace}]
|
||||
RED.actions.add("core:hide-flow", function(workspace) {
|
||||
let selection
|
||||
if (workspace) {
|
||||
selection = [workspace]
|
||||
} else {
|
||||
selection = workspace_tabs.selection();
|
||||
if (selection.length === 0) {
|
||||
selection = [{id:activeWorkspace}]
|
||||
}
|
||||
}
|
||||
var hiddenTabs = [];
|
||||
selection.forEach(function(ws) {
|
||||
@@ -378,10 +531,15 @@ RED.workspaces = (function() {
|
||||
workspace_tabs.clearSelection();
|
||||
})
|
||||
|
||||
RED.actions.add("core:hide-other-flows", function() {
|
||||
var selection = workspace_tabs.selection();
|
||||
if (selection.length === 0) {
|
||||
selection = [{id:activeWorkspace}]
|
||||
RED.actions.add("core:hide-other-flows", function(workspace) {
|
||||
let selection
|
||||
if (workspace) {
|
||||
selection = [workspace]
|
||||
} else {
|
||||
selection = workspace_tabs.selection();
|
||||
if (selection.length === 0) {
|
||||
selection = [{id:activeWorkspace}]
|
||||
}
|
||||
}
|
||||
var selected = new Set(selection.map(function(ws) { return ws.id }))
|
||||
|
||||
@@ -486,7 +644,7 @@ RED.workspaces = (function() {
|
||||
}
|
||||
function setWorkspaceState(id,disabled) {
|
||||
var workspace = RED.nodes.workspace(id||activeWorkspace);
|
||||
if (!workspace) {
|
||||
if (!workspace || workspace.locked) {
|
||||
return;
|
||||
}
|
||||
if (workspace.disabled !== disabled) {
|
||||
@@ -521,11 +679,58 @@ RED.workspaces = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
function lockWorkspace(id) {
|
||||
setWorkspaceLockState(id,true);
|
||||
}
|
||||
function unlockWorkspace(id) {
|
||||
setWorkspaceLockState(id,false);
|
||||
}
|
||||
function setWorkspaceLockState(id,locked) {
|
||||
var workspace = RED.nodes.workspace(id||activeWorkspace);
|
||||
if (!workspace) {
|
||||
return;
|
||||
}
|
||||
if (workspace.locked !== locked) {
|
||||
var changes = { locked: workspace.locked };
|
||||
workspace.locked = locked;
|
||||
$("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked);
|
||||
if (!id || (id === activeWorkspace)) {
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked",!!workspace.locked);
|
||||
}
|
||||
var historyEvent = {
|
||||
t: "edit",
|
||||
changes:changes,
|
||||
node: workspace,
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
workspace.changed = true;
|
||||
RED.history.push(historyEvent);
|
||||
RED.events.emit("flows:change",workspace);
|
||||
RED.nodes.dirty(true);
|
||||
// RED.sidebar.config.refresh();
|
||||
// var selection = RED.view.selection();
|
||||
// if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) {
|
||||
// RED.sidebar.info.refresh(workspace);
|
||||
// }
|
||||
// if (changes.hasOwnProperty('disabled')) {
|
||||
// RED.nodes.eachNode(function(n) {
|
||||
// if (n.z === workspace.id) {
|
||||
// n.dirty = true;
|
||||
// }
|
||||
// });
|
||||
// RED.view.redraw();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
function removeWorkspace(ws) {
|
||||
if (!ws) {
|
||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||
ws = RED.nodes.workspace(activeWorkspace)
|
||||
if (ws && !ws.locked) {
|
||||
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
|
||||
}
|
||||
} else {
|
||||
if (ws.locked) { return }
|
||||
if (workspace_tabs.contains(ws.id)) {
|
||||
workspace_tabs.removeTab(ws.id);
|
||||
}
|
||||
@@ -535,16 +740,46 @@ RED.workspaces = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function moveWorkspace(id, direction) {
|
||||
const workspace = RED.nodes.workspace(id||activeWorkspace) || RED.nodes.subflow(id||activeWorkspace);
|
||||
if (!workspace) {
|
||||
return;
|
||||
}
|
||||
const currentOrder = workspace_tabs.listTabs()
|
||||
const oldOrder = [...currentOrder]
|
||||
const currentIndex = currentOrder.findIndex(id => id === workspace.id)
|
||||
currentOrder.splice(currentIndex, 1)
|
||||
if (direction === 'start') {
|
||||
currentOrder.unshift(workspace.id)
|
||||
} else if (direction === 'end') {
|
||||
currentOrder.push(workspace.id)
|
||||
}
|
||||
const newOrder = setWorkspaceOrder(currentOrder)
|
||||
if (JSON.stringify(newOrder) !== JSON.stringify(oldOrder)) {
|
||||
RED.history.push({
|
||||
t:'reorder',
|
||||
workspaces: {
|
||||
from:oldOrder,
|
||||
to:newOrder
|
||||
},
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id))
|
||||
const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id))
|
||||
if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) {
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
function setWorkspaceOrder(order) {
|
||||
var newOrder = order.filter(function(id) {
|
||||
return RED.nodes.workspace(id) !== undefined;
|
||||
})
|
||||
var newOrder = order.filter(id => !!RED.nodes.workspace(id))
|
||||
var currentOrder = RED.nodes.getWorkspaceOrder();
|
||||
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
|
||||
RED.nodes.setWorkspaceOrder(newOrder);
|
||||
RED.events.emit("flows:reorder",newOrder);
|
||||
}
|
||||
workspace_tabs.order(order);
|
||||
return newOrder
|
||||
}
|
||||
|
||||
function flashTab(tabId) {
|
||||
@@ -590,6 +825,10 @@ RED.workspaces = (function() {
|
||||
active: function() {
|
||||
return activeWorkspace
|
||||
},
|
||||
isActiveLocked: function() {
|
||||
var ws = RED.nodes.workspace(activeWorkspace) || RED.nodes.subflow(activeWorkspace)
|
||||
return ws && ws.locked
|
||||
},
|
||||
selection: function() {
|
||||
return workspace_tabs.selection();
|
||||
},
|
||||
@@ -646,6 +885,8 @@ RED.workspaces = (function() {
|
||||
workspace_tabs.resize();
|
||||
},
|
||||
enable: enableWorkspace,
|
||||
disable: disableWorkspace
|
||||
disable: disableWorkspace,
|
||||
lock: lockWorkspace,
|
||||
unlock: unlockWorkspace
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -68,6 +68,9 @@
|
||||
stroke: var(--red-ui-node-border);
|
||||
cursor: move;
|
||||
stroke-width: 1;
|
||||
.red-ui-workspace-locked & {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.red-ui-workspace-select-mode {
|
||||
g.red-ui-flow-node.red-ui-flow-node-hovered * {
|
||||
@@ -287,9 +290,11 @@ g.red-ui-flow-node-selected {
|
||||
text-anchor:start;
|
||||
}
|
||||
|
||||
.red-ui-flow-port-hovered {
|
||||
stroke: var(--red-ui-port-selected-color);
|
||||
fill: var(--red-ui-port-selected-color);
|
||||
#red-ui-workspace:not(.red-ui-workspace-locked) {
|
||||
.red-ui-flow-port-hovered {
|
||||
stroke: var(--red-ui-port-selected-color);
|
||||
fill: var(--red-ui-port-selected-color);
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-flow-subflow-port {
|
||||
|
||||
@@ -467,6 +467,9 @@ div.red-ui-info-table {
|
||||
.fa-eye {
|
||||
display: none;
|
||||
}
|
||||
.fa-unlock-alt {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.red-ui-info-outline-item-control-reveal,
|
||||
.red-ui-info-outline-item-control-action {
|
||||
@@ -500,6 +503,25 @@ div.red-ui-info-table {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.fa-lock {
|
||||
display: none;
|
||||
}
|
||||
.red-ui-info-outline-item.red-ui-info-outline-item-locked & {
|
||||
.fa-lock {
|
||||
display: inline-block;
|
||||
}
|
||||
.fa-unlock-alt {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// If the parent is locked, do not show the display/action buttons when
|
||||
// hovering in the outline
|
||||
.red-ui-info-outline-item-locked .red-ui-info-outline-item & {
|
||||
.red-ui-info-outline-item-control-disable,
|
||||
.red-ui-info-outline-item-control-action {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
button {
|
||||
margin-right: 3px
|
||||
}
|
||||
@@ -517,8 +539,6 @@ div.red-ui-info-table {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.red-ui-icons {
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
|
||||
@@ -106,6 +106,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-workspace-locked-icon {
|
||||
display: none;
|
||||
}
|
||||
.red-ui-workspace-locked {
|
||||
&.red-ui-tab {
|
||||
// border-top-style: dashed;
|
||||
// border-left-style: dashed;
|
||||
// border-right-style: dashed;
|
||||
|
||||
// a {
|
||||
// font-style: italic;
|
||||
// color: var(--red-ui-tab-text-color-disabled-inactive) !important;
|
||||
// }
|
||||
// &.active a {
|
||||
// font-weight: normal;
|
||||
// color: var(--red-ui-tab-text-color-disabled-active) !important;
|
||||
// }
|
||||
.red-ui-workspace-locked-icon {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#red-ui-navigator-canvas {
|
||||
position: absolute;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<option value="scale" data-i18n="range.scale.payload"></option>
|
||||
<option value="clamp" data-i18n="range.scale.limit"></option>
|
||||
<option value="roll" data-i18n="range.scale.wrap"></option>
|
||||
<option value="drop" data-i18n="range.scale.drop"></option>
|
||||
</select>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
@@ -32,11 +32,15 @@ module.exports = function(RED) {
|
||||
if (value !== undefined) {
|
||||
var n = Number(value);
|
||||
if (!isNaN(n)) {
|
||||
if (node.action == "clamp") {
|
||||
if (node.action === "drop") {
|
||||
if (n < node.minin) { done(); return; }
|
||||
if (n > node.maxin) { done(); return; }
|
||||
}
|
||||
if (node.action === "clamp") {
|
||||
if (n < node.minin) { n = node.minin; }
|
||||
if (n > node.maxin) { n = node.maxin; }
|
||||
}
|
||||
if (node.action == "roll") {
|
||||
if (node.action === "roll") {
|
||||
var divisor = node.maxin - node.minin;
|
||||
n = ((n - node.minin) % divisor + divisor) % divisor + node.minin;
|
||||
}
|
||||
|
||||
@@ -201,6 +201,7 @@ module.exports = function(RED) {
|
||||
});
|
||||
node.on("close", function() { clearDelayList(); });
|
||||
}
|
||||
|
||||
else if (node.pauseType === "random") {
|
||||
node.on("input", function(msg, send, done) {
|
||||
var wait = node.randomFirst + (node.diff * Math.random());
|
||||
@@ -226,34 +227,19 @@ module.exports = function(RED) {
|
||||
// The rate limit/queue type modes
|
||||
else if (node.pauseType === "rate") {
|
||||
node.on("input", function(msg, send, done) {
|
||||
if (msg.hasOwnProperty("reset")) {
|
||||
if (node.intervalID !== -1 ) {
|
||||
clearInterval(node.intervalID);
|
||||
node.intervalID = -1;
|
||||
}
|
||||
delete node.lastSent;
|
||||
node.buffer = [];
|
||||
node.rate = node.fixedrate;
|
||||
node.status({fill:"blue",shape:"ring",text:0});
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.drop) {
|
||||
var m = RED.util.cloneMessage(msg);
|
||||
delete m.flush;
|
||||
delete m.lifo;
|
||||
if (Object.keys(m).length > 1) {
|
||||
if (node.intervalID !== -1) {
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
|
||||
node.rate = msg.rate;
|
||||
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate)) && node.rate !== m.rate) {
|
||||
node.rate = m.rate;
|
||||
clearInterval(node.intervalID);
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
}
|
||||
var max_msgs = maxKeptMsgsCount(node);
|
||||
if ((max_msgs > 0) && (node.buffer.length >= max_msgs)) {
|
||||
node.buffer = [];
|
||||
node.error(RED._("delay.errors.too-many"), msg);
|
||||
node.error(RED._("delay.errors.too-many"), m);
|
||||
} else if (msg.toFront === true) {
|
||||
node.buffer.unshift({msg: m, send: send, done: done});
|
||||
node.reportDepth();
|
||||
@@ -263,8 +249,8 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
|
||||
node.rate = msg.rate;
|
||||
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate))) {
|
||||
node.rate = m.rate;
|
||||
}
|
||||
send(m);
|
||||
node.reportDepth();
|
||||
@@ -282,6 +268,8 @@ module.exports = function(RED) {
|
||||
else {
|
||||
while (len > 0) {
|
||||
const msgInfo = node.buffer.shift();
|
||||
delete msgInfo.msg.flush;
|
||||
delete msgInfo.msg.reset;
|
||||
if (Object.keys(msgInfo.msg).length > 1) {
|
||||
node.send(msgInfo.msg);
|
||||
msgInfo.done();
|
||||
@@ -335,6 +323,21 @@ module.exports = function(RED) {
|
||||
}
|
||||
done();
|
||||
}
|
||||
|
||||
if (msg.hasOwnProperty("reset")) {
|
||||
if (msg.flush === undefined) {
|
||||
if (node.intervalID !== -1 ) {
|
||||
clearInterval(node.intervalID);
|
||||
node.intervalID = -1;
|
||||
}
|
||||
delete node.lastSent;
|
||||
}
|
||||
node.buffer = [];
|
||||
node.rate = node.fixedrate;
|
||||
node.status({fill:"blue",shape:"ring",text:0});
|
||||
done();
|
||||
return;
|
||||
}
|
||||
});
|
||||
node.on("close", function() {
|
||||
clearInterval(node.intervalID);
|
||||
@@ -387,6 +390,22 @@ module.exports = function(RED) {
|
||||
node.buffer.push({msg, send, done}); // if not add to end of queue
|
||||
node.reportDepth();
|
||||
}
|
||||
if (msg.hasOwnProperty("flush")) {
|
||||
var len = node.buffer.length;
|
||||
if (typeof(msg.flush) == 'number') { len = Math.min(Math.floor(msg.flush,len)); }
|
||||
while (len > 0) {
|
||||
const msgInfo = node.buffer.shift();
|
||||
delete msgInfo.msg.flush;
|
||||
delete msgInfo.msg.reset;
|
||||
if (Object.keys(msgInfo.msg).length > 2) {
|
||||
node.send(msgInfo.msg);
|
||||
msgInfo.done();
|
||||
}
|
||||
len = len - 1;
|
||||
}
|
||||
node.status({});
|
||||
done();
|
||||
}
|
||||
if (msg.hasOwnProperty("reset")) {
|
||||
while (node.buffer.length > 0) {
|
||||
const msgInfo = node.buffer.shift();
|
||||
@@ -397,21 +416,6 @@ module.exports = function(RED) {
|
||||
node.status({text:"reset"});
|
||||
done();
|
||||
}
|
||||
if (msg.hasOwnProperty("flush")) {
|
||||
var len = node.buffer.length;
|
||||
if (typeof(msg.flush) == 'number') { len = Math.min(Math.floor(msg.flush,len)); }
|
||||
while (len > 0) {
|
||||
const msgInfo = node.buffer.shift();
|
||||
delete msgInfo.msg.flush;
|
||||
if (Object.keys(msgInfo.msg).length > 2) {
|
||||
node.send(msgInfo.msg);
|
||||
msgInfo.done();
|
||||
}
|
||||
len = len - 1;
|
||||
}
|
||||
node.status({});
|
||||
done();
|
||||
}
|
||||
});
|
||||
node.on("close", function() {
|
||||
clearInterval(node.intervalID);
|
||||
|
||||
@@ -34,11 +34,14 @@
|
||||
the range specified within the target range.</p>
|
||||
<p><i>Scale and wrap within the target range</i> means that the result will
|
||||
be wrapped within the target range.</p>
|
||||
<p><i>Scale, but drop if outside input range</i> means that the result will
|
||||
be scaled, but any inputs outside of the inout range will be dropped.</p>
|
||||
<p>For example an input 0 - 10 mapped to 0 - 100.</p>
|
||||
<table style="outline-width:#888 solid thin">
|
||||
<tr><th width="80px">mode</th><th width="80px">input</th><th width="80px">output</th></tr>
|
||||
<tr><td><center>scale</center></td><td><center>12</center></td><td><center>120</center></td></tr>
|
||||
<tr><td><center>limit</center></td><td><center>12</center></td><td><center>100</center></td></tr>
|
||||
<tr><td><center>wrap</center></td><td><center>12</center></td><td><center>20</center></td></tr>
|
||||
<tr><td><center>drop</center></td><td><center>12</center></td><td><center><i>(no output)</i></center></td></tr>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
@@ -813,7 +813,8 @@
|
||||
"scale": {
|
||||
"payload": "Scale the message property",
|
||||
"limit": "Scale and limit to the target range",
|
||||
"wrap": "Scale and wrap within the target range"
|
||||
"wrap": "Scale and wrap within the target range",
|
||||
"drop": "Scale, but drop msg if outside input range"
|
||||
},
|
||||
"tip": "Tip: This node ONLY works with numbers.",
|
||||
"errors": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.0.0",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "10.1.0",
|
||||
"semver": "7.3.7",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "3.0.0",
|
||||
"@node-red/util": "3.0.0",
|
||||
"@node-red/registry": "3.1.0-beta.0",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"async-mutex": "0.3.2",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.18.1",
|
||||
|
||||
12
packages/node_modules/@node-red/util/lib/util.js
vendored
12
packages/node_modules/@node-red/util/lib/util.js
vendored
@@ -696,13 +696,19 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
|
||||
function prepareJSONataExpression(value,node) {
|
||||
var expr = jsonata(value);
|
||||
expr.assign('flowContext', function(val, store) {
|
||||
return node.context().flow.get(val, store);
|
||||
if (node) {
|
||||
return node.context().flow.get(val, store);
|
||||
}
|
||||
return "";
|
||||
});
|
||||
expr.assign('globalContext', function(val, store) {
|
||||
return node.context().global.get(val, store);
|
||||
if (node) {
|
||||
return node.context().global.get(val, store);
|
||||
}
|
||||
return "";
|
||||
});
|
||||
expr.assign('env', function(name) {
|
||||
var val = getSetting(node, name, node._flow);
|
||||
var val = getSetting(node, name, node ? node._flow : null);
|
||||
if (typeof val !== 'undefined') {
|
||||
return val;
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
10
packages/node_modules/node-red/package.json
vendored
10
packages/node_modules/node-red/package.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "3.0.0",
|
||||
"@node-red/runtime": "3.0.0",
|
||||
"@node-red/util": "3.0.0",
|
||||
"@node-red/nodes": "3.0.0",
|
||||
"@node-red/editor-api": "3.1.0-beta.0",
|
||||
"@node-red/runtime": "3.1.0-beta.0",
|
||||
"@node-red/util": "3.1.0-beta.0",
|
||||
"@node-red/nodes": "3.1.0-beta.0",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.18.1",
|
||||
|
||||
@@ -106,6 +106,27 @@ describe('range Node', function() {
|
||||
genericRangeTest("clamp", 0, 10, 0, 1000, false, -1, 0, done);
|
||||
});
|
||||
|
||||
it('drops msg if in drop mode and input outside range', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":2,"maxin":8,"minout":20,"maxout":80,"action":"drop","round":true,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload');
|
||||
msg.payload.should.equal(50);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
rangeNode1.receive({payload:1});
|
||||
rangeNode1.receive({payload:9});
|
||||
rangeNode1.receive({payload:5});
|
||||
});
|
||||
});
|
||||
|
||||
it('just passes on msg if payload not present', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":0,"maxin":100,"minout":0,"maxout":100,"action":"scale","round":true,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
|
||||
@@ -817,6 +817,105 @@ describe('delay Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('can part flush and reset rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":1,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
var c = 0;
|
||||
helperNode1.on("input", function(msg) {
|
||||
// console.log("GOT",Date.now() - t,msg)
|
||||
msg.should.have.a.property('payload');
|
||||
msg.should.have.a.property('topic');
|
||||
try {
|
||||
if (msg.topic === "foo") {
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(0,50);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "bar") {
|
||||
msg.payload.should.equal(2);
|
||||
(Date.now() - t).should.be.approximately(200,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "fob") {
|
||||
msg.payload.should.equal(5);
|
||||
(Date.now() - t).should.be.approximately(400,100);
|
||||
c = 5;
|
||||
}
|
||||
if (c === 5) { done(); }
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
// send test messages
|
||||
// delayNode1.receive({payload:1,topic:"foo"});
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"foo"}); } );
|
||||
setTimeout( function() { delayNode1.receive({payload:2,topic:"far"}); }, 10 );
|
||||
setTimeout( function() { delayNode1.receive({payload:3,topic:"boo"}); }, 20 );
|
||||
setTimeout( function() { delayNode1.receive({payload:4,topic:"bar"}); }, 30 );
|
||||
setTimeout( function() { delayNode1.receive({flush:2,reset:true}); }, 200);
|
||||
setTimeout( function() { delayNode1.receive({payload:5,topic:"fob"}); }, 300 );
|
||||
setTimeout( function() { delayNode1.receive({flush:1,reset:true}); }, 400);
|
||||
});
|
||||
});
|
||||
|
||||
it('can full flush and reset rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":1,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
var c = 0;
|
||||
helperNode1.on("input", function(msg) {
|
||||
// console.log("GOT",Date.now() - t,msg)
|
||||
msg.should.have.a.property('payload');
|
||||
msg.should.have.a.property('topic');
|
||||
try {
|
||||
if (msg.topic === "foo") {
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(0,50);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "bar") {
|
||||
msg.payload.should.equal(4);
|
||||
(Date.now() - t).should.be.approximately(200,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "all") {
|
||||
msg.payload.should.equal(5);
|
||||
(Date.now() - t).should.be.approximately(200,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "fob") {
|
||||
msg.payload.should.equal(6);
|
||||
(Date.now() - t).should.be.approximately(400,100);
|
||||
c = 5;
|
||||
}
|
||||
if (c === 5) { done(); }
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
// send test messages
|
||||
// delayNode1.receive({payload:1,topic:"foo"});
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"foo"}); } );
|
||||
setTimeout( function() { delayNode1.receive({payload:2,topic:"far"}); }, 10 );
|
||||
setTimeout( function() { delayNode1.receive({payload:3,topic:"boo"}); }, 20 );
|
||||
setTimeout( function() { delayNode1.receive({payload:4,topic:"bar"}); }, 30 );
|
||||
setTimeout( function() { delayNode1.receive({payload:5,topic:"last",flush:true,reset:true}); }, 200);
|
||||
setTimeout( function() { delayNode1.receive({payload:6,topic:"fob"}); }, 300 );
|
||||
setTimeout( function() { delayNode1.receive({flush:1,reset:true}); }, 400);
|
||||
});
|
||||
});
|
||||
|
||||
it('can part push to front of rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":1,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
|
||||
@@ -260,7 +260,8 @@ describe('subflow', function() {
|
||||
{name: "KB", type: "bool", value: "true"},
|
||||
{name: "KJ", type: "json", value: "[1,2,3]"},
|
||||
{name: "Kb", type: "bin", value: "[65,65]"},
|
||||
{name: "Ke", type: "env", value: "KS"}
|
||||
{name: "Ke", type: "env", value: "KS"},
|
||||
{name: "Kj", type: "jsonata", value: "1+2"},
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
@@ -279,7 +280,7 @@ describe('subflow', function() {
|
||||
]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.VE = env.get('Ke'); msg.VS = env.get('KS'); msg.VN = env.get('KN'); msg.VB = env.get('KB'); msg.VJ = env.get('KJ'); msg.Vb = env.get('Kb'); return msg;",
|
||||
func:"msg.VE = env.get('Ke'); msg.VS = env.get('KS'); msg.VN = env.get('KN'); msg.VB = env.get('KB'); msg.VJ = env.get('KJ'); msg.Vb = env.get('Kb'); msg.Vj = env.get('Kj'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
@@ -294,6 +295,7 @@ describe('subflow', function() {
|
||||
msg.should.have.property("Vb");
|
||||
should.ok(msg.Vb instanceof Buffer);
|
||||
msg.should.have.property("VE","STR");
|
||||
msg.should.have.property("Vj",3);
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
@@ -1322,6 +1322,40 @@ describe('Flow', function() {
|
||||
|
||||
});
|
||||
|
||||
it("can define environment variable using JSONata", function (done) {
|
||||
try {
|
||||
after(function() {
|
||||
delete process.env.V0;
|
||||
})
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab",env:[
|
||||
{"name": "V0", value: "1+2", type: "jsonata"}
|
||||
]},
|
||||
{id:"g1",type:"group",z:"t1",env:[
|
||||
{"name": "V1", value: "2+3", type: "jsonata"},
|
||||
]},
|
||||
{id:"1",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V0)",wires:[]},
|
||||
{id:"2",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V1)",wires:[]},
|
||||
]);
|
||||
var flow = Flow.create({getSetting:v=>process.env[v]},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].foo.should.equal(3);
|
||||
activeNodes["2"].foo.should.equal(5);
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e.stack);
|
||||
done(e);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user