diff options
author | Robert Jaros <rjaros@finn.pl> | 2017-11-25 13:39:39 +0100 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2017-11-25 13:39:39 +0100 |
commit | 343390df5a0e01f45539939291c35d535a1b8af6 (patch) | |
tree | fcba5b87efa1b740bd5a011739af1e066cba28f0 /src/main/kotlin/pl | |
parent | 4a31ea44d479358658a614ad56a5675436260813 (diff) | |
download | kvision-343390df5a0e01f45539939291c35d535a1b8af6.tar.gz kvision-343390df5a0e01f45539939291c35d535a1b8af6.tar.bz2 kvision-343390df5a0e01f45539939291c35d535a1b8af6.zip |
Form validation
Diffstat (limited to 'src/main/kotlin/pl')
35 files changed, 598 insertions, 172 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt index 8e7fcb3b..82651b71 100644 --- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt +++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt @@ -7,14 +7,21 @@ import pl.treksoft.kvision.data.DataComponent import pl.treksoft.kvision.data.DataContainer import pl.treksoft.kvision.dropdown.DD.* import pl.treksoft.kvision.dropdown.DropDown +import pl.treksoft.kvision.form.Form +import pl.treksoft.kvision.form.FormPanel import pl.treksoft.kvision.form.INPUTSIZE +import pl.treksoft.kvision.form.bool import pl.treksoft.kvision.form.check.CheckBox +import pl.treksoft.kvision.form.check.Radio +import pl.treksoft.kvision.form.date import pl.treksoft.kvision.form.select.AjaxOptions import pl.treksoft.kvision.form.select.SELECTWIDTHTYPE import pl.treksoft.kvision.form.select.Select import pl.treksoft.kvision.form.select.SelectInput import pl.treksoft.kvision.form.select.SelectOptGroup import pl.treksoft.kvision.form.select.SelectOption +import pl.treksoft.kvision.form.string +import pl.treksoft.kvision.form.text.Password import pl.treksoft.kvision.form.text.RichText import pl.treksoft.kvision.form.text.TEXTINPUTTYPE import pl.treksoft.kvision.form.text.Text @@ -40,6 +47,35 @@ import kotlin.js.Date class Showcase : ApplicationBase() { override fun start(state: Map<String, Any>) { + data class DataForm(val a: String?, val b: Boolean?, val c: Date?) + + val f = DataForm("ala", true, Date()) + val form = Form { + DataForm(it.string("a"), it.bool("b"), it.date("c")) + } + form.add("a", Text()) + form.add("b", CheckBox()) + form.add("c", DateTime()) + form.setData(f) + val ret = form.getData() + console.log(ret) + + class DataFormMap(val map: Map<String, Any?>) { + val name: String by map + val age: Date by map + } + + val fm = DataFormMap(mapOf("name" to "Ala", "age" to Date())) + val formm = Form { + DataFormMap(it) + } + formm.add("name", Text()) + formm.add("age", DateTime()) + formm.setData(fm) + val retm = formm.getData() + console.log(retm.name) + console.log(retm.age) + val root = Root("showcase") class Model(p: Boolean, t: String) : DataComponent() { @@ -286,6 +322,7 @@ class Showcase : ApplicationBase() { date.value = "2017-01-16".toDateF("YYYY-MM-DD") date.showPopup() date.weekStart = 1 + date4.value = null date4.format = "mm:HH" date4.disabled = !date4.disabled } @@ -368,6 +405,58 @@ class Showcase : ApplicationBase() { } } + class Formularz(val map: Map<String, Any?>) { + val text: String? by map + val password: String? by map + val textarea: String? by map + val richtext: String? by map + val data: Date? by map + val checkbox: Boolean by map + val radio: Boolean by map + val select: String? by map + } + + val formPanel = FormPanel() { + Formularz(it) + }.apply { + add("text", Text(label = "Tekst"), required = true, validatorMessage = { "Wprowadź tylko cyfry" }) { + it.getValue()?.matches("^[0-9]+$") + } + add("password", Password(label = "Hasło"), required = true, + validatorMessage = { "Wprowadź co najmniej 5 znaków" }) { + (it.getValue()?.length ?: 0) >= 5 + } + add("textarea", TextArea(label = "Obszar"), required = true) + add("richtext", RichText(label = "Obszar WYSIWYG"), required = true) + add("data", DateTime(format = "YYYY-MM-DD", label = "Data"), required = true) + add("checkbox", CheckBox(label = "Checkbox")) { it.getValue() } + add("radio", Radio(label = "Radiobutton")) { it.getValue() } + add("select", Select(options = listOf("a" to "Pierwsza opcja", "b" to "Druga opcja"), + label = "Wybierz opcje").apply { + // selectWidthType = SELECTWIDTHTYPE.FIT + emptyOption = true + }, required = true) + + validator = { + var result = it["text"] == it["textarea"] + if (!result) { + it.getControl("text")?.validatorError = "Niezgodne dane" + it.getControl("textarea")?.validatorError = "Niezgodne dane" + } + result + } + validatorMessage = { "Pole Tekst i Obszar muszą być takie same!" } + } + root.add(formPanel) + val formButton = Button("Pokaż dane").setEventListener<Button> { + click = { + console.log(formPanel.validate()) + console.log(formPanel.getData().map.toString()) +// formPanel.setData(Formularz(mapOf("zazn" to false, "select" to "a"))) + } + } + formPanel.add(formButton) + val dd = DropDown("Dropdown", listOf("abc" to "#!/x", "def" to "#!/y"), "flag") root.add(dd) dd.setEventListener<DropDown> { diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Component.kt b/src/main/kotlin/pl/treksoft/kvision/core/Component.kt new file mode 100644 index 00000000..af5ac830 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/core/Component.kt @@ -0,0 +1,26 @@ +package pl.treksoft.kvision.core + +import com.github.snabbdom.VNode +import org.w3c.dom.Node +import pl.treksoft.jquery.JQuery + +@Suppress("TooManyFunctions") +interface Component { + var parent: Component? + var visible: Boolean + var width: CssSize? + var height: CssSize? + + fun addCssClass(css: String): Widget + fun removeCssClass(css: String): Widget + fun addSurroundingCssClass(css: String): Widget + fun removeSurroundingCssClass(css: String): Widget + + fun renderVNode(): VNode + fun getElement(): Node? + fun getElementJQuery(): JQuery? + fun getElementJQueryD(): dynamic + fun clearParent(): Component + fun getRoot(): Root? + fun dispose() +} diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt index 4621a050..da436aba 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt @@ -3,12 +3,12 @@ package pl.treksoft.kvision.core import com.github.snabbdom.VNode interface Container { - var parent: Widget? + var parent: Component? var visible: Boolean fun renderVNode(): VNode - fun add(child: Widget): Container - fun addAll(children: List<Widget>): Container - fun remove(child: Widget): Container + fun add(child: Component): Container + fun addAll(children: List<Component>): Container + fun remove(child: Component): Container fun removeAll(): Container - fun getChildren(): List<Widget> + fun getChildren(): List<Component> } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/KVObject.kt b/src/main/kotlin/pl/treksoft/kvision/core/KVObject.kt deleted file mode 100644 index aa90ccf8..00000000 --- a/src/main/kotlin/pl/treksoft/kvision/core/KVObject.kt +++ /dev/null @@ -1,3 +0,0 @@ -package pl.treksoft.kvision.core - -interface KVObject diff --git a/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt b/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt index 8b883d82..12ed797e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt @@ -2,9 +2,9 @@ package pl.treksoft.kvision.core import pl.treksoft.kvision.snabbdom.StringPair -abstract class StyledComponent : KVObject { +abstract class StyledComponent : Component { - var width: CssSize? = null + override var width: CssSize? = null set(value) { field = value refresh() @@ -19,7 +19,7 @@ abstract class StyledComponent : KVObject { field = value refresh() } - var height: CssSize? = null + override var height: CssSize? = null set(value) { field = value refresh() @@ -138,7 +138,7 @@ abstract class StyledComponent : KVObject { private var snStyleCache: List<StringPair>? = null - protected open fun refresh(): StyledComponent { + open fun refresh(): StyledComponent { snStyleCache = null return this } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt index 46aa2a90..fec62ec7 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt @@ -21,13 +21,13 @@ import pl.treksoft.kvision.snabbdom.snStyle open class Widget(classes: Set<String> = setOf()) : StyledComponent() { internal val classes = classes.toMutableSet() + internal val surroundingClasses: MutableSet<String> = mutableSetOf() internal val internalListeners = mutableListOf<SnOn<Widget>.() -> Unit>() internal val listeners = mutableListOf<SnOn<Widget>.() -> Unit>() - var parent: Widget? = null - internal set + override var parent: Component? = null - open var visible: Boolean = true + override var visible: Boolean = true set(value) { val oldField = field field = value @@ -65,8 +65,15 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return t } - open fun renderVNode(): VNode { - return render() + override fun renderVNode(): VNode { + return if (surroundingClasses.isEmpty()) { + render() + } else { + val opt = snOpt { + `class` = snClasses(surroundingClasses.map { c -> c to true }) + } + h("div", opt, arrayOf(render())) + } } protected open fun render(): VNode { @@ -258,31 +265,43 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return this } - open fun addCssClass(css: String): Widget { + override fun addCssClass(css: String): Widget { this.classes.add(css) refresh() return this } - open fun removeCssClass(css: String): Widget { + override fun removeCssClass(css: String): Widget { this.classes.remove(css) refresh() return this } - open fun getElement(): Node? { + override fun addSurroundingCssClass(css: String): Widget { + this.surroundingClasses.add(css) + refresh() + return this + } + + override fun removeSurroundingCssClass(css: String): Widget { + this.surroundingClasses.remove(css) + refresh() + return this + } + + override fun getElement(): Node? { return this.vnode?.elm } - open fun getElementJQuery(): JQuery? { + override fun getElementJQuery(): JQuery? { return getElement()?.let { jQuery(it) } } - open fun getElementJQueryD(): dynamic { + override fun getElementJQueryD(): dynamic { return getElement()?.let { jQuery(it).asDynamic() } } - internal fun clearParent(): Widget { + override fun clearParent(): Widget { this.parent = null return this } @@ -309,7 +328,7 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { protected open fun afterDestroy() { } - internal open fun getRoot(): Root? { + override fun getRoot(): Root? { return this.parent?.getRoot() } @@ -333,6 +352,6 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return this.getElement()?.dispatchEvent(event) } - open fun dispose() { + override fun dispose() { } } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt b/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt index 6f6c2f57..26f9308d 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt @@ -2,7 +2,7 @@ package pl.treksoft.kvision.core import com.github.snabbdom.VNode -open class WidgetWrapper(internal var delegate: Widget?, classes: Set<String> = setOf()) : Widget(classes) { +open class WidgetWrapper(internal var delegate: Component?, classes: Set<String> = setOf()) : Widget(classes) { override var visible get() = delegate?.visible == true diff --git a/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt b/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt index 5af2eb66..019ee414 100644 --- a/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt +++ b/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt @@ -3,6 +3,7 @@ package pl.treksoft.kvision.data import com.github.snabbdom.VNode import com.lightningkite.kotlin.observable.list.ObservableList import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.panel.VPanel @@ -25,17 +26,17 @@ class DataContainer<M : DataComponent, C : Widget>(val model: ObservableList<M>, update() } - override fun add(child: Widget): Container { + override fun add(child: Component): Container { this.child.add(child) return this } - override fun addAll(children: List<Widget>): Container { + override fun addAll(children: List<Component>): Container { this.child.addAll(children) return this } - override fun remove(child: Widget): Container { + override fun remove(child: Component): Container { this.child.remove(child) return this } @@ -45,7 +46,7 @@ class DataContainer<M : DataComponent, C : Widget>(val model: ObservableList<M>, return this } - override fun getChildren(): List<Widget> { + override fun getChildren(): List<Component> { return this.child.getChildren() } diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt index 3f6ca828..880cb436 100644 --- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt +++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt @@ -1,7 +1,7 @@ package pl.treksoft.kvision.dropdown import com.github.snabbdom.VNode -import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.html.BUTTONSTYLE import pl.treksoft.kvision.html.Button import pl.treksoft.kvision.html.LIST @@ -87,17 +87,17 @@ open class DropDown(text: String, elements: List<StringPair>? = null, icon: Stri var counter = 0 } - override fun add(child: Widget): SimplePanel { + override fun add(child: Component): SimplePanel { list.add(child) return this } - override fun addAll(children: List<Widget>): SimplePanel { + override fun addAll(children: List<Component>): SimplePanel { list.addAll(children) return this } - override fun remove(child: Widget): SimplePanel { + override fun remove(child: Component): SimplePanel { list.remove(child) return this } @@ -107,7 +107,7 @@ open class DropDown(text: String, elements: List<StringPair>? = null, icon: Stri return this } - override fun getChildren(): List<Widget> { + override fun getChildren(): List<Component> { return list.getChildren() } 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) } diff --git a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt index 77e40349..08d56f4c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt +++ b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt @@ -1,6 +1,7 @@ package pl.treksoft.kvision.modal import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.Root import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.helpers.CloseIcon @@ -87,12 +88,12 @@ open class Modal(caption: String? = null, closeButton: Boolean = true, } } - override fun add(child: Widget): SimplePanel { + override fun add(child: Component): SimplePanel { body.add(child) return this } - override fun addAll(children: List<Widget>): SimplePanel { + override fun addAll(children: List<Component>): SimplePanel { body.addAll(children) return this } diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt index 6e037c28..376e34b9 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt @@ -1,6 +1,6 @@ package pl.treksoft.kvision.panel -import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.core.Component enum class SIDE { LEFT, @@ -11,11 +11,11 @@ enum class SIDE { } open class DockPanel(classes: Set<String> = setOf()) : SimplePanel(classes = classes) { - protected var left: Widget? = null - protected var center: Widget? = null - protected var right: Widget? = null - protected var up: Widget? = null - protected var down: Widget? = null + protected var left: Component? = null + protected var center: Component? = null + protected var right: Component? = null + protected var up: Component? = null + protected var down: Component? = null protected val mainContainer = FlexPanel(direction = FLEXDIR.COLUMN, justify = FLEXJUSTIFY.SPACEBETWEEN, alignItems = FLEXALIGNITEMS.STRETCH) @@ -27,7 +27,7 @@ open class DockPanel(classes: Set<String> = setOf()) : SimplePanel(classes = cla } @Suppress("MagicNumber") - open fun add(widget: Widget, position: SIDE): DockPanel { + open fun add(widget: Component, position: SIDE): DockPanel { when (position) { SIDE.UP -> { up?.let { mainContainer.remove(it) } @@ -58,16 +58,16 @@ open class DockPanel(classes: Set<String> = setOf()) : SimplePanel(classes = cla return this } - override fun add(child: Widget): DockPanel { + override fun add(child: Component): DockPanel { return this.add(child, SIDE.CENTER) } - override fun addAll(children: List<Widget>): DockPanel { + override fun addAll(children: List<Component>): DockPanel { children.forEach { this.add(it) } return this } - override fun remove(child: Widget): DockPanel { + override fun remove(child: Component): DockPanel { if (child == left) removeAt(SIDE.LEFT) if (child == center) removeAt(SIDE.CENTER) if (child == right) removeAt(SIDE.RIGHT) diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt index 6b6e11fb..80eddb23 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt @@ -1,6 +1,6 @@ package pl.treksoft.kvision.panel -import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.WidgetWrapper import pl.treksoft.kvision.snabbdom.StringPair @@ -73,22 +73,22 @@ open class FlexPanel(direction: FLEXDIR? = null, wrap: FLEXWRAP? = null, justify } @Suppress("LongParameterList") - fun add(child: Widget, order: Int? = null, grow: Int? = null, shrink: Int? = null, + fun add(child: Component, order: Int? = null, grow: Int? = null, shrink: Int? = null, basis: Int? = null, alignSelf: FLEXALIGNITEMS? = null, classes: Set<String> = setOf()): FlexPanel { addInternal(FlexWrapper(child, order, grow, shrink, basis, alignSelf, classes)) return this } - override fun add(child: Widget): FlexPanel { + override fun add(child: Component): FlexPanel { return add(child, null) } - override fun addAll(children: List<Widget>): FlexPanel { + override fun addAll(children: List<Component>): FlexPanel { children.forEach { add(it, null) } return this } - override fun remove(child: Widget): FlexPanel { + override fun remove(child: Component): FlexPanel { children.find { (it as FlexWrapper).delegate == child }?.let { super.remove(it) it.dispose() @@ -128,7 +128,7 @@ open class FlexPanel(direction: FLEXDIR? = null, wrap: FLEXWRAP? = null, justify } } -class FlexWrapper(delegate: Widget, private val order: Int? = null, private val grow: Int? = null, +class FlexWrapper(delegate: Component, private val order: Int? = null, private val grow: Int? = null, private val shrink: Int? = null, private val basis: Int? = null, private val alignSelf: FLEXALIGNITEMS? = null, classes: Set<String> = setOf()) : WidgetWrapper(delegate, classes) { diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt index cac5c79b..dac5867c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt @@ -1,6 +1,6 @@ package pl.treksoft.kvision.panel -import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.WidgetWrapper import pl.treksoft.kvision.snabbdom.StringPair @@ -112,23 +112,23 @@ open class GridPanel(autoColumns: String? = null, autoRows: String? = null, auto } @Suppress("LongParameterList") - fun add(child: Widget, columnStart: Int? = null, rowStart: Int? = null, + fun add(child: Component, columnStart: Int? = null, rowStart: Int? = null, columnEnd: String? = null, rowEnd: String? = null, area: String? = null, justifySelf: GRIDJUSTIFY? = null, alignSelf: GRIDALIGN? = null, classes: Set<String> = setOf()): GridPanel { addInternal(GridWrapper(child, columnStart, rowStart, columnEnd, rowEnd, area, justifySelf, alignSelf, classes)) return this } - override fun add(child: Widget): GridPanel { + override fun add(child: Component): GridPanel { return add(child, null, null) } - override fun addAll(children: List<Widget>): GridPanel { + override fun addAll(children: List<Component>): GridPanel { children.forEach { add(it, null, null) } return this } - override fun remove(child: Widget): GridPanel { + override fun remove(child: Component): GridPanel { children.find { (it as GridWrapper).delegate == child }?.let { super.remove(it) it.dispose() @@ -190,7 +190,7 @@ open class GridPanel(autoColumns: String? = null, autoRows: String? = null, auto } } -class GridWrapper(delegate: Widget, private val columnStart: Int? = null, private val rowStart: Int? = null, +class GridWrapper(delegate: Component, private val columnStart: Int? = null, private val rowStart: Int? = null, private val columnEnd: String? = null, private val rowEnd: String? = null, private val area: String? = null, private val justifySelf: GRIDJUSTIFY? = null, private val alignSelf: GRIDALIGN? = null, diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt index 3587ea8e..88d70a64 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt @@ -1,6 +1,6 @@ package pl.treksoft.kvision.panel -import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.WidgetWrapper import pl.treksoft.kvision.html.ALIGN import pl.treksoft.kvision.html.TAG @@ -15,7 +15,7 @@ enum class GRIDSIZE(val size: String) { const val MAX_COLUMNS = 12 -internal data class WidgetParam(val widget: Widget, val size: Int, val offset: Int) +internal data class WidgetParam(val widget: Component, val size: Int, val offset: Int) open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD, private var rows: Int = 0, private var cols: Int = 0, align: ALIGN? = null, @@ -29,7 +29,7 @@ open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD, internal val map = mutableMapOf<Int, MutableMap<Int, WidgetParam>>() private var auto: Boolean = true - open fun add(child: Widget, row: Int, col: Int, size: Int = 0, offset: Int = 0): ResponsiveGridPanel { + open fun add(child: Component, row: Int, col: Int, size: Int = 0, offset: Int = 0): ResponsiveGridPanel { val cRow = if (row < 0) 0 else row val cCol = if (col < 0) 0 else col if (row > rows - 1) rows = cRow + 1 @@ -40,17 +40,17 @@ open class ResponsiveGridPanel(private val gridsize: GRIDSIZE = GRIDSIZE.MD, return this } - override fun add(child: Widget): ResponsiveGridPanel { + override fun add(child: Component): ResponsiveGridPanel { return this.add(child, 0, this.cols) } - override fun addAll(children: List<Widget>): ResponsiveGridPanel { + override fun addAll(children: List<Component>): ResponsiveGridPanel { children.forEach { this.add(it) } return this } @Suppress("NestedBlockDepth") - override fun remove(child: Widget): ResponsiveGridPanel { + override fun remove(child: Component): ResponsiveGridPanel { for (i in 0 until rows) { val row = map[i] if (row != null) { diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt index e9cf503b..90362127 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt @@ -2,10 +2,11 @@ package pl.treksoft.kvision.panel import com.github.snabbdom.VNode import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.Widget open class SimplePanel(classes: Set<String> = setOf()) : Widget(classes), Container { - internal val children: MutableList<Widget> = mutableListOf() + internal val children: MutableList<Component> = mutableListOf() override fun render(): VNode { return kvh("div", childrenVNodes()) @@ -15,25 +16,25 @@ open class SimplePanel(classes: Set<String> = setOf()) : Widget(classes), Contai return children.filter { it.visible }.map { it.renderVNode() }.toTypedArray() } - protected fun addInternal(child: Widget): SimplePanel { + protected fun addInternal(child: Component): SimplePanel { children.add(child) child.parent = this refresh() return this } - override fun add(child: Widget): SimplePanel { + override fun add(child: Component): SimplePanel { return addInternal(child) } - override fun addAll(children: List<Widget>): SimplePanel { + override fun addAll(children: List<Component>): SimplePanel { this.children.addAll(children) children.map { it.parent = this } refresh() return this } - override fun remove(child: Widget): SimplePanel { + override fun remove(child: Component): SimplePanel { if (children.remove(child)) { child.clearParent() refresh() @@ -48,7 +49,7 @@ open class SimplePanel(classes: Set<String> = setOf()) : Widget(classes), Contai return this } - override fun getChildren(): List<Widget> { + override fun getChildren(): List<Component> { return ArrayList(children) } diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt index e8975dce..55bd2cca 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt @@ -1,7 +1,7 @@ package pl.treksoft.kvision.panel import com.github.snabbdom.VNode -import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.core.Component open class StackPanel(private val activateLast: Boolean = true, classes: Set<String> = setOf()) : SimplePanel(classes) { @@ -19,21 +19,21 @@ open class StackPanel(private val activateLast: Boolean = true, } } - override fun add(child: Widget): StackPanel { + override fun add(child: Component): StackPanel { super.add(child) if (activateLast) activeIndex = children.size - 1 else if (activeIndex == -1) activeIndex = 0 return this } - override fun addAll(children: List<Widget>): StackPanel { + override fun addAll(children: List<Component>): StackPanel { super.addAll(children) if (activateLast) activeIndex = this.children.size - 1 else if (activeIndex == -1) activeIndex = 0 return this } - override fun remove(child: Widget): StackPanel { + override fun remove(child: Component): StackPanel { super.remove(child) if (activeIndex > children.size - 1) activeIndex = children.size - 1 return this diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt index 4190dbae..e60d9480 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt @@ -1,7 +1,7 @@ package pl.treksoft.kvision.panel +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.ResString -import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.html.Link import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag @@ -25,7 +25,7 @@ open class TabPanel : SimplePanel(setOf()) { this.addInternal(content) } - open fun addTab(title: String, panel: Widget, icon: String? = null, + open fun addTab(title: String, panel: Component, icon: String? = null, image: ResString? = null): TabPanel { val tag = Tag(TAG.LI) tag.role = "presentation" @@ -53,16 +53,16 @@ open class TabPanel : SimplePanel(setOf()) { return this } - override fun add(child: Widget): TabPanel { + override fun add(child: Component): TabPanel { return addTab("", child) } - override fun addAll(children: List<Widget>): TabPanel { + override fun addAll(children: List<Component>): TabPanel { children.forEach { add(it) } return this } - override fun remove(child: Widget): TabPanel { + override fun remove(child: Component): TabPanel { val index = content.children.indexOf(child) return removeTab(index) } |