Skip to content

Commit 045209e

Browse files
committed
Add static rendering for GitHub
Fixes #476 Signed-off-by: Ilya Muradyan <ilya.muradyan@jetbrains.com>
1 parent 86ada2c commit 045209e

File tree

4 files changed

+168
-0
lines changed
  • core
    • generated-sources/src
      • main/kotlin/org/jetbrains/kotlinx/dataframe/io
      • test/kotlin/org/jetbrains/kotlinx/dataframe/rendering
    • src
      • main/kotlin/org/jetbrains/kotlinx/dataframe/io
      • test/kotlin/org/jetbrains/kotlinx/dataframe/rendering

4 files changed

+168
-0
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,68 @@ internal fun AnyFrame.toHtmlData(
172172
return DataFrameHtmlData("", body, script)
173173
}
174174

175+
internal fun AnyFrame.toStaticHtml(
176+
configuration: DisplayConfiguration = DisplayConfiguration.DEFAULT,
177+
cellRenderer: CellRenderer,
178+
): DataFrameHtmlData {
179+
val df = this
180+
val id = "static_df_${nextTableId()}"
181+
val columnsToRender = columns()
182+
183+
fun StringBuilder.emitTag(tag: String, attributes: String = "", tagContents: StringBuilder.() -> Unit) {
184+
append("<")
185+
append(tag)
186+
if (attributes.isNotEmpty()) {
187+
append(" ")
188+
append(attributes)
189+
}
190+
append(">")
191+
192+
tagContents()
193+
194+
append("</")
195+
append(tag)
196+
append(">")
197+
}
198+
199+
fun StringBuilder.emitHeader() = emitTag("thead") {
200+
emitTag("tr") {
201+
columnsToRender.forEach { col ->
202+
emitTag("th") {
203+
append(col.name())
204+
}
205+
}
206+
}
207+
}
208+
209+
fun StringBuilder.emitRow(row: AnyRow) = emitTag("tr") {
210+
columnsToRender.forEach { col ->
211+
emitTag("td") {
212+
append(cellRenderer.content(row[col.path()], configuration).truncatedContent)
213+
}
214+
}
215+
}
216+
217+
fun StringBuilder.emitBody() = emitTag("tbody") {
218+
val rowsCountToRender = minOf(rowsCount(), configuration.rowsLimit ?: Int.MAX_VALUE)
219+
for (rowIndex in 0..<rowsCountToRender) {
220+
emitRow(df[rowIndex])
221+
}
222+
}
223+
224+
fun StringBuilder.emitTable() = emitTag("table", """class="dataframe" id="$id"""") {
225+
emitHeader()
226+
emitBody()
227+
}
228+
229+
return DataFrameHtmlData(
230+
body = buildString { emitTable() },
231+
script = """
232+
document.getElementById("$id").style.display = "none";
233+
""".trimIndent()
234+
)
235+
}
236+
175237
internal fun DataFrameHtmlData.print() = println(this)
176238

177239
@Deprecated(
@@ -216,6 +278,8 @@ public fun <T> DataFrame<T>.toHTML(
216278

217279
var tableHtml = toHtmlData(configuration, cellRenderer)
218280

281+
tableHtml += toStaticHtml(configuration, cellRenderer)
282+
219283
if (bodyFooter != null) {
220284
tableHtml += DataFrameHtmlData("", bodyFooter, "")
221285
}

core/generated-sources/src/test/kotlin/org/jetbrains/kotlinx/dataframe/rendering/RenderingTests.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,24 @@ class RenderingTests {
125125
df.toHTML().script shouldContain rendered
126126
}
127127
}
128+
129+
@Test
130+
fun `static rendering should be present`() {
131+
val df = dataFrameOf("a", "b")(listOf(1, 1), listOf(2, 4))
132+
val actualHtml = df.toHTML()
133+
134+
actualHtml.body shouldContain """
135+
<thead>
136+
<tr>
137+
<th>a</th><th>b</th>
138+
</tr>
139+
</thead>
140+
<tbody>
141+
<tr>
142+
<td>[1, 1]</td><td>[2, 4]</td>
143+
</tr>
144+
</tbody>
145+
</table>
146+
""".trimIndent().replace("\n", "")
147+
}
128148
}

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,68 @@ internal fun AnyFrame.toHtmlData(
172172
return DataFrameHtmlData("", body, script)
173173
}
174174

175+
internal fun AnyFrame.toStaticHtml(
176+
configuration: DisplayConfiguration = DisplayConfiguration.DEFAULT,
177+
cellRenderer: CellRenderer,
178+
): DataFrameHtmlData {
179+
val df = this
180+
val id = "static_df_${nextTableId()}"
181+
val columnsToRender = columns()
182+
183+
fun StringBuilder.emitTag(tag: String, attributes: String = "", tagContents: StringBuilder.() -> Unit) {
184+
append("<")
185+
append(tag)
186+
if (attributes.isNotEmpty()) {
187+
append(" ")
188+
append(attributes)
189+
}
190+
append(">")
191+
192+
tagContents()
193+
194+
append("</")
195+
append(tag)
196+
append(">")
197+
}
198+
199+
fun StringBuilder.emitHeader() = emitTag("thead") {
200+
emitTag("tr") {
201+
columnsToRender.forEach { col ->
202+
emitTag("th") {
203+
append(col.name())
204+
}
205+
}
206+
}
207+
}
208+
209+
fun StringBuilder.emitRow(row: AnyRow) = emitTag("tr") {
210+
columnsToRender.forEach { col ->
211+
emitTag("td") {
212+
append(cellRenderer.content(row[col.path()], configuration).truncatedContent)
213+
}
214+
}
215+
}
216+
217+
fun StringBuilder.emitBody() = emitTag("tbody") {
218+
val rowsCountToRender = minOf(rowsCount(), configuration.rowsLimit ?: Int.MAX_VALUE)
219+
for (rowIndex in 0..<rowsCountToRender) {
220+
emitRow(df[rowIndex])
221+
}
222+
}
223+
224+
fun StringBuilder.emitTable() = emitTag("table", """class="dataframe" id="$id"""") {
225+
emitHeader()
226+
emitBody()
227+
}
228+
229+
return DataFrameHtmlData(
230+
body = buildString { emitTable() },
231+
script = """
232+
document.getElementById("$id").style.display = "none";
233+
""".trimIndent()
234+
)
235+
}
236+
175237
internal fun DataFrameHtmlData.print() = println(this)
176238

177239
@Deprecated(
@@ -216,6 +278,8 @@ public fun <T> DataFrame<T>.toHTML(
216278

217279
var tableHtml = toHtmlData(configuration, cellRenderer)
218280

281+
tableHtml += toStaticHtml(configuration, cellRenderer)
282+
219283
if (bodyFooter != null) {
220284
tableHtml += DataFrameHtmlData("", bodyFooter, "")
221285
}

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/rendering/RenderingTests.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,24 @@ class RenderingTests {
125125
df.toHTML().script shouldContain rendered
126126
}
127127
}
128+
129+
@Test
130+
fun `static rendering should be present`() {
131+
val df = dataFrameOf("a", "b")(listOf(1, 1), listOf(2, 4))
132+
val actualHtml = df.toHTML()
133+
134+
actualHtml.body shouldContain """
135+
<thead>
136+
<tr>
137+
<th>a</th><th>b</th>
138+
</tr>
139+
</thead>
140+
<tbody>
141+
<tr>
142+
<td>[1, 1]</td><td>[2, 4]</td>
143+
</tr>
144+
</tbody>
145+
</table>
146+
""".trimIndent().replace("\n", "")
147+
}
128148
}

0 commit comments

Comments
 (0)