Merge pull request #267 from yjs/wishlist-259
Implements some features of wishlist #259
This commit is contained in:
commit
d3b56702ad
18
README.md
18
README.md
@ -242,6 +242,8 @@ necessary.
|
|||||||
</p>
|
</p>
|
||||||
<pre>const yarray = new Y.Array()</pre>
|
<pre>const yarray = new Y.Array()</pre>
|
||||||
<dl>
|
<dl>
|
||||||
|
<b><code>parent:Y.AbstractType|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
<b><code>insert(index:number, content:Array<object|boolean|Array|string|number|Uint8Array|Y.Type>)</code></b>
|
<b><code>insert(index:number, content:Array<object|boolean|Array|string|number|Uint8Array|Y.Type>)</code></b>
|
||||||
<dd>
|
<dd>
|
||||||
Insert content at <var>index</var>. Note that content is an array of elements.
|
Insert content at <var>index</var>. Note that content is an array of elements.
|
||||||
@ -313,6 +315,8 @@ or any of its children.
|
|||||||
</p>
|
</p>
|
||||||
<pre><code>const ymap = new Y.Map()</code></pre>
|
<pre><code>const ymap = new Y.Map()</code></pre>
|
||||||
<dl>
|
<dl>
|
||||||
|
<b><code>parent:Y.AbstractType|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
<b><code>get(key:string):object|boolean|string|number|Uint8Array|Y.Type</code></b>
|
<b><code>get(key:string):object|boolean|string|number|Uint8Array|Y.Type</code></b>
|
||||||
<dd></dd>
|
<dd></dd>
|
||||||
<b><code>set(key:string, value:object|boolean|string|number|Uint8Array|Y.Type)</code></b>
|
<b><code>set(key:string, value:object|boolean|string|number|Uint8Array|Y.Type)</code></b>
|
||||||
@ -392,6 +396,8 @@ YTextEvents compute changes as deltas.
|
|||||||
</p>
|
</p>
|
||||||
<pre>const ytext = new Y.Text()</pre>
|
<pre>const ytext = new Y.Text()</pre>
|
||||||
<dl>
|
<dl>
|
||||||
|
<b><code>parent:Y.AbstractType|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
<b><code>insert(index:number, content:string, [formattingAttributes:Object<string,string>])</code></b>
|
<b><code>insert(index:number, content:string, [formattingAttributes:Object<string,string>])</code></b>
|
||||||
<dd>
|
<dd>
|
||||||
Insert a string at <var>index</var> and assign formatting attributes to it.
|
Insert a string at <var>index</var> and assign formatting attributes to it.
|
||||||
@ -450,6 +456,10 @@ or any of its children.
|
|||||||
</p>
|
</p>
|
||||||
<pre><code>const yxml = new Y.XmlFragment()</code></pre>
|
<pre><code>const yxml = new Y.XmlFragment()</code></pre>
|
||||||
<dl>
|
<dl>
|
||||||
|
<b><code>parent:Y.AbstractType|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
|
<b><code>firstChild:Y.XmlElement|Y.XmlText|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
<b><code>insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)</code></b>
|
<b><code>insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)</code></b>
|
||||||
<dd></dd>
|
<dd></dd>
|
||||||
<b><code>delete(index:number, length:number)</code></b>
|
<b><code>delete(index:number, length:number)</code></b>
|
||||||
@ -505,6 +515,14 @@ content and be actually XML compliant.
|
|||||||
</p>
|
</p>
|
||||||
<pre><code>const yxml = new Y.XmlElement()</code></pre>
|
<pre><code>const yxml = new Y.XmlElement()</code></pre>
|
||||||
<dl>
|
<dl>
|
||||||
|
<b><code>parent:Y.AbstractType|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
|
<b><code>firstChild:Y.XmlElement|Y.XmlText|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
|
<b><code>nextSibling:Y.XmlElement|Y.XmlText|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
|
<b><code>prevSibling:Y.XmlElement|Y.XmlText|null</code></b>
|
||||||
|
<dd></dd>
|
||||||
<b><code>insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)</code></b>
|
<b><code>insert(index:number, content:Array<Y.XmlElement|Y.XmlText>)</code></b>
|
||||||
<dd></dd>
|
<dd></dd>
|
||||||
<b><code>delete(index:number, length:number)</code></b>
|
<b><code>delete(index:number, length:number)</code></b>
|
||||||
|
@ -287,6 +287,13 @@ export class AbstractType {
|
|||||||
this._searchMarker = null
|
this._searchMarker = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {AbstractType<any>|null}
|
||||||
|
*/
|
||||||
|
get parent () {
|
||||||
|
return this._item ? /** @type {AbstractType<any>} */ (this._item.parent) : null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integrate this type into the Yjs instance.
|
* Integrate this type into the Yjs instance.
|
||||||
*
|
*
|
||||||
|
@ -21,6 +21,10 @@ import {
|
|||||||
iterateDeletedStructs,
|
iterateDeletedStructs,
|
||||||
iterateStructs,
|
iterateStructs,
|
||||||
findMarker,
|
findMarker,
|
||||||
|
typeMapDelete,
|
||||||
|
typeMapSet,
|
||||||
|
typeMapGet,
|
||||||
|
typeMapGetAll,
|
||||||
updateMarkerChanges,
|
updateMarkerChanges,
|
||||||
ArraySearchMarker, AbstractUpdateDecoder, AbstractUpdateEncoder, ID, Doc, Item, Snapshot, Transaction // eslint-disable-line
|
ArraySearchMarker, AbstractUpdateDecoder, AbstractUpdateEncoder, ID, Doc, Item, Snapshot, Transaction // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
@ -512,13 +516,32 @@ export class YTextEvent extends YEvent {
|
|||||||
/**
|
/**
|
||||||
* @param {YText} ytext
|
* @param {YText} ytext
|
||||||
* @param {Transaction} transaction
|
* @param {Transaction} transaction
|
||||||
|
* @param {Set<any>} subs The keys that changed
|
||||||
*/
|
*/
|
||||||
constructor (ytext, transaction) {
|
constructor (ytext, transaction, subs) {
|
||||||
super(ytext, transaction)
|
super(ytext, transaction)
|
||||||
/**
|
/**
|
||||||
* @type {Array<DeltaItem>|null}
|
* @type {Array<DeltaItem>|null}
|
||||||
*/
|
*/
|
||||||
this._delta = null
|
this._delta = null
|
||||||
|
/**
|
||||||
|
* Whether the children changed.
|
||||||
|
* @type {Boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.childListChanged = false
|
||||||
|
/**
|
||||||
|
* Set of all changed attributes.
|
||||||
|
* @type {Set<string>}
|
||||||
|
*/
|
||||||
|
this.keysChanged = new Set()
|
||||||
|
subs.forEach((sub) => {
|
||||||
|
if (sub === null) {
|
||||||
|
this.childListChanged = true
|
||||||
|
} else {
|
||||||
|
this.keysChanged.add(sub)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -779,7 +802,7 @@ export class YText extends AbstractType {
|
|||||||
*/
|
*/
|
||||||
_callObserver (transaction, parentSubs) {
|
_callObserver (transaction, parentSubs) {
|
||||||
super._callObserver(transaction, parentSubs)
|
super._callObserver(transaction, parentSubs)
|
||||||
const event = new YTextEvent(this, transaction)
|
const event = new YTextEvent(this, transaction, parentSubs)
|
||||||
const doc = transaction.doc
|
const doc = transaction.doc
|
||||||
// If a remote change happened, we try to cleanup potential formatting duplicates.
|
// If a remote change happened, we try to cleanup potential formatting duplicates.
|
||||||
if (!transaction.local) {
|
if (!transaction.local) {
|
||||||
@ -1111,6 +1134,74 @@ export class YText extends AbstractType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an attribute.
|
||||||
|
*
|
||||||
|
* @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
|
||||||
|
*
|
||||||
|
* @param {String} attributeName The attribute name that is to be removed.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
removeAttribute (attributeName) {
|
||||||
|
if (this.doc !== null) {
|
||||||
|
transact(this.doc, transaction => {
|
||||||
|
typeMapDelete(transaction, this, attributeName)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
/** @type {Array<function>} */ (this._pending).push(() => this.removeAttribute(attributeName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets or updates an attribute.
|
||||||
|
*
|
||||||
|
* @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
|
||||||
|
*
|
||||||
|
* @param {String} attributeName The attribute name that is to be set.
|
||||||
|
* @param {any} attributeValue The attribute value that is to be set.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
setAttribute (attributeName, attributeValue) {
|
||||||
|
if (this.doc !== null) {
|
||||||
|
transact(this.doc, transaction => {
|
||||||
|
typeMapSet(transaction, this, attributeName, attributeValue)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
/** @type {Array<function>} */ (this._pending).push(() => this.setAttribute(attributeName, attributeValue))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an attribute value that belongs to the attribute name.
|
||||||
|
*
|
||||||
|
* @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
|
||||||
|
*
|
||||||
|
* @param {String} attributeName The attribute name that identifies the
|
||||||
|
* queried value.
|
||||||
|
* @return {any} The queried attribute value.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
getAttribute (attributeName) {
|
||||||
|
return /** @type {any} */ (typeMapGet(this, attributeName))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all attribute name/value pairs in a JSON Object.
|
||||||
|
*
|
||||||
|
* @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks.
|
||||||
|
*
|
||||||
|
* @param {Snapshot} [snapshot]
|
||||||
|
* @return {Object<string, any>} A JSON Object that describes the attributes.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
getAttributes (snapshot) {
|
||||||
|
return typeMapGetAll(this)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {AbstractUpdateEncoder} encoder
|
* @param {AbstractUpdateEncoder} encoder
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
typeMapGetAll,
|
typeMapGetAll,
|
||||||
typeListForEach,
|
typeListForEach,
|
||||||
YXmlElementRefID,
|
YXmlElementRefID,
|
||||||
AbstractType, AbstractUpdateDecoder, AbstractUpdateEncoder, Snapshot, Doc, Item // eslint-disable-line
|
YXmlText, ContentType, AbstractType, AbstractUpdateDecoder, AbstractUpdateEncoder, Snapshot, Doc, Item // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,6 +28,22 @@ export class YXmlElement extends YXmlFragment {
|
|||||||
this._prelimAttrs = new Map()
|
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.
|
* Integrate this type into the Yjs instance.
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
YEvent,
|
YEvent,
|
||||||
YXmlElement, YXmlFragment, Transaction // eslint-disable-line
|
YXmlText, YXmlElement, YXmlFragment, Transaction // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,7 +9,7 @@ import {
|
|||||||
*/
|
*/
|
||||||
export class YXmlEvent extends YEvent {
|
export class YXmlEvent extends YEvent {
|
||||||
/**
|
/**
|
||||||
* @param {YXmlElement|YXmlFragment} target The target on which the event is created.
|
* @param {YXmlElement|YXmlText|YXmlFragment} target The target on which the event is created.
|
||||||
* @param {Set<string|null>} subs The set of changed attributes. `null` is included if the
|
* @param {Set<string|null>} subs The set of changed attributes. `null` is included if the
|
||||||
* child list changed.
|
* child list changed.
|
||||||
* @param {Transaction} transaction The transaction instance with wich the
|
* @param {Transaction} transaction The transaction instance with wich the
|
||||||
@ -25,7 +25,7 @@ export class YXmlEvent extends YEvent {
|
|||||||
this.childListChanged = false
|
this.childListChanged = false
|
||||||
/**
|
/**
|
||||||
* Set of all changed attributes.
|
* Set of all changed attributes.
|
||||||
* @type {Set<string|null>}
|
* @type {Set<string>}
|
||||||
*/
|
*/
|
||||||
this.attributesChanged = new Set()
|
this.attributesChanged = new Set()
|
||||||
subs.forEach((sub) => {
|
subs.forEach((sub) => {
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
typeListMap,
|
typeListMap,
|
||||||
typeListForEach,
|
typeListForEach,
|
||||||
typeListInsertGenerics,
|
typeListInsertGenerics,
|
||||||
|
typeListInsertGenericsAfter,
|
||||||
typeListDelete,
|
typeListDelete,
|
||||||
typeListToArray,
|
typeListToArray,
|
||||||
YXmlFragmentRefID,
|
YXmlFragmentRefID,
|
||||||
@ -19,6 +20,8 @@ import {
|
|||||||
AbstractUpdateDecoder, AbstractUpdateEncoder, Doc, ContentType, Transaction, Item, YXmlText, YXmlHook, Snapshot // eslint-disable-line
|
AbstractUpdateDecoder, AbstractUpdateEncoder, Doc, ContentType, Transaction, Item, YXmlText, YXmlHook, Snapshot // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
|
|
||||||
|
import * as error from 'lib0/error.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the elements to which a set of CSS queries apply.
|
* 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}
|
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
|
||||||
@ -130,6 +133,14 @@ export class YXmlFragment extends AbstractType {
|
|||||||
this._prelimContent = []
|
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.
|
* Integrate this type into the Yjs instance.
|
||||||
*
|
*
|
||||||
@ -302,6 +313,32 @@ export class YXmlFragment extends AbstractType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts new content at an index.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Insert character 'a' at position 0
|
||||||
|
* xml.insert(0, [new Y.XmlText('text')])
|
||||||
|
*
|
||||||
|
* @param {null|Item|YXmlElement|YXmlText} ref The index to insert content at
|
||||||
|
* @param {Array<YXmlElement|YXmlText>} content The array of content
|
||||||
|
*/
|
||||||
|
insertAfter (ref, content) {
|
||||||
|
if (this.doc !== null) {
|
||||||
|
transact(this.doc, transaction => {
|
||||||
|
const refItem = (ref && ref instanceof AbstractType) ? ref._item : ref
|
||||||
|
typeListInsertGenericsAfter(transaction, this, refItem, content)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const pc = /** @type {Array<any>} */ (this._prelimContent)
|
||||||
|
const index = ref === null ? 0 : pc.findIndex(el => el === ref) + 1
|
||||||
|
if (index === 0 && ref !== null) {
|
||||||
|
throw error.create('Reference item not found')
|
||||||
|
}
|
||||||
|
pc.splice(index, 0, ...content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes elements starting from an index.
|
* Deletes elements starting from an index.
|
||||||
*
|
*
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import {
|
import {
|
||||||
YText,
|
YText,
|
||||||
YXmlTextRefID,
|
YXmlTextRefID,
|
||||||
AbstractUpdateDecoder, AbstractUpdateEncoder // eslint-disable-line
|
ContentType, YXmlElement, AbstractUpdateDecoder, AbstractUpdateEncoder // eslint-disable-line
|
||||||
} from '../internals.js'
|
} from '../internals.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,6 +10,22 @@ import {
|
|||||||
* simple formatting information like bold and italic.
|
* simple formatting information like bold and italic.
|
||||||
*/
|
*/
|
||||||
export class YXmlText extends YText {
|
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 () {
|
_copy () {
|
||||||
return new YXmlText()
|
return new YXmlText()
|
||||||
}
|
}
|
||||||
|
@ -264,6 +264,7 @@ export const createAbsolutePositionFromRelativePosition = (rpos, doc) => {
|
|||||||
/**
|
/**
|
||||||
* @param {RelativePosition|null} a
|
* @param {RelativePosition|null} a
|
||||||
* @param {RelativePosition|null} b
|
* @param {RelativePosition|null} b
|
||||||
|
* @return {boolean}
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
|
@ -119,9 +119,6 @@ const popStackItem = (undoManager, stack, eventType) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = stackItem
|
result = stackItem
|
||||||
if (result != null) {
|
|
||||||
undoManager.emit('stack-item-popped', [{ stackItem: result, type: eventType }, undoManager])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
transaction.changed.forEach((subProps, type) => {
|
transaction.changed.forEach((subProps, type) => {
|
||||||
// destroy search marker if necessary
|
// destroy search marker if necessary
|
||||||
@ -130,6 +127,9 @@ const popStackItem = (undoManager, stack, eventType) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, undoManager)
|
}, undoManager)
|
||||||
|
if (result != null) {
|
||||||
|
undoManager.emit('stack-item-popped', [{ stackItem: result, type: eventType }, undoManager])
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ export class YEvent {
|
|||||||
/**
|
/**
|
||||||
* Computes the path from `y` to the changed type.
|
* Computes the path from `y` to the changed type.
|
||||||
*
|
*
|
||||||
|
* @todo v14 should standardize on path: Array<{parent, index}> because that is easier to work with.
|
||||||
|
*
|
||||||
* The following property holds:
|
* The following property holds:
|
||||||
* @example
|
* @example
|
||||||
* let type = y
|
* let type = y
|
||||||
|
@ -73,3 +73,63 @@ export const testTreewalker = tc => {
|
|||||||
t.assert(xml0.querySelector('p') === paragraph1, 'querySelector found paragraph1')
|
t.assert(xml0.querySelector('p') === paragraph1, 'querySelector found paragraph1')
|
||||||
compare(users)
|
compare(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {t.TestCase} tc
|
||||||
|
*/
|
||||||
|
export const testYtextAttributes = tc => {
|
||||||
|
const ydoc = new Y.Doc()
|
||||||
|
const ytext = /** @type {Y.XmlText} */ (ydoc.get('', Y.XmlText))
|
||||||
|
ytext.observe(event => {
|
||||||
|
t.compare(event.changes.keys.get('test'), { action: 'add', oldValue: undefined })
|
||||||
|
})
|
||||||
|
ytext.setAttribute('test', 42)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {t.TestCase} tc
|
||||||
|
*/
|
||||||
|
export const testInsertafter = tc => {
|
||||||
|
const ydoc = new Y.Doc()
|
||||||
|
const yxml = ydoc.getXmlFragment()
|
||||||
|
const first = new Y.XmlText()
|
||||||
|
const second = new Y.XmlElement('p')
|
||||||
|
const third = new Y.XmlElement('p')
|
||||||
|
|
||||||
|
const deepsecond1 = new Y.XmlElement('span')
|
||||||
|
const deepsecond2 = new Y.XmlText()
|
||||||
|
second.insertAfter(null, [deepsecond1])
|
||||||
|
second.insertAfter(deepsecond1, [deepsecond2])
|
||||||
|
|
||||||
|
yxml.insertAfter(null, [first, second])
|
||||||
|
yxml.insertAfter(second, [third])
|
||||||
|
|
||||||
|
t.assert(yxml.length === 3)
|
||||||
|
t.assert(second.get(0) === deepsecond1)
|
||||||
|
t.assert(second.get(1) === deepsecond2)
|
||||||
|
|
||||||
|
t.compareArrays(yxml.toArray(), [first, second, third])
|
||||||
|
|
||||||
|
t.fails(() => {
|
||||||
|
const el = new Y.XmlElement('p')
|
||||||
|
el.insertAfter(deepsecond1, [new Y.XmlText()])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user