Skip to content

Commit

Permalink
Added support for RTL tables
Browse files Browse the repository at this point in the history
Fixes #306
  • Loading branch information
spacecowboy committed Jun 16, 2024
1 parent d4a9655 commit eabf243
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,18 @@ class FullTextParser(override val di: DI) : DIAware {
uri: String,
html: String,
): String? {
return Readability4JExtended(uri, html).parse().contentWithUtf8Encoding
val article = Readability4JExtended(uri, html).parse()

val dir = article.dir

// Ensure dir is set on the outermost element
return article.contentWithUtf8Encoding?.let { fullHtml ->
if (dir?.isNotBlank() == true) {
fullHtml.replaceFirst("<html".toRegex(), "<html dir=\"$dir\"")
} else {
fullHtml
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.nononsenseapps.feeder.model.html

import android.util.Log
import com.nononsenseapps.feeder.ui.compose.text.ancestors
import com.nononsenseapps.feeder.ui.compose.text.attrInHierarchy
import com.nononsenseapps.feeder.ui.compose.text.stripHtml
import com.nononsenseapps.feeder.ui.text.getVideo
import com.nononsenseapps.feeder.util.asUTF8Sequence
Expand Down Expand Up @@ -514,6 +515,9 @@ class HtmlLinearizer {
"table" -> {
finalizeAndAddCurrentElement(blockStyle)

// This can also be auto, but for tables that's equivalent to LTR probably
val leftToRight = element.attrInHierarchy("dir") != "rtl"

val rowSequence =
sequence<Element> {
element.children()
Expand Down Expand Up @@ -556,7 +560,7 @@ class HtmlLinearizer {
)
} else {
add(
LinearTable.build {
LinearTable.build(leftToRight = leftToRight) {
rowSequence
.forEach { row ->
newRow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,24 @@ data class LinearTable(
rowCount: Int,
colCount: Int,
cells: List<LinearTableCellItem>,
leftToRight: Boolean,
) : this(
rowCount,
colCount,
ArrayMap<Coordinate, LinearTableCellItem>().apply {
cells.forEachIndexed { index, item ->
put(Coordinate(row = index / colCount, col = index % colCount), item)
put(
Coordinate(
row = index / colCount,
col =
if (leftToRight) {
index % colCount
} else {
colCount - 1 - index % colCount
},
),
item,
)
}
},
)
Expand All @@ -117,7 +129,7 @@ data class LinearTable(
return cells[Coordinate(row = row, col = col)]
}

class Builder {
class Builder(val leftToRight: Boolean) {
private val cells: ArrayMap<Coordinate, LinearTableCellItem> = ArrayMap()
private var rowCount: Int = 0
private var colCount: Int = 0
Expand Down Expand Up @@ -165,13 +177,35 @@ data class LinearTable(
}

fun build(): LinearTable {
return LinearTable(rowCount, colCount, cells)
return LinearTable(
rowCount = rowCount,
colCount = colCount,
cellsReal =
if (leftToRight) {
cells
} else {
ArrayMap<Coordinate, LinearTableCellItem>().apply {
cells.forEach { (ltrCoord, item) ->
put(
Coordinate(
row = ltrCoord.row,
col = colCount - 1 - ltrCoord.col,
),
item,
)
}
}
},
)
}
}

companion object {
fun build(block: Builder.() -> Unit): LinearTable {
return Builder().apply(block).build()
fun build(
leftToRight: Boolean,
block: Builder.() -> Unit,
): LinearTable {
return Builder(leftToRight = leftToRight).apply(block).build()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,7 @@ private fun PreviewLinearTableContent() {
LinearTable(
rowCount = 2,
colCount = 2,
leftToRight = false,
cells =
listOf(
LinearTableCellItem(
Expand Down Expand Up @@ -1178,6 +1179,7 @@ private fun PreviewNestedTableContent() {
LinearTable(
rowCount = 2,
colCount = 2,
leftToRight = false,
cells =
listOf(
LinearTableCellItem(
Expand Down Expand Up @@ -1268,6 +1270,7 @@ private fun PreviewNestedTableContent() {
LinearTable(
rowCount = 2,
colCount = 2,
leftToRight = false,
cells =
listOf(
LinearTableCellItem(
Expand Down Expand Up @@ -1410,14 +1413,6 @@ fun LinearTable.toTableData(): TableData {
},
)
}
.sortedWith(
compareBy(
{ it.colSpan },
{ it.rowSpan },
{ it.row },
{ it.column },
),
)
.toList(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ data class TableData private constructor(
if (a.row != b.row) {
return@sortedWith a.row.compareTo(b.row)
}

return@sortedWith a.column.compareTo(b.column)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ import org.jsoup.nodes.Element
import org.jsoup.nodes.TextNode
import kotlin.math.roundToInt

fun Element.attrInHierarchy(attr: String): String {
var current: Element? = this

while (current != null) {
val value = current.attr(attr)
if (value.isNotEmpty()) {
return value
}
current = current.parent()
}

return ""
}

fun Element.ancestors(predicate: (Element) -> Boolean): Sequence<Element> {
return ancestors().filter(predicate)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ class HtmlLinearizerTest {

assertEquals(1, result.size, "Expected one item: $result")
assertEquals(
LinearTable.build {
LinearTable.build(leftToRight = true) {
newRow()
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("1", LinearTextBlockStyle.TEXT))))
add(LinearTableCellItem(type = LinearTableCellItemType.DATA, colSpan = 1, rowSpan = 1, content = listOf(LinearText("2", LinearTextBlockStyle.TEXT))))
Expand All @@ -726,6 +726,27 @@ class HtmlLinearizerTest {
)
}

@Test
fun `table block 2x2 rtl`() {
val html = "<html dir=\"rtl\"><body><table><tr><th>1</th><td>2</td></tr><tr><td>3</td><th>4</th></tr></table></body></html>"
val baseUrl = "https://example.com"

val result = linearizer.linearize(html, baseUrl).elements

assertEquals(1, result.size, "Expected one item: $result")
assertEquals(
LinearTable.build(leftToRight = true) {
newRow()
add(LinearTableCellItem(type = LinearTableCellItemType.DATA, colSpan = 1, rowSpan = 1, content = listOf(LinearText("2", LinearTextBlockStyle.TEXT))))
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("1", LinearTextBlockStyle.TEXT))))
newRow()
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("4", LinearTextBlockStyle.TEXT))))
add(LinearTableCellItem(type = LinearTableCellItemType.DATA, colSpan = 1, rowSpan = 1, content = listOf(LinearText("3", LinearTextBlockStyle.TEXT))))
},
result[0],
)
}

@Test
fun `table with colspan, rowspan, and a double span`() {
val html =
Expand Down Expand Up @@ -755,7 +776,7 @@ class HtmlLinearizerTest {
assertEquals(1, result.size, "Expected one item: $result")
val table = result[0] as LinearTable
assertEquals(
LinearTable.build {
LinearTable.build(leftToRight = true) {
newRow()
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("Name", LinearTextBlockStyle.TEXT))))
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("Age", LinearTextBlockStyle.TEXT))))
Expand Down Expand Up @@ -798,7 +819,7 @@ class HtmlLinearizerTest {
assertEquals(1, result.size, "Expected one item: $result")
val table = result[0] as LinearTable
assertEquals(
LinearTable.build {
LinearTable.build(leftToRight = true) {
newRow()
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("Name", LinearTextBlockStyle.TEXT))))
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("Age", LinearTextBlockStyle.TEXT))))
Expand Down Expand Up @@ -892,7 +913,7 @@ class HtmlLinearizerTest {

assertEquals(1, result.size, "Expected one item: $result")
val expected =
LinearTable.build {
LinearTable.build(leftToRight = true) {
newRow()
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("Name", LinearTextBlockStyle.TEXT))))
add(LinearTableCellItem(type = LinearTableCellItemType.HEADER, colSpan = 1, rowSpan = 1, content = listOf(LinearText("Number", LinearTextBlockStyle.TEXT))))
Expand Down

0 comments on commit eabf243

Please sign in to comment.