diff --git a/README.md b/README.md index 60dcf892..d36b15b8 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,8 @@ necessary.

const yarray = new Y.Array()
+ parent:Y.AbstractType|null +
insert(index:number, content:Array<object|boolean|Array|string|number|Uint8Array|Y.Type>)
Insert content at index. Note that content is an array of elements. @@ -312,6 +314,8 @@ or any of its children.

const ymap = new Y.Map()
+ parent:Y.AbstractType|null +
get(key:string):object|boolean|string|number|Uint8Array|Y.Type
set(key:string, value:object|boolean|string|number|Uint8Array|Y.Type) @@ -391,6 +395,8 @@ YTextEvents compute changes as deltas.

const ytext = new Y.Text()
+ parent:Y.AbstractType|null +
insert(index:number, content:string, [formattingAttributes:Object<string,string>])
Insert a string at index and assign formatting attributes to it. @@ -449,6 +455,10 @@ or any of its children.

const yxml = new Y.XmlFragment()
+ parent:Y.AbstractType|null +
+ firstChild:Y.XmlElement|Y.XmlText|null +
insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)
delete(index:number, length:number) @@ -504,6 +514,14 @@ content and be actually XML compliant.

const yxml = new Y.XmlElement()
+ parent:Y.AbstractType|null +
+ firstChild:Y.XmlElement|Y.XmlText|null +
+ nextSibling:Y.XmlElement|Y.XmlText|null +
+ prevSibling:Y.XmlElement|Y.XmlText|null +
insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)
delete(index:number, length:number) diff --git a/src/types/AbstractType.js b/src/types/AbstractType.js index c3513d68..3b6aa581 100644 --- a/src/types/AbstractType.js +++ b/src/types/AbstractType.js @@ -287,6 +287,13 @@ export class AbstractType { this._searchMarker = null } + /** + * @return {AbstractType|null} + */ + get parent () { + return this._item ? /** @type {AbstractType} */ (this._item.parent) : null + } + /** * Integrate this type into the Yjs instance. * diff --git a/src/types/YXmlElement.js b/src/types/YXmlElement.js index 0757e1b2..3b64fa51 100644 --- a/src/types/YXmlElement.js +++ b/src/types/YXmlElement.js @@ -8,7 +8,7 @@ import { typeMapGetAll, typeListForEach, YXmlElementRefID, - AbstractType, AbstractUpdateDecoder, AbstractUpdateEncoder, Snapshot, Doc, Item // eslint-disable-line + YXmlText, ContentType, AbstractType, AbstractUpdateDecoder, AbstractUpdateEncoder, Snapshot, Doc, Item // eslint-disable-line } from '../internals.js' /** @@ -28,6 +28,22 @@ export class YXmlElement extends YXmlFragment { this._prelimAttrs = new Map() } + /** + * @type {YXmlElement|YXmlText|null} + */ + get nextSibling () { + const n = this._item ? this._item.next : null + return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null + } + + /** + * @type {YXmlElement|YXmlText|null} + */ + get prevSibling () { + const n = this._item ? this._item.prev : null + return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null + } + /** * Integrate this type into the Yjs instance. * diff --git a/src/types/YXmlFragment.js b/src/types/YXmlFragment.js index 711c9687..41c581e1 100644 --- a/src/types/YXmlFragment.js +++ b/src/types/YXmlFragment.js @@ -130,6 +130,14 @@ export class YXmlFragment extends AbstractType { this._prelimContent = [] } + /** + * @type {YXmlElement|YXmlText|null} + */ + get firstChild () { + const first = this._first + return first ? first.content.getContent()[0] : null + } + /** * Integrate this type into the Yjs instance. * diff --git a/src/types/YXmlText.js b/src/types/YXmlText.js index 697e31c9..dd8d892d 100644 --- a/src/types/YXmlText.js +++ b/src/types/YXmlText.js @@ -2,7 +2,7 @@ import { YText, YXmlTextRefID, - AbstractUpdateDecoder, AbstractUpdateEncoder // eslint-disable-line + ContentType, YXmlElement, AbstractUpdateDecoder, AbstractUpdateEncoder // eslint-disable-line } from '../internals.js' /** @@ -10,6 +10,22 @@ import { * simple formatting information like bold and italic. */ export class YXmlText extends YText { + /** + * @type {YXmlElement|YXmlText|null} + */ + get nextSibling () { + const n = this._item ? this._item.next : null + return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null + } + + /** + * @type {YXmlElement|YXmlText|null} + */ + get prevSibling () { + const n = this._item ? this._item.prev : null + return n ? /** @type {YXmlElement|YXmlText} */ (/** @type {ContentType} */ (n.content).type) : null + } + _copy () { return new YXmlText() } diff --git a/tests/y-xml.tests.js b/tests/y-xml.tests.js index d59ee6c8..48132175 100644 --- a/tests/y-xml.tests.js +++ b/tests/y-xml.tests.js @@ -87,3 +87,19 @@ export const testYtextAttributes = tc => { t.compare(ytext.getAttribute('test'), 42) t.compare(ytext.getAttributes(), { test: 42 }) } + +/** + * @param {t.TestCase} tc + */ +export const testSiblings = tc => { + const ydoc = new Y.Doc() + const yxml = ydoc.getXmlFragment() + const first = new Y.XmlText() + const second = new Y.XmlElement('p') + yxml.insert(0, [first, second]) + t.assert(first.nextSibling === second) + t.assert(second.prevSibling === first) + t.assert(first.parent === yxml) + t.assert(yxml.parent === null) + t.assert(yxml.firstChild === first) +}