Merge pull request #5992 from CatoTH/bugfix/diff-only-formatting-changes

Allow formatting-only-changes without breaking the inline diff
This commit is contained in:
Emanuel Schütze 2021-04-06 22:35:07 +02:00 committed by GitHub
commit 1edf4437a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 3 deletions

View File

@ -936,7 +936,7 @@ describe('DiffService', () => {
const diff = service.diff(before, after); const diff = service.diff(before, after);
expect(diff).toBe( expect(diff).toBe(
'<P class="delete">...so frißt er Euch alle mit Haut und Haar.</P><P class="insert">...so frißt er <SPAN>Euch alle</SPAN> mit Haut und Haar.</P>' '<p>...so frißt er <del>Euch alle</del><ins><span style="color: #000000;">Euch alle</span></ins> mit Haut und Haar.</p>'
); );
})); }));
@ -947,7 +947,7 @@ describe('DiffService', () => {
const diff = service.diff(before, after); const diff = service.diff(before, after);
expect(diff).toBe( expect(diff).toBe(
'<P class="delete">...so frißt er Euch alle mit Haut und Haar.</P><P class="insert">...so frißt er <SPAN style="font-size: 2em; opacity: 0.5">Euch alle</SPAN> mit Haut und Haar.</P>' '<p>...so frißt er <del>Euch alle</del><ins><span style="font-size: 2em; color: #000000; opacity: 0.5">Euch alle</span></ins> mit Haut und Haar.</p>'
); );
})); }));
@ -1001,6 +1001,30 @@ describe('DiffService', () => {
} }
)); ));
it('does not fall back to block level replacement when only a formatting is inserted', inject(
[DiffService],
(service: DiffService) => {
const before = '<p>This is a text with a word that will be formatted</p>',
after = '<p>This is a text with a <span class="testclass">word</span> that will be formatted</p>';
const diff = service.diff(before, after);
expect(diff).toBe(
'<p>This is a text with a <del>word</del><ins><span class="testclass">word</span></ins> that will be formatted</p>'
);
}
));
it('does not fall back to block level replacement when only a formatting is deleted', inject(
[DiffService],
(service: DiffService) => {
const before = '<p>This is a text with a <strong>word</strong> that is formatted</p>',
after = '<p>This is a text with a word that is formatted</p>';
const diff = service.diff(before, after);
expect(diff).toBe(
'<p>This is a text with a <del><strong>word</strong></del><ins>word</ins> that is formatted</p>'
);
}
));
it('works with multiple inserted paragraphs', inject([DiffService], (service: DiffService) => { it('works with multiple inserted paragraphs', inject([DiffService], (service: DiffService) => {
const before = '<p>This is the text before</p>', const before = '<p>This is the text before</p>',
after = '<p>This is the text before</p>\n<p>This is one added line</p>\n<p>Another added line</p>'; after = '<p>This is the text before</p>\n<p>This is one added line</p>\n<p>Another added line</p>';

View File

@ -965,7 +965,7 @@ export class DiffService {
let found, inner; let found, inner;
while (!!(found = findDel.exec(html))) { while (!!(found = findDel.exec(html))) {
inner = found[1].replace(/<br[^>]*>/gi, ''); inner = found[1].replace(/<br[^>]*>/gi, '');
if (inner.match(/<[^>]*>/)) { if (!this.isValidInlineHtml(inner)) {
return true; return true;
} }
} }
@ -2081,6 +2081,46 @@ export class DiffService {
} }
); );
// <ins><STRONG></ins>formatted<ins></STRONG></ins> => <del>formatted</del><ins><STRONG>formatted</STRONG></ins>
diffUnnormalized = diffUnnormalized.replace(
/<ins><(span|strong|em|b|i|u|s|a|small|big|sup|sub)( [^>]*)?><\/ins>([^<]*)<ins><\/\1><\/ins>/gi,
(whole: string, inlineTag: string, tagAttributes: string, content: string): string => {
return (
'<del>' +
content +
'</del>' +
'<ins><' +
inlineTag +
(tagAttributes ? tagAttributes : '') +
'>' +
content +
'</' +
inlineTag +
'></ins>'
);
}
);
// <del><STRONG></del>formatted<del></STRONG></del> => <del><STRONG>formatted</STRONG></del><ins>formatted</ins>
diffUnnormalized = diffUnnormalized.replace(
/<del><(span|strong|em|b|i|u|s|a|small|big|sup|sub)( [^>]*)?><\/del>([^<]*)<del><\/\1><\/del>/gi,
(whole: string, inlineTag: string, tagAttributes: string, content: string): string => {
return (
'<del><' +
inlineTag +
(tagAttributes ? tagAttributes : '') +
'>' +
content +
'</' +
inlineTag +
'></del>' +
'<ins>' +
content +
'</ins>'
);
}
);
// </p> </ins> -> </ins></p> // </p> </ins> -> </ins></p>
diffUnnormalized = diffUnnormalized.replace( diffUnnormalized = diffUnnormalized.replace(
/(<\/(p|div|blockquote|li)>)(\s*)<\/(ins|del)>/gi, /(<\/(p|div|blockquote|li)>)(\s*)<\/(ins|del)>/gi,