Skip to content

Change toHTML rendering to allow custom HTML content inside cells and not just text #967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 3, 2024
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 @@ -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 """<img src="$src" style="$style"}/>"""
return """<img src="$src" style="$style"/>"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow good find

}
}
14 changes: 13 additions & 1 deletion core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -514,6 +516,8 @@ private fun AnyFrame.getColumnsHeaderGrid(): List<List<ColumnWithPathWithBorder<
internal fun DataFrameHtmlData.print() = println(this)

/**
* By default, cell content is formatted as text
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very helpful comment, thanks!

* Use [RenderedContent.media] or [IMG], [IFRAME] if you need custom HTML inside a cell.
* @return DataFrameHtmlData with table script and css definitions. Can be saved as an *.html file and displayed in the browser
*/
public fun <T> DataFrame<T>.toStandaloneHTML(
Expand All @@ -523,6 +527,8 @@ public fun <T> DataFrame<T>.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 <T> DataFrame<T>.toHTML(
Expand Down Expand Up @@ -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 -> {
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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: ["<img src=\"https://github.com/Kotlin/dataframe/blob/master/docs/StardustDocs/images/gettingStarted.png?raw=true\" style=\"\"/>"]"""
}

@Test
fun `render custom content`() {
val df = dataFrameOf("customUrl")(RenderedContent.media("""<a href="http://example.com">Click me!</a>"""))
df.toStandaloneHTML().toString() shouldInclude
"""values: ["<a href=\"http://example.com\">Click me!</a>"]"""
}

@Test
fun `render iframe content`() {
val df = dataFrameOf("iframe")(IFRAME("http://example.com"))
df.toStandaloneHTML().toString() shouldInclude
"""values: ["<iframe src=\"http://example.com\"""
}
}