From 8d59c97c1925360d1dee1ff080efa40372a5741e Mon Sep 17 00:00:00 2001 From: Nikita Klimenko Date: Mon, 25 Nov 2024 16:45:56 +0200 Subject: [PATCH] Change toHTML rendering to allow custom HTML content inside cells and not just text fixes #319 --- .../kotlinx/dataframe/dataTypes/IMG.kt | 2 +- .../jetbrains/kotlinx/dataframe/io/html.kt | 14 ++++++++++- .../kotlinx/dataframe/jupyter/CellRenderer.kt | 5 +++- .../dataframe/rendering/RenderingTests.kt | 24 +++++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/dataTypes/IMG.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/dataTypes/IMG.kt index 15ca325853..4dfb55e038 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/dataTypes/IMG.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/dataTypes/IMG.kt @@ -23,6 +23,6 @@ public data class IMG( if (height != null) style.append("height:${height}px;") if (maxWidth != null) style.append("max-width:${maxWidth}px;") if (maxHeight != null) style.append("max-height:${maxHeight}px;") - return """""" + return """""" } } diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt index 432eab2c02..956fd99aa0 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt @@ -20,6 +20,8 @@ import org.jetbrains.kotlinx.dataframe.columns.BaseColumn import org.jetbrains.kotlinx.dataframe.columns.ColumnGroup import org.jetbrains.kotlinx.dataframe.columns.ColumnWithPath import org.jetbrains.kotlinx.dataframe.columns.FrameColumn +import org.jetbrains.kotlinx.dataframe.dataTypes.IFRAME +import org.jetbrains.kotlinx.dataframe.dataTypes.IMG import org.jetbrains.kotlinx.dataframe.impl.DataFrameSize import org.jetbrains.kotlinx.dataframe.impl.columns.addPath import org.jetbrains.kotlinx.dataframe.impl.io.resizeKeepingAspectRatio @@ -514,6 +516,8 @@ private fun AnyFrame.getColumnsHeaderGrid(): List DataFrame.toStandaloneHTML( @@ -523,6 +527,8 @@ public fun DataFrame.toStandaloneHTML( ): DataFrameHtmlData = toHTML(configuration, cellRenderer, getFooter).withTableDefinitions() /** + * By default, cell content is formatted as text + * Use [RenderedContent.media] or [IMG], [IFRAME] if you need custom HTML inside a cell. * @return DataFrameHtmlData without additional definitions. Can be rendered in Jupyter kernel environments */ public fun DataFrame.toHTML( @@ -834,7 +840,7 @@ internal class DataFrameFormatter( return sb.result() } - val result = when (value) { + val result: RenderedContent? = when (value) { null -> "null".addCss(nullClass) is AnyRow -> { @@ -899,6 +905,12 @@ internal class DataFrameFormatter( is DataFrameHtmlData -> RenderedContent.text(value.body) + is IMG -> RenderedContent.media(value.toString()) + + is IFRAME -> RenderedContent.media(value.toString()) + + is RenderedContent -> value + else -> renderer.content(value, configuration) } if (result != null && result.textLength > configuration.cellContentLimit) return null diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/CellRenderer.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/CellRenderer.kt index 6046d3f890..c9cb625cf4 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/CellRenderer.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/CellRenderer.kt @@ -1,5 +1,6 @@ package org.jetbrains.kotlinx.dataframe.jupyter +import org.intellij.lang.annotations.Language import org.jetbrains.kotlinx.dataframe.io.DisplayConfiguration import org.jetbrains.kotlinx.dataframe.io.renderValueForHtml import org.jetbrains.kotlinx.dataframe.io.tooltipLimit @@ -12,7 +13,9 @@ public data class RenderedContent( ) { public companion object { - public fun media(html: String): RenderedContent = RenderedContent(html, 0, null, false) + public fun media( + @Language("HTML") html: String, + ): RenderedContent = RenderedContent(html, 0, null, false) public fun textWithLength(str: String, len: Int): RenderedContent = RenderedContent(str, len, null, false) diff --git a/core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/rendering/RenderingTests.kt b/core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/rendering/RenderingTests.kt index 786e946649..c2caec3de4 100644 --- a/core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/rendering/RenderingTests.kt +++ b/core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/rendering/RenderingTests.kt @@ -20,6 +20,8 @@ import org.jetbrains.kotlinx.dataframe.api.parse import org.jetbrains.kotlinx.dataframe.api.schema import org.jetbrains.kotlinx.dataframe.api.toDataFrame import org.jetbrains.kotlinx.dataframe.api.with +import org.jetbrains.kotlinx.dataframe.dataTypes.IFRAME +import org.jetbrains.kotlinx.dataframe.dataTypes.IMG import org.jetbrains.kotlinx.dataframe.io.DisplayConfiguration import org.jetbrains.kotlinx.dataframe.io.escapeHTML import org.jetbrains.kotlinx.dataframe.io.formatter @@ -227,4 +229,26 @@ class RenderingTests : TestBase() { val html = df.toStandaloneHTML() html.toString() shouldInclude "style: \"background-color" } + + @Test + fun `render img`() { + val src = "https://github.com/Kotlin/dataframe/blob/master/docs/StardustDocs/images/gettingStarted.png?raw=true" + val df = dataFrameOf("img")(IMG(src)) + df.toStandaloneHTML().toString() shouldInclude + """values: [""]""" + } + + @Test + fun `render custom content`() { + val df = dataFrameOf("customUrl")(RenderedContent.media("""Click me!""")) + df.toStandaloneHTML().toString() shouldInclude + """values: ["Click me!"]""" + } + + @Test + fun `render iframe content`() { + val df = dataFrameOf("iframe")(IFRAME("http://example.com")) + df.toStandaloneHTML().toString() shouldInclude + """values: ["