From e7405051d10e13a7f12972ce6dfa7d3c1351db1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Poizat?= Date: Mon, 15 Dec 2025 11:13:22 +0100 Subject: [PATCH] fixup! Use html parser instead of regex to clean composer input Improve efficiency and add more tests in convertHtmlContentToTextContent --- core/lib/utils/string_convert.dart | 19 ++----- core/test/utils/string_convert_test.dart | 63 ++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/core/lib/utils/string_convert.dart b/core/lib/utils/string_convert.dart index 595ef1958..fefedf069 100644 --- a/core/lib/utils/string_convert.dart +++ b/core/lib/utils/string_convert.dart @@ -204,22 +204,11 @@ class StringConvert { // Each paragraph is surrounded by block tags so we add a /n for each block tag // Even
are surrounded by block tags so we can ignore
and treat them // as paragraph - const blockTags = [ - 'p', - 'div', - 'li', - 'section', - 'article', - 'header', - 'footer', - 'h1','h2','h3','h4','h5','h6' - ]; + const blockTags = 'p, div, li, section, blockquote, article, header, footer, h1, h2, h3, h4, h5, h6'; - for (final tag in blockTags) { - document.querySelectorAll(tag).forEach((element) { - element.append(Text('\n')); - }); - } + document.querySelectorAll(blockTags).forEach((element) { + element.append(Text('\n')); + }); final String textContent = document.body?.text ?? ''; diff --git a/core/test/utils/string_convert_test.dart b/core/test/utils/string_convert_test.dart index b72ab12db..d3dde6e70 100644 --- a/core/test/utils/string_convert_test.dart +++ b/core/test/utils/string_convert_test.dart @@ -831,5 +831,68 @@ void main() { expect(result, 'First paragraph\n\nSecond paragraph'); }); + + test('should preserve list items for ul li', () { + const htmlContent = ''; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'First item\nSecond item\nThird item'); + }); + + test('should preserve list items for ol li', () { + const htmlContent = '
  1. First item
  2. Second item
  3. Third item
'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'First item\nSecond item\nThird item'); + }); + + test('should strip inline style about text alignment', () { + const htmlContent = '

First paragraph

Aligned right text

Last paragraph

'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'First paragraph\nAligned right text\nLast paragraph'); + }); + + test('should strip inline style about indentation', () { + const htmlContent = '

First paragraph

Indented text

Last paragraph

'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'First paragraph\nIndented text\nLast paragraph'); + }); + + test('should decode HTML entities', () { + const htmlContent = '

Text with   and & and < and > and "

'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'Text with \u00A0 and & and < and > and "'); + }); + + test('should preserve text with nested inline formatting', () { + const htmlContent = '

Text with bold and italic and underline

'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'Text with bold and italic and underline'); + }); + + test('should handle empty content', () { + const htmlContent = '

'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, ''); + }); + + test('should preserve header text with line breaks', () { + const htmlContent = '

Main Title

Content paragraph

'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'Main Title\nContent paragraph'); + }); + + test('should preserve link text only', () { + const htmlContent = '

Click here for more info

'; + final result = StringConvert.convertHtmlContentToTextContent(htmlContent); + + expect(result, 'Click here for more info'); + }); }); }