aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/pl/treksoft/kvision/form/spinner
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2018-01-16 00:13:54 +0100
committerRobert Jaros <rjaros@finn.pl>2018-01-16 00:13:54 +0100
commitbcc5292dd95e5824da41a19bfbf64ebc25d79102 (patch)
tree5a97a4da432d2db97ea2fa6755c8b0e42394690f /src/main/kotlin/pl/treksoft/kvision/form/spinner
parenta107c5b7fe1cf0429436045e336b08d16b387367 (diff)
downloadkvision-bcc5292dd95e5824da41a19bfbf64ebc25d79102.tar.gz
kvision-bcc5292dd95e5824da41a19bfbf64ebc25d79102.tar.bz2
kvision-bcc5292dd95e5824da41a19bfbf64ebc25d79102.zip
Spinner form controls
Unit tests
Diffstat (limited to 'src/main/kotlin/pl/treksoft/kvision/form/spinner')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt148
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt242
2 files changed, 390 insertions, 0 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt b/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt
new file mode 100644
index 00000000..c6084fa8
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt
@@ -0,0 +1,148 @@
+package pl.treksoft.kvision.form.spinner
+
+import pl.treksoft.kvision.core.Widget
+import pl.treksoft.kvision.form.FieldLabel
+import pl.treksoft.kvision.form.HelpBlock
+import pl.treksoft.kvision.form.NumberFormControl
+import pl.treksoft.kvision.panel.SimplePanel
+import pl.treksoft.kvision.snabbdom.SnOn
+import pl.treksoft.kvision.snabbdom.StringBoolPair
+
+open class Spinner(value: Number? = null, min: Int = 0, max: Int = DEFAULT_MAX, step: Double = DEFAULT_STEP,
+ decimals: Int = 0, buttonsType: BUTTONSTYPE = BUTTONSTYPE.VERTICAL,
+ forceType: FORCETYPE = FORCETYPE.NONE, label: String? = null,
+ rich: Boolean = false) : SimplePanel(setOf("form-group")), NumberFormControl {
+
+ override var value
+ get() = input.value
+ set(value) {
+ input.value = value
+ }
+ var min
+ get() = input.min
+ set(value) {
+ input.min = value
+ }
+ var max
+ get() = input.max
+ set(value) {
+ input.max = value
+ }
+ var step
+ get() = input.step
+ set(value) {
+ input.step = value
+ }
+ var decimals
+ get() = input.decimals
+ set(value) {
+ input.decimals = value
+ }
+ var buttonsType
+ get() = input.buttonsType
+ set(value) {
+ input.buttonsType = value
+ }
+ var forceType
+ get() = input.forceType
+ set(value) {
+ input.forceType = 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 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_spinner_" + counter
+ final override val input: SpinnerInput = SpinnerInput(value, min, max, step, decimals, buttonsType, forceType)
+ .apply { id = idc }
+ final override val flabel: FieldLabel = FieldLabel(idc, label, rich)
+ final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false }
+
+ init {
+ @Suppress("LeakingThis")
+ input.eventTarget = this
+ this.addInternal(flabel)
+ this.addInternal(input)
+ this.addInternal(validationInfo)
+ counter++
+ }
+
+ companion object {
+ 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)
+ return this
+ }
+
+ override fun setEventListener(block: SnOn<Widget>.() -> Unit): Widget {
+ input.setEventListener(block)
+ return this
+ }
+
+ override fun removeEventListeners(): Widget {
+ input.removeEventListeners()
+ return this
+ }
+
+ override fun getValueAsString(): String? {
+ return input.getValueAsString()
+ }
+
+ open fun spinUp(): Spinner {
+ input.spinUp()
+ return this
+ }
+
+ open fun spinDown(): Spinner {
+ input.spinDown()
+ return this
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt
new file mode 100644
index 00000000..b7d0f959
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt
@@ -0,0 +1,242 @@
+package pl.treksoft.kvision.form.spinner
+
+import com.github.snabbdom.VNode
+import pl.treksoft.jquery.JQuery
+import pl.treksoft.kvision.core.Widget
+import pl.treksoft.kvision.form.INPUTSIZE
+import pl.treksoft.kvision.snabbdom.StringBoolPair
+import pl.treksoft.kvision.snabbdom.StringPair
+import pl.treksoft.kvision.snabbdom.obj
+
+enum class BUTTONSTYPE {
+ NONE,
+ HORIZONTAL,
+ VERTICAL
+}
+
+enum class FORCETYPE(val value: String) {
+ NONE("none"),
+ ROUND("round"),
+ FLOOR("floor"),
+ CEIL("cail")
+}
+
+const val DEFAULT_STEP = 1.0
+const val DEFAULT_MAX = 100
+
+@Suppress("TooManyFunctions")
+open class SpinnerInput(value: Number? = null, min: Int = 0, max: Int = DEFAULT_MAX, step: Double = DEFAULT_STEP,
+ decimals: Int = 0, buttonsType: BUTTONSTYPE = BUTTONSTYPE.VERTICAL,
+ forceType: FORCETYPE = FORCETYPE.NONE,
+ classes: Set<String> = setOf()) : Widget(classes + "form-control") {
+
+ init {
+ this.addSurroundingCssClass("input-group")
+ if (buttonsType == BUTTONSTYPE.NONE) {
+ this.addSurroundingCssClass("kv-spinner-btn-none")
+ } else {
+ this.removeSurroundingCssClass("kv-spinner-btn-none")
+ }
+ if (buttonsType == BUTTONSTYPE.VERTICAL) {
+ this.addSurroundingCssClass("kv-spinner-btn-vertical")
+ } else {
+ this.removeSurroundingCssClass("kv-spinner-btn-vertical")
+ }
+ this.surroundingSpan = true
+ this.refreshSpinner()
+ this.setInternalEventListener<SpinnerInput> {
+ change = {
+ self.changeValue()
+ }
+ }
+ }
+
+ var value: Number? = value
+ set(value) {
+ field = value
+ refreshState()
+ }
+ var startValue: Number? = value
+ set(value) {
+ field = value
+ this.value = value
+ refresh()
+ }
+ var min: Int = min
+ set(value) {
+ field = value
+ refreshSpinner()
+ }
+ var max: Int = max
+ set(value) {
+ field = value
+ refreshSpinner()
+ }
+ var step: Double = step
+ set(value) {
+ field = value
+ refreshSpinner()
+ }
+ var decimals: Int = decimals
+ set(value) {
+ field = value
+ refreshSpinner()
+ }
+ var buttonsType: BUTTONSTYPE = buttonsType
+ set(value) {
+ field = value
+ refreshSpinner()
+ }
+ var forceType: FORCETYPE = forceType
+ set(value) {
+ field = value
+ refreshSpinner()
+ }
+ var placeholder: String? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ var name: String? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+ 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()
+ }
+ var size: INPUTSIZE? = null
+ set(value) {
+ field = value
+ refresh()
+ }
+
+ private var siblings: JQuery? = null
+
+ 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")
+ startValue?.let {
+ sn.add("value" to it.toString())
+ }
+ 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.toString())
+ }
+ }
+ return sn
+ }
+
+ protected open fun changeValue() {
+ val v = getElementJQuery()?.`val`() as String?
+ if (v != null && v.isNotEmpty()) {
+ this.value = v.toDoubleOrNull()
+ } else {
+ this.value = null
+ }
+ }
+
+ @Suppress("UnsafeCastFromDynamic")
+ override fun afterInsert(node: VNode) {
+ getElementJQueryD()?.TouchSpin(getSettingsObj())
+ siblings = getElementJQuery()?.parent(".bootstrap-touchspin")?.children("span")
+ size?.let {
+ siblings?.find("button")?.addClass(it.className)
+ }
+ this.getElementJQuery()?.on("change", { e, _ ->
+ if (e.asDynamic().isTrigger != null) {
+ val event = org.w3c.dom.events.Event("change")
+ this.getElement()?.dispatchEvent(event)
+ }
+ })
+ this.getElementJQuery()?.on("touchspin.on.min", { e, _ ->
+ this.dispatchEvent("onMinBsSpinner", obj { detail = e })
+ })
+ this.getElementJQuery()?.on("touchspin.on.max", { e, _ ->
+ this.dispatchEvent("onMaxBsSpinner", obj { detail = e })
+ })
+ refreshState()
+ }
+
+ override fun afterDestroy() {
+ siblings?.remove()
+ siblings = null
+ }
+
+ fun getValueAsString(): String? {
+ return value?.toString()
+ }
+
+ fun spinUp(): SpinnerInput {
+ getElementJQueryD()?.trigger("touchspin.uponce")
+ return this
+ }
+
+ fun spinDown(): SpinnerInput {
+ getElementJQueryD()?.trigger("touchspin.downonce")
+ return this
+ }
+
+ private fun refreshState() {
+ value?.let {
+ getElementJQuery()?.`val`(it.toString())
+ } ?: getElementJQueryD()?.`val`(null)
+ }
+
+ private fun refreshSpinner() {
+ getElementJQueryD()?.trigger("touchspin.updatesettings", getSettingsObj())
+ }
+
+ private fun getSettingsObj(): dynamic {
+ val verticalbuttons = buttonsType == BUTTONSTYPE.VERTICAL || buttonsType == BUTTONSTYPE.NONE
+ return obj {
+ this.min = min
+ this.max = max
+ this.step = step
+ this.decimals = decimals
+ this.verticalbuttons = verticalbuttons
+ this.forcestepdivisibility = forceType.value
+ }
+ }
+}