From 99dcb8e434d7e0ccf5dada379c1b03e894e6aa82 Mon Sep 17 00:00:00 2001 From: Robert Jaros Date: Wed, 26 Feb 2020 13:30:23 +0100 Subject: Major changes in the event handling architecture. Support for multiple event handlers. --- .../pl/treksoft/kvision/form/time/DateTime.kt | 13 ++- .../treksoft/kvision/form/select/SelectRemote.kt | 13 ++- .../kvision/form/select/SelectRemoteInput.kt | 3 +- .../pl/treksoft/kvision/form/select/Select.kt | 13 ++- .../pl/treksoft/kvision/form/select/SelectInput.kt | 3 +- .../pl/treksoft/kvision/form/spinner/Spinner.kt | 13 ++- .../treksoft/kvision/form/spinner/SpinnerInput.kt | 3 +- .../pl/treksoft/kvision/form/upload/Upload.kt | 13 ++- .../pl/treksoft/kvision/dropdown/DropDown.kt | 3 +- src/main/kotlin/pl/treksoft/kvision/core/Widget.kt | 114 ++++++++------------- .../pl/treksoft/kvision/form/check/CheckBox.kt | 18 ++-- .../pl/treksoft/kvision/form/check/CheckInput.kt | 3 +- .../kotlin/pl/treksoft/kvision/form/check/Radio.kt | 18 ++-- .../kotlin/pl/treksoft/kvision/form/range/Range.kt | 13 ++- .../pl/treksoft/kvision/form/range/RangeInput.kt | 3 +- .../treksoft/kvision/form/select/SimpleSelect.kt | 13 ++- .../kvision/form/select/SimpleSelectInput.kt | 3 +- .../pl/treksoft/kvision/form/text/AbstractText.kt | 13 ++- .../kvision/form/text/AbstractTextInput.kt | 3 +- src/main/kotlin/pl/treksoft/kvision/panel/Root.kt | 3 +- .../test/pl/treksoft/kvision/core/StyleSpec.kt | 6 +- .../test/pl/treksoft/kvision/core/WidgetSpec.kt | 4 +- 22 files changed, 152 insertions(+), 139 deletions(-) diff --git a/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt index fdf9f95a..4f3f3f48 100644 --- a/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt +++ b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt @@ -217,15 +217,18 @@ open class DateTime( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } diff --git a/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt b/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt index 550de427..e2f84fff 100644 --- a/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt +++ b/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt @@ -187,15 +187,18 @@ open class SelectRemote( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } diff --git a/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt b/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt index 96277728..d6abc0f6 100644 --- a/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt +++ b/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt @@ -29,6 +29,7 @@ import kotlinx.serialization.list import kotlinx.serialization.stringify import org.w3c.dom.get import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.onEvent import pl.treksoft.kvision.remote.CallAgent import pl.treksoft.kvision.remote.HttpMethod import pl.treksoft.kvision.remote.JsonRpcRequest @@ -114,7 +115,7 @@ open class SelectRemoteInput( preserveSelected = ajaxOptions?.preserveSelected ?: true ) if (this.ajaxOptions?.emptyRequest == true) { - this.setInternalEventListener> { + this.onEvent { shownBsSelect = { val input = self.getElementJQuery()?.parent()?.find("input") input?.trigger("keyup", null) diff --git a/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt b/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt index cd8b5817..9f66afd8 100644 --- a/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt +++ b/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt @@ -205,15 +205,18 @@ open class Select( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } diff --git a/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt index fe574fa7..a96e614e 100644 --- a/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt +++ b/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt @@ -28,6 +28,7 @@ import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.core.CssSize 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 @@ -149,7 +150,7 @@ open class SelectInput( init { setChildrenFromOptions() - this.setInternalEventListener { + this.onEvent { change = { val v = getElementJQuery()?.`val`() self.value = v?.let { diff --git a/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt b/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt index 69d9410b..c8b51372 100644 --- a/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt +++ b/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt @@ -201,18 +201,21 @@ open class Spinner( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated( "Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent") ) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } diff --git a/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt b/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt index 3a52fed2..f195234a 100644 --- a/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt +++ b/kvision-modules/kvision-bootstrap-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt @@ -27,6 +27,7 @@ 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 @@ -151,7 +152,7 @@ open class SpinnerInput( ButtonsType.HORIZONTAL -> this.addSurroundingCssClass("kv-spinner-btn-horizontal") } this.surroundingSpan = true - this.setInternalEventListener { + this.onEvent { change = { self.changeValue() } diff --git a/kvision-modules/kvision-bootstrap-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt b/kvision-modules/kvision-bootstrap-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt index 20d836f0..3ba635fd 100644 --- a/kvision-modules/kvision-bootstrap-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt +++ b/kvision-modules/kvision-bootstrap-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt @@ -228,15 +228,18 @@ open class Upload( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } diff --git a/kvision-modules/kvision-bootstrap/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/kvision-modules/kvision-bootstrap/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt index 3fa6cd36..a7f8992a 100644 --- a/kvision-modules/kvision-bootstrap/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt +++ b/kvision-modules/kvision-bootstrap/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt @@ -28,6 +28,7 @@ import pl.treksoft.kvision.core.CssSize import pl.treksoft.kvision.core.ResString import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.onEvent import pl.treksoft.kvision.html.Button import pl.treksoft.kvision.html.ButtonStyle import pl.treksoft.kvision.html.ButtonType @@ -355,7 +356,7 @@ internal class DropDownButton( init { this.id = id if (!forNavbar && !forDropDown) this.role = "button" - setInternalEventListener { + onEvent { click = { e -> if (parent?.parent is ContextMenu) { e.asDynamic().dropDownCM = true diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt index 6b98664f..e1871c6c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt @@ -57,8 +57,8 @@ open class Widget(classes: Set = setOf()) : StyledComponent(), Component internal val classes = classes.toMutableSet() internal val surroundingClasses: MutableSet = mutableSetOf() internal val attributes: MutableMap = mutableMapOf() - internal val internalListeners = mutableListOf.() -> Unit>() - internal val listeners = mutableListOf.() -> Unit>() + internal val listenersMap = mutableMapOf.() -> Unit>>() + internal var listenerCounter: Int = 0 override var parent: Container? = null @@ -259,59 +259,14 @@ open class Widget(classes: Set = setOf()) : StyledComponent(), Component * Returns list of event handlers in the form of a Snabbdom *On* object. * @return list of event handlers */ - @Suppress("ComplexMethod") protected open fun getSnOn(): com.github.snabbdom.On? { - return if (internalListeners.size > 0 || listeners.size > 0) { - val internalHandlers = on(this) - internalListeners.forEach { l -> (internalHandlers::apply)(l) } + return if (listenersMap.isNotEmpty()) { val handlers = on(eventTarget ?: this) - listeners.forEach { l -> (handlers::apply)(l) } - if (internalHandlers.click != null) { - if (handlers.click == null) { - handlers.click = internalHandlers.click + listenersMap.filter { it.value.isNotEmpty() }.forEach { (event, listeners) -> + handlers.asDynamic()[event] = if (listeners.size == 1) { + listeners.values.first() } 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) - } - } - } - if (internalHandlers.shownBsSelect != null) { - if (handlers.shownBsSelect == null) { - handlers.shownBsSelect = internalHandlers.shownBsSelect - } else { - val intc = internalHandlers.shownBsSelect - val c = handlers.shownBsSelect - handlers.shownBsSelect = { e -> - intc?.invoke(e) - c?.invoke(e) - } + listeners.map { arrayOf(it.value) }.toTypedArray() } } handlers @@ -346,22 +301,11 @@ open class Widget(classes: Set = setOf()) : StyledComponent(), Component return hooks } - /** - * @suppress - * Internal function - */ - @Suppress("UNCHECKED_CAST") - protected fun setInternalEventListener(block: SnOn.() -> Unit): Widget { - internalListeners.add(block as SnOn.() -> Unit) - refresh() - return this - } - /** * Sets an event listener for current widget, keeping the actual type of component. * @param T widget type * @param block event handler - * @return current widget + * @return id of the handler * * Example: * @@ -373,16 +317,28 @@ open class Widget(classes: Set = setOf()) : StyledComponent(), Component * } */ @Suppress("UNCHECKED_CAST") - open fun setEventListener(block: SnOn.() -> Unit): Widget { - listeners.add(block as SnOn.() -> Unit) + open fun setEventListener(block: SnOn.() -> Unit): Int { + val handlerCounter = listenerCounter++ + val blockAsWidget = block as SnOn.() -> Unit + val handlers = js("{}") as SnOn + (handlers::apply)(blockAsWidget) + for (key: String in js("Object").keys(handlers)) { + val handler = handlers.asDynamic()[key] + val map = listenersMap[key] + if (map != null) { + map[handlerCounter] = handler + } else { + listenersMap[key] = mutableMapOf(handlerCounter to handler) + } + } refresh() - return this + return handlerCounter } /** * Sets an event listener for current widget. * @param block event handler - * @return current widget + * @return id of the handler * * Example: * @@ -393,9 +349,21 @@ open class Widget(classes: Set = setOf()) : StyledComponent(), Component * } * } */ - @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - open fun setEventListener(block: SnOn.() -> Unit): Widget { - listeners.add(block) + @Deprecated( + "Use onEvent extension function instead.", + ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent") + ) + open fun setEventListener(block: SnOn.() -> Unit): Int { + return setEventListener(block) + } + + /** + * Removes event listener from current widget. + * @param id the id of the handler returned by onEvent + * @return current widget + */ + open fun removeEventListener(id: Int): Widget { + listenersMap.forEach { it.value.remove(id) } refresh() return this } @@ -405,7 +373,7 @@ open class Widget(classes: Set = setOf()) : StyledComponent(), Component * @return current widget */ open fun removeEventListeners(): Widget { - listeners.clear() + listenersMap.clear() refresh() return this } @@ -819,6 +787,6 @@ fun Container.widget(classes: Set = setOf(), init: (Widget.() -> Unit)? return widget } -inline fun T.onEvent(noinline block: SnOn.() -> Unit): Widget { +inline fun T.onEvent(noinline block: SnOn.() -> Unit): Int { return this.setEventListener(block) } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt index 8575b09e..7dae0f86 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt @@ -123,15 +123,21 @@ open class CheckBox( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } - @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + @Deprecated( + "Use onEvent extension function instead.", + ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent") + ) + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } 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 f93fd436..b5c3ead0 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt @@ -26,6 +26,7 @@ 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 @@ -52,7 +53,7 @@ abstract class CheckInput( ) : Widget(classes), FormInput { init { - this.setInternalEventListener { + this.onEvent { click = { val v = getElementJQuery()?.prop("checked") as Boolean? self.value = (v == true) diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt index bef7f078..4d8a1607 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt @@ -133,15 +133,21 @@ open class Radio( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } - @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + @Deprecated( + "Use onEvent extension function instead.", + ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent") + ) + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/range/Range.kt b/src/main/kotlin/pl/treksoft/kvision/form/range/Range.kt index ac772d02..a03ce2c8 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/range/Range.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/range/Range.kt @@ -161,18 +161,21 @@ open class Range( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated( "Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent") ) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } 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 dc9ad7d4..b2471411 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/range/RangeInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/range/RangeInput.kt @@ -27,6 +27,7 @@ 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 @@ -97,7 +98,7 @@ open class RangeInput( override var validationStatus: ValidationStatus? by refreshOnUpdate() init { - this.setInternalEventListener { + this.onEvent { change = { self.changeValue() } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelect.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelect.kt index 5b262cef..97e61de3 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelect.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelect.kt @@ -137,15 +137,18 @@ open class SimpleSelect( } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } 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 bc99f514..796f653c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt @@ -25,6 +25,7 @@ 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 @@ -91,7 +92,7 @@ open class SimpleSelectInput( init { setChildrenFromOptions() - this.setInternalEventListener { + this.onEvent { change = { self.changeValue() } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt index 250d142e..c7528cb1 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt @@ -134,15 +134,18 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) : } @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this + override fun setEventListener(block: SnOn.() -> Unit): Int { + return input.setEventListener(block) } @Deprecated("Use onEvent extension function instead.", ReplaceWith("onEvent(block)", "pl.treksoft.kvision.core.onEvent")) - override fun setEventListener(block: SnOn.() -> Unit): Widget { + override fun setEventListener(block: SnOn.() -> Unit): Int { @Suppress("DEPRECATION") - input.setEventListener(block) + return input.setEventListener(block) + } + + override fun removeEventListener(id: Int): Widget { + input.removeEventListener(id) return this } 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 192b33c8..343129f3 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt @@ -25,6 +25,7 @@ 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 @@ -42,7 +43,7 @@ abstract class AbstractTextInput( ) : Widget(classes), FormInput { init { - this.setInternalEventListener { + this.onEvent { 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 b1bb36a8..4b02db5a 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt @@ -29,6 +29,7 @@ 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 @@ -103,7 +104,7 @@ class Root : SimplePanel { fun addContextMenu(contextMenu: Widget) { contextMenus.add(contextMenu) contextMenu.parent = this - this.setInternalEventListener { + this.onEvent { click = { e -> @Suppress("UnsafeCastFromDynamic") if (!e.asDynamic().dropDownCM) contextMenu.hide() diff --git a/src/test/kotlin/test/pl/treksoft/kvision/core/StyleSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/core/StyleSpec.kt index cf7c21b2..cac53e90 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/core/StyleSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/core/StyleSpec.kt @@ -41,7 +41,7 @@ class StyleSpec : DomSpec { widget { style { margin = 2.px - color = Color(Col.SILVER) + color = Color.name(Col.SILVER) overflow = Overflow.SCROLL } } @@ -62,7 +62,7 @@ class StyleSpec : DomSpec { widget { style("customclass") { margin = 2.px - color = Color(Col.SILVER) + color = Color.name(Col.SILVER) overflow = Overflow.SCROLL } } @@ -83,7 +83,7 @@ class StyleSpec : DomSpec { widget { style("customclass") { margin = 2.px - color = Color(Col.SILVER) + color = Color.name(Col.SILVER) overflow = Overflow.SCROLL style("image") { marginTop = 10.px diff --git a/src/test/kotlin/test/pl/treksoft/kvision/core/WidgetSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/core/WidgetSpec.kt index 59f5f8e0..42a07ba8 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/core/WidgetSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/core/WidgetSpec.kt @@ -96,7 +96,7 @@ class WidgetSpec : WSpec { fun setEventListener() { runW { widget, _ -> widget.setEventListener { click = { } } - assertTrue("Element should have an event listener") { widget.listeners.size == 1 } + assertTrue("Element should have an event listener") { widget.listenersMap.size == 1 } } } @@ -105,7 +105,7 @@ class WidgetSpec : WSpec { runW { widget, _ -> widget.setEventListener { click = { } } widget.removeEventListeners() - assertTrue("Element should not have any event listener") { widget.listeners.size == 0 } + assertTrue("Element should not have any event listener") { widget.listenersMap.size == 0 } } } -- cgit