From ba177a89d49da59f9cfe56b96b82c7a2f4040b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Ho=CC=88=C3=9Fl?= Date: Mon, 5 Apr 2021 10:00:47 +0200 Subject: [PATCH] Allow formatting-only-changes without breaking the inline diff --- .../app/core/ui-services/diff.service.spec.ts | 28 ++++++++++++- .../src/app/core/ui-services/diff.service.ts | 42 ++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/client/src/app/core/ui-services/diff.service.spec.ts b/client/src/app/core/ui-services/diff.service.spec.ts index 2247ffb0b..24309298d 100644 --- a/client/src/app/core/ui-services/diff.service.spec.ts +++ b/client/src/app/core/ui-services/diff.service.spec.ts @@ -936,7 +936,7 @@ describe('DiffService', () => { const diff = service.diff(before, after); expect(diff).toBe( - '

...so frißt er Euch alle mit Haut und Haar.

...so frißt er Euch alle mit Haut und Haar.

' + '

...so frißt er Euch alleEuch alle mit Haut und Haar.

' ); })); @@ -947,7 +947,7 @@ describe('DiffService', () => { const diff = service.diff(before, after); expect(diff).toBe( - '

...so frißt er Euch alle mit Haut und Haar.

...so frißt er Euch alle mit Haut und Haar.

' + '

...so frißt er Euch alleEuch alle mit Haut und Haar.

' ); })); @@ -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 = '

This is a text with a word that will be formatted

', + after = '

This is a text with a word that will be formatted

'; + const diff = service.diff(before, after); + expect(diff).toBe( + '

This is a text with a wordword that will be formatted

' + ); + } + )); + + it('does not fall back to block level replacement when only a formatting is deleted', inject( + [DiffService], + (service: DiffService) => { + const before = '

This is a text with a word that is formatted

', + after = '

This is a text with a word that is formatted

'; + const diff = service.diff(before, after); + expect(diff).toBe( + '

This is a text with a wordword that is formatted

' + ); + } + )); + it('works with multiple inserted paragraphs', inject([DiffService], (service: DiffService) => { const before = '

This is the text before

', after = '

This is the text before

\n

This is one added line

\n

Another added line

'; diff --git a/client/src/app/core/ui-services/diff.service.ts b/client/src/app/core/ui-services/diff.service.ts index 33bb4d247..480af42b4 100644 --- a/client/src/app/core/ui-services/diff.service.ts +++ b/client/src/app/core/ui-services/diff.service.ts @@ -965,7 +965,7 @@ export class DiffService { let found, inner; while (!!(found = findDel.exec(html))) { inner = found[1].replace(/]*>/gi, ''); - if (inner.match(/<[^>]*>/)) { + if (!this.isValidInlineHtml(inner)) { return true; } } @@ -2081,6 +2081,46 @@ export class DiffService { } ); + // formatted => formattedformatted + diffUnnormalized = diffUnnormalized.replace( + /<(span|strong|em|b|i|u|s|a|small|big|sup|sub)( [^>]*)?><\/ins>([^<]*)<\/\1><\/ins>/gi, + (whole: string, inlineTag: string, tagAttributes: string, content: string): string => { + return ( + '' + + content + + '' + + '<' + + inlineTag + + (tagAttributes ? tagAttributes : '') + + '>' + + content + + '' + ); + } + ); + + // formatted => formattedformatted + diffUnnormalized = diffUnnormalized.replace( + /<(span|strong|em|b|i|u|s|a|small|big|sup|sub)( [^>]*)?><\/del>([^<]*)<\/\1><\/del>/gi, + (whole: string, inlineTag: string, tagAttributes: string, content: string): string => { + return ( + '<' + + inlineTag + + (tagAttributes ? tagAttributes : '') + + '>' + + content + + '' + + '' + + content + + '' + ); + } + ); + //

->

diffUnnormalized = diffUnnormalized.replace( /(<\/(p|div|blockquote|li)>)(\s*)<\/(ins|del)>/gi,