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

Commit

Permalink
Merge pull request #1310 from ckeditor/t/1309
Browse files Browse the repository at this point in the history
Fix: Corrected offsets transformation in `model.Differ` when multiple change items interfere with each other. Closes #1309. Closes ckeditor/ckeditor5#849.
  • Loading branch information
Piotr Jasiun authored Feb 20, 2018
2 parents 6968eea + 118da77 commit 30dcf6c
Show file tree
Hide file tree
Showing 2 changed files with 778 additions and 427 deletions.
49 changes: 35 additions & 14 deletions src/model/differ.js
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,24 @@ export default class Differ {
* @param {Array.<Object>} changes An array containing all the changes done on that element.
*/
_handleChange( inc, changes ) {
// We need a helper variable that will store how many nodes are to be still handled for this change item.
// `nodesToHandle` (how many nodes still need to be handled) and `howMany` (how many nodes were affected)
// needs to be differentiated.
//
// This comes up when there are multiple changes that are affected by `inc` change item.
//
// For example: assume two insert changes: `{ offset: 2, howMany: 1 }` and `{ offset: 5, howMany: 1 }`.
// Assume that `inc` change is remove `{ offset: 2, howMany: 2, nodesToHandle: 2 }`.
//
// Then, we:
// - "forget" about first insert change (it is "eaten" by remove),
// - because of that, at the end we will want to remove only one node (`nodesToHandle = 1`),
// - but still we have to change offset of the second insert change from `5` to `3`!
//
// So, `howMany` does not change throughout items transformation and keeps information about how many nodes were affected,
// while `nodesToHandle` means how many nodes need to be handled after the change item is transformed by other changes.
inc.nodesToHandle = inc.howMany;

for ( const old of changes ) {
const incEnd = inc.offset + inc.howMany;
const oldEnd = old.offset + old.howMany;
Expand All @@ -556,8 +574,8 @@ export default class Differ {
if ( inc.offset <= old.offset ) {
old.offset += inc.howMany;
} else if ( inc.offset < oldEnd ) {
old.howMany += inc.howMany;
inc.howMany = 0;
old.howMany += inc.nodesToHandle;
inc.nodesToHandle = 0;
}
}

Expand Down Expand Up @@ -608,20 +626,20 @@ export default class Differ {
old.offset = inc.offset;

old.howMany -= intersectionLength;
inc.howMany -= intersectionLength;
inc.nodesToHandle -= intersectionLength;
} else {
old.howMany -= inc.howMany;
inc.howMany = 0;
old.howMany -= inc.nodesToHandle;
inc.nodesToHandle = 0;
}
} else {
if ( inc.offset <= old.offset ) {
inc.howMany = inc.howMany - old.howMany;
inc.nodesToHandle -= old.howMany;
old.howMany = 0;
} else if ( inc.offset < oldEnd ) {
const intersectionLength = oldEnd - inc.offset;

old.howMany -= intersectionLength;
inc.howMany -= intersectionLength;
inc.nodesToHandle -= intersectionLength;
}
}
}
Expand All @@ -631,9 +649,9 @@ export default class Differ {
old.offset -= inc.howMany;
} else if ( inc.offset < old.offset ) {
old.offset = inc.offset;
old.howMany += inc.howMany;
old.howMany += inc.nodesToHandle;

inc.howMany = 0;
inc.nodesToHandle = 0;
}
}

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

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

const howManyAfter = howMany - old.howMany - inc.howMany;
const howManyAfter = howMany - old.howMany - inc.nodesToHandle;

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

inc.howMany = old.offset - inc.offset;
inc.nodesToHandle = old.offset - inc.offset;
} else if ( inc.offset >= old.offset && inc.offset < oldEnd ) {
if ( incEnd > oldEnd ) {
inc.howMany = incEnd - oldEnd;
inc.nodesToHandle = incEnd - oldEnd;
inc.offset = oldEnd;
} else {
inc.howMany = 0;
inc.nodesToHandle = 0;
}
}
}

if ( old.type == 'attribute' ) {
if ( inc.offset >= old.offset && incEnd <= oldEnd ) {
inc.howMany = 0;
inc.nodesToHandle = 0;
}
}
}
}

inc.howMany = inc.nodesToHandle;
delete inc.nodesToHandle;
}

/**
Expand Down
Loading

0 comments on commit 30dcf6c

Please sign in to comment.