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