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