From ea9d0452931934c6e0fdbdf7d7ad2ea7b7e6c070 Mon Sep 17 00:00:00 2001 From: Robert Jaros Date: Wed, 16 Jan 2019 18:39:15 +0100 Subject: Unification of class hierarchy in form.check package. --- .../pl/treksoft/kvision/form/check/CheckBox.kt | 4 +- .../treksoft/kvision/form/check/CheckBoxInput.kt | 53 ++++++ .../pl/treksoft/kvision/form/check/CheckInput.kt | 17 +- .../kotlin/pl/treksoft/kvision/form/check/Radio.kt | 2 +- .../pl/treksoft/kvision/form/check/RadioGroup.kt | 2 +- .../treksoft/kvision/form/check/RadioGroupInput.kt | 178 +++++++++++++++++++++ .../pl/treksoft/kvision/form/check/RadioInput.kt | 53 ++++++ 7 files changed, 289 insertions(+), 20 deletions(-) create mode 100644 src/main/kotlin/pl/treksoft/kvision/form/check/CheckBoxInput.kt create mode 100644 src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt create mode 100644 src/main/kotlin/pl/treksoft/kvision/form/check/RadioInput.kt (limited to 'src/main/kotlin/pl/treksoft/kvision') 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 3afca46e..730488eb 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt @@ -106,8 +106,8 @@ open class CheckBox( var inline by refreshOnUpdate(false) private val idc = "kv_form_checkbox_$counter" - final override val input: CheckInput = CheckInput( - CheckInputType.CHECKBOX, value, + final override val input: CheckBoxInput = CheckBoxInput( + value, setOf("styled") ).apply { this.id = idc diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBoxInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBoxInput.kt new file mode 100644 index 00000000..ea58268d --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBoxInput.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.check + +import pl.treksoft.kvision.core.Container + +/** + * The basic input component rendered as HTML *input type="checkbox"*. + * + * @constructor + * @param value selection state + * @param classes a set of CSS class names + */ +open class CheckBoxInput( + value: Boolean = false, + classes: Set = setOf() +) : CheckInput(CheckInputType.CHECKBOX, value, classes) { + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.checkBoxInput( + value: Boolean = false, + classes: Set = setOf(), init: (CheckInput.() -> Unit)? = null + ): CheckBoxInput { + val checkBoxInput = CheckBoxInput(value, classes).apply { init?.invoke(this) } + this.add(checkBoxInput) + return checkBoxInput + } + } +} 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 2df3a055..7940ea0e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt @@ -46,7 +46,7 @@ enum class CheckInputType(internal val type: String) { * @param value selection state * @param classes a set of CSS class names */ -open class CheckInput( +abstract class CheckInput( type: CheckInputType = CheckInputType.CHECKBOX, value: Boolean = false, classes: Set = setOf() ) : Widget(classes), FormInput { @@ -167,19 +167,4 @@ open class CheckInput( getElementJQuery()?.blur() } - companion object { - /** - * DSL builder extension function. - * - * It takes the same parameters as the constructor of the built component. - */ - fun Container.checkInput( - type: CheckInputType = CheckInputType.CHECKBOX, value: Boolean = false, - classes: Set = setOf(), init: (CheckInput.() -> Unit)? = null - ): CheckInput { - val checkInput = CheckInput(type, value, classes).apply { init?.invoke(this) } - this.add(checkInput) - return checkInput - } - } } 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 181d9665..29b3cb35 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt @@ -115,7 +115,7 @@ open class Radio( var inline by refreshOnUpdate(false) private val idc = "kv_form_radio_$counter" - final override val input: CheckInput = CheckInput(CheckInputType.RADIO, value).apply { + final override val input: RadioInput = RadioInput(value).apply { this.id = idc this.extraValue = extraValue this.name = name diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt index e2f27c36..6ac58bb7 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt @@ -99,7 +99,7 @@ open class RadioGroup( } private val idc = "kv_form_radiogroup_$counter" - final override val input = CheckInput() + final override val input = RadioInput() final override val flabel: FieldLabel = FieldLabel(idc, label, rich) final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt new file mode 100644 index 00000000..98839982 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.check + +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.form.FormInput +import pl.treksoft.kvision.form.InputSize +import pl.treksoft.kvision.panel.SimplePanel + +/** + * The input component rendered as a group of HTML *input type="radio"* elements with the same name attribute. + * + * The radio group can be populated directly from *options* parameter or manually by adding + * [Radio] components to the container. + * + * @constructor + * @param options an optional list of options (label to value pairs) for the group + * @param value selected option + * @param name the name attribute of the generated HTML input element + * @param inline determines if the options are rendered inline + */ +@Suppress("TooManyFunctions") +open class RadioGroupInput( + options: List? = null, value: String? = null, name: String? = null, inline: Boolean = false +) : SimplePanel(setOf("form-group")), FormInput { + + /** + * A list of options (label to value pairs) for the group. + */ + var options by refreshOnUpdate(options) { setChildrenFromOptions() } + + /** + * A value of the selected option. + */ + var value by refreshOnUpdate(value) { setValueToChildren(it) } + + /** + * Determines if the options are rendered inline. + */ + var inline by refreshOnUpdate(inline) + + override var disabled + get() = getDisabledFromChildren() + set(value) { + setDisabledToChildren(value) + } + override var name + get() = getNameFromChildren() + set(value) { + setNameToChildren(value) + } + override var size + get() = getSizeFromChildren() + set(value) { + setSizeToChildren(value) + } + + private val idc = "kv_form_radiogroup_$counter" + + init { + setChildrenFromOptions() + setValueToChildren(value) + setNameToChildren(name) + counter++ + } + + override fun getSnClass(): List { + val cl = super.getSnClass().toMutableList() + if (inline) { + cl.add("kv-radiogroup-inline" to true) + } else { + cl.add("kv-radiogroup" to true) + } + return cl + } + + private fun setValueToChildren(value: String?) { + val radios = getChildren().filterIsInstance() + radios.forEach { it.value = false } + radios.find { + it.extraValue == value + }?.value = true + } + + private fun getDisabledFromChildren(): Boolean { + return getChildren().filterIsInstance().firstOrNull()?.disabled ?: false + } + + private fun setDisabledToChildren(disabled: Boolean) { + getChildren().filterIsInstance().forEach { it.disabled = disabled } + } + + private fun getNameFromChildren(): String? { + return getChildren().filterIsInstance().firstOrNull()?.name ?: this.idc + } + + private fun setNameToChildren(name: String?) { + val tname = name ?: this.idc + getChildren().filterIsInstance().forEach { it.name = tname } + } + + private fun getSizeFromChildren(): InputSize? { + return getChildren().filterIsInstance().firstOrNull()?.size + } + + private fun setSizeToChildren(size: InputSize?) { + getChildren().filterIsInstance().forEach { it.size = size } + } + + private fun setChildrenFromOptions() { + val currentName = this.name + super.removeAll() + options?.let { + val tname = currentName ?: this.idc + val tinline = this.inline + val c = it.map { + Radio(false, extraValue = it.first, label = it.second).apply { + inline = tinline + name = tname + eventTarget = this@RadioGroupInput + setEventListener { + change = { + this@RadioGroupInput.value = self.extraValue + } + } + } + } + super.addAll(c) + } + } + + fun focus() { + getChildren().filterIsInstance().firstOrNull()?.focus() + } + + fun blur() { + getChildren().filterIsInstance().firstOrNull()?.blur() + } + + companion object { + internal var counter = 0 + + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.radioGroupInput( + options: List? = null, value: String? = null, name: String? = null, inline: Boolean = false, + init: (RadioGroupInput.() -> Unit)? = null + ): RadioGroupInput { + val radioGroupInput = RadioGroupInput(options, value, name, inline).apply { init?.invoke(this) } + this.add(radioGroupInput) + return radioGroupInput + } + } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioInput.kt new file mode 100644 index 00000000..9c6a1670 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioInput.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.check + +import pl.treksoft.kvision.core.Container + +/** + * The basic input component rendered as HTML *input type="radio"*. + * + * @constructor + * @param value selection state + * @param classes a set of CSS class names + */ +open class RadioInput( + value: Boolean = false, + classes: Set = setOf() +) : CheckInput(CheckInputType.RADIO, value, classes) { + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.radioInput( + value: Boolean = false, + classes: Set = setOf(), init: (CheckInput.() -> Unit)? = null + ): RadioInput { + val checkBoxInput = RadioInput(value, classes).apply { init?.invoke(this) } + this.add(checkBoxInput) + return checkBoxInput + } + } +} -- cgit