Add core:detach-selected-nodes action

This commit is contained in:
Nick O'Leary 2022-01-11 00:16:24 +00:00
parent cb3fcb7bfa
commit 58c94b7773
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
4 changed files with 140 additions and 10 deletions

View File

@ -684,6 +684,13 @@ RED.history = (function() {
peek: function() {
return undoHistory[undoHistory.length-1];
},
replace: function(ev) {
if (undoHistory.length === 0) {
RED.history.push(ev);
} else {
undoHistory[undoHistory.length-1] = ev;
}
},
clear: function() {
undoHistory = [];
redoHistory = [];

View File

@ -2552,6 +2552,9 @@ RED.nodes = (function() {
addLink: addLink,
removeLink: removeLink,
getNodeLinks: function(id, portType) {
if (typeof id !== 'string') {
id = id.id;
}
if (nodeLinks[id]) {
if (portType === 1) {
// Return cloned arrays so they can be safely modified by caller

View File

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

View File

@ -538,6 +538,8 @@ RED.view = (function() {
RED.actions.add("core:cut-selection-to-internal-clipboard",function(){copySelection();deleteSelection();});
RED.actions.add("core:paste-from-internal-clipboard",function(){importNodes(clipboard,{generateIds: true});});
RED.actions.add("core:detach-selected-nodes", function() { detachSelectedNodes() })
RED.events.on("view:selection-changed", function(selection) {
var hasSelection = (selection.nodes && selection.nodes.length > 0);
var hasMultipleSelection = hasSelection && selection.nodes.length > 1;
@ -1384,7 +1386,7 @@ RED.view = (function() {
return;
}
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && !mousedown_node && !mousedown_group && selectedLinks.length() === 0) {
if (mouse_mode != RED.state.QUICK_JOINING && mouse_mode != RED.state.IMPORT_DRAGGING && mouse_mode != RED.state.DETACHED_DRAGGING && !mousedown_node && !mousedown_group && selectedLinks.length() === 0) {
return;
}
@ -1489,7 +1491,7 @@ RED.view = (function() {
RED.nodes.filterLinks({ target: node.n }).length === 0;
}
}
} else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING) {
} else if (mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.IMPORT_DRAGGING || mouse_mode == RED.state.DETACHED_DRAGGING) {
mousePos = mouse_position;
var minX = 0;
var minY = 0;
@ -1845,10 +1847,30 @@ RED.view = (function() {
// movingSet.add(mousedown_node);
// }
// }
if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE) {
if (mouse_mode == RED.state.MOVING || mouse_mode == RED.state.MOVING_ACTIVE || mouse_mode == RED.state.DETACHED_DRAGGING) {
// if (mousedown_node) {
// delete mousedown_node.gSelected;
// }
if (mouse_mode === RED.state.DETACHED_DRAGGING) {
var ns = [];
for (var j=0;j<movingSet.length();j++) {
var n = movingSet.get(j);
if (n.ox !== n.n.x || n.oy !== n.n.y) {
ns.push({n:n.n,ox:n.ox,oy:n.oy,moved:n.n.moved});
n.n.dirty = true;
n.n.moved = true;
}
}
var detachEvent = RED.history.peek();
// The last event in the stack *should* be a multi-event from
// where the links were added/removed
var historyEvent = {t:"move",nodes:ns,dirty:RED.nodes.dirty()}
if (detachEvent.t === "multi") {
detachEvent.events.push(historyEvent)
} else {
RED.history.push(historyEvent)
}
}
for (i=0;i<movingSet.length();i++) {
var node = movingSet.get(i);
delete node.ox;
@ -1893,7 +1915,10 @@ RED.view = (function() {
if (mouse_mode === RED.state.MOVING || mouse_mode === RED.state.MOVING_ACTIVE) {
return;
}
if (mouse_mode === RED.state.IMPORT_DRAGGING) {
if (mouse_mode === RED.state.DETACHED_DRAGGING) {
clearSelection();
mouse_mode = 0;
} else if (mouse_mode === RED.state.IMPORT_DRAGGING) {
clearSelection();
RED.history.pop();
mouse_mode = 0;
@ -2431,6 +2456,85 @@ RED.view = (function() {
}
}
function detachSelectedNodes() {
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length === 1) {
// var selectedNodes = new Set(selection.nodes);
//
// var allInboundLinks = [];
// var allOutboundLinks = [];
//
// selection.nodes.forEach(node => {
// var inboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_INPUT);
// var outboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_OUTPUT);
// inboundLinks.forEach(l => {
// if (!selectedNodes.has(l.source)) {
// allInboundLinks.push(l);
// }
// })
// outboundLinks.forEach(l => {
// if (!selectedNodes.has(l.target)) {
// allOutboundLinks.push(l);
// }
// })
// })
var node = selection.nodes[0];
// 1. find all the links attached to this node
var inboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_INPUT);
var outboundLinks = RED.nodes.getNodeLinks(node, PORT_TYPE_OUTPUT);
// 2. delete all those links
inboundLinks.forEach(l => RED.nodes.removeLink(l))
outboundLinks.forEach(l => RED.nodes.removeLink(l))
// 3. restore links from all source nodes to all target nodes
var newLinks = [];
var createdLinkIds = new Set();
inboundLinks.forEach(inLink => {
outboundLinks.forEach(outLink => {
var linkId = inLink.source.id+":"+inLink.sourcePort+":"+outLink.target.id
if (!createdLinkIds.has(linkId)) {
createdLinkIds.add(linkId);
var link = {
source: inLink.source,
sourcePort: inLink.sourcePort,
target: outLink.target
};
var existingLinks = RED.nodes.filterLinks(link)
if (existingLinks.length === 0) {
newLinks.push(link);
RED.nodes.addLink(link);
}
}
})
})
var oldLinks = inboundLinks.concat(outboundLinks);
if (oldLinks.length) {
RED.history.push({
t: "multi",
events: [
{ t:'delete', links: oldLinks },
{ t:'add', links: newLinks }
],
dirty: RED.nodes.dirty()
})
RED.nodes.dirty(true)
}
prepareDrag([node.x,node.y]);
mouse_mode = RED.state.DETACHED_DRAGGING;
RED.view.redraw(true);
}
}
function calculateTextWidth(str, className) {
var result = convertLineBreakCharacter(str);
var width = 0;
@ -2956,10 +3060,13 @@ RED.view = (function() {
msn.dx = msn.n.x-mouse[0];
msn.dy = msn.n.y-mouse[1];
}
mouse_offset = d3.mouse(document.body);
if (isNaN(mouse_offset[0])) {
mouse_offset = d3.touches(document.body)[0];
try {
mouse_offset = d3.mouse(document.body);
if (isNaN(mouse_offset[0])) {
mouse_offset = d3.touches(document.body)[0];
}
} catch(err) {
mouse_offset = [0,0]
}
}
@ -3040,7 +3147,7 @@ RED.view = (function() {
//var touch0 = d3.event;
//var pos = [touch0.pageX,touch0.pageY];
//RED.touch.radialMenu.show(d3.select(this),pos);
if (mouse_mode == RED.state.IMPORT_DRAGGING) {
if (mouse_mode == RED.state.IMPORT_DRAGGING || mouse_mode == RED.state.DETACHED_DRAGGING) {
var historyEvent = RED.history.peek();
if (activeSpliceLink) {
// TODO: DRY - droppable/nodeMouseDown/canvasMouseUp
@ -3078,6 +3185,18 @@ RED.view = (function() {
activeHoverGroup = null;
}
if (mouse_mode == RED.state.DETACHED_DRAGGING) {
var ns = [];
for (var j=0;j<movingSet.length();j++) {
var n = movingSet.get(j);
if (n.ox !== n.n.x || n.oy !== n.n.y) {
ns.push({n:n.n,ox:n.ox,oy:n.oy,moved:n.n.moved});
n.n.dirty = true;
n.n.moved = true;
}
}
RED.history.replace({t:"multi",events:[historyEvent,{t:"move",nodes:ns}],dirty: historyEvent.dirty})
}
updateSelection();
RED.nodes.dirty(true);