diff options
author | Robert Jaros <rjaros@finn.pl> | 2018-03-07 00:07:07 +0100 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2018-03-07 00:07:07 +0100 |
commit | c87e1851919c60d57aeb77809a94f589d537f827 (patch) | |
tree | 4c1ba89595d7710711c35829baf149740e0cbf90 /src | |
parent | 35a6bc496500d77a9f76fc9806713ed378cfbb68 (diff) | |
download | kvision-c87e1851919c60d57aeb77809a94f589d537f827.tar.gz kvision-c87e1851919c60d57aeb77809a94f589d537f827.tar.bz2 kvision-c87e1851919c60d57aeb77809a94f589d537f827.zip |
More type-safe forms implementation.
Diffstat (limited to 'src')
4 files changed, 176 insertions, 55 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt index e91002e9..1b06156e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt @@ -23,6 +23,7 @@ package pl.treksoft.kvision.form import kotlin.js.Date import kotlin.js.Json +import kotlin.reflect.KProperty1 /** * Internal data class containing form field parameters. @@ -48,23 +49,82 @@ class Form<K>(private val panel: FormPanel<K>? = null, private val modelFactory: internal var validatorMessage: ((Form<K>) -> String?)? = null internal var validator: ((Form<K>) -> Boolean?)? = null + internal fun <C : FormControl> addInternal( + key: KProperty1<K, *>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): Form<K> { + this.fields[key.name] = control + this.fieldsParams[key.name] = FieldParams(required, validatorMessage, validator) + return this + } + /** - * Adds a control to the form. + * Adds a string control to the form. * @param key key identifier of the control - * @param control the form control + * @param control the string form control * @param required determines if the control is required * @param validatorMessage optional function returning validation message * @param validator optional validation function * @return current form */ - fun <C : FormControl> add( - key: String, control: C, required: Boolean = false, + fun <C : StringFormControl> add( + key: KProperty1<K, String?>, control: C, required: Boolean = false, validatorMessage: ((C) -> String?)? = null, validator: ((C) -> Boolean?)? = null ): Form<K> { - this.fields[key] = control - this.fieldsParams[key] = FieldParams(required, validatorMessage, validator) - return this + return addInternal(key, control, required, validatorMessage, validator) + } + + /** + * Adds a boolean control to the form. + * @param key key identifier of the control + * @param control the boolean form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form + */ + fun <C : BoolFormControl> add( + key: KProperty1<K, Boolean?>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): Form<K> { + return addInternal(key, control, required, validatorMessage, validator) + } + + /** + * Adds a number control to the form. + * @param key key identifier of the control + * @param control the number form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form + */ + fun <C : NumberFormControl> add( + key: KProperty1<K, Number?>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): Form<K> { + return addInternal(key, control, required, validatorMessage, validator) + } + + /** + * Adds a date control to the form. + * @param key key identifier of the control + * @param control the date form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form + */ + fun <C : DateFormControl> add( + key: KProperty1<K, Date?>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): Form<K> { + return addInternal(key, control, required, validatorMessage, validator) } /** @@ -72,8 +132,8 @@ class Form<K>(private val panel: FormPanel<K>? = null, private val modelFactory: * @param key key identifier of the control * @return current form */ - fun remove(key: String): Form<K> { - this.fields.remove(key) + fun remove(key: KProperty1<K, *>): Form<K> { + this.fields.remove(key.name) return this } @@ -91,8 +151,8 @@ class Form<K>(private val panel: FormPanel<K>? = null, private val modelFactory: * @param key key identifier of the control * @return selected control */ - fun getControl(key: String): FormControl? { - return this.fields[key] + fun getControl(key: KProperty1<K, *>): FormControl? { + return this.fields[key.name] } /** @@ -100,7 +160,7 @@ class Form<K>(private val panel: FormPanel<K>? = null, private val modelFactory: * @param key key identifier of the control * @return value of the control */ - operator fun get(key: String): Any? { + operator fun get(key: KProperty1<K, *>): Any? { return getControl(key)?.getValue() } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt index c13fe9f1..5df2d299 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt @@ -29,7 +29,9 @@ 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 kotlin.js.Date import kotlin.js.Json +import kotlin.reflect.KProperty1 /** * Bootstrap form layout options. @@ -109,17 +111,8 @@ open class FormPanel<K>( return cl } - /** - * Adds a control to the form panel. - * @param key key identifier of the control - * @param control the form control - * @param required determines if the control is required - * @param validatorMessage optional function returning validation message - * @param validator optional validation function - * @return current form panel - */ - open fun <C : FormControl> add( - key: String, control: C, required: Boolean = false, + protected fun <C : FormControl> addInternal( + key: KProperty1<K, *>, control: C, required: Boolean = false, validatorMessage: ((C) -> String?)? = null, validator: ((C) -> Boolean?)? = null ): FormPanel<K> { @@ -135,16 +128,84 @@ open class FormPanel<K>( } } super.add(control) - form.add(key, control, required, validatorMessage, validator) + form.addInternal(key, control, required, validatorMessage, validator) return this } /** + * Adds a string control to the form panel. + * @param key key identifier of the control + * @param control the string form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form panel + */ + open fun <C : StringFormControl> add( + key: KProperty1<K, String?>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): FormPanel<K> { + return addInternal(key, control, required, validatorMessage, validator) + } + + /** + * Adds a boolean control to the form panel. + * @param key key identifier of the control + * @param control the boolean form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form panel + */ + open fun <C : BoolFormControl> add( + key: KProperty1<K, Boolean?>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): FormPanel<K> { + return addInternal(key, control, required, validatorMessage, validator) + } + + /** + * Adds a number control to the form panel. + * @param key key identifier of the control + * @param control the number form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form panel + */ + open fun <C : NumberFormControl> add( + key: KProperty1<K, Number?>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): FormPanel<K> { + return addInternal(key, control, required, validatorMessage, validator) + } + + /** + * Adds a date control to the form panel. + * @param key key identifier of the control + * @param control the date form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form panel + */ + open fun <C : DateFormControl> add( + key: KProperty1<K, Date?>, control: C, required: Boolean = false, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): FormPanel<K> { + return addInternal(key, control, required, validatorMessage, validator) + } + + /** * Removes a control from the form panel. * @param key key identifier of the control * @return current form panel */ - open fun remove(key: String): FormPanel<K> { + open fun remove(key: KProperty1<K, *>): FormPanel<K> { form.getControl(key)?.let { super.remove(it) } @@ -164,7 +225,7 @@ open class FormPanel<K>( * @param key key identifier of the control * @return selected control */ - open fun getControl(key: String): FormControl? { + open fun getControl(key: KProperty1<K, *>): FormControl? { return form.getControl(key) } @@ -173,7 +234,7 @@ open class FormPanel<K>( * @param key key identifier of the control * @return value of the control */ - operator fun get(key: String): Any? { + operator fun get(key: KProperty1<K, *>): Any? { return getControl(key)?.getValue() } diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/FormPanelSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/FormPanelSpec.kt index 88695366..33b439a5 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/form/FormPanelSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/FormPanelSpec.kt @@ -51,7 +51,7 @@ class FormPanelSpec : SimpleSpec { val result = formPanel.getData() assertNull(result.a, "FormPanel should return null without adding any control") val textField = Text() - formPanel.add("a", textField) + formPanel.add(DataForm::a, textField) formPanel.setData(data) val result2 = formPanel.getData() assertEquals("Test value", result2.a, "FormPanel should return initial value") @@ -71,9 +71,9 @@ class FormPanelSpec : SimpleSpec { DataForm(it) } val data = DataForm(mapOf("a" to "Test value")) - formPanel.add("a", Text()) + formPanel.add(DataForm::a, Text()) formPanel.setData(data) - formPanel.remove("a") + formPanel.remove(DataForm::a) val result = formPanel.getData() assertNull(result.a, "FormPanel should return null after removing control") } @@ -92,7 +92,7 @@ class FormPanelSpec : SimpleSpec { DataForm(it) } val data = DataForm(mapOf("a" to "Test value")) - formPanel.add("a", Text()) + formPanel.add(DataForm::a, Text()) formPanel.setData(data) formPanel.removeAll() val result = formPanel.getData() @@ -112,10 +112,10 @@ class FormPanelSpec : SimpleSpec { val formPanel = FormPanel { DataForm(it) } - formPanel.add("a", Text()) - val control = formPanel.getControl("b") + formPanel.add(DataForm::a, Text()) + val control = formPanel.getControl(DataForm::b) assertNull(control, "Should return null when there is no such control") - val control2 = formPanel.getControl("a") + val control2 = formPanel.getControl(DataForm::a) assertNotNull(control2, "Should return correct control") } } @@ -133,13 +133,13 @@ class FormPanelSpec : SimpleSpec { DataForm(it) } val data = DataForm(mapOf("a" to "Test value")) - formPanel.add("a", Text()) - val b = formPanel["b"] + formPanel.add(DataForm::a, Text()) + val b = formPanel[DataForm::b] assertNull(b, "Should return null value when there is no added control") - val a = formPanel["a"] + val a = formPanel[DataForm::a] assertNull(a, "Should return null value when control is empty") formPanel.setData(data) - val a2 = formPanel["a"] + val a2 = formPanel[DataForm::a] assertEquals("Test value", a2, "Should return correct value") } } @@ -158,7 +158,7 @@ class FormPanelSpec : SimpleSpec { } val data = DataForm(mapOf("a" to "Test value")) val textField = Text() - formPanel.add("a", textField) + formPanel.add(DataForm::a, textField) formPanel.setData(data) textField.value = "New value" val result = formPanel.getData() @@ -177,10 +177,10 @@ class FormPanelSpec : SimpleSpec { val formPanel = FormPanel { DataForm(it) } - formPanel.add("s", Text()) { + formPanel.add(DataForm::s, Text()) { it.getValue()?.length ?: 0 > 4 } - formPanel.add("d", DateTime(), required = true) + formPanel.add(DataForm::d, DateTime(), required = true) formPanel.setData(DataForm(mapOf("s" to "123"))) val valid = formPanel.validate() assertEquals(false, valid, "Should be invalid with initial data") diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/FormSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/FormSpec.kt index 128b96b1..ee3cd2af 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/form/FormSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/FormSpec.kt @@ -51,7 +51,7 @@ class FormSpec : SimpleSpec { val result = form.getData() assertNull(result.a, "Form should return null without adding any control") val textField = Text() - form.add("a", textField) + form.add(DataForm::a, textField) form.setData(data) val result2 = form.getData() assertEquals("Test value", result2.a, "Form should return initial value") @@ -71,9 +71,9 @@ class FormSpec : SimpleSpec { DataForm(it) } val data = DataForm(mapOf("a" to "Test value")) - form.add("a", Text()) + form.add(DataForm::a, Text()) form.setData(data) - form.remove("a") + form.remove(DataForm::a) val result = form.getData() assertNull(result.a, "Form should return null after removing control") } @@ -92,7 +92,7 @@ class FormSpec : SimpleSpec { DataForm(it) } val data = DataForm(mapOf("a" to "Test value")) - form.add("a", Text()) + form.add(DataForm::a, Text()) form.setData(data) form.removeAll() val result = form.getData() @@ -112,10 +112,10 @@ class FormSpec : SimpleSpec { val form = Form { DataForm(it) } - form.add("a", Text()) - val control = form.getControl("b") + form.add(DataForm::a, Text()) + val control = form.getControl(DataForm::b) assertNull(control, "Should return null when there is no such control") - val control2 = form.getControl("a") + val control2 = form.getControl(DataForm::a) assertNotNull(control2, "Should return correct control") } } @@ -133,13 +133,13 @@ class FormSpec : SimpleSpec { DataForm(it) } val data = DataForm(mapOf("a" to "Test value")) - form.add("a", Text()) - val b = form["b"] + form.add(DataForm::a, Text()) + val b = form[DataForm::b] assertNull(b, "Should return null value when there is no added control") - val a = form["a"] + val a = form[DataForm::a] assertNull(a, "Should return null value when control is empty") form.setData(data) - val a2 = form["a"] + val a2 = form[DataForm::a] assertEquals("Test value", a2, "Should return correct value") } } @@ -158,7 +158,7 @@ class FormSpec : SimpleSpec { } val data = DataForm(mapOf("a" to "Test value")) val textField = Text() - form.add("a", textField) + form.add(DataForm::a, textField) form.setData(data) textField.value = "New value" val result = form.getData() @@ -177,10 +177,10 @@ class FormSpec : SimpleSpec { val form = Form { DataForm(it) } - form.add("s", Text()) { + form.add(DataForm::s, Text()) { it.getValue()?.length ?: 0 > 4 } - form.add("d", DateTime(), required = true) + form.add(DataForm::d, DateTime(), required = true) form.setData(DataForm(mapOf("s" to "123"))) val valid = form.validate() assertEquals(false, valid, "Should be invalid with initial data") |