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