diff options
7 files changed, 182 insertions, 20 deletions
diff --git a/src/main/assets/js/ajax-bootstrap-select.pl-PL.js b/src/main/assets/js/ajax-bootstrap-select.pl-PL.js new file mode 100644 index 00000000..3006d5af --- /dev/null +++ b/src/main/assets/js/ajax-bootstrap-select.pl-PL.js @@ -0,0 +1,88 @@ +/*! + * 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.2 + * @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-01 11:24:59 AM EDT + */ +!(function ($) { +/*! + * Polish translation for the "pl-PL" and "pl" language codes. + * Robert Jaros <rjaros@treksoft.pl> +*/ +$.fn.ajaxSelectPicker.locale['pl-PL'] = { + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} currentlySelected = 'Currently Selected' + * @markdown + * The text to use for the label of the option group when currently selected options are preserved. + */ + currentlySelected: 'Aktualnie wybrane', + + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} emptyTitle = 'Select and begin typing' + * @markdown + * The text to use as the title for the select element when there are no items to display. + */ + emptyTitle: 'Wybierz i zacznij pisać', + + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} errorText = ''Unable to retrieve results' + * @markdown + * The text to use in the status container when a request returns with an error. + */ + errorText: 'Nie udało się pobrać wyników', + + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} searchPlaceholder = 'Search...' + * @markdown + * The text to use for the search input placeholder attribute. + */ + searchPlaceholder: 'Szukaj...', + + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} statusInitialized = 'Start typing a search query' + * @markdown + * The text used in the status container when it is initialized. + */ + statusInitialized: 'Zacznij pisać warunek wyszukiwania', + + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} statusNoResults = 'No Results' + * @markdown + * The text used in the status container when the request returns no results. + */ + statusNoResults: 'Brak wyników', + + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} statusSearching = 'Searching...' + * @markdown + * The text to use in the status container when a request is being initiated. + */ + statusSearching: 'Szukam...', + + /** + * @member $.fn.ajaxSelectPicker.locale + * @cfg {String} statusTooShort = 'Please enter more characters' + * @markdown + * The text used in the status container when the request returns no results. + */ + statusTooShort: 'Wprowadź więcej znaków' +}; +$.fn.ajaxSelectPicker.locale.pl = $.fn.ajaxSelectPicker.locale['pl-PL']; +})(jQuery); diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt index 985f9f98..a3fec251 100644 --- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt +++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt @@ -187,6 +187,36 @@ class Showcase : ApplicationBase() { } root.add(select7) + val select8 = Select(label = "Wybierz repozytorium").apply { + emptyOption = true + ajaxOptions = AjaxOptions("https://api.github.com/search/repositories", processData = { + it.items.map { item -> + obj { + this.value = item.id + this.text = item.name + this.data = obj { + this.subtext = item.owner.login + } + } + } + }, processParams = obj { + q = "{{{q}}}" + }, minLength = 3, requestDelay = 1000) + setEventListener<Select> { + change = { _ -> + println(self.value) + } + } + } + root.add(select8) + val mbuttons8 = Button("Sprawdz repozytorium").setEventListener<Button> { + click = { + println(select8.value) + select8.value = null + } + } + root.add(mbuttons8) + val container = SimplePanel(setOf("abc", "def")) val h1 = Tag(H1, "To jest <i>test pisania</i> tekstu", false, null, classes = setOf("test", "test2")) container.add(h1) diff --git a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt index a1f48982..541733b3 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt @@ -14,6 +14,9 @@ import kotlin.browser.document import kotlin.dom.clear object KVManager { + internal const val AJAX_REQUEST_DELAY = 300 + internal const val KVNULL = "#kvnull" + private val bootstrapWebpack = require("bootstrap-webpack") private val fontAwesomeWebpack = require("font-awesome-webpack") private val resizable = require("jquery-resizable-dom") @@ -23,6 +26,7 @@ object KVManager { private val bootstrapSelectI18n = require("./js/bootstrap-select-i18n.min.js") private val bootstrapSelectAjaxCss = require("ajax-bootstrap-select/dist/css/ajax-bootstrap-select.min.css") private val bootstrapSelectAjax = require("ajax-bootstrap-select/dist/js/ajax-bootstrap-select.min.js") + private val bootstrapSelectAjaxI18n = require("./js/ajax-bootstrap-select.pl-PL.js") private val sdPatch = Snabbdom.init(arrayOf(classModule, attributesModule, propsModule, styleModule, eventListenersModule, datasetModule)) diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt index 8dbb5f65..d86e6899 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt @@ -1,5 +1,7 @@ package pl.treksoft.kvision.form.select +import pl.treksoft.kvision.core.KVManager.AJAX_REQUEST_DELAY +import pl.treksoft.kvision.core.KVManager.KVNULL import pl.treksoft.kvision.snabbdom.obj enum class HttpType(val type: String) { @@ -20,17 +22,38 @@ data class AjaxOptions(val url: String, val processData: (dynamic) -> dynamic, 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 preserveSelected: Boolean = true, - val requestDelay: Int = 300, val restoreOnError: Boolean = false) + val requestDelay: Int = AJAX_REQUEST_DELAY, val restoreOnError: Boolean = false) -fun AjaxOptions.toJs(): dynamic { +fun AjaxOptions.toJs(emptyOption: Boolean): dynamic { + val procData = { data: dynamic -> + val processedData = this.processData(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 + } + } return obj { this.ajax = obj { this.url = url this.type = httpType.type + this.dataType = dataType.type this.data = processParams } - this.preprocessData = processData + this.preprocessData = procData + this.minLength = minLength + this.cache = cache + this.clearOnEmpty = clearOnEmpty + this.clearOnError = clearOnError + this.emptyRequest = emptyRequest + this.preserveSelected = preserveSelected + this.requestDelay = requestDelay + this.restoreOnError = restoreOnError } } - -data class AjaxData(val value: String, val text: String? = null) diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt index 321e3a70..4b991605 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt @@ -7,8 +7,9 @@ import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.snabbdom.SnOn import pl.treksoft.kvision.snabbdom.StringPair +@Suppress("TooManyFunctions") open class Select(options: List<StringPair>? = null, value: String? = null, - multiple: Boolean = false, label: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null, rich: Boolean = false) : SimplePanel(setOf("form-group")), StringFormField { var options @@ -36,6 +37,11 @@ open class Select(options: List<StringPair>? = null, value: String? = null, set(value) { input.multiple = value } + var ajaxOptions + get() = input.ajaxOptions + set(value) { + input.ajaxOptions = value + } var maxOptions get() = input.maxOptions set(value) { @@ -93,7 +99,8 @@ open class Select(options: List<StringPair>? = null, value: String? = null, } private val idc = "kv_form_select_" + counter - val input: SelectInput = SelectInput(options, value, multiple, null, setOf("form-control")).apply { id = idc } + val input: SelectInput = SelectInput(options, value, multiple, ajaxOptions, + setOf("form-control")).apply { id = idc } val flabel: FieldLabel = FieldLabel(idc, label, rich) init { @@ -159,4 +166,8 @@ open class Select(options: List<StringPair>? = null, value: String? = null, open fun toggleOptions() { input.toggleOptions() } + + open fun deselect() { + input.deselect() + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt index 7522ef98..c95cf434 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt @@ -2,6 +2,7 @@ package pl.treksoft.kvision.form.select import com.github.snabbdom.VNode import pl.treksoft.kvision.core.CssSize +import pl.treksoft.kvision.core.KVManager.KVNULL import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.form.StringFormField @@ -11,13 +12,12 @@ import pl.treksoft.kvision.snabbdom.StringBoolPair import pl.treksoft.kvision.snabbdom.StringPair import pl.treksoft.kvision.snabbdom.obj -private val _aKVNULL = "#kvnull" - enum class SELECTWIDTHTYPE(val value: String) { AUTO("auto"), FIT("fit") } +@Suppress("TooManyFunctions") open class SelectInput(options: List<StringPair>? = null, value: String? = null, multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, classes: Set<String> = setOf()) : SimplePanel(classes), StringFormField { @@ -125,7 +125,7 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null, } } else { val vs = it as String - if (_aKVNULL == vs) { + if (KVNULL == vs) { null } else { vs @@ -165,15 +165,17 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null, } private fun setChildrenFromOptions() { - super.removeAll() - if (emptyOption) { - super.add(SelectOption(_aKVNULL, "")) - } - options?.let { - val c = it.map { - SelectOption(it.first, it.second) + 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) } - super.addAll(c) } this.refreshSelectInput() } @@ -190,6 +192,10 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null, getElementJQueryD()?.selectpicker("toggle") } + open fun deselect() { + getElementJQueryD()?.selectpicker("deselectAll") + } + override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() cl.add("selectpicker" to true) @@ -253,7 +259,7 @@ open class SelectInput(options: List<StringPair>? = null, value: String? = null, @Suppress("UnsafeCastFromDynamic") override fun afterInsert(node: VNode) { ajaxOptions?.let { - getElementJQueryD()?.selectpicker("render").ajaxSelectPicker(it.toJs()) + getElementJQueryD()?.selectpicker("render").ajaxSelectPicker(it.toJs(emptyOption)) } ?: getElementJQueryD()?.selectpicker("render") this.getElementJQuery()?.on("show.bs.select", { e, _ -> diff --git a/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt index 129f74da..7034f836 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt @@ -14,7 +14,7 @@ class SelectSpec : DomSpec { fun render() { run { val root = Root("test") - val select = Select(listOf("test1" to "Test 1", "test2" to "Test 2"), "test1", true, "Label").apply { + val select = Select(listOf("test1" to "Test 1", "test2" to "Test 2"), "test1", true, null, "Label").apply { liveSearch = true placeholder = "Choose ..." selectWidthType = SELECTWIDTHTYPE.FIT |