added tests for quoting multiple elements in arrays
This commit is contained in:
parent
5415565cf0
commit
535bcc3424
@ -10,7 +10,8 @@ import {
|
||||
readYXmlText,
|
||||
UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction, Item, YEvent, AbstractType, // eslint-disable-line
|
||||
readYWeakLink,
|
||||
unlinkFrom
|
||||
unlinkFrom,
|
||||
ID
|
||||
} from '../internals.js'
|
||||
|
||||
import * as error from 'lib0/error'
|
||||
@ -113,15 +114,17 @@ export class ContentType {
|
||||
// when removing weak links, remove references to them
|
||||
// from type they're pointing to
|
||||
const type = /** @type {WeakLink<any>} */ (this.type);
|
||||
const end = /** @type {ID} */ (type._quoteEnd.item)
|
||||
for (let item = type._firstItem; item !== null; item = item.right) {
|
||||
if (item.linked) {
|
||||
unlinkFrom(transaction, item, type)
|
||||
}
|
||||
if (item === type._lastItem) {
|
||||
const lastId = item.lastId
|
||||
if (lastId.client === end.client && lastId.clock === end.clock) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
type._firstItem = type._lastItem = null
|
||||
type._firstItem = null
|
||||
}
|
||||
|
||||
let item = this.type._start
|
||||
|
@ -40,14 +40,12 @@ export class YWeakLink extends AbstractType {
|
||||
* @param {RelativePosition} start
|
||||
* @param {RelativePosition} end
|
||||
* @param {Item|null} firstItem
|
||||
* @param {Item|null} lastItem
|
||||
*/
|
||||
constructor(start, end, firstItem, lastItem) {
|
||||
constructor(start, end, firstItem) {
|
||||
super()
|
||||
this._quoteStart = start
|
||||
this._quoteEnd = end
|
||||
this._firstItem = firstItem
|
||||
this._lastItem = lastItem
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,11 +88,16 @@ export class YWeakLink extends AbstractType {
|
||||
unqote() {
|
||||
let result = /** @type {Array<any>} */ ([])
|
||||
let item = this._firstItem
|
||||
const end = /** @type {ID} */ (this._quoteEnd.item)
|
||||
//TODO: moved elements
|
||||
while (item !== null && item !== this._lastItem) {
|
||||
while (item !== null) {
|
||||
if (!item.deleted) {
|
||||
result = result.concat(item.content.getContent())
|
||||
}
|
||||
const lastId = item.lastId
|
||||
if (lastId.client === end.client && lastId.clock === end.clock) {
|
||||
break;
|
||||
}
|
||||
item = item.right
|
||||
}
|
||||
return result
|
||||
@ -118,22 +121,22 @@ export class YWeakLink extends AbstractType {
|
||||
// in such case we need to cut of the linked element into a
|
||||
// separate block
|
||||
let firstItem = this._firstItem !== null ? this._firstItem : getItemCleanStart(transaction, /** @type {ID} */ (this._quoteStart.item))
|
||||
let lastItem = this._lastItem !== null ? this._lastItem : getItemCleanEnd(transaction, y.store, /** @type {ID} */(this._quoteEnd.item))
|
||||
getItemCleanEnd(transaction, y.store, /** @type {ID} */(this._quoteEnd.item))
|
||||
if (firstItem.parentSub !== null) {
|
||||
// for maps, advance to most recent item
|
||||
while (firstItem.right !== null) {
|
||||
firstItem = firstItem.right
|
||||
}
|
||||
lastItem = firstItem
|
||||
}
|
||||
this._firstItem = firstItem
|
||||
this._lastItem = lastItem
|
||||
|
||||
/** @type {Item|null} */
|
||||
let item = firstItem
|
||||
for (; item !== null; item = item.right) {
|
||||
let end = /** @type {ID} */ (this._quoteEnd.item)
|
||||
for (;item !== null; item = item.right) {
|
||||
createLink(transaction, item, this)
|
||||
if (item === lastItem) {
|
||||
const lastId = item.lastId
|
||||
if (lastId.client === end.client && lastId.clock === end.clock) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -145,14 +148,14 @@ export class YWeakLink extends AbstractType {
|
||||
* @return {YWeakLink<T>}
|
||||
*/
|
||||
_copy () {
|
||||
return new YWeakLink(this._quoteStart, this._quoteEnd, this._firstItem, this._lastItem)
|
||||
return new YWeakLink(this._quoteStart, this._quoteEnd, this._firstItem)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {YWeakLink<T>}
|
||||
*/
|
||||
clone () {
|
||||
return new YWeakLink(this._quoteStart, this._quoteEnd, this._firstItem, this._lastItem)
|
||||
return new YWeakLink(this._quoteStart, this._quoteEnd, this._firstItem)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,7 +197,7 @@ export const readYWeakLink = decoder => {
|
||||
const startID = readID(decoder.restDecoder)
|
||||
const start = new RelativePosition(null, null, startID, startAssoc)
|
||||
const end = new RelativePosition(null, null, isSingle ? startID : readID(decoder.restDecoder), endAssoc)
|
||||
return new YWeakLink(start, end, null, null)
|
||||
return new YWeakLink(start, end, null)
|
||||
}
|
||||
|
||||
const invalidQuotedRange = error.create('Invalid quoted range length.')
|
||||
@ -223,33 +226,36 @@ export const arrayWeakLink = (transaction, parent, index, length = 1) => {
|
||||
index -= startItem.length
|
||||
}
|
||||
}
|
||||
|
||||
if (startItem !== null) {
|
||||
let endItem = startItem
|
||||
let remaining = length
|
||||
for (;endItem !== null && endItem.right !== null && endItem.length > remaining; endItem = endItem.right) {
|
||||
// iterate over the items to reach the last block in the quoted range
|
||||
remaining -= endItem.length
|
||||
}
|
||||
if (endItem.length >= remaining) {
|
||||
endItem = getItemCleanEnd(transaction, transaction.doc.store, createID(startItem.id.client, startItem.id.clock + remaining - 1))
|
||||
const start = new RelativePosition(null, null, startItem.id, 0)
|
||||
const end = new RelativePosition(null, null, endItem.lastId, -1)
|
||||
const link = new YWeakLink(start, end, startItem, endItem)
|
||||
if (parent.doc !== null) {
|
||||
transact(parent.doc, (transaction) => {
|
||||
for (let item = link._firstItem; item !== null; item = item = item.right) {
|
||||
createLink(transaction, item, link)
|
||||
if (item === link._lastItem) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
let endItem = startItem
|
||||
let remaining = length
|
||||
for (;endItem !== null; endItem = endItem.right) {
|
||||
if (!endItem.deleted && endItem.countable) {
|
||||
if (remaining > endItem.length) {
|
||||
remaining -= endItem.length
|
||||
} else {
|
||||
endItem = getItemCleanEnd(transaction, transaction.doc.store, createID(endItem.id.client, endItem.id.clock + remaining - 1))
|
||||
break;
|
||||
}
|
||||
return link
|
||||
}
|
||||
}
|
||||
|
||||
if (startItem !== null && endItem !== null) {
|
||||
const start = new RelativePosition(null, null, startItem.id, 0)
|
||||
const end = new RelativePosition(null, null, endItem.lastId, -1)
|
||||
const link = new YWeakLink(start, end, startItem)
|
||||
if (parent.doc !== null) {
|
||||
transact(parent.doc, (transaction) => {
|
||||
const end = /** @type {ID} */ (link._quoteEnd.item)
|
||||
for (let item = link._firstItem; item !== null; item = item = item.right) {
|
||||
createLink(transaction, item, link)
|
||||
const lastId = item.lastId
|
||||
if (lastId.client === end.client && lastId.clock === end.clock) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return link
|
||||
}
|
||||
throw invalidQuotedRange
|
||||
}
|
||||
|
||||
@ -265,7 +271,7 @@ export const mapWeakLink = (parent, key) => {
|
||||
if (item !== undefined) {
|
||||
const start = new RelativePosition(null, null, item.id, 0)
|
||||
const end = new RelativePosition(null, null, item.id, -1)
|
||||
const link = new YWeakLink(start, end, item, item)
|
||||
const link = new YWeakLink(start, end, item)
|
||||
if (parent.doc !== null) {
|
||||
transact(parent.doc, (transaction) => {
|
||||
createLink(transaction, item, link)
|
||||
|
@ -42,6 +42,75 @@ export const testBasicArray = tc => {
|
||||
t.compare(array1.get(3).deref(), 2)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testArrayQuoteMultipleElements = tc => {
|
||||
const { testConnector, array0, array1 } = init(tc, {users:2})
|
||||
const nested = new Y.Map([['key', 'value']])
|
||||
array0.insert(0, [1, 2, nested, 3])
|
||||
array0.insert(0, [array0.quote(1, 3)])
|
||||
|
||||
const link0 = array0.get(0)
|
||||
t.compare(link0.unqote(), [2, nested, 3])
|
||||
t.compare(array0.get(1), 1)
|
||||
t.compare(array0.get(2), 2)
|
||||
t.compare(array0.get(3), nested)
|
||||
t.compare(array0.get(4), 3)
|
||||
|
||||
testConnector.flushAllMessages()
|
||||
|
||||
const link1 = array1.get(0)
|
||||
let unqoted = link1.unqote()
|
||||
t.compare(unqoted[0], 2)
|
||||
t.compare(unqoted[1].toJSON(), {'key':'value'})
|
||||
t.compare(unqoted[2], 3)
|
||||
t.compare(array1.get(1), 1)
|
||||
t.compare(array1.get(2), 2)
|
||||
t.compare(array1.get(3).toJSON(), {'key':'value'})
|
||||
t.compare(array1.get(4), 3)
|
||||
|
||||
array1.insert(3, ['A', 'B'])
|
||||
unqoted = link1.unqote()
|
||||
t.compare(unqoted[0], 2)
|
||||
t.compare(unqoted[1], 'A')
|
||||
t.compare(unqoted[2], 'B')
|
||||
t.compare(unqoted[3].toJSON(), {'key':'value'})
|
||||
t.compare(unqoted[4], 3)
|
||||
|
||||
testConnector.flushAllMessages()
|
||||
|
||||
t.compare(array0.get(0).unqote(), [2, 'A', 'B', nested, 3])
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
export const testSelfQuotation = tc => {
|
||||
const { testConnector, array0, array1 } = init(tc, {users:2})
|
||||
array0.insert(0, [1, 2, 3, 4])
|
||||
const link0 = array0.quote(0, 3)
|
||||
array0.insert(1, [link0]) // link is inserted into its own range
|
||||
|
||||
t.compare(link0.unqote(), [1, link0, 2, 3])
|
||||
t.compare(array0.get(0), 1)
|
||||
t.compare(array0.get(1), link0)
|
||||
t.compare(array0.get(2), 2)
|
||||
t.compare(array0.get(3), 3)
|
||||
t.compare(array0.get(4), 4)
|
||||
|
||||
testConnector.flushAllMessages()
|
||||
|
||||
const link1 = array1.get(1)
|
||||
let unqoted = link1.unqote()
|
||||
t.compare(unqoted, [1, link1, 2, 3])
|
||||
t.compare(array1.get(0), 1)
|
||||
t.compare(array1.get(1), link1)
|
||||
t.compare(array1.get(2), 2)
|
||||
t.compare(array1.get(3), 3)
|
||||
t.compare(array1.get(4), 4)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {t.TestCase} tc
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user