diff options
Diffstat (limited to 'kvision-modules')
5 files changed, 278 insertions, 0 deletions
diff --git a/kvision-modules/kvision-bootstrap-typeahead-remote/build.gradle b/kvision-modules/kvision-bootstrap-typeahead-remote/build.gradle new file mode 100644 index 00000000..cab403d5 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-typeahead-remote/build.gradle @@ -0,0 +1,6 @@ +apply from: "../shared.gradle" + +dependencies { + compile project(":kvision-modules:kvision-bootstrap-typeahead") + compile project(":kvision-modules:kvision-remote") +} diff --git a/kvision-modules/kvision-bootstrap-typeahead-remote/package.json.d/project.info b/kvision-modules/kvision-bootstrap-typeahead-remote/package.json.d/project.info new file mode 100644 index 00000000..15dc8333 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-typeahead-remote/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Typeahead remote addon module" +} diff --git a/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemote.kt b/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemote.kt new file mode 100644 index 00000000..961b5dd0 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemote.kt @@ -0,0 +1,167 @@ +/* + * 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.text + +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.remote.KVServiceManager + +/** + * Form field typeahead component connected to the multiplatform service. + * + * @constructor + * @param serviceManager multiplatform service manager + * @param function multiplatform service method returning the list of options + * @param stateFunction a function to generate the state object passed with the remote request + * @param items the max number of items to display in the dropdown + * @param minLength the minimum character length needed before triggering dropdown + * @param delay a delay between lookups + * @param type text input type (default "text") + * @param value text input value + * @param name the name attribute of the generated HTML input element + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ +open class TypeaheadRemote<T : Any>( + serviceManager: KVServiceManager<T>, + function: suspend T.(String?, String?) -> List<String>, + private val stateFunction: (() -> String)? = null, + items: Int? = 8, minLength: Int = 1, delay: Int = 0, + type: TextInputType = TextInputType.TEXT, value: String? = null, name: String? = null, + label: String? = null, rich: Boolean = false +) : AbstractText(label, rich) { + + /** + * The max number of items to display in the dropdown + */ + var items + get() = input.items + set(value) { + input.items = value + } + + /** + * The minimum character length needed before triggering dropdown + */ + var minLength + get() = input.minLength + set(value) { + input.minLength = value + } + + /** + * Determines if hints should be shown as soon as the input gets focus. + */ + var showHintOnFocus + get() = input.showHintOnFocus + set(value) { + input.showHintOnFocus = value + } + + /** + * Determines if the first suggestion is selected automatically. + */ + var autoSelect + get() = input.autoSelect + set(value) { + input.autoSelect = value + } + + /** + * A delay between lookups. + */ + var delay + get() = input.ajaxOptions + set(value) { + input.ajaxOptions = value + } + + /** + * Determines if the menu is the same size as the input it is attached to. + */ + var fitToElement + get() = input.fitToElement + set(value) { + input.fitToElement = value + } + + /** + * Text input type. + */ + var type + get() = input.type + set(value) { + input.type = value + } + /** + * Determines if autocomplete is enabled for the input element. + */ + var autocomplete + get() = input.autocomplete + set(value) { + input.autocomplete = value + } + + final override val input: TypeaheadRemoteInput<T> = + TypeaheadRemoteInput(serviceManager, function, stateFunction, items, minLength, delay, type, value).apply { + this.id = idc + this.name = name + } + + init { + @Suppress("LeakingThis") + input.eventTarget = this + this.addInternal(input) + this.addInternal(invalidFeedback) + } +} + +/** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ +fun <T : Any> Container.typeaheadRemote( + serviceManager: KVServiceManager<T>, + function: suspend T.(String?, String?) -> List<String>, + stateFunction: (() -> String)? = null, + items: Int? = 8, minLength: Int = 1, delay: Int = 0, + type: TextInputType = TextInputType.TEXT, value: String? = null, name: String? = null, + label: String? = null, rich: Boolean = false, init: (TypeaheadRemote<T>.() -> Unit)? = null +): TypeaheadRemote<T> { + val typeaheadRemote = TypeaheadRemote( + serviceManager, + function, + stateFunction, + items, + minLength, + delay, + type, + value, + name, + label, + rich + ).apply { + init?.invoke(this) + } + this.add(typeaheadRemote) + return typeaheadRemote +} diff --git a/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemoteInput.kt b/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemoteInput.kt new file mode 100644 index 00000000..e56468d1 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemoteInput.kt @@ -0,0 +1,100 @@ +/* + * 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.text + +import kotlinx.serialization.ImplicitReflectionSerializer +import kotlinx.serialization.list +import kotlinx.serialization.serializer +import kotlinx.serialization.stringify +import org.w3c.dom.get +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.remote.JsonRpcRequest +import pl.treksoft.kvision.remote.KVServiceManager +import pl.treksoft.kvision.utils.JSON +import kotlin.browser.window + +/** + * The Typeahead control connected to the multiplatform service. + * + * @constructor + * @param serviceManager multiplatform service manager + * @param function multiplatform service method returning the list of options + * @param stateFunction a function to generate the state object passed with the remote request + * @param items the max number of items to display in the dropdown + * @param minLength the minimum character length needed before triggering dropdown + * @param delay a delay between lookups + * @param type text input type (default "text") + * @param value text input value + * @param classes a set of CSS class names + */ +@UseExperimental(ImplicitReflectionSerializer::class) +open class TypeaheadRemoteInput<T : Any>( + serviceManager: KVServiceManager<T>, + function: suspend T.(String?, String?) -> List<String>, + private val stateFunction: (() -> String)? = null, + items: Int? = 8, minLength: Int = 1, delay: Int = 0, + type: TextInputType = TextInputType.TEXT, value: String? = null, classes: Set<String> = setOf() +) : TypeaheadInput(null, null, items, minLength, delay, type, value, classes) { + + private val kvUrlPrefix = window["kv_remote_url_prefix"] + private val urlPrefix: String = if (kvUrlPrefix != undefined) kvUrlPrefix else "" + + init { + val (url, method) = + serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] + ?: throw IllegalStateException("Function not specified!") + this.ajaxOptions = TaAjaxOptions( + urlPrefix + url, + preprocessQuery = { query -> + val state = stateFunction?.invoke() + JSON.plain.stringify(JsonRpcRequest(0, url, listOf(query, state))) + }, + preprocessData = { + JSON.plain.parse(String.serializer().list, it.result as String).toTypedArray() + }, + httpType = HttpType.valueOf(method.name) + ) + } +} + +/** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ +fun <T : Any> Container.typeaheadRemoteInput( + serviceManager: KVServiceManager<T>, + function: suspend T.(String?, String?) -> List<String>, + stateFunction: (() -> String)? = null, + items: Int? = 8, minLength: Int = 1, delay: Int = 0, + type: TextInputType = TextInputType.TEXT, value: String? = null, classes: Set<String> = setOf(), + init: (TypeaheadRemoteInput<T>.() -> Unit)? = null +): TypeaheadRemoteInput<T> { + val typeaheadRemoteInput = + TypeaheadRemoteInput( + serviceManager, function, stateFunction, items, minLength, delay, type, value, classes + ).apply { + init?.invoke(this) + } + this.add(typeaheadRemoteInput) + return typeaheadRemoteInput +} diff --git a/kvision-modules/kvision-bootstrap-typeahead-remote/webpack.config.d/css.js b/kvision-modules/kvision-bootstrap-typeahead-remote/webpack.config.d/css.js new file mode 100644 index 00000000..5d710d35 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-typeahead-remote/webpack.config.d/css.js @@ -0,0 +1,2 @@ +config.module.rules.push({ test: /\.css$/, loader: "style-loader!css-loader" }); + |