aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2020-02-26 23:12:48 +0100
committerRobert Jaros <rjaros@finn.pl>2020-02-26 23:12:48 +0100
commit450d3d259cd3253f7cda8ab4baffb0a6d070d596 (patch)
tree25ff42e5e9e7d683ce5395fdd7159ed85244b1a3 /src/main
parent94f36f212a60654571728a1f34701d95453efc22 (diff)
downloadkvision-450d3d259cd3253f7cda8ab4baffb0a6d070d596.tar.gz
kvision-450d3d259cd3253f7cda8ab4baffb0a6d070d596.tar.bz2
kvision-450d3d259cd3253f7cda8ab4baffb0a6d070d596.zip
Major changes in the event handling architecture. Support for multiple event handlers.
Diffstat (limited to 'src/main')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Widget.kt43
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/range/RangeInput.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/panel/Root.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt13
7 files changed, 55 insertions, 16 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
index e1871c6c..abff5e37 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
@@ -34,6 +34,7 @@ import pl.treksoft.kvision.i18n.I18n
import pl.treksoft.kvision.i18n.I18n.trans
import pl.treksoft.kvision.panel.Root
import pl.treksoft.kvision.utils.SnOn
+import pl.treksoft.kvision.utils.emptyOn
import pl.treksoft.kvision.utils.hooks
import pl.treksoft.kvision.utils.on
import pl.treksoft.kvision.utils.snAttrs
@@ -57,6 +58,7 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent(), Component
internal val classes = classes.toMutableSet()
internal val surroundingClasses: MutableSet<String> = mutableSetOf()
internal val attributes: MutableMap<String, String> = mutableMapOf()
+ internal val internalListenersMap = mutableMapOf<String, MutableMap<Int, SnOn<Widget>.() -> Unit>>()
internal val listenersMap = mutableMapOf<String, MutableMap<Int, SnOn<Widget>.() -> Unit>>()
internal var listenerCounter: Int = 0
@@ -260,9 +262,19 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent(), Component
* @return list of event handlers
*/
protected open fun getSnOn(): com.github.snabbdom.On? {
- return if (listenersMap.isNotEmpty()) {
- val handlers = on(eventTarget ?: this)
- listenersMap.filter { it.value.isNotEmpty() }.forEach { (event, listeners) ->
+ val map = listenersMap.filter { it.key != "self" && it.value.isNotEmpty() }.toMutableMap()
+ internalListenersMap.filter { it.key != "self" && it.value.isNotEmpty() }
+ .forEach { (event, internalListeners) ->
+ val listeners = map[event]
+ if (listeners != null) {
+ listeners.putAll(internalListeners)
+ } else {
+ map[event] = internalListeners
+ }
+ }
+ return if (map.isNotEmpty()) {
+ val handlers = emptyOn()
+ map.forEach { (event, listeners) ->
handlers.asDynamic()[event] = if (listeners.size == 1) {
listeners.values.first()
} else {
@@ -302,6 +314,29 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent(), Component
}
/**
+ * @suppress
+ * Internal function
+ */
+ @Suppress("UNCHECKED_CAST")
+ protected fun <T : Widget> setInternalEventListener(block: SnOn<T>.() -> Unit): Int {
+ val handlerCounter = listenerCounter++
+ val blockAsWidget = block as SnOn<Widget>.() -> Unit
+ val handlers = on(this)
+ (handlers::apply)(blockAsWidget)
+ for (key: String in js("Object").keys(handlers)) {
+ val handler = handlers.asDynamic()[key]
+ val map = internalListenersMap[key]
+ if (map != null) {
+ map[handlerCounter] = handler
+ } else {
+ internalListenersMap[key] = mutableMapOf(handlerCounter to handler)
+ }
+ }
+ refresh()
+ return handlerCounter
+ }
+
+ /**
* Sets an event listener for current widget, keeping the actual type of component.
* @param T widget type
* @param block event handler
@@ -320,7 +355,7 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent(), Component
open fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Int {
val handlerCounter = listenerCounter++
val blockAsWidget = block as SnOn<Widget>.() -> Unit
- val handlers = js("{}") as SnOn<Widget>
+ val handlers = on(eventTarget ?: this)
(handlers::apply)(blockAsWidget)
for (key: String in js("Object").keys(handlers)) {
val handler = handlers.asDynamic()[key]
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt
index b5c3ead0..f93fd436 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt
@@ -26,7 +26,6 @@ import org.w3c.dom.events.MouseEvent
import pl.treksoft.kvision.core.StringBoolPair
import pl.treksoft.kvision.core.StringPair
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.core.onEvent
import pl.treksoft.kvision.form.FormInput
import pl.treksoft.kvision.form.InputSize
import pl.treksoft.kvision.form.ValidationStatus
@@ -53,7 +52,7 @@ abstract class CheckInput(
) : Widget(classes), FormInput {
init {
- this.onEvent {
+ this.setInternalEventListener<CheckInput> {
click = {
val v = getElementJQuery()?.prop("checked") as Boolean?
self.value = (v == true)
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/range/RangeInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/range/RangeInput.kt
index b2471411..dc9ad7d4 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/range/RangeInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/range/RangeInput.kt
@@ -27,7 +27,6 @@ import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.StringBoolPair
import pl.treksoft.kvision.core.StringPair
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.core.onEvent
import pl.treksoft.kvision.form.FormInput
import pl.treksoft.kvision.form.InputSize
import pl.treksoft.kvision.form.ValidationStatus
@@ -98,7 +97,7 @@ open class RangeInput(
override var validationStatus: ValidationStatus? by refreshOnUpdate()
init {
- this.onEvent {
+ this.setInternalEventListener<RangeInput> {
change = {
self.changeValue()
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt
index 796f653c..bc99f514 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt
@@ -25,7 +25,6 @@ import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.StringBoolPair
import pl.treksoft.kvision.core.StringPair
-import pl.treksoft.kvision.core.onEvent
import pl.treksoft.kvision.form.FormInput
import pl.treksoft.kvision.form.InputSize
import pl.treksoft.kvision.form.ValidationStatus
@@ -92,7 +91,7 @@ open class SimpleSelectInput(
init {
setChildrenFromOptions()
- this.onEvent {
+ this.setInternalEventListener<SimpleSelectInput> {
change = {
self.changeValue()
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt
index 343129f3..192b33c8 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt
@@ -25,7 +25,6 @@ import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.StringBoolPair
import pl.treksoft.kvision.core.StringPair
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.core.onEvent
import pl.treksoft.kvision.form.FormInput
import pl.treksoft.kvision.form.InputSize
import pl.treksoft.kvision.form.ValidationStatus
@@ -43,7 +42,7 @@ abstract class AbstractTextInput(
) : Widget(classes), FormInput {
init {
- this.onEvent {
+ this.setInternalEventListener<AbstractTextInput> {
input = {
self.changeValue()
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt b/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt
index 4b02db5a..b1bb36a8 100644
--- a/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt
@@ -29,7 +29,6 @@ import pl.treksoft.kvision.KVManager
import pl.treksoft.kvision.core.StringBoolPair
import pl.treksoft.kvision.core.Style
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.core.onEvent
import pl.treksoft.kvision.utils.snClasses
import pl.treksoft.kvision.utils.snOpt
import kotlin.browser.document
@@ -104,7 +103,7 @@ class Root : SimplePanel {
fun addContextMenu(contextMenu: Widget) {
contextMenus.add(contextMenu)
contextMenu.parent = this
- this.onEvent {
+ this.setInternalEventListener<Root> {
click = { e ->
@Suppress("UnsafeCastFromDynamic")
if (!e.asDynamic().dropDownCM) contextMenu.hide()
diff --git a/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt b/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt
index 00d7e59a..768ce8aa 100644
--- a/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt
@@ -157,12 +157,21 @@ inline fun snOpt(noinline block: VNodeData.() -> Unit) = (vNodeData()::apply)(bl
* Internal function.
*/
@Suppress("UnsafeCastFromDynamic")
-internal fun on(widget: Widget): SnOn<Widget> {
+internal fun on(target: Widget): SnOn<Widget> {
val obj = js("{}")
- obj["self"] = widget
+ obj["self"] = target
return obj
}
+/**
+ * @suppress
+ * Internal function.
+ */
+@Suppress("UnsafeCastFromDynamic")
+internal fun emptyOn(): SnOn<Widget> {
+ return js("{}")
+}
+
@Suppress("UnsafeCastFromDynamic", "NOTHING_TO_INLINE")
internal inline fun hooks(): Hooks {
return js("{}")