diff --git a/src/types/YXmlFragment.js b/src/types/YXmlFragment.js index 41c581e1..21c6a3a0 100644 --- a/src/types/YXmlFragment.js +++ b/src/types/YXmlFragment.js @@ -9,6 +9,7 @@ import { typeListMap, typeListForEach, typeListInsertGenerics, + typeListInsertGenericsAfter, typeListDelete, typeListToArray, YXmlFragmentRefID, @@ -19,6 +20,8 @@ import { AbstractUpdateDecoder, AbstractUpdateEncoder, Doc, ContentType, Transaction, Item, YXmlText, YXmlHook, Snapshot // eslint-disable-line } from '../internals.js' +import * as error from 'lib0/error.js' + /** * 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} @@ -310,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} 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} */ (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. * diff --git a/tests/y-xml.tests.js b/tests/y-xml.tests.js index 48132175..31513091 100644 --- a/tests/y-xml.tests.js +++ b/tests/y-xml.tests.js @@ -103,3 +103,33 @@ export const testSiblings = tc => { 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()]) + }) +}