aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2017-11-03 15:16:42 +0100
committerRobert Jaros <rjaros@finn.pl>2017-11-03 15:16:42 +0100
commitb9a849b4ebf397b04b4b3c405de325b740b958aa (patch)
tree0be1b01f68064e0f62f295573acaf3579b3d7d82
parentd4d9ea0afaf76778f3bb588e501749867053ca5f (diff)
downloadkvision-b9a849b4ebf397b04b4b3c405de325b740b958aa.tar.gz
kvision-b9a849b4ebf397b04b4b3c405de325b740b958aa.tar.bz2
kvision-b9a849b4ebf397b04b4b3c405de325b740b958aa.zip
Select input components
-rw-r--r--build.gradle2
-rw-r--r--src/main/assets/js/bootstrap-select-i18n.min.js1
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/Showcase.kt86
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/SelectInput.kt203
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/SelectOptGroup.kt60
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/SelectOption.kt75
6 files changed, 404 insertions, 23 deletions
diff --git a/build.gradle b/build.gradle
index e58a071b..8e43c79b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -52,6 +52,8 @@ kotlinFrontend {
dependency "file-loader"
dependency "url-loader"
dependency("awesome-bootstrap-checkbox", "0.3.7")
+ dependency "bootstrap-select"
+ dependency "ajax-bootstrap-select"
dependency("snabbdom", "0.6.9")
dependency "snabbdom-virtualize"
dependency "navigo"
diff --git a/src/main/assets/js/bootstrap-select-i18n.min.js b/src/main/assets/js/bootstrap-select-i18n.min.js
new file mode 100644
index 00000000..4428d3c0
--- /dev/null
+++ b/src/main/assets/js/bootstrap-select-i18n.min.js
@@ -0,0 +1 @@
+!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"",noneResultsText:"",countSelectedText:function(a,b){return 1==a?"... ({n})":"... ({n})"},maxOptionsText:function(a,b){return[1==a?"🛇":"🛇",1==b?"🛇":"🛇"]},selectAllText:"++",deselectAllText:"--",multipleSeparator:", "}}(a)}); \ No newline at end of file
diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
index 282ea510..8821e94b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
@@ -2,26 +2,12 @@ package pl.treksoft.kvision
import com.lightningkite.kotlin.observable.list.observableListOf
import pl.treksoft.kvision.basic.Label
-import pl.treksoft.kvision.core.BGATTACH
-import pl.treksoft.kvision.core.BGREPEAT
-import pl.treksoft.kvision.core.BGSIZE
-import pl.treksoft.kvision.core.BORDERSTYLE
-import pl.treksoft.kvision.core.Background
-import pl.treksoft.kvision.core.Border
-import pl.treksoft.kvision.core.COLOR
-import pl.treksoft.kvision.core.Img
-import pl.treksoft.kvision.core.Root
+import pl.treksoft.kvision.core.*
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.CheckBox
-import pl.treksoft.kvision.form.INPUTSIZE
-import pl.treksoft.kvision.form.TEXTINPUTTYPE
-import pl.treksoft.kvision.form.Text
-import pl.treksoft.kvision.form.TextArea
-import pl.treksoft.kvision.form.TextAreaInput
-import pl.treksoft.kvision.form.TextInput
+import pl.treksoft.kvision.form.*
import pl.treksoft.kvision.html.*
import pl.treksoft.kvision.html.TAG.DIV
import pl.treksoft.kvision.html.TAG.H1
@@ -73,7 +59,7 @@ class Showcase : ApplicationBase() {
}
}
root.add(mbutton2)
- val textField = TextInput(placeholder = "Wprowadź hasło ...", value = "abc")
+ val textField = TextInput(value = "abc").apply { placeholder = "Wprowadź hasło ..." }
val mbutton3 = Button("Ukryj/Pokaż").setEventListener<Button> {
click = {
if (datac.visible) datac.hide() else datac.show()
@@ -82,6 +68,45 @@ class Showcase : ApplicationBase() {
}
root.add(mbutton3)
+ val select = SelectInput(listOf("klucz1" to "Klucz 1", "klucz2" to "Klucz 2"), "klucz2,klucz1", multiple = true)
+ root.add(select)
+
+ val mbuttons = Button("Select").setEventListener<Button> {
+ click = {
+ println(select.value)
+ }
+ }
+ root.add(mbuttons)
+
+ val select2 = SelectInput(value = "klucz1")
+ select2.add(SelectOption("klucz0", "Klucz 0", "Subtext 0", "flag"))
+ select2.add(SelectOption(divider = true))
+ select2.add(SelectOption("klucz1", "Klucz 1", "Subtext 1", "fa-flag"))
+ select2.add(SelectOption("klucz2", "Klucz 2", disabled = true))
+ root.add(select2)
+
+ val select3 = SelectInput().apply {
+ placeholder = "Wybierz opcje"
+ emptyOption = true
+ liveSearch = true
+ style = BUTTONSTYLE.WARNING
+ selectWidthType = SELECTWIDTHTYPE.FIT
+ }
+ select3.add(SelectOptGroup("Opcje pierwsze", listOf("k" to "Opcja pierwsza 1", "m" to "Opcja pierwsza 2")))
+ val sopt = SelectOptGroup("Opcje drugie", maxOptions = 2)
+ sopt.add(SelectOption("a", "Opcja druga 1", "Subtext 1"))
+ sopt.add(SelectOption("b", "Opcja druga 2"))
+ sopt.add(SelectOption("c", "Opcja druga 3").apply { color = Color(COLOR.RED) })
+ select3.add(sopt)
+ root.add(select3)
+
+ val mbuttons3 = Button("Select").setEventListener<Button> {
+ click = {
+ println(select3.value)
+ }
+ }
+ root.add(mbuttons3)
+
val container = SimplePanel(setOf("abc", "def"))
val h1 = Tag(H1, "To jest <i>test pisania</i> tekstu", false, null, classes = setOf("test", "test2"))
container.add(h1)
@@ -109,7 +134,7 @@ class Showcase : ApplicationBase() {
val passwordField = TextInput(TEXTINPUTTYPE.PASSWORD)
root.add(passwordField)
- val textField2 = TextInput(placeholder = "Disabled")
+ val textField2 = TextInput().apply { placeholder = "Disabled" }
textField2.disabled = true
textField2.size = INPUTSIZE.LARGE
root.add(textField2)
@@ -140,13 +165,20 @@ class Showcase : ApplicationBase() {
change = { e -> println("rchange" + self.value) }
}*/
- val text = Text(placeholder = "Pole formularza", maxlength = 5, label = "To jest pole")
+ val text = Text(label = "To jest pole").apply {
+ placeholder = "Pole formularza"
+ maxlength = 5
+ }
root.add(text)
- val textareainput = TextAreaInput(cols = 5, rows = 2, placeholder = "...", value = "To jest tekst\nTo jest <b>te</b></textarea>kst2")
+ val textareainput = TextAreaInput(cols = 5, rows = 2, value = "To jest tekst\nTo jest <b>te</b></textarea>kst2").apply {
+ placeholder = "..."
+ }
root.add(textareainput)
- val textarea = TextArea(cols = 5, rows = 2, placeholder = "...", value = "To jest tekst\nTo jest <b>te</b></textarea>kst2", label = "Pole długie")
+ val textarea = TextArea(cols = 5, rows = 2, value = "To jest tekst\nTo jest <b>te</b></textarea>kst2", label = "Pole długie").apply {
+ placeholder = "..."
+ }
root.add(textarea)
textarea.setEventListener<TextArea> {
input = { e ->
@@ -171,13 +203,21 @@ class Showcase : ApplicationBase() {
val dd2 = DropDown("Dropdown2", listOf("abc" to "#!/abc", "def" to "#!/def", "xyz" to DISABLED.type,
"Header" to HEADER.type, "Separtatorek" to SEPARATOR.type
- ), "flag", dropup = true)
+ ), "flag").apply { dropup = true }
root.add(dd2)
dd2.setEventListener<DropDown> {
hideBsDropdown = { e -> println("hide" + e.detail) }
hiddenBsDropdown = { e -> println("hidden" + e.detail) }
}
+ val ddbutton = Button("Toggle").setEventListener<Button> {
+ click = {
+ console.log("x")
+ dd2.toggle()
+ }
+ }
+ root.add(ddbutton)
+
val dd3 = DropDown("Dropdown3", icon = "file")
dd3.add(Tag(TAG.H4, "ABC"))
dd3.add(Button("To jest button"))
@@ -362,7 +402,7 @@ class Showcase : ApplicationBase() {
}
}
root.add(button2)
- val button3 = Button("To jest przycisk IMG", image = Img("kotlin.png"))
+ val button3 = Button("To jest przycisk IMG").apply { image = Img("kotlin.png") }
button3.setEventListener {
click = { e ->
Confirm.show("Pytanie", "Czy na pewno chcesz kliknąć przycisk?", noCallback = { println("no") }) {
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/SelectInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/SelectInput.kt
new file mode 100644
index 00000000..61c0240c
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/SelectInput.kt
@@ -0,0 +1,203 @@
+package pl.treksoft.kvision.form
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.core.CssSize
+import pl.treksoft.kvision.html.BUTTONSTYLE
+import pl.treksoft.kvision.panel.SimplePanel
+import pl.treksoft.kvision.snabbdom.StringBoolPair
+import pl.treksoft.kvision.snabbdom.StringPair
+
+private val _aKVNULL = "#kvnull"
+
+enum class SELECTWIDTHTYPE(val value: String) {
+ AUTO("auto"),
+ FIT("fit")
+}
+
+class SelectInput(options: List<StringPair>? = null, override var value: String? = null,
+ multiple: Boolean = false, classes: Set<String> = setOf()) : SimplePanel(classes), StringFormField {
+
+ private var options = options
+ set(value) {
+ field = value
+ setChildrenFromOptions()
+ }
+
+ @Suppress("LeakingThis")
+ var startValue: String? = value
+ set(value) {
+ field = value
+ this.value = value
+ refresh()
+ }
+ var name: String? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var multiple: Boolean = multiple
+ set(value) {
+ field = value
+ refresh()
+ }
+ var maxOptions: Int? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var liveSearch: Boolean = false
+ set(value) {
+ field = value
+ refresh()
+ }
+ var placeholder: String? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var style: BUTTONSTYLE? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var selectWidth: CssSize? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var selectWidthType: SELECTWIDTHTYPE? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var emptyOption: Boolean = false
+ set(value) {
+ field = value
+ setChildrenFromOptions()
+ }
+ override var disabled: Boolean = false
+ set(value) {
+ field = value
+ refresh()
+ }
+ var autofocus: Boolean? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ override var size: INPUTSIZE? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ init {
+ setChildrenFromOptions()
+ this.setInternalEventListener<SelectInput> {
+ change = {
+ val v = getElementJQuery()?.`val`()
+ self.value = v?.let {
+ if (self.multiple) {
+ @Suppress("UNCHECKED_CAST")
+ val arr = it as? Array<String>
+ if (arr != null && arr.isNotEmpty()) {
+ arr.joinToString()
+ } else {
+ null
+ }
+ } else {
+ val vs = it as String
+ if (_aKVNULL == vs) {
+ null
+ } else {
+ vs
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun render(): VNode {
+ return kvh("select", childrenVNodes())
+ }
+
+ private fun setChildrenFromOptions() {
+ this.removeAll()
+ if (emptyOption) {
+ this.add(SelectOption(_aKVNULL, ""))
+ }
+ options?.let {
+ val c = it.map {
+ SelectOption(it.first, it.second)
+ }
+ this.addAll(c)
+ }
+ }
+
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ cl.add("selectpicker" to true)
+ size?.let {
+ cl.add(it.className to true)
+ }
+ return cl
+ }
+
+ override fun getSnAttrs(): List<StringPair> {
+ val sn = super.getSnAttrs().toMutableList()
+ name?.let {
+ sn.add("name" to it)
+ }
+ if (multiple) {
+ sn.add("multiple" to "true")
+ }
+ maxOptions?.let {
+ sn.add("data-max-options" to "" + it)
+ }
+ if (liveSearch) {
+ sn.add("data-live-search" to "true")
+ }
+ placeholder?.let {
+ sn.add("title" to it)
+ }
+ autofocus?.let {
+ if (it) {
+ sn.add("autofocus" to "autofocus")
+ }
+ }
+ if (disabled) {
+ sn.add("disabled" to "true")
+ }
+ val btnStyle = style?.className ?: "btn-default"
+ when (size) {
+ INPUTSIZE.LARGE -> {
+ sn.add("data-style" to "$btnStyle btn-lg")
+ }
+ INPUTSIZE.SMALL -> {
+ sn.add("data-style" to "$btnStyle btn-sm")
+ }
+ else -> {
+ sn.add("data-style" to btnStyle)
+ }
+ }
+ selectWidthType?.let {
+ sn.add("data-width" to it.value)
+ } ?: selectWidth?.let {
+ sn.add("data-width" to it.first.toString() + it.second.unit)
+ }
+ return sn
+ }
+
+ @Suppress("UnsafeCastFromDynamic")
+ override fun afterInsert(node: VNode) {
+ getElementJQueryD()?.selectpicker("render")
+ value?.let {
+ if (multiple) {
+ getElementJQueryD()?.selectpicker("val", it.split(",").toTypedArray())
+ } else {
+ getElementJQueryD()?.selectpicker("val", it)
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/SelectOptGroup.kt b/src/main/kotlin/pl/treksoft/kvision/form/SelectOptGroup.kt
new file mode 100644
index 00000000..22483777
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/SelectOptGroup.kt
@@ -0,0 +1,60 @@
+package pl.treksoft.kvision.form
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.panel.SimplePanel
+import pl.treksoft.kvision.snabbdom.StringPair
+
+class SelectOptGroup(label: String, options: List<StringPair>? = null, maxOptions: Int? = null,
+ disabled: Boolean = false, classes: Set<String> = setOf()) : SimplePanel(classes) {
+
+ var label: String = label
+ set(value) {
+ field = value
+ refresh()
+ }
+ private var options = options
+ set(value) {
+ field = value
+ setChildrenFromOptions()
+ }
+ var maxOptions: Int? = maxOptions
+ set(value) {
+ field = value
+ refresh()
+ }
+ var disabled: Boolean = disabled
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ init {
+ setChildrenFromOptions()
+ }
+
+ override fun render(): VNode {
+ return kvh("optgroup", childrenVNodes())
+ }
+
+ private fun setChildrenFromOptions() {
+ this.removeAll()
+ options?.let {
+ val c = it.map {
+ SelectOption(it.first, it.second)
+ }
+ this.addAll(c)
+ }
+ }
+
+ override fun getSnAttrs(): List<StringPair> {
+ val sn = super.getSnAttrs().toMutableList()
+ sn.add("label" to label)
+ maxOptions?.let {
+ sn.add("data-max-options" to "" + it)
+ }
+ if (disabled) {
+ sn.add("disabled" to "true")
+ }
+ return sn
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/SelectOption.kt b/src/main/kotlin/pl/treksoft/kvision/form/SelectOption.kt
new file mode 100644
index 00000000..48412e17
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/SelectOption.kt
@@ -0,0 +1,75 @@
+package pl.treksoft.kvision.form
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.core.Widget
+import pl.treksoft.kvision.snabbdom.StringPair
+
+open class SelectOption(value: String? = null, label: String? = null, subtext: String? = null, icon: String? = null,
+ divider: Boolean = false, disabled: Boolean = false,
+ classes: Set<String> = setOf()) : Widget(classes) {
+
+ var value: String? = value
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ var label: String? = label
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ var subtext: String? = subtext
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ var icon: String? = icon
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ var divider: Boolean = divider
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ var disabled: Boolean = disabled
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ override fun render(): VNode {
+ return kvh("option", arrayOf(label ?: value))
+ }
+
+ override fun getSnAttrs(): List<StringPair> {
+ val sn = super.getSnAttrs().toMutableList()
+ value?.let {
+ sn.add("value" to it)
+ }
+ if (!divider) {
+ subtext?.let {
+ sn.add("data-subtext" to it)
+ }
+ icon?.let {
+ if (it.startsWith("fa-")) {
+ sn.add("data-icon" to "fa $it")
+ } else {
+ sn.add("data-icon" to "glyphicon-$it")
+ }
+ }
+ if (disabled) {
+ sn.add("disabled" to "true")
+ }
+ } else {
+ sn.add("data-divider" to "true")
+ }
+ return sn
+ }
+}