@@ -5,6 +5,7 @@ import org.jetbrains.kotlinx.dataframe.AnyCol
55import org.jetbrains.kotlinx.dataframe.AnyFrame
66import org.jetbrains.kotlinx.dataframe.AnyRow
77import org.jetbrains.kotlinx.dataframe.DataFrame
8+ import org.jetbrains.kotlinx.dataframe.api.FormattedFrame
89import org.jetbrains.kotlinx.dataframe.api.FormattingDSL
910import org.jetbrains.kotlinx.dataframe.api.RowColFormatter
1011import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
@@ -138,13 +139,13 @@ internal var sessionId = (Random().nextInt() % 128) shl 24
138139internal fun nextTableId () = sessionId + (tableInSessionId++ )
139140
140141internal fun AnyFrame.toHtmlData (
141- configuration : DisplayConfiguration = DisplayConfiguration .DEFAULT ,
142+ defaultConfiguration : DisplayConfiguration = DisplayConfiguration .DEFAULT ,
142143 cellRenderer : CellRenderer ,
143144): DataFrameHtmlData {
144145 val scripts = mutableListOf<String >()
145- val queue = LinkedList <Pair < AnyFrame , Int > >()
146+ val queue = LinkedList <RenderingQueueItem >()
146147
147- fun AnyFrame.columnToJs (col : AnyCol , rowsLimit : Int? ): ColumnDataForJs {
148+ fun AnyFrame.columnToJs (col : AnyCol , rowsLimit : Int? , configuration : DisplayConfiguration ): ColumnDataForJs {
148149 val values = if (rowsLimit != null ) rows().take(rowsLimit) else rows()
149150 val scale = if (col.isNumber()) col.asNumbers().scale() else 1
150151 val format = if (scale > 0 ) {
@@ -155,13 +156,15 @@ internal fun AnyFrame.toHtmlData(
155156 val renderConfig = configuration.copy(decimalFormat = format)
156157 val contents = values.map {
157158 val value = it[col]
158- if (value is AnyFrame ) {
159- if (value.isEmpty()) {
159+ val content = dataFrameLikeOrNull(value)
160+ if (content != null ) {
161+ val df = content.df()
162+ if (df.isEmpty()) {
160163 HtmlContent (" " , null )
161164 } else {
162165 val id = nextTableId()
163- queue.add(value to id )
164- DataFrameReference (id, value .size)
166+ queue.add(RenderingQueueItem (df, id, content.configuration(defaultConfiguration)) )
167+ DataFrameReference (id, df .size)
165168 }
166169 } else {
167170 val html =
@@ -174,20 +177,25 @@ internal fun AnyFrame.toHtmlData(
174177 HtmlContent (html, style)
175178 }
176179 }
180+ val nested = if (col is ColumnGroup <* >) {
181+ col.columns().map { col.columnToJs(it, rowsLimit, configuration) }
182+ } else {
183+ emptyList()
184+ }
177185 return ColumnDataForJs (
178186 column = col,
179- nested = if (col is ColumnGroup < * >) col.columns().map { col.columnToJs(it, rowsLimit) } else emptyList() ,
187+ nested = nested ,
180188 rightAlign = col.isSubtypeOf<Number ?>(),
181189 values = contents,
182190 )
183191 }
184192
185193 val rootId = nextTableId()
186- queue.add(this to rootId)
194+ queue.add(RenderingQueueItem ( this , rootId, defaultConfiguration) )
187195 while (! queue.isEmpty()) {
188- val (nextDf, nextId) = queue.pop()
196+ val (nextDf, nextId, configuration ) = queue.pop()
189197 val rowsLimit = if (nextId == rootId) configuration.rowsLimit else configuration.nestedRowsLimit
190- val preparedColumns = nextDf.columns().map { nextDf.columnToJs(it, rowsLimit) }
198+ val preparedColumns = nextDf.columns().map { nextDf.columnToJs(it, rowsLimit, configuration ) }
191199 val js = tableJs(preparedColumns, nextId, rootId, nextDf.nrow)
192200 scripts.add(js)
193201 }
@@ -196,6 +204,36 @@ internal fun AnyFrame.toHtmlData(
196204 return DataFrameHtmlData (style = " " , body = body, script = script)
197205}
198206
207+ private interface DataFrameLike {
208+ fun configuration (default : DisplayConfiguration ): DisplayConfiguration
209+
210+ fun df (): AnyFrame
211+ }
212+
213+ private fun dataFrameLikeOrNull (value : Any? ): DataFrameLike ? =
214+ when (value) {
215+ is AnyFrame -> {
216+ object : DataFrameLike {
217+ override fun configuration (default : DisplayConfiguration ) = default
218+
219+ override fun df (): AnyFrame = value
220+ }
221+ }
222+
223+ is FormattedFrame <* > -> {
224+ object : DataFrameLike {
225+ override fun configuration (default : DisplayConfiguration ): DisplayConfiguration =
226+ value.getDisplayConfiguration(default)
227+
228+ override fun df (): AnyFrame = value.df
229+ }
230+ }
231+
232+ else -> null
233+ }
234+
235+ private data class RenderingQueueItem (val df : DataFrame <* >, val id : Int , val configuration : DisplayConfiguration )
236+
199237private const val DEFAULT_HTML_IMG_SIZE = 100
200238
201239/* *
0 commit comments