Compare commits
1 Commits
v13.0.0-60
...
v13.0.0-57
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bac7362c2 |
@@ -1,7 +1,7 @@
|
||||
/* global Y */
|
||||
|
||||
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', {
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yjs",
|
||||
"version": "13.0.0-60",
|
||||
"version": "13.0.0-57",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yjs",
|
||||
"version": "13.0.0-60",
|
||||
"version": "13.0.0-57",
|
||||
"description": "A framework for real-time p2p shared editing on any data",
|
||||
"main": "./y.node.js",
|
||||
"browser": "./y.js",
|
||||
@@ -71,5 +71,8 @@
|
||||
"rollup-watch": "^3.2.2",
|
||||
"standard": "^10.0.2",
|
||||
"tag-dist-files": "^0.1.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^2.6.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ 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}
|
||||
@@ -106,6 +105,17 @@ 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.
|
||||
|
||||
@@ -60,8 +60,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
|
||||
removeAssociation(binding, childNode, childType)
|
||||
} else {
|
||||
// child was moved to a different position.
|
||||
removeAssociation(binding, childNode, childType)
|
||||
childType._delete(y)
|
||||
removeAssociation(binding, childNode, childType)
|
||||
}
|
||||
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
|
||||
} else {
|
||||
@@ -90,19 +90,8 @@ export default function domObserver (mutations, _document) {
|
||||
mutations.forEach(mutation => {
|
||||
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 = dom
|
||||
let yParent
|
||||
do {
|
||||
parent = parent.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
|
||||
if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
|
||||
// dom element is filtered
|
||||
return
|
||||
}
|
||||
switch (mutation.type) {
|
||||
@@ -136,6 +125,9 @@ 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)
|
||||
}
|
||||
|
||||
@@ -1,49 +1,13 @@
|
||||
/* 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 // 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
|
||||
*/
|
||||
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)
|
||||
@@ -95,6 +59,5 @@ export default function typeObserver (events) {
|
||||
}
|
||||
}
|
||||
})
|
||||
fixScroll(this.scrollingElement, scrollRef)
|
||||
})
|
||||
}
|
||||
|
||||
72
y.node.js
72
y.node.js
@@ -1,7 +1,7 @@
|
||||
|
||||
/**
|
||||
* yjs - A framework for real-time p2p shared editing on any data
|
||||
* @version v13.0.0-60
|
||||
* @version v13.0.0-57
|
||||
* @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
|
||||
*/
|
||||
function typeObserver (events) {
|
||||
this._mutualExclude(() => {
|
||||
const scrollRef = findScrollReference(this.scrollingElement);
|
||||
events.forEach(event => {
|
||||
const yxml = event.target;
|
||||
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);
|
||||
} else {
|
||||
// child was moved to a different position.
|
||||
removeAssociation(binding, childNode, childType);
|
||||
childType._delete(y);
|
||||
removeAssociation(binding, childNode, childType);
|
||||
}
|
||||
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding);
|
||||
} else {
|
||||
@@ -5494,19 +5456,8 @@ function domObserver (mutations, _document) {
|
||||
mutations.forEach(mutation => {
|
||||
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 = dom;
|
||||
let yParent;
|
||||
do {
|
||||
parent = parent.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
|
||||
if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
|
||||
// dom element is filtered
|
||||
return
|
||||
}
|
||||
switch (mutation.type) {
|
||||
@@ -5540,6 +5491,9 @@ 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);
|
||||
}
|
||||
@@ -5575,7 +5529,6 @@ 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}
|
||||
@@ -5648,6 +5601,17 @@ 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.
|
||||
|
||||
File diff suppressed because one or more lines are too long
305
y.test.js
305
y.test.js
@@ -13552,6 +13552,9 @@ function test (testDescription, ...args) {
|
||||
testHandler.register(testCase);
|
||||
}
|
||||
|
||||
|
||||
//# sourceMappingURL=cutest.mjs.map
|
||||
|
||||
proxyConsole();
|
||||
|
||||
var numberOfRBTreeTests = 10000;
|
||||
@@ -13827,9 +13830,6 @@ class DeleteStore extends Tree {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A BinaryDecoder handles the decoding of an ArrayBuffer.
|
||||
*/
|
||||
class BinaryDecoder {
|
||||
/**
|
||||
* @param {Uint8Array|Buffer} buffer The binary data that this instance
|
||||
@@ -13976,7 +13976,6 @@ class BinaryDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO should have the same base class as Item
|
||||
class GC {
|
||||
constructor () {
|
||||
this._id = null;
|
||||
@@ -14613,11 +14612,6 @@ function logItemHelper (name, item, append) {
|
||||
return `${name}(id:${logID(item._id)},start:${logID(item._start)},left:${logID(left)},origin:${logID(origin)},right:${logID(item._right)},parent:${logID(item._parent)},parentSub:${item._parentSub}${append !== undefined ? ' - ' + append : ''})`
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Delete all items in an ID-range
|
||||
* TODO: implement getItemCleanStartNode for better performance (only one lookup)
|
||||
*/
|
||||
function deleteItemRange (y, user, clock, range, gcChildren) {
|
||||
const createDelete = y.connector !== null && y.connector._forwardAppliedStructs;
|
||||
let item = y.os.getItemCleanStart(new ID(user, clock));
|
||||
@@ -14810,14 +14804,6 @@ function transactionTypeChanged (y, type, sub) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Helper utility to split an Item (see {@link Item#_splitAt})
|
||||
* - copies all properties from a to b
|
||||
* - connects a to b
|
||||
* - assigns the correct _id
|
||||
* - saves b to os
|
||||
*/
|
||||
function splitHelper (y, a, b, diff) {
|
||||
const aID = a._id;
|
||||
b._id = new ID(aID.user, aID.clock + diff);
|
||||
@@ -15400,7 +15386,6 @@ class EventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// restructure children as if they were inserted one after another
|
||||
function integrateChildren (y, start) {
|
||||
let right;
|
||||
do {
|
||||
@@ -15774,13 +15759,6 @@ class YEvent {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that describes the changes on a YArray
|
||||
*
|
||||
* @param {YArray} yarray The changed type
|
||||
* @param {Boolean} remote Whether the changed was caused by a remote peer
|
||||
* @param {Transaction} transaction The transaction object
|
||||
*/
|
||||
class YArrayEvent extends YEvent {
|
||||
constructor (yarray, remote, transaction) {
|
||||
super(yarray);
|
||||
@@ -16147,13 +16125,6 @@ class YArray extends Type {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that describes the changes on a YMap.
|
||||
*
|
||||
* @param {YMap} ymap The YArray that changed.
|
||||
* @param {Set<any>} subs The keys that changed.
|
||||
* @param {boolean} remote Whether the change was created by a remote peer.
|
||||
*/
|
||||
class YMapEvent extends YEvent {
|
||||
constructor (ymap, subs, remote) {
|
||||
super(ymap);
|
||||
@@ -16390,9 +16361,6 @@ class ItemFormat extends Item {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function integrateItem (item, parent, y, left, right) {
|
||||
item._origin = left;
|
||||
item._left = left;
|
||||
@@ -17059,14 +17027,6 @@ function isParentOf (parent, child) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Default filter method (does nothing).
|
||||
*
|
||||
* @param {String} nodeName The nodeName of the element
|
||||
* @param {Map} attrs Map of key-value pairs that are attributes of the node.
|
||||
* @return {Map | null} The allowed attributes or null, if the element should be
|
||||
* filtered.
|
||||
*/
|
||||
function defaultFilter (nodeName, attrs) {
|
||||
// TODO: implement basic filter that filters out dangerous properties!
|
||||
return attrs
|
||||
@@ -17118,16 +17078,6 @@ function applyFilterOnType (y, binding, type) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Yjs type (YXml) based on the contents of a DOM Element.
|
||||
*
|
||||
* @param {Element|TextNode} element The DOM Element
|
||||
* @param {?Document} _document Optional. Provide the global document object
|
||||
* @param {Hooks} [hooks = {}] Optional. Set of Yjs Hooks
|
||||
* @param {Filter} [filter=defaultFilter] Optional. Dom element filter
|
||||
* @param {?DomBinding} binding Warning: This property is for internal use only!
|
||||
* @return {YXmlElement | YXmlText}
|
||||
*/
|
||||
function domToType (element, _document = document, hooks = {}, filter = defaultFilter, binding) {
|
||||
let type;
|
||||
switch (element.nodeType) {
|
||||
@@ -17173,11 +17123,6 @@ function domToType (element, _document = document, hooks = {}, filter = defaultF
|
||||
return type
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates items until an undeleted item is found.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function iterateUntilUndeleted (item) {
|
||||
while (item !== null && item._deleted) {
|
||||
item = item._right;
|
||||
@@ -17295,26 +17240,6 @@ function removeDomChildrenUntilElementFound (parent, currentChild, elem) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the elements to which a set of CSS queries apply.
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
|
||||
*
|
||||
* @example
|
||||
* query = '.classSelector'
|
||||
* query = 'nodeSelector'
|
||||
* query = '#idSelector'
|
||||
*
|
||||
* @typedef {string} CSS_Selector
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a subset of the nodes of a YXmlElement / YXmlFragment and a
|
||||
* position within them.
|
||||
*
|
||||
* Can be created with {@link YXmlFragment#createTreeWalker}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
class YXmlTreeWalker {
|
||||
constructor (root, f) {
|
||||
this._filter = f || (() => true);
|
||||
@@ -17370,11 +17295,6 @@ class YXmlTreeWalker {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Event that describes changes on a YXml Element or Yxml Fragment
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
class YXmlEvent extends YEvent {
|
||||
/**
|
||||
* @param {YType} target The target on which the event is created.
|
||||
@@ -17416,35 +17336,6 @@ class YXmlEvent extends YEvent {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dom filter function.
|
||||
*
|
||||
* @callback domFilter
|
||||
* @param {string} nodeName The nodeName of the element
|
||||
* @param {Map} attributes The map of attributes.
|
||||
* @return {boolean} Whether to include the Dom node in the YXmlElement.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Define the elements to which a set of CSS queries apply.
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
|
||||
*
|
||||
* @example
|
||||
* query = '.classSelector'
|
||||
* query = 'nodeSelector'
|
||||
* query = '#idSelector'
|
||||
*
|
||||
* @typedef {string} CSS_Selector
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a list of {@link YXmlElement}.and {@link YXmlText} types.
|
||||
* A YxmlFragment is similar to a {@link YXmlElement}, but it does not have a
|
||||
* nodeName and it does not have attributes. Though it can be bound to a DOM
|
||||
* element - in this case the attributes and the nodeName are not shared.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
class YXmlFragment extends YArray {
|
||||
/**
|
||||
* Create a subtree of childNodes.
|
||||
@@ -17577,15 +17468,6 @@ class YXmlFragment extends YArray {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An YXmlElement imitates the behavior of a
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}.
|
||||
*
|
||||
* * An YXmlElement has attributes (key value pairs)
|
||||
* * An YXmlElement has childElements that must inherit from YXmlElement
|
||||
*
|
||||
* @param {String} nodeName Node name
|
||||
*/
|
||||
class YXmlElement extends YXmlFragment {
|
||||
constructor (nodeName = 'UNDEFINED') {
|
||||
super();
|
||||
@@ -17762,11 +17644,6 @@ class YXmlElement extends YXmlFragment {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* You can manage binding to a custom type with YXmlHook.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
class YXmlHook extends YMap {
|
||||
/**
|
||||
* @param {String} hookName nodeName of the Dom Node.
|
||||
@@ -17868,12 +17745,6 @@ class YXmlHook extends YMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents text in a Dom Element. In the future this type will also handle
|
||||
* simple formatting information like bold and italic.
|
||||
*
|
||||
* @param {String} arg1 Initial value.
|
||||
*/
|
||||
class YXmlText extends YText {
|
||||
/**
|
||||
* Creates a Dom Element that mirrors this YXmlText.
|
||||
@@ -18281,21 +18152,6 @@ function createMutualExclude () {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class for bindings.
|
||||
*
|
||||
* A binding handles data binding from a Yjs type to a data object. For example,
|
||||
* you can bind a Quill editor instance to a YText instance with the `QuillBinding` class.
|
||||
*
|
||||
* It is expected that a concrete implementation accepts two parameters
|
||||
* (type and binding target).
|
||||
*
|
||||
* @example
|
||||
* const quill = new Quill(document.createElement('div'))
|
||||
* const type = y.define('quill', Y.Text)
|
||||
* const binding = new Y.QuillBinding(quill, type)
|
||||
*
|
||||
*/
|
||||
class Binding {
|
||||
/**
|
||||
* @param {YType} type Yjs type.
|
||||
@@ -18326,43 +18182,6 @@ class Binding {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement function to describe ranges
|
||||
|
||||
/**
|
||||
* A relative position that is based on the Yjs model. In contrast to an
|
||||
* absolute position (position by index), the relative position can be
|
||||
* recomputed when remote changes are received. For example:
|
||||
*
|
||||
* ```Insert(0, 'x')('a|bc') = 'xa|bc'``` Where | is the cursor position.
|
||||
*
|
||||
* A relative cursor position can be obtained with the function
|
||||
* {@link getRelativePosition} and it can be transformed to an absolute position
|
||||
* with {@link fromRelativePosition}.
|
||||
*
|
||||
* Pro tip: Use this to implement shared cursor locations in YText or YXml!
|
||||
* The relative position is {@link encodable}, so you can send it to other
|
||||
* clients.
|
||||
*
|
||||
* @example
|
||||
* // Current cursor position is at position 10
|
||||
* let relativePosition = getRelativePosition(yText, 10)
|
||||
* // modify yText
|
||||
* yText.insert(0, 'abc')
|
||||
* yText.delete(3, 10)
|
||||
* // Compute the cursor position
|
||||
* let absolutePosition = fromRelativePosition(y, relativePosition)
|
||||
* absolutePosition.type // => yText
|
||||
* console.log('cursor location is ' + absolutePosition.offset) // => cursor location is 3
|
||||
*
|
||||
* @typedef {encodable} RelativePosition
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a relativePosition based on a absolute position.
|
||||
*
|
||||
* @param {YType} type The base type (e.g. YText or YArray).
|
||||
* @param {Integer} offset The absolute position.
|
||||
*/
|
||||
function getRelativePosition (type, offset) {
|
||||
// TODO: rename to createRelativePosition
|
||||
let t = type._start;
|
||||
@@ -18515,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) {
|
||||
this._mutualExclude(() => {
|
||||
const scrollRef = findScrollReference(this.scrollingElement);
|
||||
events.forEach(event => {
|
||||
const yxml = event.target;
|
||||
const dom = this.typeToDom.get(yxml);
|
||||
@@ -18608,7 +18387,6 @@ function typeObserver (events) {
|
||||
}
|
||||
}
|
||||
});
|
||||
fixScroll(this.scrollingElement, scrollRef);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18659,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) {
|
||||
if (yxml == null || yxml === false || yxml.constructor === YXmlHook) {
|
||||
return
|
||||
@@ -18712,8 +18478,8 @@ function applyChangesFromDom (binding, dom, yxml, _document) {
|
||||
removeAssociation(binding, childNode, childType);
|
||||
} else {
|
||||
// child was moved to a different position.
|
||||
removeAssociation(binding, childNode, childType);
|
||||
childType._delete(y);
|
||||
removeAssociation(binding, childNode, childType);
|
||||
}
|
||||
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding);
|
||||
} else {
|
||||
@@ -18742,19 +18508,8 @@ function domObserver (mutations, _document) {
|
||||
mutations.forEach(mutation => {
|
||||
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 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
|
||||
if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
|
||||
// dom element is filtered
|
||||
return
|
||||
}
|
||||
switch (mutation.type) {
|
||||
@@ -18788,6 +18543,9 @@ 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);
|
||||
}
|
||||
@@ -18797,17 +18555,6 @@ function domObserver (mutations, _document) {
|
||||
|
||||
/* global MutationObserver */
|
||||
|
||||
/**
|
||||
* A binding that binds the children of a YXmlFragment to a DOM element.
|
||||
*
|
||||
* This binding is automatically destroyed when its parent is deleted.
|
||||
*
|
||||
* @example
|
||||
* const div = document.createElement('div')
|
||||
* const type = y.define('xml', Y.XmlFragment)
|
||||
* const binding = new Y.QuillBinding(type, div)
|
||||
*
|
||||
*/
|
||||
class DomBinding extends Binding {
|
||||
/**
|
||||
* @param {YXmlFragment} type The bind source. This is the ultimate source of
|
||||
@@ -18823,7 +18570,6 @@ 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}
|
||||
@@ -18896,6 +18642,17 @@ 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.
|
||||
@@ -19895,8 +19652,6 @@ var browser_5 = browser.useColors;
|
||||
var browser_6 = browser.storage;
|
||||
var browser_7 = browser.colors;
|
||||
|
||||
// TODO: rename Connector
|
||||
|
||||
class AbstractConnector {
|
||||
constructor (y, opts) {
|
||||
this.y = y;
|
||||
@@ -20184,12 +19939,6 @@ class AbstractConnector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the Decoder and fill the Yjs instance with data in the decoder.
|
||||
*
|
||||
* @param {Y} y The Yjs instance
|
||||
* @param {BinaryDecoder} decoder The BinaryDecoder to read from.
|
||||
*/
|
||||
function fromBinary (y, decoder) {
|
||||
y.transact(function () {
|
||||
integrateRemoteStructs(y, decoder);
|
||||
@@ -20432,7 +20181,6 @@ class QuillBinding extends Binding {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The following assignments should be moved to yjs-dist
|
||||
Y$1.AbstractConnector = AbstractConnector;
|
||||
Y$1.AbstractPersistence = AbstractPersistence;
|
||||
Y$1.Array = YArray;
|
||||
@@ -20625,19 +20373,6 @@ class TestConnector extends AbstractConnector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to merge all items in os with their successors.
|
||||
*
|
||||
* Some transformations (like delete) fragment items.
|
||||
* Item(c: 'ab') + Delete(1,1) + Delete(0, 1) -> Item(c: 'a',deleted);Item(c: 'b',deleted)
|
||||
*
|
||||
* This functions merges the fragmented nodes together:
|
||||
* Item(c: 'a',deleted);Item(c: 'b',deleted) -> Item(c: 'ab', deleted)
|
||||
*
|
||||
* TODO: The Tree implementation does not support deletions in-spot.
|
||||
* This is why all deletions must be performed after the traversal.
|
||||
*
|
||||
*/
|
||||
function defragmentItemContent (y) {
|
||||
const os = y.os;
|
||||
if (os.length < 2) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user