diff options
author | Robert Jaros <rjaros@finn.pl> | 2019-10-03 19:03:21 +0200 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2019-10-03 19:03:21 +0200 |
commit | 6b53324c97bfc80ed14dfca6a5dbc879950715b9 (patch) | |
tree | 55c7bb7d06e37470795a93e1f542e51ef3f1ace6 /src/main/kotlin/pl/treksoft/kvision/form | |
parent | 22a8d5c35db97d65a90b21d97e6835380191845d (diff) | |
download | kvision-6b53324c97bfc80ed14dfca6a5dbc879950715b9.tar.gz kvision-6b53324c97bfc80ed14dfca6a5dbc879950715b9.tar.bz2 kvision-6b53324c97bfc80ed14dfca6a5dbc879950715b9.zip |
Upgrade to Bootstrap 4.
Upgrade to Font Awesome 5.
Restructure modules.
Diffstat (limited to 'src/main/kotlin/pl/treksoft/kvision/form')
15 files changed, 236 insertions, 88 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt index 3019fb6f..f75007c0 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt @@ -30,8 +30,16 @@ import kotlin.js.Date * Input controls sizes. */ enum class InputSize(val className: String) { - LARGE("input-lg"), - SMALL("input-sm") + LARGE("form-control-lg"), + SMALL("form-control-sm") +} + +/** + * Input controls validation status. + */ +enum class ValidationStatus(val className: String) { + VALID("is-valid"), + INVALID("is-invalid") } interface FormInput : Component { @@ -47,6 +55,10 @@ interface FormInput : Component { * The name attribute of the generated HTML input element. */ var name: String? + /** + * Input control validation status. + */ + var validationStatus: ValidationStatus? /** * Makes the input element focused. @@ -78,6 +90,16 @@ interface FormControl : Component { get() = input.size set(value) { input.size = value + if (value == InputSize.SMALL) { + flabel.addCssClass("col-form-label-sm") + } else { + flabel.removeCssClass("col-form-label-sm") + } + if (value == InputSize.LARGE) { + flabel.addCssClass("col-form-label-lg") + } else { + flabel.removeCssClass("col-form-label-lg") + } } /** * The name attribute of the generated HTML input element. @@ -88,6 +110,14 @@ interface FormControl : Component { input.name = value } /** + * Input control validation status. + */ + var validationStatus: ValidationStatus? + get() = input.validationStatus + set(value) { + input.validationStatus = value + } + /** * The actual input component. */ val input: FormInput @@ -96,9 +126,9 @@ interface FormControl : Component { */ val flabel: FieldLabel /** - * Validation info component. + * Invalid feedback component. */ - val validationInfo: HelpBlock + val invalidFeedback: InvalidFeedback /** * Returns the value of the control. @@ -129,10 +159,11 @@ interface FormControl : Component { * Validator error message. */ var validatorError: String? - get() = validationInfo.content + get() = invalidFeedback.content set(value) { - validationInfo.content = value - validationInfo.visible = value != null + invalidFeedback.content = value + invalidFeedback.visible = value != null + input.validationStatus = if (value != null) ValidationStatus.INVALID else null refresh() } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt index 21281556..41e8010c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt @@ -30,8 +30,8 @@ import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.form.check.CheckBox import pl.treksoft.kvision.form.check.Radio -import pl.treksoft.kvision.html.TAG -import pl.treksoft.kvision.html.Tag +import pl.treksoft.kvision.form.check.RadioGroup +import pl.treksoft.kvision.html.Div import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.types.KFile import kotlin.js.Date @@ -82,13 +82,14 @@ enum class FormTarget(internal val target: String) { * @param action the URL address to send data * @param enctype form encoding type * @param type form layout + * @param condensed determines if the form is condensed. * @param classes set of CSS class names * @param serializer a serializer for model type */ @Suppress("TooManyFunctions") open class FormPanel<K : Any>( method: FormMethod? = null, action: String? = null, enctype: FormEnctype? = null, - private val type: FormType? = null, classes: Set<String> = setOf(), + private val type: FormType? = null, condensed: Boolean = false, classes: Set<String> = setOf(), serializer: KSerializer<K> ) : SimplePanel(classes) { @@ -120,6 +121,10 @@ open class FormPanel<K : Any>( * Determines if the form should have autocomplete. */ var autocomplete: Boolean? by refreshOnUpdate() + /** + * Determines if the form is condensed. + */ + var condensed by refreshOnUpdate(condensed) /** * Function returning validation message. @@ -156,7 +161,7 @@ open class FormPanel<K : Any>( * @suppress * Internal property. */ - protected val validationAlert = Tag(TAG.H5, classes = setOf("alert", "alert-danger")).apply { + protected val validationAlert = Div(classes = setOf("alert", "alert-danger")).apply { role = "alert" visible = false } @@ -173,7 +178,9 @@ open class FormPanel<K : Any>( val cl = super.getSnClass().toMutableList() if (type != null) { cl.add(type.formType to true) + if (type == FormType.HORIZONTAL) cl.add("container-fluid" to true) } + if (condensed) cl.add("kv-form-condensed" to true) return cl } @@ -210,13 +217,28 @@ open class FormPanel<K : Any>( ): FormPanel<K> { if (type == FormType.HORIZONTAL) { if (control is CheckBox || control is Radio) { - control.addCssClass("col-sm-offset-2") + control.addCssClass("form-group") + control.addSurroundingCssClass("row") + control.addCssClass("offset-sm-2") control.addCssClass("col-sm-10") + } else if (control is RadioGroup) { + control.addCssClass("row") + control.flabel.addCssClass("col-sm-2") + control.flabel.addCssClass("col-form-label") + control.container.addCssClass("col-sm-10") + control.invalidFeedback.addCssClass("offset-sm-2") + control.invalidFeedback.addCssClass("col-sm-10") } else { + control.addCssClass("row") control.flabel.addCssClass("col-sm-2") - control.input.addSurroundingCssClass("col-sm-10") - control.validationInfo.addCssClass("col-sm-offset-2") - control.validationInfo.addCssClass("col-sm-10") + control.flabel.addCssClass("col-form-label") + control.input.addCssClass("col-sm-10") + control.invalidFeedback.addCssClass("offset-sm-2") + control.invalidFeedback.addCssClass("col-sm-10") + } + } else { + if (control is CheckBox || control is Radio) { + control.addCssClass("form-group") } } super.add(control) @@ -399,10 +421,10 @@ open class FormPanel<K : Any>( */ inline fun <reified K : Any> Container.formPanel( method: FormMethod? = null, action: String? = null, enctype: FormEnctype? = null, - type: FormType? = null, classes: Set<String> = setOf(), + type: FormType? = null, condensed: Boolean = false, classes: Set<String> = setOf(), noinline init: (FormPanel<K>.() -> Unit)? = null ): FormPanel<K> { - val formPanel = create<K>(method, action, enctype, type, classes) + val formPanel = create<K>(method, action, enctype, type, condensed, classes) init?.invoke(formPanel) this.add(formPanel) return formPanel @@ -411,10 +433,10 @@ open class FormPanel<K : Any>( @UseExperimental(ImplicitReflectionSerializer::class) inline fun <reified K : Any> create( method: FormMethod? = null, action: String? = null, enctype: FormEnctype? = null, - type: FormType? = null, classes: Set<String> = setOf(), + type: FormType? = null, condensed: Boolean = false, classes: Set<String> = setOf(), noinline init: (FormPanel<K>.() -> Unit)? = null ): FormPanel<K> { - val formPanel = FormPanel(method, action, enctype, type, classes, K::class.serializer()) + val formPanel = FormPanel(method, action, enctype, type, condensed, classes, K::class.serializer()) init?.invoke(formPanel) return formPanel } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt b/src/main/kotlin/pl/treksoft/kvision/form/HelpText.kt index 9ec3d8ae..0362d03a 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/HelpText.kt @@ -25,13 +25,13 @@ import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag /** - * Helper class for Bootstrap help block element. + * Helper class for Bootstrap help text element. * * @constructor * @param content the text of the label * @param rich determines if [content] can contain HTML code */ -open class HelpBlock(content: String? = null, rich: Boolean = false) : Tag( - TAG.SPAN, content, rich, - classes = setOf("help-block", "small") +open class HelpText(content: String? = null, rich: Boolean = false) : Tag( + TAG.SMALL, content, rich, + classes = setOf("form-text", "text-muted") ) diff --git a/src/main/kotlin/pl/treksoft/kvision/form/InvalidFeedback.kt b/src/main/kotlin/pl/treksoft/kvision/form/InvalidFeedback.kt new file mode 100644 index 00000000..dad68239 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/form/InvalidFeedback.kt @@ -0,0 +1,37 @@ +/* + * 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 + +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag + +/** + * Helper class for Bootstrap invalid feedback element. + * + * @constructor + * @param content the text of the label + * @param rich determines if [content] can contain HTML code + */ +open class InvalidFeedback(content: String? = null, rich: Boolean = false) : Tag( + TAG.DIV, content, rich, + classes = setOf("invalid-feedback") +) 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 730488eb..f011b1cb 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt @@ -27,7 +27,7 @@ import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.BoolFormControl import pl.treksoft.kvision.form.FieldLabel -import pl.treksoft.kvision.form.HelpBlock +import pl.treksoft.kvision.form.InvalidFeedback import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn @@ -35,12 +35,11 @@ import pl.treksoft.kvision.utils.SnOn * Checkbox style options. */ enum class CheckBoxStyle(internal val className: String) { - DEFAULT("checkbox-default"), - PRIMARY("checkbox-primary"), - SUCCESS("checkbox-success"), - INFO("checkbox-info"), - WARNING("checkbox-warning"), - DANGER("checkbox-danger"), + PRIMARY("abc-checkbox-primary"), + SUCCESS("abc-checkbox-success"), + INFO("abc-checkbox-info"), + WARNING("abc-checkbox-warning"), + DANGER("abc-checkbox-danger"), } /** @@ -55,7 +54,7 @@ enum class CheckBoxStyle(internal val className: String) { open class CheckBox( value: Boolean = false, name: String? = null, label: String? = null, rich: Boolean = false -) : SimplePanel(setOf("checkbox")), BoolFormControl { +) : SimplePanel(setOf("form-check", "abc-checkbox")), BoolFormControl { /** * The selection state of the checkbox. @@ -106,22 +105,19 @@ open class CheckBox( var inline by refreshOnUpdate(false) private val idc = "kv_form_checkbox_$counter" - final override val input: CheckBoxInput = CheckBoxInput( - value, - setOf("styled") - ).apply { + final override val input: CheckBoxInput = CheckBoxInput(value, classes = setOf("form-check-input")).apply { this.id = idc this.name = name } - final override val flabel: FieldLabel = FieldLabel(idc, label, rich, classes = setOf()) - final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } + final override val flabel: FieldLabel = FieldLabel(idc, label, rich, classes = setOf("form-check-label")) + final override val invalidFeedback: InvalidFeedback = InvalidFeedback().apply { visible = false } init { @Suppress("LeakingThis") input.eventTarget = this this.addInternal(input) this.addInternal(flabel) - this.addInternal(validationInfo) + this.addInternal(invalidFeedback) counter++ } @@ -147,13 +143,13 @@ open class CheckBox( cl.add(it.className to true) } if (circled) { - cl.add("checkbox-circle" to true) + cl.add("abc-checkbox-circle" to true) } if (inline) { - cl.add("checkbox-inline" to true) + cl.add("form-check-inline" to true) } if (validatorError != null) { - cl.add("has-error" to true) + cl.add("text-danger" to true) } return cl } 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 a486b82e..f93fd436 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt @@ -28,6 +28,7 @@ import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.FormInput import pl.treksoft.kvision.form.InputSize +import pl.treksoft.kvision.form.ValidationStatus /** * Type of the check input control (checkbox or radio). @@ -94,6 +95,10 @@ abstract class CheckInput( * The size of the input. */ override var size: InputSize? by refreshOnUpdate() + /** + * The validation status of the input. + */ + override var validationStatus: ValidationStatus? by refreshOnUpdate() override fun render(): VNode { return render("input") @@ -101,6 +106,9 @@ abstract class CheckInput( override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() + validationStatus?.let { + cl.add(it.className to true) + } size?.let { cl.add(it.className to 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 29b3cb35..7ab509c4 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt @@ -27,7 +27,7 @@ import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.BoolFormControl import pl.treksoft.kvision.form.FieldLabel -import pl.treksoft.kvision.form.HelpBlock +import pl.treksoft.kvision.form.InvalidFeedback import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn @@ -35,12 +35,12 @@ import pl.treksoft.kvision.utils.SnOn * Radio style options. */ enum class RadioStyle(internal val className: String) { - DEFAULT("radio-default"), - PRIMARY("radio-primary"), - SUCCESS("radio-success"), - INFO("radio-info"), - WARNING("radio-warning"), - DANGER("radio-danger"), + DEFAULT("abc-radio-default"), + PRIMARY("abc-radio-primary"), + SUCCESS("abc-radio-success"), + INFO("abc-radio-info"), + WARNING("abc-radio-warning"), + DANGER("abc-radio-danger"), } /** @@ -56,7 +56,7 @@ enum class RadioStyle(internal val className: String) { open class Radio( value: Boolean = false, extraValue: String? = null, name: String? = null, label: String? = null, rich: Boolean = false -) : SimplePanel(), BoolFormControl { +) : SimplePanel(classes = setOf("form-check")), BoolFormControl { /** * The selection state of the radio button. @@ -115,20 +115,20 @@ open class Radio( var inline by refreshOnUpdate(false) private val idc = "kv_form_radio_$counter" - final override val input: RadioInput = RadioInput(value).apply { + final override val input: RadioInput = RadioInput(value, classes = setOf("form-check-input")).apply { this.id = idc this.extraValue = extraValue this.name = name } - final override val flabel: FieldLabel = FieldLabel(idc, label, rich, classes = setOf()) - final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } + final override val flabel: FieldLabel = FieldLabel(idc, label, rich, classes = setOf("form-check-label")) + final override val invalidFeedback: InvalidFeedback = InvalidFeedback().apply { visible = false } init { @Suppress("LeakingThis") input.eventTarget = this.eventTarget ?: this this.addInternal(input) this.addInternal(flabel) - this.addInternal(validationInfo) + this.addInternal(invalidFeedback) counter++ } @@ -151,25 +151,21 @@ open class Radio( override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() if (!squared) { - cl.add("radio" to true) + cl.add("abc-radio" to true) style?.let { cl.add(it.className to true) } - if (inline) { - cl.add("radio-inline" to true) - } } else { - cl.add("checkbox" to true) - cl.add("kv-radio-checkbox" to true) + cl.add("abc-checkbox" to true) style?.let { cl.add(it.className.replace("radio", "checkbox") to true) } - if (inline) { - cl.add("checkbox-inline" to true) - } + } + if (inline) { + cl.add("form-check-inline" to true) } if (validatorError != null) { - cl.add("has-error" to true) + cl.add("text-danger" to true) } return cl } 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 6ac58bb7..b1a0a703 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt @@ -25,9 +25,10 @@ import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.form.FieldLabel -import pl.treksoft.kvision.form.HelpBlock import pl.treksoft.kvision.form.InputSize +import pl.treksoft.kvision.form.InvalidFeedback import pl.treksoft.kvision.form.StringFormControl +import pl.treksoft.kvision.form.ValidationStatus import pl.treksoft.kvision.panel.SimplePanel /** @@ -97,13 +98,33 @@ open class RadioGroup( set(value) { setSizeToChildren(value) } + override var validationStatus + get() = getValidationStatusFromChildren() + set(value) { + setValidationStatusToChildren(value) + } + override var validatorError: String? + get() = super.validatorError + set(value) { + super.validatorError = value + if (value!=null) { + container.addCssClass("is-invalid") + } else { + container.removeCssClass("is-invalid") + } + } private val idc = "kv_form_radiogroup_$counter" final override val input = RadioInput() final override val flabel: FieldLabel = FieldLabel(idc, label, rich) - final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } + final override val invalidFeedback: InvalidFeedback = InvalidFeedback().apply { visible = false } + + internal val container = SimplePanel(setOf("kv-radiogroup-container")) init { + this.addInternal(flabel) + this.addInternal(container) + this.addInternal(invalidFeedback) setChildrenFromOptions() setValueToChildren(value) setNameToChildren(name) @@ -113,7 +134,7 @@ open class RadioGroup( override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() if (validatorError != null) { - cl.add("has-error" to true) + cl.add("text-danger" to true) } if (inline) { cl.add("kv-radiogroup-inline" to true) @@ -124,7 +145,7 @@ open class RadioGroup( } private fun setValueToChildren(value: String?) { - val radios = getChildren().filterIsInstance<Radio>() + val radios = container.getChildren().filterIsInstance<Radio>() radios.forEach { it.value = false } radios.find { it.extraValue == value @@ -132,34 +153,42 @@ open class RadioGroup( } private fun getDisabledFromChildren(): Boolean { - return getChildren().filterIsInstance<Radio>().firstOrNull()?.disabled ?: false + return container.getChildren().filterIsInstance<Radio>().firstOrNull()?.disabled ?: false } private fun setDisabledToChildren(disabled: Boolean) { - getChildren().filterIsInstance<Radio>().forEach { it.disabled = disabled } + container.getChildren().filterIsInstance<Radio>().forEach { it.disabled = disabled } } private fun getNameFromChildren(): String? { - return getChildren().filterIsInstance<Radio>().firstOrNull()?.name ?: this.idc + return container.getChildren().filterIsInstance<Radio>().firstOrNull()?.name ?: this.idc } private fun setNameToChildren(name: String?) { val tname = name ?: this.idc - getChildren().filterIsInstance<Radio>().forEach { it.name = tname } + container.getChildren().filterIsInstance<Radio>().forEach { it.name = tname } } private fun getSizeFromChildren(): InputSize? { - return getChildren().filterIsInstance<Radio>().firstOrNull()?.size + return container.getChildren().filterIsInstance<Radio>().firstOrNull()?.size } private fun setSizeToChildren(size: InputSize?) { - getChildren().filterIsInstance<Radio>().forEach { it.size = size } + container.getChildren().filterIsInstance<Radio>().forEach { it.size = size } + super.size = size + } + + private fun getValidationStatusFromChildren(): ValidationStatus? { + return container.getChildren().filterIsInstance<Radio>().firstOrNull()?.validationStatus + } + + private fun setValidationStatusToChildren(validationStatus: ValidationStatus?) { + container.getChildren().filterIsInstance<Radio>().forEach { it.validationStatus = validationStatus } } private fun setChildrenFromOptions() { val currentName = this.name - super.removeAll() - this.addInternal(flabel) + container.removeAll() options?.let { val tname = currentName ?: this.idc val tinline = this.inline @@ -175,17 +204,16 @@ open class RadioGroup( } } } - super.addAll(c) + container.addAll(c) } - this.addInternal(validationInfo) } override fun focus() { - getChildren().filterIsInstance<Radio>().firstOrNull()?.focus() + container.getChildren().filterIsInstance<Radio>().firstOrNull()?.focus() } override fun blur() { - getChildren().filterIsInstance<Radio>().firstOrNull()?.blur() + container.getChildren().filterIsInstance<Radio>().firstOrNull()?.blur() } companion object { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt index fca681f6..d4301709 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroupInput.kt @@ -26,6 +26,7 @@ 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.form.ValidationStatus import pl.treksoft.kvision.panel.SimplePanel /** @@ -75,6 +76,11 @@ open class RadioGroupInput( set(value) { setSizeToChildren(value) } + override var validationStatus + get() = getValidationStatusFromChildren() + set(value) { + setValidationStatusToChildren(value) + } private val idc = "kv_form_radiogroup_$counter" @@ -128,6 +134,14 @@ open class RadioGroupInput( getChildren().filterIsInstance<Radio>().forEach { it.size = size } } + private fun getValidationStatusFromChildren(): ValidationStatus? { + return getChildren().filterIsInstance<Radio>().firstOrNull()?.validationStatus + } + + private fun setValidationStatusToChildren(validationStatus: ValidationStatus?) { + getChildren().filterIsInstance<Radio>().forEach { it.validationStatus = validationStatus } + } + private fun setChildrenFromOptions() { val currentName = this.name super.removeAll() 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 4d278ad2..bef14bfa 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelect.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelect.kt @@ -27,7 +27,7 @@ import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.FieldLabel -import pl.treksoft.kvision.form.HelpBlock +import pl.treksoft.kvision.form.InvalidFeedback import pl.treksoft.kvision.form.StringFormControl import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn @@ -117,21 +117,21 @@ open class SimpleSelect( this.name = name } final override val flabel: FieldLabel = FieldLabel(idc, label, rich) - final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } + final override val invalidFeedback: InvalidFeedback = InvalidFeedback().apply { visible = false } init { @Suppress("LeakingThis") input.eventTarget = this this.addInternal(flabel) this.addInternal(input) - this.addInternal(validationInfo) + this.addInternal(invalidFeedback) counter++ } override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() if (validatorError != null) { - cl.add("has-error" to true) + cl.add("text-danger" to true) } return cl } 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 b2ba1d43..31d32052 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SimpleSelectInput.kt @@ -27,6 +27,7 @@ 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.form.ValidationStatus import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag import pl.treksoft.kvision.panel.SimplePanel @@ -83,6 +84,10 @@ open class SimpleSelectInput( * The size of the input. */ override var size: InputSize? by refreshOnUpdate() + /** + * The validation status of the input. + */ + override var validationStatus: ValidationStatus? by refreshOnUpdate() init { setChildrenFromOptions() @@ -129,6 +134,9 @@ open class SimpleSelectInput( override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() + validationStatus?.let { + cl.add(it.className to true) + } size?.let { cl.add(it.className to true) } 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 7c23615a..091278fc 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt @@ -24,7 +24,7 @@ package pl.treksoft.kvision.form.text import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.FieldLabel -import pl.treksoft.kvision.form.HelpBlock +import pl.treksoft.kvision.form.InvalidFeedback import pl.treksoft.kvision.form.StringFormControl import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn @@ -114,7 +114,7 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) : protected val idc = "kv_form_text_$counter" abstract override val input: AbstractTextInput final override val flabel: FieldLabel = FieldLabel(idc, label, rich) - final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } + final override val invalidFeedback: InvalidFeedback = InvalidFeedback().apply { visible = false } init { this.addInternal(flabel) @@ -128,7 +128,7 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) : override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() if (validatorError != null) { - cl.add("has-error" to true) + cl.add("text-danger" to true) } return cl } 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 e7ecba8a..192b33c8 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt @@ -27,6 +27,7 @@ import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.FormInput import pl.treksoft.kvision.form.InputSize +import pl.treksoft.kvision.form.ValidationStatus /** * Base class for basic text components. @@ -87,9 +88,16 @@ abstract class AbstractTextInput( * The size of the input. */ override var size: InputSize? by refreshOnUpdate() + /** + * The validation status of the input. + */ + override var validationStatus: ValidationStatus? by refreshOnUpdate() override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() + validationStatus?.let { + cl.add(it.className to true) + } size?.let { cl.add(it.className to true) } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt index 7e4127f5..f493b06e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt @@ -64,7 +64,7 @@ open class Text( @Suppress("LeakingThis") input.eventTarget = this this.addInternal(input) - this.addInternal(validationInfo) + this.addInternal(invalidFeedback) } companion object { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt index d5058583..ccf17892 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt @@ -73,7 +73,7 @@ open class TextArea( @Suppress("LeakingThis") input.eventTarget = this this.addInternal(input) - this.addInternal(validationInfo) + this.addInternal(invalidFeedback) } companion object { |