Compare commits

..

1 Commits

Author SHA1 Message Date
Kevin Jahns
3bac7362c2 v13.0.0-57 -- distribution files 2018-05-02 18:43:14 +02:00
12 changed files with 75 additions and 181 deletions

View File

@@ -1,7 +1,7 @@
/* global Y */ /* global Y */
window.onload = function () { window.onload = function () {
window.domBinding = new Y.DomBinding(window.yXmlType, document.body, { scrollingElement: document.scrollingElement }) window.domBinding = new Y.DomBinding(window.yXmlType, document.body)
} }
let y = new Y('htmleditor', { let y = new Y('htmleditor', {

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-58", "version": "13.0.0-57",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-58", "version": "13.0.0-57",
"description": "A framework for real-time p2p shared editing on any data", "description": "A framework for real-time p2p shared editing on any data",
"main": "./y.node.js", "main": "./y.node.js",
"browser": "./y.js", "browser": "./y.js",

View File

@@ -33,7 +33,6 @@ export default class DomBinding extends Binding {
this.opts = opts this.opts = opts
opts.document = opts.document || document opts.document = opts.document || document
opts.hooks = opts.hooks || {} opts.hooks = opts.hooks || {}
this.scrollingElement = opts.scrollingElement || null
/** /**
* Maps each DOM element to the type that it is associated with. * Maps each DOM element to the type that it is associated with.
* @type {Map} * @type {Map}
@@ -106,6 +105,17 @@ export default class DomBinding extends Binding {
createAssociation(this, target, type) 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! * NOTE: currently does not apply filter to existing elements!
* @param {FilterFunction} filter The filter function to use from now on. * @param {FilterFunction} filter The filter function to use from now on.

View File

@@ -60,8 +60,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
removeAssociation(binding, childNode, childType) removeAssociation(binding, childNode, childType)
} else { } else {
// child was moved to a different position. // child was moved to a different position.
removeAssociation(binding, childNode, childType)
childType._delete(y) childType._delete(y)
removeAssociation(binding, childNode, childType)
} }
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding) prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
} else { } else {
@@ -92,18 +92,6 @@ export default function domObserver (mutations, _document) {
const yxml = this.domToType.get(dom) const yxml = this.domToType.get(dom)
if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) { if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
// dom element is filtered // 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 return
} }
switch (mutation.type) { switch (mutation.type) {
@@ -137,6 +125,9 @@ export default function domObserver (mutations, _document) {
} }
}) })
for (let dom of diffChildren) { for (let dom of diffChildren) {
if (dom.yOnChildrenChanged !== undefined) {
dom.yOnChildrenChanged()
}
const yxml = this.domToType.get(dom) const yxml = this.domToType.get(dom)
applyChangesFromDom(this, dom, yxml, _document) applyChangesFromDom(this, dom, yxml, _document)
} }

View File

@@ -1,49 +1,13 @@
/* global getSelection */
import YXmlText from '../../Types/YXml/YXmlText.js' import YXmlText from '../../Types/YXml/YXmlText.js'
import YXmlHook from '../../Types/YXml/YXmlHook.js' import YXmlHook from '../../Types/YXml/YXmlHook.js'
import { removeDomChildrenUntilElementFound } from './util.js' import { removeDomChildrenUntilElementFound } from './util.js'
function findScrollReference (scrollingElement) {
if (scrollingElement !== null) {
let anchor = getSelection().anchorNode
if (anchor == null) {
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()
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 * @private
*/ */
export default function typeObserver (events) { export default function typeObserver (events) {
this._mutualExclude(() => { this._mutualExclude(() => {
const scrollRef = findScrollReference(this.scrollingElement)
events.forEach(event => { events.forEach(event => {
const yxml = event.target const yxml = event.target
const dom = this.typeToDom.get(yxml) const dom = this.typeToDom.get(yxml)
@@ -95,6 +59,5 @@ export default function typeObserver (events) {
} }
} }
}) })
fixScroll(this.scrollingElement, scrollRef)
}) })
} }

8
y.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
/** /**
* yjs - A framework for real-time p2p shared editing on any data * yjs - A framework for real-time p2p shared editing on any data
* @version v13.0.0-58 * @version v13.0.0-57
* @license MIT * @license MIT
*/ */
@@ -5267,48 +5267,11 @@ function afterTransactionSelectionFixer (y, domBinding, transaction, remote) {
} }
} }
/* global getSelection */
function findScrollReference (scrollingElement) {
if (scrollingElement !== null) {
let anchor = getSelection().anchorNode;
if (anchor == null) {
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();
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 * @private
*/ */
function typeObserver (events) { function typeObserver (events) {
this._mutualExclude(() => { this._mutualExclude(() => {
const scrollRef = findScrollReference(this.scrollingElement);
events.forEach(event => { events.forEach(event => {
const yxml = event.target; const yxml = event.target;
const dom = this.typeToDom.get(yxml); const dom = this.typeToDom.get(yxml);
@@ -5360,7 +5323,6 @@ function typeObserver (events) {
} }
} }
}); });
fixScroll(this.scrollingElement, scrollRef);
}); });
} }
@@ -5464,8 +5426,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
removeAssociation(binding, childNode, childType); removeAssociation(binding, childNode, childType);
} else { } else {
// child was moved to a different position. // child was moved to a different position.
removeAssociation(binding, childNode, childType);
childType._delete(y); childType._delete(y);
removeAssociation(binding, childNode, childType);
} }
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding); prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding);
} else { } else {
@@ -5496,18 +5458,6 @@ function domObserver (mutations, _document) {
const yxml = this.domToType.get(dom); const yxml = this.domToType.get(dom);
if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) { if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
// dom element is filtered // 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 return
} }
switch (mutation.type) { switch (mutation.type) {
@@ -5541,6 +5491,9 @@ function domObserver (mutations, _document) {
} }
}); });
for (let dom of diffChildren) { for (let dom of diffChildren) {
if (dom.yOnChildrenChanged !== undefined) {
dom.yOnChildrenChanged();
}
const yxml = this.domToType.get(dom); const yxml = this.domToType.get(dom);
applyChangesFromDom(this, dom, yxml, _document); applyChangesFromDom(this, dom, yxml, _document);
} }
@@ -5576,7 +5529,6 @@ class DomBinding extends Binding {
this.opts = opts; this.opts = opts;
opts.document = opts.document || document; opts.document = opts.document || document;
opts.hooks = opts.hooks || {}; opts.hooks = opts.hooks || {};
this.scrollingElement = opts.scrollingElement || null;
/** /**
* Maps each DOM element to the type that it is associated with. * Maps each DOM element to the type that it is associated with.
* @type {Map} * @type {Map}
@@ -5649,6 +5601,17 @@ class DomBinding extends Binding {
createAssociation(this, target, type); 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! * NOTE: currently does not apply filter to existing elements!
* @param {FilterFunction} filter The filter function to use from now on. * @param {FilterFunction} filter The filter function to use from now on.

File diff suppressed because one or more lines are too long

101
y.test.js
View File

@@ -18334,48 +18334,8 @@ function afterTransactionSelectionFixer (y, domBinding, transaction, remote) {
} }
} }
/* global getSelection */
function findScrollReference (scrollingElement) {
if (scrollingElement !== null) {
let anchor = getSelection().anchorNode;
if (anchor == null) {
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();
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
*/
function typeObserver (events) { function typeObserver (events) {
this._mutualExclude(() => { this._mutualExclude(() => {
const scrollRef = findScrollReference(this.scrollingElement);
events.forEach(event => { events.forEach(event => {
const yxml = event.target; const yxml = event.target;
const dom = this.typeToDom.get(yxml); const dom = this.typeToDom.get(yxml);
@@ -18427,7 +18387,6 @@ function typeObserver (events) {
} }
} }
}); });
fixScroll(this.scrollingElement, scrollRef);
}); });
} }
@@ -18478,18 +18437,6 @@ function simpleDiff (a, b) {
} }
} }
/**
* 1. Check if any of the nodes was deleted
* 2. Iterate over the children.
* 2.1 If a node exists that is not yet bound to a type, insert a new node
* 2.2 If _contents.length < dom.childNodes.length, fill the
* rest of _content with childNodes
* 2.3 If a node was moved, delete it and
* recreate a new yxml element that is bound to that node.
* You can detect that a node was moved because expectedId
* !== actualId in the list
* @private
*/
function applyChangesFromDom (binding, dom, yxml, _document) { function applyChangesFromDom (binding, dom, yxml, _document) {
if (yxml == null || yxml === false || yxml.constructor === YXmlHook) { if (yxml == null || yxml === false || yxml.constructor === YXmlHook) {
return return
@@ -18531,8 +18478,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
removeAssociation(binding, childNode, childType); removeAssociation(binding, childNode, childType);
} else { } else {
// child was moved to a different position. // child was moved to a different position.
removeAssociation(binding, childNode, childType);
childType._delete(y); childType._delete(y);
removeAssociation(binding, childNode, childType);
} }
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding); prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding);
} else { } else {
@@ -18563,18 +18510,6 @@ function domObserver (mutations, _document) {
const yxml = this.domToType.get(dom); const yxml = this.domToType.get(dom);
if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) { if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
// dom element is filtered // 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 return
} }
switch (mutation.type) { switch (mutation.type) {
@@ -18608,6 +18543,9 @@ function domObserver (mutations, _document) {
} }
}); });
for (let dom of diffChildren) { for (let dom of diffChildren) {
if (dom.yOnChildrenChanged !== undefined) {
dom.yOnChildrenChanged();
}
const yxml = this.domToType.get(dom); const yxml = this.domToType.get(dom);
applyChangesFromDom(this, dom, yxml, _document); applyChangesFromDom(this, dom, yxml, _document);
} }
@@ -18632,7 +18570,6 @@ class DomBinding extends Binding {
this.opts = opts; this.opts = opts;
opts.document = opts.document || document; opts.document = opts.document || document;
opts.hooks = opts.hooks || {}; opts.hooks = opts.hooks || {};
this.scrollingElement = opts.scrollingElement || null;
/** /**
* Maps each DOM element to the type that it is associated with. * Maps each DOM element to the type that it is associated with.
* @type {Map} * @type {Map}
@@ -18705,6 +18642,17 @@ class DomBinding extends Binding {
createAssociation(this, target, type); 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! * NOTE: currently does not apply filter to existing elements!
* @param {FilterFunction} filter The filter function to use from now on. * @param {FilterFunction} filter The filter function to use from now on.
@@ -18739,6 +18687,25 @@ class DomBinding extends Binding {
* @typedef {function(nodeName: String, attrs: Map): Map|null} FilterFunction * @typedef {function(nodeName: String, attrs: Map): Map|null} FilterFunction
*/ */
/**
* Anything that can be encoded with `JSON.stringify` and can be decoded with
* `JSON.parse`.
*
* The following property should hold:
* `JSON.parse(JSON.stringify(key))===key`
*
* At the moment the only safe values are number and string.
*
* @typedef {(number|string)} encodable
*/
/**
* A Yjs instance handles the state of shared data.
*
* @param {string} room Users in the same room share the same content
* @param {Object} opts Connector definition
* @param {AbstractPersistence} persistence Persistence adapter instance
*/
class Y$1 extends NamedEventHandler { class Y$1 extends NamedEventHandler {
constructor (room, opts, persistence, conf = {}) { constructor (room, opts, persistence, conf = {}) {
super(); super();

File diff suppressed because one or more lines are too long