diff options
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/Form.kt | 51 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt | 2 | ||||
-rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt | 41 |
3 files changed, 81 insertions, 13 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt index 8f63662e..1c17999d 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt @@ -30,9 +30,9 @@ import pl.treksoft.kvision.i18n.I18n.trans import pl.treksoft.kvision.types.DateSerializer import pl.treksoft.kvision.types.KFile import pl.treksoft.kvision.types.toStringF -import pl.treksoft.kvision.utils.JSON import kotlin.js.Date import kotlin.js.Json +import kotlin.reflect.KClass import kotlin.reflect.KProperty1 /** @@ -75,7 +75,11 @@ private class FormMapWrapper<out V>(private val map: Map<String, V>) : Map<Strin * @param serializer a serializer for model type */ @Suppress("TooManyFunctions") -class Form<K : Any>(private val panel: FormPanel<K>? = null, private val serializer: KSerializer<K>) { +class Form<K : Any>( + private val panel: FormPanel<K>? = null, + private val serializer: KSerializer<K>, + private val customSerializers: Map<KClass<*>, KSerializer<*>>? = null +) { val modelFactory: (Map<String, Any?>) -> K val fields: MutableMap<String, FormControl> = mutableMapOf() @@ -106,7 +110,12 @@ class Form<K : Any>(private val panel: FormPanel<K>? = null, private val seriali else -> listOf(entry.key to entry.value) } }.toMap() - Mapper(context = serializersModuleOf(Date::class, DateSerializer)).unmapNullable( + val serializersModule = if (customSerializers == null) { + serializersModuleOf(Date::class, DateSerializer) + } else { + serializersModuleOf(customSerializers + (Date::class to DateSerializer)) + } + Mapper(context = serializersModule).unmapNullable( serializer, FormMapWrapper(map) ) @@ -142,6 +151,24 @@ class Form<K : Any>(private val panel: FormPanel<K>? = null, private val seriali } /** + * Adds a string control to the form bound to custom field type. + * @param key key identifier of the control + * @param control the string form control + * @param required determines if the control is required + * @param requiredMessage optional required validation message + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form + */ + fun <C : StringFormControl> addCustom( + key: KProperty1<K, Any?>, control: C, required: Boolean = false, requiredMessage: String? = null, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): Form<K> { + return addInternal(key, control, required, requiredMessage, validatorMessage, validator) + } + + /** * Adds a boolean control to the form. * @param key key identifier of the control * @param control the boolean form control @@ -278,13 +305,22 @@ class Form<K : Any>(private val panel: FormPanel<K>? = null, private val seriali return modelFactory(map.withDefault { null }) } - /** * Returns current data model as JSON. * @return data model as JSON */ fun getDataJson(): Json { - return kotlin.js.JSON.parse(JSON.plain.stringify(serializer, getData())) + val serializersModule = if (customSerializers == null) { + serializersModuleOf(Date::class, DateSerializer) + } else { + serializersModuleOf(customSerializers + (Date::class to DateSerializer)) + } + return JSON.parse( + kotlinx.serialization.json.Json(context = serializersModule).stringify( + serializer, + getData() + ) + ) } /** @@ -325,14 +361,13 @@ class Form<K : Any>(private val panel: FormPanel<K>? = null, private val seriali @UseExperimental(ImplicitReflectionSerializer::class) inline fun <reified K : Any> create( panel: FormPanel<K>? = null, + customSerializers: Map<KClass<*>, KSerializer<*>>? = null, noinline init: (Form<K>.() -> Unit)? = null ): Form<K> { - val form = Form(panel, K::class.serializer()) + val form = Form(panel, K::class.serializer(), customSerializers) init?.invoke(form) return form } - - } } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt index 9c9aba80..1e915ac9 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt @@ -213,7 +213,7 @@ interface StringFormControl : FormControl { override fun getValue(): String? = value override fun setValue(v: Any?) { - value = v as? String + value = v as? String ?: v?.toString() } override fun getValueAsString(): String? = value diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt index 62f3395e..77c324c5 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt @@ -35,6 +35,7 @@ import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.types.KFile import kotlin.js.Date import kotlin.js.Json +import kotlin.reflect.KClass import kotlin.reflect.KProperty1 /** @@ -106,7 +107,7 @@ open class FormPanel<K : Any>( method: FormMethod? = null, action: String? = null, enctype: FormEnctype? = null, private val type: FormType? = null, condensed: Boolean = false, horizRatio: FormHorizontalRatio = FormHorizontalRatio.RATIO_2, classes: Set<String> = setOf(), - serializer: KSerializer<K> + serializer: KSerializer<K>, customSerializers: Map<KClass<*>, KSerializer<*>>? = null ) : SimplePanel(classes) { /** @@ -176,7 +177,7 @@ open class FormPanel<K : Any>( * Internal property. */ @Suppress("LeakingThis") - val form = Form(this, serializer) + val form = Form(this, serializer, customSerializers) /** * @suppress * Internal property. @@ -279,6 +280,26 @@ open class FormPanel<K : Any>( } /** + * Adds a string control to the form panel bound to custom field type. + * @param key key identifier of the control + * @param control the string form control + * @param required determines if the control is required + * @param requiredMessage optional required validation message + * @param legend put this control inside a fieldset with given legend + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form panel + */ + open fun <C : StringFormControl> addCustom( + key: KProperty1<K, Any?>, control: C, required: Boolean = false, requiredMessage: String? = null, + legend: String? = null, + validatorMessage: ((C) -> String?)? = null, + validator: ((C) -> Boolean?)? = null + ): FormPanel<K> { + return addInternal(key, control, required, requiredMessage, legend, validatorMessage, validator) + } + + /** * Adds a boolean control to the form panel. * @param key key identifier of the control * @param control the boolean form control @@ -442,10 +463,21 @@ open class FormPanel<K : Any>( method: FormMethod? = null, action: String? = null, enctype: FormEnctype? = null, type: FormType? = null, condensed: Boolean = false, horizRatio: FormHorizontalRatio = FormHorizontalRatio.RATIO_2, classes: Set<String> = setOf(), + customSerializers: Map<KClass<*>, KSerializer<*>>? = null, noinline init: (FormPanel<K>.() -> Unit)? = null ): FormPanel<K> { val formPanel = - FormPanel(method, action, enctype, type, condensed, horizRatio, classes, K::class.serializer()) + FormPanel( + method, + action, + enctype, + type, + condensed, + horizRatio, + classes, + K::class.serializer(), + customSerializers + ) init?.invoke(formPanel) return formPanel } @@ -462,9 +494,10 @@ inline fun <reified K : Any> Container.formPanel( method: FormMethod? = null, action: String? = null, enctype: FormEnctype? = null, type: FormType? = null, condensed: Boolean = false, horizRatio: FormHorizontalRatio = FormHorizontalRatio.RATIO_2, classes: Set<String> = setOf(), + customSerializers: Map<KClass<*>, KSerializer<*>>? = null, noinline init: (FormPanel<K>.() -> Unit)? = null ): FormPanel<K> { - val formPanel = create<K>(method, action, enctype, type, condensed, horizRatio, classes) + val formPanel = create<K>(method, action, enctype, type, condensed, horizRatio, classes, customSerializers) init?.invoke(formPanel) this.add(formPanel) return formPanel |