Fix undo/redo (WIP)
This commit is contained in:
parent
ab8e6322d2
commit
338df99410
|
@ -1,7 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
var util = require('./util');
|
||||
|
||||
/**
|
||||
* @constructor History
|
||||
* Store action history, enables undo and redo
|
||||
|
@ -14,122 +12,144 @@ function History (editor) {
|
|||
|
||||
this.clear();
|
||||
|
||||
// helper function to find a Node from a path
|
||||
function findNode(path) {
|
||||
return editor.node.findNodeByPath(path)
|
||||
}
|
||||
|
||||
// helper function to clone a Node
|
||||
function cloneNode(node) {
|
||||
return node.clone();
|
||||
}
|
||||
|
||||
// map with all supported actions
|
||||
this.actions = {
|
||||
'editField': {
|
||||
'undo': function (params) {
|
||||
params.node.updateField(params.oldValue);
|
||||
findNode(params.path).updateField(params.oldValue);
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.node.updateField(params.newValue);
|
||||
findNode(params.path).updateField(params.newValue);
|
||||
}
|
||||
},
|
||||
'editValue': {
|
||||
'undo': function (params) {
|
||||
params.node.updateValue(params.oldValue);
|
||||
findNode(params.path).updateValue(params.oldValue);
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.node.updateValue(params.newValue);
|
||||
findNode(params.path).updateValue(params.newValue);
|
||||
}
|
||||
},
|
||||
'changeType': {
|
||||
'undo': function (params) {
|
||||
params.node.changeType(params.oldType);
|
||||
findNode(params.path).changeType(params.oldType);
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.node.changeType(params.newType);
|
||||
findNode(params.path).changeType(params.newType);
|
||||
}
|
||||
},
|
||||
|
||||
'appendNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.removeChild(node);
|
||||
});
|
||||
},
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.appendChild(node);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.appendChild(node);
|
||||
});
|
||||
}
|
||||
},
|
||||
'insertBeforeNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.removeChild(node);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.insertBefore(node, params.beforeNode);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
var beforeNode = findNode(params.beforePath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.insertBefore(node, beforeNode);
|
||||
});
|
||||
}
|
||||
},
|
||||
'insertAfterNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.removeChild(node);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
var afterNode = params.afterNode;
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.insertAfter(params.node, afterNode);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
var afterNode = findNode(params.afterPath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.insertAfter(node, afterNode);
|
||||
afterNode = node;
|
||||
});
|
||||
}
|
||||
},
|
||||
'removeNodes': {
|
||||
'undo': function (params) {
|
||||
var parent = params.parent;
|
||||
var beforeNode = parent.childs[params.index] || parent.append;
|
||||
params.nodes.forEach(function (node) {
|
||||
parent.insertBefore(node, beforeNode);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
var beforeNode = parentNode.childs[params.index] || parentNode.append;
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.insertBefore(node, beforeNode);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
});
|
||||
}
|
||||
},
|
||||
'duplicateNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
parentNode.removeChild(node);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
var afterNode = params.afterNode;
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.insertAfter(node, afterNode);
|
||||
var parentNode = findNode(params.parentPath);
|
||||
var afterNode = findNode(params.afterPath);
|
||||
var nodes = params.paths.map(findNode).map(cloneNode);
|
||||
nodes.forEach(function (node) {
|
||||
parentNode.insertAfter(node, afterNode);
|
||||
afterNode = node;
|
||||
});
|
||||
}
|
||||
},
|
||||
'moveNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.oldBeforeNode.parent.moveBefore(node, params.oldBeforeNode);
|
||||
var oldBeforeNode = findNode(params.oldBeforePath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
oldBeforeNode.parent.moveBefore(node, oldBeforeNode);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.newBeforeNode.parent.moveBefore(node, params.newBeforeNode);
|
||||
var newBeforeNode = findNode(params.newBeforePath);
|
||||
params.paths.map(findNode).forEach(function (node) {
|
||||
newBeforeNode.parent.moveBefore(node, newBeforeNode);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
'sort': {
|
||||
'undo': function (params) {
|
||||
var node = params.node;
|
||||
var node = findNode(params.path);
|
||||
node.hideChilds();
|
||||
node.childs = params.oldChilds;
|
||||
node.updateDom({updateIndexes: true});
|
||||
node.showChilds();
|
||||
},
|
||||
'redo': function (params) {
|
||||
var node = params.node;
|
||||
var node = findNode(params.path);
|
||||
node.hideChilds();
|
||||
node.childs = params.newChilds;
|
||||
node.updateDom({updateIndexes: true});
|
||||
|
@ -139,14 +159,12 @@ function History (editor) {
|
|||
|
||||
'transform': {
|
||||
'undo': function (params) {
|
||||
var node = params.node;
|
||||
node.setValue(params.oldValue);
|
||||
findNode(params.path).setValue(params.oldValue);
|
||||
|
||||
// TODO: would be nice to restore the state of the node and childs
|
||||
},
|
||||
'redo': function (params) {
|
||||
var node = params.node;
|
||||
node.setValue(params.newValue);
|
||||
findNode(params.path).setValue(params.newValue);
|
||||
|
||||
// TODO: would be nice to restore the state of the node and childs
|
||||
}
|
||||
|
|
|
@ -1404,7 +1404,7 @@ Node.prototype._onChangeValue = function () {
|
|||
}
|
||||
|
||||
this.editor._onAction('editValue', {
|
||||
node: this,
|
||||
path: this.getPath(),
|
||||
oldValue: this.previousValue,
|
||||
newValue: this.value,
|
||||
oldSelection: oldSelection,
|
||||
|
@ -1436,7 +1436,7 @@ Node.prototype._onChangeField = function () {
|
|||
}
|
||||
|
||||
this.editor._onAction('editField', {
|
||||
node: this,
|
||||
path: this.getPath(),
|
||||
oldValue: this.previousField,
|
||||
newValue: this.field,
|
||||
oldSelection: oldSelection,
|
||||
|
@ -2010,11 +2010,11 @@ Node.onDragEnd = function (nodes, event) {
|
|||
}
|
||||
|
||||
var params = {
|
||||
nodes: nodes,
|
||||
paths: nodes.map(getPath),
|
||||
oldSelection: editor.drag.oldSelection,
|
||||
newSelection: editor.getDomSelection(),
|
||||
oldBeforeNode: editor.drag.oldBeforeNode,
|
||||
newBeforeNode: beforeNode
|
||||
oldBeforePath: editor.drag.oldBeforeNode.getPath(),
|
||||
newBeforePath: beforeNode.getPath()
|
||||
};
|
||||
|
||||
if (params.oldBeforeNode != params.newBeforeNode) {
|
||||
|
@ -2811,9 +2811,9 @@ Node.prototype.onKeyDown = function (event) {
|
|||
this.focus(Node.focusElement || this._getElementName(target));
|
||||
|
||||
this.editor._onAction('moveNodes', {
|
||||
nodes: selectedNodes,
|
||||
oldBeforeNode: oldBeforeNode,
|
||||
newBeforeNode: nextNode2,
|
||||
paths: selectedNodes.map(getPath),
|
||||
oldBeforePath: oldBeforeNode.getPath(),
|
||||
newBeforePath: nextNode2.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: this.editor.getDomSelection()
|
||||
});
|
||||
|
@ -2858,9 +2858,9 @@ Node.prototype.onKeyDown = function (event) {
|
|||
this.focus(Node.focusElement || this._getElementName(target));
|
||||
|
||||
this.editor._onAction('moveNodes', {
|
||||
nodes: selectedNodes,
|
||||
oldBeforeNode: oldBeforeNode,
|
||||
newBeforeNode: prevNode,
|
||||
paths: selectedNodes.map(getPath),
|
||||
oldBeforePath: oldBeforeNode.getPath(),
|
||||
newBeforePath: prevNode.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: this.editor.getDomSelection()
|
||||
});
|
||||
|
@ -2892,9 +2892,9 @@ Node.prototype.onKeyDown = function (event) {
|
|||
this.focus(Node.focusElement || this._getElementName(target));
|
||||
|
||||
this.editor._onAction('moveNodes', {
|
||||
nodes: selectedNodes,
|
||||
oldBeforeNode: oldBeforeNode,
|
||||
newBeforeNode: prevNode,
|
||||
paths: selectedNodes.map(getPath),
|
||||
oldBeforePath: oldBeforeNode.getPath(),
|
||||
newBeforePath: prevNode.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: this.editor.getDomSelection()
|
||||
});
|
||||
|
@ -2955,9 +2955,9 @@ Node.prototype.onKeyDown = function (event) {
|
|||
this.focus(Node.focusElement || this._getElementName(target));
|
||||
|
||||
this.editor._onAction('moveNodes', {
|
||||
nodes: selectedNodes,
|
||||
oldBeforeNode: oldBeforeNode,
|
||||
newBeforeNode: nextNode2,
|
||||
paths: selectedNodes.map(getPath),
|
||||
oldBeforePath: oldBeforeNode.getPath(),
|
||||
newBeforePath: nextNode2.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: this.editor.getDomSelection()
|
||||
});
|
||||
|
@ -3028,8 +3028,8 @@ Node.onRemove = function(nodes) {
|
|||
|
||||
// store history action
|
||||
editor._onAction('removeNodes', {
|
||||
nodes: nodes.slice(0), // store a copy of the array!
|
||||
parent: parent,
|
||||
paths: nodes.map(getPath),
|
||||
parentPath: parent.getPath(),
|
||||
index: firstIndex,
|
||||
oldSelection: oldSelection,
|
||||
newSelection: newSelection
|
||||
|
@ -3075,9 +3075,9 @@ Node.onDuplicate = function(nodes) {
|
|||
var newSelection = editor.getDomSelection();
|
||||
|
||||
editor._onAction('duplicateNodes', {
|
||||
afterNode: lastNode,
|
||||
nodes: clones,
|
||||
parent: parent,
|
||||
afterPath: lastNode.getPath(),
|
||||
paths: clones.map(getPath),
|
||||
parentPath: parent.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: newSelection
|
||||
});
|
||||
|
@ -3106,9 +3106,9 @@ Node.prototype._onInsertBefore = function (field, value, type) {
|
|||
var newSelection = this.editor.getDomSelection();
|
||||
|
||||
this.editor._onAction('insertBeforeNodes', {
|
||||
nodes: [newNode],
|
||||
beforeNode: this,
|
||||
parent: this.parent,
|
||||
paths: [newNode.getPath()],
|
||||
beforePath: this.getPath(),
|
||||
parentPath: this.parent.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: newSelection
|
||||
});
|
||||
|
@ -3136,9 +3136,9 @@ Node.prototype._onInsertAfter = function (field, value, type) {
|
|||
var newSelection = this.editor.getDomSelection();
|
||||
|
||||
this.editor._onAction('insertAfterNodes', {
|
||||
nodes: [newNode],
|
||||
afterNode: this,
|
||||
parent: this.parent,
|
||||
paths: [newNode.getPath()],
|
||||
afterPath: this.getPath(),
|
||||
parentPath: this.parent.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: newSelection
|
||||
});
|
||||
|
@ -3166,8 +3166,8 @@ Node.prototype._onAppend = function (field, value, type) {
|
|||
var newSelection = this.editor.getDomSelection();
|
||||
|
||||
this.editor._onAction('appendNodes', {
|
||||
nodes: [newNode],
|
||||
parent: this.parent,
|
||||
paths: [newNode.getPath()],
|
||||
parentPath: this.parent.getPath(),
|
||||
oldSelection: oldSelection,
|
||||
newSelection: newSelection
|
||||
});
|
||||
|
@ -3186,7 +3186,7 @@ Node.prototype._onChangeType = function (newType) {
|
|||
var newSelection = this.editor.getDomSelection();
|
||||
|
||||
this.editor._onAction('changeType', {
|
||||
node: this,
|
||||
path: this.getPath(),
|
||||
oldType: oldType,
|
||||
newType: newType,
|
||||
oldSelection: oldSelection,
|
||||
|
@ -3249,7 +3249,7 @@ Node.prototype.sort = function (path, direction) {
|
|||
this._updateDomIndexes();
|
||||
|
||||
this.editor._onAction('sort', {
|
||||
node: this,
|
||||
path: this.getPath(),
|
||||
oldChilds: oldChilds,
|
||||
newChilds: this.childs
|
||||
});
|
||||
|
@ -3269,7 +3269,7 @@ Node.prototype.update = function (newValue) {
|
|||
this.setValue(newValue);
|
||||
|
||||
this.editor._onAction('transform', {
|
||||
node: this,
|
||||
path: this.getPath(),
|
||||
oldType: oldType,
|
||||
newType: this.type,
|
||||
oldValue: oldValue,
|
||||
|
@ -3302,7 +3302,7 @@ Node.prototype.transform = function (query) {
|
|||
this.setValue(newValue);
|
||||
|
||||
this.editor._onAction('transform', {
|
||||
node: this,
|
||||
path: this.getPath(),
|
||||
oldType: oldType,
|
||||
newType: this.type,
|
||||
oldValue: oldValue,
|
||||
|
@ -4018,6 +4018,11 @@ Node.prototype._escapeJSON = function (text) {
|
|||
return escaped;
|
||||
};
|
||||
|
||||
// helper function to the get path of a node
|
||||
function getPath (node) {
|
||||
return node.getPath();
|
||||
}
|
||||
|
||||
// TODO: find a nicer solution to resolve this circular dependency between Node and AppendNode
|
||||
// idea: introduce properties .isAppendNode and .isNode and use that instead of instanceof AppendNode checks
|
||||
var AppendNode = appendNodeFactory(Node);
|
||||
|
|
Loading…
Reference in New Issue