From a804e0aa277efc1b46c1111b0ad8302d267684b2 Mon Sep 17 00:00:00 2001 From: Robert Jaros Date: Sat, 13 Jul 2019 00:21:33 +0200 Subject: Refactor RemoteSelect -> SelectRemote and RemoteTabulator -> TabulatorRemote --- .../pl/treksoft/kvision/remote/KVServiceManager.kt | 2 +- .../pl/treksoft/kvision/remote/RemoteTypes.kt | 3 +- .../pl/treksoft/kvision/remote/KVServiceManager.kt | 2 +- .../treksoft/kvision/form/select/RemoteSelect.kt | 276 --------------------- .../kvision/form/select/RemoteSelectInput.kt | 140 ----------- .../treksoft/kvision/form/select/SelectRemote.kt | 276 +++++++++++++++++++++ .../kvision/form/select/SelectRemoteInput.kt | 140 +++++++++++ .../pl/treksoft/kvision/remote/KVServiceManager.kt | 6 +- .../pl/treksoft/kvision/remote/KVServiceManager.kt | 6 +- .../pl/treksoft/kvision/remote/KVServiceManager.kt | 6 +- .../treksoft/kvision/tabulator/RemoteTabulator.kt | 114 --------- .../treksoft/kvision/tabulator/TabulatorRemote.kt | 114 +++++++++ 12 files changed, 546 insertions(+), 539 deletions(-) delete mode 100644 kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelect.kt delete mode 100644 kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelectInput.kt create mode 100644 kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt create mode 100644 kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt delete mode 100644 kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/RemoteTabulator.kt create mode 100644 kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt diff --git a/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt b/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt index 786143e8..006aba89 100644 --- a/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt +++ b/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt @@ -115,7 +115,7 @@ expect open class KVServiceManager(serviceClass: KClass) { * @param function a function of the receiver */ protected fun bind( - function: T.(String?, String?) -> List + function: T.(String?, String?) -> List ) /** diff --git a/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/RemoteTypes.kt b/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/RemoteTypes.kt index 7285295b..29cb6a9b 100644 --- a/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/RemoteTypes.kt +++ b/kvision-modules/kvision-common-remote/src/main/kotlin/pl/treksoft/kvision/remote/RemoteTypes.kt @@ -24,7 +24,7 @@ package pl.treksoft.kvision.remote import kotlinx.serialization.Serializable @Serializable -data class RemoteSelectOption( +data class RemoteOption( val value: String? = null, val text: String? = null, val className: String? = null, @@ -36,6 +36,7 @@ data class RemoteSelectOption( ) @Serializable +@Suppress("ConstructorParameterNaming") data class RemoteData(val data: List = listOf(), val last_page: Int = 0) @Serializable diff --git a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt b/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt index 5b5ae87f..829ccbd6 100644 --- a/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt +++ b/kvision-modules/kvision-remote/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt @@ -133,7 +133,7 @@ actual open class KVServiceManager actual constructor(serviceClass: KCl * @param function a function of the receiver */ protected actual fun bind( - function: T.(String?, String?) -> List + function: T.(String?, String?) -> List ) { val routeDef = "route${this::class.simpleName}${counter++}" calls[function.toString().replace("\\s".toRegex(), "")] = Pair("/kv/$routeDef", HttpMethod.POST) diff --git a/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelect.kt b/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelect.kt deleted file mode 100644 index 0e30d0fd..00000000 --- a/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelect.kt +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (c) 2017-present Robert Jaros - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package pl.treksoft.kvision.form.select - -import pl.treksoft.kvision.core.Component -import pl.treksoft.kvision.core.Container -import pl.treksoft.kvision.core.StringBoolPair -import pl.treksoft.kvision.core.Widget -import pl.treksoft.kvision.form.FieldLabel -import pl.treksoft.kvision.form.HelpBlock -import pl.treksoft.kvision.form.StringFormControl -import pl.treksoft.kvision.panel.SimplePanel -import pl.treksoft.kvision.remote.KVServiceManager -import pl.treksoft.kvision.remote.RemoteSelectOption -import pl.treksoft.kvision.utils.SnOn - -/** - * The form field component for RemoteSelect control. - * - * @constructor - * @param value selected value - * @param serviceManager multiplatform service manager - * @param function multiplatform service method returning the list of options - * @param name the name attribute of the generated HTML input element - * @param multiple allows multiple value selection (multiple values are comma delimited) - * @param ajaxOptions additional options for remote data source - * @param label label text bound to the input element - * @param rich determines if [label] can contain HTML code - */ -@Suppress("TooManyFunctions") -open class RemoteSelect( - value: String? = null, - serviceManager: KVServiceManager, - function: T.(String?, String?) -> List, - name: String? = null, - multiple: Boolean = false, - ajaxOptions: AjaxOptions? = null, - label: String? = null, - rich: Boolean = false -) : SimplePanel(setOf("form-group")), StringFormControl { - /** - * A value of the selected option. - */ - override var value - get() = input.value - set(value) { - input.value = value - } - /** - * Determines if multiple value selection is allowed. - */ - var multiple - get() = input.multiple - set(value) { - input.multiple = value - } - /** - * Maximal number of selected options. - */ - var maxOptions - get() = input.maxOptions - set(value) { - input.maxOptions = value - } - /** - * The placeholder for the select control. - */ - var placeholder - get() = input.placeholder - set(value) { - input.placeholder = value - } - /** - * The style of the select control. - */ - var style - get() = input.style - set(value) { - input.style = value - } - /** - * The width of the select control. - */ - var selectWidth - get() = input.selectWidth - set(value) { - input.selectWidth = value - } - /** - * The width type of the select control. - */ - var selectWidthType - get() = input.selectWidthType - set(value) { - input.selectWidthType = value - } - /** - * Determines if an empty option is automatically generated. - */ - var emptyOption - get() = input.emptyOption - set(value) { - input.emptyOption = value - } - /** - * Determines if the select is automatically focused. - */ - var autofocus - get() = input.autofocus - set(value) { - input.autofocus = value - } - /** - * The label text bound to the select element. - */ - var label - get() = flabel.content - set(value) { - flabel.content = value - } - /** - * Determines if [label] can contain HTML code. - */ - var rich - get() = flabel.rich - set(value) { - flabel.rich = value - } - - private val idc = "kv_form_remoteselect_$counter" - final override val input: RemoteSelectInput = RemoteSelectInput( - value, serviceManager, function, multiple, ajaxOptions, - setOf("form-control") - ).apply { - this.id = idc - this.name = name - } - 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++ - } - - override fun getSnClass(): List { - val cl = super.getSnClass().toMutableList() - if (validatorError != null) { - cl.add("has-error" to true) - } - return cl - } - - @Suppress("UNCHECKED_CAST") - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this - } - - override fun setEventListener(block: SnOn.() -> Unit): Widget { - input.setEventListener(block) - return this - } - - override fun removeEventListeners(): Widget { - input.removeEventListeners() - return this - } - - override fun add(child: Component): SimplePanel { - input.add(child) - return this - } - - override fun addAll(children: List): SimplePanel { - input.addAll(children) - return this - } - - override fun remove(child: Component): SimplePanel { - input.remove(child) - return this - } - - override fun removeAll(): SimplePanel { - input.removeAll() - return this - } - - override fun getChildren(): List { - return input.getChildren() - } - - /** - * Opens dropdown with options. - */ - open fun showOptions() { - input.showOptions() - } - - /** - * Hides dropdown with options. - */ - open fun hideOptions() { - input.hideOptions() - } - - /** - * Toggles visibility of dropdown with options. - */ - open fun toggleOptions() { - input.toggleOptions() - } - - override fun focus() { - input.focus() - } - - override fun blur() { - input.blur() - } - - companion object { - internal var counter = 0 - - /** - * DSL builder extension function. - * - * It takes the same parameters as the constructor of the built component. - */ - fun Container.remoteSelect( - value: String? = null, - serviceManager: KVServiceManager, - function: T.(String?, String?) -> List, name: String? = null, - multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null, - rich: Boolean = false, init: (RemoteSelect.() -> Unit)? = null - ): RemoteSelect { - val remoteSelect = - RemoteSelect( - value, - serviceManager, - function, - name, - multiple, - ajaxOptions, - label, - rich - ).apply { init?.invoke(this) } - this.add(remoteSelect) - return remoteSelect - } - } -} diff --git a/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelectInput.kt b/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelectInput.kt deleted file mode 100644 index ff1b04f4..00000000 --- a/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/RemoteSelectInput.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2017-present Robert Jaros - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package pl.treksoft.kvision.form.select - -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.asDeferred -import kotlinx.coroutines.launch -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.list -import kotlinx.serialization.stringify -import pl.treksoft.kvision.core.Container -import pl.treksoft.kvision.remote.CallAgent -import pl.treksoft.kvision.remote.HttpMethod -import pl.treksoft.kvision.remote.JsonRpcRequest -import pl.treksoft.kvision.remote.KVServiceManager -import pl.treksoft.kvision.remote.RemoteSelectOption -import pl.treksoft.kvision.utils.JSON -import pl.treksoft.kvision.utils.obj - -external fun decodeURIComponent(encodedURI: String): String - -/** - * The Select control connected to the multiplatform service. - * - * @constructor - * @param value selected value - * @param serviceManager multiplatform service manager - * @param function multiplatform service method returning the list of options - * @param multiple allows multiple value selection (multiple values are comma delimited) - * @param ajaxOptions additional options for remote data source - * @param classes a set of CSS class names - */ -@UseExperimental(ImplicitReflectionSerializer::class) -open class RemoteSelectInput( - value: String? = null, - serviceManager: KVServiceManager, - function: T.(String?, String?) -> List, - multiple: Boolean = false, - ajaxOptions: AjaxOptions? = null, - classes: Set = setOf() -) : SelectInput(null, value, multiple, null, classes) { - init { - val (url, method) = - serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] - ?: throw IllegalStateException("Function not specified!") - val data = obj { - q = "{{{q}}}" - } - val tempAjaxOptions = ajaxOptions ?: AjaxOptions() - this.ajaxOptions = tempAjaxOptions.copy(url = url, preprocessData = { - @Suppress("UnsafeCastFromDynamic") - JSON.plain.parse(RemoteSelectOption.serializer().list, it.result as String).map { - obj { - this.value = it.value - if (it.text != null) this.text = it.text - if (it.className != null) this.`class` = it.className - if (it.disabled) this.disabled = true - if (it.divider) this.divider = true - this.data = obj { - if (it.subtext != null) this.subtext = it.subtext - if (it.icon != null) this.icon = it.icon - if (it.content != null) this.content = it.content - } - } - }.toTypedArray() - }, data = data, beforeSend = { _, b -> - @Suppress("UnsafeCastFromDynamic") - val q = decodeURIComponent(b.data.substring(2)) - b.data = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(q, this.value))) - true - }, httpType = HttpType.valueOf(method.name), cache = false, preserveSelected = true) - if (value != null) { - GlobalScope.launch { - val callAgent = CallAgent() - val initials = callAgent.remoteCall( - url, - JSON.plain.stringify(JsonRpcRequest(0, url, listOf(null, value))), - HttpMethod.POST - ).asDeferred().await() - JSON.plain.parse(RemoteSelectOption.serializer().list, initials.result as String).map { - add(SelectOption(it.value, it.text, selected = true)) - } - this@RemoteSelectInput.refreshSelectInput() - } - } - if (this.ajaxOptions?.emptyRequest == true) { - this.setInternalEventListener> { - shownBsSelect = { - val input = self.getElementJQuery()?.parent()?.find("input") - input?.trigger("keyup", null) - input?.hide(0) - } - } - - } - } - - companion object { - /** - * DSL builder extension function. - * - * It takes the same parameters as the constructor of the built component. - */ - fun Container.remoteSelectInput( - value: String? = null, - serviceManager: KVServiceManager, - function: T.(String?, String?) -> List, - multiple: Boolean = false, - ajaxOptions: AjaxOptions? = null, - classes: Set = setOf(), init: (RemoteSelectInput.() -> Unit)? = null - ): RemoteSelectInput { - val remoteSelectInput = - RemoteSelectInput(value, serviceManager, function, multiple, ajaxOptions, classes).apply { - init?.invoke(this) - } - this.add(remoteSelectInput) - return remoteSelectInput - } - } - -} diff --git a/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt b/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt new file mode 100644 index 00000000..ea9d369b --- /dev/null +++ b/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemote.kt @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.form.FieldLabel +import pl.treksoft.kvision.form.HelpBlock +import pl.treksoft.kvision.form.StringFormControl +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.remote.KVServiceManager +import pl.treksoft.kvision.remote.RemoteOption +import pl.treksoft.kvision.utils.SnOn + +/** + * The form field component for SelectRemote control. + * + * @constructor + * @param value selected value + * @param serviceManager multiplatform service manager + * @param function multiplatform service method returning the list of options + * @param name the name attribute of the generated HTML input element + * @param multiple allows multiple value selection (multiple values are comma delimited) + * @param ajaxOptions additional options for remote data source + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ +@Suppress("TooManyFunctions") +open class SelectRemote( + value: String? = null, + serviceManager: KVServiceManager, + function: T.(String?, String?) -> List, + name: String? = null, + multiple: Boolean = false, + ajaxOptions: AjaxOptions? = null, + label: String? = null, + rich: Boolean = false +) : SimplePanel(setOf("form-group")), StringFormControl { + /** + * A value of the selected option. + */ + override var value + get() = input.value + set(value) { + input.value = value + } + /** + * Determines if multiple value selection is allowed. + */ + var multiple + get() = input.multiple + set(value) { + input.multiple = value + } + /** + * Maximal number of selected options. + */ + var maxOptions + get() = input.maxOptions + set(value) { + input.maxOptions = value + } + /** + * The placeholder for the select control. + */ + var placeholder + get() = input.placeholder + set(value) { + input.placeholder = value + } + /** + * The style of the select control. + */ + var style + get() = input.style + set(value) { + input.style = value + } + /** + * The width of the select control. + */ + var selectWidth + get() = input.selectWidth + set(value) { + input.selectWidth = value + } + /** + * The width type of the select control. + */ + var selectWidthType + get() = input.selectWidthType + set(value) { + input.selectWidthType = value + } + /** + * Determines if an empty option is automatically generated. + */ + var emptyOption + get() = input.emptyOption + set(value) { + input.emptyOption = value + } + /** + * Determines if the select is automatically focused. + */ + var autofocus + get() = input.autofocus + set(value) { + input.autofocus = value + } + /** + * The label text bound to the select element. + */ + var label + get() = flabel.content + set(value) { + flabel.content = value + } + /** + * Determines if [label] can contain HTML code. + */ + var rich + get() = flabel.rich + set(value) { + flabel.rich = value + } + + private val idc = "kv_form_SelectRemote_$counter" + final override val input: SelectRemoteInput = SelectRemoteInput( + value, serviceManager, function, multiple, ajaxOptions, + setOf("form-control") + ).apply { + this.id = idc + this.name = name + } + 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++ + } + + override fun getSnClass(): List { + val cl = super.getSnClass().toMutableList() + if (validatorError != null) { + cl.add("has-error" to true) + } + return cl + } + + @Suppress("UNCHECKED_CAST") + override fun setEventListener(block: SnOn.() -> Unit): Widget { + input.setEventListener(block) + return this + } + + override fun setEventListener(block: SnOn.() -> Unit): Widget { + input.setEventListener(block) + return this + } + + override fun removeEventListeners(): Widget { + input.removeEventListeners() + return this + } + + override fun add(child: Component): SimplePanel { + input.add(child) + return this + } + + override fun addAll(children: List): SimplePanel { + input.addAll(children) + return this + } + + override fun remove(child: Component): SimplePanel { + input.remove(child) + return this + } + + override fun removeAll(): SimplePanel { + input.removeAll() + return this + } + + override fun getChildren(): List { + return input.getChildren() + } + + /** + * Opens dropdown with options. + */ + open fun showOptions() { + input.showOptions() + } + + /** + * Hides dropdown with options. + */ + open fun hideOptions() { + input.hideOptions() + } + + /** + * Toggles visibility of dropdown with options. + */ + open fun toggleOptions() { + input.toggleOptions() + } + + override fun focus() { + input.focus() + } + + override fun blur() { + input.blur() + } + + companion object { + internal var counter = 0 + + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.selectRemote( + value: String? = null, + serviceManager: KVServiceManager, + function: T.(String?, String?) -> List, name: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null, + rich: Boolean = false, init: (SelectRemote.() -> Unit)? = null + ): SelectRemote { + val selectRemote = + SelectRemote( + value, + serviceManager, + function, + name, + multiple, + ajaxOptions, + label, + rich + ).apply { init?.invoke(this) } + this.add(selectRemote) + return selectRemote + } + } +} diff --git a/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt b/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt new file mode 100644 index 00000000..4c891d30 --- /dev/null +++ b/kvision-modules/kvision-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.select + +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.asDeferred +import kotlinx.coroutines.launch +import kotlinx.serialization.ImplicitReflectionSerializer +import kotlinx.serialization.list +import kotlinx.serialization.stringify +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.remote.CallAgent +import pl.treksoft.kvision.remote.HttpMethod +import pl.treksoft.kvision.remote.JsonRpcRequest +import pl.treksoft.kvision.remote.KVServiceManager +import pl.treksoft.kvision.remote.RemoteOption +import pl.treksoft.kvision.utils.JSON +import pl.treksoft.kvision.utils.obj + +external fun decodeURIComponent(encodedURI: String): String + +/** + * The Select control connected to the multiplatform service. + * + * @constructor + * @param value selected value + * @param serviceManager multiplatform service manager + * @param function multiplatform service method returning the list of options + * @param multiple allows multiple value selection (multiple values are comma delimited) + * @param ajaxOptions additional options for remote data source + * @param classes a set of CSS class names + */ +@UseExperimental(ImplicitReflectionSerializer::class) +open class SelectRemoteInput( + value: String? = null, + serviceManager: KVServiceManager, + function: T.(String?, String?) -> List, + multiple: Boolean = false, + ajaxOptions: AjaxOptions? = null, + classes: Set = setOf() +) : SelectInput(null, value, multiple, null, classes) { + init { + val (url, method) = + serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] + ?: throw IllegalStateException("Function not specified!") + val data = obj { + q = "{{{q}}}" + } + val tempAjaxOptions = ajaxOptions ?: AjaxOptions() + this.ajaxOptions = tempAjaxOptions.copy(url = url, preprocessData = { + @Suppress("UnsafeCastFromDynamic") + JSON.plain.parse(RemoteOption.serializer().list, it.result as String).map { + obj { + this.value = it.value + if (it.text != null) this.text = it.text + if (it.className != null) this.`class` = it.className + if (it.disabled) this.disabled = true + if (it.divider) this.divider = true + this.data = obj { + if (it.subtext != null) this.subtext = it.subtext + if (it.icon != null) this.icon = it.icon + if (it.content != null) this.content = it.content + } + } + }.toTypedArray() + }, data = data, beforeSend = { _, b -> + @Suppress("UnsafeCastFromDynamic") + val q = decodeURIComponent(b.data.substring(2)) + b.data = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(q, this.value))) + true + }, httpType = HttpType.valueOf(method.name), cache = false, preserveSelected = true) + if (value != null) { + GlobalScope.launch { + val callAgent = CallAgent() + val initials = callAgent.remoteCall( + url, + JSON.plain.stringify(JsonRpcRequest(0, url, listOf(null, value))), + HttpMethod.POST + ).asDeferred().await() + JSON.plain.parse(RemoteOption.serializer().list, initials.result as String).map { + add(SelectOption(it.value, it.text, selected = true)) + } + this@SelectRemoteInput.refreshSelectInput() + } + } + if (this.ajaxOptions?.emptyRequest == true) { + this.setInternalEventListener> { + shownBsSelect = { + val input = self.getElementJQuery()?.parent()?.find("input") + input?.trigger("keyup", null) + input?.hide(0) + } + } + + } + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.selectRemoteInput( + value: String? = null, + serviceManager: KVServiceManager, + function: T.(String?, String?) -> List, + multiple: Boolean = false, + ajaxOptions: AjaxOptions? = null, + classes: Set = setOf(), init: (SelectRemoteInput.() -> Unit)? = null + ): SelectRemoteInput { + val selectRemoteInput = + SelectRemoteInput(value, serviceManager, function, multiple, ajaxOptions, classes).apply { + init?.invoke(this) + } + this.add(selectRemoteInput) + return selectRemoteInput + } + } + +} diff --git a/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt index a2bb2386..4c4d4af0 100644 --- a/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt +++ b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt @@ -42,7 +42,7 @@ import kotlin.reflect.KClass /** * Multiplatform service manager for Jooby. */ -@Suppress("LargeClass") +@Suppress("LargeClass", "TooManyFunctions") @UseExperimental(ExperimentalCoroutinesApi::class) actual open class KVServiceManager actual constructor(val serviceClass: KClass) { @@ -396,7 +396,7 @@ actual open class KVServiceManager actual constructor(val serviceClass: */ @Suppress("TooGenericExceptionCaught") protected actual fun bind( - function: T.(String?, String?) -> List + function: T.(String?, String?) -> List ) { val routeDef = "route${this::class.simpleName}${counter++}" routes.add { @@ -440,10 +440,12 @@ actual open class KVServiceManager actual constructor(val serviceClass: routes.add { call(HttpMethod.POST, "/kv/$routeDef") { req, res -> val jsonRpcRequest = req.body(JsonRpcRequest::class.java) + @Suppress("MagicNumber") if (jsonRpcRequest.params.size == 4) { val param1 = getParameter(jsonRpcRequest.params[0]) val param2 = getParameter(jsonRpcRequest.params[1]) val param3 = getParameter?>(jsonRpcRequest.params[2]) + @Suppress("MagicNumber") val param4 = getParameter?>(jsonRpcRequest.params[3]) val injector = req.require(Injector::class.java) val service = injector.getInstance(serviceClass.java) diff --git a/kvision-modules/kvision-server-ktor/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt b/kvision-modules/kvision-server-ktor/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt index c5c579a6..847604fb 100644 --- a/kvision-modules/kvision-server-ktor/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt +++ b/kvision-modules/kvision-server-ktor/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt @@ -55,7 +55,7 @@ import kotlin.reflect.KClass */ @KtorExperimentalAPI @UseExperimental(ExperimentalCoroutinesApi::class) -@Suppress("LargeClass") +@Suppress("LargeClass", "TooManyFunctions") actual open class KVServiceManager actual constructor(val serviceClass: KClass) { companion object { @@ -419,7 +419,7 @@ actual open class KVServiceManager actual constructor(val serviceClass: */ @Suppress("TooGenericExceptionCaught") protected actual fun bind( - function: T.(String?, String?) -> List + function: T.(String?, String?) -> List ) { val routeDef = "route${this::class.simpleName}${counter++}" addRoute(HttpMethod.POST, "/kv/$routeDef") { @@ -468,10 +468,12 @@ actual open class KVServiceManager actual constructor(val serviceClass: addRoute(HttpMethod.POST, "/kv/$routeDef") { val service = call.injector.createChildInjector(DummyWsSessionModule()).getInstance(serviceClass.java) val jsonRpcRequest = call.receive() + @Suppress("MagicNumber") if (jsonRpcRequest.params.size == 4) { val param1 = getParameter(jsonRpcRequest.params[0]) val param2 = getParameter(jsonRpcRequest.params[1]) val param3 = getParameter?>(jsonRpcRequest.params[2]) + @Suppress("MagicNumber") val param4 = getParameter?>(jsonRpcRequest.params[3]) try { val result = function.invoke(service, param1, param2, param3, param4) diff --git a/kvision-modules/kvision-server-spring-boot/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt b/kvision-modules/kvision-server-spring-boot/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt index ab64c50d..185356da 100644 --- a/kvision-modules/kvision-server-spring-boot/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt +++ b/kvision-modules/kvision-server-spring-boot/src/main/kotlin/pl/treksoft/kvision/remote/KVServiceManager.kt @@ -43,7 +43,7 @@ import kotlin.reflect.KClass * Multiplatform service manager for Spring Boot. */ @UseExperimental(ExperimentalCoroutinesApi::class) -@Suppress("LargeClass") +@Suppress("LargeClass", "TooManyFunctions") actual open class KVServiceManager actual constructor(val serviceClass: KClass) { companion object { @@ -455,7 +455,7 @@ actual open class KVServiceManager actual constructor(val serviceClass: */ @Suppress("TooGenericExceptionCaught") protected actual fun bind( - function: T.(String?, String?) -> List + function: T.(String?, String?) -> List ) { val routeDef = "route${this::class.simpleName}${counter++}" addRoute(HttpMethod.POST, "/kv/$routeDef") { req, res, ctx -> @@ -510,10 +510,12 @@ actual open class KVServiceManager actual constructor(val serviceClass: addRoute(HttpMethod.POST, "/kv/$routeDef") { req, res, ctx -> val service = ctx.getBean(serviceClass.java) val jsonRpcRequest = mapper.readValue(req.inputStream, JsonRpcRequest::class.java) + @Suppress("MagicNumber") if (jsonRpcRequest.params.size == 4) { val param1 = getParameter(jsonRpcRequest.params[0]) val param2 = getParameter(jsonRpcRequest.params[1]) val param3 = getParameter?>(jsonRpcRequest.params[2]) + @Suppress("MagicNumber") val param4 = getParameter?>(jsonRpcRequest.params[3]) try { val result = function.invoke(service, param1, param2, param3, param4) diff --git a/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/RemoteTabulator.kt b/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/RemoteTabulator.kt deleted file mode 100644 index 8070a187..00000000 --- a/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/RemoteTabulator.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2017-present Robert Jaros - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package pl.treksoft.kvision.tabulator - -import kotlinx.serialization.ImplicitReflectionSerializer -import kotlinx.serialization.stringify -import pl.treksoft.kvision.core.Container -import pl.treksoft.kvision.remote.JsonRpcRequest -import pl.treksoft.kvision.remote.KVServiceManager -import pl.treksoft.kvision.remote.RemoteData -import pl.treksoft.kvision.remote.RemoteFilter -import pl.treksoft.kvision.remote.RemoteSorter -import pl.treksoft.kvision.rest.HttpMethod -import pl.treksoft.kvision.rest.RestClient -import pl.treksoft.kvision.table.TableType -import pl.treksoft.kvision.utils.JSON - -/** - * Tabulator component connected to the multiplatform service. - * - * @constructor - * @param T type of row data - * @param E type of service manager - * @param serviceManager multiplatform service manager - * @param function multiplatform service method returning tabulator rows data - * @param options tabulator options - * @param types a set of table types - * @param classes a set of CSS class names - */ -@UseExperimental(ImplicitReflectionSerializer::class) -open class RemoteTabulator( - serviceManager: KVServiceManager, - function: E.(Int?, Int?, List?, List?) -> RemoteData, - options: TabulatorOptions = TabulatorOptions(), - types: Set = setOf(), - classes: Set = setOf() -) : Tabulator(null, false, options, types, classes) { - init { - val (url, method) = - serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] - ?: throw IllegalStateException("Function not specified!") - - val restClient = RestClient() - options.ajaxURL = url - options.ajaxRequestFunc = { _, _, params -> - val page = params.page - val size = params.size - @Suppress("UnsafeCastFromDynamic") - val filters = if (params.filters != null) { - kotlin.js.JSON.stringify(params.filters) - } else { - null - } - @Suppress("UnsafeCastFromDynamic") - val sorters = if (params.sorters != null) { - kotlin.js.JSON.stringify(params.sorters) - } else { - null - } - @Suppress("UnsafeCastFromDynamic") - val data = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(page, size, filters, sorters))) - restClient.remoteCall(url, data, method = HttpMethod.valueOf(method.name)).then { r: dynamic -> - val result = kotlin.js.JSON.parse(r.result as String) - @Suppress("UnsafeCastFromDynamic") - if (page != null) { - result - } else { - result.data - } - } - } - } - - companion object { - /** - * DSL builder extension function. - * - * It takes the same parameters as the constructor of the built component. - */ - fun Container.remoteTabulator( - serviceManager: KVServiceManager, - function: E.(Int?, Int?, List?, List?) -> RemoteData, - options: TabulatorOptions = TabulatorOptions(), - types: Set = setOf(), - classes: Set = setOf(), - init: (RemoteTabulator.() -> Unit)? = null - ): RemoteTabulator { - val remoteTabulator = RemoteTabulator(serviceManager, function, options, types, classes) - init?.invoke(remoteTabulator) - this.add(remoteTabulator) - return remoteTabulator - } - } - -} diff --git a/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt b/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt new file mode 100644 index 00000000..4478b942 --- /dev/null +++ b/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.tabulator + +import kotlinx.serialization.ImplicitReflectionSerializer +import kotlinx.serialization.stringify +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.remote.JsonRpcRequest +import pl.treksoft.kvision.remote.KVServiceManager +import pl.treksoft.kvision.remote.RemoteData +import pl.treksoft.kvision.remote.RemoteFilter +import pl.treksoft.kvision.remote.RemoteSorter +import pl.treksoft.kvision.rest.HttpMethod +import pl.treksoft.kvision.rest.RestClient +import pl.treksoft.kvision.table.TableType +import pl.treksoft.kvision.utils.JSON + +/** + * Tabulator component connected to the multiplatform service. + * + * @constructor + * @param T type of row data + * @param E type of service manager + * @param serviceManager multiplatform service manager + * @param function multiplatform service method returning tabulator rows data + * @param options tabulator options + * @param types a set of table types + * @param classes a set of CSS class names + */ +@UseExperimental(ImplicitReflectionSerializer::class) +open class TabulatorRemote( + serviceManager: KVServiceManager, + function: E.(Int?, Int?, List?, List?) -> RemoteData, + options: TabulatorOptions = TabulatorOptions(), + types: Set = setOf(), + classes: Set = setOf() +) : Tabulator(null, false, options, types, classes) { + init { + val (url, method) = + serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] + ?: throw IllegalStateException("Function not specified!") + + val restClient = RestClient() + options.ajaxURL = url + options.ajaxRequestFunc = { _, _, params -> + val page = params.page + val size = params.size + @Suppress("UnsafeCastFromDynamic") + val filters = if (params.filters != null) { + kotlin.js.JSON.stringify(params.filters) + } else { + null + } + @Suppress("UnsafeCastFromDynamic") + val sorters = if (params.sorters != null) { + kotlin.js.JSON.stringify(params.sorters) + } else { + null + } + @Suppress("UnsafeCastFromDynamic") + val data = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(page, size, filters, sorters))) + restClient.remoteCall(url, data, method = HttpMethod.valueOf(method.name)).then { r: dynamic -> + val result = kotlin.js.JSON.parse(r.result as String) + @Suppress("UnsafeCastFromDynamic") + if (page != null) { + result + } else { + result.data + } + } + } + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.tabulatorRemote( + serviceManager: KVServiceManager, + function: E.(Int?, Int?, List?, List?) -> RemoteData, + options: TabulatorOptions = TabulatorOptions(), + types: Set = setOf(), + classes: Set = setOf(), + init: (TabulatorRemote.() -> Unit)? = null + ): TabulatorRemote { + val tabulatorRemote = TabulatorRemote(serviceManager, function, options, types, classes) + init?.invoke(tabulatorRemote) + this.add(tabulatorRemote) + return tabulatorRemote + } + } + +} -- cgit