2013-09-05 16:02:48 +02:00
|
|
|
/**
|
2016-01-14 16:59:45 +01:00
|
|
|
* Copyright 2013, 2016 IBM Corp.
|
2013-09-05 16:02:48 +02:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
**/
|
2014-08-08 01:01:35 +02:00
|
|
|
RED.history = (function() {
|
2013-09-05 16:02:48 +02:00
|
|
|
var undo_history = [];
|
2015-07-30 12:03:37 +02:00
|
|
|
|
2013-09-05 16:02:48 +02:00
|
|
|
return {
|
|
|
|
//TODO: this function is a placeholder until there is a 'save' event that can be listened to
|
|
|
|
markAllDirty: function() {
|
2014-08-08 01:01:35 +02:00
|
|
|
for (var i=0;i<undo_history.length;i++) {
|
2013-09-05 16:02:48 +02:00
|
|
|
undo_history[i].dirty = true;
|
|
|
|
}
|
|
|
|
},
|
2016-03-17 12:12:45 +01:00
|
|
|
list: function() {
|
|
|
|
return undo_history
|
|
|
|
},
|
2014-05-15 23:49:07 +02:00
|
|
|
depth: function() {
|
|
|
|
return undo_history.length;
|
|
|
|
},
|
2013-09-05 16:02:48 +02:00
|
|
|
push: function(ev) {
|
|
|
|
undo_history.push(ev);
|
|
|
|
},
|
|
|
|
pop: function() {
|
|
|
|
var ev = undo_history.pop();
|
2014-08-08 01:01:35 +02:00
|
|
|
var i;
|
2015-03-20 00:11:55 +01:00
|
|
|
var node;
|
2015-08-13 23:18:47 +02:00
|
|
|
var subflow;
|
2015-03-20 00:11:55 +01:00
|
|
|
var modifiedTabs = {};
|
2013-09-05 16:02:48 +02:00
|
|
|
if (ev) {
|
|
|
|
if (ev.t == 'add') {
|
2014-08-20 18:05:01 +02:00
|
|
|
if (ev.nodes) {
|
|
|
|
for (i=0;i<ev.nodes.length;i++) {
|
2015-03-20 00:11:55 +01:00
|
|
|
node = RED.nodes.node(ev.nodes[i]);
|
|
|
|
if (node.z) {
|
|
|
|
modifiedTabs[node.z] = true;
|
|
|
|
}
|
2014-08-20 18:05:01 +02:00
|
|
|
RED.nodes.remove(ev.nodes[i]);
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
2014-08-20 18:05:01 +02:00
|
|
|
if (ev.links) {
|
|
|
|
for (i=0;i<ev.links.length;i++) {
|
|
|
|
RED.nodes.removeLink(ev.links[i]);
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
2014-08-20 18:05:01 +02:00
|
|
|
if (ev.workspaces) {
|
|
|
|
for (i=0;i<ev.workspaces.length;i++) {
|
|
|
|
RED.nodes.removeWorkspace(ev.workspaces[i].id);
|
2015-03-13 00:38:37 +01:00
|
|
|
RED.workspaces.remove(ev.workspaces[i]);
|
2014-08-20 18:05:01 +02:00
|
|
|
}
|
2013-10-27 21:42:42 +01:00
|
|
|
}
|
2014-02-25 00:35:11 +01:00
|
|
|
if (ev.subflows) {
|
|
|
|
for (i=0;i<ev.subflows.length;i++) {
|
|
|
|
RED.nodes.removeSubflow(ev.subflows[i]);
|
2015-03-13 00:38:37 +01:00
|
|
|
RED.workspaces.remove(ev.subflows[i]);
|
2014-02-25 00:35:11 +01:00
|
|
|
}
|
|
|
|
}
|
2015-07-30 12:03:37 +02:00
|
|
|
if (ev.subflow) {
|
|
|
|
if (ev.subflow.instances) {
|
|
|
|
ev.subflow.instances.forEach(function(n) {
|
|
|
|
var node = RED.nodes.node(n.id);
|
|
|
|
if (node) {
|
|
|
|
node.changed = n.changed;
|
|
|
|
node.dirty = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (ev.subflow.hasOwnProperty('changed')) {
|
2015-08-13 23:18:47 +02:00
|
|
|
subflow = RED.nodes.subflow(ev.subflow.id);
|
2015-07-30 12:03:37 +02:00
|
|
|
if (subflow) {
|
|
|
|
subflow.changed = ev.subflow.changed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-08 23:34:10 +01:00
|
|
|
if (ev.removedLinks) {
|
|
|
|
for (i=0;i<ev.removedLinks.length;i++) {
|
|
|
|
RED.nodes.addLink(ev.removedLinks[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-05 16:02:48 +02:00
|
|
|
} else if (ev.t == "delete") {
|
2014-08-20 18:05:01 +02:00
|
|
|
if (ev.workspaces) {
|
|
|
|
for (i=0;i<ev.workspaces.length;i++) {
|
|
|
|
RED.nodes.addWorkspace(ev.workspaces[i]);
|
2015-03-13 00:38:37 +01:00
|
|
|
RED.workspaces.add(ev.workspaces[i]);
|
2014-08-20 18:05:01 +02:00
|
|
|
}
|
2013-10-27 21:42:42 +01:00
|
|
|
}
|
2015-07-30 12:03:37 +02:00
|
|
|
if (ev.subflow && ev.subflow.subflow) {
|
|
|
|
RED.nodes.addSubflow(ev.subflow.subflow);
|
2014-02-25 00:35:11 +01:00
|
|
|
}
|
2014-11-13 01:02:41 +01:00
|
|
|
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;
|
|
|
|
}
|
2014-11-13 00:51:42 +01:00
|
|
|
if (ev.subflowOutputs && ev.subflowOutputs.length > 0) {
|
2014-11-13 01:02:41 +01:00
|
|
|
subflow = RED.nodes.subflow(ev.subflowOutputs[0].z);
|
2014-11-13 00:51:42 +01:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2014-11-13 01:02:41 +01:00
|
|
|
}
|
2015-07-30 12:03:37 +02:00
|
|
|
if (ev.subflow && ev.subflow.hasOwnProperty('instances')) {
|
|
|
|
ev.subflow.instances.forEach(function(n) {
|
|
|
|
var node = RED.nodes.node(n.id);
|
|
|
|
if (node) {
|
|
|
|
node.changed = n.changed;
|
|
|
|
node.dirty = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2014-11-13 01:02:41 +01:00
|
|
|
if (subflow) {
|
2015-03-20 00:11:55 +01:00
|
|
|
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
|
|
|
|
n.inputs = subflow.in.length;
|
|
|
|
n.outputs = subflow.out.length;
|
|
|
|
while (n.outputs > n.ports.length) {
|
|
|
|
n.ports.push(n.ports.length);
|
2014-11-13 00:51:42 +01:00
|
|
|
}
|
2015-03-20 00:11:55 +01:00
|
|
|
n.resize = true;
|
|
|
|
n.dirty = true;
|
2014-11-13 00:51:42 +01:00
|
|
|
});
|
|
|
|
}
|
2014-08-20 18:05:01 +02:00
|
|
|
if (ev.nodes) {
|
|
|
|
for (i=0;i<ev.nodes.length;i++) {
|
|
|
|
RED.nodes.add(ev.nodes[i]);
|
2015-03-20 00:11:55 +01:00
|
|
|
modifiedTabs[ev.nodes[i].z] = true;
|
2014-08-20 18:05:01 +02:00
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
2014-08-20 18:05:01 +02:00
|
|
|
if (ev.links) {
|
|
|
|
for (i=0;i<ev.links.length;i++) {
|
|
|
|
RED.nodes.addLink(ev.links[i]);
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
2015-09-25 22:49:53 +02:00
|
|
|
if (ev.changes) {
|
|
|
|
for (i in ev.changes) {
|
|
|
|
if (ev.changes.hasOwnProperty(i)) {
|
|
|
|
node = RED.nodes.node(i);
|
2015-09-28 11:15:47 +02:00
|
|
|
if (node) {
|
|
|
|
for (var d in ev.changes[i]) {
|
|
|
|
if (ev.changes[i].hasOwnProperty(d)) {
|
|
|
|
node[d] = ev.changes[i][d];
|
|
|
|
}
|
2015-09-25 22:49:53 +02:00
|
|
|
}
|
2015-09-28 11:15:47 +02:00
|
|
|
node.dirty = true;
|
2015-09-25 22:49:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
} else if (ev.t == "move") {
|
2014-08-08 01:01:35 +02:00
|
|
|
for (i=0;i<ev.nodes.length;i++) {
|
2013-09-05 16:02:48 +02:00
|
|
|
var n = ev.nodes[i];
|
|
|
|
n.n.x = n.ox;
|
|
|
|
n.n.y = n.oy;
|
|
|
|
n.n.dirty = true;
|
|
|
|
}
|
2016-01-14 16:59:45 +01:00
|
|
|
// A move could have caused a link splice
|
|
|
|
if (ev.links) {
|
|
|
|
for (i=0;i<ev.links.length;i++) {
|
|
|
|
RED.nodes.removeLink(ev.links[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ev.removedLinks) {
|
|
|
|
for (i=0;i<ev.removedLinks.length;i++) {
|
|
|
|
RED.nodes.addLink(ev.removedLinks[i]);
|
|
|
|
}
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
} else if (ev.t == "edit") {
|
2014-08-08 01:01:35 +02:00
|
|
|
for (i in ev.changes) {
|
|
|
|
if (ev.changes.hasOwnProperty(i)) {
|
2015-09-28 11:15:47 +02:00
|
|
|
if (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);
|
|
|
|
}
|
|
|
|
}
|
2014-08-08 01:01:35 +02:00
|
|
|
ev.node[i] = ev.changes[i];
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
2014-02-25 00:35:11 +01:00
|
|
|
if (ev.subflow) {
|
2014-11-13 13:59:28 +01:00
|
|
|
if (ev.subflow.hasOwnProperty('inputCount')) {
|
|
|
|
if (ev.node.in.length > 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);
|
|
|
|
}
|
2014-02-25 00:35:11 +01:00
|
|
|
}
|
2014-11-13 13:59:28 +01:00
|
|
|
if (ev.subflow.hasOwnProperty('outputCount')) {
|
|
|
|
if (ev.node.out.length > 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);
|
|
|
|
}
|
2014-02-25 00:35:11 +01:00
|
|
|
}
|
2015-07-30 12:03:37 +02:00
|
|
|
if (ev.subflow.hasOwnProperty('instances')) {
|
|
|
|
ev.subflow.instances.forEach(function(n) {
|
|
|
|
var node = RED.nodes.node(n.id);
|
|
|
|
if (node) {
|
|
|
|
node.changed = n.changed;
|
|
|
|
node.dirty = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2015-03-20 00:11:55 +01:00
|
|
|
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);
|
2014-02-25 00:35:11 +01:00
|
|
|
});
|
2015-07-30 12:03:37 +02:00
|
|
|
|
2015-09-23 18:00:37 +02:00
|
|
|
if (ev.node.type === 'subflow') {
|
2016-08-25 18:09:56 +02:00
|
|
|
$("#menu-item-workspace-menu-"+ev.node.id.replace(".","-")).text(RED.text.bidi.enforceTextDirectionWithUCC(ev.node.name));
|
2015-09-23 18:00:37 +02:00
|
|
|
}
|
2014-02-25 00:35:11 +01:00
|
|
|
} else {
|
|
|
|
RED.editor.updateNodeProperties(ev.node);
|
|
|
|
RED.editor.validateNode(ev.node);
|
|
|
|
}
|
2014-08-20 18:05:01 +02:00
|
|
|
if (ev.links) {
|
|
|
|
for (i=0;i<ev.links.length;i++) {
|
|
|
|
RED.nodes.addLink(ev.links[i]);
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
|
|
|
ev.node.dirty = true;
|
2013-12-19 22:34:25 +01:00
|
|
|
ev.node.changed = ev.changed;
|
2014-02-25 00:35:11 +01:00
|
|
|
} else if (ev.t == "createSubflow") {
|
|
|
|
if (ev.nodes) {
|
2015-10-15 12:34:17 +02:00
|
|
|
RED.nodes.filterNodes({z:ev.subflow.subflow.id}).forEach(function(n) {
|
2015-03-20 00:11:55 +01:00
|
|
|
n.z = ev.activeWorkspace;
|
|
|
|
n.dirty = true;
|
2014-02-25 00:35:11 +01:00
|
|
|
});
|
|
|
|
for (i=0;i<ev.nodes.length;i++) {
|
|
|
|
RED.nodes.remove(ev.nodes[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ev.links) {
|
|
|
|
for (i=0;i<ev.links.length;i++) {
|
|
|
|
RED.nodes.removeLink(ev.links[i]);
|
|
|
|
}
|
|
|
|
}
|
2015-07-30 12:03:37 +02:00
|
|
|
|
|
|
|
RED.nodes.removeSubflow(ev.subflow.subflow);
|
|
|
|
RED.workspaces.remove(ev.subflow.subflow);
|
|
|
|
|
2014-02-25 00:35:11 +01:00
|
|
|
if (ev.removedLinks) {
|
|
|
|
for (i=0;i<ev.removedLinks.length;i++) {
|
|
|
|
RED.nodes.addLink(ev.removedLinks[i]);
|
|
|
|
}
|
|
|
|
}
|
2016-05-04 16:22:30 +02:00
|
|
|
} else if (ev.t == "reorder") {
|
|
|
|
if (ev.order) {
|
|
|
|
RED.workspaces.order(ev.order);
|
|
|
|
}
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
2015-03-20 00:11:55 +01:00
|
|
|
Object.keys(modifiedTabs).forEach(function(id) {
|
|
|
|
var subflow = RED.nodes.subflow(id);
|
|
|
|
if (subflow) {
|
|
|
|
RED.editor.validateNode(subflow);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-03-15 22:54:36 +01:00
|
|
|
RED.nodes.dirty(ev.dirty);
|
2015-03-12 12:21:05 +01:00
|
|
|
RED.view.redraw(true);
|
2015-03-12 00:37:44 +01:00
|
|
|
RED.palette.refresh();
|
2015-09-25 22:49:53 +02:00
|
|
|
RED.workspaces.refresh();
|
2016-01-12 18:54:53 +01:00
|
|
|
RED.sidebar.config.refresh();
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
2016-03-17 12:12:45 +01:00
|
|
|
},
|
|
|
|
peek: function() {
|
|
|
|
return undo_history[undo_history.length-1];
|
2013-09-05 16:02:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-08 01:01:35 +02:00
|
|
|
})();
|