diff --git a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift index b42e9e463..5543a4cd7 100644 --- a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift +++ b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift @@ -100,9 +100,9 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol { var attributedString = AttributedString(attributedString[range]) // Remove trailing new lines if any - if let lastCharacter = attributedString.characters.last, - lastCharacter.isNewline { - attributedString = AttributedString(attributedString.characters.dropLast()) + if attributedString.characters.last?.isNewline ?? false, + let range = attributedString.range(of: "\n", options: .backwards, locale: nil) { + attributedString.removeSubrange(range) } return AttributedStringBuilderComponent(attributedString: attributedString, isBlockquote: value != nil) diff --git a/ElementXTests/AttributedStringBuilderTests.swift b/ElementXTests/AttributedStringBuilderTests.swift index 501aeb6d8..300626728 100644 --- a/ElementXTests/AttributedStringBuilderTests.swift +++ b/ElementXTests/AttributedStringBuilderTests.swift @@ -269,6 +269,89 @@ The text after the blockquote XCTFail("Couldn't find blockquote") } + func testBlockquoteWithLink() { + let htmlString = "
Blockquote with a link in it
" + + guard let attributedString = attributedStringBuilder.fromHTML(htmlString) else { + XCTFail("Could not build the attributed string") + return + } + + XCTAssertEqual(attributedString.runs.count, 3) + + guard let coalescedComponents = attributedStringBuilder.blockquoteCoalescedComponentsFrom(attributedString) else { + XCTFail("Could not build the attributed string components") + return + } + XCTAssertEqual(coalescedComponents.count, 1) + + XCTAssertEqual(coalescedComponents.first?.attributedString.runs.count, 3, "Link not present in the component") + + var foundBlockquoteAndLink = false + for run in attributedString.runs { + if run.elementX.blockquote != nil && run.link != nil { + foundBlockquoteAndLink = true + } + } + + XCTAssertNotNil(foundBlockquoteAndLink, "Couldn't find blockquote or link") + } + + func testMultipleGroupedBlockquotes() { + let htmlString = """ +
First blockquote with a link in it
+
Second blockquote with a link in it
+
Third blockquote with a link in it
+""" + + guard let attributedString = attributedStringBuilder.fromHTML(htmlString) else { + XCTFail("Could not build the attributed string") + return + } + + XCTAssertEqual(attributedString.runs.count, 7) + + XCTAssertEqual(attributedStringBuilder.blockquoteCoalescedComponentsFrom(attributedString)?.count, 1) + + var numberOfBlockquotes = 0 + for run in attributedString.runs { + if run.elementX.blockquote != nil && run.link != nil { + numberOfBlockquotes += 1 + } + } + + XCTAssertEqual(numberOfBlockquotes, 3, "Couldn't find all the blockquotes") + } + + func testMultipleSeparatedBlockquotes() { + let htmlString = """ +First +
blockquote with a link in it
+Second +
blockquote with a link in it
+Third +
blockquote with a link in it
+""" + + guard let attributedString = attributedStringBuilder.fromHTML(htmlString) else { + XCTFail("Could not build the attributed string") + return + } + + XCTAssertEqual(attributedString.runs.count, 12) + + XCTAssertEqual(attributedStringBuilder.blockquoteCoalescedComponentsFrom(attributedString)?.count, 6) + + var numberOfBlockquotes = 0 + for run in attributedString.runs { + if run.elementX.blockquote != nil && run.link != nil { + numberOfBlockquotes += 1 + } + } + + XCTAssertEqual(numberOfBlockquotes, 3, "Couldn't find all the blockquotes") + } + // MARK: - Private private func checkMatrixEntityLinkIn(attributedString: AttributedString?, expected: String) {