aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/pl/treksoft
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/pl/treksoft')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/KVManager.kt203
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt8
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/core/Widget.kt6
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/Form.kt18
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt14
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt3
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt128
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt285
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt363
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt91
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt103
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt263
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt323
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt79
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt133
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt246
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt291
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt333
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt327
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/html/Button.kt2
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/i18n/I18n.kt123
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/i18n/I18nManager.kt96
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/i18n/SimpleI18nManager.kt34
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/types/KDate.kt6
24 files changed, 155 insertions, 3323 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/KVManager.kt b/src/main/kotlin/pl/treksoft/kvision/KVManager.kt
index 80279020..de819c98 100644
--- a/src/main/kotlin/pl/treksoft/kvision/KVManager.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/KVManager.kt
@@ -29,13 +29,9 @@ import com.github.snabbdom.datasetModule
import com.github.snabbdom.eventListenersModule
import com.github.snabbdom.propsModule
import com.github.snabbdom.styleModule
-import org.w3c.dom.asList
import pl.treksoft.kvision.core.Component
-import pl.treksoft.kvision.i18n.I18n
import pl.treksoft.kvision.utils.isIE11
-import pl.treksoft.kvision.utils.obj
import kotlin.browser.document
-import kotlin.browser.window
import kotlin.dom.clear
/**
@@ -49,208 +45,18 @@ external fun require(name: String): dynamic
*/
@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught", "LargeClass")
internal object KVManager {
- internal const val AJAX_REQUEST_DELAY = 300
- internal const val KVNULL = "#kvnull"
-
- private val links = document.getElementsByTagName("link")
- private val bootstrapWebpack = try {
- val bootswatch = links.asList().find { it.getAttribute("href")?.contains("bootstrap.min.css") ?: false }
- if (bootswatch != null) {
- if (bootswatch.getAttribute("href")?.contains("/paper/") == true) {
- require("./css/paper.css")
- }
- require("bootstrap-webpack!./js/bootstrap.config.js")
- } else {
- require("bootstrap-webpack")
- }
- } catch (e: Throwable) {
- }
- private val fontAwesomeWebpack = try {
- require("font-awesome-webpack")
- } catch (e: Throwable) {
- }
- private val awesomeBootstrapCheckbox = try {
- require("awesome-bootstrap-checkbox")
- } catch (e: Throwable) {
- }
- 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/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/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js")
- require("../../js/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js")
- } catch (e: Throwable) {
- }
- private val trixCss = try {
- require("trix/dist/trix.css")
- } catch (e: Throwable) {
- }
- private val trix = try {
- val trix = require("trix")
- window.asDynamic().Trix = trix
- trix.config.languages = obj {}
- trix.config.languages["en"] = obj {}
- for (key in js("Object").keys(trix.config.lang)) {
- trix.config.languages["en"][key] = trix.config.lang[key]
- }
- val orig = trix.config.toolbar.getDefaultHTML
- trix.config.toolbar.getDefaultHTML = {
- val config = if (trix.config.languages[I18n.language] != undefined) {
- trix.config.languages[I18n.language]
- } else {
- trix.config.languages["en"]
- }
- for (key in js("Object").keys(trix.config.lang)) {
- trix.config.lang[key] = config[key]
- }
- orig()
- }
- require("../../js/js/locales/trix/trix.pl.js")
- } catch (e: Throwable) {
- }
- private val bootstrapDateTimePickerCss = try {
- require("bootstrap-datetime-picker/css/bootstrap-datetimepicker.min.css")
- } catch (e: Throwable) {
- }
- private val bootstrapDateTimePicker = try {
- require("bootstrap-datetime-picker/js/bootstrap-datetimepicker.min.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ar.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.az.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bg.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bn.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ca.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.cs.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.da.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.de.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ee.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.el.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.es.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fi.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fr.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.he.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hr.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hu.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hy.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.id.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.is.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.it.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ja.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ko.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lt.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lv.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nl.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.no.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pl.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ro.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ru.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sk.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sl.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sv.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.th.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.tr.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ua.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.uk.js")
- require("../../js/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh.js")
- } catch (e: Throwable) {
- }
- private val bootstrapTouchspinCss = try {
- require("bootstrap-touchspin/dist/jquery.bootstrap-touchspin.min.css")
- } catch (e: Throwable) {
- }
- private val bootstrapTouchspin = try {
- require("bootstrap-touchspin/dist/jquery.bootstrap-touchspin.min.js")
+ private val kvisionBootstrap = try {
+ require("kvision-bootstrap").pl.treksoft.kvision.KVManagerBootstrap
} catch (e: Throwable) {
}
private val elementResizeEvent = try {
require("element-resize-event")
} catch (e: Throwable) {
}
- private val bootstrapFileinputCss = try {
- require("bootstrap-fileinput/css/fileinput.min.css")
- } catch (e: Throwable) {
- }
- private val bootstrapFileinputCssFa = try {
- require("bootstrap-fileinput/themes/explorer-fa/theme.min.css")
- } catch (e: Throwable) {
- }
- private val bootstrapFileinput = try {
- require("bootstrap-fileinput")
- require("../../js/js/locales/bootstrap-fileinput/ar.js")
- require("../../js/js/locales/bootstrap-fileinput/az.js")
- require("../../js/js/locales/bootstrap-fileinput/bg.js")
- require("../../js/js/locales/bootstrap-fileinput/ca.js")
- require("../../js/js/locales/bootstrap-fileinput/cr.js")
- require("../../js/js/locales/bootstrap-fileinput/cs.js")
- require("../../js/js/locales/bootstrap-fileinput/da.js")
- require("../../js/js/locales/bootstrap-fileinput/de.js")
- require("../../js/js/locales/bootstrap-fileinput/el.js")
- require("../../js/js/locales/bootstrap-fileinput/es.js")
- require("../../js/js/locales/bootstrap-fileinput/et.js")
- require("../../js/js/locales/bootstrap-fileinput/fa.js")
- require("../../js/js/locales/bootstrap-fileinput/fi.js")
- require("../../js/js/locales/bootstrap-fileinput/fr.js")
- require("../../js/js/locales/bootstrap-fileinput/gl.js")
- require("../../js/js/locales/bootstrap-fileinput/id.js")
- require("../../js/js/locales/bootstrap-fileinput/it.js")
- require("../../js/js/locales/bootstrap-fileinput/ja.js")
- require("../../js/js/locales/bootstrap-fileinput/ka.js")
- require("../../js/js/locales/bootstrap-fileinput/ko.js")
- require("../../js/js/locales/bootstrap-fileinput/kz.js")
- require("../../js/js/locales/bootstrap-fileinput/lt.js")
- require("../../js/js/locales/bootstrap-fileinput/nl.js")
- require("../../js/js/locales/bootstrap-fileinput/no.js")
- require("../../js/js/locales/bootstrap-fileinput/pl.js")
- require("../../js/js/locales/bootstrap-fileinput/pt.js")
- require("../../js/js/locales/bootstrap-fileinput/ro.js")
- require("../../js/js/locales/bootstrap-fileinput/ru.js")
- require("../../js/js/locales/bootstrap-fileinput/sk.js")
- require("../../js/js/locales/bootstrap-fileinput/sl.js")
- require("../../js/js/locales/bootstrap-fileinput/sv.js")
- require("../../js/js/locales/bootstrap-fileinput/th.js")
- require("../../js/js/locales/bootstrap-fileinput/tr.js")
- require("../../js/js/locales/bootstrap-fileinput/uk.js")
- require("../../js/js/locales/bootstrap-fileinput/vi.js")
- require("../../js/js/locales/bootstrap-fileinput/zh.js")
- } catch (e: Throwable) {
- }
- private val bootstrapFileinputFa = try {
- require("bootstrap-fileinput/themes/explorer-fa/theme.min.js")
- } catch (e: Throwable) {
- }
private val resizable = try {
require("jquery-resizable-dom")
} catch (e: Throwable) {
}
- private val handlebars = try {
- require("handlebars/dist/handlebars.runtime.min.js")
- } catch (e: Throwable) {
- }
- private val jed = try {
- require("jed")
- } catch (e: Throwable) {
- }
internal val fecha = require("fecha")
private val sdPatch = Snabbdom.init(
arrayOf(
@@ -259,7 +65,10 @@ internal object KVManager {
)
)
private val sdVirtualize = require("snabbdom-virtualize/strings").default
- private val styleCss = require("./css/style.css")
+ private val styleCss = try {
+ require("./css/style.css")
+ } catch (e: Throwable) {
+ }
internal fun patch(id: String, vnode: VNode): VNode {
val container = document.getElementById(id)
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt b/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt
index c4ac8295..d54af6f7 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt
@@ -462,13 +462,13 @@ abstract class StyledComponent : Component {
return snstyle
}
- internal fun <T> refreshOnUpdate(refreshFunction: ((T) -> Unit) = { this.refresh() }) =
+ protected fun <T> refreshOnUpdate(refreshFunction: ((T) -> Unit) = { this.refresh() }) =
RefreshDelegateProvider<T>(null, refreshFunction)
- internal fun <T> refreshOnUpdate(initialValue: T, refreshFunction: ((T) -> Unit) = { this.refresh() }) =
+ protected fun <T> refreshOnUpdate(initialValue: T, refreshFunction: ((T) -> Unit) = { this.refresh() }) =
RefreshDelegateProvider(initialValue, refreshFunction)
- internal inner class RefreshDelegateProvider<T>(
+ protected inner class RefreshDelegateProvider<T>(
private val initialValue: T?, private val refreshFunction: (T) -> Unit
) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): RefreshDelegate<T> {
@@ -477,7 +477,7 @@ abstract class StyledComponent : Component {
}
}
- internal inner class RefreshDelegate<T>(private val refreshFunction: ((T) -> Unit)) {
+ protected inner class RefreshDelegate<T>(private val refreshFunction: ((T) -> Unit)) {
@Suppress("UNCHECKED_CAST")
operator fun getValue(thisRef: StyledComponent, property: KProperty<*>): T {
val value = propertyValues[property.name]
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
index e7b94cba..52f60813 100644
--- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt
@@ -84,9 +84,9 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
*/
var draggable: Boolean? by refreshOnUpdate()
- internal var surroundingSpan by refreshOnUpdate(false)
+ protected var surroundingSpan by refreshOnUpdate(false)
- internal var eventTarget: Widget? = null
+ var eventTarget: Widget? = null
private var vnode: VNode? = null
@@ -602,7 +602,7 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() {
}
}
- internal open fun dispatchEvent(type: String, eventInitDict: CustomEventInit): Boolean? {
+ protected open fun dispatchEvent(type: String, eventInitDict: CustomEventInit): Boolean? {
val event = org.w3c.dom.CustomEvent(type, eventInitDict)
return this.getElement()?.dispatchEvent(event)
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt
index 323d0e1e..b45eed60 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt
@@ -26,11 +26,9 @@ import kotlinx.serialization.Mapper
import kotlinx.serialization.decode
import kotlinx.serialization.json.JSON
import kotlinx.serialization.serializer
-import pl.treksoft.kvision.form.upload.Upload
import pl.treksoft.kvision.i18n.I18n.trans
import pl.treksoft.kvision.types.KDate
import pl.treksoft.kvision.types.KFile
-import pl.treksoft.kvision.utils.getContent
import kotlin.js.Json
import kotlin.reflect.KProperty1
@@ -255,22 +253,6 @@ class Form<K : Any>(private val panel: FormPanel<K>? = null, private val seriali
}
/**
- * Returns file with the content read.
- * @param key key identifier of the control
- * @param kFile object identifying the file
- * @return KFile object
- */
- @Suppress("EXPERIMENTAL_FEATURE_WARNING")
- suspend fun getContent(
- key: KProperty1<K, List<KFile>?>,
- kFile: KFile
- ): KFile {
- val control = getControl(key) as Upload
- val content = control.getNativeFile(kFile)?.getContent()
- return kFile.copy(content = content)
- }
-
- /**
* Returns current data model as JSON.
* @return data model as JSON
*/
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt
index a013c076..3811ed82 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt
@@ -375,20 +375,6 @@ open class FormPanel<K : Any>(
}
/**
- * Returns an object with the content of the file.
- * @param key key identifier of the control
- * @param kFile object identifying the file
- * @return KFile object
- */
- @Suppress("EXPERIMENTAL_FEATURE_WARNING")
- suspend fun getContent(
- key: KProperty1<K, List<KFile>?>,
- kFile: KFile
- ): KFile {
- return form.getContent(key, kFile)
- }
-
- /**
* Returns current data model as JSON.
* @return data model as JSON
*/
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt
index b4ed127a..fdc1e3af 100644
--- a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt
@@ -28,7 +28,6 @@ import pl.treksoft.kvision.form.FieldLabel
import pl.treksoft.kvision.form.HelpBlock
import pl.treksoft.kvision.form.InputSize
import pl.treksoft.kvision.form.StringFormControl
-import pl.treksoft.kvision.form.select.Select
import pl.treksoft.kvision.panel.SimplePanel
/**
@@ -99,7 +98,7 @@ open class RadioGroup(
setSizeToChildren(value)
}
- private val idc = "kv_form_radiogroup_" + Select.counter
+ private val idc = "kv_form_radiogroup_$counter"
final override val input = CheckInput()
final override val flabel: FieldLabel = FieldLabel(idc, label, rich)
final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false }
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt
deleted file mode 100644
index d802a111..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.select
-
-import pl.treksoft.jquery.JQueryXHR
-import pl.treksoft.kvision.KVManager.AJAX_REQUEST_DELAY
-import pl.treksoft.kvision.KVManager.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/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt
deleted file mode 100644
index f19081e1..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.select
-
-import pl.treksoft.kvision.core.Component
-import pl.treksoft.kvision.core.Container
-import pl.treksoft.kvision.core.StringBoolPair
-import pl.treksoft.kvision.core.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/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt
deleted file mode 100644
index 6d6f0fc5..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.select
-
-import com.github.snabbdom.VNode
-import pl.treksoft.kvision.KVManager.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/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt
deleted file mode 100644
index e33b3457..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.select
-
-import 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/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt
deleted file mode 100644
index d1bb636e..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.select
-
-import 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/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt b/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt
deleted file mode 100644
index 4fa68e47..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.spinner
-
-import pl.treksoft.kvision.core.Container
-import pl.treksoft.kvision.core.StringBoolPair
-import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.FieldLabel
-import pl.treksoft.kvision.form.HelpBlock
-import pl.treksoft.kvision.form.NumberFormControl
-import pl.treksoft.kvision.panel.SimplePanel
-import pl.treksoft.kvision.utils.SnOn
-
-/**
- * The form field component for spinner control.
- *
- * @constructor
- * @param value spinner value
- * @param name the name attribute of the generated HTML input element
- * @param min minimal value (default 0)
- * @param max maximal value (default 100)
- * @param step step value (default 1)
- * @param decimals number of decimal digits (default 0)
- * @param buttonsType spinner buttons type
- * @param forceType spinner force rounding type
- * @param label label text bound to the input element
- * @param rich determines if [label] can contain HTML code
- */
-open class Spinner(
- value: Number? = null, name: String? = null, min: Int = 0, max: Int = DEFAULT_MAX, step: Double = DEFAULT_STEP,
- decimals: Int = 0, buttonsType: ButtonsType = ButtonsType.VERTICAL,
- forceType: ForceType = ForceType.NONE, label: String? = null,
- rich: Boolean = false
-) : SimplePanel(setOf("form-group")), NumberFormControl {
-
- /**
- * Spinner value.
- */
- override var value
- get() = input.value
- set(value) {
- input.value = value
- }
- /**
- * The value attribute of the generated HTML input element.
- *
- * This value is placed directly in generated HTML code, while the [value] property is dynamically
- * bound to the spinner input value.
- */
- var startValue
- get() = input.startValue
- set(value) {
- input.startValue = value
- }
- /**
- * Minimal value.
- */
- var min
- get() = input.min
- set(value) {
- input.min = value
- }
- /**
- * Maximal value.
- */
- var max
- get() = input.max
- set(value) {
- input.max = value
- }
- /**
- * Step value.
- */
- var step
- get() = input.step
- set(value) {
- input.step = value
- }
- /**
- * Number of decimal digits value.
- */
- var decimals
- get() = input.decimals
- set(value) {
- input.decimals = value
- }
- /**
- * Spinner buttons type.
- */
- var buttonsType
- get() = input.buttonsType
- set(value) {
- input.buttonsType = value
- }
- /**
- * Spinner force rounding type.
- */
- var forceType
- get() = input.forceType
- set(value) {
- input.forceType = value
- }
- /**
- * The placeholder for the spinner input.
- */
- var placeholder
- get() = input.placeholder
- set(value) {
- input.placeholder = value
- }
- /**
- * Determines if the spinner is automatically focused.
- */
- var autofocus
- get() = input.autofocus
- set(value) {
- input.autofocus = value
- }
- /**
- * Determines if the spinner is read-only.
- */
- var readonly
- get() = input.readonly
- set(value) {
- input.readonly = value
- }
- /**
- * The label text bound to the spinner input 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
- }
-
- protected val idc = "kv_form_spinner_$counter"
- final override val input: SpinnerInput = SpinnerInput(value, min, max, step, decimals, buttonsType, forceType)
- .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 getValueAsString(): String? {
- return input.getValueAsString()
- }
-
- /**
- * Change value in plus.
- */
- open fun spinUp(): Spinner {
- input.spinUp()
- return this
- }
-
- /**
- * Change value in minus.
- */
- open fun spinDown(): Spinner {
- input.spinDown()
- return this
- }
-
- 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.spinner(
- value: Number? = null,
- name: String? = null,
- min: Int = 0,
- max: Int = DEFAULT_MAX,
- step: Double = DEFAULT_STEP,
- decimals: Int = 0,
- buttonsType: ButtonsType = ButtonsType.VERTICAL,
- forceType: ForceType = ForceType.NONE,
- label: String? = null,
- rich: Boolean = false,
- init: (Spinner.() -> Unit)? = null
- ): Spinner {
- val spinner = Spinner(value, name, min, max, step, decimals, buttonsType, forceType, label, rich).apply {
- init?.invoke(
- this
- )
- }
- this.add(spinner)
- return spinner
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt
deleted file mode 100644
index 7d3af684..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.spinner
-
-import com.github.snabbdom.VNode
-import pl.treksoft.jquery.JQuery
-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.FormInput
-import pl.treksoft.kvision.form.InputSize
-import pl.treksoft.kvision.utils.obj
-
-/**
- * Spinner buttons layout types.
- */
-enum class ButtonsType {
- NONE,
- HORIZONTAL,
- VERTICAL
-}
-
-/**
- * Spinner force rounding types.
- */
-enum class ForceType(internal val value: String) {
- NONE("none"),
- ROUND("round"),
- FLOOR("floor"),
- CEIL("cail")
-}
-
-internal const val DEFAULT_STEP = 1.0
-internal const val DEFAULT_MAX = 100
-
-/**
- * The basic component for spinner control.
- *
- * @constructor
- * @param value spinner value
- * @param min minimal value (default 0)
- * @param max maximal value (default 100)
- * @param step step value (default 1)
- * @param decimals number of decimal digits (default 0)
- * @param buttonsType spinner buttons type
- * @param forceType spinner force rounding type
- * @param classes a set of CSS class names
- */
-@Suppress("TooManyFunctions")
-open class SpinnerInput(
- value: Number? = null, min: Int = 0, max: Int = DEFAULT_MAX, step: Double = DEFAULT_STEP,
- decimals: Int = 0, buttonsType: ButtonsType = ButtonsType.VERTICAL,
- forceType: ForceType = ForceType.NONE,
- classes: Set<String> = setOf()
-) : Widget(classes + "form-control"), FormInput {
-
- init {
- this.addSurroundingCssClass("input-group")
- if (buttonsType == ButtonsType.NONE) {
- this.addSurroundingCssClass("kv-spinner-btn-none")
- } else {
- this.removeSurroundingCssClass("kv-spinner-btn-none")
- }
- if (buttonsType == ButtonsType.VERTICAL) {
- this.addSurroundingCssClass("kv-spinner-btn-vertical")
- } else {
- this.removeSurroundingCssClass("kv-spinner-btn-vertical")
- }
- this.surroundingSpan = true
- this.refreshSpinner()
- this.setInternalEventListener<SpinnerInput> {
- change = {
- self.changeValue()
- }
- }
- }
-
- /**
- * Spinner value.
- */
- var value by refreshOnUpdate(value, { refreshState() })
- /**
- * The value attribute of the generated HTML input element.
- *
- * This value is placed directly in generated HTML code, while the [value] property is dynamically
- * bound to the spinner input value.
- */
- var startValue by refreshOnUpdate(value, { this.value = it; refresh() })
- /**
- * Minimal value.
- */
- var min by refreshOnUpdate(min, { refreshSpinner() })
- /**
- * Maximal value.
- */
- var max by refreshOnUpdate(max, { refreshSpinner() })
- /**
- * Step value.
- */
- var step by refreshOnUpdate(step, { refreshSpinner() })
- /**
- * Number of decimal digits value.
- */
- var decimals by refreshOnUpdate(decimals, { refreshSpinner() })
- /**
- * Spinner buttons type.
- */
- var buttonsType by refreshOnUpdate(buttonsType, { refreshSpinner() })
- /**
- * Spinner force rounding type.
- */
- var forceType by refreshOnUpdate(forceType, { refreshSpinner() })
- /**
- * The placeholder for the spinner input.
- */
- var placeholder: String? by refreshOnUpdate()
- /**
- * The name attribute of the generated HTML input element.
- */
- override var name: String? by refreshOnUpdate()
- /**
- * Determines if the field is disabled.
- */
- override var disabled by refreshOnUpdate(false)
- /**
- * Determines if the spinner is automatically focused.
- */
- var autofocus: Boolean? by refreshOnUpdate()
- /**
- * Determines if the spinner is read-only.
- */
- var readonly: Boolean? by refreshOnUpdate()
- /**
- * The size of the input.
- */
- override var size: InputSize? by refreshOnUpdate()
-
- private var siblings: JQuery? = null
-
- override fun render(): VNode {
- return render("input")
- }
-
- override fun getSnClass(): List<StringBoolPair> {
- val cl = super.getSnClass().toMutableList()
- size?.let {
- cl.add(it.className to true)
- }
- return cl
- }
-
- @Suppress("ComplexMethod")
- override fun getSnAttrs(): List<StringPair> {
- val sn = super.getSnAttrs().toMutableList()
- sn.add("type" to "text")
- startValue?.let {
- sn.add("value" to it.toString())
- }
- placeholder?.let {
- sn.add("placeholder" to translate(it))
- }
- name?.let {
- sn.add("name" to it)
- }
- autofocus?.let {
- if (it) {
- sn.add("autofocus" to "autofocus")
- }
- }
- readonly?.let {
- if (it) {
- sn.add("readonly" to "readonly")
- }
- }
- if (disabled) {
- sn.add("disabled" to "disabled")
- value?.let {
- sn.add("value" to it.toString())
- }
- }
- return sn
- }
-
- protected open fun changeValue() {
- val v = getElementJQuery()?.`val`() as String?
- if (v != null && v.isNotEmpty()) {
- this.value = v.toDoubleOrNull()
- } else {
- this.value = null
- }
- }
-
- @Suppress("UnsafeCastFromDynamic")
- override fun afterInsert(node: VNode) {
- getElementJQueryD()?.TouchSpin(getSettingsObj())
- siblings = getElementJQuery()?.parent(".bootstrap-touchspin")?.children("span")
- size?.let {
- siblings?.find("button")?.addClass(it.className)
- }
- this.getElementJQuery()?.on("change", { e, _ ->
- if (e.asDynamic().isTrigger != null) {
- val event = org.w3c.dom.events.Event("change")
- this.getElement()?.dispatchEvent(event)
- }
- })
- this.getElementJQuery()?.on("touchspin.on.min", { e, _ ->
- this.dispatchEvent("onMinBsSpinner", obj { detail = e })
- })
- this.getElementJQuery()?.on("touchspin.on.max", { e, _ ->
- this.dispatchEvent("onMaxBsSpinner", obj { detail = e })
- })
- refreshState()
- }
-
- override fun afterDestroy() {
- siblings?.remove()
- siblings = null
- }
-
- /**
- * Returns the value of the spinner as a String.
- * @return value as a String
- */
- fun getValueAsString(): String? {
- return value?.toString()
- }
-
- /**
- * Change value in plus.
- */
- fun spinUp(): SpinnerInput {
- getElementJQueryD()?.trigger("touchspin.uponce")
- return this
- }
-
- /**
- * Change value in minus.
- */
- fun spinDown(): SpinnerInput {
- getElementJQueryD()?.trigger("touchspin.downonce")
- return this
- }
-
- private fun refreshState() {
- value?.let {
- getElementJQuery()?.`val`(it.toString())
- } ?: getElementJQueryD()?.`val`(null)
- }
-
- private fun refreshSpinner() {
- getElementJQueryD()?.trigger("touchspin.updatesettings", getSettingsObj())
- }
-
- private fun getSettingsObj(): dynamic {
- val verticalbuttons = buttonsType == ButtonsType.VERTICAL || buttonsType == ButtonsType.NONE
- return obj {
- this.min = min
- this.max = max
- this.step = step
- this.decimals = decimals
- this.verticalbuttons = verticalbuttons
- this.forcestepdivisibility = forceType.value
- }
- }
-
- /**
- * Makes the input element focused.
- */
- open fun focus() {
- getElementJQuery()?.focus()
- }
-
- /**
- * Makes the input element blur.
- */
- open fun blur() {
- getElementJQuery()?.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.spinnerInput(
- value: Number? = null, min: Int = 0, max: Int = DEFAULT_MAX, step: Double = DEFAULT_STEP,
- decimals: Int = 0, buttonsType: ButtonsType = ButtonsType.VERTICAL,
- forceType: ForceType = ForceType.NONE, classes: Set<String> = setOf(),
- init: (SpinnerInput.() -> Unit)? = null
- ): SpinnerInput {
- val spinnerInput = SpinnerInput(value, min, max, step, decimals, buttonsType, forceType, classes).apply {
- init?.invoke(
- this
- )
- }
- this.add(spinnerInput)
- return spinnerInput
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt
deleted file mode 100644
index 22126797..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.text
-
-import pl.treksoft.kvision.core.Container
-
-/**
- * Form field rich text component.
- *
- * @constructor
- * @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 RichText(
- value: String? = null, name: String? = null,
- label: String? = null, rich: Boolean = false
-) : AbstractText(label, rich) {
-
- /**
- * Rich input control height.
- */
- var inputHeight
- get() = input.height
- set(value) {
- input.height = value
- }
-
- final override val input: RichTextInput = RichTextInput(value).apply {
- this.id = idc
- this.name = name
- }
-
- init {
- @Suppress("LeakingThis")
- input.eventTarget = this
- this.addInternal(input)
- this.addInternal(validationInfo)
- }
-
- companion object {
- /**
- * DSL builder extension function.
- *
- * It takes the same parameters as the constructor of the built component.
- */
- fun Container.richText(
- value: String? = null,
- name: String? = null,
- label: String? = null,
- rich: Boolean = false,
- init: (RichText.() -> Unit)? = null
- ): RichText {
- val richText = RichText(value, name, label, rich).apply { init?.invoke(this) }
- this.add(richText)
- return richText
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt
deleted file mode 100644
index c5d9a556..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.text
-
-import com.github.snabbdom.VNode
-import pl.treksoft.jquery.jQuery
-import pl.treksoft.kvision.core.Container
-import pl.treksoft.kvision.core.StringPair
-import kotlin.browser.document
-
-/**
- * Basic rich text component.
- *
- * @constructor
- * @param value text input value
- * @param classes a set of CSS class names
- */
-open class RichTextInput(value: String? = null, classes: Set<String> = setOf()) :
- AbstractTextInput(value, classes + "form-control" + "trix-control") {
-
- private var trixId: String? = null
-
- override fun render(): VNode {
- return render("trix-editor")
- }
-
- override fun getSnAttrs(): List<StringPair> {
- val sn = super.getSnAttrs().toMutableList()
- placeholder?.let {
- sn.add("placeholder" to translate(it))
- }
- name?.let {
- sn.add("name" to it)
- }
- autofocus?.let {
- if (it) {
- sn.add("autofocus" to "autofocus")
- }
- }
- if (disabled) {
- sn.add("disabled" to "disabled")
- }
- return sn
- }
-
- @Suppress("UnsafeCastFromDynamic", "ComplexMethod")
- override fun afterInsert(node: VNode) {
- if (this.disabled || this.readonly == true) {
- this.getElementJQuery()?.removeAttr("contenteditable")
- } else {
- this.getElementJQuery()?.on("trix-change", { _, _ ->
- if (trixId != null) {
- val v = document.getElementById("trix-input-$trixId")?.let { jQuery(it).`val`() as String? }
- value = if (v != null && v.isNotEmpty()) {
- v
- } else {
- null
- }
- val event = org.w3c.dom.events.Event("change")
- this.getElement()?.dispatchEvent(event)
- }
- })
- }
- this.getElementJQuery()?.on("trix-initialize", { _, _ ->
- trixId = this.getElementJQuery()?.attr("trix-id")
- if (trixId != null) {
- value?.let {
- if (this.getElement().asDynamic().editor != undefined) {
- this.getElement().asDynamic().editor.loadHTML(it)
- }
- }
- }
- })
- this.getElementJQuery()?.on("trix-file-accept", { e, _ -> e.preventDefault() })
- }
-
- override fun afterDestroy() {
- document.getElementById("trix-input-$trixId")?.let { jQuery(it).remove() }
- document.getElementById("trix-toolbar-$trixId")?.let { jQuery(it).remove() }
- trixId = null
- }
-
- @Suppress("UnsafeCastFromDynamic")
- override fun refreshState() {
- val v = document.getElementById("trix-input-$trixId")?.let { jQuery(it).`val`() as String? }
- if (value != v) {
- val editor = this.getElement().asDynamic().editor
- if (editor != undefined) {
- value?.let {
- editor.loadHTML(it)
- } ?: editor.loadHTML("")
- }
- }
- }
-
- override fun changeValue() {
- // disabled parent class functionality
- }
-
- companion object {
- /**
- * DSL builder extension function.
- *
- * It takes the same parameters as the constructor of the built component.
- */
- fun Container.richTextInput(
- value: String? = null, classes: Set<String> = setOf(), init: (RichTextInput.() -> Unit)? = null
- ): RichTextInput {
- val richTextInput = RichTextInput(value, classes).apply { init?.invoke(this) }
- this.add(richTextInput)
- return richTextInput
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt
deleted file mode 100644
index 9cdd0369..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.time
-
-import pl.treksoft.kvision.core.Container
-import pl.treksoft.kvision.core.StringBoolPair
-import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.FieldLabel
-import pl.treksoft.kvision.form.HelpBlock
-import pl.treksoft.kvision.form.KDateFormControl
-import pl.treksoft.kvision.panel.SimplePanel
-import pl.treksoft.kvision.types.KDate
-import pl.treksoft.kvision.utils.SnOn
-
-/**
- * Form field date/time chooser component.
- *
- * @constructor
- * @param value date/time input value
- * @param name the name attribute of the generated HTML input element
- * @param format date/time format (default YYYY-MM-DD HH:mm)
- * @param label label text bound to the input element
- * @param rich determines if [label] can contain HTML code
- */
-open class DateTime(
- value: KDate? = null, name: String? = null, format: String = "YYYY-MM-DD HH:mm", label: String? = null,
- rich: Boolean = false
-) : SimplePanel(setOf("form-group")), KDateFormControl {
-
- /**
- * Date/time input value.
- */
- override var value
- get() = input.value
- set(value) {
- input.value = value
- }
- /**
- * Date/time format.
- */
- var format
- get() = input.format
- set(value) {
- input.format = value
- }
- /**
- * The placeholder for the date/time input.
- */
- var placeholder
- get() = input.placeholder
- set(value) {
- input.placeholder = value
- }
- /**
- * Determines if the date/time input is automatically focused.
- */
- var autofocus
- get() = input.autofocus
- set(value) {
- input.autofocus = value
- }
- /**
- * Determines if the date/time input is read-only.
- */
- var readonly
- get() = input.readonly
- set(value) {
- input.readonly = value
- }
- /**
- * Day of the week start. 0 (Sunday) to 6 (Saturday).
- */
- var weekStart
- get() = input.weekStart
- set(value) {
- input.weekStart = value
- }
- /**
- * Days of the week that should be disabled. Multiple values should be comma separated.
- */
- var daysOfWeekDisabled
- get() = input.daysOfWeekDisabled
- set(value) {
- input.daysOfWeekDisabled = value
- }
- /**
- * Determines if *Clear* button should be visible.
- */
- var clearBtn
- get() = input.clearBtn
- set(value) {
- input.clearBtn = value
- }
- /**
- * Determines if *Today* button should be visible.
- */
- var todayBtn
- get() = input.todayBtn
- set(value) {
- input.todayBtn = value
- }
- /**
- * Determines if the current day should be highlighted.
- */
- var todayHighlight
- get() = input.todayHighlight
- set(value) {
- input.todayHighlight = value
- }
- /**
- * The increment used to build the hour view.
- */
- var minuteStep
- get() = input.minuteStep
- set(value) {
- input.minuteStep = value
- }
- /**
- * Determines if meridian views are visible in day and hour views.
- */
- var showMeridian
- get() = input.showMeridian
- set(value) {
- input.showMeridian = value
- }
- /**
- * The label text bound to the input 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_time_$counter"
- final override val input: DateTimeInput = DateTimeInput(value, format).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
- }
-
- /**
- * Open date/time chooser popup.
- */
- open fun showPopup() {
- input.showPopup()
- }
-
- /**
- * Hides date/time chooser popup.
- */
- open fun hidePopup() {
- input.hidePopup()
- }
-
- override fun getValueAsString(): String? {
- return input.getValueAsString()
- }
-
- 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.dateTime(
- value: KDate? = null, name: String? = null, format: String = "YYYY-MM-DD HH:mm", label: String? = null,
- rich: Boolean = false, init: (DateTime.() -> Unit)? = null
- ): DateTime {
- val dateTime = DateTime(value, name, format, label, rich).apply { init?.invoke(this) }
- this.add(dateTime)
- return dateTime
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt
deleted file mode 100644
index 1df8a082..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.time
-
-import com.github.snabbdom.VNode
-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.FormInput
-import pl.treksoft.kvision.form.InputSize
-import pl.treksoft.kvision.i18n.I18n
-import pl.treksoft.kvision.types.KDate
-import pl.treksoft.kvision.types.toJS
-import pl.treksoft.kvision.types.toKDateF
-import pl.treksoft.kvision.types.toStringF
-import pl.treksoft.kvision.utils.obj
-
-internal const val DEFAULT_MINUTE_STEP = 5
-internal const val MAX_VIEW = 4
-
-/**
- * Basic date/time chooser component.
- *
- * @constructor
- * @param value date/time input value
- * @param format date/time format (default YYYY-MM-DD HH:mm)
- * @param classes a set of CSS class names
- */
-@Suppress("TooManyFunctions")
-open class DateTimeInput(
- value: KDate? = null, format: String = "YYYY-MM-DD HH:mm",
- classes: Set<String> = setOf()
-) : Widget(classes + "form-control"), FormInput {
-
- init {
- this.setInternalEventListener<DateTimeInput> {
- change = {
- self.changeValue()
- }
- }
- }
-
- /**
- * Date/time input value.
- */
- var value by refreshOnUpdate(value, { refreshState() })
- /**
- * Date/time format.
- */
- var format by refreshOnUpdate(format, { refreshDatePicker() })
- /**
- * The placeholder for the date/time input.
- */
- var placeholder: String? by refreshOnUpdate()
- /**
- * The name attribute of the generated HTML input element.
- */
- override var name: String? by refreshOnUpdate()
- /**
- * Determines if the field is disabled.
- */
- override var disabled by refreshOnUpdate(false)
- /**
- * Determines if the text input is automatically focused.
- */
- var autofocus: Boolean? by refreshOnUpdate()
- /**
- * Determines if the date/time input is read-only.
- */
- var readonly: Boolean? by refreshOnUpdate()
- /**
- * The size of the input.
- */
- override var size: InputSize? by refreshOnUpdate()
- /**
- * Day of the week start. 0 (Sunday) to 6 (Saturday).
- */
- var weekStart by refreshOnUpdate(0, { refreshDatePicker() })
- /**
- * Days of the week that should be disabled. Multiple values should be comma separated.
- */
- var daysOfWeekDisabled by refreshOnUpdate(arrayOf<Int>(), { refreshDatePicker() })
- /**
- * Determines if *Clear* button should be visible.
- */
- var clearBtn by refreshOnUpdate(true, { refreshDatePicker() })
- /**
- * Determines if *Today* button should be visible.
- */
- var todayBtn by refreshOnUpdate(false, { refreshDatePicker() })
- /**
- * Determines if the current day should be highlighted.
- */
- var todayHighlight by refreshOnUpdate(false, { refreshDatePicker() })
- /**
- * The increment used to build the hour view.
- */
- var minuteStep by refreshOnUpdate(DEFAULT_MINUTE_STEP, { refreshDatePicker() })
- /**
- * Determines if meridian views are visible in day and hour views.
- */
- var showMeridian by refreshOnUpdate(false, { refreshDatePicker() })
-
- override fun render(): VNode {
- return render("input")
- }
-
- override fun getSnClass(): List<StringBoolPair> {
- val cl = super.getSnClass().toMutableList()
- size?.let {
- cl.add(it.className to true)
- }
- return cl
- }
-
- override fun getSnAttrs(): List<StringPair> {
- val sn = super.getSnAttrs().toMutableList()
- sn.add("type" to "text")
- placeholder?.let {
- sn.add("placeholder" to translate(it))
- }
- name?.let {
- sn.add("name" to it)
- }
- autofocus?.let {
- if (it) {
- sn.add("autofocus" to "autofocus")
- }
- }
- readonly?.let {
- if (it) {
- sn.add("readonly" to "readonly")
- }
- }
- if (disabled) {
- sn.add("disabled" to "disabled")
- value?.let {
- sn.add("value" to it.toStringF(format))
- }
- }
- return sn
- }
-
- @Suppress("UnsafeCastFromDynamic")
- protected open fun refreshState() {
- value?.let {
- getElementJQueryD()?.datetimepicker("update", it.toJS())
- } ?: run {
- getElementJQueryD()?.`val`(null)
- getElementJQueryD()?.datetimepicker("update", null)
- }
- }
-
- protected open fun refreshDatePicker() {
- getElementJQueryD()?.`val`(null)
- getElementJQueryD()?.datetimepicker("remove")
- initDateTimePicker()
- refreshState()
- }
-
- protected open fun changeValue() {
- val v = getElementJQuery()?.`val`() as String?
- if (v != null && v.isNotEmpty()) {
- this.value = v.toKDateF(format)
- } else {
- this.value = null
- }
- }
-
- /**
- * Open date/time chooser popup.
- */
- open fun showPopup() {
- getElementJQueryD()?.datetimepicker("show")
- }
-
- /**
- * Hides date/time chooser popup.
- */
- open fun hidePopup() {
- getElementJQueryD()?.datetimepicker("hide")
- }
-
- @Suppress("UnsafeCastFromDynamic")
- override fun afterInsert(node: VNode) {
- if (!this.disabled) {
- this.initDateTimePicker()
- this.getElementJQuery()?.on("changeDate", { e, _ ->
- this.dispatchEvent("change", obj { detail = e })
- })
- this.getElementJQuery()?.on("show", { e, _ ->
- this.dispatchEvent("showBsDateTime", obj { detail = e })
- })
- this.getElementJQuery()?.on("hide", { e, _ ->
- this.dispatchEvent("hideBsDateTime", obj { detail = e })
- })
- refreshState()
- }
- }
-
- override fun afterDestroy() {
- getElementJQueryD()?.datetimepicker("remove")
- }
-
- private fun initDateTimePicker() {
- val datePickerFormat = format.toDatePickerFormat()
- val minView = if (format.contains("HH") || format.contains("mm")) 0 else 2
- val maxView = if (format.contains("YY") || format.contains("M") || format.contains("D")) MAX_VIEW else 1
- val startView = if (maxView < 2) maxView else 2
- val language = I18n.language
- getElementJQueryD()?.datetimepicker(obj {
- this.format = datePickerFormat
- this.startView = startView
- this.minView = minView
- this.maxView = maxView
- this.minuteStep = minuteStep
- this.todayHighlight = todayHighlight
- this.clearBtn = clearBtn
- this.todayBtn = todayBtn
- this.weekStart = weekStart
- this.showMeridian = showMeridian
- this.daysOfWeekDisabled = daysOfWeekDisabled
- this.autoclose = true
- this.language = language
- })
- }
-
- /**
- * Get value of date/time input control as String
- * @return value as a String
- */
- fun getValueAsString(): String? {
- return value?.toStringF(format)
- }
-
- /**
- * Makes the input element focused.
- */
- open fun focus() {
- getElementJQuery()?.focus()
- }
-
- /**
- * Makes the input element blur.
- */
- open fun blur() {
- getElementJQuery()?.blur()
- }
-
- companion object {
- private fun String.toDatePickerFormat(): String {
- return this.replace("YY", "yy").replace("m", "i").replace("MMMM", "{----}").replace("MMM", "{---}")
- .replace("M", "m").replace("{----}", "MM").replace("{---}", "M").replace("H", "{-}")
- .replace("h", "H").replace("{-}", "h").replace("D", "d").replace("a", "p").replace("A", "P")
- }
-
- /**
- * DSL builder extension function.
- *
- * It takes the same parameters as the constructor of the built component.
- */
- fun Container.dateTimeInput(
- value: KDate? = null, format: String = "YYYY-MM-DD HH:mm", classes: Set<String> = setOf(),
- init: (DateTimeInput.() -> Unit)? = null
- ): DateTimeInput {
- val dateTimeInput = DateTimeInput(value, format, classes).apply { init?.invoke(this) }
- this.add(dateTimeInput)
- return dateTimeInput
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt b/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt
deleted file mode 100644
index 314c9904..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.upload
-
-import org.w3c.files.File
-import pl.treksoft.kvision.core.Container
-import pl.treksoft.kvision.core.StringBoolPair
-import pl.treksoft.kvision.core.Widget
-import pl.treksoft.kvision.form.FieldLabel
-import pl.treksoft.kvision.form.HelpBlock
-import pl.treksoft.kvision.form.KFilesFormControl
-import pl.treksoft.kvision.panel.SimplePanel
-import pl.treksoft.kvision.types.KFile
-import pl.treksoft.kvision.utils.SnOn
-
-/**
- * The form field file upload component.
- *
- * @constructor
- * @param uploadUrl the optional URL for the upload processing action
- * @param multiple determines if multiple file upload is supported
- * @param label label text bound to the input element
- * @param rich determines if [label] can contain HTML code
- */
-@Suppress("TooManyFunctions")
-open class Upload(
- uploadUrl: String? = null, multiple: Boolean = false, label: String? = null,
- rich: Boolean = false
-) : SimplePanel(setOf("form-group")), KFilesFormControl {
-
- /**
- * File input value.
- */
- override var value
- get() = input.value
- set(value) {
- input.value = value
- }
- /**
- * The optional URL for the upload processing action.
- * If not set the upload button action will default to form submission.
- */
- var uploadUrl
- get() = input.uploadUrl
- set(value) {
- input.uploadUrl = value
- }
- /**
- * Determines if multiple file upload is supported.
- */
- var multiple
- get() = input.multiple
- set(value) {
- input.multiple = value
- }
- /**
- * The extra data that will be passed as data to the AJAX server call via POST.
- */
- var uploadExtraData
- get() = input.uploadExtraData
- set(value) {
- input.uploadExtraData = value
- }
- /**
- * Determines if the explorer theme is used.
- */
- var explorerTheme
- get() = input.explorerTheme
- set(value) {
- input.explorerTheme = value
- }
- /**
- * Determines if the input selection is required.
- */
- var required
- get() = input.required
- set(value) {
- input.required = value
- }
- /**
- * Determines if the caption is shown.
- */
- var showCaption
- get() = input.showCaption
- set(value) {
- input.showCaption = value
- }
- /**
- * Determines if the preview is shown.
- */
- var showPreview
- get() = input.showPreview
- set(value) {
- input.showPreview = value
- }
- /**
- * Determines if the remove button is shown.
- */
- var showRemove
- get() = input.showRemove
- set(value) {
- input.showRemove = value
- }
- /**
- * Determines if the upload button is shown.
- */
- var showUpload
- get() = input.showUpload
- set(value) {
- input.showUpload = value
- }
- /**
- * Determines if the cancel button is shown.
- */
- var showCancel
- get() = input.showCancel
- set(value) {
- input.showCancel = value
- }
- /**
- * Determines if the file browse button is shown.
- */
- var showBrowse
- get() = input.showBrowse
- set(value) {
- input.showBrowse = value
- }
- /**
- * Determines if the click on the preview zone opens file browse window.
- */
- var browseOnZoneClick
- get() = input.browseOnZoneClick
- set(value) {
- input.browseOnZoneClick = value
- }
- /**
- * Determines if the iconic preview is prefered.
- */
- var preferIconicPreview
- get() = input.preferIconicPreview
- set(value) {
- input.preferIconicPreview = value
- }
- /**
- * Allowed file types.
- */
- var allowedFileTypes
- get() = input.allowedFileTypes
- set(value) {
- input.allowedFileTypes = value
- }
- /**
- * Allowed file extensions.
- */
- var allowedFileExtensions
- get() = input.allowedFileExtensions
- set(value) {
- input.allowedFileExtensions = value
- }
- /**
- * Determines if Drag&Drop zone is enabled.
- */
- var dropZoneEnabled
- get() = input.dropZoneEnabled
- set(value) {
- input.dropZoneEnabled = value
- }
- /**
- * The label text bound to the spinner input 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
- }
-
- protected val idc = "kv_form_upload_$counter"
- final override val input: UploadInput = UploadInput(uploadUrl, multiple)
- .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 getValueAsString(): String? {
- return input.getValueAsString()
- }
-
- /**
- * Returns the native JavaScript File object.
- * @param kFile KFile object
- * @return File object
- */
- fun getNativeFile(kFile: KFile): File? {
- return input.getNativeFile(kFile)
- }
-
- /**
- * Resets the file input control.
- */
- open fun resetInput() {
- input.resetInput()
- }
-
- /**
- * Clears the file input control (including the native input).
- */
- open fun clearInput() {
- input.clearInput()
- }
-
- /**
- * Trigger ajax upload (only for ajax mode).
- */
- open fun upload() {
- input.upload()
- }
-
- /**
- * Cancel an ongoing ajax upload (only for ajax mode).
- */
- open fun cancel() {
- input.cancel()
- }
-
- /**
- * Locks the file input (disabling all buttons except a cancel button).
- */
- open fun lock() {
- input.lock()
- }
-
- /**
- * Unlocks the file input.
- */
- open fun unlock() {
- input.unlock()
- }
-
- 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.upload(
- uploadUrl: String? = null,
- multiple: Boolean = false,
- label: String? = null,
- rich: Boolean = false,
- init: (Upload.() -> Unit)? = null
- ): Upload {
- val upload = Upload(uploadUrl, multiple, label, rich).apply {
- init?.invoke(
- this
- )
- }
- this.add(upload)
- return upload
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt
deleted file mode 100644
index 0f8aaf4a..00000000
--- a/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (c) 2017-present Robert Jaros
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package pl.treksoft.kvision.form.upload
-
-import com.github.snabbdom.VNode
-import org.w3c.files.File
-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.FormInput
-import pl.treksoft.kvision.form.InputSize
-import pl.treksoft.kvision.i18n.I18n
-import pl.treksoft.kvision.types.KFile
-import pl.treksoft.kvision.utils.obj
-
-/**
- * The file upload component.
- *
- * @constructor
- * @param uploadUrl the optional URL for the upload processing action
- * @param multiple determines if multiple file upload is supported
- * @param classes a set of CSS class names
- */
-@Suppress("TooManyFunctions")
-open class UploadInput(uploadUrl: String? = null, multiple: Boolean = false, classes: Set<String> = setOf()) :
- Widget(classes + "form-control"), FormInput {
-
- /**
- * File input value.
- */
- var value: List<KFile>?
- get() = getValue()
- set(value) {
- if (value == null) resetInput()
- }
-
- /**
- * The optional URL for the upload processing action.
- * If not set the upload button action will default to form submission.
- */
- var uploadUrl: String? by refreshOnUpdate(uploadUrl, { refreshUploadInput() })
- /**
- * Determines if multiple file upload is supported.
- */
- var multiple: Boolean by refreshOnUpdate(multiple, { refresh(); refreshUploadInput() })
- /**
- * The extra data that will be passed as data to the AJAX server call via POST.
- */
- var uploadExtraData: ((String, Int) -> dynamic)? by refreshOnUpdate({ refreshUploadInput() })
- /**
- * Determines if the explorer theme is used.
- */
- var explorerTheme: Boolean by refreshOnUpdate(false, { refreshUploadInput() })
- /**
- * Determines if the input selection is required.
- */
- var required: Boolean by refreshOnUpdate(false, { refreshUploadInput() })
- /**
- * Determines if the caption is shown.
- */
- var showCaption: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * Determines if the preview is shown.
- */
- var showPreview: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * Determines if the remove button is shown.
- */
- var showRemove: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * Determines if the upload button is shown.
- */
- var showUpload: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * Determines if the cancel button is shown.
- */
- var showCancel: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * Determines if the file browse button is shown.
- */
- var showBrowse: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * Determines if the click on the preview zone opens file browse window.
- */
- var browseOnZoneClick: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * Determines if the iconic preview is prefered.
- */
- var preferIconicPreview: Boolean by refreshOnUpdate(false, { refreshUploadInput() })
- /**
- * Allowed file types.
- */
- var allowedFileTypes: Set<String>? by refreshOnUpdate({ refreshUploadInput() })
- /**
- * Allowed file extensions.
- */
- var allowedFileExtensions: Set<String>? by refreshOnUpdate({ refreshUploadInput() })
- /**
- * Determines if Drag&Drop zone is enabled.
- */
- var dropZoneEnabled: Boolean by refreshOnUpdate(true, { refreshUploadInput() })
- /**
- * The name attribute of the generated HTML input element.
- */
- override var name: String? by refreshOnUpdate()
- /**
- * Determines if the field is disabled.
- */
- override var disabled by refreshOnUpdate(false, { refresh(); refreshUploadInput() })
- /**
- * The size of the input (currently not working)
- */
- override var size: InputSize? by refreshOnUpdate()
-
- private val nativeFiles: MutableMap<KFile, File> = mutableMapOf()
-
- override fun render(): VNode {
- return render("input")
- }
-
- override fun getSnClass(): List<StringBoolPair> {
- val cl = super.getSnClass().toMutableList()
- size?.let {
- cl.add(it.className to true)
- }
- return cl
- }
-
- override fun getSnAttrs(): List<StringPair> {
- val sn = super.getSnAttrs().toMutableList()
- sn.add("type" to "file")
- name?.let {
- sn.add("name" to it)
- }
- if (multiple) {
- sn.add("multiple" to "true")
- }
- if (disabled) {
- sn.add("disabled" to "disabled")
- }
- return sn
- }
-
- private fun getValue(): List<KFile>? {
- val v = getFiles()
- return if (v.isNotEmpty()) v else null
- }
-
- @Suppress("UnsafeCastFromDynamic")
- override fun afterInsert(node: VNode) {
- getElementJQueryD()?.fileinput(getSettingsObj())
- this.getElementJQuery()?.on("fileselect", { e, _ ->
- this.dispatchEvent("fileSelectUpload", obj { detail = e })
- })
- this.getElementJQuery()?.on("fileclear", { e, _ ->
- this.dispatchEvent("fileClearUpload", obj { detail = e })
- })
- this.getElementJQuery()?.on("filereset", { e, _ ->
- this.dispatchEvent("fileResetUpload", obj { detail = e })
- })
- this.getElementJQuery()?.on("filebrowse", { e, _ ->
- this.dispatchEvent("fileBrowseUpload", obj { detail = e })
- })
- this.getElementJQueryD()?.on("filepreupload", lambda@{ _, data, previewId, index ->
- data["previewId"] = previewId
- data["index"] = index
- this.dispatchEvent("filePreUpload", obj { detail = data })
- return@lambda null
- })
- }
-
- override fun afterDestroy() {
- getElementJQueryD()?.fileinput("destroy")
- }
-
- private fun refreshUploadInput() {
- getElementJQueryD()?.fileinput("refresh", getSettingsObj())
- }
-
- /**
- * Resets the file input control.
- */
- open fun resetInput() {
- getElementJQueryD()?.fileinput("reset")
- }
-
- /**
- * Clears the file input control (including the native input).
- */
- open fun clearInput() {
- getElementJQueryD()?.fileinput("clear")
- }
-
- /**
- * Trigger ajax upload (only for ajax mode).
- */
- open fun upload() {
- getElementJQueryD()?.fileinput("upload")
- }
-
- /**
- * Cancel an ongoing ajax upload (only for ajax mode).
- */
- open fun cancel() {
- getElementJQueryD()?.fileinput("cancel")
- }
-
- /**
- * Locks the file input (disabling all buttons except a cancel button).
- */
- open fun lock() {
- getElementJQueryD()?.fileinput("lock")
- }
-
- /**
- * Unlocks the file input.
- */
- open fun unlock() {
- getElementJQueryD()?.fileinput("unlock")
- }
-
- /**
- * Returns the native JavaScript File object.
- * @param kFile KFile object
- * @return File object
- */
- fun getNativeFile(kFile: KFile): File? {
- return nativeFiles[kFile]
- }
-
- private fun getFiles(): List<KFile> {
- nativeFiles.clear()
- return (getElementJQueryD()?.fileinput("getFileStack") as Array<File>).toList().map {
- val kFile = KFile(it.name, it.size, null)
- nativeFiles[kFile] = it
- kFile
- }
- }
-
- /**
- * Returns the value of the file input control as a String.
- * @return value as a String
- */
- fun getValueAsString(): String? {
- return value?.joinToString { it.name }
- }
-
- /**
- * Makes the input element focused.
- */
- open fun focus() {
- getElementJQuery()?.focus()
- }
-
- /**
- * Makes the input element blur.
- */
- open fun blur() {
- getElementJQuery()?.blur()
- }
-
- private fun getSettingsObj(): dynamic {
- val language = I18n.language
- return obj {
- this.uploadUrl = uploadUrl
- this.uploadExtraData = uploadExtraData ?: undefined
- this.theme = if (explorerTheme) "explorer-fa" else null
- this.required = required
- this.showCaption = showCaption
- this.showPreview = showPreview
- this.showRemove = showRemove
- this.showUpload = showUpload
- this.showCancel = showCancel
- this.showBrowse = showBrowse
- this.browseOnZoneClick = browseOnZoneClick
- this.preferIconicPreview = preferIconicPreview
- this.allowedFileTypes = allowedFileTypes?.toTypedArray()
- this.allowedFileExtensions = allowedFileExtensions?.toTypedArray()
- this.dropZoneEnabled = dropZoneEnabled
- this.language = language
- }
- }
-
- companion object {
- internal var counter = 0
-
- /**
- * DSL builder extension function.
- *
- * It takes the same parameters as the constructor of the built component.
- */
- fun Container.uploadInput(
- uploadUrl: String? = null,
- multiple: Boolean = false,
- classes: Set<String> = setOf(),
- init: (UploadInput.() -> Unit)? = null
- ): UploadInput {
- val uploadInput = UploadInput(uploadUrl, multiple, classes).apply {
- init?.invoke(
- this
- )
- }
- this.add(uploadInput)
- return uploadInput
- }
- }
-}
diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt
index 99f4ca13..0b6b43e5 100644
--- a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt
@@ -32,7 +32,7 @@ import pl.treksoft.kvision.core.Widget
/**
* Button styles.
*/
-enum class ButtonStyle(internal val className: String) {
+enum class ButtonStyle(val className: String) {
DEFAULT("btn-default"),
PRIMARY("btn-primary"),
SUCCESS("btn-success"),
diff --git a/src/main/kotlin/pl/treksoft/kvision/i18n/I18n.kt b/src/main/kotlin/pl/treksoft/kvision/i18n/I18n.kt
index 343c18ef..b61d6e40 100644
--- a/src/main/kotlin/pl/treksoft/kvision/i18n/I18n.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/i18n/I18n.kt
@@ -21,24 +21,15 @@
*/
package pl.treksoft.kvision.i18n
-import org.w3c.xhr.XMLHttpRequest
import pl.treksoft.kvision.panel.Root
import kotlin.browser.window
-import kotlin.js.Promise
-
-external class Jed(json: dynamic) {
- fun gettext(key: String): String
- fun ngettext(singularKey: String, pluralKey: String, value: Int): String
- fun sprintf(format: String, value: Int): String
-}
-
-private const val I18N_SINGLE_DELIMITER = "###KvI18nS###"
-private const val I18N_PLURAL_DELIMITER = "###KvI18nP###"
/**
* A singleton object used for translations.
*/
-object I18n {
+object I18n : I18nManager {
+
+ var manager: I18nManager = SimpleI18nManager()
private val defaultLanguage = window.navigator.language.split("-")[0]
@@ -51,112 +42,12 @@ object I18n {
Root.roots.forEach { it.restart() }
}
- private val cache = mutableMapOf<String, Jed>()
-
- /**
- * I18n initialization function.
- * Should be called in the main function of the application.
- * @param languages a list of supported languages.
- * @param initCallback a code to run after the initialization process is complete.
- */
- fun init(vararg languages: String, initCallback: () -> Unit) {
- val promises = languages.map {
- I18n.readMessages(it)
- }.toTypedArray()
- Promise.all(promises).then { initCallback() }
+ override fun gettext(key: String): String {
+ return manager.gettext(key)
}
- @Suppress("MagicNumber")
- private fun readMessages(language: String): Promise<Jed> {
- return Promise { resolve, _ ->
- val xmlHttpRequest = XMLHttpRequest()
- xmlHttpRequest.overrideMimeType("application/json")
- xmlHttpRequest.open("GET", "js/messages-$language.json", true)
- xmlHttpRequest.onreadystatechange = {
- if (xmlHttpRequest.readyState.toInt() == 4 && (xmlHttpRequest.status.toInt() == 200 ||
- xmlHttpRequest.status.toInt() == 0)
- ) {
- val json = JSON.parse<dynamic>(xmlHttpRequest.responseText)
- val jed = Jed(json)
- cache[language] = jed
- resolve(jed)
- }
- }
- xmlHttpRequest.send()
- }
+ override fun ngettext(singularKey: String, pluralKey: String, value: Int): String {
+ return manager.ngettext(singularKey, pluralKey, value)
}
- /**
- * A static translation function for a singular form.
- * @param key a translation key.
- * @return translated text.
- */
- fun gettext(key: String): String {
- return cache[language]?.gettext(key) ?: key
- }
-
- /**
- * A static translation function for a plural form.
- * @param singularKey a translation key for a singular form.
- * @param pluralKey a translation key for a plural form.
- * @param value a count value.
- * @return translated text.
- */
- fun ngettext(singularKey: String, pluralKey: String, value: Int): String {
- return cache[language]?.run {
- sprintf(ngettext(singularKey, pluralKey, value), value)
- } ?: if (value == 1) singularKey else pluralKey
- }
-
- /**
- * A dynamic translation function for a singular form.
- * @param key a translation key.
- * @return text marked for a dynamic translation.
- */
- fun tr(key: String): String {
- return I18N_SINGLE_DELIMITER + key
- }
-
- /**
- * A dynamic translation function for a plural form.
- * @param singularKey a translation key for a singular form.
- * @param pluralKey a translation key for a plural form.
- * @param value a count value.
- * @return text marked for a dynamic translation.
- */
- fun ntr(singularKey: String, pluralKey: String, value: Int): String {
- return I18N_PLURAL_DELIMITER + singularKey + I18N_PLURAL_DELIMITER + pluralKey + I18N_PLURAL_DELIMITER + value
- }
-
- /**
- * A dynamic translation function.
- * @param text text marked for a dynamic translation.
- * @return translated text.
- */
- fun trans(text: String): String {
- return if (text.startsWith(I18N_SINGLE_DELIMITER)) {
- gettext(text.substring(I18N_SINGLE_DELIMITER.length))
- } else if (text.startsWith(I18N_PLURAL_DELIMITER)) {
- val tab = text.substring(I18N_PLURAL_DELIMITER.length).split(I18N_PLURAL_DELIMITER)
- @Suppress("MagicNumber")
- if (tab.size == 3) {
- ngettext(tab[0], tab[1], tab[2].toIntOrNull() ?: 1)
- } else {
- text
- }
- } else {
- text
- }
- }
-
- /**
- * A dynamic translation function.
- * @param text text marked for a dynamic translation.
- * @return translated text.
- */
- fun trans(text: String?): String? {
- return text?.let {
- trans(it)
- }
- }
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/i18n/I18nManager.kt b/src/main/kotlin/pl/treksoft/kvision/i18n/I18nManager.kt
new file mode 100644
index 00000000..09890e6f
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/i18n/I18nManager.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.i18n
+
+private const val I18N_SINGLE_DELIMITER = "###KvI18nS###"
+private const val I18N_PLURAL_DELIMITER = "###KvI18nP###"
+
+interface I18nManager {
+ /**
+ * A static translation function for a singular form.
+ * @param key a translation key.
+ * @return translated text.
+ */
+ fun gettext(key: String): String
+
+ /**
+ * A static translation function for a plural form.
+ * @param singularKey a translation key for a singular form.
+ * @param pluralKey a translation key for a plural form.
+ * @param value a count value.
+ * @return translated text.
+ */
+ fun ngettext(singularKey: String, pluralKey: String, value: Int): String
+
+ /**
+ * A dynamic translation function for a singular form.
+ * @param key a translation key.
+ * @return text marked for a dynamic translation.
+ */
+ fun tr(key: String): String {
+ return I18N_SINGLE_DELIMITER + key
+ }
+
+ /**
+ * A dynamic translation function for a plural form.
+ * @param singularKey a translation key for a singular form.
+ * @param pluralKey a translation key for a plural form.
+ * @param value a count value.
+ * @return text marked for a dynamic translation.
+ */
+ fun ntr(singularKey: String, pluralKey: String, value: Int): String {
+ return I18N_PLURAL_DELIMITER + singularKey + I18N_PLURAL_DELIMITER + pluralKey + I18N_PLURAL_DELIMITER + value
+ }
+
+ /**
+ * A dynamic translation function.
+ * @param text text marked for a dynamic translation.
+ * @return translated text.
+ */
+ fun trans(text: String): String {
+ return if (text.startsWith(I18N_SINGLE_DELIMITER)) {
+ gettext(text.substring(I18N_SINGLE_DELIMITER.length))
+ } else if (text.startsWith(I18N_PLURAL_DELIMITER)) {
+ val tab = text.substring(I18N_PLURAL_DELIMITER.length).split(I18N_PLURAL_DELIMITER)
+ @Suppress("MagicNumber")
+ if (tab.size == 3) {
+ ngettext(tab[0], tab[1], tab[2].toIntOrNull() ?: 1)
+ } else {
+ text
+ }
+ } else {
+ text
+ }
+ }
+
+ /**
+ * A dynamic translation function.
+ * @param text text marked for a dynamic translation.
+ * @return translated text.
+ */
+ fun trans(text: String?): String? {
+ return text?.let {
+ trans(it)
+ }
+ }
+
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/i18n/SimpleI18nManager.kt b/src/main/kotlin/pl/treksoft/kvision/i18n/SimpleI18nManager.kt
new file mode 100644
index 00000000..d8d5897c
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/i18n/SimpleI18nManager.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.i18n
+
+class SimpleI18nManager : I18nManager {
+
+ override fun gettext(key: String): String {
+ return key
+ }
+
+ override fun ngettext(singularKey: String, pluralKey: String, value: Int): String {
+ return singularKey
+ }
+
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt b/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt
index d4d73b29..c81ebde1 100644
--- a/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt
@@ -28,12 +28,12 @@ import kotlin.js.Date
@Suppress("MayBeConstant", "TopLevelPropertyNaming")
actual val KDATE_FORMAT = "YYYY-MM-DD HH:mm:ss"
-internal actual fun nowDate(): KDate =
+actual fun nowDate(): KDate =
KDate(Date().getTime().toLong())
-internal actual fun String.toKDateF(format: String): KDate =
+actual fun String.toKDateF(format: String): KDate =
this.toDateF(format)?.getTime()?.toLong()?.let { KDate(it) } ?: KDate()
-internal actual fun KDate.toStringF(format: String) = this.toJS().toStringF(format)
+actual fun KDate.toStringF(format: String) = this.toJS().toStringF(format)
fun KDate.toJS(): kotlin.js.Date = kotlin.js.Date(this.time)