fix several issues of supporting deleted move ops

This commit is contained in:
Kevin Jahns 2022-07-08 21:36:36 +02:00
parent 0ce40596d1
commit 19723670c4
4 changed files with 24 additions and 9 deletions

View File

@ -204,7 +204,14 @@ export class ContentMove {
let { start, end } = getMovedCoords(this, transaction)
while (start !== end && start != null) {
if (start.moved === item) {
if (!transaction.prevMoved.has(start)) {
const prevMoved = transaction.prevMoved.get(start)
if (addsStruct(transaction, item)) {
if (prevMoved === item) {
// Edge case: Item has been moved by this move op and it has been created & deleted in the same transaction (hence no effect that should be emitted by the change computation)
transaction.prevMoved.delete(start)
}
} else if (prevMoved == null) { // && !addsStruct(tr, item)
// Normal case: item has been moved by this move and it has not been created & deleted in the same transaction
transaction.prevMoved.set(start, item)
}
start.moved = null

View File

@ -16,6 +16,7 @@ import {
RelativePosition, ID, AbstractContent, ContentMove, Transaction, Item, AbstractType // eslint-disable-line
} from '../internals.js'
import { compareRelativePositions } from './RelativePosition.js'
import * as array from 'lib0/array'
const lengthExceeded = error.create('Length exceeded!')
@ -709,7 +710,7 @@ export const getMinimalListViewRanges = (tr, walker, len) => {
// Move ranges must be applied in order
middleMove.end = end
const normalizedRanges = ranges.map(range => {
const normalizedRanges = array.flatten(ranges.map(range => {
// A subset of a range could be moved by another move with a higher priority.
// If that is the case, we need to ignore those moved items.
const { start, end } = getMovedCoords(range, tr)
@ -741,7 +742,7 @@ export const getMinimalListViewRanges = (tr, walker, len) => {
})
}
return ranges
}).flat()
}))
// filter out unnecessary ranges
return normalizedRanges.filter(range => !compareRelativePositions(range.start, range.end))

View File

@ -142,6 +142,8 @@ export class YEvent {
*
* In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
*
* @todo this can be removed in the next release (prefer function)
*
* @param {AbstractStruct} struct
* @return {boolean}
*/
@ -172,7 +174,7 @@ export class YEvent {
const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target))
if (changed.has(null)) {
/**
* @type {Array<{ end: Item | null, move: Item | null, isNew : boolean }>}
* @type {Array<{ end: Item | null, move: Item | null, isNew: boolean, isDeleted: boolean }>}
*/
const movedStack = []
/**
@ -183,6 +185,10 @@ export class YEvent {
* @type {boolean}
*/
let currMoveIsNew = false
/**
* @type {boolean}
*/
let currMoveIsDeleted = false
/**
* @type {Item | null}
*/
@ -212,24 +218,26 @@ export class YEvent {
for (let item = target._start; ;) {
if (item === currMoveEnd && currMove) {
item = currMove
const { end, move, isNew } = movedStack.pop() || { end: null, move: null, isNew: false }
const { end, move, isNew, isDeleted } = movedStack.pop() || { end: null, move: null, isNew: false, isDeleted: false }
currMoveIsNew = isNew
currMoveIsDeleted = isDeleted
currMoveEnd = end
currMove = move
} else if (item === null) {
break
} else if (item.content.constructor === ContentMove) {
if (item.moved === currMove) { // @todo !item.deleted || this.deletes(item)
movedStack.push({ end: currMoveEnd, move: currMove, isNew: currMoveIsNew })
if (item.moved === currMove && (!item.deleted || (this.deletes(item) && !this.adds(item)))) { // @todo !item.deleted || this.deletes(item)
movedStack.push({ end: currMoveEnd, move: currMove, isNew: currMoveIsNew, isDeleted: currMoveIsDeleted })
const { start, end } = getMovedCoords(item.content, tr)
currMove = item
currMoveEnd = end
currMoveIsNew = this.adds(item) || currMoveIsNew
currMoveIsDeleted = item.deleted || currMoveIsDeleted
item = start
continue // do not move to item.right
}
} else if (item.moved !== currMove) {
if (!currMoveIsNew && item.countable && (!item.deleted || this.deletes(item)) && !this.adds(item) && (item.moved === null || isMovedByNew(item)) && (this.transaction.prevMoved.get(item) || null) === currMove) {
if (!currMoveIsNew && item.countable && (!item.deleted || this.deletes(item)) && !this.adds(item) && (item.moved === null || isMovedByNew(item) || currMoveIsDeleted) && (this.transaction.prevMoved.get(item) || null) === currMove) {
if (lastOp === null || lastOp.delete === undefined) {
packOp()
lastOp = { delete: 0 }

View File

@ -569,7 +569,6 @@ export const testMoveDeletions = tc => {
ydoc.transact(tr => {
/** @type {Item} */ (yarray._start).delete(tr)
})
debugger
t.compare(lastDelta, [{ delete: 1 }, { retain: 2 }, { insert: [3] }])
t.compareArrays(yarray.toArray(), [1, 2, 3])
t.compareArrays(yarray.toArray(), array)