fix y-text
This commit is contained in:
parent
c188f813a4
commit
1bc1e88d6a
@ -232,8 +232,12 @@ export class AbstractItem extends AbstractStruct {
|
|||||||
}
|
}
|
||||||
transaction.added.add(this)
|
transaction.added.add(this)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (parent._item.deleted) {
|
if (parent._item.deleted || (left !== null && parentSub !== null)) {
|
||||||
this.delete(transaction, false, true)
|
// delete if parent is deleted or if this is not the current attribute value of parent
|
||||||
|
this.delete(transaction)
|
||||||
|
} else if (parentSub !== null && left === null && right !== null) {
|
||||||
|
// this is the current attribute value of parent. delete right
|
||||||
|
right.delete(transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,13 +395,10 @@ export class AbstractItem extends AbstractStruct {
|
|||||||
* Mark this Item as deleted.
|
* Mark this Item as deleted.
|
||||||
*
|
*
|
||||||
* @param {Transaction} transaction
|
* @param {Transaction} transaction
|
||||||
* @param {boolean} createDelete Whether to propagate a message that this
|
|
||||||
* Type was deleted.
|
|
||||||
* @param {boolean} [gcChildren]
|
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
delete (transaction, createDelete = true, gcChildren) {
|
delete (transaction) {
|
||||||
if (!this.deleted) {
|
if (!this.deleted) {
|
||||||
const parent = this.parent
|
const parent = this.parent
|
||||||
// adjust the length of parent
|
// adjust the length of parent
|
||||||
|
@ -16,28 +16,6 @@ import { ItemBinary } from '../structs/ItemBinary.js'
|
|||||||
import { ID, createID } from '../utils/ID.js' // eslint-disable-line
|
import { ID, createID } from '../utils/ID.js' // eslint-disable-line
|
||||||
import { getItemCleanStart } from '../utils/StructStore.js'
|
import { getItemCleanStart } from '../utils/StructStore.js'
|
||||||
|
|
||||||
/**
|
|
||||||
* Restructure children as if they were inserted one after another
|
|
||||||
* @param {Transaction} transaction
|
|
||||||
* @param {AbstractItem} start
|
|
||||||
*/
|
|
||||||
const integrateChildren = (transaction, start) => {
|
|
||||||
let right
|
|
||||||
while (true) {
|
|
||||||
right = start.right
|
|
||||||
start.id = nextID(transaction)
|
|
||||||
start.right = null
|
|
||||||
start.rightOrigin = null
|
|
||||||
start.origin = start.left
|
|
||||||
start.integrate(transaction)
|
|
||||||
if (right !== null) {
|
|
||||||
start = right
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract Yjs Type class
|
* Abstract Yjs Type class
|
||||||
*/
|
*/
|
||||||
@ -81,21 +59,6 @@ export class AbstractType {
|
|||||||
_integrate (transaction, item) {
|
_integrate (transaction, item) {
|
||||||
this._y = transaction.y
|
this._y = transaction.y
|
||||||
this._item = item
|
this._item = item
|
||||||
// when integrating children we must make sure to
|
|
||||||
// integrate start
|
|
||||||
const start = this._start
|
|
||||||
if (start !== null) {
|
|
||||||
this._start = null
|
|
||||||
integrateChildren(transaction, start)
|
|
||||||
}
|
|
||||||
// integrate map children_integrate
|
|
||||||
const map = this._map
|
|
||||||
this._map = new Map()
|
|
||||||
map.forEach(t => {
|
|
||||||
t.right = null
|
|
||||||
t.rightOrigin = null
|
|
||||||
integrateChildren(transaction, t)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -336,6 +299,7 @@ export const typeArrayInsertGenericsAfter = (transaction, parent, referenceItem,
|
|||||||
let jsonContent = []
|
let jsonContent = []
|
||||||
content.forEach(c => {
|
content.forEach(c => {
|
||||||
switch (c.constructor) {
|
switch (c.constructor) {
|
||||||
|
case Number:
|
||||||
case Object:
|
case Object:
|
||||||
case Array:
|
case Array:
|
||||||
case String:
|
case String:
|
||||||
@ -398,3 +362,64 @@ export const typeMapDelete = (transaction, parent, key) => {
|
|||||||
c.delete(transaction)
|
c.delete(transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {string} key
|
||||||
|
* @param {Object|number|Array<any>|string|ArrayBuffer|AbstractType} value
|
||||||
|
*/
|
||||||
|
export const typeMapSet = (transaction, parent, key, value) => {
|
||||||
|
const right = parent._map.get(key) || null
|
||||||
|
switch (value.constructor) {
|
||||||
|
case Number:
|
||||||
|
case Object:
|
||||||
|
case Array:
|
||||||
|
case String:
|
||||||
|
new ItemJSON(nextID(transaction), null, right, parent, key, [value]).integrate(transaction)
|
||||||
|
break
|
||||||
|
case ArrayBuffer:
|
||||||
|
new ItemBinary(nextID(transaction), null, right, parent, key, value).integrate(transaction)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (value instanceof AbstractType) {
|
||||||
|
new ItemType(nextID(transaction), null, right, parent, key, value).integrate(transaction)
|
||||||
|
} else {
|
||||||
|
throw new Error('Unexpected content type')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {string} key
|
||||||
|
* @return {Object<string,any>|number|Array<any>|string|ArrayBuffer|AbstractType|undefined}
|
||||||
|
*/
|
||||||
|
export const typeMapGet = (parent, key) => {
|
||||||
|
const val = parent._map.get(key)
|
||||||
|
return val !== undefined && !val.deleted ? val.getContent()[0] : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {string} key
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export const typeMapHas = (parent, key) => {
|
||||||
|
const val = parent._map.get(key)
|
||||||
|
return val !== undefined && !val.deleted
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {string} key
|
||||||
|
* @param {Snapshot} snapshot
|
||||||
|
* @return {Object<string,any>|number|Array<any>|string|ArrayBuffer|AbstractType|undefined}
|
||||||
|
*/
|
||||||
|
export const typeMapGetSnapshot = (parent, key, snapshot) => {
|
||||||
|
let v = parent._map.get(key) || null
|
||||||
|
while (v !== null && (!snapshot.sm.has(v.id.client) || v.id.clock >= (snapshot.sm.get(v.id.client) || 0))) {
|
||||||
|
v = v.right
|
||||||
|
}
|
||||||
|
return v !== null && isVisible(v, snapshot) ? v.getContent()[0] : undefined
|
||||||
|
}
|
||||||
|
@ -13,12 +13,10 @@ import * as decoding from 'lib0/decoding.js' // eslint-disable-line
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Event that describes the changes on a YArray
|
* Event that describes the changes on a YArray
|
||||||
*
|
|
||||||
* @template T
|
|
||||||
*/
|
*/
|
||||||
export class YArrayEvent extends YEvent {
|
export class YArrayEvent extends YEvent {
|
||||||
/**
|
/**
|
||||||
* @param {YArray<T>} yarray The changed type
|
* @param {AbstractType} yarray The changed type
|
||||||
* @param {Transaction} transaction The transaction object
|
* @param {Transaction} transaction The transaction object
|
||||||
*/
|
*/
|
||||||
constructor (yarray, transaction) {
|
constructor (yarray, transaction) {
|
||||||
|
@ -5,82 +5,109 @@
|
|||||||
import { ItemEmbed } from '../structs/ItemEmbed.js'
|
import { ItemEmbed } from '../structs/ItemEmbed.js'
|
||||||
import { ItemString } from '../structs/ItemString.js'
|
import { ItemString } from '../structs/ItemString.js'
|
||||||
import { ItemFormat } from '../structs/ItemFormat.js'
|
import { ItemFormat } from '../structs/ItemFormat.js'
|
||||||
import { YArrayEvent, YArray } from './YArray.js'
|
import { YArrayEvent } from './YArray.js'
|
||||||
import { isVisible } from '../utils/Snapshot.js'
|
import { ItemType } from '../structs/ItemType.js' // eslint-disable-line
|
||||||
|
import { AbstractType } from './AbstractType.js'
|
||||||
|
import { AbstractItem } from '../structs/AbstractItem.js' // eslint-disable-line
|
||||||
|
import { isVisible, Snapshot } from '../utils/Snapshot.js' // eslint-disable-line
|
||||||
|
import { getItemCleanStart, StructStore } from '../utils/StructStore.js' // eslint-disable-line
|
||||||
|
import { Transaction, nextID } from '../utils/Transaction.js' // eslint-disable-line
|
||||||
|
import { createID } from '../utils/ID.js'
|
||||||
|
import * as decoding from 'lib0/decoding.js' // eslint-disable-line
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
* @param {StructStore} store
|
||||||
|
* @param {Map<string,any>} currentAttributes
|
||||||
|
* @param {AbstractItem|null} left
|
||||||
|
* @param {AbstractItem|null} right
|
||||||
|
* @param {number} count
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null,currentAttributes:Map<string,any>}}
|
||||||
*/
|
*/
|
||||||
const findNextPosition = (currentAttributes, parent, left, right, count) => {
|
const findNextPosition = (transaction, store, currentAttributes, left, right, count) => {
|
||||||
while (right !== null && count > 0) {
|
while (right !== null && count > 0) {
|
||||||
switch (right.constructor) {
|
switch (right.constructor) {
|
||||||
case ItemEmbed:
|
case ItemEmbed:
|
||||||
case ItemString:
|
case ItemString:
|
||||||
const rightLen = right._deleted ? 0 : (right._length - 1)
|
if (!right.deleted) {
|
||||||
if (count <= rightLen) {
|
if (count < right.length) {
|
||||||
right = right._splitAt(parent._y, count)
|
right = getItemCleanStart(store, transaction, createID(right.id.client, right.id.clock + count))
|
||||||
left = right._left
|
left = right.left
|
||||||
return [left, right, currentAttributes]
|
count = 0
|
||||||
}
|
} else {
|
||||||
if (right._deleted === false) {
|
count -= right.length
|
||||||
count -= right._length
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case ItemFormat:
|
case ItemFormat:
|
||||||
if (right._deleted === false) {
|
if (!right.deleted) {
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
updateCurrentAttributes(currentAttributes, right)
|
updateCurrentAttributes(currentAttributes, right)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
left = right
|
left = right
|
||||||
right = right._right
|
right = right.right
|
||||||
}
|
}
|
||||||
return [left, right, currentAttributes]
|
return { left, right, currentAttributes }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
* @param {StructStore} store
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {number} index
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null,currentAttributes:Map<string,any>}}
|
||||||
*/
|
*/
|
||||||
const findPosition = (parent, index) => {
|
const findPosition = (transaction, store, parent, index) => {
|
||||||
let currentAttributes = new Map()
|
let currentAttributes = new Map()
|
||||||
let left = null
|
let left = null
|
||||||
let right = parent._start
|
let right = parent._start
|
||||||
return findNextPosition(currentAttributes, parent, left, right, index)
|
return findNextPosition(transaction, store, currentAttributes, left, right, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Negate applied formats
|
* Negate applied formats
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {AbstractItem|null} left
|
||||||
|
* @param {AbstractItem|null} right
|
||||||
|
* @param {Map<string,any>} negatedAttributes
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null}}
|
||||||
*/
|
*/
|
||||||
const insertNegatedAttributes = (y, parent, left, right, negatedAttributes) => {
|
const insertNegatedAttributes = (transaction, parent, left, right, negatedAttributes) => {
|
||||||
// check if we really need to remove attributes
|
// check if we really need to remove attributes
|
||||||
while (
|
while (
|
||||||
right !== null && (
|
right !== null && (
|
||||||
right._deleted === true || (
|
right.deleted === true || (
|
||||||
right.constructor === ItemFormat &&
|
right.constructor === ItemFormat &&
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
(negatedAttributes.get(right.key) === right.value)
|
(negatedAttributes.get(right.key) === right.value)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if (right._deleted === false) {
|
if (!right.deleted) {
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
negatedAttributes.delete(right.key)
|
negatedAttributes.delete(right.key)
|
||||||
}
|
}
|
||||||
left = right
|
left = right
|
||||||
right = right._right
|
right = right.right
|
||||||
}
|
}
|
||||||
for (let [key, val] of negatedAttributes) {
|
for (let [key, val] of negatedAttributes) {
|
||||||
let format = new ItemFormat()
|
left = new ItemFormat(nextID(transaction), left, right, parent, null, key, val)
|
||||||
format.key = key
|
left.integrate(transaction)
|
||||||
format.value = val
|
|
||||||
integrateItem(format, parent, y, left, right)
|
|
||||||
left = format
|
|
||||||
}
|
}
|
||||||
return [left, right]
|
return {left, right}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Map<string,any>} currentAttributes
|
||||||
|
* @param {ItemFormat} item
|
||||||
*/
|
*/
|
||||||
const updateCurrentAttributes = (currentAttributes, item) => {
|
const updateCurrentAttributes = (currentAttributes, item) => {
|
||||||
const value = item.value
|
const value = item.value
|
||||||
@ -94,30 +121,44 @@ const updateCurrentAttributes = (currentAttributes, item) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
* @param {AbstractItem|null} left
|
||||||
|
* @param {AbstractItem|null} right
|
||||||
|
* @param {Map<string,any>} currentAttributes
|
||||||
|
* @param {Object<string,any>} attributes
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null}}
|
||||||
*/
|
*/
|
||||||
const minimizeAttributeChanges = (left, right, currentAttributes, attributes) => {
|
const minimizeAttributeChanges = (left, right, currentAttributes, attributes) => {
|
||||||
// go right while attributes[right.key] === right.value (or right is deleted)
|
// go right while attributes[right.key] === right.value (or right is deleted)
|
||||||
while (true) {
|
while (true) {
|
||||||
if (right === null) {
|
if (right === null) {
|
||||||
break
|
break
|
||||||
} else if (right._deleted === true) {
|
} else if (right.deleted) {
|
||||||
// continue
|
// continue
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
} else if (right.constructor === ItemFormat && (attributes[right.key] || null) === right.value) {
|
} else if (right.constructor === ItemFormat && (attributes[right.key] || null) === right.value) {
|
||||||
// found a format, update currentAttributes and continue
|
// found a format, update currentAttributes and continue
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
updateCurrentAttributes(currentAttributes, right)
|
updateCurrentAttributes(currentAttributes, right)
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
left = right
|
left = right
|
||||||
right = right._right
|
right = right.right
|
||||||
}
|
}
|
||||||
return [left, right]
|
return { left, right }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
* @param {Transaction} transaction
|
||||||
const insertAttributes = (y, parent, left, right, attributes, currentAttributes) => {
|
* @param {AbstractType} parent
|
||||||
|
* @param {AbstractItem|null} left
|
||||||
|
* @param {AbstractItem|null} right
|
||||||
|
* @param {Map<string,any>} currentAttributes
|
||||||
|
* @param {Object<string,any>} attributes
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null,negatedAttributes:Map<string,any>}}
|
||||||
|
**/
|
||||||
|
const insertAttributes = (transaction, parent, left, right, currentAttributes, attributes) => {
|
||||||
const negatedAttributes = new Map()
|
const negatedAttributes = new Map()
|
||||||
// insert format-start items
|
// insert format-start items
|
||||||
for (let key in attributes) {
|
for (let key in attributes) {
|
||||||
@ -126,101 +167,128 @@ const insertAttributes = (y, parent, left, right, attributes, currentAttributes)
|
|||||||
if (currentVal !== val) {
|
if (currentVal !== val) {
|
||||||
// save negated attribute (set null if currentVal undefined)
|
// save negated attribute (set null if currentVal undefined)
|
||||||
negatedAttributes.set(key, currentVal || null)
|
negatedAttributes.set(key, currentVal || null)
|
||||||
let format = new ItemFormat()
|
left = new ItemFormat(nextID(transaction), left, right, parent, null, key, val)
|
||||||
format.key = key
|
left.integrate(transaction)
|
||||||
format.value = val
|
|
||||||
integrateItem(format, parent, y, left, right)
|
|
||||||
left = format
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [left, right, negatedAttributes]
|
return { left, right, negatedAttributes }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
* @param {Transaction} transaction
|
||||||
const insertText = (y, text, parent, left, right, currentAttributes, attributes) => {
|
* @param {AbstractType} parent
|
||||||
|
* @param {AbstractItem|null} left
|
||||||
|
* @param {AbstractItem|null} right
|
||||||
|
* @param {Map<string,any>} currentAttributes
|
||||||
|
* @param {string} text
|
||||||
|
* @param {Object<string,any>} attributes
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null}}
|
||||||
|
**/
|
||||||
|
const insertText = (transaction, parent, left, right, currentAttributes, text, attributes) => {
|
||||||
for (let [key] of currentAttributes) {
|
for (let [key] of currentAttributes) {
|
||||||
if (attributes[key] === undefined) {
|
if (attributes[key] === undefined) {
|
||||||
attributes[key] = null
|
attributes[key] = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[left, right] = minimizeAttributeChanges(left, right, currentAttributes, attributes)
|
const minPos = minimizeAttributeChanges(left, right, currentAttributes, attributes)
|
||||||
let negatedAttributes
|
const insertPos = insertAttributes(transaction, parent, minPos.left, minPos.right, currentAttributes, attributes)
|
||||||
[left, right, negatedAttributes] = insertAttributes(y, parent, left, right, attributes, currentAttributes)
|
|
||||||
// insert content
|
// insert content
|
||||||
let item
|
|
||||||
if (text.constructor === String) {
|
if (text.constructor === String) {
|
||||||
item = new ItemString()
|
left = new ItemString(nextID(transaction), insertPos.left, insertPos.right, parent, null, text)
|
||||||
item._content = text
|
|
||||||
} else {
|
} else {
|
||||||
item = new ItemEmbed()
|
left = new ItemEmbed(nextID(transaction), insertPos.left, insertPos.right, parent, null, text)
|
||||||
item.embed = text
|
|
||||||
}
|
}
|
||||||
integrateItem(item, parent, y, left, right)
|
left.integrate(transaction)
|
||||||
left = item
|
return insertNegatedAttributes(transaction, parent, left, insertPos.right, insertPos.negatedAttributes)
|
||||||
return insertNegatedAttributes(y, parent, left, right, negatedAttributes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {AbstractItem|null} left
|
||||||
|
* @param {AbstractItem|null} right
|
||||||
|
* @param {Map<string,any>} currentAttributes
|
||||||
|
* @param {number} length
|
||||||
|
* @param {Object<string,any>} attributes
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null}}
|
||||||
*/
|
*/
|
||||||
const formatText = (y, length, parent, left, right, currentAttributes, attributes) => {
|
const formatText = (transaction, parent, left, right, currentAttributes, length, attributes) => {
|
||||||
[left, right] = minimizeAttributeChanges(left, right, currentAttributes, attributes)
|
const minPos = minimizeAttributeChanges(left, right, currentAttributes, attributes)
|
||||||
let negatedAttributes
|
const insertPos = insertAttributes(transaction, parent, minPos.left, minPos.right, currentAttributes, attributes)
|
||||||
[left, right, negatedAttributes] = insertAttributes(y, parent, left, right, attributes, currentAttributes)
|
const negatedAttributes = insertPos.negatedAttributes
|
||||||
|
left = insertPos.left
|
||||||
|
right = insertPos.right
|
||||||
// iterate until first non-format or null is found
|
// iterate until first non-format or null is found
|
||||||
// delete all formats with attributes[format.key] != null
|
// delete all formats with attributes[format.key] != null
|
||||||
while (length > 0 && right !== null) {
|
while (length > 0 && right !== null) {
|
||||||
if (right._deleted === false) {
|
if (right.deleted === false) {
|
||||||
switch (right.constructor) {
|
switch (right.constructor) {
|
||||||
case ItemFormat:
|
case ItemFormat:
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
const attr = attributes[right.key]
|
const attr = attributes[right.key]
|
||||||
if (attr !== undefined) {
|
if (attr !== undefined) {
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
if (attr === right.value) {
|
if (attr === right.value) {
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
negatedAttributes.delete(right.key)
|
negatedAttributes.delete(right.key)
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
negatedAttributes.set(right.key, right.value)
|
negatedAttributes.set(right.key, right.value)
|
||||||
}
|
}
|
||||||
right._delete(y)
|
right.delete(transaction)
|
||||||
}
|
}
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
updateCurrentAttributes(currentAttributes, right)
|
updateCurrentAttributes(currentAttributes, right)
|
||||||
break
|
break
|
||||||
case ItemEmbed:
|
case ItemEmbed:
|
||||||
case ItemString:
|
case ItemString:
|
||||||
right._splitAt(y, length)
|
if (length < right.length) {
|
||||||
length -= right._length
|
getItemCleanStart(transaction.y.store, transaction, createID(right.id.client, right.id.clock + length))
|
||||||
|
}
|
||||||
|
length -= right.length
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
left = right
|
left = right
|
||||||
right = right._right
|
right = right.right
|
||||||
}
|
}
|
||||||
return insertNegatedAttributes(y, parent, left, right, negatedAttributes)
|
return insertNegatedAttributes(transaction, parent, left, right, negatedAttributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
* @param {AbstractType} parent
|
||||||
|
* @param {AbstractItem|null} left
|
||||||
|
* @param {AbstractItem|null} right
|
||||||
|
* @param {Map<string,any>} currentAttributes
|
||||||
|
* @param {number} length
|
||||||
|
* @return {{left:AbstractItem|null,right:AbstractItem|null}}
|
||||||
*/
|
*/
|
||||||
const deleteText = (y, length, parent, left, right, currentAttributes) => {
|
const deleteText = (transaction, parent, left, right, currentAttributes, length) => {
|
||||||
while (length > 0 && right !== null) {
|
while (length > 0 && right !== null) {
|
||||||
if (right._deleted === false) {
|
if (right.deleted === false) {
|
||||||
switch (right.constructor) {
|
switch (right.constructor) {
|
||||||
case ItemFormat:
|
case ItemFormat:
|
||||||
|
// @ts-ignore right is ItemFormat
|
||||||
updateCurrentAttributes(currentAttributes, right)
|
updateCurrentAttributes(currentAttributes, right)
|
||||||
break
|
break
|
||||||
case ItemEmbed:
|
case ItemEmbed:
|
||||||
case ItemString:
|
case ItemString:
|
||||||
right._splitAt(y, length)
|
if (length < right.length) {
|
||||||
length -= right._length
|
getItemCleanStart(transaction.y.store, transaction, createID(right.id.client, right.id.clock + length))
|
||||||
right._delete(y)
|
}
|
||||||
|
length -= right.length
|
||||||
|
right.delete(transaction)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
left = right
|
left = right
|
||||||
right = right._right
|
right = right.right
|
||||||
}
|
}
|
||||||
return [left, right]
|
return { left, right }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: In the quill delta representation we should also use the format {ops:[..]}
|
// TODO: In the quill delta representation we should also use the format {ops:[..]}
|
||||||
@ -237,7 +305,6 @@ const deleteText = (y, length, parent, left, right, currentAttributes) => {
|
|||||||
* ]
|
* ]
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @typedef {Array<Object>} Delta
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -258,8 +325,15 @@ const deleteText = (y, length, parent, left, right, currentAttributes) => {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
class YTextEvent extends YArrayEvent {
|
class YTextEvent extends YArrayEvent {
|
||||||
constructor (ytext, remote, transaction) {
|
/**
|
||||||
super(ytext, remote, transaction)
|
* @param {AbstractType} ytext
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
*/
|
||||||
|
constructor (ytext, transaction) {
|
||||||
|
super(ytext, transaction)
|
||||||
|
/**
|
||||||
|
* @type {Array<{delete:number|undefined,retain:number|undefined,insert:string|undefined,attributes:Object<string,any>}>|null}
|
||||||
|
*/
|
||||||
this._delta = null
|
this._delta = null
|
||||||
}
|
}
|
||||||
// TODO: Should put this in a separate function. toDelta shouldn't be included
|
// TODO: Should put this in a separate function. toDelta shouldn't be included
|
||||||
@ -267,7 +341,7 @@ class YTextEvent extends YArrayEvent {
|
|||||||
/**
|
/**
|
||||||
* Compute the changes in the delta format.
|
* Compute the changes in the delta format.
|
||||||
*
|
*
|
||||||
* @return {Delta} A {@link https://quilljs.com/docs/delta/|Quill Delta}) that
|
* @type {Array<{delete:number|undefined,retain:number|undefined,insert:string|undefined,attributes:Object<string,any>}>} A {@link https://quilljs.com/docs/delta/|Quill Delta}) that
|
||||||
* represents the changes on the document.
|
* represents the changes on the document.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
@ -275,20 +349,30 @@ class YTextEvent extends YArrayEvent {
|
|||||||
get delta () {
|
get delta () {
|
||||||
if (this._delta === null) {
|
if (this._delta === null) {
|
||||||
const y = this.target._y
|
const y = this.target._y
|
||||||
y.transact(() => {
|
// @ts-ignore
|
||||||
let item = this.target._start
|
y.transact(transaction => {
|
||||||
|
/**
|
||||||
|
* @type {Array<{delete:number|undefined,retain:number|undefined,insert:string|undefined,attributes:Object<string,any>}>}
|
||||||
|
*/
|
||||||
const delta = []
|
const delta = []
|
||||||
const added = this.addedElements
|
const added = this.addedElements
|
||||||
const removed = this.removedElements
|
const removed = this.removedElements
|
||||||
this._delta = delta
|
|
||||||
let action = null
|
|
||||||
let attributes = {} // counts added or removed new attributes for retain
|
|
||||||
const currentAttributes = new Map() // saves all current attributes for insert
|
const currentAttributes = new Map() // saves all current attributes for insert
|
||||||
const oldAttributes = new Map()
|
const oldAttributes = new Map()
|
||||||
|
let item = this.target._start
|
||||||
|
/**
|
||||||
|
* @type {string?}
|
||||||
|
*/
|
||||||
|
let action = null
|
||||||
|
/**
|
||||||
|
* @type {Object<string,any>}
|
||||||
|
*/
|
||||||
|
let attributes = {} // counts added or removed new attributes for retain
|
||||||
let insert = ''
|
let insert = ''
|
||||||
let retain = 0
|
let retain = 0
|
||||||
let deleteLen = 0
|
let deleteLen = 0
|
||||||
const addOp = function addOp () {
|
this._delta = delta
|
||||||
|
const addOp = () => {
|
||||||
if (action !== null) {
|
if (action !== null) {
|
||||||
/**
|
/**
|
||||||
* @type {any}
|
* @type {any}
|
||||||
@ -332,6 +416,7 @@ class YTextEvent extends YArrayEvent {
|
|||||||
if (added.has(item)) {
|
if (added.has(item)) {
|
||||||
addOp()
|
addOp()
|
||||||
action = 'insert'
|
action = 'insert'
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
insert = item.embed
|
insert = item.embed
|
||||||
addOp()
|
addOp()
|
||||||
} else if (removed.has(item)) {
|
} else if (removed.has(item)) {
|
||||||
@ -340,7 +425,7 @@ class YTextEvent extends YArrayEvent {
|
|||||||
action = 'delete'
|
action = 'delete'
|
||||||
}
|
}
|
||||||
deleteLen += 1
|
deleteLen += 1
|
||||||
} else if (item._deleted === false) {
|
} else if (item.deleted === false) {
|
||||||
if (action !== 'retain') {
|
if (action !== 'retain') {
|
||||||
addOp()
|
addOp()
|
||||||
action = 'retain'
|
action = 'retain'
|
||||||
@ -354,72 +439,89 @@ class YTextEvent extends YArrayEvent {
|
|||||||
addOp()
|
addOp()
|
||||||
action = 'insert'
|
action = 'insert'
|
||||||
}
|
}
|
||||||
insert += item._content
|
// @ts-ignore
|
||||||
|
insert += item.string
|
||||||
} else if (removed.has(item)) {
|
} else if (removed.has(item)) {
|
||||||
if (action !== 'delete') {
|
if (action !== 'delete') {
|
||||||
addOp()
|
addOp()
|
||||||
action = 'delete'
|
action = 'delete'
|
||||||
}
|
}
|
||||||
deleteLen += item._length
|
deleteLen += item.length
|
||||||
} else if (item._deleted === false) {
|
} else if (item.deleted === false) {
|
||||||
if (action !== 'retain') {
|
if (action !== 'retain') {
|
||||||
addOp()
|
addOp()
|
||||||
action = 'retain'
|
action = 'retain'
|
||||||
}
|
}
|
||||||
retain += item._length
|
retain += item.length
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case ItemFormat:
|
case ItemFormat:
|
||||||
if (added.has(item)) {
|
if (added.has(item)) {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
const curVal = currentAttributes.get(item.key) || null
|
const curVal = currentAttributes.get(item.key) || null
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
if (curVal !== item.value) {
|
if (curVal !== item.value) {
|
||||||
if (action === 'retain') {
|
if (action === 'retain') {
|
||||||
addOp()
|
addOp()
|
||||||
}
|
}
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
if (item.value === (oldAttributes.get(item.key) || null)) {
|
if (item.value === (oldAttributes.get(item.key) || null)) {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
delete attributes[item.key]
|
delete attributes[item.key]
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
attributes[item.key] = item.value
|
attributes[item.key] = item.value
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
item._delete(y)
|
item.delete(transaction)
|
||||||
}
|
}
|
||||||
} else if (removed.has(item)) {
|
} else if (removed.has(item)) {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
oldAttributes.set(item.key, item.value)
|
oldAttributes.set(item.key, item.value)
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
const curVal = currentAttributes.get(item.key) || null
|
const curVal = currentAttributes.get(item.key) || null
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
if (curVal !== item.value) {
|
if (curVal !== item.value) {
|
||||||
if (action === 'retain') {
|
if (action === 'retain') {
|
||||||
addOp()
|
addOp()
|
||||||
}
|
}
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
attributes[item.key] = curVal
|
attributes[item.key] = curVal
|
||||||
}
|
}
|
||||||
} else if (item._deleted === false) {
|
} else if (item.deleted === false) {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
oldAttributes.set(item.key, item.value)
|
oldAttributes.set(item.key, item.value)
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
const attr = attributes[item.key]
|
const attr = attributes[item.key]
|
||||||
if (attr !== undefined) {
|
if (attr !== undefined) {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
if (attr !== item.value) {
|
if (attr !== item.value) {
|
||||||
if (action === 'retain') {
|
if (action === 'retain') {
|
||||||
addOp()
|
addOp()
|
||||||
}
|
}
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
if (item.value === null) {
|
if (item.value === null) {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
attributes[item.key] = item.value
|
attributes[item.key] = item.value
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
delete attributes[item.key]
|
delete attributes[item.key]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
item._delete(y)
|
item.delete(transaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item._deleted === false) {
|
if (item.deleted === false) {
|
||||||
if (action === 'insert') {
|
if (action === 'insert') {
|
||||||
addOp()
|
addOp()
|
||||||
}
|
}
|
||||||
|
// @ts-ignore item is ItemFormat
|
||||||
updateCurrentAttributes(currentAttributes, item)
|
updateCurrentAttributes(currentAttributes, item)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
item = item._right
|
item = item.right
|
||||||
}
|
}
|
||||||
addOp()
|
addOp()
|
||||||
while (this._delta.length > 0) {
|
while (this._delta.length > 0) {
|
||||||
@ -433,6 +535,7 @@ class YTextEvent extends YArrayEvent {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// @ts-ignore _delta is defined above
|
||||||
return this._delta
|
return this._delta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,18 +547,31 @@ class YTextEvent extends YArrayEvent {
|
|||||||
* block formats (format information on a paragraph), embeds (complex elements
|
* block formats (format information on a paragraph), embeds (complex elements
|
||||||
* like pictures and videos), and text formats (**bold**, *italic*).
|
* like pictures and videos), and text formats (**bold**, *italic*).
|
||||||
*/
|
*/
|
||||||
export class YText extends YArray {
|
export class YText extends AbstractType {
|
||||||
/**
|
/**
|
||||||
* @param {String} [string] The initial value of the YText.
|
* @param {String} [string] The initial value of the YText.
|
||||||
*/
|
*/
|
||||||
constructor (string) {
|
constructor (string) {
|
||||||
super()
|
super()
|
||||||
if (typeof string === 'string') {
|
/**
|
||||||
const start = new ItemString()
|
* @type {Array<string>?}
|
||||||
start._parent = this
|
*/
|
||||||
start._content = string
|
this._prelimContent = string !== undefined ? [string] : []
|
||||||
this._start = start
|
}
|
||||||
}
|
|
||||||
|
get length () {
|
||||||
|
return this._length
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
* @param {ItemType} item
|
||||||
|
*/
|
||||||
|
_integrate (transaction, item) {
|
||||||
|
super._integrate(transaction, item)
|
||||||
|
// @ts-ignore this._prelimContent is still defined
|
||||||
|
this.insert(0, this._prelimContent.join(''))
|
||||||
|
this._prelimContent = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -494,6 +610,7 @@ export class YText extends YArray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toDomString () {
|
toDomString () {
|
||||||
|
// @ts-ignore
|
||||||
return this.toDelta().map(delta => {
|
return this.toDelta().map(delta => {
|
||||||
const nestedNodes = []
|
const nestedNodes = []
|
||||||
for (let nodeName in delta.attributes) {
|
for (let nodeName in delta.attributes) {
|
||||||
@ -529,40 +646,47 @@ export class YText extends YArray {
|
|||||||
/**
|
/**
|
||||||
* Apply a {@link Delta} on this shared YText type.
|
* Apply a {@link Delta} on this shared YText type.
|
||||||
*
|
*
|
||||||
* @param {Delta} delta The changes to apply on this element.
|
* @param {any} delta The changes to apply on this element.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
applyDelta (delta) {
|
applyDelta (delta) {
|
||||||
this._transact(y => {
|
if (this._y !== null) {
|
||||||
let left = null
|
this._y.transact(transaction => {
|
||||||
let right = this._start
|
/**
|
||||||
const currentAttributes = new Map()
|
* @type {{left:AbstractItem|null,right:AbstractItem|null}}
|
||||||
for (let i = 0; i < delta.length; i++) {
|
*/
|
||||||
let op = delta[i]
|
let pos = { left: null, right: this._start }
|
||||||
if (op.insert !== undefined) {
|
const currentAttributes = new Map()
|
||||||
;[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {})
|
for (let i = 0; i < delta.length; i++) {
|
||||||
} else if (op.retain !== undefined) {
|
const op = delta[i]
|
||||||
;[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {})
|
if (op.insert !== undefined) {
|
||||||
} else if (op.delete !== undefined) {
|
pos = insertText(transaction, this, pos.left, pos.right, currentAttributes, op.insert, op.attributes || {})
|
||||||
;[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes)
|
} else if (op.retain !== undefined) {
|
||||||
|
pos = formatText(transaction, this, pos.left, pos.right, currentAttributes, op.retain, op.attributes || {})
|
||||||
|
} else if (op.delete !== undefined) {
|
||||||
|
pos = deleteText(transaction, this, pos.left, pos.right, currentAttributes, op.delete)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Delta representation of this YText type.
|
* Returns the Delta representation of this YText type.
|
||||||
*
|
*
|
||||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
* @param {Snapshot} [snapshot]
|
||||||
* @param {import('../protocols/history.js').HistorySnapshot} [prevSnapshot]
|
* @param {Snapshot} [prevSnapshot]
|
||||||
* @return {Delta} The Delta representation of this type.
|
* @return {any} The Delta representation of this type.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
toDelta (snapshot, prevSnapshot) {
|
toDelta (snapshot, prevSnapshot) {
|
||||||
let ops = []
|
/**
|
||||||
let currentAttributes = new Map()
|
* @type{Array<any>}
|
||||||
|
*/
|
||||||
|
const ops = []
|
||||||
|
const currentAttributes = new Map()
|
||||||
let str = ''
|
let str = ''
|
||||||
/**
|
/**
|
||||||
* @type {any}
|
* @type {any}
|
||||||
@ -571,12 +695,18 @@ export class YText extends YArray {
|
|||||||
function packStr () {
|
function packStr () {
|
||||||
if (str.length > 0) {
|
if (str.length > 0) {
|
||||||
// pack str with attributes to ops
|
// pack str with attributes to ops
|
||||||
|
/**
|
||||||
|
* @type {Object<string,any>}
|
||||||
|
*/
|
||||||
let attributes = {}
|
let attributes = {}
|
||||||
let addAttributes = false
|
let addAttributes = false
|
||||||
for (let [key, value] of currentAttributes) {
|
for (let [key, value] of currentAttributes) {
|
||||||
addAttributes = true
|
addAttributes = true
|
||||||
attributes[key] = value
|
attributes[key] = value
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @type {Object<string,any>}
|
||||||
|
*/
|
||||||
let op = { insert: str }
|
let op = { insert: str }
|
||||||
if (addAttributes) {
|
if (addAttributes) {
|
||||||
op.attributes = attributes
|
op.attributes = attributes
|
||||||
@ -632,10 +762,13 @@ export class YText extends YArray {
|
|||||||
if (text.length <= 0) {
|
if (text.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this._transact(y => {
|
const y = this._y
|
||||||
let [left, right, currentAttributes] = findPosition(this, index)
|
if (y !== null) {
|
||||||
insertText(y, text, this, left, right, currentAttributes, attributes)
|
y.transact(transaction => {
|
||||||
})
|
const {left, right, currentAttributes} = findPosition(transaction, y.store, this, index)
|
||||||
|
insertText(transaction, this, left, right, currentAttributes, text, attributes)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -652,10 +785,13 @@ export class YText extends YArray {
|
|||||||
if (embed.constructor !== Object) {
|
if (embed.constructor !== Object) {
|
||||||
throw new Error('Embed must be an Object')
|
throw new Error('Embed must be an Object')
|
||||||
}
|
}
|
||||||
this._transact(y => {
|
const y = this._y
|
||||||
let [left, right, currentAttributes] = findPosition(this, index)
|
if (y !== null) {
|
||||||
insertText(y, embed, this, left, right, currentAttributes, attributes)
|
y.transact(transaction => {
|
||||||
})
|
const { left, right, currentAttributes } = findPosition(transaction, y.store, this, index)
|
||||||
|
insertText(transaction, this, left, right, currentAttributes, embed, attributes)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -670,10 +806,13 @@ export class YText extends YArray {
|
|||||||
if (length === 0) {
|
if (length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this._transact(y => {
|
const y = this._y
|
||||||
let [left, right, currentAttributes] = findPosition(this, index)
|
if (y !== null) {
|
||||||
deleteText(y, length, this, left, right, currentAttributes)
|
y.transact(transaction => {
|
||||||
})
|
const { left, right, currentAttributes } = findPosition(transaction, y.store, this, index)
|
||||||
|
deleteText(transaction, this, left, right, currentAttributes, length)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -687,24 +826,21 @@ export class YText extends YArray {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
format (index, length, attributes) {
|
format (index, length, attributes) {
|
||||||
this._transact(y => {
|
const y = this._y
|
||||||
let [left, right, currentAttributes] = findPosition(this, index)
|
if (y !== null) {
|
||||||
if (right === null) {
|
y.transact(transaction => {
|
||||||
return
|
let { left, right, currentAttributes } = findPosition(transaction, y.store, this, index)
|
||||||
}
|
if (right === null) {
|
||||||
formatText(y, length, this, left, right, currentAttributes, attributes)
|
return
|
||||||
})
|
}
|
||||||
}
|
formatText(transaction, this, left, right, currentAttributes, length, attributes)
|
||||||
// TODO: De-duplicate code. The following code is in every type.
|
})
|
||||||
/**
|
}
|
||||||
* Transform this YText to a readable format.
|
|
||||||
* Useful for logging as all Items implement this method.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_logString () {
|
|
||||||
return logItemHelper('YText', this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {decoding.Decoder} decoder
|
||||||
|
* @return {YText}
|
||||||
|
*/
|
||||||
export const readYText = decoder => new YText()
|
export const readYText = decoder => new YText()
|
@ -2,7 +2,6 @@
|
|||||||
import { runTests } from 'lib0/testing.js'
|
import { runTests } from 'lib0/testing.js'
|
||||||
import { isBrowser } from 'lib0/environment.js'
|
import { isBrowser } from 'lib0/environment.js'
|
||||||
import * as log from 'lib0/logging.js'
|
import * as log from 'lib0/logging.js'
|
||||||
import * as deleteStore from './DeleteStore.tests.js'
|
|
||||||
import * as array from './y-array.tests.js'
|
import * as array from './y-array.tests.js'
|
||||||
import * as map from './y-map.tests.js'
|
import * as map from './y-map.tests.js'
|
||||||
import * as text from './y-text.tests.js'
|
import * as text from './y-text.tests.js'
|
||||||
@ -12,4 +11,4 @@ import * as perf from './perf.js'
|
|||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
log.createVConsole(document.body)
|
log.createVConsole(document.body)
|
||||||
}
|
}
|
||||||
runTests({ deleteStore, map, array, text, xml, perf })
|
runTests({ map, array, text, xml, perf })
|
||||||
|
Loading…
x
Reference in New Issue
Block a user