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)
}
}
}