aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2017-11-12 03:26:57 +0100
committerRobert Jaros <rjaros@finn.pl>2017-11-12 03:26:57 +0100
commitc5c29491437f1b9de2ab6bff05a1455b42edfcfc (patch)
treeb9d20472a9427d1bf8d8880c52e206333ca94513 /src
parenta4343ed3c4021db99de0fbc3f7c76929ad758265 (diff)
downloadkvision-c5c29491437f1b9de2ab6bff05a1455b42edfcfc.tar.gz
kvision-c5c29491437f1b9de2ab6bff05a1455b42edfcfc.tar.bz2
kvision-c5c29491437f1b9de2ab6bff05a1455b42edfcfc.zip
DateTimePicker components
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/Showcase.kt55
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/FormField.kt7
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt12
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt142
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt226
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/snabbdom/Types.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt12
-rw-r--r--src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt33
9 files changed, 491 insertions, 2 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
index 084b60d6..8e7fcb3b 100644
--- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt
@@ -21,6 +21,8 @@ import pl.treksoft.kvision.form.text.Text
import pl.treksoft.kvision.form.text.TextArea
import pl.treksoft.kvision.form.text.TextAreaInput
import pl.treksoft.kvision.form.text.TextInput
+import pl.treksoft.kvision.form.time.DateTime
+import pl.treksoft.kvision.form.time.DateTimeInput
import pl.treksoft.kvision.html.*
import pl.treksoft.kvision.html.TAG.DIV
import pl.treksoft.kvision.html.TAG.H1
@@ -32,6 +34,8 @@ import pl.treksoft.kvision.routing.routing
import pl.treksoft.kvision.snabbdom.obj
import pl.treksoft.kvision.utils.perc
import pl.treksoft.kvision.utils.px
+import pl.treksoft.kvision.utils.toDateF
+import kotlin.js.Date
class Showcase : ApplicationBase() {
@@ -237,6 +241,57 @@ class Showcase : ApplicationBase() {
}
root.add(mbuttons9)
+ val date = DateTimeInput().apply {
+ placeholder = "Wprowadź datę"
+ size = INPUTSIZE.LARGE
+ todayBtn = true
+ showMeridian = true
+ daysOfWeekDisabled = arrayOf(0, 6)
+
+ }
+ root.add(date)
+
+ val date2 = DateTimeInput(Date(), format = "DD-MM-YY").apply {
+ disabled = true
+ }
+ root.add(date2)
+
+ val date3 = DateTimeInput(Date(), format = "DD-MM-YYYY hh:mm A").apply {
+ readonly = true
+ showMeridian = true
+ }
+ root.add(date3)
+
+ val date4 = DateTime(Date(), format = "HH:mm", label = "Wprowadź datę wpływu")
+ date4.setEventListener<DateTime> {
+ showBsDateTime = {
+ println("show dt")
+ }
+ hideBsDateTime = {
+ println("hide dt")
+ }
+ }
+ root.add(date4)
+
+ val mbuttons10 = Button("Sprawdz daty").setEventListener<Button> {
+ click = {
+ println(date.value)
+ println(date.getValueAsString())
+ println(date2.value)
+ println(date2.getValueAsString())
+ println(date3.value)
+ println(date3.getValueAsString())
+ println(date4.value)
+ println(date4.getValueAsString())
+ date.value = "2017-01-16".toDateF("YYYY-MM-DD")
+ date.showPopup()
+ date.weekStart = 1
+ date4.format = "mm:HH"
+ date4.disabled = !date4.disabled
+ }
+ }
+ root.add(mbuttons10)
+
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)
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt
index e3c34190..65a7fe6e 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt
@@ -29,6 +29,9 @@ object KVManager {
private val bootstrapSelectAjaxI18n = require("./js/ajax-bootstrap-select.pl-PL.js")
private val trixCss = require("trix/dist/trix.css")
private val trix = require("trix")
+ private val bootstrapDateTimePickerCss = require("bootstrap-datetime-picker/css/bootstrap-datetimepicker.min.css")
+ private val bootstrapDateTimePicker = require("bootstrap-datetime-picker/js/bootstrap-datetimepicker.min.js")
+ internal val fecha = require("fecha")
private val sdPatch = Snabbdom.init(arrayOf(classModule, attributesModule, propsModule, styleModule,
eventListenersModule, datasetModule))
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormField.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormField.kt
index dd7ae745..503ee51d 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/FormField.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/FormField.kt
@@ -1,5 +1,7 @@
package pl.treksoft.kvision.form
+import kotlin.js.Date
+
enum class INPUTSIZE(val className: String) {
LARGE("input-lg"),
SMALL("input-sm")
@@ -25,3 +27,8 @@ 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/text/AbstractText.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt
index 4d0ebf51..0b50cbab 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt
@@ -1,9 +1,9 @@
package pl.treksoft.kvision.form.text
-import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.core.Widget
import pl.treksoft.kvision.form.FieldLabel
import pl.treksoft.kvision.form.StringFormField
+import pl.treksoft.kvision.panel.SimplePanel
import pl.treksoft.kvision.snabbdom.SnOn
abstract class AbstractText(label: String? = null, rich: Boolean = false) :
@@ -39,6 +39,16 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) :
set(value) {
input.disabled = value
}
+ var autofocus
+ get() = input.autofocus
+ set(value) {
+ input.autofocus = value
+ }
+ var readonly
+ get() = input.readonly
+ set(value) {
+ input.readonly = value
+ }
var label
get() = flabel.text
set(value) {
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt
new file mode 100644
index 00000000..ae732030
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt
@@ -0,0 +1,142 @@
+package pl.treksoft.kvision.form.time
+
+import pl.treksoft.kvision.core.Widget
+import pl.treksoft.kvision.form.DateFormField
+import pl.treksoft.kvision.form.FieldLabel
+import pl.treksoft.kvision.panel.SimplePanel
+import pl.treksoft.kvision.snabbdom.SnOn
+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 {
+
+ override var value
+ get() = input.value
+ set(value) {
+ input.value = value
+ }
+ var format
+ get() = input.format
+ set(value) {
+ input.format = value
+ }
+ var placeholder
+ get() = input.placeholder
+ set(value) {
+ input.placeholder = value
+ }
+ var name
+ get() = input.name
+ set(value) {
+ input.name = value
+ }
+ override var disabled
+ get() = input.disabled
+ set(value) {
+ input.disabled = value
+ }
+ var autofocus
+ get() = input.autofocus
+ set(value) {
+ input.autofocus = value
+ }
+ var readonly
+ get() = input.readonly
+ set(value) {
+ input.readonly = value
+ }
+ var weekStart
+ get() = input.weekStart
+ set(value) {
+ input.weekStart = value
+ }
+ var daysOfWeekDisabled
+ get() = input.daysOfWeekDisabled
+ set(value) {
+ input.daysOfWeekDisabled = value
+ }
+ var clearBtn
+ get() = input.clearBtn
+ set(value) {
+ input.clearBtn = value
+ }
+ var todayBtn
+ get() = input.todayBtn
+ set(value) {
+ input.todayBtn = value
+ }
+ var todayHighlight
+ get() = input.todayHighlight
+ set(value) {
+ input.todayHighlight = value
+ }
+ var minuteStep
+ get() = input.minuteStep
+ set(value) {
+ input.minuteStep = value
+ }
+ var showMeridian
+ get() = input.showMeridian
+ set(value) {
+ input.showMeridian = value
+ }
+ var label
+ get() = flabel.text
+ set(value) {
+ flabel.text = value
+ }
+ var rich
+ get() = flabel.rich
+ set(value) {
+ flabel.rich = value
+ }
+ override var size
+ get() = input.size
+ set(value) {
+ input.size = value
+ }
+
+ 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)
+
+ init {
+ this.addInternal(flabel)
+ @Suppress("LeakingThis")
+ input.eventTarget = this
+ this.addInternal(input)
+ counter++
+ }
+
+ companion object {
+ var counter = 0
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Widget {
+ input.setEventListener(block)
+ return this
+ }
+
+ override fun setEventListener(block: SnOn<Widget>.() -> Unit): Widget {
+ input.setEventListener(block)
+ return this
+ }
+
+ override fun removeEventListeners(): Widget {
+ input.removeEventListeners()
+ return this
+ }
+
+ open fun showPopup() {
+ input.showPopup()
+ }
+
+ open fun hidePopup() {
+ input.hidePopup()
+ }
+
+ override fun getValueAsString(): String? {
+ return input.getValueAsString()
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt
new file mode 100644
index 00000000..78321c10
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt
@@ -0,0 +1,226 @@
+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
+import pl.treksoft.kvision.snabbdom.obj
+import pl.treksoft.kvision.utils.toDateF
+import pl.treksoft.kvision.utils.toStringF
+import kotlin.js.Date
+
+const val DEFAULT_MINUTE_STEP = 5
+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 {
+
+
+ init {
+ this.setInternalEventListener<DateTimeInput> {
+ change = {
+ self.changeValue()
+ }
+ }
+ }
+
+ override var value: Date? = value
+ set(value) {
+ field = value
+ refreshState()
+ }
+ var format: String = format
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+ var placeholder: String? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var name: String? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ override var disabled: Boolean = false
+ set(value) {
+ field = value
+ refresh()
+ }
+ var autofocus: Boolean? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var readonly: Boolean? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ override var size: INPUTSIZE? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var weekStart: Int = 0
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+ var daysOfWeekDisabled: Array<Int> = arrayOf()
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+ var clearBtn: Boolean = true
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+ var todayBtn: Boolean = false
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+ var todayHighlight: Boolean = false
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+ var minuteStep: Int = DEFAULT_MINUTE_STEP
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+ var showMeridian: Boolean = false
+ set(value) {
+ field = value
+ refreshDatePicker()
+ }
+
+ override fun render(): VNode {
+ return kvh("input")
+ }
+
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ size?.let {
+ cl.add(it.className to true)
+ }
+ return cl
+ }
+
+ override fun getSnAttrs(): List<StringPair> {
+ val sn = super.getSnAttrs().toMutableList()
+ sn.add("type" to "text")
+ placeholder?.let {
+ sn.add("placeholder" to it)
+ }
+ name?.let {
+ sn.add("name" to it)
+ }
+ autofocus?.let {
+ if (it) {
+ sn.add("autofocus" to "autofocus")
+ }
+ }
+ readonly?.let {
+ if (it) {
+ sn.add("readonly" to "readonly")
+ }
+ }
+ if (disabled) {
+ sn.add("disabled" to "true")
+ value?.let {
+ sn.add("value" to it.toStringF(format))
+ }
+ }
+ return sn
+ }
+
+ @Suppress("UnsafeCastFromDynamic")
+ protected open fun refreshState() {
+ value?.let {
+ getElementJQueryD()?.datetimepicker("update", it)
+ } ?: getElementJQueryD()?.datetimepicker("update", null)
+ }
+
+ protected open fun refreshDatePicker() {
+ getElementJQueryD()?.`val`(null)
+ getElementJQueryD()?.datetimepicker("remove")
+ initDateTimePicker()
+ refreshState()
+ }
+
+ protected open fun changeValue() {
+ val v = getElementJQuery()?.`val`() as String?
+ if (v != null && v.isNotEmpty()) {
+ this.value = v.toDateF(format)
+ } else {
+ this.value = null
+ }
+ }
+
+ open fun showPopup() {
+ getElementJQueryD()?.datetimepicker("show")
+ }
+
+ open fun hidePopup() {
+ getElementJQueryD()?.datetimepicker("hide")
+ }
+
+ @Suppress("UnsafeCastFromDynamic")
+ override fun afterInsert(node: VNode) {
+ if (!this.disabled) {
+ this.initDateTimePicker()
+ this.getElementJQuery()?.on("changeDate", { e, _ ->
+ this.dispatchEvent("change", obj { detail = e })
+ })
+ this.getElementJQuery()?.on("show", { e, _ ->
+ this.dispatchEvent("showBsDateTime", obj { detail = e })
+ })
+ this.getElementJQuery()?.on("hide", { e, _ ->
+ this.dispatchEvent("hideBsDateTime", obj { detail = e })
+ })
+ refreshState()
+ }
+ }
+
+ private fun initDateTimePicker() {
+ val datePickerFormat = format.toDatePickerFormat()
+ val minView = if (format.contains("HH") || format.contains("mm")) 0 else 2
+ val maxView = if (format.contains("YY") || format.contains("M") || format.contains("D")) MAX_VIEW else 1
+ val startView = if (maxView < 2) maxView else 2
+ getElementJQueryD()?.datetimepicker(obj {
+ this.format = datePickerFormat
+ this.startView = startView
+ this.minView = minView
+ this.maxView = maxView
+ this.minuteStep = minuteStep
+ this.todayHighlight = todayHighlight
+ this.clearBtn = clearBtn
+ this.todayBtn = todayBtn
+ this.weekStart = weekStart
+ this.showMeridian = showMeridian
+ this.daysOfWeekDisabled = daysOfWeekDisabled
+ this.autoclose = true
+ })
+ }
+
+ override fun getValueAsString(): String? {
+ return value?.toStringF(format)
+ }
+
+ companion object {
+ private fun String.toDatePickerFormat(): String {
+ return this.replace("YY", "yy").replace("m", "i").replace("MMMM", "{----}").replace("MMM", "{---}")
+ .replace("M", "m").replace("{----}", "MM").replace("{---}", "M").replace("H", "{-}")
+ .replace("h", "H").replace("{-}", "h").replace("D", "d").replace("a", "p").replace("A", "P")
+ }
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/snabbdom/Types.kt b/src/main/kotlin/pl/treksoft/kvision/snabbdom/Types.kt
index 3ed50967..1606e83a 100644
--- a/src/main/kotlin/pl/treksoft/kvision/snabbdom/Types.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/snabbdom/Types.kt
@@ -49,6 +49,9 @@ interface BtOn : On {
var renderedBsSelect: ((KvEvent) -> kotlin.Unit)?
var refreshedBsSelect: ((KvEvent) -> kotlin.Unit)?
var changedBsSelect: ((KvEvent) -> kotlin.Unit)?
+ var changeDate: ((KvEvent) -> kotlin.Unit)?
+ var showBsDateTime: ((KvEvent) -> kotlin.Unit)?
+ var hideBsDateTime: ((KvEvent) -> kotlin.Unit)?
}
interface SnOn<T> : BtOn {
diff --git a/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt b/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt
index e2396868..b426e432 100644
--- a/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt
@@ -3,7 +3,9 @@
package pl.treksoft.kvision.utils
import pl.treksoft.kvision.core.CssSize
+import pl.treksoft.kvision.core.KVManager
import pl.treksoft.kvision.core.UNIT
+import kotlin.js.Date
fun Int.px(): CssSize = Pair(this, UNIT.px)
fun Int.em(): CssSize = Pair(this, UNIT.em)
@@ -34,3 +36,13 @@ fun Int.toHexString(): String {
}
return result
}
+
+@Suppress("UnsafeCastFromDynamic")
+fun String.toDateF(format: String = "YYYY-MM-DD HH:mm:ss"): Date {
+ return KVManager.fecha.parse(this, format)
+}
+
+@Suppress("UnsafeCastFromDynamic")
+fun Date.toStringF(format: String = "YYYY-MM-DD HH:mm:ss"): String {
+ return KVManager.fecha.format(this, format)
+}
diff --git a/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt
index 1190bc1a..3157affc 100644
--- a/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt
+++ b/src/test/kotlin/test/pl/treksoft/kvision/utils/UtilsSpec.kt
@@ -1,7 +1,10 @@
package test.pl.treksoft.kvision.utils
+import pl.treksoft.kvision.utils.toDateF
import pl.treksoft.kvision.utils.toHexString
+import pl.treksoft.kvision.utils.toStringF
import test.pl.treksoft.kvision.SimpleSpec
+import kotlin.js.Date
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -16,4 +19,32 @@ class UtilsSpec : SimpleSpec {
assertEquals("123456", res2, "Should convert int value to hex string")
}
}
-} \ No newline at end of file
+
+ @Test
+ fun toDateF() {
+ run {
+ val res = "2017-03-14 14:50:35".toDateF()
+ assertEquals(js("new Date(2017,2,14,14,50,35).getTime()"), res.getTime(), "Should convert String value to Date")
+ }
+ }
+
+ @Test
+ fun toStringF() {
+ run {
+ val date = js("new Date()")
+ val res = Date().toStringF()
+ val y = date.getFullYear()
+ val m = date.getMonth() + 1
+ val m2 = if (m<10) "0$m" else "$m"
+ val d = date.getDate()
+ val d2 = if (d<10) "0$d" else "$d"
+ val h = date.getHours()
+ val h2 = if (h<10) "0$h" else "$h"
+ val min = date.getMinutes()
+ val min2 = if (min<10) "0$min" else "$min"
+ val sec = date.getSeconds()
+ val sec2 = if (sec<10) "0$sec" else "$sec"
+ assertEquals("$y-$m2-$d2 $h2:$min2:$sec2", res, "Should convert Date value to String")
+ }
+ }
+}