diff options
Diffstat (limited to 'kvision-modules/kvision-select')
26 files changed, 1636 insertions, 0 deletions
diff --git a/kvision-modules/kvision-select/build.gradle b/kvision-modules/kvision-select/build.gradle new file mode 100644 index 00000000..f8fcbc8a --- /dev/null +++ b/kvision-modules/kvision-select/build.gradle @@ -0,0 +1,10 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("bootstrap-select", "1.12.4") + dependency("ajax-bootstrap-select", "1.4.3") + } + +} diff --git a/kvision-modules/kvision-select/package.json.d/project.info b/kvision-modules/kvision-select/package.json.d/project.info new file mode 100644 index 00000000..80e675b0 --- /dev/null +++ b/kvision-modules/kvision-select/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Select module" +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/KVManagerSelect.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/KVManagerSelect.kt new file mode 100644 index 00000000..c7c3815a --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/KVManagerSelect.kt @@ -0,0 +1,65 @@ +/* + * 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 + +internal val KVManagerSelectInit = KVManagerSelect.init() + +/** + * Internal singleton object which initializes and configures KVision select module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerSelect { + internal const val AJAX_REQUEST_DELAY = 300 + internal const val KVNULL = "#kvnull" + + fun init() {} + + private val bootstrapSelectCss = try { + require("bootstrap-select/dist/css/bootstrap-select.min.css") + } catch (e: Throwable) { + } + private val bootstrapSelect = try { + require("bootstrap-select/dist/js/bootstrap-select.min.js") + require("./js/locales/bootstrap-select/bootstrap-select-i18n.min.js") + } catch (e: Throwable) { + } + private val bootstrapSelectAjaxCss = try { + require("ajax-bootstrap-select/dist/css/ajax-bootstrap-select.min.css") + } catch (e: Throwable) { + } + private val bootstrapSelectAjax = try { + require("ajax-bootstrap-select/dist/js/ajax-bootstrap-select.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js") + } catch (e: Throwable) { + } + +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt new file mode 100644 index 00000000..212dc456 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt @@ -0,0 +1,128 @@ +/* + * 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.jquery.JQueryXHR +import pl.treksoft.kvision.KVManagerSelect.AJAX_REQUEST_DELAY +import pl.treksoft.kvision.KVManagerSelect.KVNULL +import pl.treksoft.kvision.i18n.I18n +import pl.treksoft.kvision.utils.obj + +/** + * HTTP protocol type for the AJAX call. + */ +enum class HttpType(internal val type: String) { + GET("GET"), + POST("POST") +} + +/** + * Data type for the AJAX call. + */ +enum class DataType(internal val type: String) { + JSON("json"), + JSONP("jsonp"), + XML("xml"), + TEXT("text"), + SCRIPT("script") +} + +/** + * Data class for AJAX options. + * + * @constructor + * @param url the url address + * @param preprocessData + * [AjaxBootstrapSelect preprocessOption](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionspreprocessdata) + * option + * @param beforeSend + * [JQuery ajax.beforeSend](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) option + * @param data + * [JQuery ajax.data](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) option + * @param httpType + * [JQuery ajax.type](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) option + * @param minLength + * [AjaxBootstrapSelect minLength](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsminlength) option + * @param cache + * [AjaxBootstrapSelect cache](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionscache) option + * @param clearOnEmpty + * [AjaxBootstrapSelect clearOnEmpty](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsclearonempty) option + * @param clearOnError + * [AjaxBootstrapSelect clearOnError](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsclearonerror) option + * @param emptyRequest + * [AjaxBootstrapSelect emptyRequest](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsemptyrequest) option + * @param requestDelay + * [AjaxBootstrapSelect requestDelay](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsrequestdelay) option + * @param restoreOnError + * [AjaxBootstrapSelect restoreOnError](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsrestoreonerror) + * option + */ +data class AjaxOptions( + val url: String, val preprocessData: (dynamic) -> dynamic, val beforeSend: ((JQueryXHR) -> dynamic)? = null, + val data: dynamic = null, val httpType: HttpType = HttpType.GET, + val dataType: DataType = DataType.JSON, val minLength: Int = 0, + val cache: Boolean = true, val clearOnEmpty: Boolean = true, val clearOnError: Boolean = true, + val emptyRequest: Boolean = false, + val requestDelay: Int = AJAX_REQUEST_DELAY, val restoreOnError: Boolean = false +) + +/** + * Convert AjaxOptions to JavaScript JSON object. + * @param emptyOption add an empty position as the first select option + * @return JSON object + */ +fun AjaxOptions.toJs(emptyOption: Boolean): dynamic { + val procData = { data: dynamic -> + val processedData = this.preprocessData(data) + if (emptyOption) { + val ret = mutableListOf(obj { + this.value = KVNULL + this.text = "" + }) + @Suppress("UnsafeCastFromDynamic") + ret.addAll((processedData as Array<dynamic>).asList()) + ret.toTypedArray() + } else { + processedData + } + } + val language = I18n.language + return obj { + this.ajax = obj { + this.url = url + this.type = httpType.type + this.dataType = dataType.type + this.data = data + this.beforeSend = beforeSend + } + this.preprocessData = procData + this.minLength = minLength + this.cache = cache + this.clearOnEmpty = clearOnEmpty + this.clearOnError = clearOnError + this.emptyRequest = emptyRequest + this.preserveSelected = false + this.requestDelay = requestDelay + this.restoreOnError = restoreOnError + this.langCode = language + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt new file mode 100644 index 00000000..f19081e1 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt @@ -0,0 +1,285 @@ +/* + * 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.StringPair +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.utils.SnOn + +/** + * The form field component for Select control. + * + * The select control can be populated directly from *options* parameter or manually by adding + * [SelectOption] or [SelectOptGroup] components to the container. + * + * @constructor + * @param options an optional list of options (label to value pairs) for the select control + * @param value selected value + * @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 (AJAX) data source + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ +@Suppress("TooManyFunctions") +open class Select( + options: List<StringPair>? = null, value: String? = null, name: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null, + rich: Boolean = false +) : SimplePanel(setOf("form-group")), StringFormControl { + + /** + * A list of options (label to value pairs) for the select control. + */ + var options + get() = input.options + set(value) { + input.options = value + } + /** + * 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 + } + /** + * Additional options for remote (AJAX) data source. + */ + var ajaxOptions + get() = input.ajaxOptions + set(value) { + input.ajaxOptions = value + } + /** + * Maximal number of selected options. + */ + var maxOptions + get() = input.maxOptions + set(value) { + input.maxOptions = value + } + /** + * Determines if live search is available. + */ + var liveSearch + get() = input.liveSearch + set(value) { + input.liveSearch = 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_select_$counter" + final override val input: SelectInput = SelectInput( + options, value, 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<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 add(child: Component): SimplePanel { + input.add(child) + return this + } + + override fun addAll(children: List<Component>): 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<Component> { + 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.select( + options: List<StringPair>? = null, value: String? = null, name: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null, + rich: Boolean = false, init: (Select.() -> Unit)? = null + ): Select { + val select = Select(options, value, name, multiple, ajaxOptions, label, rich).apply { init?.invoke(this) } + this.add(select) + return select + } + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt new file mode 100644 index 00000000..8f4569c7 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt @@ -0,0 +1,363 @@ +/* + * 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 com.github.snabbdom.VNode +import pl.treksoft.kvision.KVManagerSelect.KVNULL +import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.CssSize +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.form.FormInput +import pl.treksoft.kvision.form.InputSize +import pl.treksoft.kvision.html.ButtonStyle +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.utils.asString +import pl.treksoft.kvision.utils.obj + +/** + * Select width types. See [Bootstrap Select width](http://silviomoreto.github.io/bootstrap-select/examples/#width). + */ +enum class SelectWidthType(internal val value: String) { + AUTO("auto"), + FIT("fit") +} + +/** + * The basic component for Select control. + * + * The select control can be populated directly from *options* parameter or manually by adding + * [SelectOption] or [SelectOptGroup] components to the container. + * + * @constructor + * @param options an optional list of options (label to value pairs) for the select control + * @param value selected value + * @param multiple allows multiple value selection (multiple values are comma delimited) + * @param ajaxOptions additional options for remote (AJAX) data source + * @param classes a set of CSS class names + */ +@Suppress("TooManyFunctions") +open class SelectInput( + options: List<StringPair>? = null, value: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, + classes: Set<String> = setOf() +) : SimplePanel(classes), FormInput { + + /** + * A list of options (label to value pairs) for the select control. + */ + internal var options by refreshOnUpdate(options, { setChildrenFromOptions() }) + /** + * A value of the selected option. + */ + var value by refreshOnUpdate(value, { refreshState() }) + /** + * The name attribute of the generated HTML select element. + */ + override var name: String? by refreshOnUpdate() + /** + * Determines if multiple value selection is allowed. + */ + var multiple by refreshOnUpdate(multiple) + /** + * Additional options for remote (AJAX) data source. + */ + var ajaxOptions by refreshOnUpdate(ajaxOptions, { + if (it != null) { + liveSearch = true + } + refresh() + }) + /** + * Maximal number of selected options. + */ + var maxOptions: Int? by refreshOnUpdate() + /** + * Determines if live search is available. + */ + var liveSearch by refreshOnUpdate(false) + /** + * The placeholder for the select control. + */ + var placeholder: String? by refreshOnUpdate() + /** + * The style of the select control. + */ + var style: ButtonStyle? by refreshOnUpdate() + /** + * The width of the select control. + */ + var selectWidth: CssSize? by refreshOnUpdate() + /** + * The width type of the select control. + */ + var selectWidthType: SelectWidthType? by refreshOnUpdate() + /** + * Determines if an empty option is automatically generated. + */ + var emptyOption by refreshOnUpdate(false, { setChildrenFromOptions() }) + /** + * Determines if the field is disabled. + */ + override var disabled by refreshOnUpdate(false) + /** + * Determines if the select is automatically focused. + */ + var autofocus: Boolean? by refreshOnUpdate() + /** + * The size of the input. + */ + override var size: InputSize? by refreshOnUpdate() + + init { + setChildrenFromOptions() + this.setInternalEventListener<SelectInput> { + change = { + val v = getElementJQuery()?.`val`() + self.value = v?.let { + calculateValue(it) + } + } + } + } + + private fun calculateValue(v: Any): String? { + return if (this.multiple) { + @Suppress("UNCHECKED_CAST") + val arr = v as? Array<String> + if (arr != null && arr.isNotEmpty()) { + arr.joinToString() + } else { + null + } + } else { + val vs = v as String + if (KVNULL == vs || vs.isEmpty()) { + null + } else { + vs + } + } + } + + override fun render(): VNode { + return render("select", childrenVNodes()) + } + + override fun add(child: Component): SimplePanel { + super.add(child) + refreshSelectInput() + return this + } + + override fun addAll(children: List<Component>): SimplePanel { + super.addAll(children) + refreshSelectInput() + return this + } + + override fun remove(child: Component): SimplePanel { + super.remove(child) + refreshSelectInput() + return this + } + + override fun removeAll(): SimplePanel { + super.removeAll() + refreshSelectInput() + return this + } + + private fun setChildrenFromOptions() { + if (ajaxOptions == null) { + super.removeAll() + if (emptyOption) { + super.add(SelectOption(KVNULL, "")) + } + options?.let { + val c = it.map { + SelectOption(it.first, it.second) + } + super.addAll(c) + } + } + this.refreshSelectInput() + } + + /** + * Opens dropdown with options. + */ + open fun showOptions() { + getElementJQueryD()?.selectpicker("show") + } + + /** + * Hides dropdown with options. + */ + open fun hideOptions() { + getElementJQueryD()?.selectpicker("hide") + } + + /** + * Toggles visibility of dropdown with options. + */ + open fun toggleOptions() { + getElementJQueryD()?.selectpicker("toggle") + } + + override fun getSnClass(): List<StringBoolPair> { + val cl = super.getSnClass().toMutableList() + cl.add("selectpicker" to true) + size?.let { + cl.add(it.className to true) + } + return cl + } + + private fun refreshSelectInput() { + getElementJQueryD()?.selectpicker("refresh") + refreshState() + } + + @Suppress("ComplexMethod") + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + name?.let { + sn.add("name" to it) + } + if (multiple) { + sn.add("multiple" to "multiple") + } + maxOptions?.let { + sn.add("data-max-options" to "" + it) + } + if (liveSearch) { + sn.add("data-live-search" to "true") + } + placeholder?.let { + sn.add("title" to translate(it)) + } + autofocus?.let { + if (it) { + sn.add("autofocus" to "autofocus") + } + } + if (disabled) { + sn.add("disabled" to "disabled") + } + val btnStyle = style?.className ?: "btn-default" + when (size) { + InputSize.LARGE -> { + sn.add("data-style" to "$btnStyle btn-lg") + } + InputSize.SMALL -> { + sn.add("data-style" to "$btnStyle btn-sm") + } + else -> { + sn.add("data-style" to btnStyle) + } + } + selectWidthType?.let { + sn.add("data-width" to it.value) + } ?: selectWidth?.let { + sn.add("data-width" to it.asString()) + } + return sn + } + + @Suppress("UnsafeCastFromDynamic") + override fun afterInsert(node: VNode) { + ajaxOptions?.let { + getElementJQueryD()?.selectpicker("render").ajaxSelectPicker(it.toJs(emptyOption)) + } ?: getElementJQueryD()?.selectpicker("render") + + this.getElementJQuery()?.on("show.bs.select", { e, _ -> + this.dispatchEvent("showBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("shown.bs.select", { e, _ -> + this.dispatchEvent("shownBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("hide.bs.select", { e, _ -> + this.dispatchEvent("hideBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("hidden.bs.select", { e, _ -> + this.dispatchEvent("hiddenBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("loaded.bs.select", { e, _ -> + this.dispatchEvent("loadedBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("rendered.bs.select", { e, _ -> + this.dispatchEvent("renderedBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("refreshed.bs.select", { e, _ -> + this.dispatchEvent("refreshedBsSelect", obj { detail = e }) + }) + this.getElementJQueryD()?.on("changed.bs.select", { e, cIndex: Int -> + e["clickedIndex"] = cIndex + this.dispatchEvent("changedBsSelect", obj { detail = e }) + }) + refreshState() + } + + @Suppress("UnsafeCastFromDynamic") + private fun refreshState() { + value?.let { + if (multiple) { + getElementJQueryD()?.selectpicker("val", it.split(",").toTypedArray()) + } else { + getElementJQueryD()?.selectpicker("val", it) + } + } ?: getElementJQueryD()?.selectpicker("val", null) + } + + /** + * Makes the input element focused. + */ + open fun focus() { + getElementJQuery()?.focus() + } + + /** + * Makes the input element blur. + */ + open fun blur() { + getElementJQuery()?.blur() + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.selectInput( + options: List<StringPair>? = null, value: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, + classes: Set<String> = setOf(), init: (SelectInput.() -> Unit)? = null + ): SelectInput { + val selectInput = SelectInput(options, value, multiple, ajaxOptions, classes).apply { init?.invoke(this) } + this.add(selectInput) + return selectInput + } + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt new file mode 100644 index 00000000..e33b3457 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt @@ -0,0 +1,91 @@ +/* + * 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 com.github.snabbdom.VNode +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.panel.SimplePanel + +/** + * The helper container for adding option groups to [Select]. + * + * The option group can be populated directly from *options* parameter or manually by adding + * [SelectOption] components to the container. + * + * @constructor + * @param label the label of the group + * @param options an optional list of options (label to value pairs) for the group + * @param maxOptions maximal number of selected options in the group + * @param disabled renders a disabled group + * @param classes a set of CSS class names + */ +open class SelectOptGroup( + label: String, options: List<StringPair>? = null, maxOptions: Int? = null, + disabled: Boolean = false, classes: Set<String> = setOf() +) : SimplePanel(classes) { + /** + * A label for the group. + */ + var label by refreshOnUpdate(label) + /** + * A list of options (label to value pairs) for the group. + */ + var options by refreshOnUpdate(options, { setChildrenFromOptions() }) + /** + * Maximal number of selected options in the group. + */ + var maxOptions by refreshOnUpdate(maxOptions) + /** + * Determines if the group is disabled. + */ + var disabled by refreshOnUpdate(disabled) + + init { + setChildrenFromOptions() + } + + override fun render(): VNode { + return render("optgroup", childrenVNodes()) + } + + private fun setChildrenFromOptions() { + this.removeAll() + options?.let { + val c = it.map { + SelectOption(it.first, it.second) + } + this.addAll(c) + } + } + + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + sn.add("label" to translate(label)) + maxOptions?.let { + sn.add("data-max-options" to "" + it) + } + if (disabled) { + sn.add("disabled" to "disabled") + } + return sn + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt new file mode 100644 index 00000000..d1bb636e --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt @@ -0,0 +1,103 @@ +/* + * 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 com.github.snabbdom.VNode +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget + +/** + * The helper component for adding options to [Select] or [SelectOptGroup]. + * + * @constructor + * @param value the value of the option + * @param label the label of the option + * @param subtext the small subtext after the label of the option + * @param icon the icon before the label of the option + * @param divider renders this option as a divider + * @param disabled renders a disabled option + * @param classes a set of CSS class names + */ +open class SelectOption( + value: String? = null, label: String? = null, subtext: String? = null, icon: String? = null, + divider: Boolean = false, disabled: Boolean = false, + classes: Set<String> = setOf() +) : Widget(classes) { + + /** + * The value of the option. + */ + var value by refreshOnUpdate(value) + /** + * The label of the option. + */ + var label by refreshOnUpdate(label) + /** + * The subtext after the label of the option. + */ + var subtext by refreshOnUpdate(subtext) + /** + * The icon before the label of the option. + */ + var icon by refreshOnUpdate(icon) + /** + * Determines if the option should be rendered as divider. + */ + var divider by refreshOnUpdate(divider) + /** + * Determines if the option should be disabled. + */ + var disabled by refreshOnUpdate(disabled) + + override fun render(): VNode { + return if (!divider) { + render("option", arrayOf(translate(label) ?: value)) + } else { + render("option") + } + } + + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + if (!divider) { + value?.let { + sn.add("value" to it) + } + subtext?.let { + sn.add("data-subtext" to translate(it)) + } + icon?.let { + if (it.startsWith("fa-")) { + sn.add("data-icon" to "fa $it") + } else { + sn.add("data-icon" to "glyphicon-$it") + } + } + if (disabled) { + sn.add("disabled" to "disabled") + } + } else { + sn.add("data-divider" to "true") + } + return sn + } +} diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js new file mode 100644 index 00000000..08b38207 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * English translation for the "en-US" and "en" language codes. + * Tobias Weichart <tobias.weichart@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["de-DE"]={currentlySelected:"Momentan ausgewählt",emptyTitle:"Hier klicken und eingeben",errorText:"Ergebnisse konnten nicht abgerufen wurden",searchPlaceholder:"Suche...",statusInitialized:"Suchbegriff eingeben",statusNoResults:"Keine Ergebnisse",statusSearching:"Suche...",statusTooShort:"Der Suchbegriff ist nicht lang genug"},$.fn.ajaxSelectPicker.locale.de=$.fn.ajaxSelectPicker.locale["de-DE"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.en-US.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.en-US.min.js new file mode 100644 index 00000000..8b130b97 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.en-US.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * English translation for the "en-US" and "en" language codes. + * Mark Carver <mark.carver@me.com> + */ +$.fn.ajaxSelectPicker.locale["en-US"]={currentlySelected:"Currently Selected",emptyTitle:"Select and begin typing",errorText:"Unable to retrieve results",searchPlaceholder:"Search...",statusInitialized:"Start typing a search query",statusNoResults:"No Results",statusSearching:"Searching...",statusTooShort:"Please enter more characters"},$.fn.ajaxSelectPicker.locale.en=$.fn.ajaxSelectPicker.locale["en-US"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js new file mode 100644 index 00000000..bbe3fe45 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Spanish translation for the "es-ES" and "es" language codes. + * Diomedes Domínguez <diomedes.domimnguez@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["es-ES"]={currentlySelected:"Seleccionado",emptyTitle:"Seleccione y comience a escribir",errorText:"No se puede recuperar resultados",searchPlaceholder:"Buscar...",statusInitialized:"Empieza a escribir una consulta de búsqueda",statusNoResults:"Sin Resultados",statusSearching:"Buscando...",statusTooShort:"Introduzca más caracteres"},$.fn.ajaxSelectPicker.locale.es=$.fn.ajaxSelectPicker.locale["es-ES"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js new file mode 100644 index 00000000..1d86582f --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * French translation for the "fr-FR" and "fr" language codes. + * Bastien (https://github.com/lisurc) + */ +$.fn.ajaxSelectPicker.locale["fr-FR"]={currentlySelected:"Actuellement sélectionné",emptyTitle:"Sélectionner et commencer à taper",errorText:"Impossible de récupérer les résultats",searchPlaceholder:"Rechercher...",statusInitialized:"Commencer à taper une recherche",statusNoResults:"Aucun résultat",statusSearching:"Recherche en cours...",statusTooShort:"Entrez plus de caractères"},$.fn.ajaxSelectPicker.locale.fr=$.fn.ajaxSelectPicker.locale["fr-FR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js new file mode 100644 index 00000000..b30deb3e --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Italian translation for the "it-IT" and "it" language codes. + * Luca Longo <l.longo@ambita.it> + */ +$.fn.ajaxSelectPicker.locale["it-IT"]={currentlySelected:"Selezionati",emptyTitle:"Clicca qui e scrivi...",errorText:"Impossibile recuperare dei risultati",searchPlaceholder:"Cerca...",statusInitialized:"Inizia a digitare...",statusNoResults:"Non ci sono risultati",statusSearching:"Ricerca in corso...",statusTooShort:"Inserisci altri caratteri"},$.fn.ajaxSelectPicker.locale.it=$.fn.ajaxSelectPicker.locale["it-IT"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js new file mode 100644 index 00000000..23a9a348 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Japanese translation for the "ja-JP" and "ja" language codes. + * Haginaga <haginaga@unetworks.jp> + */ +$.fn.ajaxSelectPicker.locale["ja-JP"]={currentlySelected:"現在の値",emptyTitle:"未選択",errorText:"検索できません",searchPlaceholder:"検索する",statusInitialized:"選択肢を入力",statusNoResults:"見つかりません",statusSearching:"検索中...",statusTooShort:"入力文字数不足"},$.fn.ajaxSelectPicker.locale.ja=$.fn.ajaxSelectPicker.locale["ja-JP"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js new file mode 100644 index 00000000..2fd5299b --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Korean translation for the "ko-KR" and "ko" language codes. + * Jo JungLae <ubermenschjo@google.com> + */ +$.fn.ajaxSelectPicker.locale["ko-KR"]={currentlySelected:"현재 선택된 항목",emptyTitle:"클릭하고 입력 시작",errorText:"결과를 검색할 수 없습니다",searchPlaceholder:"검색",statusInitialized:"검색어를 입력",statusNoResults:"검색결과가 없습니다",statusSearching:"검색중",statusTooShort:"추가 문자를 입력하십시오."},$.fn.ajaxSelectPicker.locale.ko=$.fn.ajaxSelectPicker.locale["ko-KR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js new file mode 100644 index 00000000..6c6a16f2 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Dutch translation for the "nl-NL" and "nl" language codes. + * Arjen Ruiterkamp <arjenruiterkamp@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["nl-NL"]={currentlySelected:"Momenteel geselecteerd",emptyTitle:"Selecteer en begin met typen",errorText:"Kon geen resultaten ophalen",searchPlaceholder:"Zoeken...",statusInitialized:"Begin met typen om te zoeken",statusNoResults:"Geen resultaten",statusSearching:"Zoeken...",statusTooShort:"U dient meer karakters in te voeren"},$.fn.ajaxSelectPicker.locale.nl=$.fn.ajaxSelectPicker.locale["nl-NL"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js new file mode 100644 index 00000000..f104f491 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Polish translation for the "pl-PL" and "pl" language codes. + * Robert Jaros <rjaros@treksoft.pl> + */ +$.fn.ajaxSelectPicker.locale["pl-PL"]={currentlySelected:"Aktualny wybór",emptyTitle:"Wybierz i zacznij pisać",errorText:"Nie można pobrać wyników",searchPlaceholder:"Szukaj...",statusInitialized:"Zacznij pisać warunek wyszukiwania",statusNoResults:"Brak wyników",statusSearching:"Szukam...",statusTooShort:"Wprowadź więcej znaków"},$.fn.ajaxSelectPicker.locale.pl=$.fn.ajaxSelectPicker.locale["pl-PL"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js new file mode 100644 index 00000000..2a6e743d --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Brazilian portuguese translation for the "pt-BR" and "pt" language codes. + * Luan Fonseca <luanfonceca@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["pt-BR"]={currentlySelected:"Selecionado Atualmente",emptyTitle:"Clique e comece a digitar",errorText:"Incapaz de encontrar resultados",searchPlaceholder:"Buscar...",statusInitialized:"Comece a digitar",statusNoResults:"Sem Resultados",statusSearching:"Buscando...",statusTooShort:"Digite mais caracteres"},$.fn.ajaxSelectPicker.locale.pt=$.fn.ajaxSelectPicker.locale["pt-BR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js new file mode 100644 index 00000000..aa6d4d06 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Russian translation for the "ru-RU" and "ru" language codes. + * Bercut Stray <bercut497@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["ru-RU"]={currentlySelected:"Выбрано",emptyTitle:"Выделите и начните печатать",errorText:"Невозможно получить результат",searchPlaceholder:"Искать...",statusInitialized:"Начните печатать запрос для поиска",statusNoResults:"Нет результатов",statusSearching:"Поиск...",statusTooShort:"Введите еще несколько символов"},$.fn.ajaxSelectPicker.locale.ru=$.fn.ajaxSelectPicker.locale["ru-RU"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js new file mode 100644 index 00000000..6af588f4 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Turkish translation for the "tr-TR" and "tr" language codes. + * Burak Çakırel <burakcakirel@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["tr-TR"]={currentlySelected:"Seçili olanlar",emptyTitle:"Seç ve yazmaya başla",errorText:"Sonuçlar alınamadı",searchPlaceholder:"Ara...",statusInitialized:"Arama için yazmaya başla",statusNoResults:"Sonuç yok",statusSearching:"Aranıyor...",statusTooShort:"Lütfen daha fazla karakter girin"},$.fn.ajaxSelectPicker.locale.tr=$.fn.ajaxSelectPicker.locale["tr-TR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/bootstrap-select/bootstrap-select-i18n.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/bootstrap-select/bootstrap-select-i18n.min.js new file mode 100644 index 00000000..4428d3c0 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/bootstrap-select/bootstrap-select-i18n.min.js @@ -0,0 +1 @@ +!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"",noneResultsText:"",countSelectedText:function(a,b){return 1==a?"... ({n})":"... ({n})"},maxOptionsText:function(a,b){return[1==a?"🛇":"🛇",1==b?"🛇":"🛇"]},selectAllText:"++",deselectAllText:"--",multipleSeparator:", "}}(a)});
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt new file mode 100644 index 00000000..1da1fe1a --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt @@ -0,0 +1,99 @@ +/* + * 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 test.pl.treksoft.kvision + +import org.w3c.dom.Element +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.panel.Root +import kotlin.browser.document +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +interface TestSpec { + fun beforeTest() + + fun afterTest() + + fun run(code: () -> Unit) { + beforeTest() + code() + afterTest() + } +} + +interface SimpleSpec : TestSpec { + + override fun beforeTest() { + } + + override fun afterTest() { + } + +} + +interface DomSpec : TestSpec { + + override fun beforeTest() { + val fixture = "<div style=\"display: none\" id=\"pretest\">" + + "<div id=\"test\"></div></div>" + document.body?.insertAdjacentHTML("afterbegin", fixture) + } + + override fun afterTest() { + val div = document.getElementById("pretest") + div?.let { jQuery(it).remove() } + jQuery(`object` = ".modal-backdrop").remove() + } + + fun assertEqualsHtml(expected: String?, actual: String?, message: String?) { + if (expected != null && actual != null) { + val exp = jQuery(html = expected) + val act = jQuery(html = actual) + val result = exp[0]?.isEqualNode(act[0]) + if (result == true) { + assertTrue(result == true, message) + } else { + assertEquals(expected, actual, message) + } + } else { + assertEquals(expected, actual, message) + } + } +} + +interface WSpec : DomSpec { + + fun runW(code: (widget: Widget, element: Element?) -> Unit) { + run { + val root = Root("test", true) + val widget = Widget() + widget.id = "test_id" + root.add(widget) + val element = document.getElementById("test_id") + code(widget, element) + } + } + +} + +external fun require(name: String): dynamic diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectInputSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectInputSpec.kt new file mode 100644 index 00000000..30f42e9c --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectInputSpec.kt @@ -0,0 +1,53 @@ +/* + * 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 test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.form.select.SelectWidthType +import pl.treksoft.kvision.form.select.SelectInput +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertTrue + +class SelectInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val selectInput = SelectInput(listOf("test1" to "Test 1", "test2" to "Test 2"), "test1", true).apply { + liveSearch = true + placeholder = "Choose ..." + selectWidthType = SelectWidthType.FIT + emptyOption = true + } + root.add(selectInput) + val element = document.getElementById("test") + assertTrue( + true == element?.innerHTML?.endsWith("<select class=\"selectpicker\" multiple=\"multiple\" data-live-search=\"true\" title=\"Choose ...\" data-style=\"btn-default\" data-width=\"fit\" tabindex=\"-98\"><option value=\"#kvnull\"></option><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option></select></div>"), + "Should render correct select input" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptGroupSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptGroupSpec.kt new file mode 100644 index 00000000..bd88f560 --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptGroupSpec.kt @@ -0,0 +1,54 @@ +/* + * 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 test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.form.select.SelectOptGroup +import pl.treksoft.kvision.form.select.SelectOption +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class SelectOptGroupSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val selectOptGroup = SelectOptGroup("Group", listOf("test1" to "Test 1", "test2" to "Test 2"), 2) + root.add(selectOptGroup) + val element = document.getElementById("test") + assertEqualsHtml( + "<optgroup label=\"Group\" data-max-options=\"2\"><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option></optgroup>", + element?.innerHTML, + "Should render correct select option group" + ) + selectOptGroup.add(SelectOption("test3", "Test 3")) + assertEqualsHtml( + "<optgroup label=\"Group\" data-max-options=\"2\"><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option><option value=\"test3\">Test 3</option></optgroup>", + element?.innerHTML, + "Should render correct select option group with added option" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptionSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptionSpec.kt new file mode 100644 index 00000000..f7e07d42 --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptionSpec.kt @@ -0,0 +1,59 @@ +/* + * 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 test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.form.select.SelectOption +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class SelectOptionSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val selectOption = SelectOption("testValue", "testLabel") + root.add(selectOption) + val element = document.getElementById("test") + assertEqualsHtml( + "<option value=\"testValue\">testLabel</option>", + element?.innerHTML, + "Should render correct select option" + ) + selectOption.icon = "fa-flag" + assertEqualsHtml( + "<option value=\"testValue\" data-icon=\"fa fa-flag\">testLabel</option>", + element?.innerHTML, + "Should render correct select option with icon" + ) + selectOption.divider = true + assertEqualsHtml( + "<option data-divider=\"true\"></option>", + element?.innerHTML, + "Should render correct divider option" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt new file mode 100644 index 00000000..eaccd551 --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt @@ -0,0 +1,58 @@ +/* + * 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 test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.form.select.SelectWidthType +import pl.treksoft.kvision.form.select.Select +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertTrue + +class SelectSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val select = Select(listOf("test1" to "Test 1", "test2" to "Test 2"), "test1", null, true, null, "Label").apply { + liveSearch = true + placeholder = "Choose ..." + selectWidthType = SelectWidthType.FIT + emptyOption = true + } + root.add(select) + val element = document.getElementById("test") + val id = select.input.id + assertTrue( + true == element?.innerHTML?.startsWith("<div class=\"form-group\"><label class=\"control-label\" for=\"$id\">Label</label>"), + "Should render correct select form control" + ) + assertTrue( + true == element?.innerHTML?.endsWith("<select class=\"form-control selectpicker\" id=\"$id\" multiple=\"multiple\" data-live-search=\"true\" title=\"Choose ...\" data-style=\"btn-default\" data-width=\"fit\" tabindex=\"-98\"><option value=\"#kvnull\"></option><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option></select></div></div>"), + "Should render correct select form control" + ) + } + } + +}
\ No newline at end of file |