From 7ba2035ebf18d3b0cabad289670f565ee0cb62b8 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 5 Jul 2024 16:25:13 +0400 Subject: [PATCH] Avoid removing meaningful whitespaces. Fixes #5984 --- src/parser/model/ParserHtml.ts | 11 ++++-- test/specs/parser/model/ParserHtml.ts | 57 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/parser/model/ParserHtml.ts b/src/parser/model/ParserHtml.ts index d98c77d65..d41f0997f 100644 --- a/src/parser/model/ParserHtml.ts +++ b/src/parser/model/ParserHtml.ts @@ -179,7 +179,7 @@ const ParserHtml = (em?: EditorModel, config: ParserConfig & { returnArray?: boo if (typeof obj !== 'object') { obj = { type: compType.id }; } - result = obj + result = obj; break; } } @@ -280,10 +280,13 @@ const ParserHtml = (em?: EditorModel, config: ParserConfig & { returnArray?: boo continue; } - // Throw away empty nodes (keep spaces) + // Try to keep meaningful whitespaces when possible (#5984) + // Ref: https://github.com/GrapesJS/grapesjs/pull/5719#discussion_r1518531999 if (!opts.keepEmptyTextNodes) { - const content = node.nodeValue; - if (content != ' ' && !content!.trim()) { + const content = node.nodeValue || ''; + const isFirstOrLast = i === 0 || i === nodesLen - 1; + const hasNewLive = content.includes('\n'); + if (content != ' ' && !content.trim() && (isFirstOrLast || hasNewLive)) { continue; } } diff --git a/test/specs/parser/model/ParserHtml.ts b/test/specs/parser/model/ParserHtml.ts index ca619f185..c01680be0 100644 --- a/test/specs/parser/model/ParserHtml.ts +++ b/test/specs/parser/model/ParserHtml.ts @@ -493,6 +493,63 @@ describe('ParserHtml', () => { expect(obj.parse(str).html).toEqual(result); }); + test('Cleanup useless empty whitespaces', () => { + const str = `
+

TestText

+
`; + const result = [ + { + tagName: 'div', + components: [ + { + tagName: 'p', + components: { type: 'textnode', content: 'TestText' }, + type: 'text', + }, + ], + }, + ]; + expect(obj.parse(str).html).toEqual(result); + }); + + test('Keep meaningful whitespaces', () => { + const str = `
+

A

B

C

 

D

+
`; + const result = [ + { + tagName: 'div', + type: 'text', + components: [ + { + tagName: 'p', + components: { type: 'textnode', content: 'A' }, + type: 'text', + }, + { type: 'textnode', content: ' ', tagName: '' }, + { + tagName: 'p', + components: { type: 'textnode', content: 'B' }, + type: 'text', + }, + { type: 'textnode', content: ' ', tagName: '' }, + { + tagName: 'p', + components: { type: 'textnode', content: 'C' }, + type: 'text', + }, + { type: 'textnode', content: ' ', tagName: '' }, + { + tagName: 'p', + components: { type: 'textnode', content: 'D' }, + type: 'text', + }, + ], + }, + ]; + expect(obj.parse(str).html).toEqual(result); + }); + test('Parse node with model attributes to fetch', () => { const str = '
test2
';