Skip to content

Commit 837c922

Browse files
authored
Android: allow passing a Jsoup Document to html converter (#91)
* Android: allow passing a Jsoup `Document` to html converter Also, centralise, extract and make public the HTML to Document parser. * Fix tests
1 parent da86958 commit 837c922

File tree

7 files changed

+49
-28
lines changed

7 files changed

+49
-28
lines changed

platforms/android/library-compose/src/main/java/io/element/android/wysiwyg/compose/StyledHtmlConverter.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import android.content.Context
1212
import io.element.android.wysiwyg.compose.internal.toStyleConfig
1313
import io.element.android.wysiwyg.display.MentionDisplayHandler
1414
import io.element.android.wysiwyg.utils.HtmlConverter
15+
import org.jsoup.nodes.Document
1516
import timber.log.Timber
1617

1718
/**
@@ -41,9 +42,11 @@ class StyledHtmlConverter(
4142
return htmlConverter?.fromHtmlToSpans(html) ?: errorNotConfigured()
4243
}
4344

45+
override fun fromDocumentToSpans(dom: Document): CharSequence {
46+
return htmlConverter?.fromDocumentToSpans(dom) ?: errorNotConfigured()
47+
}
48+
4449
private fun errorNotConfigured(): Nothing {
4550
error("ComposableHtmlConverter must be configured with a RichTextEditorStyle before use")
4651
}
47-
48-
4952
}

platforms/android/library/src/main/java/io/element/android/wysiwyg/internal/utils/AndroidHtmlConverter.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,20 @@
99
package io.element.android.wysiwyg.internal.utils
1010

1111
import io.element.android.wysiwyg.utils.HtmlConverter
12+
import io.element.android.wysiwyg.utils.HtmlToDomParser
1213
import io.element.android.wysiwyg.utils.HtmlToSpansParser
14+
import org.jsoup.nodes.Document
1315

1416
internal class AndroidHtmlConverter(
15-
private val provideHtmlToSpansParser: (html: String) -> HtmlToSpansParser
17+
private val provideHtmlToSpansParser: (dom: Document) -> HtmlToSpansParser
1618
) : HtmlConverter {
1719

18-
override fun fromHtmlToSpans(html: String): CharSequence =
19-
provideHtmlToSpansParser(html).convert()
20+
override fun fromHtmlToSpans(html: String): CharSequence {
21+
val dom = HtmlToDomParser.document(html)
22+
return fromDocumentToSpans(dom)
23+
}
2024

25+
override fun fromDocumentToSpans(dom: Document): CharSequence {
26+
return provideHtmlToSpansParser(dom).convert()
27+
}
2128
}

platforms/android/library/src/main/java/io/element/android/wysiwyg/utils/HtmlConverter.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88

99
package io.element.android.wysiwyg.utils
1010

11-
import android.app.Application
1211
import android.content.Context
1312
import io.element.android.wysiwyg.display.MentionDisplayHandler
1413
import io.element.android.wysiwyg.internal.utils.AndroidHtmlConverter
1514
import io.element.android.wysiwyg.view.StyleConfig
15+
import org.jsoup.nodes.Document
1616

1717
interface HtmlConverter {
18-
1918
fun fromHtmlToSpans(html: String): CharSequence
19+
fun fromDocumentToSpans(dom: Document): CharSequence
2020

2121
object Factory {
2222
fun create(
@@ -27,10 +27,10 @@ interface HtmlConverter {
2727
isMention: ((text: String, url: String) -> Boolean)? = null,
2828
): HtmlConverter {
2929
val resourcesProvider = AndroidResourcesHelper(context)
30-
return AndroidHtmlConverter(provideHtmlToSpansParser = { html ->
30+
return AndroidHtmlConverter(provideHtmlToSpansParser = { dom ->
3131
HtmlToSpansParser(
3232
resourcesHelper = resourcesProvider,
33-
html = html,
33+
dom = dom,
3434
styleConfig = styleConfig,
3535
mentionDisplayHandler = mentionDisplayHandler,
3636
isEditor = isEditor,
@@ -39,6 +39,4 @@ interface HtmlConverter {
3939
})
4040
}
4141
}
42-
43-
4442
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.element.android.wysiwyg.utils
2+
3+
import org.jsoup.Jsoup
4+
import org.jsoup.nodes.Document
5+
import org.jsoup.nodes.Document.OutputSettings
6+
import org.jsoup.safety.Safelist
7+
8+
object HtmlToDomParser {
9+
fun document(html: String): Document {
10+
val outputSettings = OutputSettings().prettyPrint(false).indentAmount(0)
11+
val cleanHtml = Jsoup.clean(html, "", safeList, outputSettings)
12+
return Jsoup.parse(cleanHtml)
13+
}
14+
15+
private val safeList = Safelist()
16+
.addTags(
17+
"a", "b", "strong", "i", "em", "u", "del", "code", "ul", "ol", "li", "pre",
18+
"blockquote", "p", "br"
19+
)
20+
.addAttributes("a", "href", "data-mention-type", "contenteditable")
21+
.addAttributes("ol", "start")
22+
}

platforms/android/library/src/main/java/io/element/android/wysiwyg/utils/HtmlToSpansParser.kt

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,11 @@ import io.element.android.wysiwyg.view.spans.PillSpan
3232
import io.element.android.wysiwyg.view.spans.PlainAtRoomMentionDisplaySpan
3333
import io.element.android.wysiwyg.view.spans.QuoteSpan
3434
import io.element.android.wysiwyg.view.spans.UnorderedListSpan
35-
import org.jsoup.Jsoup
3635
import org.jsoup.internal.StringUtil
37-
import org.jsoup.nodes.Document.OutputSettings
36+
import org.jsoup.nodes.Document
3837
import org.jsoup.nodes.Element
3938
import org.jsoup.nodes.Node
4039
import org.jsoup.nodes.TextNode
41-
import org.jsoup.safety.Safelist
4240
import timber.log.Timber
4341
import kotlin.math.roundToInt
4442

@@ -51,27 +49,16 @@ import kotlin.math.roundToInt
5149
*/
5250
internal class HtmlToSpansParser(
5351
private val resourcesHelper: ResourcesHelper,
54-
private val html: String,
52+
private val dom: Document,
5553
private val styleConfig: StyleConfig,
5654
private val mentionDisplayHandler: MentionDisplayHandler?,
5755
private val isEditor: Boolean,
5856
private val isMention: ((text: String, url: String) -> Boolean)? = null,
5957
) {
60-
private val safeList = Safelist()
61-
.addTags(
62-
"a", "b", "strong", "i", "em", "u", "del", "code", "ul", "ol", "li", "pre",
63-
"blockquote", "p", "br"
64-
)
65-
.addAttributes("a", "href", "data-mention-type", "contenteditable")
66-
.addAttributes("ol", "start")
67-
6858
/**
6959
* Convert the HTML string into a [Spanned] text.
7060
*/
7161
fun convert(): Spanned {
72-
val outputSettings = OutputSettings().prettyPrint(false).indentAmount(0)
73-
val cleanHtml = Jsoup.clean(html, "", safeList, outputSettings)
74-
val dom = Jsoup.parse(cleanHtml)
7562
val text = buildSpannedString {
7663
val body = dom.body()
7764
parseChildren(body)

platforms/android/library/src/test/kotlin/io/element/android/wysiwyg/utils/BasicHtmlConverter.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88

99
package io.element.android.wysiwyg.utils
1010

11+
import org.jsoup.nodes.Document
12+
1113
/**
1214
* HTML converter that is not depend on Android, for unit tests.
1315
*/
1416
class BasicHtmlConverter: HtmlConverter {
15-
1617
override fun fromHtmlToSpans(html: String): CharSequence = html.replace("<[^>]*>".toRegex(), "")
18+
override fun fromDocumentToSpans(dom: Document): CharSequence {
19+
return fromHtmlToSpans(dom.html())
20+
}
1721
}

platforms/android/library/src/test/kotlin/io/element/android/wysiwyg/utils/HtmlToSpansParserTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ class HtmlToSpansParserTest {
304304
val styleConfig = createFakeStyleConfig()
305305
return HtmlToSpansParser(
306306
resourcesHelper = AndroidResourcesHelper(context = app),
307-
html = html,
307+
dom = HtmlToDomParser.document(html),
308308
styleConfig = styleConfig,
309309
mentionDisplayHandler = mentionDisplayHandler,
310310
isEditor = isEditor,

0 commit comments

Comments
 (0)