From 0dfc89efeec2d163ad7db93ab2787e498205d257 Mon Sep 17 00:00:00 2001 From: Robert Jaros Date: Sun, 4 Mar 2018 23:48:11 +0100 Subject: HTML table components. --- src/main/kotlin/pl/treksoft/kvision/html/Tag.kt | 9 +- src/main/kotlin/pl/treksoft/kvision/table/Cell.kt | 50 ++++++ .../kotlin/pl/treksoft/kvision/table/HeaderCell.kt | 50 ++++++ src/main/kotlin/pl/treksoft/kvision/table/Row.kt | 39 +++++ src/main/kotlin/pl/treksoft/kvision/table/Table.kt | 174 +++++++++++++++++++++ 5 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/pl/treksoft/kvision/table/Cell.kt create mode 100644 src/main/kotlin/pl/treksoft/kvision/table/HeaderCell.kt create mode 100644 src/main/kotlin/pl/treksoft/kvision/table/Row.kt create mode 100644 src/main/kotlin/pl/treksoft/kvision/table/Table.kt (limited to 'src/main/kotlin/pl') diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt index 33ef2cb7..897daa60 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt @@ -65,7 +65,14 @@ enum class TAG(internal val tagName: String) { VAR("var"), SAMP("samp"), SPAN("span"), - LI("li") + LI("li"), + + CAPTION("caption"), + THEAD("thead"), + TH("th"), + TBODY("tbody"), + TR("tr"), + TD("td") } /** diff --git a/src/main/kotlin/pl/treksoft/kvision/table/Cell.kt b/src/main/kotlin/pl/treksoft/kvision/table/Cell.kt new file mode 100644 index 00000000..ea59ed81 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/table/Cell.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018. Robert Jaros + */ +package pl.treksoft.kvision.table + +import pl.treksoft.kvision.html.Align +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag + +/** + * HTML table cell component. + * + * @constructor + * @param text text content of the cell + * @param rich determines if [text] can contain HTML code + * @param align text align + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class Cell( + text: String? = null, + rich: Boolean = false, + align: Align? = null, + classes: Set = setOf(), + init: (Cell.() -> Unit)? = null +) : Tag(TAG.TD, text, rich, align, classes) { + + init { + init?.invoke(this) + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Row.cell( + text: String? = null, + rich: Boolean = false, + align: Align? = null, + classes: Set = setOf(), init: (Cell.() -> Unit)? = null + ): Cell { + val cell = Cell(text, rich, align, classes, init) + this.add(cell) + return cell + } + } + +} diff --git a/src/main/kotlin/pl/treksoft/kvision/table/HeaderCell.kt b/src/main/kotlin/pl/treksoft/kvision/table/HeaderCell.kt new file mode 100644 index 00000000..26ea24d2 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/table/HeaderCell.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018. Robert Jaros + */ +package pl.treksoft.kvision.table + +import pl.treksoft.kvision.html.Align +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag + +/** + * HTML table header cell component. + * + * @constructor + * @param text text content of the cell + * @param rich determines if [text] can contain HTML code + * @param align text align + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class HeaderCell( + text: String? = null, + rich: Boolean = false, + align: Align? = null, + classes: Set = setOf(), + init: (HeaderCell.() -> Unit)? = null +) : Tag(TAG.TH, text, rich, align, classes) { + + init { + init?.invoke(this) + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Row.headerCell( + text: String? = null, + rich: Boolean = false, + align: Align? = null, + classes: Set = setOf(), init: (HeaderCell.() -> Unit)? = null + ): HeaderCell { + val cell = HeaderCell(text, rich, align, classes, init) + this.add(cell) + return cell + } + } + +} diff --git a/src/main/kotlin/pl/treksoft/kvision/table/Row.kt b/src/main/kotlin/pl/treksoft/kvision/table/Row.kt new file mode 100644 index 00000000..d408f699 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/table/Row.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018. Robert Jaros + */ +package pl.treksoft.kvision.table + +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag + +/** + * HTML table row component. + * + * @constructor + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class Row(classes: Set = setOf(), init: (Row.() -> Unit)? = null) : Tag( + TAG.TR, classes = classes +) { + + init { + init?.invoke(this) + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Table.row( + classes: Set = setOf(), init: (Row.() -> Unit)? = null + ): Row { + val row = Row(classes, init) + this.add(row) + return row + } + } + +} diff --git a/src/main/kotlin/pl/treksoft/kvision/table/Table.kt b/src/main/kotlin/pl/treksoft/kvision/table/Table.kt new file mode 100644 index 00000000..31a0913a --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/table/Table.kt @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2018. Robert Jaros + */ +package pl.treksoft.kvision.table + +import com.github.snabbdom.VNode +import com.github.snabbdom.h +import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.utils.snClasses +import pl.treksoft.kvision.utils.snOpt + +/** + * HTML table types. + */ +enum class TableType(internal val type: String) { + STRIPED("table-striped"), + BORDERED("table-bordered"), + HOVER("table-hover"), + CONDENSED("table-condensed") +} + +/** + * HTML table component. + * + * @constructor + * @param headerNames a list of table headers names + * @param types a set of table types + * @param caption table caption + * @param responsive determines if the table is responsive + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class Table( + headerNames: List? = null, + types: Set = setOf(), caption: String? = null, responsive: Boolean = false, + classes: Set = setOf(), init: (Table.() -> Unit)? = null +) : SimplePanel(classes + "table") { + + /** + * Table headers names. + */ + var headerNames by refreshOnUpdate(headerNames, { refreshHeaders() }) + /** + * Table types. + */ + var types by refreshOnUpdate(types) + /** + * Table caption. + */ + var caption by refreshOnUpdate(caption) + /** + * Determines if the table is responsive. + */ + var responsive by refreshOnUpdate(responsive) + + private val theadRow = Tag(TAG.TR) + private val thead = Tag(TAG.THEAD).add(theadRow) + private val tbody = Tag(TAG.TBODY) + + init { + refreshHeaders() + @Suppress("LeakingThis") + init?.invoke(this) + } + + private fun refreshHeaders() { + theadRow.removeAll() + headerNames?.forEach { + theadRow.add(HeaderCell(it)) + } + } + + /** + * Adds new header cell to the table. + * @param cell header cell + * @return this table + */ + fun addHeaderCell(cell: HeaderCell): Table { + theadRow.add(cell) + return this + } + + /** + * Removes given header cell from the table. + * @param cell header cell + * @return this table + */ + fun removeHeaderCell(cell: HeaderCell): Table { + theadRow.remove(cell) + return this + } + + /** + * Removes all header cells from table. + * @return this table + */ + fun removeHeaderCells(): Table { + theadRow.removeAll() + return this + } + + override fun render(): VNode { + return if (responsive) { + val opt = snOpt { + `class` = snClasses(listOf("table-responsive" to true)) + } + h("div", opt, arrayOf(render("table", childrenVNodes()))) + } else { + render("table", childrenVNodes()) + } + } + + override fun childrenVNodes(): Array { + val captionElement = caption?.let { + Tag(TAG.CAPTION, it) + } + return listOf(captionElement, thead, tbody).mapNotNull { it?.renderVNode() }.toTypedArray() + } + + override fun getSnClass(): List { + val cl = super.getSnClass().toMutableList() + types.forEach { + cl.add(it.type to true) + } + return cl + } + + override fun add(child: Component): SimplePanel { + tbody.add(child) + return this + } + + override fun addAll(children: List): SimplePanel { + tbody.addAll(children) + return this + } + + override fun remove(child: Component): SimplePanel { + tbody.remove(child) + return this + } + + override fun removeAll(): SimplePanel { + tbody.removeAll() + return this + } + + override fun getChildren(): List { + return tbody.getChildren() + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.table( + headerNames: List? = null, + types: Set = setOf(), caption: String? = null, responsive: Boolean = false, + classes: Set = setOf(), init: (Table.() -> Unit)? = null + ): Table { + val table = + Table(headerNames, types, caption, responsive, classes, init) + this.add(table) + return table + } + } +} -- cgit