mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
[groups] Add undo support for group actions
This commit is contained in:
parent
0ef3471f8f
commit
7886e5d57c
@ -278,6 +278,13 @@ RED.history = (function() {
|
||||
RED.nodes.addLink(ev.removedLinks[i]);
|
||||
}
|
||||
}
|
||||
if (ev.addToGroup) {
|
||||
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }));
|
||||
inverseEv.removeFromGroup = ev.addToGroup;
|
||||
} else if (ev.removeFromGroup) {
|
||||
RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n }));
|
||||
inverseEv.addToGroup = ev.removeFromGroup;
|
||||
}
|
||||
} else if (ev.t == "edit") {
|
||||
inverseEv = {
|
||||
t: "edit",
|
||||
@ -469,7 +476,52 @@ RED.history = (function() {
|
||||
RED.workspaces.order(ev.order);
|
||||
}
|
||||
} else if (ev.t == "createGroup") {
|
||||
|
||||
inverseEv = {
|
||||
t: "ungroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
groups: []
|
||||
}
|
||||
if (ev.groups) {
|
||||
for (i=0;i<ev.groups.length;i++) {
|
||||
inverseEv.groups.push(ev.groups[i]);
|
||||
RED.group.ungroup(ev.groups[i]);
|
||||
}
|
||||
}
|
||||
} else if (ev.t == "ungroup") {
|
||||
inverseEv = {
|
||||
t: "createGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
groups: []
|
||||
}
|
||||
if (ev.groups) {
|
||||
for (i=0;i<ev.groups.length;i++) {
|
||||
inverseEv.groups.push(ev.groups[i]);
|
||||
var nodes = ev.groups[i].nodes.slice();
|
||||
ev.groups[i].nodes = [];
|
||||
RED.nodes.addGroup(ev.groups[i]);
|
||||
RED.group.addToGroup(ev.groups[i],nodes);
|
||||
}
|
||||
}
|
||||
} else if (ev.t == "addToGroup") {
|
||||
inverse = {
|
||||
t: "removeFromGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
group: ev.group,
|
||||
nodes: ev.nodes
|
||||
}
|
||||
if (ev.nodes) {
|
||||
RED.group.removeFromGroup(ev.group,ev.nodes);
|
||||
}
|
||||
} else if (ev.t == "removeFromGroup") {
|
||||
inverse = {
|
||||
t: "addToGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
group: ev.group,
|
||||
nodes: ev.nodes
|
||||
}
|
||||
if (ev.nodes) {
|
||||
RED.group.addToGroup(ev.group,ev.nodes);
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(modifiedTabs).forEach(function(id) {
|
||||
|
@ -343,6 +343,7 @@ RED.nodes = (function() {
|
||||
|
||||
var removedNodes = [];
|
||||
var removedLinks = [];
|
||||
var removedGroups = [];
|
||||
var n;
|
||||
var node;
|
||||
for (n=0;n<nodes.length;n++) {
|
||||
@ -359,11 +360,14 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
removedGroups = groupsByZ[id] || [];
|
||||
delete groupsByZ[id];
|
||||
|
||||
for (n=0;n<removedNodes.length;n++) {
|
||||
var result = removeNode(removedNodes[n].id);
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
}
|
||||
return {nodes:removedNodes,links:removedLinks};
|
||||
return {nodes:removedNodes,links:removedLinks, groups: removedGroups};
|
||||
}
|
||||
|
||||
function addSubflow(sf, createNewIds) {
|
||||
|
@ -74,7 +74,14 @@ RED.group = (function() {
|
||||
if (selection.nodes) {
|
||||
var group = createGroup(selection.nodes);
|
||||
if (group) {
|
||||
RED.view.select({nodes:[group]})
|
||||
var historyEvent = {
|
||||
t:"createGroup",
|
||||
groups: [ group ],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:[group]});
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,10 +90,22 @@ RED.group = (function() {
|
||||
if (selection.nodes) {
|
||||
var newSelection = [];
|
||||
groups = selection.nodes.filter(function(n) { return n.type === "group" });
|
||||
|
||||
var historyEvent = {
|
||||
t:"ungroup",
|
||||
groups: [ ],
|
||||
dirty: RED.nodes.dirty()
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
|
||||
|
||||
groups.forEach(function(g) {
|
||||
newSelection = newSelection.concat(ungroup(g))
|
||||
historyEvent.groups.push(g);
|
||||
})
|
||||
RED.history.push(historyEvent);
|
||||
RED.view.select({nodes:newSelection})
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,6 +134,17 @@ RED.group = (function() {
|
||||
var selection = RED.view.selection();
|
||||
if (selection.nodes) {
|
||||
var nodes = [];
|
||||
|
||||
var historyEvent = {
|
||||
t: "multi",
|
||||
events: []
|
||||
}
|
||||
var ungroupHistoryEvent = {
|
||||
t: "ungroup",
|
||||
groups: []
|
||||
}
|
||||
|
||||
|
||||
var n;
|
||||
var parentGroup;
|
||||
// First pass, check they are all in the same parent
|
||||
@ -133,18 +163,28 @@ RED.group = (function() {
|
||||
for (var i=0; i<selection.nodes.length; i++) {
|
||||
n = selection.nodes[i];
|
||||
if (n.type === "group") {
|
||||
ungroupHistoryEvent.groups.push(n);
|
||||
nodes = nodes.concat(ungroup(n));
|
||||
} else {
|
||||
nodes.push(n);
|
||||
}
|
||||
n.dirty = true;
|
||||
}
|
||||
if (ungroupHistoryEvent.groups.length > 0) {
|
||||
historyEvent.events.push(ungroupHistoryEvent);
|
||||
}
|
||||
// Finally, create the new group
|
||||
var group = createGroup(nodes);
|
||||
if (group) {
|
||||
RED.view.select({nodes:[group]})
|
||||
}
|
||||
|
||||
historyEvent.events.push({
|
||||
t:"createGroup",
|
||||
groups: [ group ],
|
||||
dirty: RED.nodes.dirty()
|
||||
});
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,37 +193,24 @@ RED.group = (function() {
|
||||
if (selection.nodes) {
|
||||
var nodes = [];
|
||||
var n;
|
||||
var parentGroup;
|
||||
// First pass, check they are all in the same parent
|
||||
// TODO: DRY mergeSelection,removeSelection,...
|
||||
for (var i=0; i<selection.nodes.length; i++) {
|
||||
n = selection.nodes[i];
|
||||
if (i === 0) {
|
||||
parentGroup = n.g;
|
||||
} else if (n.g !== parentGroup) {
|
||||
RED.notify("Cannot merge nodes from different groups","error");
|
||||
var parentGroup = RED.nodes.group(selection.nodes[0].g);
|
||||
if (parentGroup) {
|
||||
try {
|
||||
removeFromGroup(parentGroup,selection.nodes);
|
||||
var historyEvent = {
|
||||
t: "removeFromGroup",
|
||||
dirty: RED.nodes.dirty(),
|
||||
group: parentGroup,
|
||||
nodes: selection.nodes
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
} catch(err) {
|
||||
RED.notify(err,"error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (parentGroup) {
|
||||
parentGroup = RED.nodes.group(parentGroup);
|
||||
var grandparentGroup = RED.nodes.group(parentGroup.g);
|
||||
for (var i=0; i<selection.nodes.length; i++) {
|
||||
n = selection.nodes[i];
|
||||
n.dirty = true;
|
||||
nodes.push(n);
|
||||
var index = parentGroup.nodes.indexOf(n);
|
||||
parentGroup.nodes.splice(index,1);
|
||||
if (parentGroup.g) {
|
||||
n.g = parentGroup.g
|
||||
grandparentGroup.nodes.push(n);
|
||||
grandparentGroup.dirty = true;
|
||||
} else {
|
||||
delete n.g;
|
||||
}
|
||||
}
|
||||
RED.view.select({nodes:nodes})
|
||||
}
|
||||
RED.view.select({nodes:selection.nodes})
|
||||
}
|
||||
}
|
||||
function createGroup(nodes) {
|
||||
@ -217,7 +244,6 @@ RED.group = (function() {
|
||||
RED.nodes.addGroup(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
function addToGroup(group,nodes) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
nodes = [nodes];
|
||||
@ -274,6 +300,37 @@ RED.group = (function() {
|
||||
group.h = Math.max(group.h,n.y+n.h/2+25-group.y);
|
||||
}
|
||||
}
|
||||
function removeFromGroup(group, nodes) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
nodes = [nodes];
|
||||
}
|
||||
var n;
|
||||
// First pass, check they are all in the same parent
|
||||
// TODO: DRY mergeSelection,removeSelection,...
|
||||
for (var i=0; i<nodes.length; i++) {
|
||||
if (nodes[i].g !== group.id) {
|
||||
RED.notify("Cannot remove node "+nodes[i].id+" from group it isn't in");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var parentGroup = RED.nodes.group(group.g);
|
||||
for (var i=0; i<nodes.length; i++) {
|
||||
n = nodes[i];
|
||||
n.dirty = true;
|
||||
var index = group.nodes.indexOf(n);
|
||||
group.nodes.splice(index,1);
|
||||
group.dirty = true;
|
||||
if (group.g) {
|
||||
n.g = group.g
|
||||
parentGroup.nodes.push(n);
|
||||
parentGroup.dirty = true;
|
||||
} else {
|
||||
delete n.g;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getNodes(group,recursive) {
|
||||
var nodes = [];
|
||||
@ -312,7 +369,9 @@ RED.group = (function() {
|
||||
def: groupDef,
|
||||
init: init,
|
||||
createGroup: createGroup,
|
||||
ungroup: ungroup,
|
||||
addToGroup: addToGroup,
|
||||
removeFromGroup: removeFromGroup,
|
||||
getNodes: getNodes,
|
||||
contains: groupContains
|
||||
}
|
||||
|
@ -1008,6 +1008,17 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseDown", mouse_mode); }
|
||||
}
|
||||
if (targetGroup) {
|
||||
RED.group.addToGroup(targetGroup, nn);
|
||||
if (historyEvent.t !== "multi") {
|
||||
historyEvent = {
|
||||
t:'multi',
|
||||
events: [historyEvent]
|
||||
}
|
||||
}
|
||||
historyEvent.events.push({
|
||||
t: "addToGroup",
|
||||
group: targetGroup,
|
||||
nodes: nn
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@ -1482,11 +1493,14 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
||||
}
|
||||
if (mouse_mode == RED.state.MOVING_ACTIVE) {
|
||||
if (moving_set.length > 0) {
|
||||
var addedToGroup = null;
|
||||
if (activeHoverGroup) {
|
||||
for (var j=0;j<moving_set.length;j++) {
|
||||
var n = moving_set[j];
|
||||
RED.group.addToGroup(activeHoverGroup,n.n);
|
||||
}
|
||||
addedToGroup = activeHoverGroup;
|
||||
|
||||
activeHoverGroup.hovered = false;
|
||||
activeHoverGroup.dirty = true;
|
||||
activeHoverGroup.active = true;
|
||||
@ -1527,6 +1541,9 @@ if (DEBUG_EVENTS) { console.warn("canvasMouseUp", mouse_mode); }
|
||||
historyEvent.removedLinks = [spliceLink];
|
||||
updateActiveNodes();
|
||||
}
|
||||
if (addedToGroup) {
|
||||
historyEvent.addToGroup = addedToGroup;
|
||||
}
|
||||
RED.nodes.dirty(true);
|
||||
RED.history.push(historyEvent);
|
||||
}
|
||||
@ -1813,6 +1830,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
dirty: RED.nodes.dirty(),
|
||||
nodes: [],
|
||||
links: [],
|
||||
groups: [],
|
||||
workspaces: [],
|
||||
subflows: []
|
||||
}
|
||||
@ -1832,6 +1850,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
}
|
||||
historyEvent.nodes = historyEvent.nodes.concat(subEvent.nodes);
|
||||
historyEvent.links = historyEvent.links.concat(subEvent.links);
|
||||
historyEvent.groups = historyEvent.groups.concat(subEvent.groups);
|
||||
}
|
||||
RED.history.push(historyEvent);
|
||||
RED.nodes.dirty(true);
|
||||
@ -1842,9 +1861,9 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
var result;
|
||||
var removedNodes = [];
|
||||
var removedLinks = [];
|
||||
var removedGroups = [];
|
||||
var removedSubflowOutputs = [];
|
||||
var removedSubflowInputs = [];
|
||||
var removedGroups = [];
|
||||
var removedSubflowStatus;
|
||||
var subflowInstances = [];
|
||||
|
||||
@ -1911,7 +1930,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
subflowInstances = instances.instances;
|
||||
}
|
||||
moving_set = [];
|
||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus) {
|
||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus || removedGroups.length > 0) {
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
@ -1964,6 +1983,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
t:"delete",
|
||||
nodes:removedNodes,
|
||||
links:removedLinks,
|
||||
groups: removedGroups,
|
||||
subflowOutputs:removedSubflowOutputs,
|
||||
subflowInputs:removedSubflowInputs,
|
||||
subflow: {
|
||||
@ -2005,7 +2025,9 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
}
|
||||
var groups = activeGroups.filter(function(g) { return g.selected && !g.active });
|
||||
while (groups.length > 0) {
|
||||
console.log("GROUPS",groups.slice())
|
||||
var group = groups.shift();
|
||||
console.log("GROUP",group);
|
||||
nodes.push(group);
|
||||
groups = groups.concat(group.nodes.filter(function(n) { return n.type === "group" }))
|
||||
}
|
||||
@ -2033,7 +2055,7 @@ if (DEBUG_EVENTS) { console.warn("clearSelection", mouse_mode); }
|
||||
}
|
||||
}
|
||||
clipboard = JSON.stringify(nns);
|
||||
console.log(nns);
|
||||
console.warn(nns);
|
||||
RED.notify(RED._("clipboard.nodeCopied",{count:nns.length}),{id:"clipboard"});
|
||||
}
|
||||
}
|
||||
@ -4486,6 +4508,7 @@ if (DEBUG_EVENTS) { console.warn("nodeMouseDown", mouse_mode,d); }
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getGroupAtPoint: getGroupAt,
|
||||
reveal: function(id) {
|
||||
if (RED.nodes.workspace(id) || RED.nodes.subflow(id)) {
|
||||
RED.workspaces.show(id);
|
||||
|
Loading…
Reference in New Issue
Block a user