fix #481 - calculate path correctly when parents are moved

This commit is contained in:
Kevin Jahns 2023-06-28 15:25:59 +02:00
parent 7ced59c847
commit 5b16071380
2 changed files with 55 additions and 11 deletions

View File

@ -8,6 +8,7 @@ import {
import * as set from 'lib0/set' import * as set from 'lib0/set'
import * as array from 'lib0/array' import * as array from 'lib0/array'
import { addsStruct } from './Transaction.js' import { addsStruct } from './Transaction.js'
import { ListCursor } from './ListCursor.js'
/** /**
* YEvent describes the changes on a YType. * YEvent describes the changes on a YType.
@ -62,7 +63,7 @@ export class YEvent {
*/ */
get path () { get path () {
// @ts-ignore _item is defined because target is integrated // @ts-ignore _item is defined because target is integrated
return getPathTo(this.currentTarget, this.target) return getPathTo(this.currentTarget, this.target, this.transaction)
} }
/** /**
@ -297,12 +298,13 @@ export class YEvent {
* *
* @param {AbstractType<any>} parent * @param {AbstractType<any>} parent
* @param {AbstractType<any>} child target * @param {AbstractType<any>} child target
* @param {Transaction} tr
* @return {Array<string|number>} Path to the target * @return {Array<string|number>} Path to the target
* *
* @private * @private
* @function * @function
*/ */
const getPathTo = (parent, child) => { const getPathTo = (parent, child, tr) => {
const path = [] const path = []
while (child._item !== null && child !== parent) { while (child._item !== null && child !== parent) {
if (child._item.parentSub !== null) { if (child._item.parentSub !== null) {
@ -310,15 +312,11 @@ const getPathTo = (parent, child) => {
path.unshift(child._item.parentSub) path.unshift(child._item.parentSub)
} else { } else {
// parent is array-ish // parent is array-ish
let i = 0 const c = new ListCursor(/** @type {AbstractType<any>} */ (child._item.parent))
let c = /** @type {AbstractType<any>} */ (child._item.parent)._start while (c.nextItem != null && !c.reachedEnd && c.nextItem !== child._item) {
while (c !== child._item && c !== null) { c.forward(tr, (c.nextItem.countable && !c.nextItem.deleted) ? c.nextItem.length : 0, true)
if (!c.deleted) {
i++
}
c = c.right
} }
path.unshift(i) path.unshift(c.index)
} }
child = /** @type {AbstractType<any>} */ (child._item.parent) child = /** @type {AbstractType<any>} */ (child._item.parent)
} }

View File

@ -1,10 +1,56 @@
import { init, compare, applyRandomTests, Doc, AbstractType, TestConnector, Item } from './testHelper.js' // eslint-disable-line import { init, compare, applyRandomTests, Doc, Item } from './testHelper.js' // eslint-disable-line
import * as Y from '../src/index.js' import * as Y from '../src/index.js'
import * as t from 'lib0/testing' import * as t from 'lib0/testing'
import * as prng from 'lib0/prng' import * as prng from 'lib0/prng'
import * as math from 'lib0/math' import * as math from 'lib0/math'
/**
* path should be correct when moving item - see yjs#481
*
* @param {t.TestCase} tc
*/
export const testArrayMovePathIssue481 = tc => {
const { users, testConnector, array0, array1 } = init(tc, { users: 2 })
array0.observeDeep(events => {
events.forEach(event => {
if (event.path.length > 0) {
/**
* @type {any}
*/
let target = event.currentTarget
event.path.forEach(p => {
target = target.get(p)
})
t.assert(target === event.target)
}
})
})
array0.push([
['a', '1.1'],
['b', '2.2'],
['c', '3.1'],
['d', '4.1'],
['e', '5.1']
].map(e => Y.Array.from(e)))
testConnector.flushAllMessages()
users[1].transact(() => {
array1.get(1).insert(0, ['0'])
array1.move(1, 0)
})
testConnector.flushAllMessages()
users[1].transact(() => {
array1.get(3).insert(0, ['1'])
array1.move(3, 4)
})
testConnector.flushAllMessages()
users[1].transact(() => {
array1.get(2).insert(0, ['2'])
array1.move(2, array1.length)
})
testConnector.flushAllMessages()
}
/** /**
* foreach has correct index - see yjs#485 * foreach has correct index - see yjs#485
* *