mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #3294 from node-red/multi-select-links
Allow multiple links to be selected by ctrl-click
This commit is contained in:
commit
fad708e8de
@ -63,7 +63,6 @@ RED.view = (function() {
|
|||||||
var activeGroups = [];
|
var activeGroups = [];
|
||||||
var dirtyGroups = {};
|
var dirtyGroups = {};
|
||||||
|
|
||||||
var selected_link = null;
|
|
||||||
var mousedown_link = null;
|
var mousedown_link = null;
|
||||||
var mousedown_node = null;
|
var mousedown_node = null;
|
||||||
var mousedown_group = null;
|
var mousedown_group = null;
|
||||||
@ -159,6 +158,31 @@ RED.view = (function() {
|
|||||||
return api;
|
return api;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var selectedLinks = (function() {
|
||||||
|
var links = new Set();
|
||||||
|
return {
|
||||||
|
add: function(link) {
|
||||||
|
links.add(link);
|
||||||
|
link.selected = true;
|
||||||
|
},
|
||||||
|
remove: function(link) {
|
||||||
|
links.delete(link);
|
||||||
|
link.selected = false;
|
||||||
|
},
|
||||||
|
clear: function() {
|
||||||
|
links.forEach(function(link) { link.selected = false })
|
||||||
|
links.clear();
|
||||||
|
},
|
||||||
|
length: function() {
|
||||||
|
return links.size;
|
||||||
|
},
|
||||||
|
forEach: function(func) { links.forEach(func) },
|
||||||
|
has: function(link) { return links.has(link) },
|
||||||
|
toArray: function() { return Array.from(links) }
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
|
||||||
chart = $("#red-ui-workspace-chart");
|
chart = $("#red-ui-workspace-chart");
|
||||||
@ -909,7 +933,7 @@ RED.view = (function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mousedown_node && !mousedown_link && !mousedown_group) {
|
if (!mousedown_node && !mousedown_link && !mousedown_group) {
|
||||||
selected_link = null;
|
selectedLinks.clear();
|
||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
}
|
||||||
if (mouse_mode === 0) {
|
if (mouse_mode === 0) {
|
||||||
@ -1348,7 +1372,7 @@ RED.view = (function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && !mousedown_group && selected_link == null) {
|
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && !mousedown_group && selectedLinks.length() === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1372,16 +1396,18 @@ RED.view = (function() {
|
|||||||
// Get all the wires we need to detach.
|
// Get all the wires we need to detach.
|
||||||
var links = [];
|
var links = [];
|
||||||
var existingLinks = [];
|
var existingLinks = [];
|
||||||
if (selected_link &&
|
if (selectedLinks.length() > 0) {
|
||||||
((mousedown_port_type === PORT_TYPE_OUTPUT &&
|
selectedLinks.forEach(function(link) {
|
||||||
selected_link.source === mousedown_node &&
|
if (((mousedown_port_type === PORT_TYPE_OUTPUT &&
|
||||||
selected_link.sourcePort === mousedown_port_index
|
link.source === mousedown_node &&
|
||||||
|
link.sourcePort === mousedown_port_index
|
||||||
) ||
|
) ||
|
||||||
(mousedown_port_type === PORT_TYPE_INPUT &&
|
(mousedown_port_type === PORT_TYPE_INPUT &&
|
||||||
selected_link.target === mousedown_node
|
link.target === mousedown_node
|
||||||
))
|
))) {
|
||||||
) {
|
existingLinks.push(link);
|
||||||
existingLinks = [selected_link];
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
var filter;
|
var filter;
|
||||||
if (mousedown_port_type === PORT_TYPE_OUTPUT) {
|
if (mousedown_port_type === PORT_TYPE_OUTPUT) {
|
||||||
@ -1419,7 +1445,7 @@ RED.view = (function() {
|
|||||||
} else if (mousedown_node && !quickAddLink) {
|
} else if (mousedown_node && !quickAddLink) {
|
||||||
showDragLines([{node:mousedown_node,port:mousedown_port_index,portType:mousedown_port_type}]);
|
showDragLines([{node:mousedown_node,port:mousedown_port_index,portType:mousedown_port_type}]);
|
||||||
}
|
}
|
||||||
selected_link = null;
|
selectedLinks.clear();
|
||||||
}
|
}
|
||||||
mousePos = mouse_position;
|
mousePos = mouse_position;
|
||||||
for (i=0;i<drag_lines.length;i++) {
|
for (i=0;i<drag_lines.length;i++) {
|
||||||
@ -1941,7 +1967,7 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selected_link = null;
|
selectedLinks.clear();
|
||||||
if (mouse_mode !== RED.state.SELECTING_NODE) {
|
if (mouse_mode !== RED.state.SELECTING_NODE) {
|
||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
}
|
||||||
@ -1956,7 +1982,7 @@ RED.view = (function() {
|
|||||||
n.n.selected = false;
|
n.n.selected = false;
|
||||||
}
|
}
|
||||||
movingSet.clear();
|
movingSet.clear();
|
||||||
selected_link = null;
|
selectedLinks.clear();
|
||||||
if (activeGroup) {
|
if (activeGroup) {
|
||||||
activeGroup.active = false
|
activeGroup.active = false
|
||||||
activeGroup.dirty = true;
|
activeGroup.dirty = true;
|
||||||
@ -2050,12 +2076,16 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (activeFlowLinks.length === 0 && selected_link !== null && selected_link.link) {
|
if (activeFlowLinks.length === 0 && selectedLinks.length() > 0) {
|
||||||
activeLinks.push(selected_link);
|
selectedLinks.forEach(function(link) {
|
||||||
activeLinkNodes[selected_link.source.id] = selected_link.source;
|
if (link.link) {
|
||||||
selected_link.source.dirty = true;
|
activeLinks.push(link);
|
||||||
activeLinkNodes[selected_link.target.id] = selected_link.target;
|
activeLinkNodes[link.source.id] = link.source;
|
||||||
selected_link.target.dirty = true;
|
link.source.dirty = true;
|
||||||
|
activeLinkNodes[link.target.id] = link.target;
|
||||||
|
link.target.dirty = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selection.flows = workspaceSelection;
|
selection.flows = workspaceSelection;
|
||||||
@ -2066,6 +2096,10 @@ RED.view = (function() {
|
|||||||
return value.map(function(n) { return n.id })
|
return value.map(function(n) { return n.id })
|
||||||
} else if (key === 'link') {
|
} else if (key === 'link') {
|
||||||
return value.source.id+":"+value.sourcePort+":"+value.target.id;
|
return value.source.id+":"+value.sourcePort+":"+value.target.id;
|
||||||
|
} else if (key === 'links') {
|
||||||
|
return value.map(function(link) {
|
||||||
|
return link.source.id+":"+link.sourcePort+":"+link.target.id;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
@ -2135,7 +2169,7 @@ RED.view = (function() {
|
|||||||
updateActiveNodes();
|
updateActiveNodes();
|
||||||
updateSelection();
|
updateSelection();
|
||||||
redraw();
|
redraw();
|
||||||
} else if (movingSet.length() > 0 || selected_link != null) {
|
} else if (movingSet.length() > 0 || selectedLinks.length() > 0) {
|
||||||
var result;
|
var result;
|
||||||
var node;
|
var node;
|
||||||
var removedNodes = [];
|
var removedNodes = [];
|
||||||
@ -2234,52 +2268,55 @@ RED.view = (function() {
|
|||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var historyEvent;
|
|
||||||
|
|
||||||
if (selected_link && selected_link.link) {
|
var linkRemoveHistoryEvents = [];
|
||||||
var sourceId = selected_link.source.id;
|
if (selectedLinks.length() > 0) {
|
||||||
var targetId = selected_link.target.id;
|
selectedLinks.forEach(function(link) {
|
||||||
var sourceIdIndex = selected_link.target.links.indexOf(sourceId);
|
if (link.link) {
|
||||||
var targetIdIndex = selected_link.source.links.indexOf(targetId);
|
var sourceId = link.source.id;
|
||||||
|
var targetId = link.target.id;
|
||||||
|
var sourceIdIndex = link.target.links.indexOf(sourceId);
|
||||||
|
var targetIdIndex = link.source.links.indexOf(targetId);
|
||||||
|
|
||||||
historyEvent = {
|
linkRemoveHistoryEvents.push({
|
||||||
t:"multi",
|
t:"multi",
|
||||||
events: [
|
events: [
|
||||||
{
|
{
|
||||||
t: "edit",
|
t: "edit",
|
||||||
node: selected_link.source,
|
node: link.source,
|
||||||
changed: selected_link.source.changed,
|
changed: link.source.changed,
|
||||||
changes: {
|
changes: {
|
||||||
links: $.extend(true,{},{v:selected_link.source.links}).v
|
links: $.extend(true,{},{v:link.source.links}).v
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "edit",
|
t: "edit",
|
||||||
node: selected_link.target,
|
node: link.target,
|
||||||
changed: selected_link.target.changed,
|
changed: link.target.changed,
|
||||||
changes: {
|
changes: {
|
||||||
links: $.extend(true,{},{v:selected_link.target.links}).v
|
links: $.extend(true,{},{v:link.target.links}).v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
dirty:RED.nodes.dirty()
|
dirty:startDirty
|
||||||
}
|
})
|
||||||
RED.nodes.dirty(true);
|
|
||||||
selected_link.source.changed = true;
|
link.source.changed = true;
|
||||||
selected_link.target.changed = true;
|
link.target.changed = true;
|
||||||
selected_link.target.links.splice(sourceIdIndex,1);
|
link.target.links.splice(sourceIdIndex,1);
|
||||||
selected_link.source.links.splice(targetIdIndex,1);
|
link.source.links.splice(targetIdIndex,1);
|
||||||
selected_link.source.dirty = true;
|
link.source.dirty = true;
|
||||||
selected_link.target.dirty = true;
|
link.target.dirty = true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (selected_link) {
|
RED.nodes.removeLink(link);
|
||||||
RED.nodes.removeLink(selected_link);
|
removedLinks.push(link);
|
||||||
removedLinks.push(selected_link);
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
historyEvent = {
|
var historyEvent = {
|
||||||
t:"delete",
|
t:"delete",
|
||||||
nodes:removedNodes,
|
nodes:removedNodes,
|
||||||
links:removedLinks,
|
links:removedLinks,
|
||||||
@ -2295,10 +2332,17 @@ RED.view = (function() {
|
|||||||
if (removedSubflowStatus) {
|
if (removedSubflowStatus) {
|
||||||
historyEvent.subflow.status = removedSubflowStatus;
|
historyEvent.subflow.status = removedSubflowStatus;
|
||||||
}
|
}
|
||||||
}
|
if (linkRemoveHistoryEvents.length > 0) {
|
||||||
|
linkRemoveHistoryEvents.unshift(historyEvent);
|
||||||
|
RED.history.push({
|
||||||
|
t:"multi",
|
||||||
|
events: linkRemoveHistoryEvents
|
||||||
|
})
|
||||||
|
} else {
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
|
}
|
||||||
|
|
||||||
selected_link = null;
|
selectedLinks.clear();
|
||||||
updateActiveNodes();
|
updateActiveNodes();
|
||||||
updateSelection();
|
updateSelection();
|
||||||
redraw();
|
redraw();
|
||||||
@ -2709,10 +2753,13 @@ RED.view = (function() {
|
|||||||
} else {
|
} else {
|
||||||
resetMouseVars();
|
resetMouseVars();
|
||||||
}
|
}
|
||||||
selected_link = select_link;
|
|
||||||
mousedown_link = select_link;
|
mousedown_link = select_link;
|
||||||
if (select_link) {
|
if (select_link) {
|
||||||
|
selectedLinks.clear();
|
||||||
|
selectedLinks.add(select_link);
|
||||||
updateSelection();
|
updateSelection();
|
||||||
|
} else {
|
||||||
|
selectedLinks.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
redraw();
|
redraw();
|
||||||
@ -2721,7 +2768,10 @@ RED.view = (function() {
|
|||||||
|
|
||||||
resetMouseVars();
|
resetMouseVars();
|
||||||
hideDragLines();
|
hideDragLines();
|
||||||
selected_link = select_link;
|
if (select_link) {
|
||||||
|
selectedLinks.clear();
|
||||||
|
selectedLinks.add(select_link);
|
||||||
|
}
|
||||||
mousedown_link = select_link;
|
mousedown_link = select_link;
|
||||||
if (select_link) {
|
if (select_link) {
|
||||||
updateSelection();
|
updateSelection();
|
||||||
@ -3212,7 +3262,7 @@ RED.view = (function() {
|
|||||||
mousedown_node.selected = true;
|
mousedown_node.selected = true;
|
||||||
movingSet.add(mousedown_node);
|
movingSet.add(mousedown_node);
|
||||||
}
|
}
|
||||||
selected_link = null;
|
selectedLinks.clear();
|
||||||
if (d3.event.button != 2) {
|
if (d3.event.button != 2) {
|
||||||
mouse_mode = RED.state.MOVING;
|
mouse_mode = RED.state.MOVING;
|
||||||
var mouse = d3.touches(this)[0]||d3.mouse(this);
|
var mouse = d3.touches(this)[0]||d3.mouse(this);
|
||||||
@ -3339,17 +3389,30 @@ RED.view = (function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mousedown_link = d;
|
mousedown_link = d;
|
||||||
|
|
||||||
|
if (selectedLinks.length() === 0 || !(d3.event.metaKey || d3.event.ctrlKey)) {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
selected_link = mousedown_link;
|
}
|
||||||
|
if (d3.event.metaKey || d3.event.ctrlKey) {
|
||||||
|
if (!selectedLinks.has(mousedown_link)) {
|
||||||
|
selectedLinks.add(mousedown_link);
|
||||||
|
} else {
|
||||||
|
if (selectedLinks.length() !== 1) {
|
||||||
|
selectedLinks.remove(mousedown_link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectedLinks.add(mousedown_link);
|
||||||
|
}
|
||||||
updateSelection();
|
updateSelection();
|
||||||
redraw();
|
redraw();
|
||||||
focusView();
|
focusView();
|
||||||
d3.event.stopPropagation();
|
d3.event.stopPropagation();
|
||||||
if (d3.event.metaKey || d3.event.ctrlKey) {
|
if (!mousedown_link.link && selectedLinks.length() === 1 && selectedLinks.has(mousedown_link) && (d3.event.metaKey || d3.event.ctrlKey)) {
|
||||||
d3.select(this).classed("red-ui-flow-link-splice",true);
|
d3.select(this).classed("red-ui-flow-link-splice",true);
|
||||||
var point = d3.mouse(this);
|
var point = d3.mouse(this);
|
||||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||||
showQuickAddDialog({position:point, splice:selected_link, group:clickedGroup});
|
showQuickAddDialog({position:point, splice:mousedown_link, group:clickedGroup});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function linkTouchStart(d) {
|
function linkTouchStart(d) {
|
||||||
@ -3359,7 +3422,8 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
mousedown_link = d;
|
mousedown_link = d;
|
||||||
clearSelection();
|
clearSelection();
|
||||||
selected_link = mousedown_link;
|
selectedLinks.clear();
|
||||||
|
selectedLinks.add(mousedown_link);
|
||||||
updateSelection();
|
updateSelection();
|
||||||
redraw();
|
redraw();
|
||||||
focusView();
|
focusView();
|
||||||
@ -3595,7 +3659,7 @@ RED.view = (function() {
|
|||||||
function showTouchMenu(obj,pos) {
|
function showTouchMenu(obj,pos) {
|
||||||
var mdn = mousedown_node;
|
var mdn = mousedown_node;
|
||||||
var options = [];
|
var options = [];
|
||||||
options.push({name:"delete",disabled:(movingSet.length()===0 && selected_link === null),onselect:function() {deleteSelection();}});
|
options.push({name:"delete",disabled:(movingSet.length()===0 && selectedLinks.length() === 0),onselect:function() {deleteSelection();}});
|
||||||
options.push({name:"cut",disabled:(movingSet.length()===0),onselect:function() {copySelection();deleteSelection();}});
|
options.push({name:"cut",disabled:(movingSet.length()===0),onselect:function() {copySelection();deleteSelection();}});
|
||||||
options.push({name:"copy",disabled:(movingSet.length()===0),onselect:function() {copySelection();}});
|
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:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard, {generateIds: true, touchImport: true});}});
|
||||||
@ -4352,7 +4416,7 @@ RED.view = (function() {
|
|||||||
link.exit().remove();
|
link.exit().remove();
|
||||||
link.each(function(d) {
|
link.each(function(d) {
|
||||||
var link = d3.select(this);
|
var link = d3.select(this);
|
||||||
if (d.added || d===selected_link || d.selected || dirtyNodes[d.source.id] || dirtyNodes[d.target.id]) {
|
if (d.added || d.selected || dirtyNodes[d.source.id] || dirtyNodes[d.target.id]) {
|
||||||
var numOutputs = d.source.outputs || 1;
|
var numOutputs = d.source.outputs || 1;
|
||||||
var sourcePort = d.sourcePort || 0;
|
var sourcePort = d.sourcePort || 0;
|
||||||
var y = -((numOutputs-1)/2)*13 +13*sourcePort;
|
var y = -((numOutputs-1)/2)*13 +13*sourcePort;
|
||||||
@ -4375,7 +4439,8 @@ RED.view = (function() {
|
|||||||
this.__pathLine__.classList.toggle("red-ui-flow-node-disabled",!!(d.source.d || d.target.d));
|
this.__pathLine__.classList.toggle("red-ui-flow-node-disabled",!!(d.source.d || d.target.d));
|
||||||
this.__pathLine__.classList.toggle("red-ui-flow-subflow-link", !d.link && activeSubflow);
|
this.__pathLine__.classList.toggle("red-ui-flow-subflow-link", !d.link && activeSubflow);
|
||||||
}
|
}
|
||||||
this.classList.toggle("red-ui-flow-link-selected", !!(d===selected_link||d.selected));
|
|
||||||
|
this.classList.toggle("red-ui-flow-link-selected", !!d.selected);
|
||||||
|
|
||||||
var connectedToUnknown = !!(d.target.type == "unknown" || d.source.type == "unknown");
|
var connectedToUnknown = !!(d.target.type == "unknown" || d.source.type == "unknown");
|
||||||
this.classList.toggle("red-ui-flow-link-unknown",!!(d.target.type == "unknown" || d.source.type == "unknown"))
|
this.classList.toggle("red-ui-flow-link-unknown",!!(d.target.type == "unknown" || d.source.type == "unknown"))
|
||||||
@ -5083,8 +5148,9 @@ RED.view = (function() {
|
|||||||
if (allNodes.size > 0) {
|
if (allNodes.size > 0) {
|
||||||
selection.nodes = Array.from(allNodes);
|
selection.nodes = Array.from(allNodes);
|
||||||
}
|
}
|
||||||
if (selected_link != null) {
|
if (selectedLinks.length() > 0) {
|
||||||
selection.link = selected_link;
|
selection.links = selectedLinks.toArray();
|
||||||
|
selection.link = selection.links[0];
|
||||||
}
|
}
|
||||||
return selection;
|
return selection;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user