diff --git a/package.json b/package.json index 178cb9c1..94962458 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "test": "npm run dist && PRODUCTION=1 node ./dist/tests.js --repitition-time 50 --production", "test-exhaustive": "npm run lint && npm run dist && node ./dist/tests.js --repitition-time 10000", "dist": "rm -rf dist examples/build && rollup -c", + "serve-examples": "concurrently 'npm run watch' 'serve examples'", "watch": "rollup -wc", "lint": "standard && tsc", "docs": "rm -rf docs; jsdoc --configure ./.jsdoc.json --verbose --readme ./README.v13.md --package ./package.json || true", diff --git a/src/structs/AbstractItem.js b/src/structs/AbstractItem.js index d37e35b3..bcdbbe22 100644 --- a/src/structs/AbstractItem.js +++ b/src/structs/AbstractItem.js @@ -27,6 +27,22 @@ import * as maplib from 'lib0/map.js' import * as set from 'lib0/set.js' import * as binary from 'lib0/binary.js' +/** + * @param {AbstractItem} left + * @param {AbstractItem} right + * @return {boolean} If true, right is removed from the linked list and should be discarded + */ +export const mergeItemWith = (left, right) => { + if (compareIDs(right.origin, left.lastId) && left.right === right && compareIDs(left.rightOrigin, right.rightOrigin)) { + left.right = right.right + if (left.right !== null) { + left.right.left = left + } + return true + } + return false +} + /** * Split leftItem into two items * @param {Transaction} transaction @@ -376,22 +392,6 @@ export class AbstractItem extends AbstractStruct { throw new Error('unimplemented') } - /** - * @param {AbstractItem} right - * @return {boolean} - * - * @private - */ - mergeWith (right) { - if (compareIDs(right.origin, this.lastId) && this.right === right && compareIDs(this.rightOrigin, right.rightOrigin)) { - this.right = right.right - if (this.right !== null) { - this.right.left = this - } - return true - } - return false - } /** * Mark this Item as deleted. * diff --git a/src/structs/ItemDeleted.js b/src/structs/ItemDeleted.js index 3b4f753f..a683c6c7 100644 --- a/src/structs/ItemDeleted.js +++ b/src/structs/ItemDeleted.js @@ -7,6 +7,7 @@ import { GC, splitItem, addToDeleteSet, + mergeItemWith, Y, StructStore, Transaction, ID, AbstractType // eslint-disable-line } from '../internals.js' @@ -78,7 +79,7 @@ export class ItemDeleted extends AbstractItem { * @return {boolean} */ mergeWith (right) { - if (super.mergeWith(right)) { + if (mergeItemWith(this, right)) { this._len += right._len return true } diff --git a/src/structs/ItemJSON.js b/src/structs/ItemJSON.js index 42d8e656..1b69a90e 100644 --- a/src/structs/ItemJSON.js +++ b/src/structs/ItemJSON.js @@ -6,6 +6,7 @@ import { splitItem, changeItemRefOffset, GC, + mergeItemWith, Transaction, StructStore, Y, ID, AbstractType // eslint-disable-line } from '../internals.js' @@ -74,7 +75,7 @@ export class ItemJSON extends AbstractItem { * @return {boolean} */ mergeWith (right) { - if (super.mergeWith(right)) { + if (mergeItemWith(this, right)) { this.content = this.content.concat(right.content) return true } diff --git a/src/structs/ItemString.js b/src/structs/ItemString.js index de683ba0..8409c9f7 100644 --- a/src/structs/ItemString.js +++ b/src/structs/ItemString.js @@ -6,6 +6,7 @@ import { splitItem, changeItemRefOffset, GC, + mergeItemWith, Transaction, StructStore, Y, ID, AbstractType // eslint-disable-line } from '../internals.js' @@ -73,7 +74,7 @@ export class ItemString extends AbstractItem { * @return {boolean} */ mergeWith (right) { - if (super.mergeWith(right)) { + if (mergeItemWith(this, right)) { this.string += right.string return true } diff --git a/src/types/YText.js b/src/types/YText.js index f6f1a8d5..22c8d6bd 100644 --- a/src/types/YText.js +++ b/src/types/YText.js @@ -657,10 +657,6 @@ export class YText extends AbstractType { callTypeObservers(this, transaction, new YTextEvent(this, transaction)) } - toDom () { - return document.createTextNode(this.toString()) - } - /** * Returns the unformatted string representation of this YText type. * @@ -682,40 +678,6 @@ export class YText extends AbstractType { return str } - toDomString () { - // @ts-ignore - return this.toDelta().map(delta => { - const nestedNodes = [] - for (let nodeName in delta.attributes) { - const attrs = [] - for (let key in delta.attributes[nodeName]) { - attrs.push({ key, value: delta.attributes[nodeName][key] }) - } - // sort attributes to get a unique order - attrs.sort((a, b) => a.key < b.key ? -1 : 1) - nestedNodes.push({ nodeName, attrs }) - } - // sort node order to get a unique order - nestedNodes.sort((a, b) => a.nodeName < b.nodeName ? -1 : 1) - // now convert to dom string - let str = '' - for (let i = 0; i < nestedNodes.length; i++) { - const node = nestedNodes[i] - str += `<${node.nodeName}` - for (let j = 0; j < node.attrs.length; j++) { - const attr = node.attrs[i] - str += ` ${attr.key}="${attr.value}"` - } - str += '>' - } - str += delta.insert - for (let i = nestedNodes.length - 1; i >= 0; i--) { - str += `` - } - return str - }) - } - /** * Apply a {@link Delta} on this shared YText type. * diff --git a/src/types/YXmlText.js b/src/types/YXmlText.js index 09612251..7ec2c728 100644 --- a/src/types/YXmlText.js +++ b/src/types/YXmlText.js @@ -31,6 +31,41 @@ export class YXmlText extends YText { } return dom } + + toDomString () { + // @ts-ignore + return this.toDelta().map(delta => { + const nestedNodes = [] + for (let nodeName in delta.attributes) { + const attrs = [] + for (let key in delta.attributes[nodeName]) { + attrs.push({ key, value: delta.attributes[nodeName][key] }) + } + // sort attributes to get a unique order + attrs.sort((a, b) => a.key < b.key ? -1 : 1) + nestedNodes.push({ nodeName, attrs }) + } + // sort node order to get a unique order + nestedNodes.sort((a, b) => a.nodeName < b.nodeName ? -1 : 1) + // now convert to dom string + let str = '' + for (let i = 0; i < nestedNodes.length; i++) { + const node = nestedNodes[i] + str += `<${node.nodeName}` + for (let j = 0; j < node.attrs.length; j++) { + const attr = node.attrs[i] + str += ` ${attr.key}="${attr.value}"` + } + str += '>' + } + str += delta.insert + for (let i = nestedNodes.length - 1; i >= 0; i--) { + str += `` + } + return str + }).join('') + } + /** * @param {encoding.Encoder} encoder * diff --git a/src/utils/cursor.js b/src/utils/cursor.js index cbd318ed..75f7aaad 100644 --- a/src/utils/cursor.js +++ b/src/utils/cursor.js @@ -241,6 +241,10 @@ export const createAbsolutePositionFromCursor = (cursor, y) => { if (tname !== null) { type = y.get(tname) } else if (typeID !== null) { + if (getState(store, typeID.client) <= typeID.clock) { + // type does not exist yet + return null + } const struct = getItemType(store, typeID) if (struct instanceof ItemType) { type = struct.type