From bdb3782f8f6b27db9b90bc601a3763e46781aa7e Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Wed, 2 May 2018 18:42:18 +0200
Subject: [PATCH 01/11] add option to disable gc (compatible with older
 versions)

---
 src/MessageHandler/integrateRemoteStructs.js | 2 +-
 src/Struct/Type.js                           | 4 ++--
 src/Y.js                                     | 3 ++-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/MessageHandler/integrateRemoteStructs.js b/src/MessageHandler/integrateRemoteStructs.js
index 390f0924..802c3af6 100644
--- a/src/MessageHandler/integrateRemoteStructs.js
+++ b/src/MessageHandler/integrateRemoteStructs.js
@@ -25,7 +25,7 @@ function _integrateRemoteStructHelper (y, struct) {
     if (y.ss.getState(id.user) > id.clock) {
       return
     }
-    if (struct.constructor === GC || (struct._parent.constructor !== GC && struct._parent._deleted === false)) {
+    if (!y.gcEnabled || struct.constructor === GC || (struct._parent.constructor !== GC && struct._parent._deleted === false)) {
       // Is either a GC or Item with an undeleted parent
       // save to integrate
       struct._integrate(y)
diff --git a/src/Struct/Type.js b/src/Struct/Type.js
index 6202454b..c8b63395 100644
--- a/src/Struct/Type.js
+++ b/src/Struct/Type.js
@@ -217,8 +217,8 @@ export default class Type extends Item {
    *                                         collect the children of this type.
    */
   _delete (y, createDelete, gcChildren) {
-    if (gcChildren === undefined) {
-      gcChildren = y._hasUndoManager === false
+    if (gcChildren === undefined || !y.gcEnabled) {
+      gcChildren = y._hasUndoManager === false && y.gcEnabled
     }
     super._delete(y, createDelete, gcChildren)
     y._transaction.changedTypes.delete(this)
diff --git a/src/Y.js b/src/Y.js
index 7a1ab318..0279cf17 100644
--- a/src/Y.js
+++ b/src/Y.js
@@ -28,8 +28,9 @@ export { default as DomBinding } from './Bindings/DomBinding/DomBinding.js'
  * @param {AbstractPersistence} persistence Persistence adapter instance
  */
 export default class Y extends NamedEventHandler {
-  constructor (room, opts, persistence) {
+  constructor (room, opts, persistence, conf = {}) {
     super()
+    this.gcEnabled = conf.gc || false
     /**
      * The room name that this Yjs instance connects to.
      * @type {String}

From 38558a7fad04739ac4ce22a76887f01af31899f3 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Wed, 2 May 2018 18:42:56 +0200
Subject: [PATCH 02/11] 13.0.0-57

---
 package-lock.json | 2 +-
 package.json      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index ac06c647..ed99c0db 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-56",
+  "version": "13.0.0-57",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 266af208..3f998591 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-56",
+  "version": "13.0.0-57",
   "description": "A framework for real-time p2p shared editing on any data",
   "main": "./y.node.js",
   "browser": "./y.js",

From c098e8e7457076be9ff148d42fc4b074a84c1f67 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Sat, 5 May 2018 14:47:59 +0200
Subject: [PATCH 03/11] implement scroll-fixer

---
 examples/html-editor/index.js           |  2 +-
 src/Bindings/DomBinding/DomBinding.js   | 12 +-------
 src/Bindings/DomBinding/domObserver.js  |  3 --
 src/Bindings/DomBinding/typeObserver.js | 37 +++++++++++++++++++++++++
 4 files changed, 39 insertions(+), 15 deletions(-)

diff --git a/examples/html-editor/index.js b/examples/html-editor/index.js
index 80623031..a13010a4 100644
--- a/examples/html-editor/index.js
+++ b/examples/html-editor/index.js
@@ -1,7 +1,7 @@
 /* global Y */
 
 window.onload = function () {
-  window.domBinding = new Y.DomBinding(window.yXmlType, document.body)
+  window.domBinding = new Y.DomBinding(window.yXmlType, document.body, { scrollingElement: document.scrollingElement })
 }
 
 let y = new Y('htmleditor', {
diff --git a/src/Bindings/DomBinding/DomBinding.js b/src/Bindings/DomBinding/DomBinding.js
index 1568f08d..b3ecb625 100644
--- a/src/Bindings/DomBinding/DomBinding.js
+++ b/src/Bindings/DomBinding/DomBinding.js
@@ -33,6 +33,7 @@ export default class DomBinding extends Binding {
     this.opts = opts
     opts.document = opts.document || document
     opts.hooks = opts.hooks || {}
+    this.scrollingElement = opts.scrollingElement || null
     /**
      * Maps each DOM element to the type that it is associated with.
      * @type {Map}
@@ -105,17 +106,6 @@ export default class DomBinding extends Binding {
     createAssociation(this, target, type)
   }
 
-  /**
-   * Enables the smart scrolling functionality for a Dom Binding.
-   * This is useful when YXml is bound to a shared editor. When activated,
-   * the viewport will be changed to accommodate remote changes.
-   *
-   * @param {Element} scrollElement The node that is
-   */
-  enableSmartScrolling (scrollElement) {
-    // @TODO: implement smart scrolling
-  }
-
   /**
    * NOTE: currently does not apply filter to existing elements!
    * @param {FilterFunction} filter The filter function to use from now on.
diff --git a/src/Bindings/DomBinding/domObserver.js b/src/Bindings/DomBinding/domObserver.js
index 8304c079..593510a5 100644
--- a/src/Bindings/DomBinding/domObserver.js
+++ b/src/Bindings/DomBinding/domObserver.js
@@ -125,9 +125,6 @@ export default function domObserver (mutations, _document) {
         }
       })
       for (let dom of diffChildren) {
-        if (dom.yOnChildrenChanged !== undefined) {
-          dom.yOnChildrenChanged()
-        }
         const yxml = this.domToType.get(dom)
         applyChangesFromDom(this, dom, yxml, _document)
       }
diff --git a/src/Bindings/DomBinding/typeObserver.js b/src/Bindings/DomBinding/typeObserver.js
index 1417cc4e..6b193159 100644
--- a/src/Bindings/DomBinding/typeObserver.js
+++ b/src/Bindings/DomBinding/typeObserver.js
@@ -1,13 +1,49 @@
+/* global getSelection */
 
 import YXmlText from '../../Types/YXml/YXmlText.js'
 import YXmlHook from '../../Types/YXml/YXmlHook.js'
 import { removeDomChildrenUntilElementFound } from './util.js'
 
+function findScrollReference (scrollingElement) {
+  if (scrollingElement !== null) {
+    let anchor = getSelection().anchorNode
+    if (anchor == null) {
+      let children = scrollingElement.children
+      for (let i = 0; i < children.length; i++) {
+        const elem = children[i]
+        const rect = elem.getBoundingClientRect()
+        if (rect.top >= 0) {
+          return { elem, top: rect.top }
+        }
+      }
+    } else {
+      if (anchor.nodeType === document.TEXT_NODE) {
+        anchor = anchor.parentElement
+      }
+      const top = anchor.getBoundingClientRect().top
+      return { elem: anchor, top: top }
+    }
+  }
+  return null
+}
+
+function fixScroll (scrollingElement, ref) {
+  if (ref !== null) {
+    const { elem, top } = ref
+    const currentTop = elem.getBoundingClientRect().top
+    const newScroll = scrollingElement.scrollTop + currentTop - top
+    if (newScroll >= 0) {
+      scrollingElement.scrollTop = newScroll
+    }
+  }
+}
+
 /**
  * @private
  */
 export default function typeObserver (events) {
   this._mutualExclude(() => {
+    const scrollRef = findScrollReference(this.scrollingElement)
     events.forEach(event => {
       const yxml = event.target
       const dom = this.typeToDom.get(yxml)
@@ -59,5 +95,6 @@ export default function typeObserver (events) {
         }
       }
     })
+    fixScroll(this.scrollingElement, scrollRef)
   })
 }

From 49d2e42b41eb772e7d428d72641584198273c7e4 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Sat, 5 May 2018 15:33:16 +0200
Subject: [PATCH 04/11] fix missing dom-binding - still investigating

---
 src/Bindings/DomBinding/domObserver.js  | 14 +++++++++++++-
 src/Bindings/DomBinding/typeObserver.js |  2 +-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/Bindings/DomBinding/domObserver.js b/src/Bindings/DomBinding/domObserver.js
index 593510a5..48929dfa 100644
--- a/src/Bindings/DomBinding/domObserver.js
+++ b/src/Bindings/DomBinding/domObserver.js
@@ -60,8 +60,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
             removeAssociation(binding, childNode, childType)
           } else {
             // child was moved to a different position.
-            childType._delete(y)
             removeAssociation(binding, childNode, childType)
+            childType._delete(y)
           }
           prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
         } else {
@@ -92,6 +92,18 @@ export default function domObserver (mutations, _document) {
         const yxml = this.domToType.get(dom)
         if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
           // dom element is filtered
+          if (yxml === undefined) { // In case yxml is undefined, we double check if we forgot to bind the dom
+            console.error('Yjs DomBinding: Reconstructing DomBinding, please report how to reproduce this.')
+            let parent
+            let yParent
+            do {
+              parent = dom.parentNode
+              yParent = this.domToType.get(parent)
+            } while (yParent === undefined)
+            if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
+              diffChildren.add(parent)
+            }
+          }
           return
         }
         switch (mutation.type) {
diff --git a/src/Bindings/DomBinding/typeObserver.js b/src/Bindings/DomBinding/typeObserver.js
index 6b193159..d874e7af 100644
--- a/src/Bindings/DomBinding/typeObserver.js
+++ b/src/Bindings/DomBinding/typeObserver.js
@@ -8,7 +8,7 @@ function findScrollReference (scrollingElement) {
   if (scrollingElement !== null) {
     let anchor = getSelection().anchorNode
     if (anchor == null) {
-      let children = scrollingElement.children
+      let children = scrollingElement.children // only iterate through non-text nodes
       for (let i = 0; i < children.length; i++) {
         const elem = children[i]
         const rect = elem.getBoundingClientRect()

From 633606451667f0eb516a5ee067482151666947a0 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Sat, 5 May 2018 15:33:53 +0200
Subject: [PATCH 05/11] 13.0.0-58

---
 package-lock.json | 2 +-
 package.json      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index ed99c0db..f2342929 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-57",
+  "version": "13.0.0-58",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 3f998591..c4f5df64 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-57",
+  "version": "13.0.0-58",
   "description": "A framework for real-time p2p shared editing on any data",
   "main": "./y.node.js",
   "browser": "./y.js",

From 1ace7f4b7349e09d6adaa691e9499517575f74e7 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Mon, 7 May 2018 11:41:45 +0200
Subject: [PATCH 06/11] fix parentNode binding in case parent doesn't fire MO

---
 src/Bindings/DomBinding/domObserver.js | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/Bindings/DomBinding/domObserver.js b/src/Bindings/DomBinding/domObserver.js
index 48929dfa..3c1b274d 100644
--- a/src/Bindings/DomBinding/domObserver.js
+++ b/src/Bindings/DomBinding/domObserver.js
@@ -90,21 +90,20 @@ export default function domObserver (mutations, _document) {
       mutations.forEach(mutation => {
         const dom = mutation.target
         const yxml = this.domToType.get(dom)
-        if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
-          // dom element is filtered
-          if (yxml === undefined) { // In case yxml is undefined, we double check if we forgot to bind the dom
-            console.error('Yjs DomBinding: Reconstructing DomBinding, please report how to reproduce this.')
-            let parent
-            let yParent
-            do {
-              parent = dom.parentNode
-              yParent = this.domToType.get(parent)
-            } while (yParent === undefined)
-            if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
-              diffChildren.add(parent)
-            }
+        if (yxml === undefined) { // In case yxml is undefined, we double check if we forgot to bind the dom
+          let parent
+          let yParent
+          do {
+            parent = dom.parentNode
+            yParent = this.domToType.get(parent)
+          } while (yParent === undefined && parent !== null)
+          if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
+            diffChildren.add(parent)
           }
           return
+        } else if (yxml === false || yxml.constructor === YXmlHook) {
+          // dom element is filtered / a dom hook
+          return
         }
         switch (mutation.type) {
           case 'characterData':

From 65b8921f05a9d39bfaab931630812deb84f57c94 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Mon, 7 May 2018 11:45:39 +0200
Subject: [PATCH 07/11] 13.0.0-59

---
 package-lock.json | 2 +-
 package.json      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index f2342929..0a89f499 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-58",
+  "version": "13.0.0-59",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index c4f5df64..1b738fcb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-58",
+  "version": "13.0.0-59",
   "description": "A framework for real-time p2p shared editing on any data",
   "main": "./y.node.js",
   "browser": "./y.js",

From 92c2fbd6d348ea74a10cd2d0db19504292a52f24 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Mon, 7 May 2018 11:52:37 +0200
Subject: [PATCH 08/11] remove debug dependency

---
 package.json | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/package.json b/package.json
index 1b738fcb..3951bc48 100644
--- a/package.json
+++ b/package.json
@@ -71,8 +71,5 @@
     "rollup-watch": "^3.2.2",
     "standard": "^10.0.2",
     "tag-dist-files": "^0.1.6"
-  },
-  "dependencies": {
-    "debug": "^2.6.8"
   }
 }

From ca1384982825f147138f2f734a3dbe87c00f8bff Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Tue, 8 May 2018 13:45:51 +0200
Subject: [PATCH 09/11] fix domBinding infinite loop

---
 src/Bindings/DomBinding/domObserver.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Bindings/DomBinding/domObserver.js b/src/Bindings/DomBinding/domObserver.js
index 3c1b274d..4284d11f 100644
--- a/src/Bindings/DomBinding/domObserver.js
+++ b/src/Bindings/DomBinding/domObserver.js
@@ -91,10 +91,10 @@ export default function domObserver (mutations, _document) {
         const dom = mutation.target
         const yxml = this.domToType.get(dom)
         if (yxml === undefined) { // In case yxml is undefined, we double check if we forgot to bind the dom
-          let parent
+          let parent = dom
           let yParent
           do {
-            parent = dom.parentNode
+            parent = parent.parentNode
             yParent = this.domToType.get(parent)
           } while (yParent === undefined && parent !== null)
           if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {

From e56457a0ef5451bd756abf943cf0fa7ddcba09a7 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Tue, 8 May 2018 13:46:27 +0200
Subject: [PATCH 10/11] 13.0.0-60

---
 package-lock.json | 2 +-
 package.json      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 0a89f499..286c3036 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-59",
+  "version": "13.0.0-60",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 3951bc48..fd7cd781 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "13.0.0-59",
+  "version": "13.0.0-60",
   "description": "A framework for real-time p2p shared editing on any data",
   "main": "./y.node.js",
   "browser": "./y.js",

From c0e630b635768b7923cdea71f12512cc05c18dc7 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Wed, 9 May 2018 14:42:24 +0200
Subject: [PATCH 11/11] prefer parentElement instead of parentNode

---
 src/Bindings/DomBinding/domObserver.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Bindings/DomBinding/domObserver.js b/src/Bindings/DomBinding/domObserver.js
index 4284d11f..0dfb176e 100644
--- a/src/Bindings/DomBinding/domObserver.js
+++ b/src/Bindings/DomBinding/domObserver.js
@@ -94,7 +94,7 @@ export default function domObserver (mutations, _document) {
           let parent = dom
           let yParent
           do {
-            parent = parent.parentNode
+            parent = parent.parentElement
             yParent = this.domToType.get(parent)
           } while (yParent === undefined && parent !== null)
           if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {