Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import android.content.Context
import io.element.android.wysiwyg.compose.internal.toStyleConfig
import io.element.android.wysiwyg.display.MentionDisplayHandler
import io.element.android.wysiwyg.utils.HtmlConverter
import org.jsoup.nodes.Document
import timber.log.Timber

/**
Expand Down Expand Up @@ -41,9 +42,11 @@ class StyledHtmlConverter(
return htmlConverter?.fromHtmlToSpans(html) ?: errorNotConfigured()
}

override fun fromDocumentToSpans(dom: Document): CharSequence {
return htmlConverter?.fromDocumentToSpans(dom) ?: errorNotConfigured()
}

private fun errorNotConfigured(): Nothing {
error("ComposableHtmlConverter must be configured with a RichTextEditorStyle before use")
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@
package io.element.android.wysiwyg.internal.utils

import io.element.android.wysiwyg.utils.HtmlConverter
import io.element.android.wysiwyg.utils.HtmlToDomParser
import io.element.android.wysiwyg.utils.HtmlToSpansParser
import org.jsoup.nodes.Document

internal class AndroidHtmlConverter(
private val provideHtmlToSpansParser: (html: String) -> HtmlToSpansParser
private val provideHtmlToSpansParser: (dom: Document) -> HtmlToSpansParser
) : HtmlConverter {

override fun fromHtmlToSpans(html: String): CharSequence =
provideHtmlToSpansParser(html).convert()
override fun fromHtmlToSpans(html: String): CharSequence {
val dom = HtmlToDomParser.document(html)
return fromDocumentToSpans(dom)
}

override fun fromDocumentToSpans(dom: Document): CharSequence {
return provideHtmlToSpansParser(dom).convert()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@

package io.element.android.wysiwyg.utils

import android.app.Application
import android.content.Context
import io.element.android.wysiwyg.display.MentionDisplayHandler
import io.element.android.wysiwyg.internal.utils.AndroidHtmlConverter
import io.element.android.wysiwyg.view.StyleConfig
import org.jsoup.nodes.Document

interface HtmlConverter {

fun fromHtmlToSpans(html: String): CharSequence
fun fromDocumentToSpans(dom: Document): CharSequence

object Factory {
fun create(
Expand All @@ -27,10 +27,10 @@ interface HtmlConverter {
isMention: ((text: String, url: String) -> Boolean)? = null,
): HtmlConverter {
val resourcesProvider = AndroidResourcesHelper(context)
return AndroidHtmlConverter(provideHtmlToSpansParser = { html ->
return AndroidHtmlConverter(provideHtmlToSpansParser = { dom ->
HtmlToSpansParser(
resourcesHelper = resourcesProvider,
html = html,
dom = dom,
styleConfig = styleConfig,
mentionDisplayHandler = mentionDisplayHandler,
isEditor = isEditor,
Expand All @@ -39,6 +39,4 @@ interface HtmlConverter {
})
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.element.android.wysiwyg.utils

import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Document.OutputSettings
import org.jsoup.safety.Safelist

object HtmlToDomParser {
fun document(html: String): Document {
val outputSettings = OutputSettings().prettyPrint(false).indentAmount(0)
val cleanHtml = Jsoup.clean(html, "", safeList, outputSettings)
return Jsoup.parse(cleanHtml)
}

private val safeList = Safelist()
.addTags(
"a", "b", "strong", "i", "em", "u", "del", "code", "ul", "ol", "li", "pre",
"blockquote", "p", "br"
)
.addAttributes("a", "href", "data-mention-type", "contenteditable")
.addAttributes("ol", "start")
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ import io.element.android.wysiwyg.view.spans.PillSpan
import io.element.android.wysiwyg.view.spans.PlainAtRoomMentionDisplaySpan
import io.element.android.wysiwyg.view.spans.QuoteSpan
import io.element.android.wysiwyg.view.spans.UnorderedListSpan
import org.jsoup.Jsoup
import org.jsoup.internal.StringUtil
import org.jsoup.nodes.Document.OutputSettings
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.nodes.Node
import org.jsoup.nodes.TextNode
import org.jsoup.safety.Safelist
import timber.log.Timber
import kotlin.math.roundToInt

Expand All @@ -51,27 +49,16 @@ import kotlin.math.roundToInt
*/
internal class HtmlToSpansParser(
private val resourcesHelper: ResourcesHelper,
private val html: String,
private val dom: Document,
private val styleConfig: StyleConfig,
private val mentionDisplayHandler: MentionDisplayHandler?,
private val isEditor: Boolean,
private val isMention: ((text: String, url: String) -> Boolean)? = null,
) {
private val safeList = Safelist()
.addTags(
"a", "b", "strong", "i", "em", "u", "del", "code", "ul", "ol", "li", "pre",
"blockquote", "p", "br"
)
.addAttributes("a", "href", "data-mention-type", "contenteditable")
.addAttributes("ol", "start")

/**
* Convert the HTML string into a [Spanned] text.
*/
fun convert(): Spanned {
val outputSettings = OutputSettings().prettyPrint(false).indentAmount(0)
val cleanHtml = Jsoup.clean(html, "", safeList, outputSettings)
val dom = Jsoup.parse(cleanHtml)
val text = buildSpannedString {
val body = dom.body()
parseChildren(body)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@

package io.element.android.wysiwyg.utils

import org.jsoup.nodes.Document

/**
* HTML converter that is not depend on Android, for unit tests.
*/
class BasicHtmlConverter: HtmlConverter {

override fun fromHtmlToSpans(html: String): CharSequence = html.replace("<[^>]*>".toRegex(), "")
override fun fromDocumentToSpans(dom: Document): CharSequence {
return fromHtmlToSpans(dom.html())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ class HtmlToSpansParserTest {
val styleConfig = createFakeStyleConfig()
return HtmlToSpansParser(
resourcesHelper = AndroidResourcesHelper(context = app),
html = html,
dom = HtmlToDomParser.document(html),
styleConfig = styleConfig,
mentionDisplayHandler = mentionDisplayHandler,
isEditor = isEditor,
Expand Down
Loading