diff --git a/examples/html-editor/index.js b/examples/html-editor/index.js index 330fadf0..946fdb3a 100644 --- a/examples/html-editor/index.js +++ b/examples/html-editor/index.js @@ -18,7 +18,7 @@ window.undoManager = new Y.utils.UndoManager(window.yXmlType, { }) document.onkeydown = function interceptUndoRedo (e) { - if (e.keyCode === 90 && e.metaKey) { + if (e.keyCode === 90 && (e.metaKey || e.ctrlKey)) { if (!e.shiftKey) { window.undoManager.undo() } else { diff --git a/src/Struct/Item.js b/src/Struct/Item.js index ae99c984..2f9f87b7 100644 --- a/src/Struct/Item.js +++ b/src/Struct/Item.js @@ -51,22 +51,56 @@ export default class Item { this._parent = null this._parentSub = null this._deleted = false + this._redone = null } /** - * Copy the effect of struct + * Create a operation with the same effect (without position effect) */ - _copy (undeleteChildren, copyPosition) { - let struct = new this.constructor() - if (copyPosition) { - struct._origin = this._left - struct._left = this._left - struct._right = this - struct._right_origin = this - struct._parent = this._parent - struct._parentSub = this._parentSub + _copy () { + return new this.constructor() + } + /** + * Redo the effect of this operation. + */ + _redo (y) { + if (this._redone !== null) { + return this._redone } + let struct = this._copy() + let left = this._left + let right = this + let parent = this._parent + // make sure that parent is redone + if (parent._deleted === true && parent._redone === null) { + parent._redo(y) + } + if (parent._redone !== null) { + parent = parent._redone + // find next cloned items + while (left !== null && left._redone === null) { + left = left._left + } + if (left !== null) { + left = left._redone + } + while (right !== null && right._redone === null) { + right = right._right + } + if (right !== null) { + right = right._redone + } + } + struct._origin = left + struct._left = left + struct._right = right + struct._right_origin = right + struct._parent = parent + struct._parentSub = this._parentSub + struct._integrate(y) + this._redone = struct return struct } + get _lastId () { return new ID(this._id.user, this._id.clock + this._length - 1) } diff --git a/src/Struct/ItemJSON.js b/src/Struct/ItemJSON.js index f2d773d1..f8d22dd4 100644 --- a/src/Struct/ItemJSON.js +++ b/src/Struct/ItemJSON.js @@ -6,8 +6,8 @@ export default class ItemJSON extends Item { super() this._content = null } - _copy (undeleteChildren, copyPosition) { - let struct = super._copy(undeleteChildren, copyPosition) + _copy () { + let struct = super._copy() struct._content = this._content return struct } diff --git a/src/Struct/ItemString.js b/src/Struct/ItemString.js index 7b888b64..a5a0b90c 100644 --- a/src/Struct/ItemString.js +++ b/src/Struct/ItemString.js @@ -6,8 +6,8 @@ export default class ItemString extends Item { super() this._content = null } - _copy (undeleteChildren, copyPosition) { - let struct = super._copy(undeleteChildren, copyPosition) + _copy () { + let struct = super._copy() struct._content = this._content return struct } diff --git a/src/Struct/Type.js b/src/Struct/Type.js index 734dcdcf..80d93fed 100644 --- a/src/Struct/Type.js +++ b/src/Struct/Type.js @@ -79,40 +79,6 @@ export default class Type extends Item { type = type._parent } } - _copy (undeleteChildren, copyPosition) { - let copy = super._copy(undeleteChildren, copyPosition) - let map = new Map() - copy._map = map - for (let [key, value] of this._map) { - if (undeleteChildren.has(value) || !value.deleted) { - let _item = value._copy(undeleteChildren, false) - _item._parent = copy - _item._parentSub = key - map.set(key, _item) - } - } - let prevUndeleted = null - copy._start = null - let item = this._start - while (item !== null) { - if (undeleteChildren.has(item) || !item.deleted) { - let _item = item._copy(undeleteChildren, false) - _item._left = prevUndeleted - _item._origin = prevUndeleted - _item._right = null - _item._right_origin = null - _item._parent = copy - if (prevUndeleted === null) { - copy._start = _item - } else { - prevUndeleted._right = _item - } - prevUndeleted = _item - } - item = item._right - } - return copy - } _transact (f) { const y = this._y if (y !== null) { diff --git a/src/Type/y-xml/YXmlElement.js b/src/Type/y-xml/YXmlElement.js index 39c4a3ae..e546c8b3 100644 --- a/src/Type/y-xml/YXmlElement.js +++ b/src/Type/y-xml/YXmlElement.js @@ -20,8 +20,8 @@ export default class YXmlElement extends YXmlFragment { this._domFilter = arg2 } } - _copy (undeleteChildren, copyPosition) { - let struct = super._copy(undeleteChildren, copyPosition) + _copy () { + let struct = super._copy() struct.nodeName = this.nodeName return struct } diff --git a/src/Type/y-xml/YXmlHook.js b/src/Type/y-xml/YXmlHook.js index 60926148..ee2ce4f7 100644 --- a/src/Type/y-xml/YXmlHook.js +++ b/src/Type/y-xml/YXmlHook.js @@ -14,8 +14,8 @@ export default class YXmlHook extends YMap { getHook(hookName).fillType(dom, this) } } - _copy (undeleteChildren, copyPosition) { - const struct = super._copy(undeleteChildren, copyPosition) + _copy () { + const struct = super._copy() struct.hookName = this.hookName return struct } diff --git a/src/Util/UndoManager.js b/src/Util/UndoManager.js index 9d8a16ef..83b37530 100644 --- a/src/Util/UndoManager.js +++ b/src/Util/UndoManager.js @@ -4,11 +4,12 @@ class ReverseOperation { constructor (y, transaction) { this.created = new Date() const beforeState = transaction.beforeState - this.toState = new ID(y.userID, y.ss.getState(y.userID) - 1) if (beforeState.has(y.userID)) { + this.toState = new ID(y.userID, y.ss.getState(y.userID) - 1) this.fromState = new ID(y.userID, beforeState.get(y.userID)) } else { - this.fromState = this.toState + this.toState = null + this.fromState = null } this.deletedStructs = transaction.deletedStructs } @@ -30,28 +31,28 @@ function applyReverseOperation (y, scope, reverseBuffer) { while (!performedUndo && reverseBuffer.length > 0) { let undoOp = reverseBuffer.pop() // make sure that it is possible to iterate {from}-{to} - y.os.getItemCleanStart(undoOp.fromState) - y.os.getItemCleanEnd(undoOp.toState) - y.os.iterate(undoOp.fromState, undoOp.toState, op => { - if (!op._deleted && isStructInScope(y, op, scope)) { - performedUndo = true - op._delete(y) - } - }) + if (undoOp.fromState !== null) { + let start = y.os.getItemCleanStart(undoOp.fromState) + y.os.getItemCleanEnd(undoOp.toState) + console.log(start) + y.os.iterate(undoOp.fromState, undoOp.toState, op => { + debugger + if (op._deleted && op._redone !== null) { + op = op._redone + } + if (op._deleted === false && isStructInScope(y, op, scope)) { + performedUndo = true + op._delete(y) + } + }) + } for (let op of undoOp.deletedStructs) { if ( isStructInScope(y, op, scope) && - op._parent !== y && - !op._parent._deleted && - ( - op._parent._id.user !== y.userID || - op._parent._id.clock < undoOp.fromState.clock || - op._parent._id.clock > undoOp.fromState.clock - ) + op._parent !== y ) { performedUndo = true - op = op._copy(undoOp.deletedStructs, true) - op._integrate(y) + op._redo(y) } } }