aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2017-10-28 23:45:26 +0200
committerRobert Jaros <rjaros@finn.pl>2017-10-28 23:45:26 +0200
commit06f297d68887c7934e66d2c757abc8bf619df66a (patch)
treea828eec09f0bdc99b0f3fd45972b8cead37fbdec /src
parent6b13b8909a302b0f0f2155b81b83cd5ab4d7a046 (diff)
downloadkvision-06f297d68887c7934e66d2c757abc8bf619df66a.tar.gz
kvision-06f297d68887c7934e66d2c757abc8bf619df66a.tar.bz2
kvision-06f297d68887c7934e66d2c757abc8bf619df66a.zip
Databinding components
Event handlers refactoring
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/Showcase.kt81
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Container.kt61
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Root.kt9
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Widget.kt79
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt15
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt60
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt5
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt8
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/AbstractText.kt4
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/AbstractTextInput.kt28
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/CheckBox.kt4
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/CheckInput.kt32
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/Radio.kt4
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/html/Link.kt4
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/html/List.kt4
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/html/Tag.kt4
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt18
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt13
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt16
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt17
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt63
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt59
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt11
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt33
-rw-r--r--src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt18
-rw-r--r--src/test/kotlin/test/pl/treksoft/kvision/core/KVManagerSpec.kt16
-rw-r--r--src/test/kotlin/test/pl/treksoft/kvision/core/RootSpec.kt4
28 files changed, 465 insertions, 208 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
index f1406505..282ea510 100644
--- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
@@ -1,10 +1,27 @@
package pl.treksoft.kvision
+import com.lightningkite.kotlin.observable.list.observableListOf
import pl.treksoft.kvision.basic.Label
-import pl.treksoft.kvision.core.*
+import pl.treksoft.kvision.core.BGATTACH
+import pl.treksoft.kvision.core.BGREPEAT
+import pl.treksoft.kvision.core.BGSIZE
+import pl.treksoft.kvision.core.BORDERSTYLE
+import pl.treksoft.kvision.core.Background
+import pl.treksoft.kvision.core.Border
+import pl.treksoft.kvision.core.COLOR
+import pl.treksoft.kvision.core.Img
+import pl.treksoft.kvision.core.Root
+import pl.treksoft.kvision.data.DataComponent
+import pl.treksoft.kvision.data.DataContainer
import pl.treksoft.kvision.dropdown.DD.*
import pl.treksoft.kvision.dropdown.DropDown
-import pl.treksoft.kvision.form.*
+import pl.treksoft.kvision.form.CheckBox
+import pl.treksoft.kvision.form.INPUTSIZE
+import pl.treksoft.kvision.form.TEXTINPUTTYPE
+import pl.treksoft.kvision.form.Text
+import pl.treksoft.kvision.form.TextArea
+import pl.treksoft.kvision.form.TextAreaInput
+import pl.treksoft.kvision.form.TextInput
import pl.treksoft.kvision.html.*
import pl.treksoft.kvision.html.TAG.DIV
import pl.treksoft.kvision.html.TAG.H1
@@ -21,7 +38,51 @@ class Showcase : ApplicationBase() {
override fun start(state: Map<String, Any>) {
val root = Root("showcase")
- val container = Container(setOf("abc", "def"))
+ class Model(p: Boolean, t: String) : DataComponent() {
+ var p: Boolean by obs(p)
+ var t: String by obs(t)
+ }
+
+ val model = observableListOf(Model(true, "Pierwszy"), Model(false, "Drugi"), Model(false, "Trzeci"))
+ val datac = DataContainer(model, { element, index ->
+ CheckBox(value = element.p,
+ label = if (element.p) "<b>" + (index + 1) + " " + element.t + "</b>" else element.t,
+ rich = true).setEventListener<CheckBox>({
+ click = {
+ element.p = self.value
+ }
+ })
+ })
+ root.add(datac)
+
+ val mbutton = Button("Pokaż wartości").setEventListener<Button> {
+ click = {
+ println(model.collection)
+ }
+ dblclick = {
+ model.add(Model(true, "XXX"))
+ }
+ }
+ root.add(mbutton)
+ val mbutton2 = Button("Zaznacz").setEventListener<Button> {
+ click = {
+ model.forEach { it.p = true }
+ }
+ dblclick = {
+ model.forEach { it.p = false }
+ }
+ }
+ root.add(mbutton2)
+ val textField = TextInput(placeholder = "Wprowadź hasło ...", value = "abc")
+ val mbutton3 = Button("Ukryj/Pokaż").setEventListener<Button> {
+ click = {
+ if (datac.visible) datac.hide() else datac.show()
+ if (textField.visible) textField.hide() else textField.show()
+ }
+ }
+ root.add(mbutton3)
+
+ val container = SimplePanel(setOf("abc", "def"))
val h1 = Tag(H1, "To jest <i>test pisania</i> tekstu", false, null, classes = setOf("test", "test2"))
container.add(h1)
val label = Label("KVLabel1")
@@ -36,7 +97,6 @@ class Showcase : ApplicationBase() {
link.add(Tag(TAG.P, "Cośtam"))
root.add(link)
- val textField = TextInput(placeholder = "Wprowadź hasło ...", value = "abc")
root.add(textField)
textField.setEventListener<TextInput> {
input = { e ->
@@ -54,7 +114,7 @@ class Showcase : ApplicationBase() {
textField2.size = INPUTSIZE.LARGE
root.add(textField2)
- val checkbox = CheckBox(true, label = "Kliknij aby <b>przetestować</b>", rich = true, circled = true,
+/* val checkbox = CheckBox(true, label = "Kliknij aby <b>przetestować</b>", rich = true, circled = true,
style = CHECKBOXSTYLE.DANGER)
root.add(checkbox)
checkbox.setEventListener<CheckBox> {
@@ -62,9 +122,9 @@ class Showcase : ApplicationBase() {
println("click" + self.value)
}
change = { e -> println("change" + self.value) }
- }
+ }*/
- val radio = Radio(true, name = "radios", label = "Opcja 1", inline = true,
+/* val radio = Radio(true, name = "radios", label = "Opcja 1", inline = true,
style = RADIOSTYLE.DANGER, extraValue = "o1")
val radio2 = Radio(false, name = "radios", label = "Opcja 2", rich = true, inline = true,
style = RADIOSTYLE.WARNING, extraValue = "o2")
@@ -78,7 +138,7 @@ class Showcase : ApplicationBase() {
println("rclick" + self.value)
}
change = { e -> println("rchange" + self.value) }
- }
+ }*/
val text = Text(placeholder = "Pole formularza", maxlength = 5, label = "To jest pole")
root.add(text)
@@ -258,9 +318,10 @@ class Showcase : ApplicationBase() {
val button = Button("To jest przycisk FA", "fa-flag", BUTTONSTYLE.DANGER)
button.setEventListener<Button> {
click = { _ ->
+ println(model.collection)
println(self.text)
println(textField.value)
- println(checkbox.value)
+// println(checkbox.value)
textField2.disabled = false
grid4.colorHex = 0xff0000
dd3.text = "Zmiana"
@@ -340,7 +401,7 @@ class Showcase : ApplicationBase() {
props = snProps("href" to "/foo", "target" to "_blank")
}, "I\'ll take you places!")
))
- val v = patch(container, vnode)
+ val v = patch(child, vnode)
val vnode2 = virtualize("<a href='/top' target='_top'>Test2</a>")
patch(v, vnode2)*/
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt
index df854637..4621a050 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt
@@ -2,56 +2,13 @@ package pl.treksoft.kvision.core
import com.github.snabbdom.VNode
-open class Container(classes: Set<String> = setOf()) : Widget(classes) {
- internal val children: MutableList<Widget> = mutableListOf()
-
- override fun render(): VNode {
- return kvh("div", childrenVNodes())
- }
-
- protected open fun childrenVNodes(): Array<VNode> {
- return children.filter { it.visible }.map { it.renderVNode() }.toTypedArray()
- }
-
- protected fun addInternal(child: Widget): Container {
- children.add(child)
- child.parent = this
- refresh()
- return this
- }
-
- open fun add(child: Widget): Container {
- return addInternal(child)
- }
-
- open fun addAll(children: List<Widget>): Container {
- this.children.addAll(children)
- children.map { it.parent = this }
- refresh()
- return this
- }
-
- open fun remove(child: Widget): Container {
- if (children.remove(child)) {
- child.clearParent()
- refresh()
- }
- return this
- }
-
- open fun removeAll(): Container {
- children.map { it.clearParent() }
- children.clear()
- refresh()
- return this
- }
-
- open fun getChildren(): List<Widget> {
- return ArrayList(children)
- }
-
- override fun dispose() {
- children.forEach { it.dispose() }
- removeAll()
- }
+interface Container {
+ var parent: Widget?
+ var visible: Boolean
+ fun renderVNode(): VNode
+ fun add(child: Widget): Container
+ fun addAll(children: List<Widget>): Container
+ fun remove(child: Widget): Container
+ fun removeAll(): Container
+ fun getChildren(): List<Widget>
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Root.kt b/src/main/kotlin/pl/treksoft/kvision/core/Root.kt
index 0c8a80f6..9d968874 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Root.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Root.kt
@@ -2,12 +2,15 @@ package pl.treksoft.kvision.core
import com.github.snabbdom.VNode
import pl.treksoft.kvision.modal.Modal
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.StringBoolPair
-class Root(id: String, private val fixed: Boolean = false) : Container() {
+class Root(id: String, private val fixed: Boolean = false) : SimplePanel() {
private val modals: MutableList<Modal> = mutableListOf()
private var rootVnode: VNode = renderVNode()
+ internal var renderDisabled = false
+
init {
rootVnode = KVManager.patch(id, this.renderVNode())
this.id = id
@@ -34,7 +37,9 @@ class Root(id: String, private val fixed: Boolean = false) : Container() {
}
internal fun reRender(): Root {
- rootVnode = KVManager.patch(rootVnode, renderVNode())
+ if (!renderDisabled) {
+ rootVnode = KVManager.patch(rootVnode, renderVNode())
+ }
return this
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
index d56e7614..6ce1eade 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
@@ -17,11 +17,12 @@ import pl.treksoft.kvision.snabbdom.snClasses
import pl.treksoft.kvision.snabbdom.snOpt
import pl.treksoft.kvision.snabbdom.snStyle
-@Suppress("TooManyFunctions")
+@Suppress("TooManyFunctions", "LargeClass")
open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
- val classes = classes.toMutableSet()
- val listeners = mutableListOf<SnOn<Widget>.() -> Unit>()
+ internal val classes = classes.toMutableSet()
+ internal val internalListeners = mutableListOf<SnOn<Widget>.() -> Unit>()
+ internal val listeners = mutableListOf<SnOn<Widget>.() -> Unit>()
var parent: Widget? = null
internal set
@@ -55,7 +56,15 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
private var snOnCache: com.github.snabbdom.On? = null
private var snHooksCache: com.github.snabbdom.Hooks? = null
- internal open fun renderVNode(): VNode {
+ protected fun <T> singleRender(block: () -> T): T {
+ getRoot()?.renderDisabled = true
+ val t = block()
+ getRoot()?.renderDisabled = false
+ getRoot()?.reRender()
+ return t
+ }
+
+ open fun renderVNode(): VNode {
return render()
}
@@ -132,9 +141,47 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
}
protected open fun getSnOn(): com.github.snabbdom.On? {
- return if (listeners.size > 0) {
+ return if (internalListeners.size > 0 || listeners.size > 0) {
+ val internalHandlers = on(this)
+ internalListeners.forEach { l -> (internalHandlers::apply)(l) }
val handlers = on(this)
listeners.forEach { l -> (handlers::apply)(l) }
+ if (internalHandlers.click != null) {
+ if (handlers.click == null) {
+ handlers.click = internalHandlers.click
+ } else {
+ val intc = internalHandlers.click
+ val c = handlers.click
+ handlers.click = { e ->
+ intc?.invoke(e)
+ c?.invoke(e)
+ }
+ }
+ }
+ if (internalHandlers.change != null) {
+ if (handlers.change == null) {
+ handlers.change = internalHandlers.change
+ } else {
+ val intc = internalHandlers.change
+ val c = handlers.change
+ handlers.change = { e ->
+ intc?.invoke(e)
+ c?.invoke(e)
+ }
+ }
+ }
+ if (internalHandlers.input != null) {
+ if (handlers.input == null) {
+ handlers.input = internalHandlers.input
+ } else {
+ val intc = internalHandlers.input
+ val c = handlers.input
+ handlers.input = { e ->
+ intc?.invoke(e)
+ c?.invoke(e)
+ }
+ }
+ }
handlers
} else {
null
@@ -144,13 +191,21 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
protected open fun getSnHooks(): com.github.snabbdom.Hooks? {
val hooks = hooks()
hooks.apply {
+ create = { _, v ->
+ vnode = v
+ afterCreate(v)
+ }
insert = { v ->
vnode = v
afterInsert(v)
}
postpatch = { ov, v ->
vnode = v
- if (ov.elm !== v.elm) afterInsert(v)
+ if (ov.elm !== v.elm) {
+ afterInsert(v)
+ } else {
+ afterPostpatch(v)
+ }
}
destroy = { _ ->
vnode = null
@@ -160,6 +215,12 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
return hooks
}
+ protected fun setInternalEventListener(block: SnOn<Widget>.() -> Unit): Widget {
+ internalListeners.add(block)
+ refresh()
+ return this
+ }
+
@Suppress("UNCHECKED_CAST")
open fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Widget {
listeners.add(block as SnOn<Widget>.() -> Unit)
@@ -228,9 +289,15 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
return this
}
+ protected open fun afterCreate(node: VNode) {
+ }
+
protected open fun afterInsert(node: VNode) {
}
+ protected open fun afterPostpatch(node: VNode) {
+ }
+
protected open fun afterDestroy() {
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt b/src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt
new file mode 100644
index 00000000..605e1e2e
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt
@@ -0,0 +1,15 @@
+package pl.treksoft.kvision.data
+
+import kotlin.properties.ObservableProperty
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+
+open class DataComponent {
+ var container: DataUpdatable? = null
+
+ fun <T> obs(initialValue: T): ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
+ override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
+ container?.update()
+ }
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt b/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt
new file mode 100644
index 00000000..3b6d3aa8
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt
@@ -0,0 +1,60 @@
+package pl.treksoft.kvision.data
+
+import com.github.snabbdom.VNode
+import com.lightningkite.kotlin.observable.list.ObservableList
+import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.core.Widget
+import pl.treksoft.kvision.panel.VPanel
+
+class DataContainer<M : DataComponent, C : Widget>(val model: ObservableList<M>,
+ private val binding: (M, Int) -> C,
+ private val child: Container = VPanel()) :
+ Widget(setOf()), Container, DataUpdatable {
+
+ override var visible
+ get() = child.visible
+ set(value) {
+ child.visible = value
+ }
+
+ init {
+ child.parent = this
+ model.onUpdate += { _ ->
+ update()
+ }
+ update()
+ }
+
+ override fun add(child: Widget): Container {
+ return this.child.add(child)
+ }
+
+ override fun addAll(children: List<Widget>): Container {
+ return this.child.addAll(children)
+ }
+
+ override fun remove(child: Widget): Container {
+ return this.child.remove(child)
+ }
+
+ override fun removeAll(): Container {
+ return this.child.removeAll()
+ }
+
+ override fun getChildren(): List<Widget> {
+ return this.child.getChildren()
+ }
+
+ override fun renderVNode(): VNode {
+ return this.child.renderVNode()
+ }
+
+ override fun update() {
+ model.forEach { it.container = this }
+ singleRender {
+ child.removeAll()
+ child.addAll(model.mapIndexed { index, m -> binding(m, index) })
+ }
+ }
+
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt b/src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt
new file mode 100644
index 00000000..5f9b7563
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt
@@ -0,0 +1,5 @@
+package pl.treksoft.kvision.data
+
+interface DataUpdatable {
+ fun update()
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
index 92f06591..1ba20211 100644
--- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
@@ -1,7 +1,7 @@
package pl.treksoft.kvision.dropdown
import com.github.snabbdom.VNode
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.ResString
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.html.BUTTONSTYLE
@@ -23,7 +23,7 @@ enum class DD(val type: String) {
open class DropDown(text: String, elements: List<StringPair>? = null, icon: String? = null,
style: BUTTONSTYLE = BUTTONSTYLE.DEFAULT, disabled: Boolean = false, image: ResString? = null,
- dropup: Boolean = false, classes: Set<String> = setOf()) : Container(classes) {
+ dropup: Boolean = false, classes: Set<String> = setOf()) : SimplePanel(classes) {
var text
get() = button.text
set(value) {
@@ -93,12 +93,12 @@ open class DropDown(text: String, elements: List<StringPair>? = null, icon: Stri
var counter = 0
}
- override fun add(child: Widget): Container {
+ override fun add(child: Widget): SimplePanel {
list.add(child)
return this
}
- override fun addAll(children: List<Widget>): Container {
+ override fun addAll(children: List<Widget>): SimplePanel {
list.addAll(children)
return this
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/AbstractText.kt b/src/main/kotlin/pl/treksoft/kvision/form/AbstractText.kt
index 98619dbc..dfa4233b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/AbstractText.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/AbstractText.kt
@@ -1,11 +1,11 @@
package pl.treksoft.kvision.form
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.snabbdom.SnOn
abstract class AbstractText(label: String? = null, rich: Boolean = false) :
- Container(setOf("form-group")), StringFormField {
+ SimplePanel(setOf("form-group")), StringFormField {
override var value
get() = input.value
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/AbstractTextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/AbstractTextInput.kt
index 017e7fef..82846012 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/AbstractTextInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/AbstractTextInput.kt
@@ -1,16 +1,25 @@
package pl.treksoft.kvision.form
-import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.snabbdom.StringBoolPair
import pl.treksoft.kvision.snabbdom.StringPair
abstract class AbstractTextInput(placeholder: String? = null,
- override var value: String? = null, name: String? = null, maxlength: Int? = null,
- disabled: Boolean = false, id: String? = null,
- classes: Set<String> = setOf()) : Widget(classes + "form-control"), StringFormField {
+ override var value: String? = null, name: String? = null, maxlength: Int? = null,
+ disabled: Boolean = false, id: String? = null,
+ classes: Set<String> = setOf()) : Widget(classes + "form-control"), StringFormField {
init {
this.id = id
+ this.setInternalEventListener {
+ input = {
+ val v = getElementJQuery()?.`val`() as String?
+ if (v != null && v.isNotEmpty()) {
+ value = v
+ } else {
+ value = null
+ }
+ }
+ }
}
@Suppress("LeakingThis")
@@ -90,15 +99,4 @@ abstract class AbstractTextInput(placeholder: String? = null,
}
return sn
}
-
- override fun afterInsert(node: VNode) {
- this.getElementJQuery()?.on("input", { _, _ ->
- val v = getElementJQuery()?.`val`() as String?
- if (v != null && v.isNotEmpty()) {
- value = v
- } else {
- value = null
- }
- })
- }
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/CheckBox.kt b/src/main/kotlin/pl/treksoft/kvision/form/CheckBox.kt
index 325c1982..65941495 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/CheckBox.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/CheckBox.kt
@@ -1,6 +1,6 @@
package pl.treksoft.kvision.form
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.snabbdom.SnOn
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -16,7 +16,7 @@ enum class CHECKBOXSTYLE(val className: String) {
open class CheckBox(value: Boolean = false, name: String? = null, style: CHECKBOXSTYLE? = null,
circled: Boolean = false, inline: Boolean = false, disabled: Boolean = false,
- label: String? = null, rich: Boolean = false) : Container(setOf("checkbox")), BoolFormField {
+ label: String? = null, rich: Boolean = false) : SimplePanel(setOf("checkbox")), BoolFormField {
override var value
get() = input.value
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/CheckInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/CheckInput.kt
index 131793b8..07008ddd 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/CheckInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/CheckInput.kt
@@ -17,6 +17,16 @@ open class CheckInput(type: CHECKINPUTTYPE = CHECKINPUTTYPE.CHECKBOX, override v
init {
this.id = id
+ this.setInternalEventListener {
+ click = {
+ val v = getElementJQuery()?.prop("checked") as Boolean?
+ value = (v == true)
+ }
+ change = {
+ val v = getElementJQuery()?.prop("checked") as Boolean?
+ value = (v == true)
+ }
+ }
}
@Suppress("LeakingThis")
@@ -83,15 +93,17 @@ open class CheckInput(type: CHECKINPUTTYPE = CHECKINPUTTYPE.CHECKBOX, override v
}
override fun afterInsert(node: VNode) {
- this.getElementJQuery()?.on("change", { _, _ ->
- val v = getElementJQuery()?.prop("checked") as Boolean?
- value = (v == true)
- true
- })
- this.getElementJQuery()?.on("click", { _, _ ->
- val v = getElementJQuery()?.prop("checked") as Boolean?
- value = (v == true)
- true
- })
+ refreshCheckedState()
+ }
+
+ override fun afterPostpatch(node: VNode) {
+ refreshCheckedState()
+ }
+
+ private fun refreshCheckedState() {
+ val v = getElementJQuery()?.prop("checked") as Boolean?
+ if (this.value != v) {
+ getElementJQuery()?.prop("checked", this.value)
+ }
}
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/Radio.kt b/src/main/kotlin/pl/treksoft/kvision/form/Radio.kt
index eebbe65a..66c2d75c 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/Radio.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/Radio.kt
@@ -1,6 +1,6 @@
package pl.treksoft.kvision.form
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.snabbdom.SnOn
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -16,7 +16,7 @@ enum class RADIOSTYLE(val className: String) {
open class Radio(value: Boolean = false, extraValue: String? = null, name: String? = null, style: RADIOSTYLE? = null,
squared: Boolean = false, inline: Boolean = false, disabled: Boolean = false,
- label: String? = null, rich: Boolean = false) : Container(), BoolFormField {
+ label: String? = null, rich: Boolean = false) : SimplePanel(), BoolFormField {
override var value
get() = input.value
diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt
index dc93d0e7..f103323b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt
@@ -1,12 +1,12 @@
package pl.treksoft.kvision.html
import com.github.snabbdom.VNode
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.ResString
import pl.treksoft.kvision.snabbdom.StringPair
open class Link(label: String, url: String, icon: String? = null, image: ResString? = null,
- classes: Set<String> = setOf()) : Container(classes) {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
private var label = label
set(value) {
field = value
diff --git a/src/main/kotlin/pl/treksoft/kvision/html/List.kt b/src/main/kotlin/pl/treksoft/kvision/html/List.kt
index 9bac3f41..40ebc50b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/html/List.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/html/List.kt
@@ -2,7 +2,7 @@ package pl.treksoft.kvision.html
import com.github.snabbdom.VNode
import com.github.snabbdom.h
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.KVManager
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -16,7 +16,7 @@ enum class LIST(val tagName: String) {
}
open class ListTag(type: LIST, elements: List<String>? = null, rich: Boolean = false,
- classes: Set<String> = setOf()) : Container(classes) {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
var type = type
set(value) {
field = value
diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt
index 70725d97..71856627 100644
--- a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt
@@ -1,7 +1,7 @@
package pl.treksoft.kvision.html
import com.github.snabbdom.VNode
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.KVManager
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -50,7 +50,7 @@ enum class ALIGN(val className: String) {
}
open class Tag(type: TAG, text: String? = null, rich: Boolean = false, align: ALIGN? = null,
- classes: Set<String> = setOf()) : Container(classes) {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
var type = type
set(value) {
field = value
diff --git a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt
index 94796326..a4e14d5c 100644
--- a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt
@@ -1,7 +1,7 @@
package pl.treksoft.kvision.modal
import com.github.snabbdom.VNode
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.Root
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.helpers.CloseIcon
@@ -20,7 +20,7 @@ enum class MODALSIZE(val className: String) {
@Suppress("TooManyFunctions")
open class Modal(caption: String? = null, closeButton: Boolean = true,
size: MODALSIZE? = null, animation: Boolean = true, private val escape: Boolean = true,
- classes: Set<String> = setOf()) : Container(classes) {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
private var caption
get() = captionTag.text
set(value) {
@@ -45,17 +45,17 @@ open class Modal(caption: String? = null, closeButton: Boolean = true,
}
private val dialog = ModalDialog(size)
- private val header = Container(setOf("modal-header"))
+ private val header = SimplePanel(setOf("modal-header"))
protected val closeIcon = CloseIcon()
private val captionTag = Tag(TAG.H4, caption, classes = setOf("modal-title"))
- protected val body = Container(setOf("modal-body"))
- private val footer = Container(setOf("modal-footer"))
+ protected val body = SimplePanel(setOf("modal-body"))
+ private val footer = SimplePanel(setOf("modal-footer"))
init {
this.hide()
this.role = "dialog"
this.addInternal(dialog)
- val content = Container(setOf("modal-content"))
+ val content = SimplePanel(setOf("modal-content"))
dialog.role = "document"
dialog.add(content)
closeIcon.visible = closeButton
@@ -87,12 +87,12 @@ open class Modal(caption: String? = null, closeButton: Boolean = true,
}
}
- override fun add(child: Widget): Container {
+ override fun add(child: Widget): SimplePanel {
body.add(child)
return this
}
- override fun addAll(children: List<Widget>): Container {
+ override fun addAll(children: List<Widget>): SimplePanel {
body.addAll(children)
return this
}
@@ -171,7 +171,7 @@ open class Modal(caption: String? = null, closeButton: Boolean = true,
}
}
-open class ModalDialog(size: MODALSIZE?) : Container(setOf("modal-dialog")) {
+open class ModalDialog(size: MODALSIZE?) : SimplePanel(setOf("modal-dialog")) {
var size = size
set(value) {
field = value
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt
index 6d86727c..6e037c28 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt
@@ -1,6 +1,5 @@
package pl.treksoft.kvision.panel
-import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.Widget
enum class SIDE {
@@ -11,7 +10,7 @@ enum class SIDE {
DOWN
}
-open class DockPanel(classes: Set<String> = setOf()) : Container(classes = classes) {
+open class DockPanel(classes: Set<String> = setOf()) : SimplePanel(classes = classes) {
protected var left: Widget? = null
protected var center: Widget? = null
protected var right: Widget? = null
@@ -59,16 +58,16 @@ open class DockPanel(classes: Set<String> = setOf()) : Container(classes = class
return this
}
- override fun add(child: Widget): Container {
+ override fun add(child: Widget): DockPanel {
return this.add(child, SIDE.CENTER)
}
- override fun addAll(children: List<Widget>): Container {
+ override fun addAll(children: List<Widget>): DockPanel {
children.forEach { this.add(it) }
return this
}
- override fun remove(child: Widget): Container {
+ override fun remove(child: Widget): DockPanel {
if (child == left) removeAt(SIDE.LEFT)
if (child == center) removeAt(SIDE.CENTER)
if (child == right) removeAt(SIDE.RIGHT)
@@ -77,7 +76,7 @@ open class DockPanel(classes: Set<String> = setOf()) : Container(classes = class
return this
}
- open fun removeAt(position: SIDE): Container {
+ open fun removeAt(position: SIDE): DockPanel {
when (position) {
SIDE.UP -> {
up?.let { mainContainer.remove(it) }
@@ -103,7 +102,7 @@ open class DockPanel(classes: Set<String> = setOf()) : Container(classes = class
return this
}
- override fun removeAll(): Container {
+ override fun removeAll(): DockPanel {
removeAt(SIDE.LEFT)
removeAt(SIDE.CENTER)
removeAt(SIDE.RIGHT)
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt
index 10483a8d..6b6e11fb 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt
@@ -1,6 +1,5 @@
package pl.treksoft.kvision.panel
-import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.core.WidgetWrapper
import pl.treksoft.kvision.snabbdom.StringPair
@@ -46,7 +45,7 @@ enum class FLEXALIGNCONTENT(val alignContent: String) {
open class FlexPanel(direction: FLEXDIR? = null, wrap: FLEXWRAP? = null, justify: FLEXJUSTIFY? = null,
alignItems: FLEXALIGNITEMS? = null, alignContent: FLEXALIGNCONTENT? = null,
- classes: Set<String> = setOf()) : Container(classes) {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
var direction = direction
set(value) {
field = value
@@ -75,20 +74,21 @@ open class FlexPanel(direction: FLEXDIR? = null, wrap: FLEXWRAP? = null, justify
@Suppress("LongParameterList")
fun add(child: Widget, order: Int? = null, grow: Int? = null, shrink: Int? = null,
- basis: Int? = null, alignSelf: FLEXALIGNITEMS? = null, classes: Set<String> = setOf()): Container {
- return addInternal(FlexWrapper(child, order, grow, shrink, basis, alignSelf, classes))
+ basis: Int? = null, alignSelf: FLEXALIGNITEMS? = null, classes: Set<String> = setOf()): FlexPanel {
+ addInternal(FlexWrapper(child, order, grow, shrink, basis, alignSelf, classes))
+ return this
}
- override fun add(child: Widget): Container {
+ override fun add(child: Widget): FlexPanel {
return add(child, null)
}
- override fun addAll(children: List<Widget>): Container {
+ override fun addAll(children: List<Widget>): FlexPanel {
children.forEach { add(it, null) }
return this
}
- override fun remove(child: Widget): Container {
+ override fun remove(child: Widget): FlexPanel {
children.find { (it as FlexWrapper).delegate == child }?.let {
super.remove(it)
it.dispose()
@@ -96,7 +96,7 @@ open class FlexPanel(direction: FLEXDIR? = null, wrap: FLEXWRAP? = null, justify
return this
}
- override fun removeAll(): Container {
+ override fun removeAll(): FlexPanel {
children.map {
it.clearParent()
it.dispose()
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt
index 44ba509f..cac5c79b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt
@@ -1,6 +1,5 @@
package pl.treksoft.kvision.panel
-import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.core.WidgetWrapper
import pl.treksoft.kvision.snabbdom.StringPair
@@ -50,7 +49,7 @@ open class GridPanel(autoColumns: String? = null, autoRows: String? = null, auto
templateColumns: String? = null, templateRows: String? = null, templateAreas: List<String>? = null,
columnGap: Int? = null, rowGap: Int? = null, justifyItems: GRIDJUSTIFY? = null,
alignItems: GRIDALIGN? = null, justifyContent: GRIDJUSTIFYCONTENT? = null,
- alignContent: GRIDALIGNCONTENT? = null, classes: Set<String> = setOf()) : Container(classes) {
+ alignContent: GRIDALIGNCONTENT? = null, classes: Set<String> = setOf()) : SimplePanel(classes) {
var autoColumns = autoColumns
set(value) {
field = value
@@ -115,21 +114,21 @@ open class GridPanel(autoColumns: String? = null, autoRows: String? = null, auto
@Suppress("LongParameterList")
fun add(child: Widget, columnStart: Int? = null, rowStart: Int? = null,
columnEnd: String? = null, rowEnd: String? = null, area: String? = null, justifySelf: GRIDJUSTIFY? = null,
- alignSelf: GRIDALIGN? = null, classes: Set<String> = setOf()): Container {
- return addInternal(GridWrapper(child, columnStart, rowStart, columnEnd, rowEnd, area, justifySelf,
- alignSelf, classes))
+ alignSelf: GRIDALIGN? = null, classes: Set<String> = setOf()): GridPanel {
+ addInternal(GridWrapper(child, columnStart, rowStart, columnEnd, rowEnd, area, justifySelf, alignSelf, classes))
+ return this
}
- override fun add(child: Widget): Container {
+ override fun add(child: Widget): GridPanel {
return add(child, null, null)
}
- override fun addAll(children: List<Widget>): Container {
+ override fun addAll(children: List<Widget>): GridPanel {
children.forEach { add(it, null, null) }
return this
}
- override fun remove(child: Widget): Container {
+ override fun remove(child: Widget): GridPanel {
children.find { (it as GridWrapper).delegate == child }?.let {
super.remove(it)
it.dispose()
@@ -137,7 +136,7 @@ open class GridPanel(autoColumns: String? = null, autoRows: String? = null, auto
return this
}
- override fun removeAll(): Container {
+ override fun removeAll(): GridPanel {
children.map {
it.clearParent()
it.dispose()
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt
index 17b3803f..3587ea8e 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt
@@ -1,6 +1,5 @@
package pl.treksoft.kvision.panel
-import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.core.WidgetWrapper
import pl.treksoft.kvision.html.ALIGN
@@ -20,7 +19,7 @@ internal data class WidgetParam(val widget: Widget, val size: Int, val offset: I
open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD,
private var rows: Int = 0, private var cols: Int = 0, align: ALIGN? = null,
- classes: Set<String> = setOf()) : Container(classes) {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
protected var align = align
set(value) {
field = value
@@ -30,7 +29,7 @@ open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD,
internal val map = mutableMapOf<Int, MutableMap<Int, WidgetParam>>()
private var auto: Boolean = true
- open fun add(child: Widget, row: Int, col: Int, size: Int = 0, offset: Int = 0): Container {
+ open fun add(child: Widget, row: Int, col: Int, size: Int = 0, offset: Int = 0): ResponsiveGridPanel {
val cRow = if (row < 0) 0 else row
val cCol = if (col < 0) 0 else col
if (row > rows - 1) rows = cRow + 1
@@ -41,17 +40,17 @@ open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD,
return this
}
- override fun add(child: Widget): Container {
+ override fun add(child: Widget): ResponsiveGridPanel {
return this.add(child, 0, this.cols)
}
- override fun addAll(children: List<Widget>): Container {
+ override fun addAll(children: List<Widget>): ResponsiveGridPanel {
children.forEach { this.add(it) }
return this
}
@Suppress("NestedBlockDepth")
- override fun remove(child: Widget): Container {
+ override fun remove(child: Widget): ResponsiveGridPanel {
for (i in 0 until rows) {
val row = map[i]
if (row != null) {
@@ -67,7 +66,7 @@ open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD,
return this
}
- open fun removeAt(row: Int, col: Int): Container {
+ open fun removeAt(row: Int, col: Int): ResponsiveGridPanel {
map[row]?.remove(col)
refreshRowContainers()
return this
@@ -75,38 +74,40 @@ open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD,
@Suppress("ComplexMethod", "NestedBlockDepth")
protected open fun refreshRowContainers() {
- clearRowContainers()
- val num = MAX_COLUMNS / cols
- for (i in 0 until rows) {
- val rowContainer = Container(setOf("row"))
- val row = map[i]
- if (row != null) {
- for (j in 0 until cols) {
- val wp = row[j]
- if (auto) {
- val widget = wp?.widget?.let {
- WidgetWrapper(it, setOf("col-" + gridsize.size + "-" + num))
- } ?: Tag(TAG.DIV, classes = setOf("col-" + gridsize.size + "-" + num))
- align?.let {
- widget.addCssClass(it.className)
- }
- rowContainer.add(widget)
- } else {
- if (wp != null) {
- val s = if (wp.size > 0) wp.size else num
- val widget = WidgetWrapper(wp.widget, setOf("col-" + gridsize.size + "-" + s))
- if (wp.offset > 0) {
- widget.addCssClass("col-" + gridsize.size + "-offset-" + wp.offset)
- }
+ singleRender {
+ clearRowContainers()
+ val num = MAX_COLUMNS / cols
+ for (i in 0 until rows) {
+ val rowContainer = SimplePanel(setOf("row"))
+ val row = map[i]
+ if (row != null) {
+ for (j in 0 until cols) {
+ val wp = row[j]
+ if (auto) {
+ val widget = wp?.widget?.let {
+ WidgetWrapper(it, setOf("col-" + gridsize.size + "-" + num))
+ } ?: Tag(TAG.DIV, classes = setOf("col-" + gridsize.size + "-" + num))
align?.let {
widget.addCssClass(it.className)
}
rowContainer.add(widget)
+ } else {
+ if (wp != null) {
+ val s = if (wp.size > 0) wp.size else num
+ val widget = WidgetWrapper(wp.widget, setOf("col-" + gridsize.size + "-" + s))
+ if (wp.offset > 0) {
+ widget.addCssClass("col-" + gridsize.size + "-offset-" + wp.offset)
+ }
+ align?.let {
+ widget.addCssClass(it.className)
+ }
+ rowContainer.add(widget)
+ }
}
}
}
+ addInternal(rowContainer)
}
- addInternal(rowContainer)
}
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt
new file mode 100644
index 00000000..e9cf503b
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt
@@ -0,0 +1,59 @@
+package pl.treksoft.kvision.panel
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.core.Widget
+
+open class SimplePanel(classes: Set<String> = setOf()) : Widget(classes), Container {
+ internal val children: MutableList<Widget> = mutableListOf()
+
+ override fun render(): VNode {
+ return kvh("div", childrenVNodes())
+ }
+
+ protected open fun childrenVNodes(): Array<VNode> {
+ return children.filter { it.visible }.map { it.renderVNode() }.toTypedArray()
+ }
+
+ protected fun addInternal(child: Widget): SimplePanel {
+ children.add(child)
+ child.parent = this
+ refresh()
+ return this
+ }
+
+ override fun add(child: Widget): SimplePanel {
+ return addInternal(child)
+ }
+
+ override fun addAll(children: List<Widget>): SimplePanel {
+ this.children.addAll(children)
+ children.map { it.parent = this }
+ refresh()
+ return this
+ }
+
+ override fun remove(child: Widget): SimplePanel {
+ if (children.remove(child)) {
+ child.clearParent()
+ refresh()
+ }
+ return this
+ }
+
+ override fun removeAll(): SimplePanel {
+ children.map { it.clearParent() }
+ children.clear()
+ refresh()
+ return this
+ }
+
+ override fun getChildren(): List<Widget> {
+ return ArrayList(children)
+ }
+
+ override fun dispose() {
+ children.forEach { it.dispose() }
+ removeAll()
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt
index 03740222..02811639 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt
@@ -3,7 +3,6 @@ package pl.treksoft.kvision.panel
import com.github.snabbdom.VNode
import pl.treksoft.jquery.JQuery
import pl.treksoft.jquery.JQueryEventObject
-import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.UNIT
import pl.treksoft.kvision.html.TAG
import pl.treksoft.kvision.html.Tag
@@ -15,7 +14,7 @@ enum class DIRECTION(val dir: String) {
}
open class SplitPanel(private val direction: DIRECTION = DIRECTION.VERTICAL,
- classes: Set<String> = setOf()) : Container(classes + ("splitpanel-" + direction.dir)) {
+ classes: Set<String> = setOf()) : SimplePanel(classes + ("splitpanel-" + direction.dir)) {
@Suppress("LeakingThis")
internal val splitter = Splitter(this, direction)
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
index c5162c0a..e8975dce 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt
@@ -1,11 +1,10 @@
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) {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
var activeIndex = -1
set(value) {
field = value
@@ -20,27 +19,27 @@ open class StackPanel(private val activateLast: Boolean = true,
}
}
- override fun add(child: Widget): Container {
+ override fun add(child: Widget): StackPanel {
super.add(child)
if (activateLast) activeIndex = children.size - 1
else if (activeIndex == -1) activeIndex = 0
return this
}
- override fun addAll(children: List<Widget>): Container {
+ override fun addAll(children: List<Widget>): StackPanel {
super.addAll(children)
if (activateLast) activeIndex = this.children.size - 1
else if (activeIndex == -1) activeIndex = 0
return this
}
- override fun remove(child: Widget): Container {
+ override fun remove(child: Widget): StackPanel {
super.remove(child)
if (activeIndex > children.size - 1) activeIndex = children.size - 1
return this
}
- override fun removeAll(): Container {
+ override fun removeAll(): StackPanel {
super.removeAll()
if (activeIndex > children.size - 1) activeIndex = children.size - 1
return this
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt
index 817ecaa0..4190dbae 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt
@@ -1,15 +1,12 @@
package pl.treksoft.kvision.panel
-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
-open class TabPanel : Container(setOf()) {
- private var nav = Tag(TAG.UL, classes = setOf("nav", "nav-tabs"))
- private var content = StackPanel(false)
+open class TabPanel : SimplePanel(setOf()) {
var activeIndex
get() = content.activeIndex
set(value) {
@@ -20,9 +17,12 @@ open class TabPanel : Container(setOf()) {
}
}
+ private var nav = Tag(TAG.UL, classes = setOf("nav", "nav-tabs"))
+ private var content = StackPanel(false)
+
init {
- this.add(nav)
- this.add(content)
+ this.addInternal(nav)
+ this.addInternal(content)
}
open fun addTab(title: String, panel: Widget, icon: String? = null,
@@ -52,4 +52,25 @@ open class TabPanel : Container(setOf()) {
activeIndex = content.activeIndex
return this
}
+
+ override fun add(child: Widget): TabPanel {
+ return addTab("", child)
+ }
+
+ override fun addAll(children: List<Widget>): TabPanel {
+ children.forEach { add(it) }
+ return this
+ }
+
+ override fun remove(child: Widget): TabPanel {
+ val index = content.children.indexOf(child)
+ return removeTab(index)
+ }
+
+ override fun removeAll(): TabPanel {
+ content.removeAll()
+ nav.removeAll()
+ refresh()
+ return this
+ }
}
diff --git a/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt
index c39aeb75..a169ace6 100644
--- a/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt
+++ b/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt
@@ -1,6 +1,6 @@
package test.pl.treksoft.kvision.core
-import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.Root
import pl.treksoft.kvision.core.Widget
import test.pl.treksoft.kvision.DomSpec
@@ -14,7 +14,7 @@ class ContainerSpec : DomSpec {
fun add() {
run {
val root = Root("test")
- val container = Container()
+ val container = SimplePanel()
val child1 = Widget()
child1.id = "child1"
val child2 = Widget()
@@ -24,7 +24,7 @@ class ContainerSpec : DomSpec {
root.add(container)
val elem1 = document.getElementById("child1")
val elem2 = document.getElementById("child2")
- assertTrue("Container renders children") { elem1 != null && elem2 != null }
+ assertTrue("SimplePanel renders children") { elem1 != null && elem2 != null }
}
}
@@ -32,7 +32,7 @@ class ContainerSpec : DomSpec {
fun addAll() {
run {
val root = Root("test")
- val container = Container()
+ val container = SimplePanel()
val child1 = Widget()
child1.id = "child1"
val child2 = Widget()
@@ -41,7 +41,7 @@ class ContainerSpec : DomSpec {
root.add(container)
val elem1 = document.getElementById("child1")
val elem2 = document.getElementById("child2")
- assertTrue("Container renders children") { elem1 != null && elem2 != null }
+ assertTrue("SimplePanel renders children") { elem1 != null && elem2 != null }
}
}
@@ -49,7 +49,7 @@ class ContainerSpec : DomSpec {
fun remove() {
run {
val root = Root("test")
- val container = Container()
+ val container = SimplePanel()
val child1 = Widget()
child1.id = "child1"
val child2 = Widget()
@@ -60,7 +60,7 @@ class ContainerSpec : DomSpec {
container.remove(child2)
val elem1 = document.getElementById("child1")
val elem2 = document.getElementById("child2")
- assertTrue("Container renders children") { elem1 != null && elem2 == null }
+ assertTrue("SimplePanel renders children") { elem1 != null && elem2 == null }
}
}
@@ -68,7 +68,7 @@ class ContainerSpec : DomSpec {
fun removeAll() {
run {
val root = Root("test")
- val container = Container()
+ val container = SimplePanel()
val child1 = Widget()
child1.id = "child1"
val child2 = Widget()
@@ -86,7 +86,7 @@ class ContainerSpec : DomSpec {
fun getChildren() {
run {
val root = Root("test")
- val container = Container()
+ val container = SimplePanel()
val child1 = Widget()
child1.id = "child1"
val child2 = Widget()
diff --git a/src/test/kotlin/test/pl/treksoft/kvision/core/KVManagerSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/core/KVManagerSpec.kt
index f47e1900..307ebd67 100644
--- a/src/test/kotlin/test/pl/treksoft/kvision/core/KVManagerSpec.kt
+++ b/src/test/kotlin/test/pl/treksoft/kvision/core/KVManagerSpec.kt
@@ -20,8 +20,8 @@ class KVManagerSpec : DomSpec {
style = snStyle(listOf("fontWeight" to "bold", "fontStyle" to "italic"))
})
KVManager.patch("test", vnode)
- assertTrue("Original container should not exist") { document.getElementById("test") == null }
- assertTrue("New container should exist") { document.getElementById("test_new") != null }
+ assertTrue("Original child should not exist") { document.getElementById("test") == null }
+ assertTrue("New child should exist") { document.getElementById("test_new") != null }
}
}
@@ -38,9 +38,9 @@ class KVManagerSpec : DomSpec {
style = snStyle(listOf("fontWeight" to "bold", "fontStyle" to "italic"))
})
KVManager.patch(vnode2, vnode3)
- assertTrue("First container should not exist") { document.getElementById("test") == null }
- assertTrue("Second container should not exist") { document.getElementById("test2") == null }
- assertTrue("Third container should exist") { document.getElementById("test3") != null }
+ assertTrue("First child should not exist") { document.getElementById("test") == null }
+ assertTrue("Second child should not exist") { document.getElementById("test2") == null }
+ assertTrue("Third child should exist") { document.getElementById("test3") != null }
}
}
@@ -49,10 +49,10 @@ class KVManagerSpec : DomSpec {
run {
val node = KVManager.virtualize("<div id=\"virtual\"><p>Virtual node</p></div>")
KVManager.patch("test", node)
- assertTrue("Original container should not exist") { document.getElementById("test") == null }
+ assertTrue("Original child should not exist") { document.getElementById("test") == null }
val v = document.getElementById("virtual")
- assertTrue("New container should exist") { v != null }
- assertTrue("New container should have one child") { v?.children?.length == 1 }
+ assertTrue("New child should exist") { v != null }
+ assertTrue("New child should have one child") { v?.children?.length == 1 }
}
}
}
diff --git a/src/test/kotlin/test/pl/treksoft/kvision/core/RootSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/core/RootSpec.kt
index 6407dbc3..9895c16d 100644
--- a/src/test/kotlin/test/pl/treksoft/kvision/core/RootSpec.kt
+++ b/src/test/kotlin/test/pl/treksoft/kvision/core/RootSpec.kt
@@ -14,7 +14,7 @@ class RootSpec : DomSpec {
run {
Root("test")
val rootElem = document.getElementById("test")
- assertTrue("Standard root container has correct css class") { rootElem?.className == "container-fluid" }
+ assertTrue("Standard root child has correct css class") { rootElem?.className == "container-fluid" }
}
}
@@ -23,7 +23,7 @@ class RootSpec : DomSpec {
run {
Root("test", fixed = true)
val rootElem = document.getElementById("test")
- assertTrue("Fluid root container has correct css class") { rootElem?.className == "container" }
+ assertTrue("Fluid root child has correct css class") { rootElem?.className == "container" }
}
}