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