@@ -5,6 +5,7 @@ import org.jetbrains.kotlinx.dataframe.AnyCol
5
5
import org.jetbrains.kotlinx.dataframe.AnyFrame
6
6
import org.jetbrains.kotlinx.dataframe.AnyRow
7
7
import org.jetbrains.kotlinx.dataframe.DataFrame
8
+ import org.jetbrains.kotlinx.dataframe.api.FormattedFrame
8
9
import org.jetbrains.kotlinx.dataframe.api.FormattingDSL
9
10
import org.jetbrains.kotlinx.dataframe.api.RowColFormatter
10
11
import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
@@ -138,13 +139,13 @@ internal var sessionId = (Random().nextInt() % 128) shl 24
138
139
internal fun nextTableId () = sessionId + (tableInSessionId++ )
139
140
140
141
internal fun AnyFrame.toHtmlData (
141
- configuration : DisplayConfiguration = DisplayConfiguration .DEFAULT ,
142
+ defaultConfiguration : DisplayConfiguration = DisplayConfiguration .DEFAULT ,
142
143
cellRenderer : CellRenderer ,
143
144
): DataFrameHtmlData {
144
145
val scripts = mutableListOf<String >()
145
- val queue = LinkedList <Pair < AnyFrame , Int > >()
146
+ val queue = LinkedList <RenderingQueueItem >()
146
147
147
- fun AnyFrame.columnToJs (col : AnyCol , rowsLimit : Int? ): ColumnDataForJs {
148
+ fun AnyFrame.columnToJs (col : AnyCol , rowsLimit : Int? , configuration : DisplayConfiguration ): ColumnDataForJs {
148
149
val values = if (rowsLimit != null ) rows().take(rowsLimit) else rows()
149
150
val scale = if (col.isNumber()) col.asNumbers().scale() else 1
150
151
val format = if (scale > 0 ) {
@@ -155,13 +156,15 @@ internal fun AnyFrame.toHtmlData(
155
156
val renderConfig = configuration.copy(decimalFormat = format)
156
157
val contents = values.map {
157
158
val value = it[col]
158
- if (value is AnyFrame ) {
159
- if (value.isEmpty()) {
159
+ val content = value.toDataFrameLikeOrNull()
160
+ if (content != null ) {
161
+ val df = content.df()
162
+ if (df.isEmpty()) {
160
163
HtmlContent (" " , null )
161
164
} else {
162
165
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)
165
168
}
166
169
} else {
167
170
val html =
@@ -174,20 +177,25 @@ internal fun AnyFrame.toHtmlData(
174
177
HtmlContent (html, style)
175
178
}
176
179
}
180
+ val nested = if (col is ColumnGroup <* >) {
181
+ col.columns().map { col.columnToJs(it, rowsLimit, configuration) }
182
+ } else {
183
+ emptyList()
184
+ }
177
185
return ColumnDataForJs (
178
186
column = col,
179
- nested = if (col is ColumnGroup < * >) col.columns().map { col.columnToJs(it, rowsLimit) } else emptyList() ,
187
+ nested = nested ,
180
188
rightAlign = col.isSubtypeOf<Number ?>(),
181
189
values = contents,
182
190
)
183
191
}
184
192
185
193
val rootId = nextTableId()
186
- queue.add(this to rootId)
194
+ queue.add(RenderingQueueItem ( this , rootId, defaultConfiguration) )
187
195
while (! queue.isEmpty()) {
188
- val (nextDf, nextId) = queue.pop()
196
+ val (nextDf, nextId, configuration ) = queue.pop()
189
197
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 ) }
191
199
val js = tableJs(preparedColumns, nextId, rootId, nextDf.nrow)
192
200
scripts.add(js)
193
201
}
@@ -196,6 +204,36 @@ internal fun AnyFrame.toHtmlData(
196
204
return DataFrameHtmlData (style = " " , body = body, script = script)
197
205
}
198
206
207
+ private interface DataFrameLike {
208
+ fun configuration (default : DisplayConfiguration ): DisplayConfiguration
209
+
210
+ fun df (): AnyFrame
211
+ }
212
+
213
+ private fun Any?.toDataFrameLikeOrNull (): DataFrameLike ? =
214
+ when (this ) {
215
+ is AnyFrame -> {
216
+ object : DataFrameLike {
217
+ override fun configuration (default : DisplayConfiguration ) = default
218
+
219
+ override fun df (): AnyFrame = this @toDataFrameLikeOrNull
220
+ }
221
+ }
222
+
223
+ is FormattedFrame <* > -> {
224
+ object : DataFrameLike {
225
+ override fun configuration (default : DisplayConfiguration ): DisplayConfiguration =
226
+ getDisplayConfiguration(default)
227
+
228
+ override fun df (): AnyFrame = df
229
+ }
230
+ }
231
+
232
+ else -> null
233
+ }
234
+
235
+ private data class RenderingQueueItem (val df : DataFrame <* >, val id : Int , val configuration : DisplayConfiguration )
236
+
199
237
private const val DEFAULT_HTML_IMG_SIZE = 100
200
238
201
239
/* *
0 commit comments