aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt15
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt76
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt2
-rw-r--r--src/test/kotlin/test/pl/treksoft/kvision/panel/TabPanelSpec.kt25
4 files changed, 103 insertions, 15 deletions
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.
*
diff --git a/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt b/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt
index d2177a97..cb48cfd1 100644
--- a/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt
@@ -130,6 +130,8 @@ interface BtOn : On {
var tabulatorDataLoading: ((KvEvent) -> Unit)?
var tabulatorDataLoaded: ((KvEvent) -> Unit)?
var tabulatorDataEdited: ((KvEvent) -> Unit)?
+ var tabClosing: ((KvEvent) -> Unit)?
+ var tabClosed: ((KvEvent) -> Unit)?
}
/**
diff --git a/src/test/kotlin/test/pl/treksoft/kvision/panel/TabPanelSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/panel/TabPanelSpec.kt
index 900a7268..f1f3beeb 100644
--- a/src/test/kotlin/test/pl/treksoft/kvision/panel/TabPanelSpec.kt
+++ b/src/test/kotlin/test/pl/treksoft/kvision/panel/TabPanelSpec.kt
@@ -21,6 +21,7 @@
*/
package test.pl.treksoft.kvision.panel
+import pl.treksoft.jquery.jQuery
import pl.treksoft.kvision.html.Span
import pl.treksoft.kvision.panel.Root
import pl.treksoft.kvision.panel.TabPanel
@@ -89,4 +90,28 @@ class TabPanelSpec : DomSpec {
)
}
}
+
+
+ @Test
+ fun tabClick() {
+ run {
+ val root = Root("test", true)
+ val tabs = TabPanel()
+ root.add(tabs)
+ val label1 = Span("abc")
+ val label2 = Span("def")
+ tabs.addTab("ABC", label1)
+ tabs.addTab("DEF", label2)
+ tabs.removeTab(0)
+ val label3 = Span("ghi")
+ tabs.addTab("GHI", label3)
+ jQuery("#test a")[0]?.click()
+ val element = document.getElementById("test")
+ assertEqualsHtml(
+ "<div><ul class=\"nav nav-tabs\"><li role=\"presentation\" class=\"\"><a href=\"#\">DEF</a></li><li role=\"presentation\"><a href=\"#\">GHI</a></li></ul><div><span>def</span></div></div>",
+ element?.innerHTML,
+ "Should select correct tab by clicking"
+ )
+ }
+ }
} \ No newline at end of file