aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/pl/treksoft/kvision/form
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2017-11-25 13:39:39 +0100
committerRobert Jaros <rjaros@finn.pl>2017-11-25 13:39:39 +0100
commit343390df5a0e01f45539939291c35d535a1b8af6 (patch)
treefcba5b87efa1b740bd5a011739af1e066cba28f0 /src/main/kotlin/pl/treksoft/kvision/form
parent4a31ea44d479358658a614ad56a5675436260813 (diff)
downloadkvision-343390df5a0e01f45539939291c35d535a1b8af6.tar.gz
kvision-343390df5a0e01f45539939291c35d535a1b8af6.tar.bz2
kvision-343390df5a0e01f45539939291c35d535a1b8af6.zip
Form validation
Diffstat (limited to 'src/main/kotlin/pl/treksoft/kvision/form')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt5
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/Form.kt96
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt68
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/FormField.kt34
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt106
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt7
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt15
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt11
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt14
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt31
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt19
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt19
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt10
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt1
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt1
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt1
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt22
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt16
18 files changed, 384 insertions, 92 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt
index 92b014d4..748ace83 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt
@@ -4,8 +4,9 @@ import pl.treksoft.kvision.html.TAG
import pl.treksoft.kvision.html.Tag
import pl.treksoft.kvision.snabbdom.StringPair
-open class FieldLabel(private val forId: String, text: String? = null, rich: Boolean = false) : Tag(TAG.LABEL,
- text, rich) {
+open class FieldLabel(private val forId: String, text: String? = null, rich: Boolean = false,
+ classes: Set<String> = setOf("control-label")) : Tag(TAG.LABEL,
+ text, rich, classes = classes) {
override fun getSnAttrs(): List<StringPair> {
return super.getSnAttrs() + ("for" to forId)
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt
new file mode 100644
index 00000000..66f6f450
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt
@@ -0,0 +1,96 @@
+package pl.treksoft.kvision.form
+
+import kotlin.js.Date
+
+data class FieldParams<in F : FormControl>(val required: Boolean = false,
+ val validatorMessage: ((F) -> String?)? = null,
+ val validator: ((F) -> Boolean?)? = null)
+
+open class Form<K>(private val panel: FormPanel<K>? = null, private val modelFactory: (Map<String, Any?>) -> K) {
+
+ internal val fields: MutableMap<String, FormControl> = mutableMapOf()
+ internal val fieldsParams: MutableMap<String, Any> = mutableMapOf()
+ internal var validatorMessage: ((Form<K>) -> String?)? = null
+ internal var validator: ((Form<K>) -> Boolean?)? = null
+
+ open fun <C : FormControl> add(key: String, control: C, required: Boolean = false,
+ validatorMessage: ((C) -> String?)? = null,
+ validator: ((C) -> Boolean?)? = null): Form<K> {
+ this.fields.put(key, control)
+ this.fieldsParams.put(key, FieldParams(required, validatorMessage, validator))
+ return this
+ }
+
+ open fun remove(key: String): Form<K> {
+ this.fields.remove(key)
+ return this
+ }
+
+ open fun removeAll(): Form<K> {
+ this.fields.clear()
+ return this
+ }
+
+ open fun getControl(key: String): FormControl? {
+ return this.fields[key]
+ }
+
+ operator fun get(key: String): Any? {
+ return getControl(key)?.getValue()
+ }
+
+ open fun setData(data: K) {
+ fields.forEach { it.value.setValue(null) }
+ val map = data.asDynamic().map as? Map<String, Any?>
+ if (map != null) {
+ map.forEach {
+ fields[it.key]?.setValue(it.value)
+ }
+ } else {
+ for (key in js("Object").keys(data)) {
+ @Suppress("UnsafeCastFromDynamic")
+ fields[key]?.setValue(data.asDynamic()[key])
+ }
+ }
+ }
+
+ open fun getData(): K {
+ val map = fields.entries.associateBy({ it.key }, { it.value.getValue() })
+ return modelFactory(map)
+ }
+
+ open fun validate(): Boolean {
+ val fieldWithError = fieldsParams.mapNotNull { entry ->
+ fields[entry.key]?.let { control ->
+ @Suppress("UNCHECKED_CAST")
+ val fieldsParams = (entry.value as? FieldParams<FormControl>)
+ val required = fieldsParams?.required ?: false
+ val requiredError = control.getValue() == null && required
+ if (requiredError) {
+ control.validatorError = "Value is required"
+ true
+ } else {
+ val validatorPassed = fieldsParams?.validator?.invoke(control) ?: true
+ control.validatorError = if (!validatorPassed) {
+ fieldsParams?.validatorMessage?.invoke(control) ?: "Invalid value"
+ } else {
+ null
+ }
+ !validatorPassed
+ }
+ }
+ }.find { it }
+ val validatorPassed = validator?.invoke(this) ?: true
+ panel?.validatorError = if (!validatorPassed) {
+ panel?.validatorMessage?.invoke(this) ?: "Invalid form data"
+ } else {
+ null
+ }
+ return fieldWithError == null && validatorPassed
+ }
+}
+
+fun Map<String, Any?>.string(key: String): String? = this[key] as? String
+fun Map<String, Any?>.number(key: String): Number? = this[key] as? Number
+fun Map<String, Any?>.bool(key: String): Boolean? = this[key] as? Boolean
+fun Map<String, Any?>.date(key: String): Date? = this[key] as? Date
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt
new file mode 100644
index 00000000..d0858d4e
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt
@@ -0,0 +1,68 @@
+package pl.treksoft.kvision.form
+
+import pl.treksoft.kvision.core.Component
+import kotlin.js.Date
+
+enum class INPUTSIZE(val className: String) {
+ LARGE("input-lg"),
+ SMALL("input-sm")
+}
+
+interface FormControl : Component {
+ var disabled: Boolean
+ var size: INPUTSIZE?
+ val input: Component
+ val flabel: FieldLabel
+ val validationInfo: HelpBlock
+ fun getValue(): Any?
+ fun setValue(v: Any?)
+ fun getValueAsString(): String?
+ fun refresh(): Component
+ var validatorError: String?
+ get() = validationInfo.text
+ set(value) {
+ validationInfo.text = value
+ validationInfo.visible = value != null
+ refresh()
+ }
+}
+
+interface StringFormControl : FormControl {
+ var value: String?
+ override fun getValue(): String? = value
+ override fun setValue(v: Any?) {
+ value = v as? String
+ }
+
+ override fun getValueAsString(): String? = value
+}
+
+interface NumberFormControl : FormControl {
+ var value: Number?
+ override fun getValue(): Number? = value
+ override fun setValue(v: Any?) {
+ value = v as? Number
+ }
+
+ override fun getValueAsString(): String? = value?.toString()
+}
+
+interface BoolFormControl : FormControl {
+ var value: Boolean
+ override fun getValue(): Boolean = value
+ override fun setValue(v: Any?) {
+ value = v as? Boolean ?: false
+ }
+
+ override fun getValueAsString(): String? = value.toString()
+}
+
+interface DateFormControl : FormControl {
+ var value: Date?
+ override fun getValue(): Date? = value
+ override fun setValue(v: Any?) {
+ value = v as? Date
+ }
+
+ override fun getValueAsString(): String? = value?.toString()
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormField.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormField.kt
deleted file mode 100644
index 503ee51d..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/FormField.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package pl.treksoft.kvision.form
-
-import kotlin.js.Date
-
-enum class INPUTSIZE(val className: String) {
- LARGE("input-lg"),
- SMALL("input-sm")
-}
-
-interface FormField {
- var disabled: Boolean
- var size: INPUTSIZE?
- fun getValueAsString(): String?
-}
-
-interface StringFormField : FormField {
- var value: String?
- override fun getValueAsString(): String? = value
-}
-
-interface NumberFormField : FormField {
- var value: Number?
- override fun getValueAsString(): String? = value?.toString()
-}
-
-interface BoolFormField : FormField {
- var value: Boolean
- override fun getValueAsString(): String? = value.toString()
-}
-
-interface DateFormField : FormField {
- var value: Date?
- override fun getValueAsString(): String? = value?.toString()
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt
new file mode 100644
index 00000000..e996cfae
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt
@@ -0,0 +1,106 @@
+package pl.treksoft.kvision.form
+
+import com.github.snabbdom.VNode
+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.panel.SimplePanel
+import pl.treksoft.kvision.snabbdom.StringBoolPair
+
+enum class FORMTYPE(val formType: String) {
+ INLINE("form-inline"),
+ HORIZONTAL("form-horizontal")
+}
+
+open class FormPanel<K>(private val type: FORMTYPE? = null, classes: Set<String> = setOf(),
+ modelFactory: (Map<String, Any?>) -> K) : SimplePanel(classes) {
+
+ var validatorMessage
+ get() = form.validatorMessage
+ set(value) {
+ form.validatorMessage = value
+ }
+ var validator
+ get() = form.validator
+ set(value) {
+ form.validator = value
+ }
+
+ internal var validatorError: String?
+ get() = validationAlert.text
+ set(value) {
+ validationAlert.text = value
+ validationAlert.visible = value != null
+ refresh()
+ }
+
+ @Suppress("LeakingThis")
+ protected val form = Form(this, modelFactory)
+ protected val validationAlert = Tag(TAG.H5, classes = setOf("alert", "alert-danger")).apply {
+ role = "alert"
+ visible = false
+ }
+
+ init {
+ this.addInternal(validationAlert)
+ }
+
+ override fun render(): VNode {
+ return kvh("form", childrenVNodes())
+ }
+
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ if (type != null) {
+ cl.add(type.formType to true)
+ }
+ return cl
+ }
+
+ open fun <C : FormControl> add(key: String, control: C, required: Boolean = false,
+ validatorMessage: ((C) -> String?)? = null,
+ validator: ((C) -> Boolean?)? = null): FormPanel<K> {
+ if (type == FORMTYPE.HORIZONTAL) {
+ if (control is CheckBox || control is Radio) {
+ control.addCssClass("col-sm-offset-2")
+ control.addCssClass("col-sm-10")
+ } else {
+ 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")
+ }
+ }
+ super.add(control)
+ form.add(key, control, required, validatorMessage, validator)
+ return this
+ }
+
+ fun remove(key: String): FormPanel<K> {
+ form.getControl(key)?.let {
+ super.remove(it)
+ }
+ form.remove(key)
+ return this
+ }
+
+ override fun removeAll(): FormPanel<K> {
+ super.removeAll()
+ this.addInternal(validationAlert)
+ form.removeAll()
+ return this
+ }
+
+ open fun setData(data: K) {
+ form.setData(data)
+ }
+
+ open fun getData(): K {
+ return form.getData()
+ }
+
+ open fun validate(): Boolean {
+ return form.validate()
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt b/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt
new file mode 100644
index 00000000..44b2e7b0
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt
@@ -0,0 +1,7 @@
+package pl.treksoft.kvision.form
+
+import pl.treksoft.kvision.html.TAG
+import pl.treksoft.kvision.html.Tag
+
+open class HelpBlock(text: String? = null, rich: Boolean = false) : Tag(TAG.SPAN, text, rich,
+ classes = setOf("help-block", "small"))
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 e4dd7fe9..62403f8a 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt
@@ -1,8 +1,9 @@
package pl.treksoft.kvision.form.check
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.BoolFormField
+import pl.treksoft.kvision.form.BoolFormControl
import pl.treksoft.kvision.form.FieldLabel
+import pl.treksoft.kvision.form.HelpBlock
import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.SnOn
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -17,7 +18,7 @@ enum class CHECKBOXSTYLE(val className: String) {
}
open class CheckBox(value: Boolean = false, label: String? = null,
- rich: Boolean = false) : SimplePanel(setOf("checkbox")), BoolFormField {
+ rich: Boolean = false) : SimplePanel(setOf("checkbox")), BoolFormControl {
override var value
get() = input.value
@@ -71,14 +72,17 @@ open class CheckBox(value: Boolean = false, label: String? = null,
}
private val idc = "kv_form_checkbox_" + counter
- val input: CheckInput = CheckInput(CHECKINPUTTYPE.CHECKBOX, value, setOf("styled")).apply { id = idc }
- val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val input: CheckInput = CheckInput(CHECKINPUTTYPE.CHECKBOX, value,
+ setOf("styled")).apply { id = idc }
+ final override val flabel: FieldLabel = FieldLabel(idc, label, rich, classes = setOf())
+ final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false }
init {
@Suppress("LeakingThis")
input.eventTarget = this
this.addInternal(input)
this.addInternal(flabel)
+ this.addInternal(validationInfo)
counter++
}
@@ -113,6 +117,9 @@ open class CheckBox(value: Boolean = false, label: String? = null,
if (inline) {
cl.add("checkbox-inline" to true)
}
+ if (validatorError != null) {
+ cl.add("has-error" 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 a4899f45..a2ebd06d 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt
@@ -2,7 +2,6 @@ package pl.treksoft.kvision.form.check
import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.BoolFormField
import pl.treksoft.kvision.form.INPUTSIZE
import pl.treksoft.kvision.snabbdom.StringBoolPair
import pl.treksoft.kvision.snabbdom.StringPair
@@ -13,7 +12,7 @@ enum class CHECKINPUTTYPE(val type: String) {
}
open class CheckInput(type: CHECKINPUTTYPE = CHECKINPUTTYPE.CHECKBOX, value: Boolean = false,
- classes: Set<String> = setOf()) : Widget(classes), BoolFormField {
+ classes: Set<String> = setOf()) : Widget(classes) {
init {
this.setInternalEventListener<CheckInput> {
@@ -27,12 +26,12 @@ open class CheckInput(type: CHECKINPUTTYPE = CHECKINPUTTYPE.CHECKBOX, value: Boo
}
}
}
- override var value: Boolean = value
+
+ var value: Boolean = value
set(value) {
field = value
refreshState()
}
- @Suppress("LeakingThis")
var startValue: Boolean = value
set(value) {
field = value
@@ -49,7 +48,7 @@ open class CheckInput(type: CHECKINPUTTYPE = CHECKINPUTTYPE.CHECKBOX, value: Boo
field = value
refresh()
}
- override var disabled: Boolean = false
+ var disabled: Boolean = false
set(value) {
field = value
refresh()
@@ -59,7 +58,7 @@ open class CheckInput(type: CHECKINPUTTYPE = CHECKINPUTTYPE.CHECKBOX, value: Boo
field = value
refresh()
}
- override var size: INPUTSIZE? = null
+ var size: INPUTSIZE? = null
set(value) {
field = value
refresh()
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 284cf26c..1a28870a 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt
@@ -1,8 +1,9 @@
package pl.treksoft.kvision.form.check
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.BoolFormField
+import pl.treksoft.kvision.form.BoolFormControl
import pl.treksoft.kvision.form.FieldLabel
+import pl.treksoft.kvision.form.HelpBlock
import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.SnOn
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -17,7 +18,7 @@ enum class RADIOSTYLE(val className: String) {
}
open class Radio(value: Boolean = false, extraValue: String? = null, label: String? = null,
- rich: Boolean = false) : SimplePanel(), BoolFormField {
+ rich: Boolean = false) : SimplePanel(), BoolFormControl {
override var value
get() = input.value
@@ -76,17 +77,19 @@ open class Radio(value: Boolean = false, extraValue: String? = null, label: Stri
}
private val idc = "kv_form_radio_" + counter
- val input: CheckInput = CheckInput(CHECKINPUTTYPE.RADIO, value).apply {
+ final override val input: CheckInput = CheckInput(CHECKINPUTTYPE.RADIO, value).apply {
this.id = idc
this.extraValue = extraValue
}
- val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val flabel: FieldLabel = FieldLabel(idc, label, rich, classes = setOf())
+ final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false }
init {
@Suppress("LeakingThis")
input.eventTarget = this
this.addInternal(input)
this.addInternal(flabel)
+ this.addInternal(validationInfo)
counter++
}
@@ -129,6 +132,9 @@ open class Radio(value: Boolean = false, extraValue: String? = null, label: Stri
cl.add("checkbox-inline" to true)
}
}
+ if (validatorError != null) {
+ cl.add("has-error" to true)
+ }
return cl
}
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt
index 4b991605..2d750683 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt
@@ -1,16 +1,19 @@
package pl.treksoft.kvision.form.select
+import pl.treksoft.kvision.core.Component
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.form.FieldLabel
-import pl.treksoft.kvision.form.StringFormField
+import pl.treksoft.kvision.form.HelpBlock
+import pl.treksoft.kvision.form.StringFormControl
import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.SnOn
+import pl.treksoft.kvision.snabbdom.StringBoolPair
import pl.treksoft.kvision.snabbdom.StringPair
@Suppress("TooManyFunctions")
open class Select(options: List<StringPair>? = null, value: String? = null,
multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null,
- rich: Boolean = false) : SimplePanel(setOf("form-group")), StringFormField {
+ rich: Boolean = false) : SimplePanel(setOf("form-group")), StringFormControl {
var options
get() = input.options
@@ -99,15 +102,17 @@ open class Select(options: List<StringPair>? = null, value: String? = null,
}
private val idc = "kv_form_select_" + counter
- val input: SelectInput = SelectInput(options, value, multiple, ajaxOptions,
+ final override val input: SelectInput = SelectInput(options, value, multiple, ajaxOptions,
setOf("form-control")).apply { id = idc }
- val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false }
init {
- this.addInternal(flabel)
@Suppress("LeakingThis")
input.eventTarget = this
+ this.addInternal(flabel)
this.addInternal(input)
+ this.addInternal(validationInfo)
counter++
}
@@ -115,6 +120,14 @@ open class Select(options: List<StringPair>? = null, value: String? = null,
var counter = 0
}
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ if (validatorError != null) {
+ cl.add("has-error" to true)
+ }
+ return cl
+ }
+
@Suppress("UNCHECKED_CAST")
override fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Widget {
input.setEventListener(block)
@@ -131,17 +144,17 @@ open class Select(options: List<StringPair>? = null, value: String? = null,
return this
}
- override fun add(child: Widget): SimplePanel {
+ override fun add(child: Component): SimplePanel {
input.add(child)
return this
}
- override fun addAll(children: List<Widget>): SimplePanel {
+ override fun addAll(children: List<Component>): SimplePanel {
input.addAll(children)
return this
}
- override fun remove(child: Widget): SimplePanel {
+ override fun remove(child: Component): SimplePanel {
input.remove(child)
return this
}
@@ -151,7 +164,7 @@ open class Select(options: List<StringPair>? = null, value: String? = null,
return this
}
- override fun getChildren(): List<Widget> {
+ override fun getChildren(): List<Component> {
return input.getChildren()
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt
index c95cf434..2dcbe99b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt
@@ -3,9 +3,8 @@ package pl.treksoft.kvision.form.select
import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.CssSize
import pl.treksoft.kvision.core.KVManager.KVNULL
-import pl.treksoft.kvision.core.Widget
+import pl.treksoft.kvision.core.Component
import pl.treksoft.kvision.form.INPUTSIZE
-import pl.treksoft.kvision.form.StringFormField
import pl.treksoft.kvision.html.BUTTONSTYLE
import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.StringBoolPair
@@ -20,7 +19,7 @@ enum class SELECTWIDTHTYPE(val value: String) {
@Suppress("TooManyFunctions")
open class SelectInput(options: List<StringPair>? = null, value: String? = null,
multiple: Boolean = false, ajaxOptions: AjaxOptions? = null,
- classes: Set<String> = setOf()) : SimplePanel(classes), StringFormField {
+ classes: Set<String> = setOf()) : SimplePanel(classes) {
internal var options = options
set(value) {
@@ -28,14 +27,12 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null,
setChildrenFromOptions()
}
- @Suppress("LeakingThis")
- override var value: String? = value
+ var value: String? = value
set(value) {
field = value
refreshState()
}
- @Suppress("LeakingThis")
var startValue: String? = value
set(value) {
field = value
@@ -93,7 +90,7 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null,
field = value
setChildrenFromOptions()
}
- override var disabled: Boolean = false
+ var disabled: Boolean = false
set(value) {
field = value
refresh()
@@ -103,7 +100,7 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null,
field = value
refresh()
}
- override var size: INPUTSIZE? = null
+ var size: INPUTSIZE? = null
set(value) {
field = value
refresh()
@@ -140,19 +137,19 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null,
return kvh("select", childrenVNodes())
}
- override fun add(child: Widget): SimplePanel {
+ override fun add(child: Component): SimplePanel {
super.add(child)
refreshSelectInput()
return this
}
- override fun addAll(children: List<Widget>): SimplePanel {
+ override fun addAll(children: List<Component>): SimplePanel {
super.addAll(children)
refreshSelectInput()
return this
}
- override fun remove(child: Widget): SimplePanel {
+ override fun remove(child: Component): SimplePanel {
super.remove(child)
refreshSelectInput()
return this
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 0b50cbab..8dd2a241 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt
@@ -2,12 +2,14 @@ package pl.treksoft.kvision.form.text
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.form.FieldLabel
-import pl.treksoft.kvision.form.StringFormField
+import pl.treksoft.kvision.form.HelpBlock
+import pl.treksoft.kvision.form.StringFormControl
import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.SnOn
+import pl.treksoft.kvision.snabbdom.StringBoolPair
abstract class AbstractText(label: String? = null, rich: Boolean = false) :
- SimplePanel(setOf("form-group")), StringFormField {
+ SimplePanel(setOf("form-group")), StringFormControl {
override var value
get() = input.value
@@ -66,8 +68,9 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) :
}
protected val idc = "kv_form_text_" + counter
- internal abstract val input: AbstractTextInput
- internal val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ abstract override val input: AbstractTextInput
+ final override val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false }
init {
this.addInternal(flabel)
@@ -78,6 +81,14 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) :
var counter = 0
}
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ if (validatorError != null) {
+ cl.add("has-error" to true)
+ }
+ return cl
+ }
+
@Suppress("UNCHECKED_CAST")
override fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Widget {
input.setEventListener(block)
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 a71a84a5..0303f5bd 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt
@@ -2,12 +2,11 @@ package pl.treksoft.kvision.form.text
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.form.INPUTSIZE
-import pl.treksoft.kvision.form.StringFormField
import pl.treksoft.kvision.snabbdom.StringBoolPair
import pl.treksoft.kvision.snabbdom.StringPair
abstract class AbstractTextInput(value: String? = null,
- classes: Set<String> = setOf()) : Widget(classes), StringFormField {
+ classes: Set<String> = setOf()) : Widget(classes) {
init {
this.setInternalEventListener<AbstractTextInput> {
@@ -17,12 +16,11 @@ abstract class AbstractTextInput(value: String? = null,
}
}
- override var value: String? = value
+ var value: String? = value
set(value) {
field = value
refreshState()
}
- @Suppress("LeakingThis")
var startValue: String? = value
set(value) {
field = value
@@ -44,7 +42,7 @@ abstract class AbstractTextInput(value: String? = null,
field = value
refresh()
}
- override var disabled: Boolean = false
+ var disabled: Boolean = false
set(value) {
field = value
refresh()
@@ -59,7 +57,7 @@ abstract class AbstractTextInput(value: String? = null,
field = value
refresh()
}
- override var size: INPUTSIZE? = null
+ var size: INPUTSIZE? = null
set(value) {
field = value
refresh()
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt
index b963b4ea..280c017d 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt
@@ -15,5 +15,6 @@ open class RichText(value: String? = null,
@Suppress("LeakingThis")
input.eventTarget = this
this.addInternal(input)
+ this.addInternal(validationInfo)
}
}
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 d5d78616..db3233ba 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt
@@ -21,5 +21,6 @@ open class Text(type: TEXTINPUTTYPE = TEXTINPUTTYPE.TEXT, value: String? = null,
@Suppress("LeakingThis")
input.eventTarget = this
this.addInternal(input)
+ this.addInternal(validationInfo)
}
}
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 ecfe9cee..181298ac 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt
@@ -25,5 +25,6 @@ open class TextArea(cols: Int? = null, rows: Int? = null, value: String? = null,
@Suppress("LeakingThis")
input.eventTarget = this
this.addInternal(input)
+ this.addInternal(validationInfo)
}
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt
index ae732030..892467b7 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt
@@ -1,14 +1,16 @@
package pl.treksoft.kvision.form.time
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.DateFormField
+import pl.treksoft.kvision.form.DateFormControl
import pl.treksoft.kvision.form.FieldLabel
+import pl.treksoft.kvision.form.HelpBlock
import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.SnOn
+import pl.treksoft.kvision.snabbdom.StringBoolPair
import kotlin.js.Date
open class DateTime(value: Date? = null, format: String = "YYYY-MM-DD HH:mm", label: String? = null,
- rich: Boolean = false) : SimplePanel(setOf("form-group")), DateFormField {
+ rich: Boolean = false) : SimplePanel(setOf("form-group")), DateFormControl {
override var value
get() = input.value
@@ -97,14 +99,16 @@ open class DateTime(value: Date? = null, format: String = "YYYY-MM-DD HH:mm", la
}
protected val idc = "kv_form_time_" + counter
- internal val input: DateTimeInput = DateTimeInput(value, format).apply { id = idc }
- internal val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val input: DateTimeInput = DateTimeInput(value, format).apply { id = idc }
+ final override val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false }
init {
- this.addInternal(flabel)
@Suppress("LeakingThis")
input.eventTarget = this
+ this.addInternal(flabel)
this.addInternal(input)
+ this.addInternal(validationInfo)
counter++
}
@@ -112,6 +116,14 @@ open class DateTime(value: Date? = null, format: String = "YYYY-MM-DD HH:mm", la
var counter = 0
}
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ if (validatorError != null) {
+ cl.add("has-error" to true)
+ }
+ return cl
+ }
+
@Suppress("UNCHECKED_CAST")
override fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Widget {
input.setEventListener(block)
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt
index 78321c10..8db66834 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt
@@ -2,7 +2,6 @@ package pl.treksoft.kvision.form.time
import com.github.snabbdom.VNode
import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.DateFormField
import pl.treksoft.kvision.form.INPUTSIZE
import pl.treksoft.kvision.snabbdom.StringBoolPair
import pl.treksoft.kvision.snabbdom.StringPair
@@ -16,7 +15,7 @@ const val MAX_VIEW = 4
@Suppress("TooManyFunctions")
open class DateTimeInput(value: Date? = null, format: String = "YYYY-MM-DD HH:mm",
- classes: Set<String> = setOf()) : Widget(classes + "form-control"), DateFormField {
+ classes: Set<String> = setOf()) : Widget(classes + "form-control") {
init {
@@ -27,7 +26,7 @@ open class DateTimeInput(value: Date? = null, format: String = "YYYY-MM-DD HH:mm
}
}
- override var value: Date? = value
+ var value: Date? = value
set(value) {
field = value
refreshState()
@@ -47,7 +46,7 @@ open class DateTimeInput(value: Date? = null, format: String = "YYYY-MM-DD HH:mm
field = value
refresh()
}
- override var disabled: Boolean = false
+ var disabled: Boolean = false
set(value) {
field = value
refresh()
@@ -62,7 +61,7 @@ open class DateTimeInput(value: Date? = null, format: String = "YYYY-MM-DD HH:mm
field = value
refresh()
}
- override var size: INPUTSIZE? = null
+ var size: INPUTSIZE? = null
set(value) {
field = value
refresh()
@@ -147,7 +146,10 @@ open class DateTimeInput(value: Date? = null, format: String = "YYYY-MM-DD HH:mm
protected open fun refreshState() {
value?.let {
getElementJQueryD()?.datetimepicker("update", it)
- } ?: getElementJQueryD()?.datetimepicker("update", null)
+ } ?: run {
+ getElementJQueryD()?.`val`(null)
+ getElementJQueryD()?.datetimepicker("update", null)
+ }
}
protected open fun refreshDatePicker() {
@@ -212,7 +214,7 @@ open class DateTimeInput(value: Date? = null, format: String = "YYYY-MM-DD HH:mm
})
}
- override fun getValueAsString(): String? {
+ fun getValueAsString(): String? {
return value?.toStringF(format)
}