aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/pl/treksoft/kvision/panel
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/pl/treksoft/kvision/panel')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt6
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/Root.kt27
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt15
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt76
4 files changed, 99 insertions, 25 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt
index 310d4d49..010f7cba 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt
@@ -24,7 +24,7 @@ package pl.treksoft.kvision.panel
import pl.treksoft.kvision.core.Component
import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.StringPair
-import pl.treksoft.kvision.core.StyledComponent
+import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.core.WidgetWrapper
import pl.treksoft.kvision.utils.px
@@ -152,10 +152,10 @@ open class FlexPanel(
}
private fun refreshSpacing() {
- getChildren().filterIsInstance<StyledComponent>().map { applySpacing(it) }
+ getChildren().filterIsInstance<Widget>().map { applySpacing(it) }
}
- private fun applySpacing(wrapper: StyledComponent): StyledComponent {
+ private fun applySpacing(wrapper: Widget): Widget {
wrapper.marginTop = null
wrapper.marginRight = null
wrapper.marginBottom = null
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt b/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt
index c17ea1a4..2d9dcc46 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt
@@ -23,6 +23,7 @@ package pl.treksoft.kvision.panel
import com.github.snabbdom.VNode
import com.github.snabbdom.h
+import org.w3c.dom.HTMLElement
import pl.treksoft.kvision.KVManager
import pl.treksoft.kvision.core.StringBoolPair
import pl.treksoft.kvision.core.Style
@@ -45,7 +46,12 @@ import pl.treksoft.kvision.utils.snOpt
* @param init an initializer extension function
*/
@Suppress("TooManyFunctions")
-class Root(id: String, private val fixed: Boolean = false, init: (Root.() -> Unit)? = null) : SimplePanel() {
+class Root(
+ id: String? = null,
+ element: HTMLElement? = null,
+ private val fixed: Boolean = false,
+ init: (Root.() -> Unit)? = null
+) : SimplePanel() {
private val contextMenus: MutableList<ContextMenu> = mutableListOf()
private var rootVnode: VNode = renderVNode()
@@ -54,11 +60,17 @@ class Root(id: String, private val fixed: Boolean = false, init: (Root.() -> Uni
val isFirstRoot = roots.isEmpty()
init {
- rootVnode = KVManager.patch(id, this.renderVNode())
- this.id = id
+ if (id != null) {
+ rootVnode = KVManager.patch(id, this.renderVNode())
+ this.id = id
+ } else if (element != null) {
+ rootVnode = KVManager.patch(element, this.renderVNode())
+ this.id = "kv_root_${counter++}"
+ } else {
+ throw IllegalArgumentException("No root element specified!")
+ }
roots.add(this)
if (isFirstRoot) {
- Style.styles.forEach { it.parent = this }
Modal.modals.forEach { it.parent = this }
}
@Suppress("LeakingThis")
@@ -89,9 +101,8 @@ class Root(id: String, private val fixed: Boolean = false, init: (Root.() -> Uni
private fun stylesVNodes(): Array<VNode> {
return if (isFirstRoot) {
- val visibleStyles = Style.styles.filter { it.visible }
- if (visibleStyles.isNotEmpty()) {
- val stylesDesc = visibleStyles.joinToString("\n") { it.generateStyle() }
+ if (Style.styles.isNotEmpty()) {
+ val stylesDesc = Style.styles.joinToString("\n") { it.generateStyle() }
arrayOf(h("style", arrayOf(stylesDesc)))
} else {
arrayOf()
@@ -144,6 +155,8 @@ class Root(id: String, private val fixed: Boolean = false, init: (Root.() -> Uni
}
companion object {
+ internal var counter = 0
+
/**
* @suppress internal function
*/
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
index 3b045fa6..37dd449b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
@@ -55,6 +55,8 @@ open class StackPanel(
activeIndex = children.indexOf(value)
}
+ internal val childrenMap = mutableMapOf<Int, Component>()
+
init {
@Suppress("LeakingThis")
init?.invoke(this)
@@ -76,8 +78,11 @@ open class StackPanel(
*/
open fun add(panel: Component, route: String): StackPanel {
add(panel)
- val currentIndex = children.size - 1
- routing.on(route, { _ -> activeIndex = currentIndex }).resolve()
+ val currentIndex = counter++
+ childrenMap[currentIndex] = panel
+ routing.on(route, { _ ->
+ activeChild = childrenMap[currentIndex]!!
+ }).resolve()
return this
}
@@ -97,17 +102,23 @@ open class StackPanel(
override fun remove(child: Component): StackPanel {
super.remove(child)
+ childrenMap.filter { it.value == child }.keys.firstOrNull()?.let {
+ childrenMap.remove(it)
+ }
if (activeIndex > children.size - 1) activeIndex = children.size - 1
return this
}
override fun removeAll(): StackPanel {
super.removeAll()
+ childrenMap.clear()
if (activeIndex > children.size - 1) activeIndex = children.size - 1
return this
}
companion object {
+ internal var counter = 0
+
/**
* DSL builder extension function.
*
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt
index 5a4fac0c..ae8360b5 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt
@@ -25,10 +25,13 @@ import pl.treksoft.kvision.core.Component
import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.ResString
import pl.treksoft.kvision.core.WidgetWrapper
-import pl.treksoft.kvision.html.Link
+import pl.treksoft.kvision.html.Icon
+import pl.treksoft.kvision.html.Link.Companion.link
import pl.treksoft.kvision.html.TAG
import pl.treksoft.kvision.html.Tag
import pl.treksoft.kvision.routing.routing
+import pl.treksoft.kvision.utils.obj
+import pl.treksoft.kvision.html.Icon.Companion.icon as cicon
/**
* Tab position.
@@ -95,6 +98,8 @@ open class TabPanel(
private var nav = Tag(TAG.UL, classes = navClasses)
private var content = StackPanel(false)
+ internal val childrenMap = mutableMapOf<Int, Component>()
+
init {
when (tabPosition) {
TabPosition.TOP -> {
@@ -135,23 +140,46 @@ open class TabPanel(
* @param panel child component
* @param icon icon of the tab
* @param image image of the tab
+ * @param closable determines if this tab is closable
* @param route JavaScript route to activate given child
* @return current container
*/
open fun addTab(
title: String, panel: Component, icon: String? = null,
- image: ResString? = null, route: String? = null
+ image: ResString? = null, closable: Boolean = false, route: String? = null
): TabPanel {
- val tag = Tag(TAG.LI)
- tag.role = "presentation"
- tag.add(Link(title, "#", icon, image))
- val index = nav.children.size
- tag.setEventListener {
- click = { e ->
- activeIndex = index
- e.preventDefault()
- if (route != null) {
- routing.navigate(route)
+ val currentIndex = counter++
+ childrenMap[currentIndex] = panel
+ val tag = Tag(TAG.LI) {
+ role = "presentation"
+ link(title, "#", icon, image) {
+ if (closable) {
+ cicon("remove") {
+ addCssClass("kv-tab-close")
+ setEventListener<Icon> {
+ click = { e ->
+ val actIndex = this@TabPanel.content.children.indexOf(childrenMap[currentIndex])
+ e.asDynamic().data = actIndex
+ if (this@TabPanel.dispatchEvent(
+ "tabClosing",
+ obj { detail = e; cancelable = true }) != false
+ ) {
+ this@TabPanel.removeTab(actIndex)
+ this@TabPanel.dispatchEvent("tabClosed", obj { detail = e })
+ }
+ e.stopPropagation()
+ }
+ }
+ }
+ }
+ }
+ setEventListener {
+ click = { e ->
+ activeIndex = this@TabPanel.content.children.indexOf(childrenMap[currentIndex])
+ e.preventDefault()
+ if (route != null) {
+ routing.navigate(route)
+ }
}
}
}
@@ -162,7 +190,8 @@ open class TabPanel(
}
content.add(panel)
if (route != null) {
- routing.on(route, { _ -> activeIndex = index }).resolve()
+ routing.on(route, { _ -> activeIndex = this@TabPanel.content.children.indexOf(childrenMap[currentIndex]) })
+ .resolve()
}
return this
}
@@ -172,6 +201,9 @@ open class TabPanel(
*/
open fun removeTab(index: Int): TabPanel {
nav.remove(nav.children[index])
+ childrenMap.filter { it.value == content.children[index] }.keys.firstOrNull()?.let {
+ childrenMap.remove(it)
+ }
content.remove(content.children[index])
activeIndex = content.activeIndex
return this
@@ -191,14 +223,32 @@ open class TabPanel(
return removeTab(index)
}
+ /**
+ * Returns child component by tab index.
+ * @param index tab index
+ */
+ open fun getChildComponent(index: Int): Component? {
+ return content.children[index]
+ }
+
+ /**
+ * Returns tab header component by tab index.
+ * @param index tab index
+ */
+ open fun getNavComponent(index: Int): Tag? {
+ return nav.children[index] as? Tag
+ }
+
override fun removeAll(): TabPanel {
content.removeAll()
nav.removeAll()
+ childrenMap.clear()
refresh()
return this
}
companion object {
+ internal var counter = 0
/**
* DSL builder extension function.
*