Skip to content

Commit 5a530ad

Browse files
authored
android - remove zero-width-space character from the input and output (#70)
* fix: html output, setting up paragraph spans, parser * fix: android parser - headings * feat: remove zero-width-space characters from the output * feat: remove zero-width from the output
1 parent 3b3a369 commit 5a530ad

9 files changed

Lines changed: 35 additions & 8 deletions

File tree

android/src/main/java/com/swmansion/reactnativerichtexteditor/spans/EditorBlockQuoteSpan.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import android.graphics.Paint
55
import android.text.Layout
66
import android.text.style.LeadingMarginSpan
77
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorParagraphSpan
8+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan
89
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle
910

1011
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/text/style/QuoteSpan.java
11-
class EditorBlockQuoteSpan(private val richTextStyle: RichTextStyle) : LeadingMarginSpan, EditorParagraphSpan {
12+
class EditorBlockQuoteSpan(private val richTextStyle: RichTextStyle) : LeadingMarginSpan, EditorParagraphSpan, EditorZeroWidthSpaceSpan {
1213
override fun getLeadingMargin(p0: Boolean): Int {
1314
return richTextStyle.blockquoteStripeWidth + richTextStyle.blockquoteGapWidth
1415
}

android/src/main/java/com/swmansion/reactnativerichtexteditor/spans/EditorCodeBlockSpan.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import android.text.TextPaint
88
import android.text.style.CharacterStyle
99
import android.text.style.LineBackgroundSpan
1010
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorParagraphSpan
11+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan
1112
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle
1213

13-
class EditorCodeBlockSpan(private val richTextStyle: RichTextStyle) : CharacterStyle(), LineBackgroundSpan, EditorParagraphSpan {
14+
class EditorCodeBlockSpan(private val richTextStyle: RichTextStyle) : CharacterStyle(), LineBackgroundSpan, EditorParagraphSpan, EditorZeroWidthSpaceSpan {
1415
override fun updateDrawState(paint: TextPaint?) {
1516
paint?.typeface = Typeface.MONOSPACE
1617
paint?.color = richTextStyle.codeBlockColor

android/src/main/java/com/swmansion/reactnativerichtexteditor/spans/EditorH1Span.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package com.swmansion.reactnativerichtexteditor.spans
33
import android.text.style.AbsoluteSizeSpan
44
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorHeadingSpan
55
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorInlineSpan
6+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan
67
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle
78

89
// Heading spans inherit from EditorInlineSpan because they can be nested inside code block and block quote
9-
class EditorH1Span(style: RichTextStyle) : AbsoluteSizeSpan(style.h1FontSize), EditorHeadingSpan, EditorInlineSpan {
10+
class EditorH1Span(style: RichTextStyle) : AbsoluteSizeSpan(style.h1FontSize), EditorHeadingSpan, EditorInlineSpan, EditorZeroWidthSpaceSpan {
1011
}

android/src/main/java/com/swmansion/reactnativerichtexteditor/spans/EditorH2Span.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package com.swmansion.reactnativerichtexteditor.spans
33
import android.text.style.AbsoluteSizeSpan
44
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorHeadingSpan
55
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorInlineSpan
6+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan
67
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle
78

89
// Heading spans inherit from EditorInlineSpan because they can be nested inside code block and block quote
9-
class EditorH2Span(richTextStyle: RichTextStyle) : AbsoluteSizeSpan(richTextStyle.h2FontSize), EditorHeadingSpan, EditorInlineSpan {
10+
class EditorH2Span(richTextStyle: RichTextStyle) : AbsoluteSizeSpan(richTextStyle.h2FontSize), EditorHeadingSpan, EditorInlineSpan, EditorZeroWidthSpaceSpan {
1011
}

android/src/main/java/com/swmansion/reactnativerichtexteditor/spans/EditorH3Span.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package com.swmansion.reactnativerichtexteditor.spans
33
import android.text.style.AbsoluteSizeSpan
44
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorHeadingSpan
55
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorInlineSpan
6+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan
67
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle
78

89
// Heading spans inherit from EditorInlineSpan because they can be nested inside code block and block quote
9-
class EditorH3Span(richTextStyle: RichTextStyle) : AbsoluteSizeSpan(richTextStyle.h3FontSize), EditorHeadingSpan, EditorInlineSpan {
10+
class EditorH3Span(richTextStyle: RichTextStyle) : AbsoluteSizeSpan(richTextStyle.h3FontSize), EditorHeadingSpan, EditorInlineSpan, EditorZeroWidthSpaceSpan {
1011
}

android/src/main/java/com/swmansion/reactnativerichtexteditor/spans/EditorOrderedListSpan.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import android.graphics.Paint
55
import android.text.Layout
66
import android.text.style.LeadingMarginSpan
77
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorInlineSpan
8+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan
89
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle
910

10-
class EditorOrderedListSpan(private var index: Int, private val richTextStyle: RichTextStyle) : LeadingMarginSpan, EditorInlineSpan {
11+
class EditorOrderedListSpan(private var index: Int, private val richTextStyle: RichTextStyle) : LeadingMarginSpan, EditorInlineSpan, EditorZeroWidthSpaceSpan {
1112
override fun getLeadingMargin(first: Boolean): Int {
1213
return richTextStyle.olMarginLeft + richTextStyle.olGapWidth
1314
}

android/src/main/java/com/swmansion/reactnativerichtexteditor/spans/EditorUnorderedListSpan.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import android.text.Layout
66
import android.text.Spanned
77
import android.text.style.LeadingMarginSpan
88
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorInlineSpan
9+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan
910
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle
1011

1112
// https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/text/style/BulletSpan.java
12-
class EditorUnorderedListSpan(private val richTextStyle: RichTextStyle) : LeadingMarginSpan, EditorInlineSpan {
13+
class EditorUnorderedListSpan(private val richTextStyle: RichTextStyle) : LeadingMarginSpan, EditorInlineSpan, EditorZeroWidthSpaceSpan {
1314
override fun getLeadingMargin(p0: Boolean): Int {
1415
return richTextStyle.ulBulletSize + richTextStyle.ulGapWidth + richTextStyle.ulMarginLeft
1516
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.swmansion.reactnativerichtexteditor.spans.interfaces
2+
3+
// Spans that are prefixed with zero-width space (\u200B) to ensure that they are visible even when empty.
4+
interface EditorZeroWidthSpaceSpan {
5+
}

android/src/main/java/com/swmansion/reactnativerichtexteditor/utils/EditorParser.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.swmansion.reactnativerichtexteditor.spans.EditorUnorderedListSpan;
3232
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorParagraphSpan;
3333
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorInlineSpan;
34+
import com.swmansion.reactnativerichtexteditor.spans.interfaces.EditorZeroWidthSpaceSpan;
3435
import com.swmansion.reactnativerichtexteditor.styles.RichTextStyle;
3536

3637
import org.ccil.cowan.tagsoup.HTMLSchema;
@@ -522,7 +523,10 @@ private static void withinStyle(StringBuilder out, CharSequence text,
522523
int start, int end) {
523524
for (int i = start; i < end; i++) {
524525
char c = text.charAt(i);
525-
if (c == '<') {
526+
if (c == '\u200B') {
527+
// Do not output zero-width space characters.
528+
continue;
529+
} else if (c == '<') {
526530
out.append("&lt;");
527531
} else if (c == '>') {
528532
out.append("&gt;");
@@ -657,6 +661,17 @@ public Spanned convert() {
657661
mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
658662
}
659663
}
664+
665+
// Assign zero-width space character to the proper spans.
666+
EditorZeroWidthSpaceSpan[] zeroWidthSpaceSpans = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), EditorZeroWidthSpaceSpan.class);
667+
for (EditorZeroWidthSpaceSpan zeroWidthSpaceSpan : zeroWidthSpaceSpans) {
668+
int start = mSpannableStringBuilder.getSpanStart(zeroWidthSpaceSpan);
669+
int end = mSpannableStringBuilder.getSpanEnd(zeroWidthSpaceSpan);
670+
mSpannableStringBuilder.insert(start, "\u200B");
671+
mSpannableStringBuilder.removeSpan(zeroWidthSpaceSpan);
672+
mSpannableStringBuilder.setSpan(zeroWidthSpaceSpan, start, end + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
673+
}
674+
660675
return mSpannableStringBuilder;
661676
}
662677

0 commit comments

Comments
 (0)