mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
c061487a16
This is a slightly scary set of changes to be making. It overhauls how the view is rendered. Rather than use d3 for every single part of generating the view, we new use native DOM functions as much as possible. d3 is still used for the basic heavy lifting of working out what nodes/links etc need to be added/removed from the view. But once it comes to rendering them, d3 is side-lined as much as possible. There's room for further improvement. This change focusses on Nodes and Links. It has not touched groups, subflow-ports and link-nodes.
651 lines
28 KiB
JavaScript
651 lines
28 KiB
JavaScript
/**
|
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
**/
|
|
RED.history = (function() {
|
|
var undoHistory = [];
|
|
var redoHistory = [];
|
|
|
|
function undoEvent(ev) {
|
|
var i;
|
|
var len;
|
|
var node;
|
|
var group;
|
|
var subflow;
|
|
var modifiedTabs = {};
|
|
var inverseEv;
|
|
if (ev) {
|
|
if (ev.t == 'multi') {
|
|
inverseEv = {
|
|
t: 'multi',
|
|
events: []
|
|
};
|
|
len = ev.events.length;
|
|
for (i=len-1;i>=0;i--) {
|
|
var r = undoEvent(ev.events[i]);
|
|
inverseEv.events.push(r);
|
|
}
|
|
} else if (ev.t == 'replace') {
|
|
inverseEv = {
|
|
t: 'replace',
|
|
config: RED.nodes.createCompleteNodeSet(),
|
|
changed: {},
|
|
rev: RED.nodes.version()
|
|
};
|
|
RED.nodes.clear();
|
|
var imported = RED.nodes.import(ev.config);
|
|
imported[0].forEach(function(n) {
|
|
if (ev.changed[n.id]) {
|
|
n.changed = true;
|
|
inverseEv.changed[n.id] = true;
|
|
}
|
|
})
|
|
|
|
RED.nodes.version(ev.rev);
|
|
} else if (ev.t == 'add') {
|
|
inverseEv = {
|
|
t: "delete",
|
|
};
|
|
if (ev.nodes) {
|
|
inverseEv.nodes = [];
|
|
for (i=0;i<ev.nodes.length;i++) {
|
|
node = RED.nodes.node(ev.nodes[i]);
|
|
if (node.z) {
|
|
modifiedTabs[node.z] = true;
|
|
}
|
|
inverseEv.nodes.push(node);
|
|
RED.nodes.remove(ev.nodes[i]);
|
|
if (node.g) {
|
|
var group = RED.nodes.group(node.g);
|
|
var index = group.nodes.indexOf(node);
|
|
if (index !== -1) {
|
|
group.nodes.splice(index,1);
|
|
RED.group.markDirty(group);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ev.links) {
|
|
inverseEv.links = [];
|
|
for (i=0;i<ev.links.length;i++) {
|
|
inverseEv.links.push(ev.links[i]);
|
|
RED.nodes.removeLink(ev.links[i]);
|
|
}
|
|
}
|
|
if (ev.groups) {
|
|
inverseEv.groups = [];
|
|
for (i=0;i<ev.groups.length;i++) {
|
|
group = ev.groups[i];
|
|
modifiedTabs[group.z] = true;
|
|
// The order of groups is important
|
|
// - to invert the action, the order is reversed
|
|
inverseEv.groups.unshift(group);
|
|
RED.nodes.removeGroup(group);
|
|
}
|
|
}
|
|
if (ev.workspaces) {
|
|
inverseEv.workspaces = [];
|
|
for (i=0;i<ev.workspaces.length;i++) {
|
|
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
|
ev.workspaces[i]._index = workspaceOrder.indexOf(ev.workspaces[i].id);
|
|
inverseEv.workspaces.push(ev.workspaces[i]);
|
|
RED.nodes.removeWorkspace(ev.workspaces[i].id);
|
|
RED.workspaces.remove(ev.workspaces[i]);
|
|
}
|
|
}
|
|
if (ev.subflows) {
|
|
inverseEv.subflows = [];
|
|
for (i=0;i<ev.subflows.length;i++) {
|
|
inverseEv.subflows.push(ev.subflows[i]);
|
|
RED.nodes.removeSubflow(ev.subflows[i]);
|
|
RED.workspaces.remove(ev.subflows[i]);
|
|
}
|
|
}
|
|
if (ev.subflow) {
|
|
inverseEv.subflow = {};
|
|
if (ev.subflow.instances) {
|
|
inverseEv.subflow.instances = [];
|
|
ev.subflow.instances.forEach(function(n) {
|
|
inverseEv.subflow.instances.push(n);
|
|
var node = RED.nodes.node(n.id);
|
|
if (node) {
|
|
node.changed = n.changed;
|
|
node.dirty = true;
|
|
}
|
|
});
|
|
}
|
|
if (ev.subflow.hasOwnProperty('changed')) {
|
|
subflow = RED.nodes.subflow(ev.subflow.id);
|
|
if (subflow) {
|
|
subflow.changed = ev.subflow.changed;
|
|
}
|
|
}
|
|
}
|
|
if (ev.removedLinks) {
|
|
inverseEv.createdLinks = [];
|
|
for (i=0;i<ev.removedLinks.length;i++) {
|
|
inverseEv.createdLinks.push(ev.removedLinks[i]);
|
|
RED.nodes.addLink(ev.removedLinks[i]);
|
|
}
|
|
}
|
|
|
|
} else if (ev.t == "delete") {
|
|
inverseEv = {
|
|
t: "add"
|
|
};
|
|
if (ev.workspaces) {
|
|
inverseEv.workspaces = [];
|
|
for (i=0;i<ev.workspaces.length;i++) {
|
|
inverseEv.workspaces.push(ev.workspaces[i]);
|
|
RED.nodes.addWorkspace(ev.workspaces[i],ev.workspaces[i]._index);
|
|
RED.workspaces.add(ev.workspaces[i],undefined,ev.workspaces[i]._index);
|
|
delete ev.workspaces[i]._index;
|
|
}
|
|
}
|
|
if (ev.subflows) {
|
|
inverseEv.subflows = [];
|
|
for (i=0;i<ev.subflows.length;i++) {
|
|
inverseEv.subflows.push(ev.subflows[i]);
|
|
RED.nodes.addSubflow(ev.subflows[i]);
|
|
}
|
|
}
|
|
if (ev.subflowInputs && ev.subflowInputs.length > 0) {
|
|
subflow = RED.nodes.subflow(ev.subflowInputs[0].z);
|
|
subflow.in.push(ev.subflowInputs[0]);
|
|
subflow.in[0].dirty = true;
|
|
}
|
|
if (ev.subflowOutputs && ev.subflowOutputs.length > 0) {
|
|
subflow = RED.nodes.subflow(ev.subflowOutputs[0].z);
|
|
ev.subflowOutputs.sort(function(a,b) { return a.i-b.i});
|
|
for (i=0;i<ev.subflowOutputs.length;i++) {
|
|
var output = ev.subflowOutputs[i];
|
|
subflow.out.splice(output.i,0,output);
|
|
for (var j=output.i+1;j<subflow.out.length;j++) {
|
|
subflow.out[j].i++;
|
|
subflow.out[j].dirty = true;
|
|
}
|
|
RED.nodes.eachLink(function(l) {
|
|
if (l.source.type == "subflow:"+subflow.id) {
|
|
if (l.sourcePort >= output.i) {
|
|
l.sourcePort++;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
if (ev.subflow) {
|
|
inverseEv.subflow = {};
|
|
if (ev.subflow.hasOwnProperty('instances')) {
|
|
inverseEv.subflow.instances = [];
|
|
ev.subflow.instances.forEach(function(n) {
|
|
inverseEv.subflow.instances.push(n);
|
|
var node = RED.nodes.node(n.id);
|
|
if (node) {
|
|
node.changed = n.changed;
|
|
node.dirty = true;
|
|
}
|
|
});
|
|
}
|
|
if (ev.subflow.hasOwnProperty('status')) {
|
|
subflow = RED.nodes.subflow(ev.subflow.id);
|
|
subflow.status = ev.subflow.status;
|
|
}
|
|
}
|
|
if (subflow) {
|
|
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
|
|
n.inputs = subflow.in.length;
|
|
n.outputs = subflow.out.length;
|
|
n.resize = true;
|
|
n.dirty = true;
|
|
});
|
|
}
|
|
if (ev.groups) {
|
|
inverseEv.groups = [];
|
|
var groupsToAdd = {};
|
|
ev.groups.forEach(function(g) { groupsToAdd[g.id] = g; });
|
|
for (i=0;i<ev.groups.length;i++) {
|
|
RED.nodes.addGroup(ev.groups[i])
|
|
modifiedTabs[ev.groups[i].z] = true;
|
|
// The order of groups is important
|
|
// - to invert the action, the order is reversed
|
|
inverseEv.groups.unshift(ev.groups[i]);
|
|
if (ev.groups[i].g) {
|
|
if (!groupsToAdd[ev.groups[i].g]) {
|
|
group = RED.nodes.group(ev.groups[i].g);
|
|
} else {
|
|
group = groupsToAdd[ev.groups[i].g];
|
|
}
|
|
if (group.nodes.indexOf(ev.groups[i]) === -1) {
|
|
group.nodes.push(ev.groups[i]);
|
|
}
|
|
RED.group.markDirty(ev.groups[i])
|
|
}
|
|
}
|
|
}
|
|
if (ev.nodes) {
|
|
inverseEv.nodes = [];
|
|
for (i=0;i<ev.nodes.length;i++) {
|
|
RED.nodes.add(ev.nodes[i]);
|
|
modifiedTabs[ev.nodes[i].z] = true;
|
|
inverseEv.nodes.push(ev.nodes[i].id);
|
|
if (ev.nodes[i].g) {
|
|
group = RED.nodes.group(ev.nodes[i].g);
|
|
if (group.nodes.indexOf(ev.nodes[i]) === -1) {
|
|
group.nodes.push(ev.nodes[i]);
|
|
}
|
|
RED.group.markDirty(group)
|
|
}
|
|
}
|
|
}
|
|
if (ev.links) {
|
|
inverseEv.links = [];
|
|
for (i=0;i<ev.links.length;i++) {
|
|
RED.nodes.addLink(ev.links[i]);
|
|
inverseEv.links.push(ev.links[i]);
|
|
}
|
|
}
|
|
if (ev.createdLinks) {
|
|
inverseEv.removedLinks = [];
|
|
for (i=0;i<ev.createdLinks.length;i++) {
|
|
inverseEv.removedLinks.push(ev.createdLinks[i]);
|
|
RED.nodes.removeLink(ev.createdLinks[i]);
|
|
}
|
|
}
|
|
if (ev.changes) {
|
|
for (i in ev.changes) {
|
|
if (ev.changes.hasOwnProperty(i)) {
|
|
node = RED.nodes.node(i);
|
|
if (node) {
|
|
for (var d in ev.changes[i]) {
|
|
if (ev.changes[i].hasOwnProperty(d)) {
|
|
node[d] = ev.changes[i][d];
|
|
}
|
|
}
|
|
node.dirty = true;
|
|
}
|
|
RED.events.emit("nodes:change",node);
|
|
}
|
|
}
|
|
}
|
|
if (subflow) {
|
|
RED.events.emit("subflows:change", subflow);
|
|
}
|
|
} else if (ev.t == "move") {
|
|
inverseEv = {
|
|
t: 'move',
|
|
nodes: []
|
|
};
|
|
for (i=0;i<ev.nodes.length;i++) {
|
|
var n = ev.nodes[i];
|
|
var rn = {n: n.n, ox: n.n.x, oy: n.n.y, dirty: true, moved: n.moved};
|
|
inverseEv.nodes.push(rn);
|
|
n.n.x = n.ox;
|
|
n.n.y = n.oy;
|
|
n.n.dirty = true;
|
|
n.n.moved = n.moved;
|
|
}
|
|
// A move could have caused a link splice
|
|
if (ev.links) {
|
|
inverseEv.removedLinks = [];
|
|
for (i=0;i<ev.links.length;i++) {
|
|
inverseEv.removedLinks.push(ev.links[i]);
|
|
RED.nodes.removeLink(ev.links[i]);
|
|
}
|
|
}
|
|
if (ev.removedLinks) {
|
|
inverseEv.links = [];
|
|
for (i=0;i<ev.removedLinks.length;i++) {
|
|
inverseEv.links.push(ev.removedLinks[i]);
|
|
RED.nodes.addLink(ev.removedLinks[i]);
|
|
}
|
|
}
|
|
if (ev.addToGroup) {
|
|
RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false);
|
|
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",
|
|
changes: {}
|
|
};
|
|
inverseEv.node = ev.node;
|
|
for (i in ev.changes) {
|
|
if (ev.changes.hasOwnProperty(i)) {
|
|
inverseEv.changes[i] = ev.node[i];
|
|
if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
|
|
// This is a config node property
|
|
var currentConfigNode = RED.nodes.node(ev.node[i]);
|
|
if (currentConfigNode) {
|
|
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
|
|
}
|
|
var newConfigNode = RED.nodes.node(ev.changes[i]);
|
|
if (newConfigNode) {
|
|
newConfigNode.users.push(ev.node);
|
|
}
|
|
}
|
|
ev.node[i] = ev.changes[i];
|
|
}
|
|
}
|
|
var eventType;
|
|
switch(ev.node.type) {
|
|
case 'tab': eventType = "flows"; break;
|
|
case 'group': eventType = "groups"; break;
|
|
case 'subflow': eventType = "subflows"; break;
|
|
default: eventType = "nodes"; break;
|
|
}
|
|
eventType += ":change";
|
|
RED.events.emit(eventType,ev.node);
|
|
|
|
|
|
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.subflow) {
|
|
inverseEv.subflow = {};
|
|
if (ev.subflow.hasOwnProperty('inputCount')) {
|
|
inverseEv.subflow.inputCount = ev.node.in.length;
|
|
if (ev.node.in.length > ev.subflow.inputCount) {
|
|
inverseEv.subflow.inputs = ev.node.in.slice(ev.subflow.inputCount);
|
|
ev.node.in.splice(ev.subflow.inputCount);
|
|
} else if (ev.subflow.inputs.length > 0) {
|
|
ev.node.in = ev.node.in.concat(ev.subflow.inputs);
|
|
}
|
|
}
|
|
if (ev.subflow.hasOwnProperty('outputCount')) {
|
|
inverseEv.subflow.outputCount = ev.node.out.length;
|
|
if (ev.node.out.length > ev.subflow.outputCount) {
|
|
inverseEv.subflow.outputs = ev.node.out.slice(ev.subflow.outputCount);
|
|
ev.node.out.splice(ev.subflow.outputCount);
|
|
} else if (ev.subflow.outputs.length > 0) {
|
|
ev.node.out = ev.node.out.concat(ev.subflow.outputs);
|
|
}
|
|
}
|
|
if (ev.subflow.hasOwnProperty('instances')) {
|
|
inverseEv.subflow.instances = [];
|
|
ev.subflow.instances.forEach(function(n) {
|
|
inverseEv.subflow.instances.push(n);
|
|
var node = RED.nodes.node(n.id);
|
|
if (node) {
|
|
node.changed = n.changed;
|
|
node.dirty = true;
|
|
}
|
|
});
|
|
}
|
|
if (ev.subflow.hasOwnProperty('status')) {
|
|
if (ev.subflow.status) {
|
|
delete ev.node.status;
|
|
}
|
|
}
|
|
RED.editor.validateNode(ev.node);
|
|
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
|
n.inputs = ev.node.in.length;
|
|
n.outputs = ev.node.out.length;
|
|
RED.editor.updateNodeProperties(n);
|
|
RED.editor.validateNode(n);
|
|
});
|
|
} else {
|
|
var outputMap;
|
|
if (ev.outputMap) {
|
|
outputMap = {};
|
|
inverseEv.outputMap = {};
|
|
for (var port in ev.outputMap) {
|
|
if (ev.outputMap.hasOwnProperty(port) && ev.outputMap[port] !== "-1") {
|
|
outputMap[ev.outputMap[port]] = port;
|
|
inverseEv.outputMap[ev.outputMap[port]] = port;
|
|
}
|
|
}
|
|
}
|
|
ev.node.__outputs = inverseEv.changes.outputs;
|
|
RED.editor.updateNodeProperties(ev.node,outputMap);
|
|
RED.editor.validateNode(ev.node);
|
|
}
|
|
if (ev.links) {
|
|
inverseEv.createdLinks = [];
|
|
for (i=0;i<ev.links.length;i++) {
|
|
RED.nodes.addLink(ev.links[i]);
|
|
inverseEv.createdLinks.push(ev.links[i]);
|
|
}
|
|
}
|
|
if (ev.createdLinks) {
|
|
inverseEv.links = [];
|
|
for (i=0;i<ev.createdLinks.length;i++) {
|
|
RED.nodes.removeLink(ev.createdLinks[i]);
|
|
inverseEv.links.push(ev.createdLinks[i]);
|
|
}
|
|
}
|
|
ev.node.dirty = true;
|
|
ev.node.changed = ev.changed;
|
|
} else if (ev.t == "createSubflow") {
|
|
inverseEv = {
|
|
t: "deleteSubflow",
|
|
activeWorkspace: ev.activeWorkspace,
|
|
dirty: RED.nodes.dirty()
|
|
};
|
|
if (ev.nodes) {
|
|
inverseEv.movedNodes = [];
|
|
var z = ev.activeWorkspace;
|
|
var fullNodeList = RED.nodes.filterNodes({z:ev.subflow.subflow.id});
|
|
fullNodeList = fullNodeList.concat(RED.nodes.groups(ev.subflow.subflow.id))
|
|
fullNodeList.forEach(function(n) {
|
|
n.x += ev.subflow.offsetX;
|
|
n.y += ev.subflow.offsetY;
|
|
n.dirty = true;
|
|
inverseEv.movedNodes.push(n.id);
|
|
RED.nodes.moveNodeToTab(n, z);
|
|
});
|
|
inverseEv.subflows = [];
|
|
for (i=0;i<ev.nodes.length;i++) {
|
|
inverseEv.subflows.push(RED.nodes.node(ev.nodes[i]));
|
|
RED.nodes.remove(ev.nodes[i]);
|
|
}
|
|
}
|
|
if (ev.links) {
|
|
inverseEv.links = [];
|
|
for (i=0;i<ev.links.length;i++) {
|
|
inverseEv.links.push(ev.links[i]);
|
|
RED.nodes.removeLink(ev.links[i]);
|
|
}
|
|
}
|
|
|
|
inverseEv.subflow = ev.subflow;
|
|
RED.nodes.removeSubflow(ev.subflow.subflow);
|
|
RED.workspaces.remove(ev.subflow.subflow);
|
|
|
|
if (ev.removedLinks) {
|
|
inverseEv.createdLinks = [];
|
|
for (i=0;i<ev.removedLinks.length;i++) {
|
|
inverseEv.createdLinks.push(ev.removedLinks[i]);
|
|
RED.nodes.addLink(ev.removedLinks[i]);
|
|
}
|
|
}
|
|
} else if (ev.t == "deleteSubflow") {
|
|
inverseEv = {
|
|
t: "createSubflow",
|
|
activeWorkspace: ev.activeWorkspace,
|
|
dirty: RED.nodes.dirty(),
|
|
};
|
|
if (ev.subflow) {
|
|
RED.nodes.addSubflow(ev.subflow.subflow);
|
|
inverseEv.subflow = ev.subflow;
|
|
if (ev.subflow.subflow.g) {
|
|
RED.group.addToGroup(RED.nodes.group(ev.subflow.subflow.g),ev.subflow.subflow);
|
|
}
|
|
}
|
|
if (ev.subflows) {
|
|
inverseEv.nodes = [];
|
|
for (i=0;i<ev.subflows.length;i++) {
|
|
RED.nodes.add(ev.subflows[i]);
|
|
inverseEv.nodes.push(ev.subflows[i].id);
|
|
}
|
|
}
|
|
if (ev.movedNodes) {
|
|
ev.movedNodes.forEach(function(nid) {
|
|
nn = RED.nodes.node(nid);
|
|
if (!nn) {
|
|
nn = RED.nodes.group(nid);
|
|
}
|
|
nn.x -= ev.subflow.offsetX;
|
|
nn.y -= ev.subflow.offsetY;
|
|
nn.dirty = true;
|
|
RED.nodes.moveNodeToTab(nn, ev.subflow.subflow.id);
|
|
});
|
|
}
|
|
if (ev.links) {
|
|
inverseEv.links = [];
|
|
for (i=0;i<ev.links.length;i++) {
|
|
inverseEv.links.push(ev.links[i]);
|
|
RED.nodes.addLink(ev.links[i]);
|
|
}
|
|
}
|
|
if (ev.createdLinks) {
|
|
inverseEv.removedLinks = [];
|
|
for (i=0;i<ev.createdLinks.length;i++) {
|
|
inverseEv.removedLinks.push(ev.createdLinks[i]);
|
|
RED.nodes.removeLink(ev.createdLinks[i]);
|
|
}
|
|
}
|
|
} else if (ev.t == "reorder") {
|
|
inverseEv = {
|
|
t: 'reorder',
|
|
order: RED.nodes.getWorkspaceOrder()
|
|
};
|
|
if (ev.order) {
|
|
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") {
|
|
inverseEv = {
|
|
t: "removeFromGroup",
|
|
dirty: RED.nodes.dirty(),
|
|
group: ev.group,
|
|
nodes: ev.nodes,
|
|
reparent: ev.reparent
|
|
}
|
|
if (ev.nodes) {
|
|
RED.group.removeFromGroup(ev.group,ev.nodes,(ev.hasOwnProperty('reparent')&&ev.hasOwnProperty('reparent')!==undefined)?ev.reparent:true);
|
|
}
|
|
} else if (ev.t == "removeFromGroup") {
|
|
inverseEv = {
|
|
t: "addToGroup",
|
|
dirty: RED.nodes.dirty(),
|
|
group: ev.group,
|
|
nodes: ev.nodes,
|
|
reparent: ev.reparent
|
|
}
|
|
if (ev.nodes) {
|
|
RED.group.addToGroup(ev.group,ev.nodes);
|
|
}
|
|
}
|
|
|
|
if(ev.callback && typeof ev.callback === 'function') {
|
|
inverseEv.callback = ev.callback;
|
|
ev.callback(ev);
|
|
}
|
|
|
|
Object.keys(modifiedTabs).forEach(function(id) {
|
|
var subflow = RED.nodes.subflow(id);
|
|
if (subflow) {
|
|
RED.editor.validateNode(subflow);
|
|
}
|
|
});
|
|
|
|
RED.nodes.dirty(ev.dirty);
|
|
RED.view.updateActive();
|
|
RED.view.select(null);
|
|
RED.workspaces.refresh();
|
|
RED.sidebar.config.refresh();
|
|
RED.subflow.refresh();
|
|
|
|
return inverseEv;
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
//TODO: this function is a placeholder until there is a 'save' event that can be listened to
|
|
markAllDirty: function() {
|
|
for (var i=0;i<undoHistory.length;i++) {
|
|
undoHistory[i].dirty = true;
|
|
}
|
|
},
|
|
list: function() {
|
|
return undoHistory;
|
|
},
|
|
listRedo: function() {
|
|
return redoHistory;
|
|
},
|
|
depth: function() {
|
|
return undoHistory.length;
|
|
},
|
|
push: function(ev) {
|
|
undoHistory.push(ev);
|
|
redoHistory = [];
|
|
},
|
|
pop: function() {
|
|
var ev = undoHistory.pop();
|
|
var rev = undoEvent(ev);
|
|
if (rev) {
|
|
redoHistory.push(rev);
|
|
}
|
|
},
|
|
peek: function() {
|
|
return undoHistory[undoHistory.length-1];
|
|
},
|
|
clear: function() {
|
|
undoHistory = [];
|
|
redoHistory = [];
|
|
},
|
|
redo: function() {
|
|
var ev = redoHistory.pop();
|
|
if (ev) {
|
|
var uev = undoEvent(ev);
|
|
if (uev) {
|
|
undoHistory.push(uev);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
})();
|