diff --git a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift index cc1f56f8a..6b50b7a85 100644 --- a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift +++ b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift @@ -122,9 +122,9 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol { for node in element.getChildNodes() { if let textNode = node as? TextNode { - // If this node is plain text just append its preformatted contents + // If this node is plain text append the whitespace normalised version if node.parent() == documentBody { - result.append(NSAttributedString(string: textNode.getWholeText())) + result.append(NSAttributedString(string: textNode.text())) continue } @@ -237,7 +237,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol { content = attributedString(element: childElement, documentBody: documentBody, preserveFormatting: preserveFormatting, listTag: tag, listIndex: &listIndex, indentLevel: indentLevel + 1) - if indentLevel > 0 { + if indentLevel > 0 || !element.ownText().isEmpty { content.insert(NSAttributedString("\n"), at: 0) } diff --git a/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift b/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift index 10332fd3f..4fefc959e 100644 --- a/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift +++ b/ElementX/Sources/Other/HTMLParsing/HTMLFixtures.swift @@ -29,11 +29,11 @@ enum HTMLFixtures: String, CaseIterable { """ case .headers: """ -

H1 Header

-

H2 Header

-

H3 Header

-

H4 Header

-
H5 Header
+

H1 Header

\ +

H2 Header

\ +

H3 Header

\ +

H4 Header

\ +
H5 Header
\
H6 Header
""" case .paragraphs: diff --git a/ElementX/Sources/Other/Pills/MessageText.swift b/ElementX/Sources/Other/Pills/MessageText.swift index e4efb533e..6de78d490 100644 --- a/ElementX/Sources/Other/Pills/MessageText.swift +++ b/ElementX/Sources/Other/Pills/MessageText.swift @@ -199,11 +199,10 @@ struct MessageText_Previews: PreviewProvider, TestablePreview { private static let htmlStringWithQuote = """ -
A blockquote that is long and goes onto multiple lines as the first item in the message
-

Then another line of text here to reply to the blockquote, which is also a multiline component.

+
A blockquote that is long and goes onto multiple lines as the first item in the message

Then another line of text here to reply to the blockquote, which is also a multiline component.

""" - private static let htmlStringWithList = "

This is a list

\n\n" + private static let htmlStringWithList = "

This is a list

\n\n" private static let attributedStringBuilder = AttributedStringBuilder(mentionBuilder: MentionBuilder()) diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png index 6533042f8..3cd3030c1 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:518aca90ecd814093b3ffbfcb361716bc55f0840fb1914d1d2dc9e6def6aee13 -size 1112322 +oid sha256:bce958a2c9eedbc8b4e63c7dc135dff80b249f64c812f47405400e1e2d314e22 +size 1069392 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png index 6533042f8..3cd3030c1 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:518aca90ecd814093b3ffbfcb361716bc55f0840fb1914d1d2dc9e6def6aee13 -size 1112322 +oid sha256:bce958a2c9eedbc8b4e63c7dc135dff80b249f64c812f47405400e1e2d314e22 +size 1069392 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-en-GB-0.png index 11b7513c1..9bbe78ed9 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9858f3bc9676f311a526d2b08a86bc9e46d19a707a052db571f19abe7c9af86 -size 1267614 +oid sha256:c5e5b587c34f19aebcefabf0d9893dfde863390348132483ac8763387b692dc4 +size 1252781 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-pseudo-0.png index 11b7513c1..9bbe78ed9 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9858f3bc9676f311a526d2b08a86bc9e46d19a707a052db571f19abe7c9af86 -size 1267614 +oid sha256:c5e5b587c34f19aebcefabf0d9893dfde863390348132483ac8763387b692dc4 +size 1252781 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-en-GB.png index dc3a5b16b..ed9fd6418 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9991bd3bd6a88efc9f39fa075c0defc2a98f2a5f0f237df478b9926cbc6aadc -size 86111 +oid sha256:5c60f428f0b84c2b499c2a3a5491ed302af3945d2dc93af2ac8702ba37f21568 +size 82432 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-pseudo.png index dc3a5b16b..ed9fd6418 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPad-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9991bd3bd6a88efc9f39fa075c0defc2a98f2a5f0f237df478b9926cbc6aadc -size 86111 +oid sha256:5c60f428f0b84c2b499c2a3a5491ed302af3945d2dc93af2ac8702ba37f21568 +size 82432 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-en-GB.png index ef8e37920..d1b1e9055 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffac5d2e62703aefb5abec3a48eb22f84f4533fe26fc054b3250929138601718 -size 49165 +oid sha256:e36b3662d56586f0f759c03ac878eeebb325f29556e8192904b7146614802a98 +size 48271 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-pseudo.png index ef8e37920..d1b1e9055 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-block-quote-iPhone-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffac5d2e62703aefb5abec3a48eb22f84f4533fe26fc054b3250929138601718 -size 49165 +oid sha256:e36b3662d56586f0f759c03ac878eeebb325f29556e8192904b7146614802a98 +size 48271 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-en-GB.png index 8350f32be..5efead302 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8deba950d704d7e6b73183aa43c62f52c031fbb93bfa546d847282d12bca0b1c -size 75467 +oid sha256:ff732f47d1ee83104eb640216c6849734a4d9b3ad8efa44f4b9bc7bb3284ccc1 +size 74485 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-pseudo.png index 8350f32be..5efead302 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPad-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8deba950d704d7e6b73183aa43c62f52c031fbb93bfa546d847282d12bca0b1c -size 75467 +oid sha256:ff732f47d1ee83104eb640216c6849734a4d9b3ad8efa44f4b9bc7bb3284ccc1 +size 74485 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-en-GB.png index d5440a041..7150bd143 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eabf0c072db6ae1062e14770b4267c1ccaf8d2478f20bde05f9a665594392b8e -size 35067 +oid sha256:8699be861d421ee9615831cb23c28a6be20a223bcc775f7d86394709f1a4f87b +size 34936 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-pseudo.png index d5440a041..7150bd143 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/messageText.With-list-iPhone-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eabf0c072db6ae1062e14770b4267c1ccaf8d2478f20bde05f9a665594392b8e -size 35067 +oid sha256:8699be861d421ee9615831cb23c28a6be20a223bcc775f7d86394709f1a4f87b +size 34936 diff --git a/UnitTests/Sources/AttributedStringBuilderTests.swift b/UnitTests/Sources/AttributedStringBuilderTests.swift index 6d2b55ecd..3b61d9088 100644 --- a/UnitTests/Sources/AttributedStringBuilderTests.swift +++ b/UnitTests/Sources/AttributedStringBuilderTests.swift @@ -23,12 +23,12 @@ class AttributedStringBuilderTests: XCTestCase { return } - XCTAssertEqual(String(attributedString.characters), "H1 Header\n\nH2 Header\n\nH3 Header\n\nH4 Header\n\nH5 Header\n\nH6 Header") + XCTAssertEqual(String(attributedString.characters), "H1 Header\nH2 Header\nH3 Header\nH4 Header\nH5 Header\nH6 Header") - XCTAssertEqual(attributedString.runs.count, 11) // newlines hold no attributes + XCTAssertEqual(attributedString.runs.count, 4) // newlines hold no attributes let pointSizes = attributedString.runs.compactMap(\.uiKit.font?.pointSize) - XCTAssertEqual(pointSizes, [23, 23, 23, 21, 19, 17]) + XCTAssertEqual(pointSizes, [23, 21, 19, 17]) } func testRenderHTMLStringWithPreCode() { @@ -46,7 +46,7 @@ class AttributedStringBuilderTests: XCTestCase { return } - XCTAssertEqual(regex.numberOfMatches(in: string, options: [], range: .init(location: 0, length: string.count)), 18) + XCTAssertEqual(regex.numberOfMatches(in: string, options: [], range: .init(location: 0, length: string.count)), 13) } func testRenderHTMLStringWithLink() { @@ -270,22 +270,24 @@ class AttributedStringBuilderTests: XCTestCase { } func testSingleBlockquote() { - let htmlString = "
Blockquote
" + let htmlString = "
Blockquote

Another paragraph

" guard let attributedString = attributedStringBuilder.fromHTML(htmlString) else { XCTFail("Could not build the attributed string") return } - XCTAssertEqual(attributedString.runs.count, 1) + XCTAssertEqual(attributedString.runs.count, 2) - XCTAssertEqual(attributedString.formattedComponents.count, 1) + XCTAssertEqual(attributedString.formattedComponents.count, 2) for run in attributedString.runs where run.elementX.blockquote ?? false { return } XCTFail("Couldn't find blockquote") + + XCTAssertEqual(String(attributedString.characters), "Blockquote\nAnother paragraph") } // swiftlint:disable line_length @@ -699,7 +701,7 @@ class AttributedStringBuilderTests: XCTestCase { return } - XCTAssertEqual(String(attributedString.characters), "like\n\n • this\ntest") + XCTAssertEqual(String(attributedString.characters), "like\n • this\ntest") } func testUnorderedList() { @@ -768,6 +770,30 @@ class AttributedStringBuilderTests: XCTestCase { XCTAssertEqual(String(attributedString.characters), " 1. A\n • A1\n • A2\n • A3\n 2. B\n 3. C") } + // https://github.com/element-hq/element-x-ios/issues/4856 + func testNormalisedWhitespaces() { + let html = """ + Stefan pushed + 2 commits + to + main: + """ + guard let attributedString = attributedStringBuilder.fromHTML(html) else { + XCTFail("Could not build the attributed string") + return + } + + XCTAssertEqual(String(attributedString.characters), "Stefan pushed 2 commits to main:\n • Some update \n • Some other update") + } + // MARK: - Phishing prevention func testPhishingLink() {