Skip to content

Commit 0a0029b

Browse files
fix: p tag parsing with alignment (#748)
# Summary This PR preserves paragraph alignment on empty paragraphs on mobile. ## Test Plan Insert input content by `Set Input's value` button: `<html><p style="text-align: right;">Asdasd</p><p style="text-align: right;"></p><p style="text-align: right;">ddd</p></html>` And see that alignment on empty p is preserved. ## Screenshots / Videos https://github.com/user-attachments/assets/c2eff7f8-071e-402b-99c8-7f49b02e1fd4 ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ✅ | | Web | ❌ | ## Checklist - [X] E2E tests are passing - [ ] Required E2E tests have been added (if applicable)
1 parent 0fdac7a commit 0a0029b

2 files changed

Lines changed: 27 additions & 4 deletions

File tree

android/src/main/java/com/swmansion/enriched/common/parser/EnrichedParser.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ public static String toHtml(Spanned text) {
9494
String normalizedBlockQuote =
9595
normalizedCodeBlock.replaceAll("</blockquote>\\n<br>", "</blockquote>");
9696

97-
// Replace empty <p> tags (with or without style attributes) with <br>
98-
String normalizedHtml = normalizedBlockQuote.replaceAll("<p[^>]*></p>", "<br>");
97+
// Replace empty <p> tags with <br>, except when they carry text-align
98+
String normalizedHtml =
99+
normalizedBlockQuote.replaceAll("<p(?![^>]*text-align\\s*:)[^>]*></p>", "<br>");
99100

100101
return "<html>\n" + normalizedHtml + "</html>";
101102
}
@@ -593,7 +594,14 @@ private void handleEndTag(String tag) {
593594
if (tag.equalsIgnoreCase("br")) {
594595
handleBr(mSpannableStringBuilder);
595596
} else if (tag.equalsIgnoreCase("p")) {
597+
boolean empty = isEmptyTag;
598+
Alignment pendingAlignment = empty ? getLast(mSpannableStringBuilder, Alignment.class) : null;
596599
endBlockElement(mSpannableStringBuilder, mSpanFactory);
600+
// Plain empty paragraphs never reach setParagraphSpanFromMark (no ZWS).
601+
// Represent them as a blank line so they round-trip as <br>.
602+
if (empty && pendingAlignment == null) {
603+
handleBr(mSpannableStringBuilder);
604+
}
597605
} else if (tag.equalsIgnoreCase("ul")) {
598606
currentListAlignmentCssValue = null;
599607
endBlockElement(mSpannableStringBuilder, mSpanFactory);

ios/htmlParser/HtmlParser.mm

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,16 @@ + (NSString *)parseToHtmlFromRange:(NSRange)range
957957
inCheckboxList = NO;
958958
}
959959
} else {
960-
[result appendString:@"\n<br>"];
960+
NSString *cssStyleString =
961+
[self prepareCssStyleString:currentRange.location
962+
isOpeningTag:YES
963+
host:host];
964+
if (cssStyleString.length > 0) {
965+
[result appendString:[NSString stringWithFormat:@"\n<p%@></p>",
966+
cssStyleString]];
967+
} else {
968+
[result appendString:@"\n<br>"];
969+
}
961970
}
962971
} else {
963972
// newline finishes a paragraph and all style tags need to be closed
@@ -1456,7 +1465,7 @@ + (NSString *)prepareCssStyleString:(NSInteger)location
14561465
}
14571466

14581467
+ (void)checkForAlignments:(NSArray *)tagData
1459-
plainText:(NSString *)plainText
1468+
plainText:(NSMutableString *)plainText
14601469
foundAlignments:(NSMutableArray<AlignmentEntry *> *)foundAlignments
14611470
precedingImageCount:(NSInteger)precedingImageCount {
14621471
if (tagData == nil) {
@@ -1474,6 +1483,12 @@ + (void)checkForAlignments:(NSArray *)tagData
14741483
NSInteger actualStart = startLoc + precedingImageCount;
14751484
NSInteger length = plainText.length - startLoc;
14761485

1486+
// Empty aligned paragraphs have no characters to attach alignment to.
1487+
if (length == 0) {
1488+
[plainText appendString:@"\u200B"];
1489+
length = 1;
1490+
}
1491+
14771492
if (length > 0) {
14781493
AlignmentEntry *entry = [[AlignmentEntry alloc] init];
14791494
entry.alignment = align;

0 commit comments

Comments
 (0)