aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2017-09-24 05:42:20 +0200
committerRobert Jaros <rjaros@finn.pl>2017-09-24 05:42:20 +0200
commit176215818b2572eefc1df18401ddaa896ea8a1fb (patch)
treea16b910d83760b6472e48dcefd8c8490b883c360
parent659b87f5c1c297c68b125f67bc0b29b547debfd0 (diff)
downloadkvision-176215818b2572eefc1df18401ddaa896ea8a1fb.tar.gz
kvision-176215818b2572eefc1df18401ddaa896ea8a1fb.tar.bz2
kvision-176215818b2572eefc1df18401ddaa896ea8a1fb.zip
New containers: StackPanel, SplitPanel, Tabs
-rw-r--r--build.gradle1
-rw-r--r--src/main/assets/css/style.css54
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/Showcase.kt39
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Container.kt5
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt4
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Root.kt2
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Widget.kt34
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt8
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/html/Button.kt13
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/html/Link.kt17
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/html/Tag.kt2
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt63
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt52
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt50
-rw-r--r--src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt6
-rw-r--r--webpack.config.d/css.js2
-rw-r--r--webpack.config.d/jquery.js4
17 files changed, 325 insertions, 31 deletions
diff --git a/build.gradle b/build.gradle
index 9aec693d..1b3f4345 100644
--- a/build.gradle
+++ b/build.gradle
@@ -52,6 +52,7 @@ kotlinFrontend {
dependency("snabbdom", "0.6.9")
dependency "snabbdom-virtualize"
dependency "navigo"
+ dependency "jquery-resizable-dom"
devDependency("karma")
}
diff --git a/src/main/assets/css/style.css b/src/main/assets/css/style.css
new file mode 100644
index 00000000..19f2c63e
--- /dev/null
+++ b/src/main/assets/css/style.css
@@ -0,0 +1,54 @@
+.splitpanel-vertical {
+ display: flex;
+ flex-direction: row;
+ overflow: auto;
+}
+
+.splitpanel-vertical > *:first-child {
+ max-width: calc(100% - 18px);
+}
+
+.splitpanel-vertical > * {
+ flex: 0 0 auto;
+ overflow: auto;
+}
+
+.splitpanel-vertical > *:last-child {
+ flex: 1 1 auto;
+ overflow: auto;
+}
+
+.splitpanel-horizontal {
+ display: flex;
+ flex-direction: column;
+ overflow: auto;
+}
+
+.splitpanel-horizontal > *:first-child {
+ max-height: calc(100% - 18px);
+}
+
+.splitpanel-horizontal > * {
+ flex: 0 0 auto;
+ overflow: auto;
+}
+
+.splitpanel-horizontal > *:last-child {
+ flex: 1 1 auto;
+ overflow: auto;
+}
+
+
+.splitter-vertical {
+ flex: 0 0 auto;
+ width: 18px;
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAhCAQAAABOpSL+AAAAIklEQVR4AWMwbb/PdR+JZDD9f1/oPhI5sgVGBSruc9xHIgGdSQqqQJGkRgAAAABJRU5ErkJggg==') center center no-repeat #535353;
+ cursor: col-resize;
+}
+
+.splitter-horizontal {
+ flex: 0 0 auto;
+ height: 18px;
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAICAQAAADdTl4aAAAAIElEQVQoz2MwrTD9TxFsZ7jPcV+IIsjFQAUw6hFqegQA+xzRHT2p7pEAAAAASUVORK5CYII=') center center no-repeat #535353;
+ cursor: row-resize;
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
index 3bccdfb1..25bacd6b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
@@ -10,10 +10,11 @@ import pl.treksoft.kvision.html.*
import pl.treksoft.kvision.html.TAG.H1
import pl.treksoft.kvision.modal.Alert
import pl.treksoft.kvision.modal.Confirm
-import pl.treksoft.kvision.modal.MODALSIZE
import pl.treksoft.kvision.modal.Modal
+import pl.treksoft.kvision.panel.DIRECTION
+import pl.treksoft.kvision.panel.SplitPanel
import pl.treksoft.kvision.routing.routing
-import kotlin.browser.window
+import pl.treksoft.kvision.tabs.Tabs
class Showcase : ApplicationBase() {
@@ -46,8 +47,8 @@ class Showcase : ApplicationBase() {
hiddenBsDropdown = { e -> println("hidden" + e.detail) }
}
- val dd2 = DropDown("Dropdown2", listOf("abc" to "#!/abc", "def" to "#!/def", "xyz" to DISABLED.POS,
- "Header" to HEADER.POS, "Separtatorek" to SEPARATOR.POS
+ val dd2 = DropDown("Dropdown2", listOf("abc" to "#!/abc", "def" to "#!/def", "xyz" to DISABLED.type,
+ "Header" to HEADER.type, "Separtatorek" to SEPARATOR.type
), "flag", dropup = true)
root.add(dd2)
dd2.setEventListener<DropDown> {
@@ -61,6 +62,27 @@ class Showcase : ApplicationBase() {
dd3.add(Image(Img("kotlin.png")))
root.add(dd3)
+ val tabs2 = Tabs()
+ tabs2.addTab("XXX", Label("XXX"), "fa-flag")
+ tabs2.addTab("YYY", Label("YYY"), "fa-flag")
+
+ val tabs = Tabs()
+ tabs.addTab("Test zakładki", Label("test zakładki"), "fa-flag")
+ tabs.addTab("Test zakładki2", Label("test zakładki2"))
+ tabs.addTab("Test zakładki3", tabs2, "fa-bars")
+
+ val split = SplitPanel()
+ split.add(tabs)
+
+ val split2 = SplitPanel(DIRECTION.HORIZONTAL)
+ split2.add(Tag(TAG.DIV, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nec fringilla turpis, vel molestie dolor. Vestibulum ut ex eget orci porta gravida eu sit amet tortor. Suspendisse vel fermentum purus, vel ornare tellus. Vivamus dictum, risus non viverra venenatis, magna mi pharetra purus, nec dignissim risus tortor a sem. Donec tincidunt dui ut eros laoreet consectetur. Nam dapibus vestibulum sem, eget accumsan ex vestibulum ac. Curabitur ac mi sit amet eros sodales dictum. Sed at felis at nunc aliquam finibus. Vestibulum lorem nulla, dictum ac libero non, mattis dictum nisl. Aenean semper lorem turpis. Praesent pellentesque ligula est, viverra molestie leo imperdiet ut. Nam vitae hendrerit justo. Nullam tincidunt et nibh ac volutpat. Aliquam vulputate mi aliquam fermentum rhoncus.\n" +
+ "\n" +
+ "Proin porttitor diam id massa eleifend aliquet. Morbi nec erat porttitor, placerat lorem et, dignissim lectus. Cras ultricies posuere arcu, et pharetra dui laoreet in. Sed nec ipsum in sapien vestibulum maximus eu id nunc. Ut finibus aliquam nisi id vehicula. Phasellus sodales lobortis orci, non interdum risus dignissim quis. Proin bibendum consectetur diam nec mattis. Suspendisse dictum vulputate metus at tincidunt."))
+ split2.add(Tag(TAG.DIV, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nec fringilla turpis, vel molestie dolor. Vestibulum ut ex eget orci porta gravida eu sit amet tortor. Suspendisse vel fermentum purus, vel ornare tellus. Vivamus dictum, risus non viverra venenatis, magna mi pharetra purus, nec dignissim risus tortor a sem. Donec tincidunt dui ut eros laoreet consectetur. Nam dapibus vestibulum sem, eget accumsan ex vestibulum ac. Curabitur ac mi sit amet eros sodales dictum. Sed at felis at nunc aliquam finibus. Vestibulum lorem nulla, dictum ac libero non, mattis dictum nisl. Aenean semper lorem turpis. Praesent pellentesque ligula est, viverra molestie leo imperdiet ut. Nam vitae hendrerit justo. Nullam tincidunt et nibh ac volutpat. Aliquam vulputate mi aliquam fermentum rhoncus.\n" +
+ "\n" +
+ "Proin porttitor diam id massa eleifend aliquet. Morbi nec erat porttitor, placerat lorem et, dignissim lectus. Cras ultricies posuere arcu, et pharetra dui laoreet in. Sed nec ipsum in sapien vestibulum maximus eu id nunc. Ut finibus aliquam nisi id vehicula. Phasellus sodales lobortis orci, non interdum risus dignissim quis. Proin bibendum consectetur diam nec mattis. Suspendisse dictum vulputate metus at tincidunt."))
+ split.add(split2)
+ root.add(split)
val p = Tag(TAG.P, "To jest prawo", align = ALIGN.RIGHT)
p.title = "Tytuł"
@@ -95,11 +117,16 @@ class Showcase : ApplicationBase() {
dd3.text = "Zmiana"
dd3.style = BUTTONSTYLE.WARNING
dd3.disabled = true
- modal.show()
+/* modal.show()
window.setTimeout({
modal.size = MODALSIZE.SMALL
modal.animation = false
- }, 2000)
+ }, 2000)*/
+ if (split.visible) {
+ split.hide()
+ } else {
+ split.show()
+ }
}
}
root.add(button)
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt
index 61199a00..575405c6 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt
@@ -3,7 +3,7 @@ package pl.treksoft.kvision.core
import com.github.snabbdom.VNode
open class Container(classes: Set<String> = setOf()) : Widget(classes) {
- protected val children: MutableList<Widget> = mutableListOf()
+ internal val children: MutableList<Widget> = mutableListOf()
override fun render(): VNode {
return kvh("div", childrenVNodes())
@@ -51,4 +51,7 @@ open class Container(classes: Set<String> = setOf()) : Widget(classes) {
return this
}
+ open fun getChildren(): List<Widget> {
+ return ArrayList(children)
+ }
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt
index 1d937511..dfcbc87c 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt
@@ -8,19 +8,23 @@ import com.github.snabbdom.datasetModule
import com.github.snabbdom.eventListenersModule
import com.github.snabbdom.propsModule
import com.github.snabbdom.styleModule
+import org.w3c.dom.Node
import pl.treksoft.jquery.jQuery
import pl.treksoft.kvision.require
import pl.treksoft.kvision.routing.routing
+import pl.treksoft.kvision.snabbdom.obj
import kotlin.browser.document
import kotlin.dom.clear
object KVManager {
private val bootstrapWebpack = require("bootstrap-webpack")
private val fontAwesomeWebpack = require("font-awesome-webpack")
+ private val resizable = require("jquery-resizable-dom")
private val sdPatch = Snabbdom.init(arrayOf(classModule, attributesModule, propsModule, styleModule,
eventListenersModule, datasetModule))
private val sdVirtualize = require("snabbdom-virtualize/strings").default
+ private val splitCss = require("./css/style.css")
internal fun patch(id: String, vnode: VNode): VNode {
val container = document.getElementById(id)
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Root.kt b/src/main/kotlin/pl/treksoft/kvision/core/Root.kt
index b5562b3f..49b3a6f4 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Root.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Root.kt
@@ -4,7 +4,7 @@ import com.github.snabbdom.VNode
import pl.treksoft.kvision.modal.Modal
import pl.treksoft.kvision.snabbdom.StringBoolPair
-class Root(id: String, private val fluid: Boolean = false) : Container() {
+class Root(id: String, private val fluid: Boolean = true) : Container() {
private val modals: MutableList<Modal> = mutableListOf()
private var rootVnode: VNode = render()
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
index 38d39814..8db506e8 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
@@ -46,6 +46,16 @@ open class Widget(classes: Set<String> = setOf()) : KVObject {
field = value
refresh()
}
+ var width: Int? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var height: Int? = null
+ set(value) {
+ field = value
+ refresh()
+ }
private var vnode: VNode? = null
@@ -72,7 +82,14 @@ open class Widget(classes: Set<String> = setOf()) : KVObject {
}
protected open fun getSnStyle(): List<StringPair> {
- return listOf()
+ val snstyle = mutableListOf<StringPair>()
+ if (width != null) {
+ snstyle.add("width" to width.toString() + "px")
+ }
+ if (height != null) {
+ snstyle.add("height" to height.toString() + "px")
+ }
+ return snstyle
}
protected open fun getSnClass(): List<StringBoolPair> {
@@ -195,4 +212,19 @@ open class Widget(classes: Set<String> = setOf()) : KVObject {
internal open fun getRoot(): Root? {
return this.parent?.getRoot()
}
+
+ protected open fun createLabelWithIcon(label: String, icon: String? = null,
+ image: ResString? = null): Array<out Any> {
+ return if (icon != null) {
+ if (icon.startsWith("fa-") == true) {
+ arrayOf(KVManager.virtualize("<i class='fa $icon fa-lg'></i>"), " " + label)
+ } else {
+ arrayOf(KVManager.virtualize("<span class='glyphicon glyphicon-$icon'></span>"), " " + label)
+ }
+ } else if (image != null) {
+ arrayOf(KVManager.virtualize("<img src='$image' alt='' />"), " " + label)
+ } else {
+ arrayOf(label)
+ }
+ }
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
index eb7a0b50..8cc7eaf6 100644
--- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
@@ -17,7 +17,7 @@ import pl.treksoft.kvision.snabbdom.StringBoolPair
import pl.treksoft.kvision.snabbdom.StringPair
import pl.treksoft.kvision.snabbdom.obj
-enum class DD(val POS: String) {
+enum class DD(val type: String) {
HEADER("DD#HEADER"),
DISABLED("DD#DISABLED"),
SEPARATOR("DD#SEPARATOR")
@@ -111,13 +111,13 @@ open class DropDown(text: String, elements: List<StringPair>? = null, icon: Stri
if (elems != null) {
val c = elems.map {
when (it.second) {
- DD.HEADER.POS -> Tag(TAG.LI, it.first, classes = setOf("dropdown-header"))
- DD.SEPARATOR.POS -> {
+ DD.HEADER.type -> Tag(TAG.LI, it.first, classes = setOf("dropdown-header"))
+ DD.SEPARATOR.type -> {
val tag = Tag(TAG.LI, it.first, classes = setOf("divider"))
tag.role = "separator"
tag
}
- DD.DISABLED.POS -> {
+ DD.DISABLED.type -> {
val tag = Tag(TAG.LI, classes = setOf("disabled"))
tag.add(Link(it.first, "#"))
tag
diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt
index 0fe2f559..74822401 100644
--- a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt
@@ -1,7 +1,6 @@
package pl.treksoft.kvision.html
import com.github.snabbdom.VNode
-import pl.treksoft.kvision.core.KVManager
import pl.treksoft.kvision.core.ResString
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -63,17 +62,7 @@ open class Button(text: String, icon: String? = null, style: BUTTONSTYLE = BUTTO
}
override fun render(): VNode {
- val t = if (icon != null) {
- if (icon?.startsWith("fa-") == true) {
- arrayOf(KVManager.virtualize("<i class='fa $icon fa-lg'></i>"), " " + text)
- } else {
- arrayOf(KVManager.virtualize("<span class='glyphicon glyphicon-$icon'></span>"), " " + text)
- }
- } else if (image != null) {
- arrayOf(KVManager.virtualize("<img src='$image' alt='' />"), " " + text)
- } else {
- arrayOf(text)
- }
+ val t = createLabelWithIcon(text, icon, image)
return kvh("button", t)
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt
index e201da48..4f333482 100644
--- a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt
@@ -2,9 +2,11 @@ package pl.treksoft.kvision.html
import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.core.ResString
import pl.treksoft.kvision.snabbdom.StringPair
-open class Link(label: String, url: String, classes: Set<String> = setOf()) : Container(classes) {
+open class Link(label: String, url: String, icon: String? = null, image: ResString? = null,
+ classes: Set<String> = setOf()) : Container(classes) {
var label = label
set(value) {
field = value
@@ -15,9 +17,20 @@ open class Link(label: String, url: String, classes: Set<String> = setOf()) : Co
field = value
refresh()
}
+ var icon = icon
+ set(value) {
+ field = value
+ refresh()
+ }
+ var image = image
+ set(value) {
+ field = value
+ refresh()
+ }
override fun render(): VNode {
- return kvh("a", arrayOf(label) + childrenVNodes())
+ val t = createLabelWithIcon(label, icon, image)
+ return kvh("a", t + childrenVNodes())
}
override fun getSnAttrs(): List<StringPair> {
diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt
index febee81b..109e5509 100644
--- a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt
@@ -19,6 +19,8 @@ enum class TAG(val tagName: String) {
BLOCKQUOTE("blockquote"),
FOOTER("footer"),
PRE("pre"),
+ UL("ul"),
+ OL("ol"),
DIV("div"),
MARK("mark"),
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt
new file mode 100644
index 00000000..234a9a20
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt
@@ -0,0 +1,63 @@
+package pl.treksoft.kvision.panel
+
+import com.github.snabbdom.VNode
+import pl.treksoft.jquery.JQuery
+import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.html.TAG
+import pl.treksoft.kvision.html.Tag
+import pl.treksoft.kvision.snabbdom.obj
+
+enum class DIRECTION(val dir: String) {
+ HORIZONTAL("horizontal"),
+ VERTICAL("vertical")
+}
+
+open class SplitPanel(val direction: DIRECTION = DIRECTION.VERTICAL,
+ classes: Set<String> = setOf()) : Container(classes + ("splitpanel-" + direction.dir)) {
+
+ internal val splitter = Splitter(this, direction)
+
+ internal fun afterInsertSplitter() {
+ if (children.size == 2) {
+ val horizontal = direction == DIRECTION.HORIZONTAL
+ children[0].getElementJQueryD().resizable(obj {
+ handleSelector = "#" + splitter.id
+ resizeWidth = !horizontal
+ resizeHeight = horizontal
+ onDragEnd = { _: dynamic, el: JQuery, _: dynamic ->
+ if (horizontal) {
+ children[0].height = el.height().toInt()
+ } else {
+ children[0].width = el.width().toInt()
+ }
+ }
+ })
+ }
+ }
+
+ override fun childrenVNodes(): Array<VNode> {
+ return if (children.size == 2) {
+ arrayOf(children[0].render(), splitter.render(), children[1].render())
+ } else {
+ arrayOf()
+ }
+ }
+}
+
+class Splitter(val splitPanel: SplitPanel, direction: DIRECTION) : Tag(TAG.DIV,
+ classes = setOf("splitter-" + direction.dir)) {
+ private val idc = "kv_splitter_" + counter
+
+ init {
+ counter++
+ this.id = idc
+ }
+
+ override fun afterInsert(node: VNode) {
+ splitPanel.afterInsertSplitter()
+ }
+
+ companion object {
+ var counter = 0
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
new file mode 100644
index 00000000..24429d42
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
@@ -0,0 +1,52 @@
+package pl.treksoft.kvision.panel
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.core.Widget
+
+open class StackPanel(private val activateLast: Boolean = true,
+ classes: Set<String> = setOf()) : Container(classes) {
+ var activeIndex = -1
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ override fun childrenVNodes(): Array<VNode> {
+ return if (activeIndex >= 0 && activeIndex < children.size) {
+ arrayOf(children[activeIndex].render())
+ } else {
+ arrayOf()
+ }
+ }
+
+ override fun add(child: Widget): Container {
+ super.add(child)
+ if (activateLast) activeIndex = children.size - 1
+ return this
+ }
+
+ override fun addAll(children: List<Widget>): Container {
+ super.addAll(children)
+ if (activateLast) activeIndex = this.children.size - 1
+ return this
+ }
+
+ override fun remove(child: Widget): Container {
+ super.remove(child)
+ if (activeIndex > children.size - 1) activeIndex = children.size - 1
+ return this
+ }
+
+ override fun removeAt(index: Int): Container {
+ super.removeAt(index)
+ if (activeIndex > children.size - 1) activeIndex = children.size - 1
+ return this
+ }
+
+ override fun removeAll(): Container {
+ super.removeAll()
+ if (activeIndex > children.size - 1) activeIndex = children.size - 1
+ return this
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt b/src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt
new file mode 100644
index 00000000..4bc4d4b6
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt
@@ -0,0 +1,50 @@
+package pl.treksoft.kvision.tabs
+
+import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.core.ResString
+import pl.treksoft.kvision.core.Widget
+import pl.treksoft.kvision.html.Link
+import pl.treksoft.kvision.html.TAG
+import pl.treksoft.kvision.html.Tag
+import pl.treksoft.kvision.panel.StackPanel
+
+open class Tabs : Container(setOf()) {
+ internal var nav = Tag(TAG.UL, classes = setOf("nav", "nav-tabs"))
+ internal var content = StackPanel(false)
+ var activeIndex
+ get() = content.activeIndex
+ set(value) {
+ content.activeIndex = value
+ nav.children.forEach { it.removeCssClass("active") }
+ if (content.activeIndex >= 0 && content.activeIndex <= nav.children.size) {
+ nav.children[content.activeIndex].addCssClass("active")
+ }
+ }
+
+ init {
+ this.add(nav)
+ this.add(content)
+ }
+
+ open fun addTab(title: String, panel: Widget, icon: String? = null,
+ image: ResString? = null): Tabs {
+ 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()
+ }
+ }
+ nav.add(tag)
+ if (nav.children.size == 1) {
+ tag.addCssClass("active")
+ activeIndex = 0
+ }
+ content.add(panel)
+ return this
+ }
+
+}
diff --git a/src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt
index f3210e22..8f327928 100644
--- a/src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt
+++ b/src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt
@@ -39,7 +39,7 @@ class DropDownSpec : DomSpec {
fun render_HeaderElement() {
run {
val root = Root("test")
- val dd = DropDown("Dropdown", listOf("abc" to DD.HEADER.POS), "flag")
+ val dd = DropDown("Dropdown", listOf("abc" to DD.HEADER.type), "flag")
root.add(dd)
dd.toggle()
val element = document.getElementById("test")
@@ -51,7 +51,7 @@ class DropDownSpec : DomSpec {
fun render_SeparatorElement() {
run {
val root = Root("test")
- val dd = DropDown("Dropdown", listOf("abc" to DD.SEPARATOR.POS), "flag")
+ val dd = DropDown("Dropdown", listOf("abc" to DD.SEPARATOR.type), "flag")
root.add(dd)
dd.toggle()
val element = document.getElementById("test")
@@ -63,7 +63,7 @@ class DropDownSpec : DomSpec {
fun render_DisabledElement() {
run {
val root = Root("test")
- val dd = DropDown("Dropdown", listOf("abc" to DD.DISABLED.POS), "flag")
+ val dd = DropDown("Dropdown", listOf("abc" to DD.DISABLED.type), "flag")
root.add(dd)
dd.toggle()
val element = document.getElementById("test")
diff --git a/webpack.config.d/css.js b/webpack.config.d/css.js
index 2b43a825..5d710d35 100644
--- a/webpack.config.d/css.js
+++ b/webpack.config.d/css.js
@@ -1,2 +1,2 @@
-config.module.rules.push({ test: /\.css$/, loader: "style!css" });
+config.module.rules.push({ test: /\.css$/, loader: "style-loader!css-loader" });
diff --git a/webpack.config.d/jquery.js b/webpack.config.d/jquery.js
new file mode 100644
index 00000000..40522595
--- /dev/null
+++ b/webpack.config.d/jquery.js
@@ -0,0 +1,4 @@
+config.plugins.push(new webpack.ProvidePlugin({
+ $: "jquery",
+ jQuery: "jquery"
+}));