Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit 30dcf6c

Browse files
author
Piotr Jasiun
authored
Merge pull request #1310 from ckeditor/t/1309
Fix: Corrected offsets transformation in `model.Differ` when multiple change items interfere with each other. Closes #1309. Closes ckeditor/ckeditor5#849.
2 parents 6968eea + 118da77 commit 30dcf6c

File tree

2 files changed

+778
-427
lines changed

2 files changed

+778
-427
lines changed

src/model/differ.js

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,24 @@ export default class Differ {
547547
* @param {Array.<Object>} changes An array containing all the changes done on that element.
548548
*/
549549
_handleChange( inc, changes ) {
550+
// We need a helper variable that will store how many nodes are to be still handled for this change item.
551+
// `nodesToHandle` (how many nodes still need to be handled) and `howMany` (how many nodes were affected)
552+
// needs to be differentiated.
553+
//
554+
// This comes up when there are multiple changes that are affected by `inc` change item.
555+
//
556+
// For example: assume two insert changes: `{ offset: 2, howMany: 1 }` and `{ offset: 5, howMany: 1 }`.
557+
// Assume that `inc` change is remove `{ offset: 2, howMany: 2, nodesToHandle: 2 }`.
558+
//
559+
// Then, we:
560+
// - "forget" about first insert change (it is "eaten" by remove),
561+
// - because of that, at the end we will want to remove only one node (`nodesToHandle = 1`),
562+
// - but still we have to change offset of the second insert change from `5` to `3`!
563+
//
564+
// So, `howMany` does not change throughout items transformation and keeps information about how many nodes were affected,
565+
// while `nodesToHandle` means how many nodes need to be handled after the change item is transformed by other changes.
566+
inc.nodesToHandle = inc.howMany;
567+
550568
for ( const old of changes ) {
551569
const incEnd = inc.offset + inc.howMany;
552570
const oldEnd = old.offset + old.howMany;
@@ -556,8 +574,8 @@ export default class Differ {
556574
if ( inc.offset <= old.offset ) {
557575
old.offset += inc.howMany;
558576
} else if ( inc.offset < oldEnd ) {
559-
old.howMany += inc.howMany;
560-
inc.howMany = 0;
577+
old.howMany += inc.nodesToHandle;
578+
inc.nodesToHandle = 0;
561579
}
562580
}
563581

@@ -608,20 +626,20 @@ export default class Differ {
608626
old.offset = inc.offset;
609627

610628
old.howMany -= intersectionLength;
611-
inc.howMany -= intersectionLength;
629+
inc.nodesToHandle -= intersectionLength;
612630
} else {
613-
old.howMany -= inc.howMany;
614-
inc.howMany = 0;
631+
old.howMany -= inc.nodesToHandle;
632+
inc.nodesToHandle = 0;
615633
}
616634
} else {
617635
if ( inc.offset <= old.offset ) {
618-
inc.howMany = inc.howMany - old.howMany;
636+
inc.nodesToHandle -= old.howMany;
619637
old.howMany = 0;
620638
} else if ( inc.offset < oldEnd ) {
621639
const intersectionLength = oldEnd - inc.offset;
622640

623641
old.howMany -= intersectionLength;
624-
inc.howMany -= intersectionLength;
642+
inc.nodesToHandle -= intersectionLength;
625643
}
626644
}
627645
}
@@ -631,9 +649,9 @@ export default class Differ {
631649
old.offset -= inc.howMany;
632650
} else if ( inc.offset < old.offset ) {
633651
old.offset = inc.offset;
634-
old.howMany += inc.howMany;
652+
old.howMany += inc.nodesToHandle;
635653

636-
inc.howMany = 0;
654+
inc.nodesToHandle = 0;
637655
}
638656
}
639657

@@ -656,7 +674,7 @@ export default class Differ {
656674

657675
old.howMany = inc.offset - old.offset;
658676

659-
const howManyAfter = howMany - old.howMany - inc.howMany;
677+
const howManyAfter = howMany - old.howMany - inc.nodesToHandle;
660678

661679
// Add the second part of attribute change to the beginning of processed array so it won't
662680
// be processed again in this loop.
@@ -695,24 +713,27 @@ export default class Differ {
695713
changes.push( attributePart );
696714
}
697715

698-
inc.howMany = old.offset - inc.offset;
716+
inc.nodesToHandle = old.offset - inc.offset;
699717
} else if ( inc.offset >= old.offset && inc.offset < oldEnd ) {
700718
if ( incEnd > oldEnd ) {
701-
inc.howMany = incEnd - oldEnd;
719+
inc.nodesToHandle = incEnd - oldEnd;
702720
inc.offset = oldEnd;
703721
} else {
704-
inc.howMany = 0;
722+
inc.nodesToHandle = 0;
705723
}
706724
}
707725
}
708726

709727
if ( old.type == 'attribute' ) {
710728
if ( inc.offset >= old.offset && incEnd <= oldEnd ) {
711-
inc.howMany = 0;
729+
inc.nodesToHandle = 0;
712730
}
713731
}
714732
}
715733
}
734+
735+
inc.howMany = inc.nodesToHandle;
736+
delete inc.nodesToHandle;
716737
}
717738

718739
/**

0 commit comments

Comments
 (0)