diff options
author | Robert Jaros <rjaros@finn.pl> | 2019-04-24 20:13:17 +0200 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2019-04-24 20:13:17 +0200 |
commit | 833390a649c633892fbc0d9b6e37d6f7913cabb1 (patch) | |
tree | afe334494ef1ab5265ed53d4f48e6fe389b532ef | |
parent | 7bc2dce08659b7cbcb3fd1865c7e3d95e8c42c52 (diff) | |
download | kvision-833390a649c633892fbc0d9b6e37d6f7913cabb1.tar.gz kvision-833390a649c633892fbc0d9b6e37d6f7913cabb1.tar.bz2 kvision-833390a649c633892fbc0d9b6e37d6f7913cabb1.zip |
Fix various problems with re-creating DOM nodes.
12 files changed, 76 insertions, 41 deletions
diff --git a/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt index 09b68633..8d7c49a7 100644 --- a/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt +++ b/kvision-modules/kvision-chart/src/main/kotlin/pl/treksoft/kvision/chart/ChartCanvas.kt @@ -53,7 +53,6 @@ internal class ChartCanvas( } override fun afterInsert(node: VNode) { - super.afterInsert(node) jsChart = JsChart(this.context2D, configuration.toJs(this::translate)) } diff --git a/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt index 69b84c87..7c1c8d71 100644 --- a/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt +++ b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt @@ -51,7 +51,10 @@ open class DateTimeInput( classes: Set<String> = setOf() ) : Widget(classes + "form-control"), FormInput { + private var initialized = false + init { + this.vnkey = "kv_datetimeinput_${counter++}" this.setInternalEventListener<DateTimeInput> { change = { self.changeValue() @@ -78,7 +81,7 @@ open class DateTimeInput( /** * Determines if the field is disabled. */ - override var disabled by refreshOnUpdate(false) + override var disabled by refreshOnUpdate(false) { refresh(); checkDisabled() } /** * Determines if the text input is automatically focused. */ @@ -160,6 +163,22 @@ open class DateTimeInput( return sn } + private fun checkDisabled() { + if (disabled) { + if (initialized) { + getElementJQueryD()?.datetimepicker("remove") + initialized = false + } + } else { + if (!initialized) { + this.initDateTimePicker() + this.initEventHandlers() + this.refreshState() + initialized = true + } + } + } + @Suppress("UnsafeCastFromDynamic") protected open fun refreshState() { value?.let { @@ -190,35 +209,31 @@ open class DateTimeInput( * Open date/time chooser popup. */ open fun showPopup() { - getElementJQueryD()?.datetimepicker("show") + if (initialized) getElementJQueryD()?.datetimepicker("show") } /** * Hides date/time chooser popup. */ open fun hidePopup() { - getElementJQueryD()?.datetimepicker("hide") + if (initialized) getElementJQueryD()?.datetimepicker("hide") } @Suppress("UnsafeCastFromDynamic") override fun afterInsert(node: VNode) { if (!this.disabled) { this.initDateTimePicker() - this.getElementJQuery()?.on("changeDate") { e, _ -> - this.dispatchEvent("change", obj { detail = e }) - } - this.getElementJQuery()?.on("show") { e, _ -> - this.dispatchEvent("showBsDateTime", obj { detail = e }) - } - this.getElementJQuery()?.on("hide") { e, _ -> - this.dispatchEvent("hideBsDateTime", obj { detail = e }) - } - refreshState() + this.initEventHandlers() + this.refreshState() + initialized = true } } override fun afterDestroy() { - getElementJQueryD()?.datetimepicker("remove") + if (initialized) { + getElementJQueryD()?.datetimepicker("remove") + initialized = false + } } private fun initDateTimePicker() { @@ -244,6 +259,18 @@ open class DateTimeInput( }) } + private fun initEventHandlers() { + this.getElementJQuery()?.on("changeDate") { e, _ -> + this.dispatchEvent("change", obj { detail = e }) + } + this.getElementJQuery()?.on("show") { e, _ -> + this.dispatchEvent("showBsDateTime", obj { detail = e }) + } + this.getElementJQuery()?.on("hide") { e, _ -> + this.dispatchEvent("hideBsDateTime", obj { detail = e }) + } + } + /** * Get value of date/time input control as String * @return value as a String @@ -267,6 +294,8 @@ open class DateTimeInput( } companion object { + internal var counter = 0 + private fun String.toDatePickerFormat(): String { return this.replace("YY", "yy").replace("m", "i").replace("MMMM", "{----}").replace("MMM", "{---}") .replace("M", "m").replace("{----}", "MM").replace("{---}", "M").replace("H", "{-}") diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt index e89d4f5e..7ffdf2c2 100644 --- a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt @@ -130,6 +130,7 @@ open class SelectInput( override var size: InputSize? by refreshOnUpdate() init { + this.vnkey = "kv_selectinput_${counter++}" setChildrenFromOptions() this.setInternalEventListener<SelectInput> { change = { @@ -348,6 +349,8 @@ open class SelectInput( } companion object { + internal var counter = 0 + /** * DSL builder extension function. * diff --git a/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt index a887c007..c60aab2f 100644 --- a/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt +++ b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt @@ -74,6 +74,7 @@ open class SpinnerInput( ) : Widget(classes + "form-control"), FormInput { init { + this.vnkey = "kv_spinnerinput_${counter++}" this.addSurroundingCssClass("input-group") if (buttonsType == ButtonsType.NONE) { this.addSurroundingCssClass("kv-spinner-btn-none") diff --git a/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt index ee17949e..a250df42 100644 --- a/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt +++ b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt @@ -138,6 +138,10 @@ open class UploadInput(uploadUrl: String? = null, multiple: Boolean = false, cla private val nativeFiles: MutableMap<KFile, File> = mutableMapOf() + init { + this.vnkey = "kv_uploadinput_${counter++}" + } + override fun render(): VNode { return render("input") } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt index 7bbbcca3..3388a011 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt @@ -96,7 +96,8 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { var eventTarget: Widget? = null - private var vnode: VNode? = null + protected var vnkey: String? by refreshOnUpdate() + protected var vnode: VNode? = null private var snAttrsCache: List<StringPair>? = null private var snClassCache: List<StringBoolPair>? = null @@ -182,6 +183,7 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { */ private fun getSnOpt(): VNodeData { return snOpt { + if (vnkey != null) key = vnkey attrs = snAttrs(getSnAttrsInternal()) style = snStyle(getSnStyleInternal()) `class` = snClasses(getSnClassInternal()) @@ -325,15 +327,6 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { afterInsertInternal(v) afterInsert(v) } - postpatch = { ov, v -> - vnode = v - if (ov.elm !== v.elm) { - afterInsertInternal(v) - afterInsert(v) - } else { - afterPostpatch(v) - } - } destroy = { afterDestroyInternal() afterDestroy() @@ -629,12 +622,6 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { } /** - * Method called after updating Snabbdom vnode. - */ - protected open fun afterPostpatch(node: VNode) { - } - - /** * Internal method called after destroying Snabbdom vnode. */ @Suppress("UnsafeCastFromDynamic") diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt index a521fe95..b58860ff 100644 --- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt +++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt @@ -149,6 +149,7 @@ open class DropDown( internal val list: DropDownListTag = DropDownListTag(idc, setOf("dropdown-menu")) init { + this.vnkey = "kv_dropdown_$counter" setChildrenFromElements() this.addInternal(button) this.addInternal(list) 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 0184c779..6973efe9 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt @@ -51,6 +51,7 @@ abstract class CheckInput( ) : Widget(classes), FormInput { init { + this.vnkey = "kv_checkinput_${counter++}" this.setInternalEventListener<CheckInput> { click = { val v = getElementJQuery()?.prop("checked") as Boolean? @@ -129,10 +130,6 @@ abstract class CheckInput( refreshState() } - override fun afterPostpatch(node: VNode) { - refreshState() - } - private fun refreshState() { val v = getElementJQuery()?.prop("checked") as Boolean? if (this.value != v) { @@ -166,4 +163,7 @@ abstract class CheckInput( getElementJQuery()?.blur() } + companion object { + internal var counter = 0 + } } 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 3a06f47b..c9ea2dba 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt @@ -41,6 +41,7 @@ abstract class AbstractTextInput( ) : Widget(classes), FormInput { init { + this.vnkey = "kv_textinput_${counter++}" this.setInternalEventListener<AbstractTextInput> { input = { self.changeValue() @@ -127,10 +128,6 @@ abstract class AbstractTextInput( refreshState() } - override fun afterPostpatch(node: VNode) { - refreshState() - } - /** * @suppress * Internal function @@ -170,4 +167,8 @@ abstract class AbstractTextInput( open fun blur() { getElementJQuery()?.blur() } + + companion object { + internal var counter = 0 + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Canvas.kt b/src/main/kotlin/pl/treksoft/kvision/html/Canvas.kt index 450042a2..476ee118 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Canvas.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Canvas.kt @@ -53,6 +53,10 @@ open class Canvas( */ lateinit var context2D: CanvasRenderingContext2D + init { + this.vnkey = "kv_canvas_${counter++}" + } + override fun render(): VNode { return render("canvas") } @@ -68,11 +72,14 @@ open class Canvas( return pr } - override fun afterInsert(node: VNode) { + override fun afterInsertInternal(node: VNode) { + super.afterInsertInternal(node) context2D = (node.elm as HTMLCanvasElement).getContext("2d") as CanvasRenderingContext2D } companion object { + internal var counter = 0 + /** * DSL builder extension function. * diff --git a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt index 5f911539..5d872b08 100644 --- a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt +++ b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt @@ -110,6 +110,7 @@ open class Modal( private val footer = SimplePanel(setOf("modal-footer")) init { + this.vnkey = "kv_modal_${counter++}" this.hide() this.role = "dialog" this.addInternal(dialog) @@ -270,6 +271,7 @@ open class Modal( } companion object { + internal var counter = 0 internal var modals = mutableListOf<Modal>() } } diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt index d3211d7a..7b046e1a 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt @@ -123,8 +123,9 @@ internal class Splitter(private val splitPanel: SplitPanel, direction: Direction private val idc = "kv_splitter_$counter" init { - counter++ + this.vnkey = "kv_splitter_$counter" this.id = idc + counter++ } override fun afterInsert(node: VNode) { |