diff options
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt | 4 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/check/CheckBoxInput.kt | 53 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt | 17 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt | 2 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt | 2 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt | 178 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/check/RadioInput.kt | 53 | ||||
-rw-r--r-- | src/test/kotlin/test/pl/treksoft/kvision/form/check/CheckBoxInputSpec.kt (renamed from src/test/kotlin/test/pl/treksoft/kvision/form/check/CheckInputSpec.kt) | 26 | ||||
-rw-r--r-- | src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioGroupInputSpec.kt | 54 | ||||
-rw-r--r-- | src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioInputSpec.kt | 51 |
10 files changed, 397 insertions, 43 deletions
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<String> = 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<String> = 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<String> = 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<String> = 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<StringPair>? = 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<StringBoolPair> { + 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<Radio>() + radios.forEach { it.value = false } + radios.find { + it.extraValue == value + }?.value = true + } + + private fun getDisabledFromChildren(): Boolean { + return getChildren().filterIsInstance<Radio>().firstOrNull()?.disabled ?: false + } + + private fun setDisabledToChildren(disabled: Boolean) { + getChildren().filterIsInstance<Radio>().forEach { it.disabled = disabled } + } + + private fun getNameFromChildren(): String? { + return getChildren().filterIsInstance<Radio>().firstOrNull()?.name ?: this.idc + } + + private fun setNameToChildren(name: String?) { + val tname = name ?: this.idc + getChildren().filterIsInstance<Radio>().forEach { it.name = tname } + } + + private fun getSizeFromChildren(): InputSize? { + return getChildren().filterIsInstance<Radio>().firstOrNull()?.size + } + + private fun setSizeToChildren(size: InputSize?) { + getChildren().filterIsInstance<Radio>().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<Radio> { + change = { + this@RadioGroupInput.value = self.extraValue + } + } + } + } + super.addAll(c) + } + } + + fun focus() { + getChildren().filterIsInstance<Radio>().firstOrNull()?.focus() + } + + fun blur() { + getChildren().filterIsInstance<Radio>().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<StringPair>? = 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<String> = 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<String> = setOf(), init: (CheckInput.() -> Unit)? = null + ): RadioInput { + val checkBoxInput = RadioInput(value, classes).apply { init?.invoke(this) } + this.add(checkBoxInput) + return checkBoxInput + } + } +} diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/check/CheckInputSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/check/CheckBoxInputSpec.kt index 6cb1cd3e..8a9f86d5 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/form/check/CheckInputSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/check/CheckBoxInputSpec.kt @@ -21,20 +21,19 @@ */ package test.pl.treksoft.kvision.form.check -import pl.treksoft.kvision.form.check.CheckInput -import pl.treksoft.kvision.form.check.CheckInputType +import pl.treksoft.kvision.form.check.CheckBoxInput import pl.treksoft.kvision.panel.Root import test.pl.treksoft.kvision.DomSpec import kotlin.browser.document import kotlin.test.Test -class CheckInputSpec : DomSpec { +class CheckBoxInputSpec : DomSpec { @Test fun render() { run { val root = Root("test", true) - val ci = CheckInput(value = true).apply { + val ci = CheckBoxInput(value = true).apply { name = "name" id = "idti" disabled = true @@ -49,23 +48,4 @@ class CheckInputSpec : DomSpec { } } - @Test - fun renderAsRadio() { - run { - val root = Root("test", true) - val ci = CheckInput(type = CheckInputType.RADIO, value = true).apply { - name = "name" - id = "idti" - extraValue = "abc" - } - root.add(ci) - val element = document.getElementById("test") - assertEqualsHtml( - "<input id=\"idti\" type=\"radio\" checked=\"checked\" name=\"name\" value=\"abc\">", - element?.innerHTML, - "Should render correct radio button control" - ) - } - } - }
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioGroupInputSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioGroupInputSpec.kt new file mode 100644 index 00000000..f74a76f7 --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioGroupInputSpec.kt @@ -0,0 +1,54 @@ +/* + * 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 test.pl.treksoft.kvision.form.check + +import pl.treksoft.kvision.form.check.Radio +import pl.treksoft.kvision.form.check.RadioGroupInput +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class RadioGroupInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val ci = RadioGroupInput(options = listOf("a" to "A", "b" to "B"), value = "a").apply { + disabled = true + inline = true + } + root.add(ci) + val element = document.getElementById("test") + val name = ci.getChildren().filterIsInstance<Radio>().first().input.name + val rid1 = ci.getChildren().filterIsInstance<Radio>().first().input.id + val rid2 = ci.getChildren().filterIsInstance<Radio>().last().input.id + assertEqualsHtml( + "<div class=\"form-group kv-radiogroup-inline\"><div class=\"radio\"><input id=\"$rid1\" type=\"radio\" name=\"$name\" disabled=\"disabled\" value=\"a\"><label for=\"$rid1\">A</label></div><div class=\"radio\"><input id=\"$rid2\" type=\"radio\" name=\"$name\" disabled=\"disabled\" value=\"b\"><label for=\"$rid2\">B</label></div></div>", + element?.innerHTML, + "Should render correct radio button group form control" + ) + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioInputSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioInputSpec.kt new file mode 100644 index 00000000..55d4108a --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/check/RadioInputSpec.kt @@ -0,0 +1,51 @@ +/* + * 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 test.pl.treksoft.kvision.form.check + +import pl.treksoft.kvision.form.check.RadioInput +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class RadioInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val ci = RadioInput(value = true).apply { + name = "name" + id = "idti" + extraValue = "abc" + } + root.add(ci) + val element = document.getElementById("test") + assertEqualsHtml( + "<input id=\"idti\" type=\"radio\" checked=\"checked\" name=\"name\" value=\"abc\">", + element?.innerHTML, + "Should render correct radio button control" + ) + } + } + +}
\ No newline at end of file |