diff options
7 files changed, 280 insertions, 0 deletions
| diff --git a/build.gradle b/build.gradle index db61ad2b..c0d156a6 100644 --- a/build.gradle +++ b/build.gradle @@ -180,6 +180,7 @@ dokka {              'kvision-modules/kvision-remote/src/main/kotlin',              'kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin',              'kvision-modules/kvision-tabulator-remote/src/main/kotlin', +            'kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin',              'kvision-modules/kvision-common/src/main/kotlin',              'kvision-modules/kvision-common-types/src/main/kotlin',              'kvision-modules/kvision-common-annotations/src/main/kotlin', 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" }); + diff --git a/settings.gradle b/settings.gradle index 8b3b6cc0..be1b7b75 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,6 +13,7 @@ include 'kvision-modules:kvision-base',          'kvision-modules:kvision-bootstrap-select-remote',          'kvision-modules:kvision-bootstrap-dialog',          'kvision-modules:kvision-bootstrap-typeahead', +        'kvision-modules:kvision-bootstrap-typeahead-remote',          'kvision-modules:kvision-richtext',          'kvision-modules:kvision-handlebars',          'kvision-modules:kvision-i18n', | 
