diff --git a/src/model/liverange.js b/src/model/liverange.js index 2822c542b..6549eee02 100644 --- a/src/model/liverange.js +++ b/src/model/liverange.js @@ -129,7 +129,7 @@ function transform( changeType, deltaType, targetRange, sourcePosition ) { const howMany = targetRange.end.offset - targetRange.start.offset; let targetPosition = targetRange.start; - if ( changeType == 'move' ) { + if ( changeType == 'move' || changeType == 'remove' || changeType == 'reinsert' ) { // Range._getTransformedByDocumentChange is expecting `targetPosition` to be "before" move // (before transformation). `targetRange.start` is already after the move happened. // We have to revert `targetPosition` to the state before the move. @@ -142,7 +142,7 @@ function transform( changeType, deltaType, targetRange, sourcePosition ) { // // First, this concerns only `move` change, because insert change includes inserted part always (changeType == 'move'). // Second, this is a case only if moved range was intersecting with this range and was inserted into this range (result.length == 3). - if ( changeType == 'move' && result.length == 3 ) { + if ( ( changeType == 'move' || changeType == 'remove' || changeType == 'reinsert' ) && result.length == 3 ) { // `result[ 2 ]` is a "common part" of this range and moved range. We substitute that common part with the whole // `targetRange` because we want to include whole `targetRange` in this range. result[ 2 ] = targetRange; diff --git a/src/model/range.js b/src/model/range.js index d2dd8ab47..1aaed7a02 100644 --- a/src/model/range.js +++ b/src/model/range.js @@ -462,6 +462,7 @@ export default class Range { } else { const sourceRange = Range.createFromPositionAndShift( sourcePosition, howMany ); + // Edge case for merge detla. if ( deltaType == 'merge' && this.isCollapsed && @@ -471,50 +472,52 @@ export default class Range { // Without fix, the range would end up in the graveyard, together with removed element. //
foo
[]bar
->foobar
[]
->foobar
->foo[]bar
return [ new Range( targetPosition.getShiftedBy( this.start.offset ) ) ]; - } else if ( type == 'move' ) { - // In all examples `[]` is `this` and `{}` is `sourceRange`, while `^` is move target position. - // - // Example: - //xx
^a[b
}c]d
-->xx
a[b
c]d
- // ^xx
a[b
}c]d
-->a[b
xx
c]d
// Notexx
inclusion. - //a[b
}c]d
-->a[b
c]d
- if ( - sourceRange.containsPosition( this.start ) && - this.containsPosition( sourceRange.end ) && - this.end.isAfter( targetPosition ) - ) { - const start = this.start._getCombined( - sourcePosition, - targetPosition._getTransformedByDeletion( sourcePosition, howMany ) - ); - const end = this.end._getTransformedByMove( sourcePosition, targetPosition, howMany, false, false ); - - return [ new Range( start, end ) ]; - } + } + // + // Other edge cases: + // + // In all examples `[]` is `this` and `{}` is `sourceRange`, while `^` is move target position. + // + // Example: + //xx
^a[b
}c]d
-->xx
a[b
c]d
+ // ^xx
a[b
}c]d
-->a[b
xx
c]d
// Notexx
inclusion. + //a[b
}c]d
-->a[b
c]d
+ if ( + sourceRange.containsPosition( this.start ) && + this.containsPosition( sourceRange.end ) && + this.end.isAfter( targetPosition ) + ) { + const start = this.start._getCombined( + sourcePosition, + targetPosition._getTransformedByDeletion( sourcePosition, howMany ) + ); + const end = this.end._getTransformedByMove( sourcePosition, targetPosition, howMany, false, false ); - // Example: - //c[d
a]b
}xx
-->c[d
a]b
xx
- //c[d
a]b
}xx
^ -->c[d
xx
a]b
// Notexx
inclusion. - //c[d
^a]b
}c[d
a]b
c[d
a]b
}xx
-->c[d
a]b
xx
+ //c[d
a]b
}xx
^ -->c[d
xx
a]b
// Notexx
inclusion. + //c[d
^a]b
}c[d
a]b