adding basic list support
This commit is contained in:
parent
7016f7c4ee
commit
446d729981
|
@ -5,10 +5,11 @@ import app.dapk.st.matrix.common.UserId
|
||||||
private const val TAG_OPEN = '<'
|
private const val TAG_OPEN = '<'
|
||||||
private const val TAG_CLOSE = '>'
|
private const val TAG_CLOSE = '>'
|
||||||
private const val NO_RESULT_FOUND = -1
|
private const val NO_RESULT_FOUND = -1
|
||||||
|
private const val LI_VALUE_CAPTURE = "value=\""
|
||||||
|
|
||||||
internal class HtmlParser {
|
internal class HtmlParser {
|
||||||
|
|
||||||
fun parseHtmlTags(input: String, searchIndex: Int, builder: PartBuilder) = input.findTag(
|
fun parseHtmlTags(input: String, searchIndex: Int, builder: PartBuilder): SearchIndex = input.findTag(
|
||||||
fromIndex = searchIndex,
|
fromIndex = searchIndex,
|
||||||
onInvalidTag = { builder.appendText(input[it].toString()) },
|
onInvalidTag = { builder.appendText(input[it].toString()) },
|
||||||
onTag = { tagOpen, tagClose ->
|
onTag = { tagOpen, tagClose ->
|
||||||
|
@ -59,7 +60,7 @@ internal class HtmlParser {
|
||||||
wholeTag: String,
|
wholeTag: String,
|
||||||
builder: PartBuilder,
|
builder: PartBuilder,
|
||||||
tagContent: String,
|
tagContent: String,
|
||||||
exitTagCloseIndex: Int
|
exitTagCloseIndex: Int,
|
||||||
) = when (tagName) {
|
) = when (tagName) {
|
||||||
"a" -> {
|
"a" -> {
|
||||||
val findHrefUrl = wholeTag.substringAfter("href=").replace("\"", "").removeSuffix(">")
|
val findHrefUrl = wholeTag.substringAfter("href=").replace("\"", "").removeSuffix(">")
|
||||||
|
@ -84,6 +85,11 @@ internal class HtmlParser {
|
||||||
exitTagCloseIndex
|
exitTagCloseIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"ul", "ol" -> {
|
||||||
|
parseList(tagName, tagContent, builder)
|
||||||
|
exitTagCloseIndex
|
||||||
|
}
|
||||||
|
|
||||||
"h1", "h2", "h3", "h4", "h5" -> {
|
"h1", "h2", "h3", "h4", "h5" -> {
|
||||||
builder.appendBold(tagContent)
|
builder.appendBold(tagContent)
|
||||||
builder.appendNewline()
|
builder.appendNewline()
|
||||||
|
@ -128,8 +134,65 @@ internal class HtmlParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseList(parentTag: String, parentContent: String, builder: PartBuilder) {
|
||||||
|
var nextIndex = 0
|
||||||
|
var index = 1
|
||||||
|
while (nextIndex != END_SEARCH) {
|
||||||
|
nextIndex = singleTagParser(parentContent, "li", nextIndex, builder) { wholeTag, tagContent ->
|
||||||
|
val content = when (parentTag) {
|
||||||
|
"ol" -> {
|
||||||
|
index = wholeTag.indexOf(LI_VALUE_CAPTURE).let {
|
||||||
|
if (it == -1) {
|
||||||
|
index
|
||||||
|
} else {
|
||||||
|
val start = it + LI_VALUE_CAPTURE.length
|
||||||
|
wholeTag.substring(start).substringBefore('\"').toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"$index. $tagContent".also {
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> "- $tagContent"
|
||||||
|
}
|
||||||
|
builder.appendText(content)
|
||||||
|
builder.appendNewline()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun singleTagParser(content: String, wantedTagName: String, searchIndex: Int, builder: PartBuilder, onTag: (String, String) -> Unit): SearchIndex {
|
||||||
|
return content.findTag(
|
||||||
|
fromIndex = searchIndex,
|
||||||
|
onInvalidTag = { builder.appendText(content[it].toString()) },
|
||||||
|
onTag = { tagOpen, tagClose ->
|
||||||
|
val wholeTag = content.substring(tagOpen, tagClose + 1)
|
||||||
|
val tagName = wholeTag.substring(1, wholeTag.indexOfFirst { it == '>' || it == ' ' })
|
||||||
|
|
||||||
|
if (tagName == wantedTagName) {
|
||||||
|
val exitTag = "</$tagName>"
|
||||||
|
val exitIndex = content.indexOf(exitTag, startIndex = tagClose)
|
||||||
|
val exitTagCloseIndex = exitIndex + exitTag.length
|
||||||
|
if (exitIndex == END_SEARCH) {
|
||||||
|
builder.appendText(content[searchIndex].toString())
|
||||||
|
searchIndex.next()
|
||||||
|
} else {
|
||||||
|
val tagContent = content.substring(tagClose + 1, exitIndex)
|
||||||
|
onTag(wholeTag, tagContent)
|
||||||
|
exitTagCloseIndex
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
END_SEARCH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun test(startingFrom: Int, intput: String): Int {
|
fun test(startingFrom: Int, intput: String): Int {
|
||||||
return intput.indexOf('<', startingFrom)
|
return intput.indexOf(TAG_OPEN, startingFrom)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -74,6 +74,27 @@ class RichMessageParserTest {
|
||||||
expected = RichText(setOf(Normal("Hello world!\nnext line\nanother line")))
|
expected = RichText(setOf(Normal("Hello world!\nnext line\nanother line")))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `parses lists`() = runParserTest(
|
||||||
|
Case(
|
||||||
|
input = "<ul><li>content in list item</li><li>another item in list</li></ul>",
|
||||||
|
expected = RichText(setOf(Normal("- content in list item\n- another item in list")))
|
||||||
|
),
|
||||||
|
Case(
|
||||||
|
input = "<ol><li>content in list item</li><li>another item in list</li></ol>",
|
||||||
|
expected = RichText(setOf(Normal("1. content in list item\n2. another item in list")))
|
||||||
|
),
|
||||||
|
Case(
|
||||||
|
input = """<ol><li value="5">content in list item</li><li>another item in list</li></ol>""",
|
||||||
|
expected = RichText(setOf(Normal("5. content in list item\n6. another item in list")))
|
||||||
|
),
|
||||||
|
Case(
|
||||||
|
input = """<ol><li value="3">content in list item</li><li>another item in list</li><li value="10">another change</li><li>without value</li></ol>""",
|
||||||
|
expected = RichText(setOf(Normal("3. content in list item\n4. another item in list\n10. another change\n11. without value")))
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `parses urls`() = runParserTest(
|
fun `parses urls`() = runParserTest(
|
||||||
Case(
|
Case(
|
||||||
|
|
Loading…
Reference in New Issue