Skip to content

Commit f4ed003

Browse files
authored
Merge branch 'main' into @exploif/fix-default-values
2 parents 653ad2c + 0ac2907 commit f4ed003

10 files changed

Lines changed: 132 additions & 124 deletions

File tree

android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ class EnrichedTextInputView : AppCompatEditText {
457457
}
458458

459459
private fun verifyStyle(name: String): Boolean {
460-
val mergingConfig = EnrichedSpans.mergingConfig[name] ?: return true
460+
val mergingConfig = EnrichedSpans.getMergingConfigForStyle(name, htmlStyle) ?: return true
461461
val conflictingStyles = mergingConfig.conflictingStyles
462462
val blockingStyles = mergingConfig.blockingStyles
463463
val isEnabling = spanState?.getStart(name) == null

android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.swmansion.enriched
22

33
import android.content.Context
4-
import android.util.Log
54
import com.facebook.react.bridge.ReadableArray
65
import com.facebook.react.bridge.ReadableMap
76
import com.facebook.react.module.annotations.ReactModule

android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.swmansion.enriched.spans
22

3+
import com.swmansion.enriched.styles.HtmlStyle
4+
35
data class BaseSpanConfig(val clazz: Class<*>)
46
data class ParagraphSpanConfig(val clazz: Class<*>, val isContinuous: Boolean)
57
data class ListSpanConfig(val clazz: Class<*>, val shortcut: String)
@@ -62,50 +64,63 @@ object EnrichedSpans {
6264
MENTION to BaseSpanConfig(EnrichedMentionSpan::class.java),
6365
)
6466

65-
val mergingConfig: Map<String, StylesMergingConfig> = mapOf(
66-
BOLD to StylesMergingConfig(
67-
blockingStyles = arrayOf(CODE_BLOCK)
68-
),
69-
ITALIC to StylesMergingConfig(
70-
blockingStyles = arrayOf(CODE_BLOCK)
71-
),
72-
UNDERLINE to StylesMergingConfig(
73-
blockingStyles = arrayOf(CODE_BLOCK)
74-
),
75-
STRIKETHROUGH to StylesMergingConfig(
76-
blockingStyles = arrayOf(CODE_BLOCK)
77-
),
78-
INLINE_CODE to StylesMergingConfig(
79-
conflictingStyles = arrayOf(MENTION, LINK),
80-
blockingStyles = arrayOf(CODE_BLOCK)
81-
),
82-
H1 to StylesMergingConfig(
83-
conflictingStyles = arrayOf(H2, H3, ORDERED_LIST, UNORDERED_LIST, BLOCK_QUOTE, CODE_BLOCK),
84-
),
85-
H2 to StylesMergingConfig(
86-
conflictingStyles = arrayOf(H1, H3, ORDERED_LIST, UNORDERED_LIST, BLOCK_QUOTE, CODE_BLOCK),
87-
),
88-
H3 to StylesMergingConfig(
89-
conflictingStyles = arrayOf(H1, H2, ORDERED_LIST, UNORDERED_LIST, BLOCK_QUOTE, CODE_BLOCK),
90-
),
91-
BLOCK_QUOTE to StylesMergingConfig(
92-
conflictingStyles = arrayOf(H1, H2, H3, CODE_BLOCK, ORDERED_LIST, UNORDERED_LIST),
93-
),
94-
CODE_BLOCK to StylesMergingConfig(
95-
conflictingStyles = arrayOf(H1, H2, H3, BOLD, ITALIC, UNDERLINE, STRIKETHROUGH, UNORDERED_LIST, ORDERED_LIST, BLOCK_QUOTE, INLINE_CODE),
96-
),
97-
UNORDERED_LIST to StylesMergingConfig(
98-
conflictingStyles = arrayOf(H1, H2, H3, ORDERED_LIST, CODE_BLOCK, BLOCK_QUOTE),
99-
),
100-
ORDERED_LIST to StylesMergingConfig(
101-
conflictingStyles = arrayOf(H1, H2, H3, UNORDERED_LIST, CODE_BLOCK, BLOCK_QUOTE),
102-
),
103-
LINK to StylesMergingConfig(
104-
blockingStyles = arrayOf(INLINE_CODE, CODE_BLOCK, MENTION)
105-
),
106-
IMAGE to StylesMergingConfig(),
107-
MENTION to StylesMergingConfig(
108-
blockingStyles = arrayOf(INLINE_CODE, CODE_BLOCK, LINK)
109-
),
110-
)
67+
fun getMergingConfigForStyle(style: String, htmlStyle: HtmlStyle): StylesMergingConfig? {
68+
return when (style) {
69+
BOLD -> {
70+
val blockingStyles = mutableListOf(CODE_BLOCK)
71+
if (htmlStyle.h1Bold) blockingStyles.add(H1)
72+
if (htmlStyle.h2Bold) blockingStyles.add(H2)
73+
if (htmlStyle.h3Bold) blockingStyles.add(H3)
74+
StylesMergingConfig(blockingStyles = blockingStyles.toTypedArray())
75+
}
76+
ITALIC -> StylesMergingConfig(
77+
blockingStyles = arrayOf(CODE_BLOCK)
78+
)
79+
UNDERLINE -> StylesMergingConfig(
80+
blockingStyles = arrayOf(CODE_BLOCK)
81+
)
82+
STRIKETHROUGH -> StylesMergingConfig(
83+
blockingStyles = arrayOf(CODE_BLOCK)
84+
)
85+
INLINE_CODE -> StylesMergingConfig(
86+
conflictingStyles = arrayOf(MENTION, LINK),
87+
blockingStyles = arrayOf(CODE_BLOCK)
88+
)
89+
H1 -> {
90+
val conflictingStyles = mutableListOf(H2, H3, ORDERED_LIST, UNORDERED_LIST, BLOCK_QUOTE, CODE_BLOCK)
91+
if (htmlStyle.h1Bold) conflictingStyles.add(BOLD)
92+
StylesMergingConfig(conflictingStyles = conflictingStyles.toTypedArray())
93+
}
94+
H2 -> {
95+
val conflictingStyles = mutableListOf(H1, H3, ORDERED_LIST, UNORDERED_LIST, BLOCK_QUOTE, CODE_BLOCK)
96+
if (htmlStyle.h2Bold) conflictingStyles.add(BOLD)
97+
StylesMergingConfig(conflictingStyles = conflictingStyles.toTypedArray())
98+
}
99+
H3 -> {
100+
val conflictingStyles = mutableListOf(H1, H2, ORDERED_LIST, UNORDERED_LIST, BLOCK_QUOTE, CODE_BLOCK)
101+
if (htmlStyle.h3Bold) conflictingStyles.add(BOLD)
102+
StylesMergingConfig(conflictingStyles = conflictingStyles.toTypedArray())
103+
}
104+
BLOCK_QUOTE -> StylesMergingConfig(
105+
conflictingStyles = arrayOf(H1, H2, H3, CODE_BLOCK, ORDERED_LIST, UNORDERED_LIST)
106+
)
107+
CODE_BLOCK -> StylesMergingConfig(
108+
conflictingStyles = arrayOf(H1, H2, H3, BOLD, ITALIC, UNDERLINE, STRIKETHROUGH, UNORDERED_LIST, ORDERED_LIST, BLOCK_QUOTE, INLINE_CODE)
109+
)
110+
UNORDERED_LIST -> StylesMergingConfig(
111+
conflictingStyles = arrayOf(H1, H2, H3, ORDERED_LIST, CODE_BLOCK, BLOCK_QUOTE)
112+
)
113+
ORDERED_LIST -> StylesMergingConfig(
114+
conflictingStyles = arrayOf(H1, H2, H3, UNORDERED_LIST, CODE_BLOCK, BLOCK_QUOTE),
115+
)
116+
LINK -> StylesMergingConfig(
117+
blockingStyles = arrayOf(INLINE_CODE, CODE_BLOCK, MENTION)
118+
)
119+
IMAGE -> StylesMergingConfig()
120+
MENTION -> StylesMergingConfig(
121+
blockingStyles = arrayOf(INLINE_CODE, CODE_BLOCK, LINK)
122+
)
123+
else -> null
124+
}
125+
}
111126
}

android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ class HtmlToSpannedConverter implements ContentHandler {
350350
private final EnrichedParser.ImageGetter mImageGetter;
351351
private static Integer currentOrderedListItemIndex = 0;
352352
private static Boolean isInOrderedList = false;
353+
private static Boolean isEmptyTag = false;
353354

354355
public HtmlToSpannedConverter(String source, HtmlStyle style, EnrichedParser.ImageGetter imageGetter, Parser parser) {
355356
mStyle = style;
@@ -396,19 +397,27 @@ public Spanned convert() {
396397
for (EnrichedZeroWidthSpaceSpan zeroWidthSpaceSpan : zeroWidthSpaceSpans) {
397398
int start = mSpannableStringBuilder.getSpanStart(zeroWidthSpaceSpan);
398399
int end = mSpannableStringBuilder.getSpanEnd(zeroWidthSpaceSpan);
399-
mSpannableStringBuilder.insert(start, "\u200B");
400+
401+
if (mSpannableStringBuilder.charAt(start) != '\u200B') {
402+
// Insert zero-width space character at the start if it's not already present.
403+
mSpannableStringBuilder.insert(start, "\u200B");
404+
end++; // Adjust end position due to insertion.
405+
}
406+
400407
mSpannableStringBuilder.removeSpan(zeroWidthSpaceSpan);
401-
mSpannableStringBuilder.setSpan(zeroWidthSpaceSpan, start, end + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
408+
mSpannableStringBuilder.setSpan(zeroWidthSpaceSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
402409
}
403410

404411
return mSpannableStringBuilder;
405412
}
406413

407414
private void handleStartTag(String tag, Attributes attributes) {
415+
isEmptyTag = false;
408416
if (tag.equalsIgnoreCase("br")) {
409417
// We don't need to handle this. TagSoup will ensure that there's a </br> for each <br>
410418
// so we can safely emit the linebreaks when we handle the close tag.
411419
} else if (tag.equalsIgnoreCase("p")) {
420+
isEmptyTag = true;
412421
startBlockElement(mSpannableStringBuilder);
413422
} else if (tag.equalsIgnoreCase("ul")) {
414423
isInOrderedList = false;
@@ -418,14 +427,17 @@ private void handleStartTag(String tag, Attributes attributes) {
418427
currentOrderedListItemIndex = 0;
419428
startBlockElement(mSpannableStringBuilder);
420429
} else if (tag.equalsIgnoreCase("li")) {
430+
isEmptyTag = true;
421431
startLi(mSpannableStringBuilder);
422432
} else if (tag.equalsIgnoreCase("b")) {
423433
start(mSpannableStringBuilder, new Bold());
424434
} else if (tag.equalsIgnoreCase("i")) {
425435
start(mSpannableStringBuilder, new Italic());
426436
} else if (tag.equalsIgnoreCase("blockquote")) {
437+
isEmptyTag = true;
427438
startBlockquote(mSpannableStringBuilder);
428439
} else if (tag.equalsIgnoreCase("codeblock")) {
440+
isEmptyTag = true;
429441
startCodeBlock(mSpannableStringBuilder);
430442
} else if (tag.equalsIgnoreCase("a")) {
431443
startA(mSpannableStringBuilder, attributes);
@@ -632,11 +644,17 @@ private static void setSpanFromMark(Spannable text, Object mark, Object... spans
632644
}
633645
}
634646

635-
private static void setParagraphSpanFromMark(Spannable text, Object mark, Object... spans) {
647+
private static void setParagraphSpanFromMark(Editable text, Object mark, Object... spans) {
636648
int where = text.getSpanStart(mark);
637649
text.removeSpan(mark);
638650
int len = text.length();
639651

652+
// Block spans require at least one character to be applied.
653+
if (isEmptyTag) {
654+
text.append("\u200B");
655+
len++;
656+
}
657+
640658
// Adjust the end position to exclude the newline character, if present
641659
if (len > 0 && text.charAt(len - 1) == '\n') {
642660
len--;
@@ -741,6 +759,8 @@ public void endElement(String uri, String localName, String qName) {
741759

742760
public void characters(char[] ch, int start, int length) {
743761
StringBuilder sb = new StringBuilder();
762+
if (length > 0) isEmptyTag = false;
763+
744764
/*
745765
* Ignore whitespace that immediately follows other whitespace;
746766
* newlines count as spaces.

0 commit comments

Comments
 (0)