diff --git a/examples/html-editor/index.js b/examples/html-editor/index.js
index e91883e4..8eb4c56d 100644
--- a/examples/html-editor/index.js
+++ b/examples/html-editor/index.js
@@ -16,7 +16,9 @@ window.onload = function () {
   // Bind children of XmlFragment to the document.body
   window.yXmlType.bindToDom(document.body)
 }
-window.undoManager = new Y.utils.UndoManager(window.yXmlType)
+window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
+  captureTimeout: 1000
+})
 
 document.onkeydown = function interceptUndoRedo (e) {
   if (e.keyCode === 90 && e.ctrlKey) {
diff --git a/src/Struct/Type.js b/src/Struct/Type.js
index 58c17eb6..6d7c4d1b 100644
--- a/src/Struct/Type.js
+++ b/src/Struct/Type.js
@@ -39,6 +39,32 @@ export default class Type extends Item {
     this._eventHandler = new EventHandler()
     this._deepEventHandler = new EventHandler()
   }
+  getPathTo (type) {
+    if (type === this) {
+      return []
+    }
+    const path = []
+    const y = this._y
+    while (type._parent !== this && this._parent !== y) {
+      let parent = type._parent
+      if (type._parentSub !== null) {
+        path.push(type._parentSub)
+      } else {
+        // parent is array-ish
+        for (let [i, child] of parent) {
+          if (child === type) {
+            path.push(i)
+            break
+          }
+        }
+      }
+      type = parent
+    }
+    if (this._parent !== this) {
+      throw new Error('The type is not a child of this node')
+    }
+    return path
+  }
   _callEventHandler (event) {
     const changedParentTypes = this._y._transaction.changedParentTypes
     this._eventHandler.callEventListeners(event)
diff --git a/src/Util/UndoManager.js b/src/Util/UndoManager.js
index aed06735..7c535d6d 100644
--- a/src/Util/UndoManager.js
+++ b/src/Util/UndoManager.js
@@ -2,6 +2,7 @@ import ID from './ID.js'
 
 class ReverseOperation {
   constructor (y) {
+    this.created = new Date()
     const beforeState = y._transaction.beforeState
     this.toState = new ID(y.userID, y.ss.getState(y.userID) - 1)
     if (beforeState.has(y.userID)) {
@@ -24,7 +25,9 @@ function isStructInScope (y, struct, scope) {
 }
 
 export default class UndoManager {
-  constructor (scope) {
+  constructor (scope, options = {}) {
+    this.options = options
+    options.captureTimeout = options.captureTimeout || 0
     this._undoBuffer = []
     this._redoBuffer = []
     this._scope = scope
@@ -36,7 +39,15 @@ export default class UndoManager {
       if (!remote && (y._transaction.beforeState.has(y.userID) || y._transaction.deletedStructs.size > 0)) {
         let reverseOperation = new ReverseOperation(y)
         if (!this._undoing) {
-          this._undoBuffer.push(reverseOperation)
+          let lastUndoOp = this._undoBuffer.length > 0 ? this._undoBuffer[this._undoBuffer.length - 1] : null
+          if (lastUndoOp !== null && lastUndoOp.created - reverseOperation.created <= options.captureTimeout) {
+            console.log('appending', lastUndoOp, reverseOperation)
+            lastUndoOp.created = reverseOperation.created
+            lastUndoOp.toState = reverseOperation.toState
+            reverseOperation.deletedStructs.forEach(lastUndoOp.deletedStructs.add, lastUndoOp.deletedStructs)
+          } else {
+            this._undoBuffer.push(reverseOperation)
+          }
           if (!this._redoing) {
             this._redoBuffer = []
           }
@@ -47,6 +58,7 @@ export default class UndoManager {
     })
   }
   undo () {
+    console.log('undoing')
     this._undoing = true
     this._applyReverseOperation(this._undoBuffer)
     this._undoing = false
diff --git a/src/Util/YEvent.js b/src/Util/YEvent.js
index a6c486b7..cf37bf35 100644
--- a/src/Util/YEvent.js
+++ b/src/Util/YEvent.js
@@ -2,32 +2,27 @@
 export default class YEvent {
   constructor (target) {
     this.target = target
-    this._path = null
+    this.currentTarget = target
   }
   get path () {
-    if (this._path !== null) {
-      return this._path
-    } else {
-      const path = []
-      let type = this.target
-      const y = type._y
-      while (type._parent !== y) {
-        let parent = type._parent
-        if (type._parentSub !== null) {
-          path.push(type._parentSub)
-        } else {
-          // parent is array-ish
-          for (let [i, child] of parent) {
-            if (child === type) {
-              path.push(i)
-              break
-            }
+    const path = []
+    let type = this.target
+    const y = type._y
+    while (type._parent !== this._currentTarget && type._parent !== y) {
+      let parent = type._parent
+      if (type._parentSub !== null) {
+        path.push(type._parentSub)
+      } else {
+        // parent is array-ish
+        for (let [i, child] of parent) {
+          if (child === type) {
+            path.push(i)
+            break
           }
         }
-        type = parent
       }
-      this._path = path
-      return path
+      type = parent
     }
+    return path
   }
 }
diff --git a/src/Y.js b/src/Y.js
index 51c22276..6cdf6e74 100644
--- a/src/Y.js
+++ b/src/Y.js
@@ -61,9 +61,14 @@ export default class Y extends NamedEventHandler {
       })
       this._transaction.changedParentTypes.forEach(function (events, type) {
         if (!type._deleted) {
-          events = events.filter(event =>
-            !event.target._deleted
-          )
+          events = events
+            .filter(event =>
+              !event.target._deleted
+            )
+          events
+            .forEach(event => {
+              event.currentTarget = type
+            })
           // we don't have to check for events.length
           // because there is no way events is empty..
           type._deepEventHandler.callEventListeners(events)