diff options
author | Robert Jaros <rjaros@finn.pl> | 2018-10-08 13:40:04 +0200 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2018-10-08 13:40:04 +0200 |
commit | 0d3e7c87bf74948f83ce006a1d340b0f3f5e68b0 (patch) | |
tree | c86d5d0251da1fa3b208f53d1ca7d634a6cbcc8e /kvision-modules | |
parent | 91ae1d02de111f15608e84193c10ed17bea9fe41 (diff) | |
download | kvision-0d3e7c87bf74948f83ce006a1d340b0f3f5e68b0.tar.gz kvision-0d3e7c87bf74948f83ce006a1d340b0f3f5e68b0.tar.bz2 kvision-0d3e7c87bf74948f83ce006a1d340b0f3f5e68b0.zip |
Refactoring to modules
Diffstat (limited to 'kvision-modules')
169 files changed, 10792 insertions, 0 deletions
diff --git a/kvision-modules/kvision-base/build.gradle b/kvision-modules/kvision-base/build.gradle new file mode 100644 index 00000000..51970a40 --- /dev/null +++ b/kvision-modules/kvision-base/build.gradle @@ -0,0 +1,7 @@ +apply plugin: 'kotlin-platform-js' + +dependencies { + compile rootProject + compile project(path: ":", configuration: "tests") + testCompile rootProject +} diff --git a/kvision-modules/kvision-bootstrap/build.gradle b/kvision-modules/kvision-bootstrap/build.gradle new file mode 100644 index 00000000..9dc6953c --- /dev/null +++ b/kvision-modules/kvision-bootstrap/build.gradle @@ -0,0 +1,13 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("bootstrap", "3.3.7") + dependency("bootstrap-webpack", "0.0.6") + dependency("font-awesome", "4.7.0") + dependency("font-awesome-webpack", "github:jarecsni/font-awesome-webpack") + dependency("awesome-bootstrap-checkbox", "0.3.7") + } + +} diff --git a/kvision-modules/kvision-bootstrap/package.json.d/project.info b/kvision-modules/kvision-bootstrap/package.json.d/project.info new file mode 100644 index 00000000..e77a0f47 --- /dev/null +++ b/kvision-modules/kvision-bootstrap/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Bootstrap module" +} diff --git a/kvision-modules/kvision-bootstrap/src/main/kotlin/pl/treksoft/kvision/KVManagerBootstrap.kt b/kvision-modules/kvision-bootstrap/src/main/kotlin/pl/treksoft/kvision/KVManagerBootstrap.kt new file mode 100644 index 00000000..552f8d42 --- /dev/null +++ b/kvision-modules/kvision-bootstrap/src/main/kotlin/pl/treksoft/kvision/KVManagerBootstrap.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision + +import org.w3c.dom.asList +import kotlin.browser.document + +/** + * Internal singleton object which initializes and configures KVision Bootstrap module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerBootstrap { + 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) { + } +} diff --git a/kvision-modules/kvision-bootstrap/src/main/resources/css/paper.css b/kvision-modules/kvision-bootstrap/src/main/resources/css/paper.css new file mode 100644 index 00000000..6e923117 --- /dev/null +++ b/kvision-modules/kvision-bootstrap/src/main/resources/css/paper.css @@ -0,0 +1,12 @@ +body { + font-size: 14px; + line-height: 1.42857143; +} + +.kv-radio-checkbox { + padding-left: 20px !important; +} + +.radio label, .checkbox label { + white-space: nowrap; +} diff --git a/kvision-modules/kvision-bootstrap/src/main/resources/js/bootstrap.config.js b/kvision-modules/kvision-bootstrap/src/main/resources/js/bootstrap.config.js new file mode 100644 index 00000000..906942d1 --- /dev/null +++ b/kvision-modules/kvision-bootstrap/src/main/resources/js/bootstrap.config.js @@ -0,0 +1,64 @@ +module.exports = { + + // Default for the style loading + styleLoader: 'style-loader!css-loader!less-loader', + + scripts: { + 'transition': true, + 'alert': true, + 'button': true, + 'carousel': true, + 'collapse': true, + 'dropdown': true, + 'modal': true, + 'tooltip': true, + 'popover': true, + 'scrollspy': true, + 'tab': true, + 'affix': true + }, + styles: { + "mixins": false, + + "normalize": false, + "print": false, + + "scaffolding": false, + "type": false, + "code": false, + "grid": false, + "tables": false, + "forms": false, + "buttons": false, + + "component-animations": false, + "glyphicons": false, + "dropdowns": false, + "button-groups": false, + "input-groups": false, + "navs": false, + "navbar": false, + "breadcrumbs": false, + "pagination": false, + "pager": false, + "labels": false, + "badges": false, + "jumbotron": false, + "thumbnails": false, + "alerts": false, + "progress-bars": false, + "media": false, + "list-group": false, + "panels": false, + "wells": false, + "close": false, + + "modals": false, + "tooltip": false, + "popovers": false, + "carousel": false, + + "utilities": false, + "responsive-utilities": false + } +}; diff --git a/kvision-modules/kvision-bootstrap/src/main/resources/js/bootstrap.config.less b/kvision-modules/kvision-bootstrap/src/main/resources/js/bootstrap.config.less new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/kvision-modules/kvision-bootstrap/src/main/resources/js/bootstrap.config.less diff --git a/kvision-modules/kvision-common/build.gradle b/kvision-modules/kvision-common/build.gradle new file mode 100644 index 00000000..af3703e6 --- /dev/null +++ b/kvision-modules/kvision-common/build.gradle @@ -0,0 +1,10 @@ +apply plugin: 'kotlin-platform-common' +apply plugin: 'kotlinx-serialization' + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion" + compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion" + compile "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutinesVersion" + testCompile "org.jetbrains.kotlin:kotlin-test-common:$kotlinVersion" + testCompile "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlinVersion" +} diff --git a/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/Jooby.kt b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/Jooby.kt new file mode 100644 index 00000000..ec348a25 --- /dev/null +++ b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/Jooby.kt @@ -0,0 +1,37 @@ +/* + * 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.remote + +/** + * A Jooby based server. + */ +expect open class JoobyServer + +/** + * A server request. + */ +expect interface Request + +/** + * A user profile. + */ +expect class Profile diff --git a/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/JsonRpc.kt b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/JsonRpc.kt new file mode 100644 index 00000000..7953ea01 --- /dev/null +++ b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/JsonRpc.kt @@ -0,0 +1,37 @@ +/* + * 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.remote + +import kotlinx.serialization.Serializable + +@Serializable +data class JsonRpcRequest(val id: Int, val method: String, val params: List<String?>, val jsonrpc: String = "2.0") { + constructor() : this(0, "", listOf()) +} + +@Serializable +data class JsonRpcResponse( + val id: Int? = null, + val result: String? = null, + val error: String? = null, + val jsonrpc: String = "2.0" +) diff --git a/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/ServiceManager.kt b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/ServiceManager.kt new file mode 100644 index 00000000..8225a785 --- /dev/null +++ b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/remote/ServiceManager.kt @@ -0,0 +1,139 @@ +/* + * 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.remote + +import kotlinx.coroutines.Deferred + +enum class RpcHttpMethod { + POST, + PUT, + DELETE, + OPTIONS +} + +enum class HttpMethod { + GET, + POST, + PUT, + DELETE, + OPTIONS +} + +/** + * Multiplatform service manager. + */ +expect open class ServiceManager<out T>(service: T) { + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected inline fun <reified RET> bind( + noinline function: T.(Request?) -> Deferred<RET>, + route: String? = null, + method: RpcHttpMethod = RpcHttpMethod.POST, + prefix: String = "/" + ) + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected inline fun <reified PAR, reified RET> bind( + noinline function: T.(PAR, Request?) -> Deferred<RET>, + route: String? = null, + method: RpcHttpMethod = RpcHttpMethod.POST, + prefix: String = "/" + ) + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected inline fun <reified PAR1, reified PAR2, reified RET> bind( + noinline function: T.(PAR1, PAR2, Request?) -> Deferred<RET>, + route: String? = null, + method: RpcHttpMethod = RpcHttpMethod.POST, + prefix: String = "/" + ) + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected inline fun <reified PAR1, reified PAR2, reified PAR3, reified RET> bind( + noinline function: T.(PAR1, PAR2, PAR3, Request?) -> Deferred<RET>, + route: String? = null, + method: RpcHttpMethod = RpcHttpMethod.POST, + prefix: String = "/" + ) + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified RET> bind( + noinline function: T.(PAR1, PAR2, PAR3, PAR4, Request?) -> Deferred<RET>, + route: String? = null, + method: RpcHttpMethod = RpcHttpMethod.POST, + prefix: String = "/" + ) + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified PAR5, reified RET> bind( + noinline function: T.(PAR1, PAR2, PAR3, PAR4, PAR5, Request?) -> Deferred<RET>, + route: String? = null, + method: RpcHttpMethod = RpcHttpMethod.POST, + prefix: String = "/" + ) + + /** + * Applies all defined routes to the given server. + * @param k a Jooby server + */ + fun applyRoutes(k: JoobyServer) + + /** + * Returns the map of defined paths. + */ + fun getCalls(): Map<String, Pair<String, RpcHttpMethod>> +} diff --git a/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt new file mode 100644 index 00000000..0cb1a1f1 --- /dev/null +++ b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt @@ -0,0 +1,49 @@ +/* + * 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.types + +import kotlinx.serialization.Serializable + +expect val KDATE_FORMAT: String + +/** + * A serializable wrapper for a multiplatform Date type. + */ +@Serializable +data class KDate(val time: Long) { + constructor() : this(now().time) + constructor(str: String) : this(str.toKDateF(KDATE_FORMAT).time) + + override fun toString(): String { + return this.toStringF(KDATE_FORMAT) + } + + companion object { + fun now() = nowDate() + } +} + +expect fun nowDate(): KDate + +expect fun String.toKDateF(format: String): KDate + +expect fun KDate.toStringF(format: String): String diff --git a/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/types/KFile.kt b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/types/KFile.kt new file mode 100644 index 00000000..ce4adca4 --- /dev/null +++ b/kvision-modules/kvision-common/src/main/kotlin/pl/treksoft/kvision/types/KFile.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.types + +import kotlinx.serialization.Serializable + +/** + * A serializable class for a multiplatform File type. + */ +@Serializable +data class KFile( + val name: String, + val size: Int, + val content: String? = null +) diff --git a/kvision-modules/kvision-datetime/build.gradle b/kvision-modules/kvision-datetime/build.gradle new file mode 100644 index 00000000..b853d2f4 --- /dev/null +++ b/kvision-modules/kvision-datetime/build.gradle @@ -0,0 +1,9 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("bootstrap-datetime-picker", "2.4.4") + } + +} diff --git a/kvision-modules/kvision-datetime/package.json.d/project.info b/kvision-modules/kvision-datetime/package.json.d/project.info new file mode 100644 index 00000000..3d332806 --- /dev/null +++ b/kvision-modules/kvision-datetime/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Datetime module" +} diff --git a/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/KVManagerDatetime.kt b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/KVManagerDatetime.kt new file mode 100644 index 00000000..cde55b1e --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/KVManagerDatetime.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision + +internal val KVManagerDatetimeInit = KVManagerDatetime.init() + +/** + * Internal singleton object which initializes and configures KVision datetime module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerDatetime { + fun init() {} + + 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/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ar.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.az.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bg.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bn.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ca.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.cs.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.da.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.de.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ee.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.el.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.es.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fi.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fr.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.he.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hr.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hu.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hy.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.id.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.is.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.it.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ja.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ko.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lt.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lv.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nl.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.no.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pl.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ro.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ru.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sk.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sl.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sv.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.th.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.tr.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ua.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.uk.js") + require("./js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh.js") + } catch (e: Throwable) { + } + +} diff --git a/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt new file mode 100644 index 00000000..9cdd0369 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt @@ -0,0 +1,246 @@ +/* + * 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/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt new file mode 100644 index 00000000..1df8a082 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt @@ -0,0 +1,291 @@ +/* + * 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/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ar.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ar.js new file mode 100644 index 00000000..a43b4739 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ar.js @@ -0,0 +1,18 @@ +/** +* Arabic translation for bootstrap-datetimepicker +* Ala' Mohammad <amohammad@birzeit.ecu> +*/ +;(function($){ + $.fn.datetimepicker.dates['ar'] = { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["أح", "إث", "ث", "أر", "خ", "ج", "س", "أح"], + months: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + monthsShort: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + today: "هذا اليوم", + clear: "x", + suffix: [], + meridiem: [], + rtl: true + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.az.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.az.js new file mode 100644 index 00000000..c840d6f0 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.az.js @@ -0,0 +1,17 @@ +/** + * Azerbaijani translation for bootstrap-datetimepicker + * Konstantin Kaluzhnikov <k.kaluzhnikov@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['az'] = { + days: ["Bazar", "Bazar ertəsi", "Çərşənbə axşamı", "Çərşənbə", "Cümə axşamı", "Cümə", "Şənbə", "Bazar"], + daysShort: ["B", "Be", "Ça", "Ç", "Ca", "C", "Ş", "B"], + daysMin: ["B", "Be", "Ça", "Ç", "Ca", "C", "Ş", "B"], + months: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr"], + monthsShort: ["Yan", "Fev", "Mar", "Apr", "May", "İyun", "İyul", "Avq", "Sen", "Okt", "Noy", "Dek"], + today: "Bugün", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bg.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bg.js new file mode 100644 index 00000000..3bc7e273 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bg.js @@ -0,0 +1,17 @@ +/** + * Bulgarian translation for bootstrap-datetimepicker + * Apostol Apostolov <apostol.s.apostolov@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['bg'] = { + days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"], + daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"], + daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"], + months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "днес", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bn.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bn.js new file mode 100644 index 00000000..b46bd54f --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.bn.js @@ -0,0 +1,17 @@ +/** + * Bangla(Bangladesh) translation for bootstrap-datetimepicker + * Mahbub Rabbani <mahbub [dot] rucse [at] gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['bn'] = { + days: ["রবিবার", "সোমবার", "মঙ্গলবার", "বুধবার", "বৃহষ্পতিবার", "শুক্রবার", "শনিবার", "রবিবার"], + daysShort: ["রবি", "সোম", "মঙ্গল", "বুধ", " বৃহঃ", "শুক্র", "শনি", "রবি"], + daysMin: ["রবি", "সোম", "মঙ্গ", "বুধ", "বৃহ", "শুক্র", "শনি", "রবি"], + months: ['জানুয়ারী', 'ফেব্রুয়ারী', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'অগাস্ট', 'সেপ্টেম্বর', 'অক্টোবর', 'নভেম্বর', 'ডিসেম্বর' ], + monthsShort: ['জানু', 'ফেব্রু', 'মার্চ', 'এপ্রি', 'মে', 'জুন', 'জুলা', 'অগা', 'সেপ্টে', 'অক্টো', 'নভে', 'ডিসে' ], + today: "আজ", + clear: "x", + suffix: [], + meridiem: ['পূর্বাহ্ণ', 'অপরাহ্ন'] + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ca.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ca.js new file mode 100644 index 00000000..d3137a2d --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ca.js @@ -0,0 +1,17 @@ +/** + * Catalan translation for bootstrap-datetimepicker + * J. Garcia <jogaco.en@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['ca'] = { + days: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"], + daysShort: ["Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"], + daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds", "dg"], + months: ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"], + monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"], + today: "Avui", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.cs.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.cs.js new file mode 100644 index 00000000..318cd5cf --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.cs.js @@ -0,0 +1,20 @@ +/** + * Czech translation for bootstrap-datetimepicker + * Matěj Koubík <matej@koubik.name> + * Fixes by Michal Remiš <michal.remis@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['cs'] = { + days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"], + daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob", "Ned"], + daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"], + months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], + monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], + today: "Dnes", + suffix: [], + clear: "x", + meridiem: [], + weekStart: 1, + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.da.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.da.js new file mode 100644 index 00000000..30d9a34a --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.da.js @@ -0,0 +1,17 @@ +/** + * Danish translation for bootstrap-datetimepicker + * Christian Pedersen <http://github.com/chripede> + */ +;(function($){ + $.fn.datetimepicker.dates['da'] = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], + months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "I Dag", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.de.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.de.js new file mode 100644 index 00000000..52a19060 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.de.js @@ -0,0 +1,19 @@ +/** + * German translation for bootstrap-datetimepicker + * Sam Zurcher <sam@orelias.ch> + */ +;(function($){ + $.fn.datetimepicker.dates['de'] = { + days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], + daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"], + daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], + months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], + monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], + today: "Heute", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1, + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ee.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ee.js new file mode 100644 index 00000000..882378f3 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ee.js @@ -0,0 +1,19 @@ +/** + * Estonian translation for bootstrap-datetimepicker + * Rene Korss <http://rene.korss.ee> + */ +;(function($){ + $.fn.datetimepicker.dates['ee'] = { + days: ["Pühapäev", "Esmaspäev", "Teisipäev", "Kolmapäev", "Neljapäev", "Reede", "Laupäev", "Pühapäev"], + daysShort: ["P", "E", "T", "K", "N", "R", "L", "P"], + daysMin: ["P", "E", "T", "K", "N", "R", "L", "P"], + months: ["Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember"], + monthsShort: ["Jaan", "Veebr", "Märts", "Apr", "Mai", "Juuni", "Juuli", "Aug", "Sept", "Okt", "Nov", "Dets"], + today: "Täna", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1, + format: "dd.mm.yyyy hh:ii" + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.el.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.el.js new file mode 100644 index 00000000..cbbdc9a7 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.el.js @@ -0,0 +1,16 @@ +/** +* Greek translation for bootstrap-datetimepicker +*/ +;(function($){ + $.fn.datetimepicker.dates['el'] = { + days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"], + daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ"], + daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα", "Κυ"], + months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], + monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], + today: "Σήμερα", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.es.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.es.js new file mode 100644 index 00000000..bbf3c207 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.es.js @@ -0,0 +1,17 @@ +/** + * Spanish translation for bootstrap-datetimepicker + * Bruno Bonamin <bruno.bonamin@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['es'] = { + days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"], + daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"], + daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"], + months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], + monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], + today: "Hoy", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fi.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fi.js new file mode 100644 index 00000000..95eb4a8d --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fi.js @@ -0,0 +1,17 @@ +/** + * Finnish translation for bootstrap-datetimepicker + * Jaakko Salonen <https://github.com/jsalonen> + */ +;(function($){ + $.fn.datetimepicker.dates['fi'] = { + days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"], + daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"], + daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"], + months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], + monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"], + today: "tänään", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fr.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fr.js new file mode 100644 index 00000000..f9194cbd --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.fr.js @@ -0,0 +1,19 @@ +/** + * French translation for bootstrap-datetimepicker + * Nico Mollet <nico.mollet@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['fr'] = { + days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"], + daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"], + daysMin: ["D", "L", "Ma", "Me", "J", "V", "S", "D"], + months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], + monthsShort: ["Jan", "Fev", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Dec"], + today: "Aujourd'hui", + suffix: [], + clear: "x", + meridiem: ["am", "pm"], + weekStart: 1, + format: "dd/mm/yyyy hh:ii" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.he.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.he.js new file mode 100644 index 00000000..1060a4a7 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.he.js @@ -0,0 +1,18 @@ +/** + * Hebrew translation for bootstrap-datetimepicker + * Sagie Maoz <sagie@maoz.info> + */ +;(function($){ + $.fn.datetimepicker.dates['he'] = { + days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], + daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], + monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], + today: "היום", + clear: "x", + suffix: [], + meridiem: [], + rtl: true + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hr.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hr.js new file mode 100644 index 00000000..f85540fa --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hr.js @@ -0,0 +1,16 @@ +/** + * Croatian localisation + */ +;(function($){ + $.fn.datetimepicker.dates['hr'] = { + days: ["Nedjelja", "Ponedjelja", "Utorak", "Srijeda", "Četrtak", "Petak", "Subota", "Nedjelja"], + daysShort: ["Ned", "Pon", "Uto", "Srr", "Čet", "Pet", "Sub", "Ned"], + daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su", "Ne"], + months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], + monthsShort: ["Sije", "Velj", "Ožu", "Tra", "Svi", "Lip", "Jul", "Kol", "Ruj", "Lis", "Stu", "Pro"], + today: "Danas", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hu.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hu.js new file mode 100644 index 00000000..5de9fe9e --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hu.js @@ -0,0 +1,18 @@ +/** + * Hungarian translation for bootstrap-datetimepicker + * darevish <http://github.com/darevish> + */ +;(function($){ + $.fn.datetimepicker.dates['hu'] = { + days: ["Vasárnap", "Hétfő", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat", "Vasárnap"], + daysShort: ["Vas", "Hét", "Ked", "Sze", "Csü", "Pén", "Szo", "Vas"], + daysMin: ["V", "H", "K", "Sze", "Cs", "P", "Szo", "V"], + months: ["Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Már", "Ápr", "Máj", "Jún", "Júl", "Aug", "Sze", "Okt", "Nov", "Dec"], + today: "Ma", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1 + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hy.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hy.js new file mode 100644 index 00000000..cedee4db --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.hy.js @@ -0,0 +1,17 @@ +/** + * Armenian translation for bootstrap-datepicker + * Hayk Chamyan <hamshen@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['hy'] = { + days: ["Կիրակի", "Երկուշաբթի", "Երեքշաբթի", "Չորեքշաբթի", "Հինգշաբթի", "Ուրբաթ", "Շաբաթ", "Կիրակի"], + daysShort: ["Կիր", "Երկ", "Երք", "Չոր", "Հնգ", "Ուր", "Շաբ", "Կիր"], + daysMin: ["Կի", "Եկ", "Եք", "Չո", "Հի", "Ու", "Շա", "Կի"], + months: ["Հունվար", "Փետրվար", "Մարտ", "Ապրիլ", "Մայիս", "Հունիս", "Հուլիս", "Օգոստոս", "Սեպտեմբեր", "Հոկտեմբեր", "Նոյեմբեր", "Դեկտեմբեր"], + monthsShort: ["Հնվ", "Փետ", "Մար", "Ապր", "Մայ", "Հուն", "Հուլ", "Օգս", "Սեպ", "Հոկ", "Նոյ", "Դեկ"], + today: "Այսօր", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.id.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.id.js new file mode 100644 index 00000000..feef4a3b --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.id.js @@ -0,0 +1,20 @@ +/** + * Bahasa translation for bootstrap-datetimepicker + * Azwar Akbar <azwar.akbar@gmail.com> + * Addtional by Yulian Sutopo <yuliansutopo@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['id'] = { + days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"], + daysShort: ["Mng", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Mng"], + daysMin: ["Mg", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa", "Mg"], + months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ags", "Sep", "Okt", "Nov", "Des"], + today: "Hari Ini", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1, + format: "dd/mm/yyyy hh:ii:ss" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.is.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.is.js new file mode 100644 index 00000000..9944c6d7 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.is.js @@ -0,0 +1,17 @@ +/** + * Icelandic translation for bootstrap-datetimepicker + * Hinrik Örn Sigurðsson <hinrik.sig@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['is'] = { + days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur", "Sunnudagur"], + daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau", "Sun"], + daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La", "Su"], + months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], + today: "Í Dag", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.it.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.it.js new file mode 100644 index 00000000..c00a0499 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.it.js @@ -0,0 +1,19 @@ +/** + * Italian translation for bootstrap-datetimepicker + * Enrico Rubboli <rubboli@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['it'] = { + days: ["Domenica", "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"], + daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"], + daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"], + months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], + today: "Oggi", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1, + format: "dd/mm/yyyy hh:ii:ss" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ja.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ja.js new file mode 100644 index 00000000..3a2d3b9b --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ja.js @@ -0,0 +1,17 @@ +/** + * Japanese translation for bootstrap-datetimepicker + * Norio Suzuki <https://github.com/suzuki/> + */ +;(function($){ + $.fn.datetimepicker.dates['ja'] = { + days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜", "日曜"], + daysShort: ["日", "月", "火", "水", "木", "金", "土", "日"], + daysMin: ["日", "月", "火", "水", "木", "金", "土", "日"], + months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今日", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ka.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ka.js new file mode 100644 index 00000000..d4595eff --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ka.js @@ -0,0 +1,17 @@ +/** + * Georgian translation for bootstrap-datetimepicker + * Zura Jijavadze <mailzura@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['ka'] = { + days: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი", "კვირა"], + daysShort: ["კვი", "ორშ", "სამ", "ოთხ", "ხუთ", "პარ", "შაბ", "კვი"], + daysMin: ["კვ", "ორ", "სა", "ოთ", "ხუ", "პა", "შა", "კვ"], + months: ["იანვარი", "თებერვალი", "მარტი", "აპრილი", "მაისი", "ივნისი", "ივლისი", "აგვისტო", "სექტემბერი", "ოქტომბერი", "ნოემბერი", "დეკემბერი"], + monthsShort: ["იან", "თებ", "მარ", "აპრ", "მაი", "ივნ", "ივლ", "აგვ", "სექ", "ოქტ", "ნოე", "დეკ"], + today: "დღეს", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ko.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ko.js new file mode 100644 index 00000000..adeb6cb6 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ko.js @@ -0,0 +1,18 @@ +/** + * Korean translation for bootstrap-datetimepicker + * Gu Youn <http://github.com/guyoun> + * Baekjoon Choi <http://github.com/Baekjoon> + */ +;(function($){ + $.fn.datetimepicker.dates['ko'] = { + days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"], + daysShort: ["일", "월", "화", "수", "목", "금", "토", "일"], + daysMin: ["일", "월", "화", "수", "목", "금", "토", "일"], + months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + suffix: [], + meridiem: ["오전", "오후"], + today: "오늘", + clear: "x" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lt.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lt.js new file mode 100644 index 00000000..917243c4 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lt.js @@ -0,0 +1,19 @@ +/** + * Lithuanian translation for bootstrap-datetimepicker + * Šarūnas Gliebus <ssharunas@yahoo.co.uk> + */ + +;(function($){ + $.fn.datetimepicker.dates['lt'] = { + days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis", "Sekmadienis"], + daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š", "S"], + daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št", "Sk"], + months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], + monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], + today: "Šiandien", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1 + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lv.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lv.js new file mode 100644 index 00000000..f9b3c774 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.lv.js @@ -0,0 +1,19 @@ +/** + * Latvian translation for bootstrap-datetimepicker + * Artis Avotins <artis@apit.lv> + */ + +;(function($){ + $.fn.datetimepicker.dates['lv'] = { + days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena", "Svētdiena"], + daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S", "Sv"], + daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "St", "Sv"], + months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec."], + today: "Šodien", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1 + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ms.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ms.js new file mode 100644 index 00000000..26a2cc0e --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ms.js @@ -0,0 +1,17 @@ +/** + * Malay translation for bootstrap-datetimepicker + * Ateman Faiz <noorulfaiz@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['ms'] = { + days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu", "Ahad"], + daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab", "Aha"], + daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa", "Ah"], + months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], + today: "Hari Ini", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nb.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nb.js new file mode 100644 index 00000000..a2fd01a6 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nb.js @@ -0,0 +1,17 @@ +/** + * Norwegian (bokmål) translation for bootstrap-datetimepicker + * Fredrik Sundmyhr <http://github.com/fsundmyhr> + */ +;(function($){ + $.fn.datetimepicker.dates['nb'] = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], + months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], + today: "I Dag", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nl.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nl.js new file mode 100644 index 00000000..a28fa031 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.nl.js @@ -0,0 +1,17 @@ +/** + * Dutch translation for bootstrap-datetimepicker + * Reinier Goltstein <mrgoltstein@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['nl'] = { + days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], + daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Vandaag", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.no.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.no.js new file mode 100644 index 00000000..36e33a0b --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.no.js @@ -0,0 +1,17 @@ +/** + * Norwegian translation for bootstrap-datetimepicker + * Rune Warhuus <rune@dinkdonkd.no> + */ +;(function($){ + $.fn.datetimepicker.dates['no'] = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], + months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], + today: "I Dag", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pl.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pl.js new file mode 100644 index 00000000..12fc7422 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pl.js @@ -0,0 +1,18 @@ +/** + * Polish translation for bootstrap-datetimepicker + * Robert <rtpm@gazeta.pl> + */ +;(function($){ +$.fn.datetimepicker.dates['pl'] = { + days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"], + daysShort: ["Nie", "Pn", "Wt", "Śr", "Czw", "Pt", "So", "Nie"], + daysMin: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "N"], + months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], + monthsShort: ["Sty", "Lu", "Mar", "Kw", "Maj", "Cze", "Lip", "Sie", "Wrz", "Pa", "Lis", "Gru"], + today: "Dzisiaj", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1 +}; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt-BR.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt-BR.js new file mode 100644 index 00000000..1d307416 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt-BR.js @@ -0,0 +1,18 @@ +/** + * Brazilian translation for bootstrap-datetimepicker + * Cauan Cabral <cauan@radig.com.br> + */ +;(function($){ + $.fn.datetimepicker.dates['pt-BR'] = { + format: 'dd/mm/yyyy', + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt.js new file mode 100644 index 00000000..166034ef --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.pt.js @@ -0,0 +1,18 @@ +/** + * Portuguese translation for bootstrap-datetimepicker + * Original code: Cauan Cabral <cauan@radig.com.br> + * Tiago Melo <tiago.blackcode@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['pt'] = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + suffix: [], + meridiem: [], + today: "Hoje", + clear: "x" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ro.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ro.js new file mode 100644 index 00000000..a7569c6f --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ro.js @@ -0,0 +1,18 @@ +/** + * Romanian translation for bootstrap-datetimepicker + * Cristian Vasile <cristi.mie@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['ro'] = { + days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"], + daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm", "Dum"], + daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ", "Du"], + months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], + monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Astăzi", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1 + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs-latin.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs-latin.js new file mode 100644 index 00000000..57c819f9 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs-latin.js @@ -0,0 +1,17 @@ +/** + * Serbian latin translation for bootstrap-datetimepicker + * Bojan Milosavlević <milboj@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['rs'] = { + days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota", "Nedelja"], + daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub", "Ned"], + daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su", "N"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danas", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs.js new file mode 100644 index 00000000..3e9db3e6 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.rs.js @@ -0,0 +1,17 @@ +/** + * Serbian cyrillic translation for bootstrap-datetimepicker + * Bojan Milosavlević <milboj@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['rs'] = { + days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота", "Недеља"], + daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб", "Нед"], + daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су", "Н"], + months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], + monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], + today: "Данас", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ru.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ru.js new file mode 100644 index 00000000..20caf251 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ru.js @@ -0,0 +1,17 @@ +/** + * Russian translation for bootstrap-datetimepicker + * Victor Taranenko <darwin@snowdale.com> + */ +;(function($){ + $.fn.datetimepicker.dates['ru'] = { + days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], + daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Вск"], + daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"], + months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], + monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], + today: "Сегодня", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sk.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sk.js new file mode 100644 index 00000000..acf1495a --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sk.js @@ -0,0 +1,20 @@ +/** + * Slovak translation for bootstrap-datetimepicker + * Marek Lichtner <marek@licht.sk> + * Fixes by Michal Remiš <michal.remis@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates["sk"] = { + days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"], + daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob", "Ned"], + daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pi", "So", "Ne"], + months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Dnes", + clear: "x", + suffix: [], + meridiem: [], + weekStart: 1, + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sl.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sl.js new file mode 100644 index 00000000..a7e58bdf --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sl.js @@ -0,0 +1,17 @@ +/** + * Slovene translation for bootstrap-datetimepicker + * Gregor Rudolf <gregor.rudolf@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['sl'] = { + days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"], + daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"], + daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So", "Ne"], + months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danes", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sv.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sv.js new file mode 100644 index 00000000..050125ad --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sv.js @@ -0,0 +1,17 @@ +/** + * Swedish translation for bootstrap-datetimepicker + * Patrik Ragnarsson <patrik@starkast.net> + */ +;(function($){ + $.fn.datetimepicker.dates['sv'] = { + days: ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"], + daysShort: ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör", "Sön"], + daysMin: ["Sö", "Må", "Ti", "On", "To", "Fr", "Lö", "Sö"], + months: ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "I Dag", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sw.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sw.js new file mode 100644 index 00000000..8cdb4df2 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.sw.js @@ -0,0 +1,18 @@ +/** + * Swahili translation for bootstrap-datetimepicker + * Edwin Mugendi <https://github.com/edwinmugendi> + * Source: http://scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku + */ +;(function($){ + $.fn.datetimepicker.dates['sw'] = { + days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi", "Jumapili"], + daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1", "J2"], + daysMin: ["2", "3", "4", "5", "A", "I", "1", "2"], + months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], + monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], + today: "Leo", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.th.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.th.js new file mode 100644 index 00000000..8adc129a --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.th.js @@ -0,0 +1,17 @@ +/** + * Thai translation for bootstrap-datetimepicker + * Suchau Jiraprapot <seroz24@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['th'] = { + days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], + daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], + monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], + today: "วันนี้", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.tr.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.tr.js new file mode 100644 index 00000000..0130c94c --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.tr.js @@ -0,0 +1,18 @@ +/** + * Turkish translation for bootstrap-datetimepicker + * Serkan Algur <kaisercrazy_2@hotmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['tr'] = { + days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi", "Pazar"], + daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts", "Pz"], + daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct", "Pz"], + months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], + monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], + today: "Bugün", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery)); + diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ua.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ua.js new file mode 100644 index 00000000..1687a1dc --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.ua.js @@ -0,0 +1,16 @@ +/** + * Ukrainian translation for bootstrap-datepicker + * Igor Polynets + */ +;(function($){ + $.fn.datetimepicker.dates['ua'] = { + days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четверг", "П'ятниця", "Субота", "Неділя"], + daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], + daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], + months: ["Cічень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], + monthsShort: ["Січ", "Лют", "Бер", "Квт", "Трв", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Грд"], + today: "Сьогодні", + clear: "x", + weekStart: 1 + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.uk.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.uk.js new file mode 100644 index 00000000..4b3a9e0a --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.uk.js @@ -0,0 +1,17 @@ +/** + * Ukrainian translation for bootstrap-datetimepicker + * Andrey Vityuk <andrey [dot] vityuk [at] gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['uk'] = { + days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота", "Неділя"], + daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], + daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], + months: ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], + monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], + today: "Сьогодні", + clear: "x", + suffix: [], + meridiem: [] + }; +}(jQuery));
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh-TW.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh-TW.js new file mode 100644 index 00000000..f84ba548 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh-TW.js @@ -0,0 +1,17 @@ +/** + * Traditional Chinese translation for bootstrap-datetimepicker + * Rung-Sheng Jang <daniel@i-trend.co.cc> + */ +;(function($){ + $.fn.datetimepicker.dates['zh-TW'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], + daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], + daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + today: "今天", + clear: "x", + suffix: [], + meridiem: ["上午", "下午"] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh.js b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh.js new file mode 100644 index 00000000..66ac5a01 --- /dev/null +++ b/kvision-modules/kvision-datetime/src/main/resources/js/locales/bootstrap-datetime-picker/bootstrap-datetimepicker.zh.js @@ -0,0 +1,17 @@ +/** + * Simplified Chinese translation for bootstrap-datetimepicker + * Yuan Cheung <advanimal@gmail.com> + */ +;(function($){ + $.fn.datetimepicker.dates['zh'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], + daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], + daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + today: "今天", + clear: "x", + suffix: [], + meridiem: ["上午", "下午"] + }; +}(jQuery)); diff --git a/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt b/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt new file mode 100644 index 00000000..1da1fe1a --- /dev/null +++ b/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision + +import org.w3c.dom.Element +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.panel.Root +import kotlin.browser.document +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +interface TestSpec { + fun beforeTest() + + fun afterTest() + + fun run(code: () -> Unit) { + beforeTest() + code() + afterTest() + } +} + +interface SimpleSpec : TestSpec { + + override fun beforeTest() { + } + + override fun afterTest() { + } + +} + +interface DomSpec : TestSpec { + + override fun beforeTest() { + val fixture = "<div style=\"display: none\" id=\"pretest\">" + + "<div id=\"test\"></div></div>" + document.body?.insertAdjacentHTML("afterbegin", fixture) + } + + override fun afterTest() { + val div = document.getElementById("pretest") + div?.let { jQuery(it).remove() } + jQuery(`object` = ".modal-backdrop").remove() + } + + fun assertEqualsHtml(expected: String?, actual: String?, message: String?) { + if (expected != null && actual != null) { + val exp = jQuery(html = expected) + val act = jQuery(html = actual) + val result = exp[0]?.isEqualNode(act[0]) + if (result == true) { + assertTrue(result == true, message) + } else { + assertEquals(expected, actual, message) + } + } else { + assertEquals(expected, actual, message) + } + } +} + +interface WSpec : DomSpec { + + fun runW(code: (widget: Widget, element: Element?) -> Unit) { + run { + val root = Root("test", true) + val widget = Widget() + widget.id = "test_id" + root.add(widget) + val element = document.getElementById("test_id") + code(widget, element) + } + } + +} + +external fun require(name: String): dynamic diff --git a/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeInputSpec.kt b/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeInputSpec.kt new file mode 100644 index 00000000..d824125b --- /dev/null +++ b/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeInputSpec.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.time + +import pl.treksoft.kvision.form.time.DateTimeInput +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.types.KDate +import pl.treksoft.kvision.types.toStringF +import test.pl.treksoft.kvision.DomSpec +import kotlin.test.Test +import kotlin.test.assertEquals + +class DateTimeInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val data = KDate() + val dti = DateTimeInput(value = data).apply { + placeholder = "place" + id = "idti" + } + root.add(dti) + val value = dti.getElementJQuery()?.`val`() + assertEquals( + data.toStringF(dti.format), + value, + "Should render date time input with correctly formatted value" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeSpec.kt b/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeSpec.kt new file mode 100644 index 00000000..482a7b7a --- /dev/null +++ b/kvision-modules/kvision-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeSpec.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.time + +import pl.treksoft.kvision.form.time.DateTime +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.types.KDate +import pl.treksoft.kvision.types.toStringF +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class DateTimeSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val data = KDate() + val ti = DateTime(value = data, label = "Label").apply { + placeholder = "place" + name = "name" + disabled = true + } + root.add(ti) + val element = document.getElementById("test") + val id = ti.input.id + val datastr = data.toStringF(ti.format) + assertEqualsHtml( + "<div class=\"form-group\"><label class=\"control-label\" for=\"$id\">Label</label><input class=\"form-control\" id=\"$id\" type=\"text\" placeholder=\"place\" name=\"name\" disabled=\"disabled\" value=\"$datastr\"></div>", + element?.innerHTML, + "Should render correct date time input form control" + ) + ti.validatorError = "Validation Error" + assertEqualsHtml( + "<div class=\"form-group has-error\"><label class=\"control-label\" for=\"$id\">Label</label><input class=\"form-control\" id=\"$id\" type=\"text\" placeholder=\"place\" name=\"name\" disabled=\"disabled\" value=\"$datastr\"><span class=\"help-block small\">Validation Error</span></div>", + element?.innerHTML, + "Should render correct date time input form control with validation error" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-handlebars/build.gradle b/kvision-modules/kvision-handlebars/build.gradle new file mode 100644 index 00000000..918ed5a7 --- /dev/null +++ b/kvision-modules/kvision-handlebars/build.gradle @@ -0,0 +1,10 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("handlebars", "4.0.11") + dependency("handlebars-loader", "1.7.0") + } + +} diff --git a/kvision-modules/kvision-handlebars/package.json.d/project.info b/kvision-modules/kvision-handlebars/package.json.d/project.info new file mode 100644 index 00000000..fd5bb305 --- /dev/null +++ b/kvision-modules/kvision-handlebars/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Handlebars module" +} diff --git a/kvision-modules/kvision-handlebars/src/main/kotlin/pl/treksoft/kvision/KVManagerHandlebars.kt b/kvision-modules/kvision-handlebars/src/main/kotlin/pl/treksoft/kvision/KVManagerHandlebars.kt new file mode 100644 index 00000000..b7f5fbc6 --- /dev/null +++ b/kvision-modules/kvision-handlebars/src/main/kotlin/pl/treksoft/kvision/KVManagerHandlebars.kt @@ -0,0 +1,41 @@ +/* + * 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 + +import org.w3c.dom.asList +import kotlin.browser.document + +internal val KVManagerHandlebarsInit = KVManagerHandlebars.init() + +/** + * Internal singleton object which initializes and configures KVision handlebars module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerHandlebars { + fun init() {} + + private val handlebars = try { + require("handlebars/dist/handlebars.runtime.min.js") + } catch (e: Throwable) { + } + +} diff --git a/kvision-modules/kvision-i18n/build.gradle b/kvision-modules/kvision-i18n/build.gradle new file mode 100644 index 00000000..a2b6d3f8 --- /dev/null +++ b/kvision-modules/kvision-i18n/build.gradle @@ -0,0 +1,9 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("jed", "1.1.1") + } + +} diff --git a/kvision-modules/kvision-i18n/package.json.d/project.info b/kvision-modules/kvision-i18n/package.json.d/project.info new file mode 100644 index 00000000..cefa5d1f --- /dev/null +++ b/kvision-modules/kvision-i18n/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision i18n module" +} diff --git a/kvision-modules/kvision-i18n/src/main/kotlin/pl/treksoft/kvision/KVManagerI18n.kt b/kvision-modules/kvision-i18n/src/main/kotlin/pl/treksoft/kvision/KVManagerI18n.kt new file mode 100644 index 00000000..66e3e72c --- /dev/null +++ b/kvision-modules/kvision-i18n/src/main/kotlin/pl/treksoft/kvision/KVManagerI18n.kt @@ -0,0 +1,41 @@ +/* + * 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 + +import org.w3c.dom.asList +import kotlin.browser.document + +internal val KVManagerI18nInit = KVManagerI18n.init() + +/** + * Internal singleton object which initializes and configures KVision i18n module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerI18n { + fun init() {} + + private val jed = try { + require("jed") + } catch (e: Throwable) { + } + +} diff --git a/kvision-modules/kvision-i18n/src/main/kotlin/pl/treksoft/kvision/i18n/DefaultI18nManager.kt b/kvision-modules/kvision-i18n/src/main/kotlin/pl/treksoft/kvision/i18n/DefaultI18nManager.kt new file mode 100644 index 00000000..1eebad5c --- /dev/null +++ b/kvision-modules/kvision-i18n/src/main/kotlin/pl/treksoft/kvision/i18n/DefaultI18nManager.kt @@ -0,0 +1,44 @@ +/* + * 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 + +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 +} + +class DefaultI18nManager(translations: Map<String, dynamic>) : I18nManager { + + private val cache: Map<String, Jed> = translations.map { it.key to Jed(it.value) }.toMap() + + override fun gettext(key: String): String { + return cache[I18n.language]?.gettext(key) ?: key + } + + override fun ngettext(singularKey: String, pluralKey: String, value: Int): String { + return cache[I18n.language]?.run { + sprintf(ngettext(singularKey, pluralKey, value), value) + } ?: if (value == 1) singularKey else pluralKey + } + +} diff --git a/kvision-modules/kvision-richtext/build.gradle b/kvision-modules/kvision-richtext/build.gradle new file mode 100644 index 00000000..c00c4c27 --- /dev/null +++ b/kvision-modules/kvision-richtext/build.gradle @@ -0,0 +1,9 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("trix", "0.11.1") + } + +} diff --git a/kvision-modules/kvision-richtext/package.json.d/project.info b/kvision-modules/kvision-richtext/package.json.d/project.info new file mode 100644 index 00000000..856dc500 --- /dev/null +++ b/kvision-modules/kvision-richtext/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision RichText module" +} diff --git a/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/KVManagerRichText.kt b/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/KVManagerRichText.kt new file mode 100644 index 00000000..1ccd7a85 --- /dev/null +++ b/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/KVManagerRichText.kt @@ -0,0 +1,64 @@ +/* + * 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 + +import pl.treksoft.kvision.i18n.I18n +import pl.treksoft.kvision.utils.obj +import kotlin.browser.window + +internal val KVManagerRichTextInit = KVManagerRichText.init() + +/** + * Internal singleton object which initializes and configures KVision RichText module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerRichText { + fun init() {} + + 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/locales/trix/trix.pl.js") + } catch (e: Throwable) { + } +} diff --git a/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt b/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt new file mode 100644 index 00000000..22126797 --- /dev/null +++ b/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt @@ -0,0 +1,79 @@ +/* + * 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/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt b/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt new file mode 100644 index 00000000..961c27cd --- /dev/null +++ b/kvision-modules/kvision-richtext/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt @@ -0,0 +1,133 @@ +/* + * 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.KVManagerRichText +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/kvision-modules/kvision-richtext/src/main/resources/js/locales/trix/trix.pl.js b/kvision-modules/kvision-richtext/src/main/resources/js/locales/trix/trix.pl.js new file mode 100644 index 00000000..84dbd886 --- /dev/null +++ b/kvision-modules/kvision-richtext/src/main/resources/js/locales/trix/trix.pl.js @@ -0,0 +1,28 @@ +(function($){ + window.Trix.config.languages["pl"] = { + GB:"GB", + KB:"KB", + MB:"MB", + PB:"PB", + TB:"TB", + bold:"Pogrubienie", + bullets:"Wypunktowanie", + byte:"Bajt", + bytes:"Bajty", + captionPlaceholder:"Dodaj tytuł…", + code:"Kod źródłowy", + heading1:"Nagłówek", + indent:"Zwiększ poziom", + italic:"Pochylenie", + link:"Link", + numbers:"Numerowanie", + outdent:"Zmniejsz poziom", + quote:"Cytat", + redo:"Ponów", + remove:"Usuń", + strike:"Przekreślenie", + undo:"Cofnij", + unlink:"Usuń link", + urlPlaceholder:"Wprowadź adres URL…" + } +}(jQuery)); diff --git a/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt b/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt new file mode 100644 index 00000000..1da1fe1a --- /dev/null +++ b/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision + +import org.w3c.dom.Element +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.panel.Root +import kotlin.browser.document +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +interface TestSpec { + fun beforeTest() + + fun afterTest() + + fun run(code: () -> Unit) { + beforeTest() + code() + afterTest() + } +} + +interface SimpleSpec : TestSpec { + + override fun beforeTest() { + } + + override fun afterTest() { + } + +} + +interface DomSpec : TestSpec { + + override fun beforeTest() { + val fixture = "<div style=\"display: none\" id=\"pretest\">" + + "<div id=\"test\"></div></div>" + document.body?.insertAdjacentHTML("afterbegin", fixture) + } + + override fun afterTest() { + val div = document.getElementById("pretest") + div?.let { jQuery(it).remove() } + jQuery(`object` = ".modal-backdrop").remove() + } + + fun assertEqualsHtml(expected: String?, actual: String?, message: String?) { + if (expected != null && actual != null) { + val exp = jQuery(html = expected) + val act = jQuery(html = actual) + val result = exp[0]?.isEqualNode(act[0]) + if (result == true) { + assertTrue(result == true, message) + } else { + assertEquals(expected, actual, message) + } + } else { + assertEquals(expected, actual, message) + } + } +} + +interface WSpec : DomSpec { + + fun runW(code: (widget: Widget, element: Element?) -> Unit) { + run { + val root = Root("test", true) + val widget = Widget() + widget.id = "test_id" + root.add(widget) + val element = document.getElementById("test_id") + code(widget, element) + } + } + +} + +external fun require(name: String): dynamic diff --git a/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextInputSpec.kt b/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextInputSpec.kt new file mode 100644 index 00000000..21b7dc39 --- /dev/null +++ b/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextInputSpec.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.text + +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.form.text.RichTextInput +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertTrue + +class RichTextInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val hai = RichTextInput(value = "abc").apply { + placeholder = "place" + id = "idti" + } + root.add(hai) + val content = document.getElementById("test")?.let { jQuery(it).find("trix-editor")[0]?.outerHTML } + assertTrue( + content?.startsWith("<trix-editor") == true, + "Should render correct html area control" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextSpec.kt b/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextSpec.kt new file mode 100644 index 00000000..844b7e94 --- /dev/null +++ b/kvision-modules/kvision-richtext/src/test/kotlin/test/pl/treksoft/kvision/form/text/RichTextSpec.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.text + +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.form.text.RichText +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertTrue + +class RichTextSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val hai = RichText(value = "abc", label = "Field").apply { + placeholder = "place" + id = "idti" + } + root.add(hai) + val iid = hai.input.id + val content = document.getElementById("test")?.let { jQuery(it).find("trix-editor")[0]?.outerHTML } + assertTrue( + content?.startsWith("<trix-editor") == true, + "Should render correct html area form control" + ) + val label = document.getElementById("test")?.let { jQuery(it).find("label")[0]?.outerHTML } + assertEqualsHtml( + "<label class=\"control-label\" for=\"$iid\">Field</label>", + label, + "Should render correct label for html area form control" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-select/build.gradle b/kvision-modules/kvision-select/build.gradle new file mode 100644 index 00000000..f8fcbc8a --- /dev/null +++ b/kvision-modules/kvision-select/build.gradle @@ -0,0 +1,10 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("bootstrap-select", "1.12.4") + dependency("ajax-bootstrap-select", "1.4.3") + } + +} diff --git a/kvision-modules/kvision-select/package.json.d/project.info b/kvision-modules/kvision-select/package.json.d/project.info new file mode 100644 index 00000000..80e675b0 --- /dev/null +++ b/kvision-modules/kvision-select/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Select module" +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/KVManagerSelect.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/KVManagerSelect.kt new file mode 100644 index 00000000..c7c3815a --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/KVManagerSelect.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision + +internal val KVManagerSelectInit = KVManagerSelect.init() + +/** + * Internal singleton object which initializes and configures KVision select module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerSelect { + internal const val AJAX_REQUEST_DELAY = 300 + internal const val KVNULL = "#kvnull" + + fun init() {} + + private val bootstrapSelectCss = try { + require("bootstrap-select/dist/css/bootstrap-select.min.css") + } catch (e: Throwable) { + } + private val bootstrapSelect = try { + require("bootstrap-select/dist/js/bootstrap-select.min.js") + require("./js/locales/bootstrap-select/bootstrap-select-i18n.min.js") + } catch (e: Throwable) { + } + private val bootstrapSelectAjaxCss = try { + require("ajax-bootstrap-select/dist/css/ajax-bootstrap-select.min.css") + } catch (e: Throwable) { + } + private val bootstrapSelectAjax = try { + require("ajax-bootstrap-select/dist/js/ajax-bootstrap-select.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js") + require("./js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js") + } catch (e: Throwable) { + } + +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt new file mode 100644 index 00000000..212dc456 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.select + +import pl.treksoft.jquery.JQueryXHR +import pl.treksoft.kvision.KVManagerSelect.AJAX_REQUEST_DELAY +import pl.treksoft.kvision.KVManagerSelect.KVNULL +import pl.treksoft.kvision.i18n.I18n +import pl.treksoft.kvision.utils.obj + +/** + * HTTP protocol type for the AJAX call. + */ +enum class HttpType(internal val type: String) { + GET("GET"), + POST("POST") +} + +/** + * Data type for the AJAX call. + */ +enum class DataType(internal val type: String) { + JSON("json"), + JSONP("jsonp"), + XML("xml"), + TEXT("text"), + SCRIPT("script") +} + +/** + * Data class for AJAX options. + * + * @constructor + * @param url the url address + * @param preprocessData + * [AjaxBootstrapSelect preprocessOption](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionspreprocessdata) + * option + * @param beforeSend + * [JQuery ajax.beforeSend](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) option + * @param data + * [JQuery ajax.data](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) option + * @param httpType + * [JQuery ajax.type](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) option + * @param minLength + * [AjaxBootstrapSelect minLength](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsminlength) option + * @param cache + * [AjaxBootstrapSelect cache](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionscache) option + * @param clearOnEmpty + * [AjaxBootstrapSelect clearOnEmpty](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsclearonempty) option + * @param clearOnError + * [AjaxBootstrapSelect clearOnError](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsclearonerror) option + * @param emptyRequest + * [AjaxBootstrapSelect emptyRequest](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsemptyrequest) option + * @param requestDelay + * [AjaxBootstrapSelect requestDelay](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsrequestdelay) option + * @param restoreOnError + * [AjaxBootstrapSelect restoreOnError](https://github.com/truckingsim/Ajax-Bootstrap-Select#optionsrestoreonerror) + * option + */ +data class AjaxOptions( + val url: String, val preprocessData: (dynamic) -> dynamic, val beforeSend: ((JQueryXHR) -> dynamic)? = null, + val data: dynamic = null, val httpType: HttpType = HttpType.GET, + val dataType: DataType = DataType.JSON, val minLength: Int = 0, + val cache: Boolean = true, val clearOnEmpty: Boolean = true, val clearOnError: Boolean = true, + val emptyRequest: Boolean = false, + val requestDelay: Int = AJAX_REQUEST_DELAY, val restoreOnError: Boolean = false +) + +/** + * Convert AjaxOptions to JavaScript JSON object. + * @param emptyOption add an empty position as the first select option + * @return JSON object + */ +fun AjaxOptions.toJs(emptyOption: Boolean): dynamic { + val procData = { data: dynamic -> + val processedData = this.preprocessData(data) + if (emptyOption) { + val ret = mutableListOf(obj { + this.value = KVNULL + this.text = "" + }) + @Suppress("UnsafeCastFromDynamic") + ret.addAll((processedData as Array<dynamic>).asList()) + ret.toTypedArray() + } else { + processedData + } + } + val language = I18n.language + return obj { + this.ajax = obj { + this.url = url + this.type = httpType.type + this.dataType = dataType.type + this.data = data + this.beforeSend = beforeSend + } + this.preprocessData = procData + this.minLength = minLength + this.cache = cache + this.clearOnEmpty = clearOnEmpty + this.clearOnError = clearOnError + this.emptyRequest = emptyRequest + this.preserveSelected = false + this.requestDelay = requestDelay + this.restoreOnError = restoreOnError + this.langCode = language + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt new file mode 100644 index 00000000..f19081e1 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.form.FieldLabel +import pl.treksoft.kvision.form.HelpBlock +import pl.treksoft.kvision.form.StringFormControl +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.utils.SnOn + +/** + * The form field component for Select control. + * + * The select control can be populated directly from *options* parameter or manually by adding + * [SelectOption] or [SelectOptGroup] components to the container. + * + * @constructor + * @param options an optional list of options (label to value pairs) for the select control + * @param value selected value + * @param name the name attribute of the generated HTML input element + * @param multiple allows multiple value selection (multiple values are comma delimited) + * @param ajaxOptions additional options for remote (AJAX) data source + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ +@Suppress("TooManyFunctions") +open class Select( + options: List<StringPair>? = null, value: String? = null, name: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null, + rich: Boolean = false +) : SimplePanel(setOf("form-group")), StringFormControl { + + /** + * A list of options (label to value pairs) for the select control. + */ + var options + get() = input.options + set(value) { + input.options = value + } + /** + * A value of the selected option. + */ + override var value + get() = input.value + set(value) { + input.value = value + } + /** + * Determines if multiple value selection is allowed. + */ + var multiple + get() = input.multiple + set(value) { + input.multiple = value + } + /** + * Additional options for remote (AJAX) data source. + */ + var ajaxOptions + get() = input.ajaxOptions + set(value) { + input.ajaxOptions = value + } + /** + * Maximal number of selected options. + */ + var maxOptions + get() = input.maxOptions + set(value) { + input.maxOptions = value + } + /** + * Determines if live search is available. + */ + var liveSearch + get() = input.liveSearch + set(value) { + input.liveSearch = value + } + /** + * The placeholder for the select control. + */ + var placeholder + get() = input.placeholder + set(value) { + input.placeholder = value + } + /** + * The style of the select control. + */ + var style + get() = input.style + set(value) { + input.style = value + } + /** + * The width of the select control. + */ + var selectWidth + get() = input.selectWidth + set(value) { + input.selectWidth = value + } + /** + * The width type of the select control. + */ + var selectWidthType + get() = input.selectWidthType + set(value) { + input.selectWidthType = value + } + /** + * Determines if an empty option is automatically generated. + */ + var emptyOption + get() = input.emptyOption + set(value) { + input.emptyOption = value + } + /** + * Determines if the select is automatically focused. + */ + var autofocus + get() = input.autofocus + set(value) { + input.autofocus = value + } + /** + * The label text bound to the select element. + */ + var label + get() = flabel.content + set(value) { + flabel.content = value + } + /** + * Determines if [label] can contain HTML code. + */ + var rich + get() = flabel.rich + set(value) { + flabel.rich = value + } + + private val idc = "kv_form_select_$counter" + final override val input: SelectInput = SelectInput( + options, value, multiple, ajaxOptions, + setOf("form-control") + ).apply { + this.id = idc + this.name = name + } + final override val flabel: FieldLabel = FieldLabel(idc, label, rich) + final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } + + init { + @Suppress("LeakingThis") + input.eventTarget = this + this.addInternal(flabel) + this.addInternal(input) + this.addInternal(validationInfo) + counter++ + } + + override fun getSnClass(): List<StringBoolPair> { + val cl = super.getSnClass().toMutableList() + if (validatorError != null) { + cl.add("has-error" to true) + } + return cl + } + + @Suppress("UNCHECKED_CAST") + override fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Widget { + input.setEventListener(block) + return this + } + + override fun setEventListener(block: SnOn<Widget>.() -> Unit): Widget { + input.setEventListener(block) + return this + } + + override fun removeEventListeners(): Widget { + input.removeEventListeners() + return this + } + + override fun add(child: Component): SimplePanel { + input.add(child) + return this + } + + override fun addAll(children: List<Component>): SimplePanel { + input.addAll(children) + return this + } + + override fun remove(child: Component): SimplePanel { + input.remove(child) + return this + } + + override fun removeAll(): SimplePanel { + input.removeAll() + return this + } + + override fun getChildren(): List<Component> { + return input.getChildren() + } + + /** + * Opens dropdown with options. + */ + open fun showOptions() { + input.showOptions() + } + + /** + * Hides dropdown with options. + */ + open fun hideOptions() { + input.hideOptions() + } + + /** + * Toggles visibility of dropdown with options. + */ + open fun toggleOptions() { + input.toggleOptions() + } + + override fun focus() { + input.focus() + } + + override fun blur() { + input.blur() + } + + companion object { + internal var counter = 0 + + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.select( + options: List<StringPair>? = null, value: String? = null, name: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, label: String? = null, + rich: Boolean = false, init: (Select.() -> Unit)? = null + ): Select { + val select = Select(options, value, name, multiple, ajaxOptions, label, rich).apply { init?.invoke(this) } + this.add(select) + return select + } + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt new file mode 100644 index 00000000..8f4569c7 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.select + +import com.github.snabbdom.VNode +import pl.treksoft.kvision.KVManagerSelect.KVNULL +import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.CssSize +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.form.FormInput +import pl.treksoft.kvision.form.InputSize +import pl.treksoft.kvision.html.ButtonStyle +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.utils.asString +import pl.treksoft.kvision.utils.obj + +/** + * Select width types. See [Bootstrap Select width](http://silviomoreto.github.io/bootstrap-select/examples/#width). + */ +enum class SelectWidthType(internal val value: String) { + AUTO("auto"), + FIT("fit") +} + +/** + * The basic component for Select control. + * + * The select control can be populated directly from *options* parameter or manually by adding + * [SelectOption] or [SelectOptGroup] components to the container. + * + * @constructor + * @param options an optional list of options (label to value pairs) for the select control + * @param value selected value + * @param multiple allows multiple value selection (multiple values are comma delimited) + * @param ajaxOptions additional options for remote (AJAX) data source + * @param classes a set of CSS class names + */ +@Suppress("TooManyFunctions") +open class SelectInput( + options: List<StringPair>? = null, value: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, + classes: Set<String> = setOf() +) : SimplePanel(classes), FormInput { + + /** + * A list of options (label to value pairs) for the select control. + */ + internal var options by refreshOnUpdate(options, { setChildrenFromOptions() }) + /** + * A value of the selected option. + */ + var value by refreshOnUpdate(value, { refreshState() }) + /** + * The name attribute of the generated HTML select element. + */ + override var name: String? by refreshOnUpdate() + /** + * Determines if multiple value selection is allowed. + */ + var multiple by refreshOnUpdate(multiple) + /** + * Additional options for remote (AJAX) data source. + */ + var ajaxOptions by refreshOnUpdate(ajaxOptions, { + if (it != null) { + liveSearch = true + } + refresh() + }) + /** + * Maximal number of selected options. + */ + var maxOptions: Int? by refreshOnUpdate() + /** + * Determines if live search is available. + */ + var liveSearch by refreshOnUpdate(false) + /** + * The placeholder for the select control. + */ + var placeholder: String? by refreshOnUpdate() + /** + * The style of the select control. + */ + var style: ButtonStyle? by refreshOnUpdate() + /** + * The width of the select control. + */ + var selectWidth: CssSize? by refreshOnUpdate() + /** + * The width type of the select control. + */ + var selectWidthType: SelectWidthType? by refreshOnUpdate() + /** + * Determines if an empty option is automatically generated. + */ + var emptyOption by refreshOnUpdate(false, { setChildrenFromOptions() }) + /** + * Determines if the field is disabled. + */ + override var disabled by refreshOnUpdate(false) + /** + * Determines if the select is automatically focused. + */ + var autofocus: Boolean? by refreshOnUpdate() + /** + * The size of the input. + */ + override var size: InputSize? by refreshOnUpdate() + + init { + setChildrenFromOptions() + this.setInternalEventListener<SelectInput> { + change = { + val v = getElementJQuery()?.`val`() + self.value = v?.let { + calculateValue(it) + } + } + } + } + + private fun calculateValue(v: Any): String? { + return if (this.multiple) { + @Suppress("UNCHECKED_CAST") + val arr = v as? Array<String> + if (arr != null && arr.isNotEmpty()) { + arr.joinToString() + } else { + null + } + } else { + val vs = v as String + if (KVNULL == vs || vs.isEmpty()) { + null + } else { + vs + } + } + } + + override fun render(): VNode { + return render("select", childrenVNodes()) + } + + override fun add(child: Component): SimplePanel { + super.add(child) + refreshSelectInput() + return this + } + + override fun addAll(children: List<Component>): SimplePanel { + super.addAll(children) + refreshSelectInput() + return this + } + + override fun remove(child: Component): SimplePanel { + super.remove(child) + refreshSelectInput() + return this + } + + override fun removeAll(): SimplePanel { + super.removeAll() + refreshSelectInput() + return this + } + + private fun setChildrenFromOptions() { + if (ajaxOptions == null) { + super.removeAll() + if (emptyOption) { + super.add(SelectOption(KVNULL, "")) + } + options?.let { + val c = it.map { + SelectOption(it.first, it.second) + } + super.addAll(c) + } + } + this.refreshSelectInput() + } + + /** + * Opens dropdown with options. + */ + open fun showOptions() { + getElementJQueryD()?.selectpicker("show") + } + + /** + * Hides dropdown with options. + */ + open fun hideOptions() { + getElementJQueryD()?.selectpicker("hide") + } + + /** + * Toggles visibility of dropdown with options. + */ + open fun toggleOptions() { + getElementJQueryD()?.selectpicker("toggle") + } + + override fun getSnClass(): List<StringBoolPair> { + val cl = super.getSnClass().toMutableList() + cl.add("selectpicker" to true) + size?.let { + cl.add(it.className to true) + } + return cl + } + + private fun refreshSelectInput() { + getElementJQueryD()?.selectpicker("refresh") + refreshState() + } + + @Suppress("ComplexMethod") + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + name?.let { + sn.add("name" to it) + } + if (multiple) { + sn.add("multiple" to "multiple") + } + maxOptions?.let { + sn.add("data-max-options" to "" + it) + } + if (liveSearch) { + sn.add("data-live-search" to "true") + } + placeholder?.let { + sn.add("title" to translate(it)) + } + autofocus?.let { + if (it) { + sn.add("autofocus" to "autofocus") + } + } + if (disabled) { + sn.add("disabled" to "disabled") + } + val btnStyle = style?.className ?: "btn-default" + when (size) { + InputSize.LARGE -> { + sn.add("data-style" to "$btnStyle btn-lg") + } + InputSize.SMALL -> { + sn.add("data-style" to "$btnStyle btn-sm") + } + else -> { + sn.add("data-style" to btnStyle) + } + } + selectWidthType?.let { + sn.add("data-width" to it.value) + } ?: selectWidth?.let { + sn.add("data-width" to it.asString()) + } + return sn + } + + @Suppress("UnsafeCastFromDynamic") + override fun afterInsert(node: VNode) { + ajaxOptions?.let { + getElementJQueryD()?.selectpicker("render").ajaxSelectPicker(it.toJs(emptyOption)) + } ?: getElementJQueryD()?.selectpicker("render") + + this.getElementJQuery()?.on("show.bs.select", { e, _ -> + this.dispatchEvent("showBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("shown.bs.select", { e, _ -> + this.dispatchEvent("shownBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("hide.bs.select", { e, _ -> + this.dispatchEvent("hideBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("hidden.bs.select", { e, _ -> + this.dispatchEvent("hiddenBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("loaded.bs.select", { e, _ -> + this.dispatchEvent("loadedBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("rendered.bs.select", { e, _ -> + this.dispatchEvent("renderedBsSelect", obj { detail = e }) + }) + this.getElementJQuery()?.on("refreshed.bs.select", { e, _ -> + this.dispatchEvent("refreshedBsSelect", obj { detail = e }) + }) + this.getElementJQueryD()?.on("changed.bs.select", { e, cIndex: Int -> + e["clickedIndex"] = cIndex + this.dispatchEvent("changedBsSelect", obj { detail = e }) + }) + refreshState() + } + + @Suppress("UnsafeCastFromDynamic") + private fun refreshState() { + value?.let { + if (multiple) { + getElementJQueryD()?.selectpicker("val", it.split(",").toTypedArray()) + } else { + getElementJQueryD()?.selectpicker("val", it) + } + } ?: getElementJQueryD()?.selectpicker("val", null) + } + + /** + * Makes the input element focused. + */ + open fun focus() { + getElementJQuery()?.focus() + } + + /** + * Makes the input element blur. + */ + open fun blur() { + getElementJQuery()?.blur() + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.selectInput( + options: List<StringPair>? = null, value: String? = null, + multiple: Boolean = false, ajaxOptions: AjaxOptions? = null, + classes: Set<String> = setOf(), init: (SelectInput.() -> Unit)? = null + ): SelectInput { + val selectInput = SelectInput(options, value, multiple, ajaxOptions, classes).apply { init?.invoke(this) } + this.add(selectInput) + return selectInput + } + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt new file mode 100644 index 00000000..e33b3457 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.select + +import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.panel.SimplePanel + +/** + * The helper container for adding option groups to [Select]. + * + * The option group can be populated directly from *options* parameter or manually by adding + * [SelectOption] components to the container. + * + * @constructor + * @param label the label of the group + * @param options an optional list of options (label to value pairs) for the group + * @param maxOptions maximal number of selected options in the group + * @param disabled renders a disabled group + * @param classes a set of CSS class names + */ +open class SelectOptGroup( + label: String, options: List<StringPair>? = null, maxOptions: Int? = null, + disabled: Boolean = false, classes: Set<String> = setOf() +) : SimplePanel(classes) { + /** + * A label for the group. + */ + var label by refreshOnUpdate(label) + /** + * A list of options (label to value pairs) for the group. + */ + var options by refreshOnUpdate(options, { setChildrenFromOptions() }) + /** + * Maximal number of selected options in the group. + */ + var maxOptions by refreshOnUpdate(maxOptions) + /** + * Determines if the group is disabled. + */ + var disabled by refreshOnUpdate(disabled) + + init { + setChildrenFromOptions() + } + + override fun render(): VNode { + return render("optgroup", childrenVNodes()) + } + + private fun setChildrenFromOptions() { + this.removeAll() + options?.let { + val c = it.map { + SelectOption(it.first, it.second) + } + this.addAll(c) + } + } + + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + sn.add("label" to translate(label)) + maxOptions?.let { + sn.add("data-max-options" to "" + it) + } + if (disabled) { + sn.add("disabled" to "disabled") + } + return sn + } +} diff --git a/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt new file mode 100644 index 00000000..d1bb636e --- /dev/null +++ b/kvision-modules/kvision-select/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.form.select + +import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget + +/** + * The helper component for adding options to [Select] or [SelectOptGroup]. + * + * @constructor + * @param value the value of the option + * @param label the label of the option + * @param subtext the small subtext after the label of the option + * @param icon the icon before the label of the option + * @param divider renders this option as a divider + * @param disabled renders a disabled option + * @param classes a set of CSS class names + */ +open class SelectOption( + value: String? = null, label: String? = null, subtext: String? = null, icon: String? = null, + divider: Boolean = false, disabled: Boolean = false, + classes: Set<String> = setOf() +) : Widget(classes) { + + /** + * The value of the option. + */ + var value by refreshOnUpdate(value) + /** + * The label of the option. + */ + var label by refreshOnUpdate(label) + /** + * The subtext after the label of the option. + */ + var subtext by refreshOnUpdate(subtext) + /** + * The icon before the label of the option. + */ + var icon by refreshOnUpdate(icon) + /** + * Determines if the option should be rendered as divider. + */ + var divider by refreshOnUpdate(divider) + /** + * Determines if the option should be disabled. + */ + var disabled by refreshOnUpdate(disabled) + + override fun render(): VNode { + return if (!divider) { + render("option", arrayOf(translate(label) ?: value)) + } else { + render("option") + } + } + + override fun getSnAttrs(): List<StringPair> { + val sn = super.getSnAttrs().toMutableList() + if (!divider) { + value?.let { + sn.add("value" to it) + } + subtext?.let { + sn.add("data-subtext" to translate(it)) + } + icon?.let { + if (it.startsWith("fa-")) { + sn.add("data-icon" to "fa $it") + } else { + sn.add("data-icon" to "glyphicon-$it") + } + } + if (disabled) { + sn.add("disabled" to "disabled") + } + } else { + sn.add("data-divider" to "true") + } + return sn + } +} diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js new file mode 100644 index 00000000..08b38207 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.de-DE.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * English translation for the "en-US" and "en" language codes. + * Tobias Weichart <tobias.weichart@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["de-DE"]={currentlySelected:"Momentan ausgewählt",emptyTitle:"Hier klicken und eingeben",errorText:"Ergebnisse konnten nicht abgerufen wurden",searchPlaceholder:"Suche...",statusInitialized:"Suchbegriff eingeben",statusNoResults:"Keine Ergebnisse",statusSearching:"Suche...",statusTooShort:"Der Suchbegriff ist nicht lang genug"},$.fn.ajaxSelectPicker.locale.de=$.fn.ajaxSelectPicker.locale["de-DE"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.en-US.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.en-US.min.js new file mode 100644 index 00000000..8b130b97 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.en-US.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * English translation for the "en-US" and "en" language codes. + * Mark Carver <mark.carver@me.com> + */ +$.fn.ajaxSelectPicker.locale["en-US"]={currentlySelected:"Currently Selected",emptyTitle:"Select and begin typing",errorText:"Unable to retrieve results",searchPlaceholder:"Search...",statusInitialized:"Start typing a search query",statusNoResults:"No Results",statusSearching:"Searching...",statusTooShort:"Please enter more characters"},$.fn.ajaxSelectPicker.locale.en=$.fn.ajaxSelectPicker.locale["en-US"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js new file mode 100644 index 00000000..bbe3fe45 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.es-ES.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Spanish translation for the "es-ES" and "es" language codes. + * Diomedes Domínguez <diomedes.domimnguez@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["es-ES"]={currentlySelected:"Seleccionado",emptyTitle:"Seleccione y comience a escribir",errorText:"No se puede recuperar resultados",searchPlaceholder:"Buscar...",statusInitialized:"Empieza a escribir una consulta de búsqueda",statusNoResults:"Sin Resultados",statusSearching:"Buscando...",statusTooShort:"Introduzca más caracteres"},$.fn.ajaxSelectPicker.locale.es=$.fn.ajaxSelectPicker.locale["es-ES"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js new file mode 100644 index 00000000..1d86582f --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.fr-FR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * French translation for the "fr-FR" and "fr" language codes. + * Bastien (https://github.com/lisurc) + */ +$.fn.ajaxSelectPicker.locale["fr-FR"]={currentlySelected:"Actuellement sélectionné",emptyTitle:"Sélectionner et commencer à taper",errorText:"Impossible de récupérer les résultats",searchPlaceholder:"Rechercher...",statusInitialized:"Commencer à taper une recherche",statusNoResults:"Aucun résultat",statusSearching:"Recherche en cours...",statusTooShort:"Entrez plus de caractères"},$.fn.ajaxSelectPicker.locale.fr=$.fn.ajaxSelectPicker.locale["fr-FR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js new file mode 100644 index 00000000..b30deb3e --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.it-IT.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Italian translation for the "it-IT" and "it" language codes. + * Luca Longo <l.longo@ambita.it> + */ +$.fn.ajaxSelectPicker.locale["it-IT"]={currentlySelected:"Selezionati",emptyTitle:"Clicca qui e scrivi...",errorText:"Impossibile recuperare dei risultati",searchPlaceholder:"Cerca...",statusInitialized:"Inizia a digitare...",statusNoResults:"Non ci sono risultati",statusSearching:"Ricerca in corso...",statusTooShort:"Inserisci altri caratteri"},$.fn.ajaxSelectPicker.locale.it=$.fn.ajaxSelectPicker.locale["it-IT"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js new file mode 100644 index 00000000..23a9a348 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ja-JP.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Japanese translation for the "ja-JP" and "ja" language codes. + * Haginaga <haginaga@unetworks.jp> + */ +$.fn.ajaxSelectPicker.locale["ja-JP"]={currentlySelected:"現在の値",emptyTitle:"未選択",errorText:"検索できません",searchPlaceholder:"検索する",statusInitialized:"選択肢を入力",statusNoResults:"見つかりません",statusSearching:"検索中...",statusTooShort:"入力文字数不足"},$.fn.ajaxSelectPicker.locale.ja=$.fn.ajaxSelectPicker.locale["ja-JP"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js new file mode 100644 index 00000000..2fd5299b --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ko-KR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Korean translation for the "ko-KR" and "ko" language codes. + * Jo JungLae <ubermenschjo@google.com> + */ +$.fn.ajaxSelectPicker.locale["ko-KR"]={currentlySelected:"현재 선택된 항목",emptyTitle:"클릭하고 입력 시작",errorText:"결과를 검색할 수 없습니다",searchPlaceholder:"검색",statusInitialized:"검색어를 입력",statusNoResults:"검색결과가 없습니다",statusSearching:"검색중",statusTooShort:"추가 문자를 입력하십시오."},$.fn.ajaxSelectPicker.locale.ko=$.fn.ajaxSelectPicker.locale["ko-KR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js new file mode 100644 index 00000000..6c6a16f2 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.nl-NL.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Dutch translation for the "nl-NL" and "nl" language codes. + * Arjen Ruiterkamp <arjenruiterkamp@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["nl-NL"]={currentlySelected:"Momenteel geselecteerd",emptyTitle:"Selecteer en begin met typen",errorText:"Kon geen resultaten ophalen",searchPlaceholder:"Zoeken...",statusInitialized:"Begin met typen om te zoeken",statusNoResults:"Geen resultaten",statusSearching:"Zoeken...",statusTooShort:"U dient meer karakters in te voeren"},$.fn.ajaxSelectPicker.locale.nl=$.fn.ajaxSelectPicker.locale["nl-NL"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js new file mode 100644 index 00000000..f104f491 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pl-PL.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Polish translation for the "pl-PL" and "pl" language codes. + * Robert Jaros <rjaros@treksoft.pl> + */ +$.fn.ajaxSelectPicker.locale["pl-PL"]={currentlySelected:"Aktualny wybór",emptyTitle:"Wybierz i zacznij pisać",errorText:"Nie można pobrać wyników",searchPlaceholder:"Szukaj...",statusInitialized:"Zacznij pisać warunek wyszukiwania",statusNoResults:"Brak wyników",statusSearching:"Szukam...",statusTooShort:"Wprowadź więcej znaków"},$.fn.ajaxSelectPicker.locale.pl=$.fn.ajaxSelectPicker.locale["pl-PL"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js new file mode 100644 index 00000000..2a6e743d --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.pt-BR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Brazilian portuguese translation for the "pt-BR" and "pt" language codes. + * Luan Fonseca <luanfonceca@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["pt-BR"]={currentlySelected:"Selecionado Atualmente",emptyTitle:"Clique e comece a digitar",errorText:"Incapaz de encontrar resultados",searchPlaceholder:"Buscar...",statusInitialized:"Comece a digitar",statusNoResults:"Sem Resultados",statusSearching:"Buscando...",statusTooShort:"Digite mais caracteres"},$.fn.ajaxSelectPicker.locale.pt=$.fn.ajaxSelectPicker.locale["pt-BR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js new file mode 100644 index 00000000..aa6d4d06 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.ru-RU.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Russian translation for the "ru-RU" and "ru" language codes. + * Bercut Stray <bercut497@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["ru-RU"]={currentlySelected:"Выбрано",emptyTitle:"Выделите и начните печатать",errorText:"Невозможно получить результат",searchPlaceholder:"Искать...",statusInitialized:"Начните печатать запрос для поиска",statusNoResults:"Нет результатов",statusSearching:"Поиск...",statusTooShort:"Введите еще несколько символов"},$.fn.ajaxSelectPicker.locale.ru=$.fn.ajaxSelectPicker.locale["ru-RU"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js new file mode 100644 index 00000000..6af588f4 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/ajax-bootstrap-select/ajax-bootstrap-select.tr-TR.min.js @@ -0,0 +1,22 @@ +/*! + * Ajax Bootstrap Select + * + * Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON. + * + * @version 1.4.3 + * @author Adam Heim - https://github.com/truckingsim + * @link https://github.com/truckingsim/Ajax-Bootstrap-Select + * @copyright 2017 Adam Heim + * @license Released under the MIT license. + * + * Contributors: + * Mark Carver - https://github.com/markcarver + * + * Last build: 2017-11-15 1:19:45 PM EST + */ +!(function ($) { +/*! + * Turkish translation for the "tr-TR" and "tr" language codes. + * Burak Çakırel <burakcakirel@gmail.com> + */ +$.fn.ajaxSelectPicker.locale["tr-TR"]={currentlySelected:"Seçili olanlar",emptyTitle:"Seç ve yazmaya başla",errorText:"Sonuçlar alınamadı",searchPlaceholder:"Ara...",statusInitialized:"Arama için yazmaya başla",statusNoResults:"Sonuç yok",statusSearching:"Aranıyor...",statusTooShort:"Lütfen daha fazla karakter girin"},$.fn.ajaxSelectPicker.locale.tr=$.fn.ajaxSelectPicker.locale["tr-TR"];})(jQuery); diff --git a/kvision-modules/kvision-select/src/main/resources/js/locales/bootstrap-select/bootstrap-select-i18n.min.js b/kvision-modules/kvision-select/src/main/resources/js/locales/bootstrap-select/bootstrap-select-i18n.min.js new file mode 100644 index 00000000..4428d3c0 --- /dev/null +++ b/kvision-modules/kvision-select/src/main/resources/js/locales/bootstrap-select/bootstrap-select-i18n.min.js @@ -0,0 +1 @@ +!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"",noneResultsText:"",countSelectedText:function(a,b){return 1==a?"... ({n})":"... ({n})"},maxOptionsText:function(a,b){return[1==a?"🛇":"🛇",1==b?"🛇":"🛇"]},selectAllText:"++",deselectAllText:"--",multipleSeparator:", "}}(a)});
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt new file mode 100644 index 00000000..1da1fe1a --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision + +import org.w3c.dom.Element +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.panel.Root +import kotlin.browser.document +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +interface TestSpec { + fun beforeTest() + + fun afterTest() + + fun run(code: () -> Unit) { + beforeTest() + code() + afterTest() + } +} + +interface SimpleSpec : TestSpec { + + override fun beforeTest() { + } + + override fun afterTest() { + } + +} + +interface DomSpec : TestSpec { + + override fun beforeTest() { + val fixture = "<div style=\"display: none\" id=\"pretest\">" + + "<div id=\"test\"></div></div>" + document.body?.insertAdjacentHTML("afterbegin", fixture) + } + + override fun afterTest() { + val div = document.getElementById("pretest") + div?.let { jQuery(it).remove() } + jQuery(`object` = ".modal-backdrop").remove() + } + + fun assertEqualsHtml(expected: String?, actual: String?, message: String?) { + if (expected != null && actual != null) { + val exp = jQuery(html = expected) + val act = jQuery(html = actual) + val result = exp[0]?.isEqualNode(act[0]) + if (result == true) { + assertTrue(result == true, message) + } else { + assertEquals(expected, actual, message) + } + } else { + assertEquals(expected, actual, message) + } + } +} + +interface WSpec : DomSpec { + + fun runW(code: (widget: Widget, element: Element?) -> Unit) { + run { + val root = Root("test", true) + val widget = Widget() + widget.id = "test_id" + root.add(widget) + val element = document.getElementById("test_id") + code(widget, element) + } + } + +} + +external fun require(name: String): dynamic diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectInputSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectInputSpec.kt new file mode 100644 index 00000000..30f42e9c --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectInputSpec.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.form.select.SelectWidthType +import pl.treksoft.kvision.form.select.SelectInput +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertTrue + +class SelectInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val selectInput = SelectInput(listOf("test1" to "Test 1", "test2" to "Test 2"), "test1", true).apply { + liveSearch = true + placeholder = "Choose ..." + selectWidthType = SelectWidthType.FIT + emptyOption = true + } + root.add(selectInput) + val element = document.getElementById("test") + assertTrue( + true == element?.innerHTML?.endsWith("<select class=\"selectpicker\" multiple=\"multiple\" data-live-search=\"true\" title=\"Choose ...\" data-style=\"btn-default\" data-width=\"fit\" tabindex=\"-98\"><option value=\"#kvnull\"></option><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option></select></div>"), + "Should render correct select input" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptGroupSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptGroupSpec.kt new file mode 100644 index 00000000..bd88f560 --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptGroupSpec.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.form.select.SelectOptGroup +import pl.treksoft.kvision.form.select.SelectOption +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class SelectOptGroupSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val selectOptGroup = SelectOptGroup("Group", listOf("test1" to "Test 1", "test2" to "Test 2"), 2) + root.add(selectOptGroup) + val element = document.getElementById("test") + assertEqualsHtml( + "<optgroup label=\"Group\" data-max-options=\"2\"><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option></optgroup>", + element?.innerHTML, + "Should render correct select option group" + ) + selectOptGroup.add(SelectOption("test3", "Test 3")) + assertEqualsHtml( + "<optgroup label=\"Group\" data-max-options=\"2\"><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option><option value=\"test3\">Test 3</option></optgroup>", + element?.innerHTML, + "Should render correct select option group with added option" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptionSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptionSpec.kt new file mode 100644 index 00000000..f7e07d42 --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectOptionSpec.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.form.select.SelectOption +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class SelectOptionSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val selectOption = SelectOption("testValue", "testLabel") + root.add(selectOption) + val element = document.getElementById("test") + assertEqualsHtml( + "<option value=\"testValue\">testLabel</option>", + element?.innerHTML, + "Should render correct select option" + ) + selectOption.icon = "fa-flag" + assertEqualsHtml( + "<option value=\"testValue\" data-icon=\"fa fa-flag\">testLabel</option>", + element?.innerHTML, + "Should render correct select option with icon" + ) + selectOption.divider = true + assertEqualsHtml( + "<option data-divider=\"true\"></option>", + element?.innerHTML, + "Should render correct divider option" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt new file mode 100644 index 00000000..eaccd551 --- /dev/null +++ b/kvision-modules/kvision-select/src/test/kotlin/test/pl/treksoft/kvision/form/select/SelectSpec.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.select + +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.form.select.SelectWidthType +import pl.treksoft.kvision.form.select.Select +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertTrue + +class SelectSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val select = Select(listOf("test1" to "Test 1", "test2" to "Test 2"), "test1", null, true, null, "Label").apply { + liveSearch = true + placeholder = "Choose ..." + selectWidthType = SelectWidthType.FIT + emptyOption = true + } + root.add(select) + val element = document.getElementById("test") + val id = select.input.id + assertTrue( + true == element?.innerHTML?.startsWith("<div class=\"form-group\"><label class=\"control-label\" for=\"$id\">Label</label>"), + "Should render correct select form control" + ) + assertTrue( + true == element?.innerHTML?.endsWith("<select class=\"form-control selectpicker\" id=\"$id\" multiple=\"multiple\" data-live-search=\"true\" title=\"Choose ...\" data-style=\"btn-default\" data-width=\"fit\" tabindex=\"-98\"><option value=\"#kvnull\"></option><option value=\"test1\">Test 1</option><option value=\"test2\">Test 2</option></select></div></div>"), + "Should render correct select form control" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-server-jooby/build.gradle b/kvision-modules/kvision-server-jooby/build.gradle new file mode 100644 index 00000000..952e9a16 --- /dev/null +++ b/kvision-modules/kvision-server-jooby/build.gradle @@ -0,0 +1,31 @@ +apply plugin: "io.spring.dependency-management" +apply plugin: 'kotlin-platform-jvm' +apply plugin: 'kotlinx-serialization' + +dependencyManagement { + imports { + mavenBom "org.jooby:jooby-bom:${joobyVersion}" + } +} + +dependencies { + expectedBy project(":kvision-modules:kvision-common") + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion" + compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" + compile "org.jooby:jooby-lang-kotlin" + compile "org.jooby:jooby-jackson" + compile "org.jooby:jooby-pac4j2" + compile "com.github.andrewoma.kwery:mapper:${kweryVersion}" + compile "com.fasterxml.jackson.module:jackson-module-kotlin:${jacksonModuleKotlinVersion}" + testCompile "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" + testCompile project(":kvision-modules:kvision-common") +} + +compileKotlin { + targetCompatibility = javaVersion + sourceCompatibility = javaVersion + kotlinOptions { + jvmTarget = javaVersion + } +} diff --git a/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/Jooby.kt b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/Jooby.kt new file mode 100644 index 00000000..928892a2 --- /dev/null +++ b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/Jooby.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +@file:Suppress("EXPERIMENTAL_FEATURE_WARNING") + +package pl.treksoft.kvision.remote + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import org.jooby.Kooby +import org.jooby.Session +import org.jooby.json.Jackson +import org.pac4j.core.profile.CommonProfile +import kotlinx.coroutines.async as coroutinesAsync + +/** + * A Jooby based server. + */ +actual open class JoobyServer(init: JoobyServer.() -> Unit) : Kooby() { + init { + @Suppress("LeakingThis") + assets("/", "index.html") + @Suppress("LeakingThis") + assets("/**").onMissing(0) + val mapper = jacksonObjectMapper() + @Suppress("LeakingThis") + use(Jackson(mapper)) + @Suppress("LeakingThis") + init.invoke(this) + } +} + +/** + * A server request. + */ +actual typealias Request = org.jooby.Request + +/** + * A user profile. + */ +actual typealias Profile = CommonProfile + +/** + * A helper extension function for asynchronous request processing. + */ +fun <RESP> Request?.async(block: (Request) -> RESP): Deferred<RESP> = this?.let { req -> + GlobalScope.coroutinesAsync(Dispatchers.Unconfined) { + block(req) + } +} ?: throw IllegalStateException("Request not set!") + +/** + * A helper extension function for asynchronous request processing with session. + */ +fun <RESP> Request?.async(block: (Request, Session) -> RESP): Deferred<RESP> = this?.let { req -> + val session = req.session() + GlobalScope.coroutinesAsync(Dispatchers.Unconfined) { + block(req, session) + } +} ?: throw IllegalStateException("Request not set!") + +/** + * A helper extension function for asynchronous request processing with session and user profile. + */ +fun <RESP> Request?.async(block: (Request, Session, Profile) -> RESP): Deferred<RESP> = this?.let { req -> + val session = req.session() + val profile = req.require(CommonProfile::class.java) + GlobalScope.coroutinesAsync(Dispatchers.Unconfined) { + block(req, session, profile) + } +} ?: throw IllegalStateException("Request not set!") diff --git a/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/ServiceManager.kt b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/ServiceManager.kt new file mode 100644 index 00000000..edaa9ba3 --- /dev/null +++ b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/remote/ServiceManager.kt @@ -0,0 +1,338 @@ +/* + * 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.remote + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.runBlocking +import org.jooby.Response +import org.jooby.Status +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +/** + * Multiplatform service manager. + */ +@Suppress("EXPERIMENTAL_FEATURE_WARNING") +actual open class ServiceManager<out T> actual constructor(val service: T) { + + companion object { + val LOG: Logger = LoggerFactory.getLogger(ServiceManager::class.java.name) + } + + protected val routes: MutableList<JoobyServer.() -> Unit> = mutableListOf() + val mapper = jacksonObjectMapper() + var counter: Int = 0 + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected actual inline fun <reified RET> bind( + noinline function: T.(Request?) -> Deferred<RET>, + route: String?, method: RpcHttpMethod, prefix: String + ) { + val routeDef = route ?: "route${this::class.simpleName}${counter++}" + routes.add({ + call(method, "$prefix$routeDef") { req, res -> + if (service != null) { + val jsonRpcRequest = req.body(JsonRpcRequest::class.java) + try { + val result = runBlocking { function.invoke(service, req).await() } + res.send( + JsonRpcResponse( + id = jsonRpcRequest.id, + result = mapper.writeValueAsString(result) + ) + ) + } catch (e: Exception) { + LOG.error(e.message, e) + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = e.message ?: "Error")) + } + } else { + res.status(Status.SERVER_ERROR) + } + }.invoke(this) + }) + } + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected actual inline fun <reified PAR, reified RET> bind( + noinline function: T.(PAR, Request?) -> Deferred<RET>, + route: String?, method: RpcHttpMethod, prefix: String + ) { + val routeDef = route ?: "route${this::class.simpleName}${counter++}" + routes.add({ + call(method, "$prefix$routeDef") { req, res -> + if (service != null) { + val jsonRpcRequest = req.body(JsonRpcRequest::class.java) + if (jsonRpcRequest.params.size == 1) { + val param = getParameter<PAR>(jsonRpcRequest.params[0]) + try { + val result = runBlocking { function.invoke(service, param, req).await() } + res.send( + JsonRpcResponse( + id = jsonRpcRequest.id, + result = mapper.writeValueAsString(result) + ) + ) + } catch (e: Exception) { + LOG.error(e.message, e) + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = e.message ?: "Error")) + } + } else { + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = "Invalid parameters")) + } + } else { + res.status(Status.SERVER_ERROR) + } + }.invoke(this) + }) + } + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected actual inline fun <reified PAR1, reified PAR2, reified RET> bind( + noinline function: T.(PAR1, PAR2, Request?) -> Deferred<RET>, + route: String?, method: RpcHttpMethod, prefix: String + ) { + val routeDef = route ?: "route${this::class.simpleName}${counter++}" + routes.add({ + call(method, "$prefix$routeDef") { req, res -> + if (service != null) { + val jsonRpcRequest = req.body(JsonRpcRequest::class.java) + if (jsonRpcRequest.params.size == 2) { + val param1 = getParameter<PAR1>(jsonRpcRequest.params[0]) + val param2 = getParameter<PAR2>(jsonRpcRequest.params[1]) + try { + val result = runBlocking { function.invoke(service, param1, param2, req).await() } + res.send( + JsonRpcResponse( + id = jsonRpcRequest.id, + result = mapper.writeValueAsString(result) + ) + ) + } catch (e: Exception) { + LOG.error(e.message, e) + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = e.message ?: "Error")) + } + } else { + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = "Invalid parameters")) + } + } else { + res.status(Status.SERVER_ERROR) + } + }.invoke(this) + }) + } + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, reified RET> bind( + noinline function: T.(PAR1, PAR2, PAR3, Request?) -> Deferred<RET>, + route: String?, method: RpcHttpMethod, prefix: String + ) { + val routeDef = route ?: "route${this::class.simpleName}${counter++}" + routes.add({ + call(method, "$prefix$routeDef") { req, res -> + if (service != null) { + val jsonRpcRequest = req.body(JsonRpcRequest::class.java) + if (jsonRpcRequest.params.size == 3) { + val param1 = getParameter<PAR1>(jsonRpcRequest.params[0]) + val param2 = getParameter<PAR2>(jsonRpcRequest.params[1]) + val param3 = getParameter<PAR3>(jsonRpcRequest.params[2]) + try { + val result = runBlocking { function.invoke(service, param1, param2, param3, req).await() } + res.send( + JsonRpcResponse( + id = jsonRpcRequest.id, + result = mapper.writeValueAsString(result) + ) + ) + } catch (e: Exception) { + LOG.error(e.message, e) + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = e.message ?: "Error")) + } + } else { + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = "Invalid parameters")) + } + } else { + res.status(Status.SERVER_ERROR) + } + }.invoke(this) + }) + } + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, reified PAR4, reified RET> bind( + noinline function: T.(PAR1, PAR2, PAR3, PAR4, Request?) -> Deferred<RET>, + route: String?, method: RpcHttpMethod, prefix: String + ) { + val routeDef = route ?: "route${this::class.simpleName}${counter++}" + routes.add({ + call(method, "$prefix$routeDef") { req, res -> + if (service != null) { + val jsonRpcRequest = req.body(JsonRpcRequest::class.java) + if (jsonRpcRequest.params.size == 4) { + val param1 = getParameter<PAR1>(jsonRpcRequest.params[0]) + val param2 = getParameter<PAR2>(jsonRpcRequest.params[1]) + val param3 = getParameter<PAR3>(jsonRpcRequest.params[2]) + val param4 = getParameter<PAR4>(jsonRpcRequest.params[3]) + try { + val result = + runBlocking { function.invoke(service, param1, param2, param3, param4, req).await() } + res.send( + JsonRpcResponse( + id = jsonRpcRequest.id, + result = mapper.writeValueAsString(result) + ) + ) + } catch (e: Exception) { + LOG.error(e.message, e) + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = e.message ?: "Error")) + } + } else { + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = "Invalid parameters")) + } + } else { + res.status(Status.SERVER_ERROR) + } + }.invoke(this) + }) + } + + /** + * Binds a given route with a function of the receiver. + * @param function a function of the receiver + * @param route a route + * @param method a HTTP method + * @param prefix an URL address prefix + */ + protected actual inline fun <reified PAR1, reified PAR2, reified PAR3, + reified PAR4, reified PAR5, reified RET> bind( + noinline function: T.(PAR1, PAR2, PAR3, PAR4, PAR5, Request?) -> Deferred<RET>, + route: String?, + method: RpcHttpMethod, + prefix: String + ) { + val routeDef = route ?: "route${this::class.simpleName}${counter++}" + routes.add({ + call(method, "$prefix$routeDef") { req, res -> + if (service != null) { + val jsonRpcRequest = req.body(JsonRpcRequest::class.java) + if (jsonRpcRequest.params.size == 5) { + val param1 = getParameter<PAR1>(jsonRpcRequest.params[0]) + val param2 = getParameter<PAR2>(jsonRpcRequest.params[1]) + val param3 = getParameter<PAR3>(jsonRpcRequest.params[2]) + val param4 = getParameter<PAR4>(jsonRpcRequest.params[3]) + val param5 = getParameter<PAR5>(jsonRpcRequest.params[4]) + try { + val result = + runBlocking { + function.invoke(service, param1, param2, param3, param4, param5, req).await() + } + res.send( + JsonRpcResponse( + id = jsonRpcRequest.id, + result = mapper.writeValueAsString(result) + ) + ) + } catch (e: Exception) { + LOG.error(e.message, e) + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = e.message ?: "Error")) + } + } else { + res.send(JsonRpcResponse(id = jsonRpcRequest.id, error = "Invalid parameters")) + } + } else { + res.status(Status.SERVER_ERROR) + } + }.invoke(this) + }) + } + + fun call( + method: RpcHttpMethod, + path: String, + handler: (Request, Response) -> Unit + ): JoobyServer.() -> Unit { + return { + when (method) { + RpcHttpMethod.POST -> post(path, handler) + RpcHttpMethod.PUT -> put(path, handler) + RpcHttpMethod.DELETE -> delete(path, handler) + RpcHttpMethod.OPTIONS -> options(path, handler) + } + } + } + + protected inline fun <reified T> getParameter(str: String?): T { + return str?.let { + if (T::class == String::class) { + str as T + } else { + mapper.readValue(str, T::class.java) + } + } ?: null as T + } + + /** + * Applies all defined routes to the given server. + * @param k a Jooby server + */ + actual fun applyRoutes(k: JoobyServer) { + routes.forEach { + it.invoke(k) + } + } + + /** + * Returns the list of defined bindings. + * Not used on the jvm platform. + */ + actual fun getCalls(): Map<String, Pair<String, RpcHttpMethod>> = mapOf() +} diff --git a/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt new file mode 100644 index 00000000..9fc534c4 --- /dev/null +++ b/kvision-modules/kvision-server-jooby/src/main/kotlin/pl/treksoft/kvision/types/KDate.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.types + +import com.github.andrewoma.kwery.mapper.SimpleConverter +import com.github.andrewoma.kwery.mapper.TableConfiguration +import com.github.andrewoma.kwery.mapper.reifiedConverter +import com.github.andrewoma.kwery.mapper.standardConverters +import com.github.andrewoma.kwery.mapper.util.camelToLowerUnderscore +import java.sql.Timestamp +import java.text.SimpleDateFormat +import java.util.* + +/** + * A serializable wrapper for a multiplatform Date type. + */ +@Suppress("MayBeConstant") +actual val KDATE_FORMAT = "yyyy-MM-dd HH:mm:ss" + +actual fun nowDate(): KDate = + KDate(Date().time) + +actual fun String.toKDateF(format: String): KDate = + KDate(SimpleDateFormat(format).parse(this).time) + +actual fun KDate.toStringF(format: String) = + SimpleDateFormat(format).format(this.toJava()) + +fun KDate.toJava(): java.util.Date = java.util.Date(this.time) + +object KDateConverter : SimpleConverter<KDate>( + { row, c -> KDate(row.timestamp(c).time) }, + { Timestamp(it.time) } +) + +val kvTableConfig = TableConfiguration( + converters = standardConverters + reifiedConverter(KDateConverter), + namingConvention = camelToLowerUnderscore +) diff --git a/kvision-modules/kvision-spinner/build.gradle b/kvision-modules/kvision-spinner/build.gradle new file mode 100644 index 00000000..ce88c117 --- /dev/null +++ b/kvision-modules/kvision-spinner/build.gradle @@ -0,0 +1,9 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("bootstrap-touchspin", "3.1.1") + } + +} diff --git a/kvision-modules/kvision-spinner/package.json.d/project.info b/kvision-modules/kvision-spinner/package.json.d/project.info new file mode 100644 index 00000000..fb0c7956 --- /dev/null +++ b/kvision-modules/kvision-spinner/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Spinner module" +} diff --git a/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/KVManagerSpinner.kt b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/KVManagerSpinner.kt new file mode 100644 index 00000000..0de06c8c --- /dev/null +++ b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/KVManagerSpinner.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision + +internal val KVManagerSpinnerInit = KVManagerSpinner.init() + +/** + * Internal singleton object which initializes and configures KVision spinner module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerSpinner { + fun init() {} + + 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") + } catch (e: Throwable) { + } + +} diff --git a/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt new file mode 100644 index 00000000..4fa68e47 --- /dev/null +++ b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt @@ -0,0 +1,263 @@ +/* + * 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/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt new file mode 100644 index 00000000..7d3af684 --- /dev/null +++ b/kvision-modules/kvision-spinner/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt @@ -0,0 +1,323 @@ +/* + * 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/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt b/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt new file mode 100644 index 00000000..1da1fe1a --- /dev/null +++ b/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision + +import org.w3c.dom.Element +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.panel.Root +import kotlin.browser.document +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +interface TestSpec { + fun beforeTest() + + fun afterTest() + + fun run(code: () -> Unit) { + beforeTest() + code() + afterTest() + } +} + +interface SimpleSpec : TestSpec { + + override fun beforeTest() { + } + + override fun afterTest() { + } + +} + +interface DomSpec : TestSpec { + + override fun beforeTest() { + val fixture = "<div style=\"display: none\" id=\"pretest\">" + + "<div id=\"test\"></div></div>" + document.body?.insertAdjacentHTML("afterbegin", fixture) + } + + override fun afterTest() { + val div = document.getElementById("pretest") + div?.let { jQuery(it).remove() } + jQuery(`object` = ".modal-backdrop").remove() + } + + fun assertEqualsHtml(expected: String?, actual: String?, message: String?) { + if (expected != null && actual != null) { + val exp = jQuery(html = expected) + val act = jQuery(html = actual) + val result = exp[0]?.isEqualNode(act[0]) + if (result == true) { + assertTrue(result == true, message) + } else { + assertEquals(expected, actual, message) + } + } else { + assertEquals(expected, actual, message) + } + } +} + +interface WSpec : DomSpec { + + fun runW(code: (widget: Widget, element: Element?) -> Unit) { + run { + val root = Root("test", true) + val widget = Widget() + widget.id = "test_id" + root.add(widget) + val element = document.getElementById("test_id") + code(widget, element) + } + } + +} + +external fun require(name: String): dynamic diff --git a/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/form/spinner/SpinnerInputSpec.kt b/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/form/spinner/SpinnerInputSpec.kt new file mode 100644 index 00000000..a240bfd8 --- /dev/null +++ b/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/form/spinner/SpinnerInputSpec.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.spinner + +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.form.spinner.SpinnerInput +import test.pl.treksoft.kvision.DomSpec +import kotlin.test.Test +import kotlin.test.assertEquals + +class SpinnerInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val si = SpinnerInput(value = 13).apply { + placeholder = "place" + id = "idti" + } + root.add(si) + val value = si.getElementJQuery()?.`val`() + assertEquals("13", value, "Should render spinner input with correct value") + } + } + + @Test + fun spinUp() { + run { + val root = Root("test", true) + val si = SpinnerInput(value = 13).apply { + placeholder = "place" + id = "idti" + } + root.add(si) + assertEquals(13, si.value, "Should return initial value before spinUp") + si.spinUp() + assertEquals(14, si.value, "Should return changed value after spinUp") + } + } + + @Test + fun spinDown() { + run { + val root = Root("test", true) + val si = SpinnerInput(value = 13).apply { + placeholder = "place" + id = "idti" + } + root.add(si) + assertEquals(13, si.value, "Should return initial value before spinDown") + si.spinDown() + assertEquals(12, si.value, "Should return changed value after spinDown") + } + } +}
\ No newline at end of file diff --git a/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/form/spinner/SpinnerSpec.kt b/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/form/spinner/SpinnerSpec.kt new file mode 100644 index 00000000..e2eec3f9 --- /dev/null +++ b/kvision-modules/kvision-spinner/src/test/kotlin/test/pl/treksoft/kvision/form/spinner/SpinnerSpec.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.spinner + +import pl.treksoft.kvision.form.spinner.Spinner +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class SpinnerSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val ti = Spinner(value = 13, label = "Label").apply { + placeholder = "place" + name = "name" + disabled = true + } + root.add(ti) + val element = document.getElementById("test") + val id = ti.input.id + assertEqualsHtml( + "<div class=\"form-group\"><label class=\"control-label\" for=\"$id\">Label</label><div class=\"input-group kv-spinner-btn-vertical\"><span><div class=\"input-group bootstrap-touchspin\"><span class=\"input-group-addon bootstrap-touchspin-prefix\" style=\"display: none;\"></span><input class=\"form-control\" id=\"$id\" type=\"text\" value=\"13\" placeholder=\"place\" name=\"name\" disabled=\"disabled\" style=\"display: block;\"><span class=\"input-group-addon bootstrap-touchspin-postfix\" style=\"display: none;\"></span><span class=\"input-group-btn-vertical\"><button class=\"btn btn-default bootstrap-touchspin-up\" type=\"button\"><i class=\"glyphicon glyphicon-chevron-up\"></i></button><button class=\"btn btn-default bootstrap-touchspin-down\" type=\"button\"><i class=\"glyphicon glyphicon-chevron-down\"></i></button></span></div></span></div></div>", + element?.innerHTML, + "Should render correct spinner input form control" + ) + ti.validatorError = "Validation Error" + assertEqualsHtml( + "<div class=\"form-group has-error\"><label class=\"control-label\" for=\"$id\">Label</label><div class=\"input-group kv-spinner-btn-vertical\"><span><div class=\"input-group bootstrap-touchspin\"><span class=\"input-group-addon bootstrap-touchspin-prefix\" style=\"display: none;\"></span><input class=\"form-control\" id=\"$id\" type=\"text\" value=\"13\" placeholder=\"place\" name=\"name\" disabled=\"disabled\" style=\"display: block;\"><span class=\"input-group-addon bootstrap-touchspin-postfix\" style=\"display: none;\"></span><span class=\"input-group-btn-vertical\"><button class=\"btn btn-default bootstrap-touchspin-up\" type=\"button\"><i class=\"glyphicon glyphicon-chevron-up\"></i></button><button class=\"btn btn-default bootstrap-touchspin-down\" type=\"button\"><i class=\"glyphicon glyphicon-chevron-down\"></i></button></span></div></span></div><span class=\"help-block small\">Validation Error</span></div>", + element?.innerHTML, + "Should render correct spinner input form control with validation error" + ) + } + } + + @Test + fun spinUp() { + run { + val root = Root("test", true) + val si = Spinner(value = 13) + root.add(si) + assertEquals(13, si.value, "Should return initial value before spinUp") + si.spinUp() + assertEquals(14, si.value, "Should return changed value after spinUp") + } + } + + @Test + fun spinDown() { + run { + val root = Root("test", true) + val si = Spinner(value = 13) + root.add(si) + assertEquals(13, si.value, "Should return initial value before spinDown") + si.spinDown() + assertEquals(12, si.value, "Should return changed value after spinDown") + } + } +}
\ No newline at end of file diff --git a/kvision-modules/kvision-upload/build.gradle b/kvision-modules/kvision-upload/build.gradle new file mode 100644 index 00000000..e45b9a3b --- /dev/null +++ b/kvision-modules/kvision-upload/build.gradle @@ -0,0 +1,9 @@ +apply from: "../shared.gradle" + +kotlinFrontend { + + npm { + dependency("bootstrap-fileinput", "4.4.7") + } + +} diff --git a/kvision-modules/kvision-upload/package.json.d/project.info b/kvision-modules/kvision-upload/package.json.d/project.info new file mode 100644 index 00000000..d789d81b --- /dev/null +++ b/kvision-modules/kvision-upload/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Upload module" +} diff --git a/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/KVManagerUpload.kt b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/KVManagerUpload.kt new file mode 100644 index 00000000..64a25545 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/KVManagerUpload.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision + +internal val KVManagerUploadInit = KVManagerUpload.init() + +/** + * Internal singleton object which initializes and configures KVision upload module. + */ +@Suppress("EmptyCatchBlock", "TooGenericExceptionCaught") +internal object KVManagerUpload { + fun init() {} + + 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/locales/bootstrap-fileinput/ar.js") + require("./js/locales/bootstrap-fileinput/az.js") + require("./js/locales/bootstrap-fileinput/bg.js") + require("./js/locales/bootstrap-fileinput/ca.js") + require("./js/locales/bootstrap-fileinput/cr.js") + require("./js/locales/bootstrap-fileinput/cs.js") + require("./js/locales/bootstrap-fileinput/da.js") + require("./js/locales/bootstrap-fileinput/de.js") + require("./js/locales/bootstrap-fileinput/el.js") + require("./js/locales/bootstrap-fileinput/es.js") + require("./js/locales/bootstrap-fileinput/et.js") + require("./js/locales/bootstrap-fileinput/fa.js") + require("./js/locales/bootstrap-fileinput/fi.js") + require("./js/locales/bootstrap-fileinput/fr.js") + require("./js/locales/bootstrap-fileinput/gl.js") + require("./js/locales/bootstrap-fileinput/id.js") + require("./js/locales/bootstrap-fileinput/it.js") + require("./js/locales/bootstrap-fileinput/ja.js") + require("./js/locales/bootstrap-fileinput/ka.js") + require("./js/locales/bootstrap-fileinput/ko.js") + require("./js/locales/bootstrap-fileinput/kz.js") + require("./js/locales/bootstrap-fileinput/lt.js") + require("./js/locales/bootstrap-fileinput/nl.js") + require("./js/locales/bootstrap-fileinput/no.js") + require("./js/locales/bootstrap-fileinput/pl.js") + require("./js/locales/bootstrap-fileinput/pt.js") + require("./js/locales/bootstrap-fileinput/ro.js") + require("./js/locales/bootstrap-fileinput/ru.js") + require("./js/locales/bootstrap-fileinput/sk.js") + require("./js/locales/bootstrap-fileinput/sl.js") + require("./js/locales/bootstrap-fileinput/sv.js") + require("./js/locales/bootstrap-fileinput/th.js") + require("./js/locales/bootstrap-fileinput/tr.js") + require("./js/locales/bootstrap-fileinput/uk.js") + require("./js/locales/bootstrap-fileinput/vi.js") + require("./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) { + } + +} diff --git a/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt new file mode 100644 index 00000000..314c9904 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/Upload.kt @@ -0,0 +1,333 @@ +/* + * 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/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt new file mode 100644 index 00000000..51b73aa1 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/kotlin/pl/treksoft/kvision/form/upload/UploadInput.kt @@ -0,0 +1,364 @@ +/* + * 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.Form +import pl.treksoft.kvision.form.FormInput +import pl.treksoft.kvision.form.FormPanel +import pl.treksoft.kvision.form.InputSize +import pl.treksoft.kvision.i18n.I18n +import pl.treksoft.kvision.types.KFile +import pl.treksoft.kvision.utils.getContent +import pl.treksoft.kvision.utils.obj +import kotlin.reflect.KProperty1 + +/** + * 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 + } + + /** + * 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 <K : Any> Form<K>.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 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 <K : Any> FormPanel<K>.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) + } + } +} diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ar.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ar.js new file mode 100644 index 00000000..92d32d28 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ar.js @@ -0,0 +1,101 @@ +/*! + * FileInput Arabic Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Yasser Lotfy <y_l@live.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['ar'] = { + fileSingle: 'ملف', + filePlural: 'ملفات', + browseLabel: 'تصفح …', + removeLabel: 'إزالة', + removeTitle: 'إزالة الملفات المختارة', + cancelLabel: 'إلغاء', + cancelTitle: 'إنهاء الرفع الحالي', + uploadLabel: 'رفع', + uploadTitle: 'رفع الملفات المختارة', + msgNo: 'لا', + msgNoFilesSelected: '', + msgCancelled: 'ألغيت', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'معاينة تفصيلية', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'الملف "{name}" (<b>{size} ك.ب</b>) تعدى الحد الأقصى المسموح للرفع <b>{maxSize} ك.ب</b>.', + msgFilesTooLess: 'يجب عليك اختيار <b>{n}</b> {files} على الأقل للرفع.', + msgFilesTooMany: 'عدد الملفات المختارة للرفع <b>({n})</b> تعدت الحد الأقصى المسموح به لعدد <b>{m}</b>.', + msgFileNotFound: 'الملف "{name}" غير موجود!', + msgFileSecured: 'قيود أمنية تمنع قراءة الملف "{name}".', + msgFileNotReadable: 'الملف "{name}" غير قابل للقراءة.', + msgFilePreviewAborted: 'تم إلغاء معاينة الملف "{name}".', + msgFilePreviewError: 'حدث خطأ أثناء قراءة الملف "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'نوعية غير صالحة للملف "{name}". فقط هذه النوعيات مدعومة "{types}".', + msgInvalidFileExtension: 'امتداد غير صالح للملف "{name}". فقط هذه الملفات مدعومة "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'تم إلغاء رفع الملف', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'خطأ التحقق من صحة', + msgLoading: 'تحميل ملف {index} من {files} …', + msgProgress: 'تحميل ملف {index} من {files} - {name} - {percent}% منتهي.', + msgSelected: '{n} {files} مختار(ة)', + msgFoldersNotAllowed: 'اسحب وأفلت الملفات فقط! تم تخطي {n} مجلد(ات).', + msgImageWidthSmall: 'عرض ملف الصورة "{name}" يجب أن يكون على الأقل {size} px.', + msgImageHeightSmall: 'طول ملف الصورة "{name}" يجب أن يكون على الأقل {size} px.', + msgImageWidthLarge: 'عرض ملف الصورة "{name}" لا يمكن أن يتعدى {size} px.', + msgImageHeightLarge: 'طول ملف الصورة "{name}" لا يمكن أن يتعدى {size} px.', + msgImageResizeError: 'لم يتمكن من معرفة أبعاد الصورة لتغييرها.', + msgImageResizeException: 'حدث خطأ أثناء تغيير أبعاد الصورة.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'اسحب وأفلت الملفات هنا …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'إزالة الملف', + uploadTitle: 'رفع الملف', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'مشاهدة التفاصيل', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'لم يتم الرفع بعد', + indicatorSuccessTitle: 'تم الرفع', + indicatorErrorTitle: 'خطأ بالرفع', + indicatorLoadingTitle: 'جارٍ الرفع ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/az.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/az.js new file mode 100644 index 00000000..5a9c6440 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/az.js @@ -0,0 +1,101 @@ +/*! + * FileInput Azerbaijan Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Elbrus <elbrusnt@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['az'] = { + fileSingle: 'fayl', + filePlural: 'fayl', + browseLabel: 'Seç …', + removeLabel: 'Sil', + removeTitle: 'Seçilmiş faylları təmizlə', + cancelLabel: 'İmtina et', + cancelTitle: 'Cari yükləməni dayandır', + uploadLabel: 'Yüklə', + uploadTitle: 'Seçilmiş faylları yüklə', + msgNo: 'xeyir', + msgNoFilesSelected: 'Heç bir fayl seçilməmişdir', + msgCancelled: 'İmtina edildi', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'İlkin baxış', + msgFileRequired: 'Yükləmə üçün fayl seçməlisiniz.', + msgSizeTooSmall: 'Seçdiyiniz "{name}" faylının həcmi (<b>{size} KB</b>)-dır, minimum <b>{minSize} KB</b> olmalıdır.', + msgSizeTooLarge: 'Seçdiyiniz "{name}" faylının həcmi (<b>{size} KB</b>)-dır, maksimum <b>{maxSize} KB</b> olmalıdır.', + msgFilesTooLess: 'Yükləmə üçün minimum <b>{n}</b> {files} seçməlisiniz.', + msgFilesTooMany: 'Seçilmiş fayl sayı <b>({n})</b>. Maksimum <b>{m}</b> fayl seçmək mümkündür.', + msgFileNotFound: 'Fayl "{name}" tapılmadı!', + msgFileSecured: '"{name}" faylının istifadəsinə yetginiz yoxdur.', + msgFileNotReadable: '"{name}" faylının istifadəsi mümkün deyil.', + msgFilePreviewAborted: '"{name}" faylı üçün ilkin baxış ləğv olunub.', + msgFilePreviewError: '"{name}" faylının oxunması mümkün olmadı.', + msgInvalidFileName: '"{name}" faylının adında qadağan olunmuş simvollardan istifadə olunmuşdur.', + msgInvalidFileType: '"{name}" faylının tipi dəstəklənmir. Yalnız "{types}" tipli faylları yükləmək mümkündür.', + msgInvalidFileExtension: '"{name}" faylının genişlənməsi yanlışdır. Yalnız "{extensions}" fayl genişlənmə(si / ləri) qəbul olunur.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Yükləmə dayandırılmışdır', + msgUploadThreshold: 'Yükləmə...', + msgUploadBegin: 'Yoxlama...', + msgUploadEnd: 'Fayl(lar) yükləndi', + msgUploadEmpty: 'Yükləmə üçün verilmiş məlumatlar yanlışdır', + msgUploadError: 'Error', + msgValidationError: 'Yoxlama nəticəsi səhvir', + msgLoading: '{files} fayldan {index} yüklənir …', + msgProgress: '{files} fayldan {index} - {name} - {percent}% yükləndi.', + msgSelected: 'Faylların sayı: {n}', + msgFoldersNotAllowed: 'Ancaq faylların daşınmasına icazə verilir! {n} qovluq yüklənmədi.', + msgImageWidthSmall: '{name} faylının eni {size} px -dən kiçik olmamalıdır.', + msgImageHeightSmall: '{name} faylının hündürlüyü {size} px -dən kiçik olmamalıdır.', + msgImageWidthLarge: '"{name}" faylının eni {size} px -dən böyük olmamalıdır.', + msgImageHeightLarge: '"{name}" faylının hündürlüyü {size} px -dən böyük olmamalıdır.', + msgImageResizeError: 'Faylın ölçülərini dəyişmək üçün ölçüləri hesablamaq mümkün olmadı.', + msgImageResizeException: 'Faylın ölçülərini dəyişmək mümkün olmadı.<pre>{errors}</pre>', + msgAjaxError: '{operation} əməliyyatı zamanı səhv baş verdi. Təkrar yoxlayın!', + msgAjaxProgressError: '{operation} əməliyyatı yerinə yetirmək mümkün olmadı.', + ajaxOperations: { + deleteThumb: 'faylı sil', + uploadThumb: 'faylı yüklə', + uploadBatch: 'bir neçə faylı yüklə', + uploadExtra: 'məlumatların yüklənməsi' + }, + dropZoneTitle: 'Faylları bura daşıyın …', + dropZoneClickTitle: '<br>(Və ya seçin {files})', + fileActionSettings: { + removeTitle: 'Faylı sil', + uploadTitle: 'Faylı yüklə', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'məlumatlara bax', + dragTitle: 'Yerini dəyiş və ya sırala', + indicatorNewTitle: 'Davam edir', + indicatorSuccessTitle: 'Tamamlandı', + indicatorErrorTitle: 'Yükləmə xətası', + indicatorLoadingTitle: 'Yükləmə ...' + }, + previewZoomButtonTitles: { + prev: 'Əvvəlki fayla bax', + next: 'Növbəti fayla bax', + toggleheader: 'Başlığı dəyiş', + fullscreen: 'Tam ekranı dəyiş', + borderless: 'Bölmələrsiz rejimi dəyiş', + close: 'Ətraflı baxışı bağla' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/bg.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/bg.js new file mode 100644 index 00000000..cf75d1ab --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/bg.js @@ -0,0 +1,100 @@ +/*! + * FileInput Bulgarian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['bg'] = { + fileSingle: 'файл', + filePlural: 'файла', + browseLabel: 'Избери …', + removeLabel: 'Премахни', + removeTitle: 'Изчисти избраните', + cancelLabel: 'Откажи', + cancelTitle: 'Откажи качването', + uploadLabel: 'Качи', + uploadTitle: 'Качи избраните файлове', + msgNo: 'Не', + msgNoFilesSelected: '', + msgCancelled: 'Отменен', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Детайлен преглед', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Файла "{name}" (<b>{size} KB</b>) надвишава максималните разрешени <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Трябва да изберете поне <b>{n}</b> {files} файла.', + msgFilesTooMany: 'Броя файлове избрани за качване <b>({n})</b> надвишава ограниченито от максимум <b>{m}</b>.', + msgFileNotFound: 'Файлът "{name}" не може да бъде намерен!', + msgFileSecured: 'От съображения за сигурност не може да прочетем файла "{name}".', + msgFileNotReadable: 'Файлът "{name}" не е четим.', + msgFilePreviewAborted: 'Прегледа на файла е прекратен за "{name}".', + msgFilePreviewError: 'Грешка при опит за четене на файла "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Невалиден тип на файла "{name}". Разрешени са само "{types}".', + msgInvalidFileExtension: 'Невалидно разрешение на "{name}". Разрешени са само "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Качите файла, бе прекратена', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'утвърждаване грешка', + msgLoading: 'Зареждане на файл {index} от общо {files} …', + msgProgress: 'Зареждане на файл {index} от общо {files} - {name} - {percent}% завършени.', + msgSelected: '{n} {files} избрани', + msgFoldersNotAllowed: 'Само пуснати файлове! Пропуснати {n} пуснати папки.', + msgImageWidthSmall: 'Широчината на изображението "{name}" трябва да е поне {size} px.', + msgImageHeightSmall: 'Височината на изображението "{name}" трябва да е поне {size} px.', + msgImageWidthLarge: 'Широчината на изображението "{name}" не може да е по-голяма от {size} px.', + msgImageHeightLarge: 'Височината на изображението "{name}" нее може да е по-голяма от {size} px.', + msgImageResizeError: 'Не може да размерите на изображението, за да промените размера.', + msgImageResizeException: 'Грешка при промяна на размера на изображението.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Пуснете файловете тук …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Махни файл', + uploadTitle: 'Качване на файл', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Вижте детайли', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Все още не е качил', + indicatorSuccessTitle: 'Качено', + indicatorErrorTitle: 'Качи Error', + indicatorLoadingTitle: 'Качва се ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ca.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ca.js new file mode 100644 index 00000000..16514535 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ca.js @@ -0,0 +1,100 @@ +/*! + * FileInput Català Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['ca'] = { + fileSingle: 'arxiu', + filePlural: 'arxius', + browseLabel: 'Examinar …', + removeLabel: 'Treure', + removeTitle: 'Treure arxius seleccionats', + cancelLabel: 'Cancel', + cancelTitle: 'Avortar la pujada en curs', + uploadLabel: 'Pujar arxiu', + uploadTitle: 'Pujar arxius seleccionats', + msgNo: 'No', + msgNoFilesSelected: '', + msgCancelled: 'cancel·lat', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Vista prèvia detallada', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Arxiu "{name}" (<b>{size} KB</b>) excedeix la mida màxima permès de <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Heu de seleccionar almenys <b>{n}</b> {files} a carregar.', + msgFilesTooMany: 'El nombre d\'arxius seleccionats a carregar <b>({n})</b> excedeix el límit màxim permès de <b>{m}</b>.', + msgFileNotFound: 'Arxiu "{name}" no trobat.', + msgFileSecured: 'No es pot accedir a l\'arxiu "{name}" perquè estarà sent usat per una altra aplicació o no tinguem permisos de lectura.', + msgFileNotReadable: 'No es pot accedir a l\'arxiu "{name}".', + msgFilePreviewAborted: 'Previsualització de l\'arxiu "{name}" cancel·lada.', + msgFilePreviewError: 'S\'ha produït un error mentre es llegia el fitxer "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Tipus de fitxer no vàlid per a "{name}". Només arxius "{types}" són permesos.', + msgInvalidFileExtension: 'Extensió de fitxer no vàlid per a "{name}". Només arxius "{extensions}" són permesos.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'La càrrega d\'arxius s\'ha cancel·lat', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Error de validació', + msgLoading: 'Pujant fitxer {index} de {files} …', + msgProgress: 'Pujant fitxer {index} de {files} - {name} - {percent}% completat.', + msgSelected: '{n} {files} seleccionat(s)', + msgFoldersNotAllowed: 'Arrossegueu i deixeu anar únicament arxius. Omesa(es) {n} carpeta(es).', + msgImageWidthSmall: 'L\'ample de la imatge "{name}" ha de ser almenys {size} px.', + msgImageHeightSmall: 'L\'alçada de la imatge "{name}" ha de ser almenys {size} px.', + msgImageWidthLarge: 'L\'ample de la imatge "{name}" no pot excedir de {size} px.', + msgImageHeightLarge: 'L\'alçada de la imatge "{name}" no pot excedir de {size} px.', + msgImageResizeError: 'No s\'ha pogut obtenir les dimensions d\'imatge per canviar la mida.', + msgImageResizeException: 'Error en canviar la mida de la imatge.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Arrossegueu i deixeu anar aquí els arxius …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Eliminar arxiu', + uploadTitle: 'Pujar arxiu', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Veure detalls', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'No pujat encara', + indicatorSuccessTitle: 'Subido', + indicatorErrorTitle: 'Pujar Error', + indicatorLoadingTitle: 'Pujant ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/cr.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/cr.js new file mode 100644 index 00000000..685da85d --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/cr.js @@ -0,0 +1,101 @@ +/*! + * FileInput Croatian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Milos Stojanovic <stojanovic.loshmi@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['cr'] = { + fileSingle: 'datoteka', + filePlural: 'datoteke', + browseLabel: 'Izaberi …', + removeLabel: 'Ukloni', + removeTitle: 'Ukloni označene datoteke', + cancelLabel: 'Odustani', + cancelTitle: 'Prekini trenutno otpremanje', + uploadLabel: 'Otpremi', + uploadTitle: 'Otpremi označene datoteke', + msgNo: 'Ne', + msgNoFilesSelected: '', + msgCancelled: 'Otkazan', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Detaljni pregled', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Datoteka "{name}" (<b>{size} KB</b>) prekoračuje maksimalnu dozvoljenu veličinu datoteke od <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Morate odabrati najmanje <b>{n}</b> {files} za otpremanje.', + msgFilesTooMany: 'Broj datoteka označenih za otpremanje <b>({n})</b> prekoračuje maksimalni dozvoljeni limit od <b>{m}</b>.', + msgFileNotFound: 'Datoteka "{name}" nije pronađena!', + msgFileSecured: 'Datoteku "{name}" nije moguće pročitati zbog bezbednosnih ograničenja.', + msgFileNotReadable: 'Datoteku "{name}" nije moguće pročitati.', + msgFilePreviewAborted: 'Generisanje prikaza nije moguće za "{name}".', + msgFilePreviewError: 'Došlo je do greške prilikom čitanja datoteke "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Datoteka "{name}" je pogrešnog formata. Dozvoljeni formati su "{types}".', + msgInvalidFileExtension: 'Ekstenzija datoteke "{name}" nije dozvoljena. Dozvoljene ekstenzije su "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Prijenos datoteka je prekinut', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Provjera pogrešaka', + msgLoading: 'Učitavanje datoteke {index} od {files} …', + msgProgress: 'Učitavanje datoteke {index} od {files} - {name} - {percent}% završeno.', + msgSelected: '{n} {files} je označeno', + msgFoldersNotAllowed: 'Moguće je prevlačiti samo datoteke! Preskočeno je {n} fascikla.', + msgImageWidthSmall: 'Širina slikovnu datoteku "{name}" moraju biti najmanje {size} px.', + msgImageHeightSmall: 'Visina slikovnu datoteku "{name}" moraju biti najmanje {size} px.', + msgImageWidthLarge: 'Širina slikovnu datoteku "{name}" ne može prelaziti {size} px.', + msgImageHeightLarge: 'Visina slikovnu datoteku "{name}" ne može prelaziti {size} px.', + msgImageResizeError: 'Nije mogao dobiti dimenzije slike na veličinu.', + msgImageResizeException: 'Greška prilikom promjene veličine slike.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Prevucite datoteke ovde …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Uklonite datoteku', + uploadTitle: 'Postavi datoteku', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Pregledavati pojedinosti', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Još nije učitao', + indicatorSuccessTitle: 'Preneseno', + indicatorErrorTitle: 'Postavi Greška', + indicatorLoadingTitle: 'Prijenos ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/cs.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/cs.js new file mode 100644 index 00000000..f5e8b723 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/cs.js @@ -0,0 +1,100 @@ +/*! + * FileInput Czech Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['cs'] = { + fileSingle: 'soubor', + filePlural: 'soubory', + browseLabel: 'Vybrat …', + removeLabel: 'Odstranit', + removeTitle: 'Vyčistit vybrané soubory', + cancelLabel: 'Storno', + cancelTitle: 'Přerušit nahrávání', + uploadLabel: 'Nahrát', + uploadTitle: 'Nahrát vybrané soubory', + msgNo: 'Ne', + msgNoFilesSelected: 'Nevybrány žádné soubory', + msgCancelled: 'Zrušeno', + msgPlaceholder: 'Vybrat {files}...', + msgZoomModalHeading: 'Detailní náhled', + msgFileRequired: 'Musíte vybrat soubor, který chcete nahrát.', + msgSizeTooSmall: 'Soubor "{name}" (<b>{size} KB</b>) je příliš malý, musí mít velikost nejméně <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Soubor "{name}" (<b>{size} KB</b>) je příliš velký, maximální povolená velikost <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Musíte vybrat nejméně <b>{n}</b> {files} souborů.', + msgFilesTooMany: 'Počet vybraných souborů <b>({n})</b> překročil maximální povolený limit <b>{m}</b>.', + msgFileNotFound: 'Soubor "{name}" nebyl nalezen!', + msgFileSecured: 'Zabezpečení souboru znemožnilo číst soubor "{name}".', + msgFileNotReadable: 'Soubor "{name}" není čitelný.', + msgFilePreviewAborted: 'Náhled souboru byl přerušen pro "{name}".', + msgFilePreviewError: 'Nastala chyba při načtení souboru "{name}".', + msgInvalidFileName: 'Neplatné nebo nepovolené znaky ve jménu souboru "{name}".', + msgInvalidFileType: 'Neplatný typ souboru "{name}". Pouze "{types}" souborů jsou podporovány.', + msgInvalidFileExtension: 'Neplatná extenze souboru "{name}". Pouze "{extensions}" souborů jsou podporovány.', + msgFileTypes: { + 'image': 'obrázek', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Nahrávání souboru bylo přerušeno', + msgUploadThreshold: 'Zpracovávám...', + msgUploadBegin: 'Inicializujem...', + msgUploadEnd: 'Hotovo', + msgUploadEmpty: 'Pro nahrávání nejsou k dispozici žádné platné údaje.', + msgUploadError: 'Chyba', + msgValidationError: 'Chyba ověření', + msgLoading: 'Nahrávání souboru {index} z {files} …', + msgProgress: 'Nahrávání souboru {index} z {files} - {name} - {percent}% dokončeno.', + msgSelected: '{n} {files} vybráno', + msgFoldersNotAllowed: 'Táhni a pusť pouze soubory! Vynechané {n} pustěné složk(y).', + msgImageWidthSmall: 'Šířka obrázku "{name}", musí být alespoň {size} px.', + msgImageHeightSmall: 'Výška obrázku "{name}", musí být alespoň {size} px.', + msgImageWidthLarge: 'Šířka obrázku "{name}" nesmí být větší než {size} px.', + msgImageHeightLarge: 'Výška obrázku "{name}" nesmí být větší než {size} px.', + msgImageResizeError: 'Nelze získat rozměry obrázku pro změnu velikosti.', + msgImageResizeException: 'Chyba při změně velikosti obrázku.<pre>{errors}</pre>', + msgAjaxError: 'Došlo k chybě v {operation}. Prosím zkuste to znovu později!', + msgAjaxProgressError: '{operation} - neúspěšné', + ajaxOperations: { + deleteThumb: 'odstranit soubor', + uploadThumb: 'nahrát soubor', + uploadBatch: 'nahrát várku souborů', + uploadExtra: 'odesílání dat formuláře' + }, + dropZoneTitle: 'Přetáhni soubory sem …', + dropZoneClickTitle: '<br>(nebo klikni sem a vyber je)', + fileActionSettings: { + removeTitle: 'Odstranit soubor', + uploadTitle: 'Nahrát soubor', + uploadRetryTitle: 'Opakovat nahrávání', + downloadTitle: 'Stáhnout soubor', + zoomTitle: 'Zobrazit podrobnosti', + dragTitle: 'Posunout / Přeskládat', + indicatorNewTitle: 'Ještě nenahrál', + indicatorSuccessTitle: 'Nahraný', + indicatorErrorTitle: 'Chyba nahrávání', + indicatorLoadingTitle: 'Nahrávání ...' + }, + previewZoomButtonTitles: { + prev: 'Zobrazit předchozí soubor', + next: 'Zobrazit následující soubor', + toggleheader: 'Přepnout záhlaví', + fullscreen: 'Přepnout celoobrazovkové zobrazení', + borderless: 'Přepnout bezrámečkové zobrazení', + close: 'Zavřít detailní náhled' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/da.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/da.js new file mode 100644 index 00000000..613defec --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/da.js @@ -0,0 +1,100 @@ +/*! + * FileInput Danish Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['da'] = { + fileSingle: 'fil', + filePlural: 'filer', + browseLabel: 'Browse …', + removeLabel: 'Fjern', + removeTitle: 'Fjern valgte filer', + cancelLabel: 'Fortryd', + cancelTitle: 'Afbryd nuværende upload', + uploadLabel: 'Upload', + uploadTitle: 'Upload valgte filer', + msgNo: 'Ingen', + msgNoFilesSelected: '', + msgCancelled: 'aflyst', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Detaljeret visning', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Fil "{name}" (<b>{size} KB</b>) er større end de tilladte <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Du skal mindst vælge <b>{n}</b> {files} til upload.', + msgFilesTooMany: '<b>({n})</b> filer valgt til upload, men maks. <b>{m}</b> er tilladt.', + msgFileNotFound: 'Filen "{name}" blev ikke fundet!', + msgFileSecured: 'Sikkerhedsrestriktioner forhindrer læsning af "{name}".', + msgFileNotReadable: 'Filen "{name}" kan ikke indlæses.', + msgFilePreviewAborted: 'Filpreview annulleret for "{name}".', + msgFilePreviewError: 'Der skete en fejl under læsningen af filen "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Ukendt type for filen "{name}". Kun "{types}" kan bruges.', + msgInvalidFileExtension: 'Ukendt filtype for filen "{name}". Kun "{extensions}" filer kan bruges.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Filupload annulleret', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Validering Fejl', + msgLoading: 'Henter fil {index} af {files} …', + msgProgress: 'Henter fil {index} af {files} - {name} - {percent}% færdiggjort.', + msgSelected: '{n} {files} valgt', + msgFoldersNotAllowed: 'Drag & drop kun filer! {n} mappe(r) sprunget over.', + msgImageWidthSmall: 'Bredden af billedet "{name}" skal være på mindst {size} px.', + msgImageHeightSmall: 'Højden af billedet "{name}" skal være på mindst {size} px.', + msgImageWidthLarge: 'Bredden af billedet "{name}" må ikke være over {size} px.', + msgImageHeightLarge: 'Højden af billedet "{name}" må ikke være over {size} px.', + msgImageResizeError: 'Kunne ikke få billedets dimensioner for at ændre størrelsen.', + msgImageResizeException: 'Fejl ved at ændre størrelsen på billedet.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Drag & drop filer her …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Fjern fil', + uploadTitle: 'Upload fil', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Se detaljer', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Ikke uploadet endnu', + indicatorSuccessTitle: 'Uploadet', + indicatorErrorTitle: 'Upload fejl', + indicatorLoadingTitle: 'Uploader ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery);
\ No newline at end of file diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/de.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/de.js new file mode 100644 index 00000000..56ee854b --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/de.js @@ -0,0 +1,98 @@ +/*! + * FileInput German Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['de'] = { + fileSingle: 'Datei', + filePlural: 'Dateien', + browseLabel: 'Auswählen …', + removeLabel: 'Löschen', + removeTitle: 'Ausgewählte löschen', + cancelLabel: 'Abbrechen', + cancelTitle: 'Hochladen abbrechen', + uploadLabel: 'Hochladen', + uploadTitle: 'Hochladen der ausgewählten Dateien', + msgNo: 'Keine', + msgNoFilesSelected: 'Keine Dateien ausgewählt', + msgCancelled: 'Abgebrochen', + msgPlaceholder: '{files} auswählen...', + msgZoomModalHeading: 'ausführliche Vorschau', + msgFileRequired: 'Sie müssen eine Datei zum Hochladen auswählen.', + msgSizeTooSmall: 'Datei "{name}" (<b>{size} KB</b>) unterschreitet mindestens notwendige Upload-Größe von <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Datei "{name}" (<b>{size} KB</b>) überschreitet maximal zulässige Upload-Größe von <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Sie müssen mindestens <b>{n}</b> {files} zum Hochladen auswählen.', + msgFilesTooMany: 'Anzahl der zum Hochladen ausgewählten Dateien <b>({n})</b>, überschreitet maximal zulässige Grenze von <b>{m}</b> Stück.', + msgFileNotFound: 'Datei "{name}" wurde nicht gefunden!', + msgFileSecured: 'Sicherheitseinstellungen verhindern das Lesen der Datei "{name}".', + msgFileNotReadable: 'Die Datei "{name}" ist nicht lesbar.', + msgFilePreviewAborted: 'Dateivorschau abgebrochen für "{name}".', + msgFilePreviewError: 'Beim Lesen der Datei "{name}" ein Fehler aufgetreten.', + msgInvalidFileName: 'Ungültige oder nicht unterstützte Zeichen im Dateinamen "{name}".', + msgInvalidFileType: 'Ungültiger Typ für Datei "{name}". Nur Dateien der Typen "{types}" werden unterstützt.', + msgInvalidFileExtension: 'Ungültige Erweiterung für Datei "{name}". Nur Dateien mit der Endung "{extensions}" werden unterstützt.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Der Datei-Upload wurde abgebrochen', + msgUploadThreshold: 'Wird bearbeitet ...', + msgUploadBegin: 'Wird initialisiert ...', + msgUploadEnd: 'Erledigt', + msgUploadEmpty: 'Keine gültigen Daten zum Hochladen verfügbar.', + msgUploadError: 'Fehler', + msgValidationError: 'Validierungsfehler', + msgLoading: 'Lade Datei {index} von {files} hoch…', + msgProgress: 'Datei {index} von {files} - {name} - zu {percent}% fertiggestellt.', + msgSelected: '{n} {files} ausgewählt', + msgFoldersNotAllowed: 'Drag & Drop funktioniert nur bei Dateien! {n} Ordner übersprungen.', + msgImageWidthSmall: 'Breite der Bilddatei "{name}" muss mindestens {size} px betragen.', + msgImageHeightSmall: 'Höhe der Bilddatei "{name}" muss mindestens {size} px betragen.', + msgImageWidthLarge: 'Breite der Bilddatei "{name}" nicht überschreiten {size} px.', + msgImageHeightLarge: 'Höhe der Bilddatei "{name}" nicht überschreiten {size} px.', + msgImageResizeError: 'Konnte nicht die Bildabmessungen zu ändern.', + msgImageResizeException: 'Fehler beim Ändern der Größe des Bildes.<pre>{errors}</pre>', + msgAjaxError: 'Bei der Aktion {operation} ist ein Fehler aufgetreten. Bitte versuche es später noch einmal!', + msgAjaxProgressError: '{operation} fehlgeschlagen', + ajaxOperations: { + deleteThumb: 'Datei löschen', + uploadThumb: 'Datei hochladen', + uploadBatch: 'Batch-Datei-Upload', + uploadExtra: 'Formular-Datei-Upload' + }, + dropZoneTitle: 'Dateien hierher ziehen …', + dropZoneClickTitle: '<br>(oder klicken um {files} auszuwählen)', + fileActionSettings: { + removeTitle: 'Datei entfernen', + uploadTitle: 'Datei hochladen', + uploadRetryTitle: 'Upload erneut versuchen', + downloadTitle: 'Datei herunterladen', + zoomTitle: 'Details anzeigen', + dragTitle: 'Verschieben / Neuordnen', + indicatorNewTitle: 'Noch nicht hochgeladen', + indicatorSuccessTitle: 'Hochgeladen', + indicatorErrorTitle: 'Upload Fehler', + indicatorLoadingTitle: 'Hochladen ...' + }, + previewZoomButtonTitles: { + prev: 'Vorherige Datei anzeigen', + next: 'Nächste Datei anzeigen', + toggleheader: 'Header umschalten', + fullscreen: 'Vollbildmodus umschalten', + borderless: 'Randlosen Modus umschalten', + close: 'Detailansicht schließen' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/el.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/el.js new file mode 100644 index 00000000..170eba1f --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/el.js @@ -0,0 +1,100 @@ +/*! + * FileInput Greek Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['el'] = { + fileSingle: 'αρχείο', + filePlural: 'αρχεία', + browseLabel: 'Αναζήτηση …', + removeLabel: 'Διαγραφή', + removeTitle: 'Εκκαθάριση αρχείων', + cancelLabel: 'Ακύρωση', + cancelTitle: 'Ακύρωση μεταφόρτωσης', + uploadLabel: 'Μεταφόρτωση', + uploadTitle: 'Μεταφόρτωση επιλεγμένων αρχείων', + msgNo: 'Όχι', + msgNoFilesSelected: 'Δεν επιλέχθηκαν αρχεία', + msgCancelled: 'Ακυρώθηκε', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Λεπτομερής Προεπισκόπηση', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'Το "{name}" (<b>{size} KB</b>) είναι πολύ μικρό, πρέπει να είναι μεγαλύτερο από <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Το αρχείο "{name}" (<b>{size} KB</b>) υπερβαίνει το μέγιστο επιτρεπόμενο μέγεθος μεταφόρτωσης <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Πρέπει να επιλέξετε τουλάχιστον <b>{n}</b> {files} για να ξεκινήσει η μεταφόρτωση.', + msgFilesTooMany: 'Ο αριθμός των αρχείων που έχουν επιλεγεί για μεταφόρτωση <b>({n})</b> υπερβαίνει το μέγιστο επιτρεπόμενο αριθμό <b>{m}</b>.', + msgFileNotFound: 'Το αρχείο "{name}" δεν βρέθηκε!', + msgFileSecured: 'Περιορισμοί ασφαλείας εμπόδισαν την ανάγνωση του αρχείου "{name}".', + msgFileNotReadable: 'Το αρχείο "{name}" δεν είναι αναγνώσιμο.', + msgFilePreviewAborted: 'Η προεπισκόπηση του αρχείου "{name}" ακυρώθηκε.', + msgFilePreviewError: 'Παρουσιάστηκε σφάλμα κατά την ανάγνωση του αρχείου "{name}".', + msgInvalidFileName: 'Μη έγκυροι χαρακτήρες στο όνομα του αρχείου "{name}".', + msgInvalidFileType: 'Μη έγκυρος ο τύπος του αρχείου "{name}". Οι τύποι αρχείων που υποστηρίζονται είναι : "{types}".', + msgInvalidFileExtension: 'Μη έγκυρη η επέκταση του αρχείου "{name}". Οι επεκτάσεις που υποστηρίζονται είναι : "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Η μεταφόρτωση του αρχείου ματαιώθηκε', + msgUploadThreshold: 'Μεταφόρτωση ...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Σφάλμα Επικύρωσης', + msgLoading: 'Φόρτωση αρχείου {index} από {files} …', + msgProgress: 'Φόρτωση αρχείου {index} απο {files} - {name} - {percent}% ολοκληρώθηκε.', + msgSelected: '{n} {files} επιλέχθηκαν', + msgFoldersNotAllowed: 'Μπορείτε να σύρετε μόνο αρχεία! Παραβλέφθηκαν {n} φάκελος(οι).', + msgImageWidthSmall: 'Το πλάτος του αρχείου εικόνας "{name}" πρέπει να είναι τουλάχιστον {size} px.', + msgImageHeightSmall: 'Το ύψος του αρχείου εικόνας "{name}" πρέπει να είναι τουλάχιστον {size} px.', + msgImageWidthLarge: 'Το πλάτος του αρχείου εικόνας "{name}" δεν μπορεί να υπερβαίνει το {size} px.', + msgImageHeightLarge: 'Το ύψος του αρχείου εικόνας "{name}" δεν μπορεί να υπερβαίνει το {size} px.', + msgImageResizeError: 'Δεν μπορούν να βρεθούν οι διαστάσεις της εικόνας για να αλλάγή μεγέθους.', + msgImageResizeException: 'Σφάλμα κατά την αλλαγή μεγέθους της εικόνας. <pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Σύρετε τα αρχεία εδώ …', + dropZoneClickTitle: '<br>(ή πατήστε για επιλογή {files})', + fileActionSettings: { + removeTitle: 'Αφαιρέστε το αρχείο', + uploadTitle: 'Μεταφορτώστε το αρχείο', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Δείτε λεπτομέρειες', + dragTitle: 'Μετακίνηση/Προσπαρμογή', + indicatorNewTitle: 'Δεν μεταφορτώθηκε ακόμα', + indicatorSuccessTitle: 'Μεταφορτώθηκε', + indicatorErrorTitle: 'Σφάλμα Μεταφόρτωσης', + indicatorLoadingTitle: 'Μεταφόρτωση ...' + }, + previewZoomButtonTitles: { + prev: 'Προηγούμενο αρχείο', + next: 'Επόμενο αρχείο', + toggleheader: 'Εμφάνιση/Απόκρυψη τίτλου', + fullscreen: 'Εναλλαγή πλήρους οθόνης', + borderless: 'Με ή χωρίς πλαίσιο', + close: 'Κλείσιμο προβολής' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/es.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/es.js new file mode 100644 index 00000000..569e7ee5 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/es.js @@ -0,0 +1,100 @@ +/*! + * FileInput Spanish Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['es'] = { + fileSingle: 'archivo', + filePlural: 'archivos', + browseLabel: 'Examinar …', + removeLabel: 'Quitar', + removeTitle: 'Quitar archivos seleccionados', + cancelLabel: 'Cancelar', + cancelTitle: 'Abortar la subida en curso', + uploadLabel: 'Subir archivo', + uploadTitle: 'Subir archivos seleccionados', + msgNo: 'No', + msgNoFilesSelected: 'No hay archivos seleccionados', + msgCancelled: 'Cancelado', + msgPlaceholder: 'Seleccionar {files}...', + msgZoomModalHeading: 'Vista previa detallada', + msgFileRequired: 'Debes seleccionar un archivo para subir.', + msgSizeTooSmall: 'El archivo "{name}" (<b>{size} KB</b>) es demasiado pequeño y debe ser mayor de <b>{minSize} KB</b>.', + msgSizeTooLarge: 'El archivo "{name}" (<b>{size} KB</b>) excede el tamaño máximo permitido de <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Debe seleccionar al menos <b>{n}</b> {files} a cargar.', + msgFilesTooMany: 'El número de archivos seleccionados a cargar <b>({n})</b> excede el límite máximo permitido de <b>{m}</b>.', + msgFileNotFound: 'Archivo "{name}" no encontrado.', + msgFileSecured: 'No es posible acceder al archivo "{name}" porque está siendo usado por otra aplicación o no tiene permisos de lectura.', + msgFileNotReadable: 'No es posible acceder al archivo "{name}".', + msgFilePreviewAborted: 'Previsualización del archivo "{name}" cancelada.', + msgFilePreviewError: 'Ocurrió un error mientras se leía el archivo "{name}".', + msgInvalidFileName: 'Caracteres no válidos o no soportados en el nombre del archivo "{name}".', + msgInvalidFileType: 'Tipo de archivo no válido para "{name}". Sólo se permiten archivos de tipo "{types}".', + msgInvalidFileExtension: 'Extensión de archivo no válida para "{name}". Sólo se permiten archivos "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'La carga de archivos se ha cancelado', + msgUploadThreshold: 'Procesando...', + msgUploadBegin: 'Inicializando...', + msgUploadEnd: 'Hecho', + msgUploadEmpty: 'No existen datos válidos para el envío.', + msgUploadError: 'Error', + msgValidationError: 'Error de validación', + msgLoading: 'Subiendo archivo {index} de {files} …', + msgProgress: 'Subiendo archivo {index} de {files} - {name} - {percent}% completado.', + msgSelected: '{n} {files} seleccionado(s)', + msgFoldersNotAllowed: 'Arrastre y suelte únicamente archivos. Omitida(s) {n} carpeta(s).', + msgImageWidthSmall: 'El ancho de la imagen "{name}" debe ser de al menos {size} px.', + msgImageHeightSmall: 'La altura de la imagen "{name}" debe ser de al menos {size} px.', + msgImageWidthLarge: 'El ancho de la imagen "{name}" no puede exceder de {size} px.', + msgImageHeightLarge: 'La altura de la imagen "{name}" no puede exceder de {size} px.', + msgImageResizeError: 'No se pudieron obtener las dimensiones de la imagen para cambiar el tamaño.', + msgImageResizeException: 'Error al cambiar el tamaño de la imagen.<pre>{errors}</pre>', + msgAjaxError: 'Algo ha ido mal con la operación {operation}. Por favor, inténtelo de nuevo mas tarde.', + msgAjaxProgressError: 'La operación {operation} ha fallado', + ajaxOperations: { + deleteThumb: 'Archivo borrado', + uploadThumb: 'Archivo subido', + uploadBatch: 'Datos subidos en lote', + uploadExtra: 'Datos del formulario subidos ' + }, + dropZoneTitle: 'Arrastre y suelte aquí los archivos …', + dropZoneClickTitle: '<br>(o haga clic para seleccionar {files})', + fileActionSettings: { + removeTitle: 'Eliminar archivo', + uploadTitle: 'Subir archivo', + uploadRetryTitle: 'Reintentar subir', + downloadTitle: 'Descargar archivo', + zoomTitle: 'Ver detalles', + dragTitle: 'Mover / Reordenar', + indicatorNewTitle: 'No subido todavía', + indicatorSuccessTitle: 'Subido', + indicatorErrorTitle: 'Error al subir', + indicatorLoadingTitle: 'Subiendo...' + }, + previewZoomButtonTitles: { + prev: 'Anterior', + next: 'Siguiente', + toggleheader: 'Mostrar encabezado', + fullscreen: 'Pantalla completa', + borderless: 'Modo sin bordes', + close: 'Cerrar vista detallada' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/et.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/et.js new file mode 100644 index 00000000..50b15477 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/et.js @@ -0,0 +1,99 @@ +/*! + * FileInput Estonian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['et'] = { + fileSingle: 'fail', + filePlural: 'failid', + browseLabel: 'Sirvi …', + removeLabel: 'Eemalda', + removeTitle: 'Clear selected files', + cancelLabel: 'Tühista', + cancelTitle: 'Abort ongoing upload', + uploadLabel: 'Salvesta', + uploadTitle: 'Salvesta valitud failid', + msgNo: 'No', + msgNoFilesSelected: 'No files selected', + msgCancelled: 'Cancelled', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Detailed Preview', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Fail "{name}" (<b>{size} KB</b>) ületab lubatu suuruse <b>{maxSize} KB</b>.', + msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.', + msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.', + msgFileNotFound: 'File "{name}" not found!', + msgFileSecured: 'Security restrictions prevent reading the file "{name}".', + msgFileNotReadable: 'File "{name}" is not readable.', + msgFilePreviewAborted: 'File preview aborted for "{name}".', + msgFilePreviewError: 'An error occurred while reading the file "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: '"{name}" on vale tüüpi. Ainult "{types}" on lubatud.', + msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'The file upload was aborted', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Validation Error', + msgLoading: 'Loading file {index} of {files} …', + msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.', + msgSelected: '{n} {files} selected', + msgFoldersNotAllowed: 'Drag & drop files only! Skipped {n} dropped folder(s).', + msgImageWidthSmall: 'Pildi laius peab olema vähemalt {size} px.', + msgImageHeightSmall: 'Pildi kõrgus peab olema vähemalt {size} px.', + msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.', + msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.', + msgImageResizeError: 'Could not get the image dimensions to resize.', + msgImageResizeException: 'Error while resizing the image.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Lohista failid siia …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Eemalda fail', + uploadTitle: 'Salvesta fail', + uploadRetryTitle: 'Retry upload', + zoomTitle: 'Vaata detaile', + dragTitle: 'Liiguta / Korralda', + indicatorNewTitle: 'Pole veel salvestatud', + indicatorSuccessTitle: 'Uploaded', + indicatorErrorTitle: 'Salvestamise viga', + indicatorLoadingTitle: 'Salvestan ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery);
\ No newline at end of file diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fa.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fa.js new file mode 100644 index 00000000..ca59bbb8 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fa.js @@ -0,0 +1,101 @@ +/*! + * FileInput Persian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Milad Nekofar <milad@nekofar.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['fa'] = { + fileSingle: 'فایل', + filePlural: 'فایلها', + browseLabel: 'مرور …', + removeLabel: 'حذف', + removeTitle: 'پاکسازی فایلهای انتخاب شده', + cancelLabel: 'لغو', + cancelTitle: 'لغو بارگزاری جاری', + uploadLabel: 'بارگذاری', + uploadTitle: 'بارگذاری فایلهای انتخاب شده', + msgNo: 'نه', + msgNoFilesSelected: 'هیچ فایلی انتخاب نشده است', + msgCancelled: 'لغو شد', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'نمایش با جزییات', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'فایل "{name}" (<b>{size} کیلوبایت</b>) خیلی کوچک است و باید از <b>{minSize} کیلوبایت بزرگتر باشد</b>.', + msgSizeTooLarge: 'فایل "{name}" (<b>{size} کیلوبایت</b>) از حداکثر مجاز <b>{maxSize} کیلوبایت</b> بزرگتر است.', + msgFilesTooLess: 'شما باید حداقل <b>{n}</b> {files} فایل برای بارگذاری انتخاب کنید.', + msgFilesTooMany: 'تعداد فایلهای انتخاب شده برای بارگذاری <b>({n})</b> از حداکثر مجاز عبور کرده است <b>{m}</b>.', + msgFileNotFound: 'فایل "{name}" یافت نشد!', + msgFileSecured: 'محدودیت های امنیتی مانع خواندن فایل "{name}" است.', + msgFileNotReadable: 'فایل "{name}" قابل نوشتن نیست.', + msgFilePreviewAborted: 'پیش نمایش فایل "{name}". به مشکل خورد', + msgFilePreviewError: 'در هنگام خواندن فایل "{name}" خطایی رخ داد.', + msgInvalidFileName: 'کاراکترهای غیرمجاز و یا ناشناخته در نام فایل "{name}".', + msgInvalidFileType: 'نوع فایل "{name}" معتبر نیست. فقط "{types}" پشیبانی میشوند.', + msgInvalidFileExtension: 'پسوند فایل "{name}" معتبر نیست. فقط "{extensions}" پشتیبانی میشوند.', + msgFileTypes: { + 'image': 'عکس', + 'html': 'اچ تا ام ال', + 'text': 'متن', + 'video': 'ویدئو', + 'audio': 'صدا', + 'flash': 'فلش', + 'pdf': 'پی دی اف', + 'object': 'دیگر' + }, + msgUploadAborted: 'بارگذاری فایل به مشکل خورد.', + msgUploadThreshold: 'در حال پردازش...', + msgUploadBegin: 'در حال شروع...', + msgUploadEnd: 'انجام شد', + msgUploadEmpty: 'هیچ داده معتبری برای بارگذاری موجود نیست.', + msgUploadError: 'Error', + msgValidationError: 'خطای اعتبار سنجی', + msgLoading: 'بارگیری فایل {index} از {files} …', + msgProgress: 'بارگیری فایل {index} از {files} - {name} - {percent}% تمام شد.', + msgSelected: '{n} {files} انتخاب شده', + msgFoldersNotAllowed: 'فقط فایلها را بکشید و رها کنید! {n} پوشه نادیده گرفته شد.', + msgImageWidthSmall: 'عرض فایل تصویر "{name}" باید حداقل {size} پیکسل باشد.', + msgImageHeightSmall: 'ارتفاع فایل تصویر "{name}" باید حداقل {size} پیکسل باشد.', + msgImageWidthLarge: 'عرض فایل تصویر "{name}" نمیتواند از {size} پیکسل بیشتر باشد.', + msgImageHeightLarge: 'ارتفاع فایل تصویر "{name}" نمیتواند از {size} پیکسل بیشتر باشد.', + msgImageResizeError: 'یافت نشد ابعاد تصویر را برای تغییر اندازه.', + msgImageResizeException: 'خطا در هنگام تغییر اندازه تصویر.<pre>{errors}</pre>', + msgAjaxError: 'به نظر مشکلی در حین {operation} روی داده است. لطفا دوباره تلاش کنید!', + msgAjaxProgressError: '{operation} لغو شد', + ajaxOperations: { + deleteThumb: 'حذف فایل', + uploadThumb: 'بارگذاری فایل', + uploadBatch: 'بارگذاری جمعی فایلها', + uploadExtra: 'بارگذاری با کمک فُرم' + }, + dropZoneTitle: 'فایلها را بکشید و در اینجا رها کنید …', + dropZoneClickTitle: '<br>(یا برای انتخاب {files} کلیک کنید)', + fileActionSettings: { + removeTitle: 'حذف فایل', + uploadTitle: 'آپلود فایل', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'دیدن جزئیات', + dragTitle: 'جابجایی / چیدمان', + indicatorNewTitle: 'آپلود نشده است', + indicatorSuccessTitle: 'آپلود شده', + indicatorErrorTitle: 'بارگذاری خطا', + indicatorLoadingTitle: 'آپلود ...' + }, + previewZoomButtonTitles: { + prev: 'مشاهده فایل قبلی', + next: 'مشاهده فایل بعدی', + toggleheader: 'نمایش عنوان', + fullscreen: 'نمایش تمام صفحه', + borderless: 'نمایش حاشیه', + close: 'بستن نمایش با جزییات' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fi.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fi.js new file mode 100644 index 00000000..19317b54 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fi.js @@ -0,0 +1,91 @@ +/*! + * FileInput Finnish Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales.fi = { + fileSingle: 'tiedosto', + filePlural: 'tiedostot', + browseLabel: 'Selaa …', + removeLabel: 'Poista', + removeTitle: 'Tyhjännä valitut tiedostot', + cancelLabel: 'Peruuta', + cancelTitle: 'Peruuta lataus', + uploadLabel: 'Lataa', + uploadTitle: 'Lataa valitut tiedostot', + msgNoFilesSelected: '', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Tiedosto "{name}" (<b>{size} Kt</b>) ylittää suurimman sallitun tiedoston koon, joka on <b>{maxSize} Kt</b>. Yritä uudelleen!', + msgFilesTooLess: 'Vähintään <b>{n}</b> {files} tiedostoa on valittava ladattavaksi. Ole hyvä ja yritä uudelleen!', + msgFilesTooMany: 'Valittujen tiedostojen lukumäärä <b>({n})</b> ylittää suurimman sallitun määrän <b>{m}</b>. Ole hyvä ja yritä uudelleen!', + msgFileNotFound: 'Tiedostoa "{name}" ei löydy!', + msgFileSecured: 'Tietoturvarajoitukset estävät tiedoston "{name}" lukemisen.', + msgFileNotReadable: 'Tiedosto "{name}" ei ole luettavissa.', + msgFilePreviewAborted: 'Tiedoston "{name}" esikatselu keskeytetty.', + msgFilePreviewError: 'Virhe on tapahtunut luettaessa tiedostoa "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Tiedosto "{name}" on väärän tyyppinen. Ainoastaan tiedostot tyyppiä "{types}" ovat tuettuja.', + msgInvalidFileExtension: 'Tiedoston "{name}" tarkenne on epäkelpo. Ainoastaan tarkenteet "{extensions}" ovat tuettuja.', + msgFileTypes: { + 'image': 'Kuva', + 'html': 'HTML', + 'text': 'Teksti', + 'video': 'Video', + 'audio': 'Ääni', + 'flash': 'Flash', + 'pdf': 'PDF', + 'object': 'Olio' + }, + msgUploadThreshold: 'Käsitellään...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'Ei ladattavaa dataa.', + msgUploadError: 'Error', + msgValidationError: 'Tiedoston latausvirhe', + msgLoading: 'Ladataan tiedostoa {index} / {files} …', + msgProgress: 'Ladataan tiedostoa {index} / {files} - {name} - {percent}% valmistunut.', + msgSelected: '{n} tiedostoa valittu', + msgFoldersNotAllowed: 'Raahaa ja pudota ainoastaan tiedostoja! Ohitettu {n} raahattua kansiota.', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Raahaa ja pudota tiedostot tähän …', + dropZoneClickTitle: '<br>(tai valitse hiirellä {files})', + fileActionSettings: { + removeTitle: 'Poista tiedosto', + uploadTitle: 'Upload file', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Yksityiskohdat', + dragTitle: 'Siirrä / Järjestele', + indicatorNewTitle: 'Ei ladattu', + indicatorSuccessTitle: 'Ladattu', + indicatorErrorTitle: 'Lataus epäonnistui', + indicatorLoadingTitle: 'Ladataan ...' + }, + previewZoomButtonTitles: { + prev: 'Seuraava tiedosto', + next: 'Edellinen tiedosto', + toggleheader: 'Näytä otsikko', + fullscreen: 'Kokonäytön tila', + borderless: 'Rajaton tila', + close: 'Sulje esikatselu' + } + }; + + $.extend($.fn.fileinput.defaults, $.fn.fileinputLocales.fi); +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fr.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fr.js new file mode 100644 index 00000000..81a77042 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/fr.js @@ -0,0 +1,99 @@ +/*! + * FileInput French Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['fr'] = { + fileSingle: 'fichier', + filePlural: 'fichiers', + browseLabel: 'Parcourir…', + removeLabel: 'Retirer', + removeTitle: 'Retirer les fichiers sélectionnés', + cancelLabel: 'Annuler', + cancelTitle: "Annuler l'envoi en cours", + uploadLabel: 'Transférer', + uploadTitle: 'Transférer les fichiers sélectionnés', + msgNo: 'Non', + msgNoFilesSelected: '', + msgCancelled: 'Annulé', + msgPlaceholder: 'Sélectionner le(s) {files}...', + msgZoomModalHeading: 'Aperçu détaillé', + msgFileRequired: 'Vous devez sélectionner un fichier à uploader.', + msgSizeTooSmall: 'Le fichier "{name}" (<b>{size} KB</b>) est inférieur à la taille minimale de <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Le fichier "{name}" (<b>{size} Ko</b>) dépasse la taille maximale autorisée qui est de <b>{maxSize} Ko</b>.', + msgFilesTooLess: 'Vous devez sélectionner au moins <b>{n}</b> {files} à transmettre.', + msgFilesTooMany: 'Le nombre de fichier sélectionné <b>({n})</b> dépasse la quantité maximale autorisée qui est de <b>{m}</b>.', + msgFileNotFound: 'Le fichier "{name}" est introuvable !', + msgFileSecured: "Des restrictions de sécurité vous empêchent d'accéder au fichier \"{name}\".", + msgFileNotReadable: 'Le fichier "{name}" est illisible.', + msgFilePreviewAborted: 'Prévisualisation du fichier "{name}" annulée.', + msgFilePreviewError: 'Une erreur est survenue lors de la lecture du fichier "{name}".', + msgInvalidFileName: 'Caractères invalides ou non supportés dans le nom de fichier "{name}".', + msgInvalidFileType: 'Type de document invalide pour "{name}". Seulement les documents de type "{types}" sont autorisés.', + msgInvalidFileExtension: 'Extension invalide pour le fichier "{name}". Seules les extensions "{extensions}" sont autorisées.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Le transfert du fichier a été interrompu', + msgUploadThreshold: 'En cours...', + msgUploadBegin: 'Initialisation...', + msgUploadEnd: 'Terminé', + msgUploadEmpty: 'Aucune donnée valide disponible pour transmission.', + msgUploadError: 'Erreur', + msgValidationError: 'Erreur de validation', + msgLoading: 'Transmission du fichier {index} sur {files}…', + msgProgress: 'Transmission du fichier {index} sur {files} - {name} - {percent}%.', + msgSelected: '{n} {files} sélectionné(s)', + msgFoldersNotAllowed: 'Glissez et déposez uniquement des fichiers ! {n} répertoire(s) exclu(s).', + msgImageWidthSmall: 'La largeur de l\'image "{name}" doit être d\'au moins {size} px.', + msgImageHeightSmall: 'La hauteur de l\'image "{name}" doit être d\'au moins {size} px.', + msgImageWidthLarge: 'La largeur de l\'image "{name}" ne peut pas dépasser {size} px.', + msgImageHeightLarge: 'La hauteur de l\'image "{name}" ne peut pas dépasser {size} px.', + msgImageResizeError: "Impossible d'obtenir les dimensions de l'image à redimensionner.", + msgImageResizeException: "Erreur lors du redimensionnement de l'image.<pre>{errors}</pre>", + msgAjaxError: "Une erreur s'est produite pendant l'opération de {operation}. Veuillez réessayer plus tard.", + msgAjaxProgressError: 'L\'opération "{operation}" a échoué', + ajaxOperations: { + deleteThumb: 'suppression du fichier', + uploadThumb: 'transfert du fichier', + uploadBatch: 'transfert des fichiers', + uploadExtra: 'soumission des données de formulaire' + }, + dropZoneTitle: 'Glissez et déposez les fichiers ici…', + dropZoneClickTitle: '<br>(ou cliquez pour sélectionner manuellement)', + fileActionSettings: { + removeTitle: 'Supprimer le fichier', + uploadTitle: 'Transférer le fichier', + uploadRetryTitle: 'Relancer le transfert', + zoomTitle: 'Voir les détails', + dragTitle: 'Déplacer / Réarranger', + indicatorNewTitle: 'Pas encore transféré', + indicatorSuccessTitle: 'Posté', + indicatorErrorTitle: 'Ajouter erreur', + indicatorLoadingTitle: 'En cours...' + }, + previewZoomButtonTitles: { + prev: 'Voir le fichier précédent', + next: 'Voir le fichier suivant', + toggleheader: 'Masquer le titre', + fullscreen: 'Mode plein écran', + borderless: 'Mode cinéma', + close: "Fermer l'aperçu" + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/gl.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/gl.js new file mode 100644 index 00000000..6efc4f61 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/gl.js @@ -0,0 +1,100 @@ +/*! + * FileInput Galician Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['gl'] = { + fileSingle: 'arquivo', + filePlural: 'arquivos', + browseLabel: 'Examinar …', + removeLabel: 'Quitar', + removeTitle: 'Quitar aquivos seleccionados', + cancelLabel: 'Cancelar', + cancelTitle: 'Abortar a subida en curso', + uploadLabel: 'Subir arquivo', + uploadTitle: 'Subir arquivos seleccionados', + msgNo: 'Non', + msgNoFilesSelected: 'Non hay arquivos seleccionados', + msgCancelled: 'Cancelado', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Vista previa detallada', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'O arquivo "{name}" (<b>{size} KB</b>) é demasiado pequeño e debe ser maior de <b>{minSize} KB</b>.', + msgSizeTooLarge: 'El arquivo "{name}" (<b>{size} KB</b>) excede o tamaño máximo permitido de <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Debe seleccionar al menos <b>{n}</b> {files} a cargar.', + msgFilesTooMany: 'O número de arquivos seleccionados a cargar <b>({n})</b> excede do límite máximo permitido de <b>{m}</b>.', + msgFileNotFound: 'Arquivo "{name}" non encontrado.', + msgFileSecured: 'Non é posible acceder o arquivo "{name}" porque estará sendo usado por outra aplicación ou non teñamos permisos de lectura.', + msgFileNotReadable: 'Non é posible acceder o archivo "{name}".', + msgFilePreviewAborted: 'Previsualización do arquivo "{name}" cancelada.', + msgFilePreviewError: 'Ocurriu un erro mentras se lía o arquivo "{name}".', + msgInvalidFileName: 'Caracteres non válidos o no soportados no nome do arquivos "{name}".', + msgInvalidFileType: 'Tipo de archivo no válido para "{name}". Sólo se permiten arquivos do tipo "{types}".', + msgInvalidFileExtension: 'Extensión de arquivo non válido para "{name}". Só se permiten arquivos "{extensions}".', + msgFileTypes: { + 'image': 'imaxe', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'A carga de arquivos cancelouse', + msgUploadThreshold: 'Procesando...', + msgUploadBegin: 'Inicialicando...', + msgUploadEnd: 'Feito', + msgUploadEmpty: 'Non existen datos válidos para o envío.', + msgUploadError: 'Error', + msgValidationError: 'Erro de validación', + msgLoading: 'Subindo arquivo {index} de {files} …', + msgProgress: 'Subiendo arquivo {index} de {files} - {name} - {percent}% completado.', + msgSelected: '{n} {files} seleccionado(s)', + msgFoldersNotAllowed: 'Arrastra e solta únicamente arquivoa. Omitida(s) {n} carpeta(s).', + msgImageWidthSmall: 'O ancho da imaxe "{name}" debe ser de al menos {size} px.', + msgImageHeightSmall: 'A altura de la imaxe "{name}" debe ser de al menos {size} px.', + msgImageWidthLarge: 'El ancho de la imaxe "{name}" no puede exceder de {size} px.', + msgImageHeightLarge: 'La altura de la imaxe "{name}" no puede exceder de {size} px.', + msgImageResizeError: 'No se pudieron obtener las dimensiones de la imaxe para cambiar el tamaño.', + msgImageResizeException: 'Erro o cambiar o tamaño da imaxe.<pre>{errors}</pre>', + msgAjaxError: 'Algo foi mal ca operación {operation}. Por favor, intentao de novo mais tarde.', + msgAjaxProgressError: 'A operación {operation} fallou', + ajaxOperations: { + deleteThumb: 'Arquivo borrado', + uploadThumb: 'Arquivo subido', + uploadBatch: 'Datos subidos en lote', + uploadExtra: 'Datos do formulario subidos' + }, + dropZoneTitle: 'Arrasta e solte aquí os arquivos …', + dropZoneClickTitle: '<br>(ou fai clic para seleccionar {files})', + fileActionSettings: { + removeTitle: 'Eliminar arquivo', + uploadTitle: 'Subir arquivo', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Ver detalles', + dragTitle: 'Mover / Reordenar', + indicatorNewTitle: 'Non subido todavía', + indicatorSuccessTitle: 'Subido', + indicatorErrorTitle: 'Erro o subir', + indicatorLoadingTitle: 'Subiendo...' + }, + previewZoomButtonTitles: { + prev: 'Ver arquivo anterior', + next: 'Ver arquivo siguinte', + toggleheader: 'Mostrar encabezado', + fullscreen: 'Mostrar a pantalla completa', + borderless: 'Activar o modo sen bordes', + close: 'Cerrar vista detallada' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/hu.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/hu.js new file mode 100644 index 00000000..f9ef93ae --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/hu.js @@ -0,0 +1,100 @@ +/*! + * FileInput Hungarian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['hu'] = { + fileSingle: 'fájl', + filePlural: 'fájlok', + browseLabel: 'Tallóz …', + removeLabel: 'Eltávolít', + removeTitle: 'Kijelölt fájlok törlése', + cancelLabel: 'Mégse', + cancelTitle: 'Feltöltés megszakítása', + uploadLabel: 'Feltöltés', + uploadTitle: 'Kijelölt fájlok feltöltése', + msgNo: 'Nem', + msgNoFilesSelected: 'Nincs fájl kiválasztva', + msgCancelled: 'Megszakítva', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Részletes Előnézet', + msgFileRequired: 'Kötelező fájlt kiválasztani a feltöltéshez.', + msgSizeTooSmall: 'A fájl: "{name}" (<b>{size} KB</b>) mérete túl kicsi, nagyobbnak kell lennie, mint <b>{minSize} KB</b>.', + msgSizeTooLarge: '"{name}" fájl (<b>{size} KB</b>) mérete nagyobb a megengedettnél <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Legalább <b>{n}</b> {files} ki kell választania a feltöltéshez.', + msgFilesTooMany: 'A feltölteni kívánt fájlok száma <b>({n})</b> elérte a megengedett maximumot <b>{m}</b>.', + msgFileNotFound: '"{name}" fájl nem található!', + msgFileSecured: 'Biztonsági beállítások nem engedik olvasni a fájlt "{name}".', + msgFileNotReadable: '"{name}" fájl nem olvasható.', + msgFilePreviewAborted: '"{name}" fájl feltöltése megszakítva.', + msgFilePreviewError: 'Hiba lépett fel a "{name}" fájl olvasása közben.', + msgInvalidFileName: 'Hibás vagy nem támogatott karakterek a fájl nevében "{name}".', + msgInvalidFileType: 'Nem megengedett fájl "{name}". Csak a "{types}" fájl típusok támogatottak.', + msgInvalidFileExtension: 'Nem megengedett kiterjesztés / fájltípus "{name}". Csak a "{extensions}" kiterjesztés(ek) / fájltípus(ok) támogatottak.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'A fájl feltöltés megszakítva', + msgUploadThreshold: 'Folyamatban...', + msgUploadBegin: 'Inicializálás...', + msgUploadEnd: 'Kész', + msgUploadEmpty: 'Nincs érvényes adat a feltöltéshez.', + msgUploadError: 'Error', + msgValidationError: 'Érvényesítés hiba', + msgLoading: '{index} / {files} töltése …', + msgProgress: 'Feltöltés: {index} / {files} - {name} - {percent}% kész.', + msgSelected: '{n} {files} kiválasztva.', + msgFoldersNotAllowed: 'Csak fájlokat húzzon ide! Kihagyva {n} könyvtár.', + msgImageWidthSmall: 'A kép szélességének "{name}" legalább {size} pixelnek kell lennie.', + msgImageHeightSmall: 'A kép magasságának "{name}" legalább {size} pixelnek kell lennie.', + msgImageWidthLarge: 'A kép szélessége "{name}" nem haladhatja meg a {size} pixelt.', + msgImageHeightLarge: 'A kép magassága "{name}" nem haladhatja meg a {size} pixelt.', + msgImageResizeError: 'Nem lehet megállapítani a kép méreteit az átméretezéshez.', + msgImageResizeException: 'Hiba történt a méretezés közben.<pre>{errors}</pre>', + msgAjaxError: 'Hiba történt a művelet közben ({operation}). Kérjük, próbálja később!', + msgAjaxProgressError: 'Hiba! ({operation})', + ajaxOperations: { + deleteThumb: 'fájl törlés', + uploadThumb: 'fájl feltöltés', + uploadBatch: 'csoportos fájl feltöltés', + uploadExtra: 'űrlap adat feltöltés' + }, + dropZoneTitle: 'Húzzon ide fájlokat …', + dropZoneClickTitle: '<br>(vagy kattintson ide a {files} tallózásához...)', + fileActionSettings: { + removeTitle: 'A fájl eltávolítása', + uploadTitle: 'fájl feltöltése', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Részletek megtekintése', + dragTitle: 'Mozgatás / Átrendezés', + indicatorNewTitle: 'Nem feltöltött', + indicatorSuccessTitle: 'Feltöltött', + indicatorErrorTitle: 'Feltöltés hiba', + indicatorLoadingTitle: 'Feltöltés ...' + }, + previewZoomButtonTitles: { + prev: 'Elöző fájl megnézése', + next: 'Következő fájl megnézése', + toggleheader: 'Fejléc mutatása', + fullscreen: 'Teljes képernyős mód bekapcsolása', + borderless: 'Keret nélküli ablak mód bekapcsolása', + close: 'Részletes előnézet bezárása' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/id.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/id.js new file mode 100644 index 00000000..06c416b3 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/id.js @@ -0,0 +1,101 @@ +/*! + * FileInput Indonesian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Bambang Riswanto <bamz3r@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['id'] = { + fileSingle: 'berkas', + filePlural: 'berkas', + browseLabel: 'Pilih File …', + removeLabel: 'Hapus', + removeTitle: 'Hapus berkas terpilih', + cancelLabel: 'Batal', + cancelTitle: 'Batalkan proses pengunggahan', + uploadLabel: 'Unggah', + uploadTitle: 'Unggah berkas terpilih', + msgNo: 'Tidak', + msgNoFilesSelected: '', + msgCancelled: 'Dibatalkan', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Pratinjau terperinci', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Berkas "{name}" (<b>{size} KB</b>) melebihi ukuran upload maksimal yaitu <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Anda harus memilih setidaknya <b>{n}</b> {files} untuk diunggah.', + msgFilesTooMany: '<b>({n})</b> berkas yang dipilih untuk diunggah melebihi ukuran upload maksimal yaitu <b>{m}</b>.', + msgFileNotFound: 'Berkas "{name}" tak ditemukan!', + msgFileSecured: 'Sistem keamanan mencegah untuk membaca berkas "{name}".', + msgFileNotReadable: 'Berkas "{name}" tak dapat dibaca.', + msgFilePreviewAborted: 'Pratinjau untuk berkas "{name}" dibatalkan.', + msgFilePreviewError: 'Kesalahan saat membaca berkas "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Jenis berkas "{name}" tidak sah. Hanya berkas "{types}" yang didukung.', + msgInvalidFileExtension: 'Ekstensi berkas "{name}" tidak sah. Hanya ekstensi "{extensions}" yang didukung.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Pengunggahan berkas dibatalkan', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Kesalahan validasi', + msgLoading: 'Memuat {index} dari {files} berkas …', + msgProgress: 'Memuat {index} dari {files} berkas - {name} - {percent}% selesai.', + msgSelected: '{n} {files} dipilih', + msgFoldersNotAllowed: 'Hanya tahan dan lepas file saja! {n} folder diabaikan.', + msgImageWidthSmall: 'Lebar dari gambar "{name}" harus sekurangnya {size} px.', + msgImageHeightSmall: 'Tinggi dari gambar "{name}" harus sekurangnya {size} px.', + msgImageWidthLarge: 'Lebar dari gambar "{name}" tak boleh melebihi {size} px.', + msgImageHeightLarge: 'Tinggi dari gambar "{name}" tak boleh melebihi {size} px.', + msgImageResizeError: 'Tak dapat menentukan dimensi gambar untuk mengubah ukuran.', + msgImageResizeException: 'Kesalahan saat mengubah ukuran gambar.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Tarik dan lepaskan berkas disini …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Hapus berkas', + uploadTitle: 'Unggah berkas', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Tampilkan Rincian', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Belum diunggah', + indicatorSuccessTitle: 'Sudah diunggah', + indicatorErrorTitle: 'Kesalahan pengunggahan', + indicatorLoadingTitle: 'Mengunggah ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/it.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/it.js new file mode 100644 index 00000000..73ee7663 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/it.js @@ -0,0 +1,102 @@ +/*! + * FileInput Italian Translation + * + * Author: Lorenzo Milesi <maxxer@yetopen.it> + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['it'] = { + fileSingle: 'file', + filePlural: 'file', + browseLabel: 'Sfoglia…', + removeLabel: 'Rimuovi', + removeTitle: 'Rimuovi i file selezionati', + cancelLabel: 'Annulla', + cancelTitle: 'Annulla i caricamenti in corso', + uploadLabel: 'Carica', + uploadTitle: 'Carica i file selezionati', + msgNo: 'No', + msgNoFilesSelected: 'Nessun file selezionato', + msgCancelled: 'Annullato', + msgPlaceholder: 'Seleziona {files}...', + msgZoomModalHeading: 'Anteprima dettagliata', + msgFileRequired: 'Devi selezionare un file da caricare.', + msgSizeTooSmall: 'Il file "{name}" (<b>{size} KB</b>) è troppo piccolo, deve essere almeno di <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Il file "{name}" (<b>{size} KB</b>) eccede la dimensione massima di caricamento di <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Devi selezionare almeno <b>{n}</b> {files} da caricare.', + msgFilesTooMany: 'Il numero di file selezionati per il caricamento <b>({n})</b> eccede il numero massimo di file accettati <b>{m}</b>.', + msgFileNotFound: 'File "{name}" non trovato!', + msgFileSecured: 'Restrizioni di sicurezza impediscono la lettura del file "{name}".', + msgFileNotReadable: 'Il file "{name}" non è leggibile.', + msgFilePreviewAborted: 'Generazione anteprima per "{name}" annullata.', + msgFilePreviewError: 'Errore durante la lettura del file "{name}".', + msgInvalidFileName: 'Carattere non valido o non supportato nel file "{name}".', + msgInvalidFileType: 'Tipo non valido per il file "{name}". Sono ammessi solo file di tipo "{types}".', + msgInvalidFileExtension: 'Estensione non valida per il file "{name}". Sono ammessi solo file con estensione "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Il caricamento del file è stato interrotto', + msgUploadThreshold: 'In lavorazione...', + msgUploadBegin: 'Inizializzazione...', + msgUploadEnd: 'Fatto', + msgUploadEmpty: 'Dati non disponibili', + msgUploadError: 'Errore', + msgValidationError: 'Errore di convalida', + msgLoading: 'Caricamento file {index} di {files}…', + msgProgress: 'Caricamento file {index} di {files} - {name} - {percent}% completato.', + msgSelected: '{n} {files} selezionati', + msgFoldersNotAllowed: 'Trascina solo file! Ignorata/e {n} cartella/e.', + msgImageWidthSmall: 'La larghezza dell\'immagine "{name}" deve essere di almeno {size} px.', + msgImageHeightSmall: 'L\'altezza dell\'immagine "{name}" deve essere di almeno {size} px.', + msgImageWidthLarge: 'La larghezza dell\'immagine "{name}" non può superare {size} px.', + msgImageHeightLarge: 'L\'altezza dell\'immagine "{name}" non può superare {size} px.', + msgImageResizeError: 'Impossibile ottenere le dimensioni dell\'immagine per ridimensionare.', + msgImageResizeException: 'Errore durante il ridimensionamento dell\'immagine.<pre>{errors}</pre>', + msgAjaxError: 'Qualcosa non ha funzionato con l\'operazione {operation}. Per favore riprova più tardi!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'eliminazione file', + uploadThumb: 'caricamento file', + uploadBatch: 'caricamento file in batch', + uploadExtra: 'upload dati del form' + }, + dropZoneTitle: 'Trascina i file qui…', + dropZoneClickTitle: '<br>(o clicca per selezionare {files})', + fileActionSettings: { + removeTitle: 'Rimuovere il file', + uploadTitle: 'Caricare un file', + uploadRetryTitle: 'Riprova il caricamento', + downloadTitle: 'Scarica file', + zoomTitle: 'Guarda i dettagli', + dragTitle: 'Muovi / Riordina', + indicatorNewTitle: 'Non ancora caricato', + indicatorSuccessTitle: 'Caricati', + indicatorErrorTitle: 'Carica Errore', + indicatorLoadingTitle: 'Caricamento ...' + }, + previewZoomButtonTitles: { + prev: 'Vedi il file precedente', + next: 'Vedi il file seguente', + toggleheader: 'Attiva header', + fullscreen: 'Attiva full screen', + borderless: 'Abilita modalità senza bordi', + close: 'Chiudi' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ja.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ja.js new file mode 100644 index 00000000..3decd7fa --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ja.js @@ -0,0 +1,109 @@ +/*! + * FileInput Japanese Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Yuta Hoshina <hoshina@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + * slugCallback + * \u4e00-\u9fa5 : Kanji (Chinese characters) + * \u3040-\u309f : Hiragana (Japanese syllabary) + * \u30a0-\u30ff\u31f0-\u31ff : Katakana (including phonetic extension) + * \u3200-\u32ff : Enclosed CJK Letters and Months + * \uff00-\uffef : Halfwidth and Fullwidth Forms + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['ja'] = { + fileSingle: 'ファイル', + filePlural: 'ファイル', + browseLabel: 'ファイルを選択…', + removeLabel: '削除', + removeTitle: '選択したファイルを削除', + cancelLabel: 'キャンセル', + cancelTitle: 'アップロードをキャンセル', + uploadLabel: 'アップロード', + uploadTitle: '選択したファイルをアップロード', + msgNo: 'いいえ', + msgNoFilesSelected: 'ファイルが選択されていません', + msgCancelled: 'キャンセル', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'プレビュー', + msgFileRequired: 'ファイルを選択してください', + msgSizeTooSmall: 'ファイル"{name}" (<b>{size} KB</b>)はアップロード可能な下限容量<b>{minSize} KB</b>より小さいです', + msgSizeTooLarge: 'ファイル"{name}" (<b>{size} KB</b>)はアップロード可能な上限容量<b>{maxSize} KB</b>を超えています', + msgFilesTooLess: '最低<b>{n}</b>個の{files}を選択してください', + msgFilesTooMany: '選択したファイルの数<b>({n}個)</b>はアップロード可能な上限数<b>({m}個)</b>を超えています', + msgFileNotFound: 'ファイル"{name}"はありませんでした', + msgFileSecured: 'ファイル"{name}"は読み取り権限がないため取得できません', + msgFileNotReadable: 'ファイル"{name}"は読み込めません', + msgFilePreviewAborted: 'ファイル"{name}"のプレビューを中止しました', + msgFilePreviewError: 'ファイル"{name}"の読み込み中にエラーが発生しました', + msgInvalidFileName: 'ファイル名に無効な文字が含まれています "{name}".', + msgInvalidFileType: '"{name}"は無効なファイル形式です。"{types}"形式のファイルのみサポートしています', + msgInvalidFileExtension: '"{name}"は無効な拡張子です。拡張子が"{extensions}"のファイルのみサポートしています', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'ファイルのアップロードが中止されました', + msgUploadThreshold: '処理中...', + msgUploadBegin: '初期化中...', + msgUploadEnd: '完了', + msgUploadEmpty: 'アップロードに有効なデータがありません', + msgUploadError: 'エラー', + msgValidationError: '検証エラー', + msgLoading: '{files}個中{index}個目のファイルを読み込み中…', + msgProgress: '{files}個中{index}個のファイルを読み込み中 - {name} - {percent}% 完了', + msgSelected: '{n}個の{files}を選択', + msgFoldersNotAllowed: 'ドラッグ&ドロップが可能なのはファイルのみです。{n}個のフォルダ-は無視されました', + msgImageWidthSmall: '画像ファイル"{name}"の幅が小さすぎます。画像サイズの幅は少なくとも{size}px必要です', + msgImageHeightSmall: '画像ファイル"{name}"の高さが小さすぎます。画像サイズの高さは少なくとも{size}px必要です', + msgImageWidthLarge: '画像ファイル"{name}"の幅がアップロード可能な画像サイズ({size}px)を超えています', + msgImageHeightLarge: '画像ファイル"{name}"の高さがアップロード可能な画像サイズ({size}px)を超えています', + msgImageResizeError: 'リサイズ時に画像サイズが取得できませんでした', + msgImageResizeException: '画像のリサイズ時にエラーが発生しました。<pre>{errors}</pre>', + msgAjaxError: '{operation}実行中にエラーが発生しました。時間をおいてもう一度お試しください。', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'ファイル削除', + uploadThumb: 'ファイルアップロード', + uploadBatch: '一括ファイルアップロード', + uploadExtra: 'フォームデータアップロード' + }, + dropZoneTitle: 'ファイルをドラッグ&ドロップ…', + dropZoneClickTitle: '<br>(または クリックして{files}を選択 )', + slugCallback: function(text) { + return text ? text.split(/(\\|\/)/g).pop().replace(/[^\w\u4e00-\u9fa5\u3040-\u309f\u30a0-\u30ff\u31f0-\u31ff\u3200-\u32ff\uff00-\uffef\-.\\\/ ]+/g, '') : ''; + }, + fileActionSettings: { + removeTitle: 'ファイルを削除', + uploadTitle: 'ファイルをアップロード', + uploadRetryTitle: '再アップロード', + zoomTitle: 'プレビュー', + dragTitle: '移動 / 再配置', + indicatorNewTitle: 'まだアップロードされていません', + indicatorSuccessTitle: 'アップロード済み', + indicatorErrorTitle: 'アップロード失敗', + indicatorLoadingTitle: 'アップロード中...' + }, + previewZoomButtonTitles: { + prev: '前のファイルを表示', + next: '次のファイルを表示', + toggleheader: 'ファイル情報の表示/非表示', + fullscreen: 'フルスクリーン表示の開始/終了', + borderless: 'フルウィンドウ表示の開始/終了', + close: 'プレビューを閉じる' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ka.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ka.js new file mode 100644 index 00000000..c6c0a230 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ka.js @@ -0,0 +1,101 @@ +/*! + * FileInput Georgian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['ka'] = { + fileSingle: 'ფაილი', + filePlural: 'ფაილები', + browseLabel: 'არჩევა …', + removeLabel: 'წაშლა', + removeTitle: 'არჩეული ფაილების წაშლა', + cancelLabel: 'გაუქმება', + cancelTitle: 'მიმდინარე ატვირთვის გაუქმება', + uploadLabel: 'ატვირთვა', + uploadTitle: 'არჩეული ფაილების ატვირთვა', + msgNo: 'არა', + msgNoFilesSelected: 'ფაილები არ არის არჩეული', + msgCancelled: 'გაუქმებულია', + msgPlaceholder: 'აირჩიეთ {files}...', + msgZoomModalHeading: 'დეტალურად ნახვა', + msgFileRequired: 'ატვირთვისთვის აუცილებელია ფაილის არჩევა.', + msgSizeTooSmall: 'ფაილი "{name}" (<b>{size} KB</b>) არის ძალიან პატარა. მისი ზომა უნდა იყოს არანაკლებ <b>{minSize} KB</b>.', + msgSizeTooLarge: 'ფაილი "{name}" (<b>{size} KB</b>) აჭარბებს მაქსიმალურ დასაშვებ ზომას <b>{maxSize} KB</b>.', + msgFilesTooLess: 'უნდა აირჩიოთ მინიმუმ <b>{n}</b> {file} ატვირთვისთვის.', + msgFilesTooMany: 'არჩეული ფაილების რაოდენობა <b>({n})</b> აჭარბებს დასაშვებ ლიმიტს <b>{m}</b>.', + msgFileNotFound: 'ფაილი "{name}" არ მოიძებნა!', + msgFileSecured: 'უსაფრთხოებით გამოწვეული შეზღუდვები კრძალავს ფაილის "{name}" წაკითხვას.', + msgFileNotReadable: 'ფაილის "{name}" წაკითხვა შეუძლებელია.', + msgFilePreviewAborted: 'პრევიუ გაუქმებულია ფაილისათვის "{name}".', + msgFilePreviewError: 'დაფიქსირდა შეცდომა ფაილის "{name}" კითხვისას.', + msgInvalidFileName: 'ნაპოვნია დაუშვებელი სიმბოლოები ფაილის "{name}" სახელში.', + msgInvalidFileType: 'ფაილს "{name}" გააჩნია დაუშვებელი ტიპი. მხოლოდ "{types}" ტიპის ფაილები არის დაშვებული.', + msgInvalidFileExtension: 'ფაილს "{name}" გააჩნია დაუშვებელი გაფართოება. მხოლოდ "{extensions}" გაფართოების ფაილები არის დაშვებული.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'ფაილის ატვირთვა შეწყდა', + msgUploadThreshold: 'მუშავდება...', + msgUploadBegin: 'ინიციალიზაცია...', + msgUploadEnd: 'დასრულებულია', + msgUploadEmpty: 'ატვირთვისთვის დაუშვებელი მონაცემები.', + msgUploadError: 'ატვირთვის შეცდომა', + msgValidationError: 'ვალიდაციის შეცდომა', + msgLoading: 'ატვირთვა {index} / {files} …', + msgProgress: 'ფაილის ატვირთვა დასრულებულია {index} / {files} - {name} - {percent}%.', + msgSelected: 'არჩეულია {n} {file}', + msgFoldersNotAllowed: 'დაშვებულია მხოლოდ ფაილების გადმოთრევა! გამოტოვებულია {n} გადმოთრეული ფოლდერი.', + msgImageWidthSmall: 'სურათის "{name}" სიგანე უნდა იყოს არანაკლებ {size} px.', + msgImageHeightSmall: 'სურათის "{name}" სიმაღლე უნდა იყოს არანაკლებ {size} px.', + msgImageWidthLarge: 'სურათის "{name}" სიგანე არ უნდა აღემატებოდეს {size} px-ს.', + msgImageHeightLarge: 'სურათის "{name}" სიმაღლე არ უნდა აღემატებოდეს {size} px-ს.', + msgImageResizeError: 'ვერ მოხერხდა სურათის ზომის შეცვლისთვის საჭირო მონაცემების გარკვევა.', + msgImageResizeException: 'შეცდომა სურათის ზომის შეცვლისას.<pre>{errors}</pre>', + msgAjaxError: 'დაფიქსირდა შეცდომა ოპერაციის {operation} შესრულებისას. ცადეთ მოგვიანებით!', + msgAjaxProgressError: 'ვერ მოხერხდა ოპერაციის {operation} შესრულება', + ajaxOperations: { + deleteThumb: 'ფაილის წაშლა', + uploadThumb: 'ფაილის ატვირთვა', + uploadBatch: 'ფაილების ატვირთვა', + uploadExtra: 'მონაცემების გაგზავნა ფორმიდან' + }, + dropZoneTitle: 'გადმოათრიეთ ფაილები აქ …', + dropZoneClickTitle: '<br>(ან დააჭირეთ რათა აირჩიოთ {files})', + fileActionSettings: { + removeTitle: 'ფაილის წაშლა', + uploadTitle: 'ფაილის ატვირთვა', + uploadRetryTitle: 'ატვირთვის გამეორება', + downloadTitle: 'ფაილის ჩამოტვირთვა', + zoomTitle: 'დეტალურად ნახვა', + dragTitle: 'გადაადგილება / მიმდევრობის შეცვლა', + indicatorNewTitle: 'ჯერ არ ატვირთულა', + indicatorSuccessTitle: 'ატვირთულია', + indicatorErrorTitle: 'ატვირთვის შეცდომა', + indicatorLoadingTitle: 'ატვირთვა ...' + }, + previewZoomButtonTitles: { + prev: 'წინა ფაილის ნახვა', + next: 'შემდეგი ფაილის ნახვა', + toggleheader: 'სათაურის დამალვა', + fullscreen: 'მთელ ეკრანზე გაშლა', + borderless: 'მთელ გვერდზე გაშლა', + close: 'დახურვა' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ko.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ko.js new file mode 100644 index 00000000..0236124e --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ko.js @@ -0,0 +1,100 @@ +/*! + * FileInput Korean Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['ko'] = { + fileSingle: '파일', + filePlural: '파일들', + browseLabel: '찾기 …', + removeLabel: '지우기', + removeTitle: '선택한 파일들 지우기', + cancelLabel: '취소', + cancelTitle: '업로드 중단하기', + uploadLabel: '업로드', + uploadTitle: '선택한 파일 업로드하기', + msgNo: '아니요', + msgNoFilesSelected: '선택한 파일이 없습니다.', + msgCancelled: '취소되었습니다.', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: '자세한 미리보기', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: '파일 "{name}" (<b>{size} KB</b>)이 너무 작습니다. <b>{minSize} KB</b>보다 용량이 커야 합니다..', + msgSizeTooLarge: '파일 "{name}" (<b>{size} KB</b>)이 너무 큽니다. 허용 파일 사이즈는 <b>{maxSize} KB</b>.입니다.', + msgFilesTooLess: '업로드하기 위해 최소 <b>{n}</b> {files}개의 파일을 선택해야 합니다.', + msgFilesTooMany: '선택한 파일의 수 <b>({n})</b>가 업로드 허용 최고치인 <b>{m}</b>를 넘었습니다..', + msgFileNotFound: '파일 "{name}"을 찾을 수 없습니다.!', + msgFileSecured: '보안상의 이유로 파일 "{name}"을/를 읽을 수 없습니다..', + msgFileNotReadable: '파일 "{name}"은/는 읽을 수 없습니다.', + msgFilePreviewAborted: '파일 "{name}"의 미리보기가 중단되었습니다.', + msgFilePreviewError: '파일 "{name}"을/를 읽다가 에러가 발생했습니다.', + msgInvalidFileName: '파일 "{name}" 중 지원 불가능한 문자가 포함되어 있습니다.', + msgInvalidFileType: '파일 "{name}"의 타입은 지원하지 않습니다. "{types}" 타입의 파일을 선택해 주십시요.', + msgInvalidFileExtension: '파일 "{name}"의 익스텐션은 지원하지 않습니다. "{extensions}" 타입의 익스텐션을 선택해 주십시요.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: '파일 업로드가 중단되었습니다.', + msgUploadThreshold: '업로드 중...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: '업로드 가능 데이터가 존재하지 않습니다.', + msgUploadError: 'Error', + msgValidationError: '유효성 오류', + msgLoading: '파일 {files} 중 {index}번째를 로딩하고 있습니다. …', + msgProgress: '파일 {files}의 {name}이 {percent}% 로딩되었습니다. ', + msgSelected: '{n} {files}이 선택 되었습니다.', + msgFoldersNotAllowed: '드래그 앤 드랍 파일만 가능합니다! 드랍한 {n}번째 폴더를 건너 뛰었습니다.', + msgImageWidthSmall: '이미지 파일 "{name}"의 가로는 최소 {size} px가 되어야 합니다.', + msgImageHeightSmall: '이미지 파일 "{name}"의 세로는 최소 {size} px가 되어야 합니다.', + msgImageWidthLarge: '이미지 파일 "{name}"의 가로는 최대 {size} px를 넘을수 없습니다.', + msgImageHeightLarge: '이미지 파일 "{name}"의 세로는 최대 {size} px를 넘을수 없습니다.', + msgImageResizeError: '이미지의 사이즈를 재조정을 위한 이미지 사이즈를 가져올 수 없습니다.', + msgImageResizeException: '이미지 사이즈 재조정이 다음 이유로 실패했습니다.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: '파일을 여기에 드래그인 드랍을 하십시요 …', + dropZoneClickTitle: '<br>(또는 {files} 선택을 위해 클릭하십시요)', + fileActionSettings: { + removeTitle: '파일 지우기', + uploadTitle: '파일 업로드 하기', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: '세부 정보 보기', + dragTitle: '옭기기 / 재배열하기', + indicatorNewTitle: '아직 업로드가 안되었습니다.', + indicatorSuccessTitle: '업로드가 성공하였습니다.', + indicatorErrorTitle: '업로드 중 에러가 발행했습니다.', + indicatorLoadingTitle: '업로드 중 ...' + }, + previewZoomButtonTitles: { + prev: '전 파일 보기', + next: '다음 파일 보기', + toggleheader: '머릿글 토글하기', + fullscreen: '전채화면 토글하기', + borderless: '무 테두리 토글하기', + close: '세부 정보 미리보기 토글하기' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/kz.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/kz.js new file mode 100644 index 00000000..82c34cc4 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/kz.js @@ -0,0 +1,88 @@ +/*! + * FileInput Kazakh Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Kali Toleugazy <almatytol@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['kz'] = { + fileSingle: 'файл', + filePlural: 'файлдар', + browseLabel: 'Таңдау …', + removeLabel: 'Жою', + removeTitle: 'Таңдалған файлдарды жою', + cancelLabel: 'Күшін жою', + cancelTitle: 'Ағымдағы жүктеуді болдырмау', + uploadLabel: 'Жүктеу', + uploadTitle: 'Таңдалған файлдарды жүктеу', + msgNo: 'жоқ', + msgNoFilesSelected: 'Файл таңдалмады', + msgCancelled: 'Күші жойылған', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Алдын ала толық көру', + msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) ең үлкен <b>{maxSize} KB</b> өлшемінен асады.', + msgFilesTooLess: 'Жүктеу үшіy кемінде <b>{n}</b> {files} таңдау керек.', + msgFilesTooMany: 'Таңдалған <b>({n})</b> файлдардың саны берілген <b>{m}</b> саннан асып кетті.', + msgFileNotFound: 'Файл "{name}" табылмады!', + msgFileSecured: 'Шектеу қауіпсіздігі "{name}" файлын оқуға тыйым салады.', + msgFileNotReadable: '"{name}" файлды оқу мүмкін емес.', + msgFilePreviewAborted: '"{name}" файл үшін алдын ала қарап көру тыйым салынған.', + msgFilePreviewError: '"{name}" файлды оқығанда қате пайда болды.', + msgInvalidFileType: '"{name}" тыйым салынған файл түрі. Тек мынаналарға рұқсат етілген: "{types}"', + msgInvalidFileExtension: '"{name}" тыйым салынған файл кеңейтімі. Тек "{extensions}" рұқсат.', + msgUploadAborted: 'Файлды жүктеу доғарылды', + msgUploadThreshold: 'Өңдеу...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Тексеру қатесі', + msgLoading: '{index} файлды {files} … жүктеу', + msgProgress: '{index} файлды {files} - {name} - {percent}% жүктеу аяқталды.', + msgSelected: 'Таңдалған файлдар саны: {n}', + msgFoldersNotAllowed: 'Тек файлдарды сүйреу рұқсат! {n} папка өткізілген.', + msgImageWidthSmall: '{name} суреттің ені {size} px. аз болмау керек', + msgImageHeightSmall: '{name} суреттің биіктігі {size} px. аз болмау керек', + msgImageWidthLarge: '"{name}" суреттің ені {size} px. аспау керек', + msgImageHeightLarge: '"{name}" суреттің биіктігі {size} px. аспау керек', + msgImageResizeError: 'Суреттің өлшемін өзгерту үшін, мөлшері алынбады', + msgImageResizeException: 'Суреттің мөлшерлерін өзгерткен кезде қателік пайда болды.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Файлдарды осында сүйреу …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Файлды өшіру', + uploadTitle: 'Файлды жүктеу', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'мәліметтерді көру', + dragTitle: 'Орнын ауыстыру', + indicatorNewTitle: 'Жүктелген жоқ', + indicatorSuccessTitle: 'Жүктелген', + indicatorErrorTitle: 'Жүктелу қатесі ', + indicatorLoadingTitle: 'Жүктелу ...' + }, + previewZoomButtonTitles: { + prev: 'Алдыңғы файлды қарау', + next: 'Келесі файлды қарау', + toggleheader: 'Тақырыпты ауыстыру', + fullscreen: 'Толық экран режимін қосу', + borderless: 'Жиексіз режиміне ауысу', + close: 'Толық көрінісін жабу' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/lt.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/lt.js new file mode 100644 index 00000000..91f36c94 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/lt.js @@ -0,0 +1,100 @@ +/*! + * FileInput <_LANG_> Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Mindaugas Varkalys <varkalys.mindaugas@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['lt'] = { + fileSingle: 'failas', + filePlural: 'failai', + browseLabel: 'Naršyti …', + removeLabel: 'Šalinti', + removeTitle: 'Pašalinti pasirinktus failus', + cancelLabel: 'Atšaukti', + cancelTitle: 'Atšaukti vykstantį įkėlimą', + uploadLabel: 'Įkelti', + uploadTitle: 'Įkelti pasirinktus failus', + msgNo: 'Ne', + msgNoFilesSelected: 'Nepasirinkta jokių failų', + msgCancelled: 'Atšaukta', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Detali Peržiūra', + msgFileRequired: 'Pasirinkite failą įkėlimui.', + msgSizeTooSmall: 'Failas "{name}" (<b>{size} KB</b>) yra per mažas ir turi būti didesnis nei <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Failas "{name}" (<b>{size} KB</b>) viršija maksimalų leidžiamą įkeliamo failo dydį <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Turite pasirinkti bent <b>{n}</b> failus įkėlimui.', + msgFilesTooMany: 'Įkėlimui pasirinktų failų skaičius <b>({n})</b> viršija maksimalų leidžiamą limitą <b>{m}</b>.', + msgFileNotFound: 'Failas "{name}" nerastas!', + msgFileSecured: 'Saugumo apribojimai neleidžia perskaityti failo "{name}".', + msgFileNotReadable: 'Failas "{name}" neperskaitomas.', + msgFilePreviewAborted: 'Failo peržiūra nutraukta "{name}".', + msgFilePreviewError: 'Įvyko klaida skaitant failą "{name}".', + msgInvalidFileName: 'Klaidingi arba nepalaikomi simboliai failo pavadinime "{name}".', + msgInvalidFileType: 'Klaidingas failo "{name}" tipas. Tik "{types}" tipai yra palaikomi.', + msgInvalidFileExtension: 'Klaidingas failo "{name}" plėtinys. Tik "{extensions}" plėtiniai yra palaikomi.', + msgFileTypes: { + 'image': 'paveikslėlis', + 'html': 'HTML', + 'text': 'tekstas', + 'video': 'vaizdo įrašas', + 'audio': 'garso įrašas', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'objektas' + }, + msgUploadAborted: 'Failo įkėlimas buvo nutrauktas', + msgUploadThreshold: 'Vykdoma...', + msgUploadBegin: 'Inicijuojama...', + msgUploadEnd: 'Baigta', + msgUploadEmpty: 'Nėra teisingų duomenų įkėlimui.', + msgUploadError: 'Klaida', + msgValidationError: 'Validacijos Klaida', + msgLoading: 'Keliamas failas {index} iš {files} …', + msgProgress: 'Keliamas failas {index} iš {files} - {name} - {percent}% baigta.', + msgSelected: 'Pasirinkti {n} {files}', + msgFoldersNotAllowed: 'Tempkite tik failus! Praleisti {n} nutempti aplankalas(-i).', + msgImageWidthSmall: 'Paveikslėlio "{name}" plotis turi būti bent {size} px.', + msgImageHeightSmall: 'Paveikslėlio "{name}" aukštis turi būti bent {size} px.', + msgImageWidthLarge: 'Paveikslėlio "{name}" plotis negali viršyti {size} px.', + msgImageHeightLarge: 'Paveikslėlio "{name}" aukštis negali viršyti {size} px.', + msgImageResizeError: 'Nepavyksta gauti paveikslėlio matmetų, kad pakeisti jo matmemis.', + msgImageResizeException: 'Klaida keičiant paveikslėlio matmenis.<pre>{errors}</pre>', + msgAjaxError: 'Kažkas nutiko vykdant {operation} operaciją. Prašome pabandyti vėliau!', + msgAjaxProgressError: '{operation} operacija nesėkminga', + ajaxOperations: { + deleteThumb: 'failo trynimo', + uploadThumb: 'failo įkėlimo', + uploadBatch: 'failų rinkinio įkėlimo', + uploadExtra: 'formos duomenų įkėlimo' + }, + dropZoneTitle: 'Tempkite failus čia …', + dropZoneClickTitle: '<br>(arba paspauskite, kad pasirinktumėte failus)', + fileActionSettings: { + removeTitle: 'Šalinti failą', + uploadTitle: 'Įkelti failą', + uploadRetryTitle: 'Bandyti įkelti vėl', + zoomTitle: 'Peržiūrėti detales', + dragTitle: 'Perstumti', + indicatorNewTitle: 'Dar neįkelta', + indicatorSuccessTitle: 'Įkelta', + indicatorErrorTitle: 'Įkėlimo Klaida', + indicatorLoadingTitle: 'Įkeliama ...' + }, + previewZoomButtonTitles: { + prev: 'Peržiūrėti ankstesnį failą', + next: 'Peržiūrėti kitą failą', + toggleheader: 'Perjungti viršutinę juostą', + fullscreen: 'Perjungti pilno ekrano rėžimą', + borderless: 'Perjungti berėmį režimą', + close: 'Uždaryti detalią peržiūrą' + } + }; +})(window.jQuery);
\ No newline at end of file diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/nl.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/nl.js new file mode 100644 index 00000000..eb83d50e --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/nl.js @@ -0,0 +1,100 @@ +/*! + * FileInput Dutch Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['nl'] = { + fileSingle: 'bestand', + filePlural: 'bestanden', + browseLabel: 'Zoek …', + removeLabel: 'Verwijder', + removeTitle: 'Verwijder geselecteerde bestanden', + cancelLabel: 'Annuleren', + cancelTitle: 'Annuleer upload', + uploadLabel: 'Upload', + uploadTitle: 'Upload geselecteerde bestanden', + msgNo: 'Nee', + msgNoFilesSelected: '', + msgCancelled: 'Geannuleerd', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Gedetailleerd voorbeeld', + msgFileRequired: 'U moet een bestand kiezen om te uploaden.', + msgSizeTooSmall: 'Bestand "{name}" (<b>{size} KB</b>) is te klein en moet groter zijn dan <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Bestand "{name}" (<b>{size} KB</b>) is groter dan de toegestane <b>{maxSize} KB</b>.', + msgFilesTooLess: 'U moet minstens <b>{n}</b> {files} selecteren om te uploaden.', + msgFilesTooMany: 'Aantal geselecteerde bestanden <b>({n})</b> is meer dan de toegestane <b>{m}</b>.', + msgFileNotFound: 'Bestand "{name}" niet gevonden!', + msgFileSecured: 'Bestand kan niet gelezen worden in verband met beveiligings redenen "{name}".', + msgFileNotReadable: 'Bestand "{name}" is niet leesbaar.', + msgFilePreviewAborted: 'Bestand weergaven geannuleerd voor "{name}".', + msgFilePreviewError: 'Er is een fout opgetreden met het lezen van "{name}".', + msgInvalidFileName: 'Ongeldige of niet ondersteunde karakters in bestandsnaam "{name}".', + msgInvalidFileType: 'Geen geldig bestand "{name}". Alleen "{types}" zijn toegestaan.', + msgInvalidFileExtension: 'Geen geldige extensie "{name}". Alleen "{extensions}" zijn toegestaan.', + msgFileTypes: { + 'image': 'afbeelding', + 'html': 'HTML', + 'text': 'tekst', + 'video': 'video', + 'audio': 'geluid', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Het uploaden van bestanden is afgebroken', + msgUploadThreshold: 'Verwerken...', + msgUploadBegin: 'Initialiseren...', + msgUploadEnd: 'Gedaan', + msgUploadEmpty: 'Geen geldige data beschikbaar voor upload.', + msgUploadError: 'Error', + msgValidationError: 'Bevestiging fout', + msgLoading: 'Bestanden laden {index} van de {files} …', + msgProgress: 'Bestanden laden {index} van de {files} - {name} - {percent}% compleet.', + msgSelected: '{n} {files} geselecteerd', + msgFoldersNotAllowed: 'Drag & drop alleen bestanden! {n} overgeslagen map(pen).', + msgImageWidthSmall: 'Breedte van het foto-bestand "{name}" moet minstens {size} px zijn.', + msgImageHeightSmall: 'Hoogte van het foto-bestand "{name}" moet minstens {size} px zijn.', + msgImageWidthLarge: 'Breedte van het foto-bestand "{name}" kan niet hoger zijn dan {size} px.', + msgImageHeightLarge: 'Hoogte van het foto bestand "{name}" kan niet hoger zijn dan {size} px.', + msgImageResizeError: 'Kon de foto afmetingen niet lezen om te verkleinen.', + msgImageResizeException: 'Fout bij het verkleinen van de foto.<pre>{errors}</pre>', + msgAjaxError: 'Er ging iets mis met de {operation} actie. Gelieve later opnieuw te proberen!', + msgAjaxProgressError: '{operation} mislukt', + ajaxOperations: { + deleteThumb: 'bestand verwijderen', + uploadThumb: 'bestand uploaden', + uploadBatch: 'alle bestanden uploaden', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Drag & drop bestanden hier …', + dropZoneClickTitle: '<br>(of klik hier om {files} te selecteren)', + fileActionSettings: { + removeTitle: 'Verwijder bestand', + uploadTitle: 'bestand uploaden', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Bekijk details', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Nog niet geupload', + indicatorSuccessTitle: 'geupload', + indicatorErrorTitle: 'fout uploaden', + indicatorLoadingTitle: 'uploaden ...' + }, + previewZoomButtonTitles: { + prev: 'Toon vorig bestand', + next: 'Toon volgend bestand', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/no.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/no.js new file mode 100644 index 00000000..773bb1bd --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/no.js @@ -0,0 +1,99 @@ +/*! + * FileInput Norwegian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['no'] = { + fileSingle: 'fil', + filePlural: 'filer', + browseLabel: 'Bla gjennom …', + removeLabel: 'Fjern', + removeTitle: 'Fjern valgte filer', + cancelLabel: 'Avbryt', + cancelTitle: 'Stopp pågående opplastninger', + uploadLabel: 'Last opp', + uploadTitle: 'Last opp valgte filer', + msgNo: 'Nei', + msgNoFilesSelected: 'Ingen filer er valgt', + msgCancelled: 'Avbrutt', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Detaljert visning', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'Filen "{name}" (<b>{size} KB</b>) er for liten og må være større enn <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Filen "{name}" (<b>{size} KB</b>) er for stor, maksimal filstørrelse er <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Du må velge minst <b>{n}</b> {files} for opplastning.', + msgFilesTooMany: 'For mange filer til opplastning, <b>({n})</b> overstiger maksantallet som er <b>{m}</b>.', + msgFileNotFound: 'Fant ikke filen "{name}"!', + msgFileSecured: 'Sikkerhetsrestriksjoner hindrer lesing av filen "{name}".', + msgFileNotReadable: 'Filen "{name}" er ikke lesbar.', + msgFilePreviewAborted: 'Filvisning avbrutt for "{name}".', + msgFilePreviewError: 'En feil oppstod under lesing av filen "{name}".', + msgInvalidFileName: 'Ugyldige tegn i filen "{name}".', + msgInvalidFileType: 'Ugyldig type for filen "{name}". Kun "{types}" filer er tillatt.', + msgInvalidFileExtension: 'Ugyldig endelse for filen "{name}". Kun "{extensions}" filer støttes.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Filopplastningen ble avbrutt', + msgUploadThreshold: 'Prosesserer...', + msgUploadBegin: 'Initialiserer...', + msgUploadEnd: 'Ferdig', + msgUploadEmpty: 'Ingen gyldige data tilgjengelig for opplastning.', + msgUploadError: 'Error', + msgValidationError: 'Valideringsfeil', + msgLoading: 'Laster fil {index} av {files} …', + msgProgress: 'Laster fil {index} av {files} - {name} - {percent}% fullført.', + msgSelected: '{n} {files} valgt', + msgFoldersNotAllowed: 'Kun Dra & slipp filer! Hoppet over {n} mappe(r).', + msgImageWidthSmall: 'Bredde på bildefilen "{name}" må være minst {size} px.', + msgImageHeightSmall: 'Høyde på bildefilen "{name}" må være minst {size} px.', + msgImageWidthLarge: 'Bredde på bildefilen "{name}" kan ikke overstige {size} px.', + msgImageHeightLarge: 'Høyde på bildefilen "{name}" kan ikke overstige {size} px.', + msgImageResizeError: 'Fant ikke dimensjonene som skulle resizes.', + msgImageResizeException: 'En feil oppstod under endring av størrelse .<pre>{errors}</pre>', + msgAjaxError: 'Noe gikk galt med {operation} operasjonen. Vennligst prøv igjen senere!', + msgAjaxProgressError: '{operation} feilet', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Dra & slipp filer her …', + dropZoneClickTitle: '<br>(eller klikk for å velge {files})', + fileActionSettings: { + removeTitle: 'Fjern fil', + uploadTitle: 'Last opp fil', + uploadRetryTitle: 'Retry upload', + zoomTitle: 'Vis detaljer', + dragTitle: 'Flytt / endre rekkefølge', + indicatorNewTitle: 'Opplastning ikke fullført', + indicatorSuccessTitle: 'Opplastet', + indicatorErrorTitle: 'Opplastningsfeil', + indicatorLoadingTitle: 'Laster opp ...' + }, + previewZoomButtonTitles: { + prev: 'Vis forrige fil', + next: 'Vis neste fil', + toggleheader: 'Vis header', + fullscreen: 'Åpne fullskjerm', + borderless: 'Åpne uten kanter', + close: 'Lukk detaljer' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pl.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pl.js new file mode 100644 index 00000000..e19a0ed2 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pl.js @@ -0,0 +1,90 @@ +/*! + * FileInput Polish Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['pl'] = { + fileSingle: 'plik', + filePlural: 'pliki', + browseLabel: 'Przeglądaj …', + removeLabel: 'Usuń', + removeTitle: 'Usuń zaznaczone pliki', + cancelLabel: 'Przerwij', + cancelTitle: 'Anuluj wysyłanie', + uploadLabel: 'Wgraj', + uploadTitle: 'Wgraj zaznaczone pliki', + msgNo: 'Nie', + msgNoFilesSelected: 'Brak zaznaczonych plików', + msgCancelled: 'Odwołany', + msgPlaceholder: 'Wybierz {files}...', + msgZoomModalHeading: 'Szczegółowy podgląd', + msgFileRequired: 'Musisz wybrać plik do wgrania.', + msgSizeTooSmall: 'Plik "{name}" (<b>{size} KB</b>) jest zbyt mały i musi być większy niż <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Plik o nazwie "{name}" (<b>{size} KB</b>) przekroczył maksymalną dopuszczalną wielkość pliku wynoszącą <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Minimalna liczba plików do wgrania: <b>{n}</b>.', + msgFilesTooMany: 'Liczba plików wybranych do wgrania w liczbie <b>({n})</b>, przekracza maksymalny dozwolony limit wynoszący <b>{m}</b>.', + msgFileNotFound: 'Plik "{name}" nie istnieje!', + msgFileSecured: 'Ustawienia zabezpieczeń uniemożliwiają odczyt pliku "{name}".', + msgFileNotReadable: 'Plik "{name}" nie jest plikiem do odczytu.', + msgFilePreviewAborted: 'Podgląd pliku "{name}" został przerwany.', + msgFilePreviewError: 'Wystąpił błąd w czasie odczytu pliku "{name}".', + msgInvalidFileName: 'Nieprawidłowe lub nieobsługiwane znaki w nazwie pliku "{name}".', + msgInvalidFileType: 'Nieznany typ pliku "{name}". Tylko następujące rodzaje plików są dozwolone: "{types}".', + msgInvalidFileExtension: 'Złe rozszerzenie dla pliku "{name}". Tylko następujące rozszerzenia plików są dozwolone: "{extensions}".', + msgUploadAborted: 'Przesyłanie pliku zostało przerwane', + msgUploadThreshold: 'Przetwarzanie...', + msgUploadBegin: 'Rozpoczynanie...', + msgUploadEnd: 'Gotowe!', + msgUploadEmpty: 'Brak poprawnych danych do przesłania.', + msgUploadError: 'Błąd', + msgValidationError: 'Błąd walidacji', + msgLoading: 'Wczytywanie pliku {index} z {files} …', + msgProgress: 'Wczytywanie pliku {index} z {files} - {name} - {percent}% zakończone.', + msgSelected: '{n} Plików zaznaczonych', + msgFoldersNotAllowed: 'Metodą przeciągnij i upuść, można przenosić tylko pliki. Pominięto {n} katalogów.', + msgImageWidthSmall: 'Szerokość pliku obrazu "{name}" musi być co najmniej {size} px.', + msgImageHeightSmall: 'Wysokość pliku obrazu "{name}" musi być co najmniej {size} px.', + msgImageWidthLarge: 'Szerokość pliku obrazu "{name}" nie może przekraczać {size} px.', + msgImageHeightLarge: 'Wysokość pliku obrazu "{name}" nie może przekraczać {size} px.', + msgImageResizeError: 'Nie udało się uzyskać wymiaru obrazu, aby zmienić rozmiar.', + msgImageResizeException: 'Błąd podczas zmiany rozmiaru obrazu.<pre>{errors}</pre>', + msgAjaxError: 'Coś poczło nie tak podczas {operation}. Spróbuj ponownie!', + msgAjaxProgressError: '{operation} nie powiodło się', + ajaxOperations: { + deleteThumb: 'usuwanie pliku', + uploadThumb: 'przesyłanie pliku', + uploadBatch: 'masowe przesyłanie plików', + uploadExtra: 'przesyłanie danych formularza' + }, + dropZoneTitle: 'Przeciągnij i upuść pliki tutaj …', + dropZoneClickTitle: '<br>(lub kliknij tutaj i wybierz {files} z komputera)', + fileActionSettings: { + removeTitle: 'Usuń plik', + uploadTitle: 'Przesyłanie pliku', + uploadRetryTitle: 'Ponów', + downloadTitle: 'Pobierz plik', + zoomTitle: 'Pokaż szczegóły', + dragTitle: 'Przenies / Ponownie zaaranżuj', + indicatorNewTitle: 'Jeszcze nie przesłany', + indicatorSuccessTitle: 'Dodane', + indicatorErrorTitle: 'Błąd', + indicatorLoadingTitle: 'Przesyłanie ...' + }, + previewZoomButtonTitles: { + prev: 'Pokaż poprzedni plik', + next: 'Pokaż następny plik', + toggleheader: 'Włącz / wyłącz nagłówek', + fullscreen: 'Włącz / wyłącz pełny ekran', + borderless: 'Włącz / wyłącz tryb bez ramek', + close: 'Zamknij szczegółowy widok' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pt-BR.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pt-BR.js new file mode 100644 index 00000000..157ac84c --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pt-BR.js @@ -0,0 +1,100 @@ +/*! + * FileInput Brazillian Portuguese Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['pt-BR'] = { + fileSingle: 'arquivo', + filePlural: 'arquivos', + browseLabel: 'Procurar…', + removeLabel: 'Remover', + removeTitle: 'Remover arquivos selecionados', + cancelLabel: 'Cancelar', + cancelTitle: 'Interromper envio em andamento', + uploadLabel: 'Enviar', + uploadTitle: 'Enviar arquivos selecionados', + msgNo: 'Não', + msgNoFilesSelected: 'Nenhum arquivo selecionado', + msgCancelled: 'Cancelado', + msgPlaceholder: 'Selecionar {files}...', + msgZoomModalHeading: 'Pré-visualização detalhada', + msgFileRequired: 'Você deve selecionar um arquivo para enviar.', + msgSizeTooSmall: 'O arquivo "{name}" (<b>{size} KB</b>) é muito pequeno e deve ser maior que <b>{minSize} KB</b>.', + msgSizeTooLarge: 'O arquivo "{name}" (<b>{size} KB</b>) excede o tamanho máximo permitido de <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Você deve selecionar pelo menos <b>{n}</b> {files} para enviar.', + msgFilesTooMany: 'O número de arquivos selecionados para o envio <b>({n})</b> excede o limite máximo permitido de <b>{m}</b>.', + msgFileNotFound: 'O arquivo "{name}" não foi encontrado!', + msgFileSecured: 'Restrições de segurança impedem a leitura do arquivo "{name}".', + msgFileNotReadable: 'O arquivo "{name}" não pode ser lido.', + msgFilePreviewAborted: 'A pré-visualização do arquivo "{name}" foi interrompida.', + msgFilePreviewError: 'Ocorreu um erro ao ler o arquivo "{name}".', + msgInvalidFileName: 'Caracteres inválidos ou não suportados no arquivo "{name}".', + msgInvalidFileType: 'Tipo inválido para o arquivo "{name}". Apenas arquivos "{types}" são permitidos.', + msgInvalidFileExtension: 'Extensão inválida para o arquivo "{name}". Apenas arquivos "{extensions}" são permitidos.', + msgFileTypes: { + 'image': 'imagem', + 'html': 'HTML', + 'text': 'texto', + 'video': 'vídeo', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'objeto' + }, + msgUploadAborted: 'O envio do arquivo foi abortado', + msgUploadThreshold: 'Processando...', + msgUploadBegin: 'Inicializando...', + msgUploadEnd: 'Concluído', + msgUploadEmpty: 'Nenhuma informação válida para upload.', + msgUploadError: 'Erro de Upload', + msgValidationError: 'Erro de validação', + msgLoading: 'Enviando arquivo {index} de {files}…', + msgProgress: 'Enviando arquivo {index} de {files} - {name} - {percent}% completo.', + msgSelected: '{n} {files} selecionado(s)', + msgFoldersNotAllowed: 'Arraste e solte apenas arquivos! {n} pasta(s) ignoradas.', + msgImageWidthSmall: 'Largura do arquivo de imagem "{name}" deve ser pelo menos {size} px.', + msgImageHeightSmall: 'Altura do arquivo de imagem "{name}" deve ser pelo menos {size} px.', + msgImageWidthLarge: 'Largura do arquivo de imagem "{name}" não pode exceder {size} px.', + msgImageHeightLarge: 'Altura do arquivo de imagem "{name}" não pode exceder {size} px.', + msgImageResizeError: 'Não foi possível obter as dimensões da imagem para redimensionar.', + msgImageResizeException: 'Erro ao redimensionar a imagem.<pre>{errors}</pre>', + msgAjaxError: 'Algo deu errado com a operação {operation}. Por favor tente novamente mais tarde!', + msgAjaxProgressError: '{operation} falhou', + ajaxOperations: { + deleteThumb: 'Exclusão de arquivo', + uploadThumb: 'Upload de arquivos', + uploadBatch: 'Carregamento de arquivos em lote', + uploadExtra: 'Carregamento de dados do formulário' + }, + dropZoneTitle: 'Arraste e solte os arquivos aqui…', + dropZoneClickTitle: '<br>(ou clique para selecionar o(s) arquivo(s))', + fileActionSettings: { + removeTitle: 'Remover arquivo', + uploadTitle: 'Enviar arquivo', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Ver detalhes', + dragTitle: 'Mover / Reordenar', + indicatorNewTitle: 'Ainda não enviado', + indicatorSuccessTitle: 'Enviado', + indicatorErrorTitle: 'Erro', + indicatorLoadingTitle: 'Enviando...' + }, + previewZoomButtonTitles: { + prev: 'Visualizar arquivo anterior', + next: 'Visualizar próximo arquivo', + toggleheader: 'Mostrar cabeçalho', + fullscreen: 'Ativar tela cheia', + borderless: 'Ativar modo sem borda', + close: 'Fechar pré-visualização detalhada' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pt.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pt.js new file mode 100644 index 00000000..419b1761 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/pt.js @@ -0,0 +1,100 @@ +/*! + * FileInput Portuguese Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['pt'] = { + fileSingle: 'ficheiro', + filePlural: 'ficheiros', + browseLabel: 'Procurar …', + removeLabel: 'Remover', + removeTitle: 'Remover ficheiros seleccionados', + cancelLabel: 'Cancelar', + cancelTitle: 'Abortar carregamento ', + uploadLabel: 'Carregar', + uploadTitle: 'Carregar ficheiros seleccionados', + msgNo: 'Não', + msgNoFilesSelected: '', + msgCancelled: 'Cancelado', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Pré-visualização detalhada', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Ficheiro "{name}" (<b>{size} KB</b>) excede o tamanho máximo permido de <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Deve seleccionar pelo menos <b>{n}</b> {files} para fazer upload.', + msgFilesTooMany: 'Número máximo de ficheiros seleccionados <b>({n})</b> excede o limite máximo de <b>{m}</b>.', + msgFileNotFound: 'Ficheiro "{name}" não encontrado!', + msgFileSecured: 'Restrições de segurança preventem a leitura do ficheiro "{name}".', + msgFileNotReadable: 'Ficheiro "{name}" não pode ser lido.', + msgFilePreviewAborted: 'Pré-visualização abortado para o ficheiro "{name}".', + msgFilePreviewError: 'Ocorreu um erro ao ler o ficheiro "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Tipo inválido para o ficheiro "{name}". Apenas ficheiros "{types}" são suportados.', + msgInvalidFileExtension: 'Extensão inválida para o ficheiro "{name}". Apenas ficheiros "{extensions}" são suportados.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'O upload do arquivo foi abortada', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Erro de validação', + msgLoading: 'A carregar ficheiro {index} de {files} …', + msgProgress: 'A carregar ficheiro {index} de {files} - {name} - {percent}% completo.', + msgSelected: '{n} {files} seleccionados', + msgFoldersNotAllowed: 'Arrastar e largar ficheiros apenas! {n} pasta(s) ignoradas.', + msgImageWidthSmall: 'Largura do arquivo de imagem "{name}" deve ser pelo menos {size} px.', + msgImageHeightSmall: 'Altura do arquivo de imagem "{name}" deve ser pelo menos {size} px.', + msgImageWidthLarge: 'Largura do arquivo de imagem "{name}" não pode exceder {size} px.', + msgImageHeightLarge: 'Altura do arquivo de imagem "{name}" não pode exceder {size} px.', + msgImageResizeError: 'Could not get the image dimensions to resize.', + msgImageResizeException: 'Erro ao redimensionar a imagem.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Arrastar e largar ficheiros aqui …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Remover arquivo', + uploadTitle: 'Carregar arquivo', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Ver detalhes', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Ainda não carregou', + indicatorSuccessTitle: 'Carregado', + indicatorErrorTitle: 'Carregar Erro', + indicatorLoadingTitle: 'A carregar ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery);
\ No newline at end of file diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ro.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ro.js new file mode 100644 index 00000000..d31b85bd --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ro.js @@ -0,0 +1,101 @@ +/*! + * FileInput Romanian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author Ciprian Voicu <pictoru@autoportret.ro> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['ro'] = { + fileSingle: 'fișier', + filePlural: 'fișiere', + browseLabel: 'Răsfoiește …', + removeLabel: 'Șterge', + removeTitle: 'Curăță fișierele selectate', + cancelLabel: 'Renunță', + cancelTitle: 'Anulează încărcarea curentă', + uploadLabel: 'Încarcă', + uploadTitle: 'Încarcă fișierele selectate', + msgNo: 'Nu', + msgNoFilesSelected: '', + msgCancelled: 'Anulat', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Previzualizare detaliată', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Fișierul "{name}" (<b>{size} KB</b>) depășește limita maximă de încărcare de <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Trebuie să selectezi cel puțin <b>{n}</b> {files} pentru a încărca.', + msgFilesTooMany: 'Numărul fișierelor pentru încărcare <b>({n})</b> depășește limita maximă de <b>{m}</b>.', + msgFileNotFound: 'Fișierul "{name}" nu a fost găsit!', + msgFileSecured: 'Restricții de securitate previn citirea fișierului "{name}".', + msgFileNotReadable: 'Fișierul "{name}" nu se poate citi.', + msgFilePreviewAborted: 'Fișierului "{name}" nu poate fi previzualizat.', + msgFilePreviewError: 'A intervenit o eroare în încercarea de citire a fișierului "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Tip de fișier incorect pentru "{name}". Sunt suportate doar fișiere de tipurile "{types}".', + msgInvalidFileExtension: 'Extensie incorectă pentru "{name}". Sunt suportate doar extensiile "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Fișierul Încărcarea a fost întrerupt', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Eroare de validare', + msgLoading: 'Se încarcă fișierul {index} din {files} …', + msgProgress: 'Se încarcă fișierul {index} din {files} - {name} - {percent}% încărcat.', + msgSelected: '{n} {files} încărcate', + msgFoldersNotAllowed: 'Se poate doar trăgând fișierele! Se renunță la {n} dosar(e).', + msgImageWidthSmall: 'Lățimea de fișier de imagine "{name}" trebuie să fie de cel puțin {size} px.', + msgImageHeightSmall: 'Înălțimea fișier imagine "{name}" trebuie să fie de cel puțin {size} px.', + msgImageWidthLarge: 'Lățimea de fișier de imagine "{name}" nu poate depăși {size} px.', + msgImageHeightLarge: 'Înălțimea fișier imagine "{name}" nu poate depăși {size} px.', + msgImageResizeError: 'Nu a putut obține dimensiunile imaginii pentru a redimensiona.', + msgImageResizeException: 'Eroare la redimensionarea imaginii.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Trage fișierele aici …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Scoateți fișier', + uploadTitle: 'Incarca fisier', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Vezi detalii', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Nu a încărcat încă', + indicatorSuccessTitle: 'încărcat', + indicatorErrorTitle: 'Încărcați eroare', + indicatorLoadingTitle: 'Se încarcă ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ru.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ru.js new file mode 100644 index 00000000..71c5ff7a --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/ru.js @@ -0,0 +1,101 @@ +/*! + * FileInput Russian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author CyanoFresh <cyanofresh@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['ru'] = { + fileSingle: 'файл', + filePlural: 'файлы', + browseLabel: 'Выбрать …', + removeLabel: 'Удалить', + removeTitle: 'Очистить выбранные файлы', + cancelLabel: 'Отмена', + cancelTitle: 'Отменить текущую загрузку', + uploadLabel: 'Загрузить', + uploadTitle: 'Загрузить выбранные файлы', + msgNo: 'нет', + msgNoFilesSelected: '', + msgCancelled: 'Отменено', + msgPlaceholder: 'Выбрать {files}...', + msgZoomModalHeading: 'Подробное превью', + msgFileRequired: 'Необходимо выбрать файл для загрузки.', + msgSizeTooSmall: 'Файл "{name}" (<b>{size} KB</b>) имеет слишком маленький размер и должен быть больше <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) превышает максимальный размер <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Вы должны выбрать как минимум <b>{n}</b> {files} для загрузки.', + msgFilesTooMany: 'Количество выбранных файлов <b>({n})</b> превышает максимально допустимое количество <b>{m}</b>.', + msgFileNotFound: 'Файл "{name}" не найден!', + msgFileSecured: 'Ограничения безопасности запрещают читать файл "{name}".', + msgFileNotReadable: 'Файл "{name}" невозможно прочитать.', + msgFilePreviewAborted: 'Предпросмотр отменен для файла "{name}".', + msgFilePreviewError: 'Произошла ошибка при чтении файла "{name}".', + msgInvalidFileName: 'Неверные или неподдерживаемые символы в названии файла "{name}".', + msgInvalidFileType: 'Запрещенный тип файла для "{name}". Только "{types}" разрешены.', + msgInvalidFileExtension: 'Запрещенное расширение для файла "{name}". Только "{extensions}" разрешены.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Выгрузка файла прервана', + msgUploadThreshold: 'Обработка...', + msgUploadBegin: 'Инициализация...', + msgUploadEnd: 'Готово', + msgUploadEmpty: 'Недопустимые данные для загрузки', + msgUploadError: 'Ошибка загрузки', + msgValidationError: 'Ошибка проверки', + msgLoading: 'Загрузка файла {index} из {files} …', + msgProgress: 'Загрузка файла {index} из {files} - {name} - {percent}% завершено.', + msgSelected: 'Выбрано файлов: {n}', + msgFoldersNotAllowed: 'Разрешено перетаскивание только файлов! Пропущено {n} папок.', + msgImageWidthSmall: 'Ширина изображения {name} должна быть не меньше {size} px.', + msgImageHeightSmall: 'Высота изображения {name} должна быть не меньше {size} px.', + msgImageWidthLarge: 'Ширина изображения "{name}" не может превышать {size} px.', + msgImageHeightLarge: 'Высота изображения "{name}" не может превышать {size} px.', + msgImageResizeError: 'Не удалось получить размеры изображения, чтобы изменить размер.', + msgImageResizeException: 'Ошибка при изменении размера изображения.<pre>{errors}</pre>', + msgAjaxError: 'Произошла ошибка при выполнении операции {operation}. Повторите попытку позже!', + msgAjaxProgressError: 'Не удалось выполнить {operation}', + ajaxOperations: { + deleteThumb: 'удалить файл', + uploadThumb: 'загрузить файл', + uploadBatch: 'загрузить пакет файлов', + uploadExtra: 'загрузка данных с формы' + }, + dropZoneTitle: 'Перетащите файлы сюда …', + dropZoneClickTitle: '<br>(Или щёлкните, чтобы выбрать {files})', + fileActionSettings: { + removeTitle: 'Удалить файл', + uploadTitle: 'Загрузить файл', + uploadRetryTitle: 'Повторить загрузку', + downloadTitle: 'Загрузить файл', + zoomTitle: 'Посмотреть детали', + dragTitle: 'Переместить / Изменить порядок', + indicatorNewTitle: 'Еще не загружен', + indicatorSuccessTitle: 'Загружен', + indicatorErrorTitle: 'Ошибка загрузки', + indicatorLoadingTitle: 'Загрузка ...' + }, + previewZoomButtonTitles: { + prev: 'Посмотреть предыдущий файл', + next: 'Посмотреть следующий файл', + toggleheader: 'Переключить заголовок', + fullscreen: 'Переключить полноэкранный режим', + borderless: 'Переключить режим без полей', + close: 'Закрыть подробный предпросмотр' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sk.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sk.js new file mode 100644 index 00000000..28d67e9a --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sk.js @@ -0,0 +1,100 @@ +/*! + * FileInput Slovakian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['sk'] = { + fileSingle: 'súbor', + filePlural: 'súbory', + browseLabel: 'Vybrať …', + removeLabel: 'Odstrániť', + removeTitle: 'Vyčistiť vybraté súbory', + cancelLabel: 'Storno', + cancelTitle: 'Prerušiť nahrávanie', + uploadLabel: 'Nahrať', + uploadTitle: 'Nahrať vybraté súbory', + msgNo: 'Nie', + msgNoFilesSelected: '', + msgCancelled: 'Zrušené', + msgPlaceholder: 'Vybrať {files}...', + msgZoomModalHeading: 'Detailný náhľad', + msgFileRequired: 'Musíte vybrať súbor, ktorý chcete nahrať.', + msgSizeTooSmall: 'Súbor "{name}" (<b>{size} KB</b>) je príliš malý, musí mať veľkosť najmenej <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Súbor "{name}" (<b>{size} KB</b>) je príliš veľký, maximálna povolená veľkosť <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Musíte vybrať najmenej <b>{n}</b> {files} pre nahranie.', + msgFilesTooMany: 'Počet vybratých súborov <b>({n})</b> prekročil maximálny povolený limit <b>{m}</b>.', + msgFileNotFound: 'Súbor "{name}" nebol nájdený!', + msgFileSecured: 'Zabezpečenie súboru znemožnilo čítať súbor "{name}".', + msgFileNotReadable: 'Súbor "{name}" nie je čitateľný.', + msgFilePreviewAborted: 'Náhľad súboru bol prerušený pre "{name}".', + msgFilePreviewError: 'Nastala chyba pri načítaní súboru "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Neplatný typ súboru "{name}". Iba "{types}" súborov sú podporované.', + msgInvalidFileExtension: 'Neplatná extenzia súboru "{name}". Iba "{extensions}" súborov sú podporované.', + msgFileTypes: { + 'image': 'obrázok', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Nahrávanie súboru bolo prerušené', + msgUploadThreshold: 'Spracovávam...', + msgUploadBegin: 'Inicializujem...', + msgUploadEnd: 'Hotovo', + msgUploadEmpty: 'Na nahrávanie nie sú k dispozícii žiadne platné údaje.', + msgUploadError: 'Chyba', + msgValidationError: 'Chyba overenia', + msgLoading: 'Nahrávanie súboru {index} z {files} …', + msgProgress: 'Nahrávanie súboru {index} z {files} - {name} - {percent}% dokončené.', + msgSelected: '{n} {files} vybraté', + msgFoldersNotAllowed: 'Tiahni a pusť iba súbory! Vynechané {n} pustené prečinok(y).', + msgImageWidthSmall: 'Šírka obrázku "{name}", musí byť minimálne {size} px.', + msgImageHeightSmall: 'Výška obrázku "{name}", musí byť minimálne {size} px.', + msgImageWidthLarge: 'Šírka obrázku "{name}" nemôže presiahnuť {size} px.', + msgImageHeightLarge: 'Výška obrázku "{name}" nesmie presiahnuť {size} px.', + msgImageResizeError: 'Nepodarilo sa získať veľkosť obrázka pre zmenu veľkosti.', + msgImageResizeException: 'Chyba pri zmene veľkosti obrázka.<pre>{errors}</pre>', + msgAjaxError: 'Pri operácii {operation} sa vyskytla chyba. Skúste to prosím neskôr!', + msgAjaxProgressError: '{operation} - neúspešné', + ajaxOperations: { + deleteThumb: 'odstrániť súbor', + uploadThumb: 'nahrať súbor', + uploadBatch: 'nahrať várku súborov', + uploadExtra: 'odosielanie údajov z formulára' + }, + dropZoneTitle: 'Tiahni a pusť súbory tu …', + dropZoneClickTitle: '<br>(alebo kliknite sem a vyberte {files})', + fileActionSettings: { + removeTitle: 'Odstrániť súbor', + uploadTitle: 'Nahrať súbor', + uploadRetryTitle: 'Znova nahrať', + downloadTitle: 'Stiahnuť súbor', + zoomTitle: 'Zobraziť podrobnosti', + dragTitle: 'Posunúť / Preskládať', + indicatorNewTitle: 'Ešte nenahral', + indicatorSuccessTitle: 'Nahraný', + indicatorErrorTitle: 'Chyba pri nahrávaní', + indicatorLoadingTitle: 'Nahrávanie ...' + }, + previewZoomButtonTitles: { + prev: 'Zobraziť predchádzajúci súbor', + next: 'Zobraziť následujúci súbor', + toggleheader: 'Prepnúť záhlavie', + fullscreen: 'Prepnúť zobrazenie na celú obrazovku', + borderless: 'Prepnúť na bezrámikové zobrazenie', + close: 'Zatvoriť detailný náhľad' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sl.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sl.js new file mode 100644 index 00000000..490d7d61 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sl.js @@ -0,0 +1,98 @@ +/*! + * FileInput Slovenian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author kv1dr <kv1dr.android@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['sl'] = { + fileSingle: 'datoteka', + filePlural: 'datotek', + browseLabel: 'Prebrskaj …', + removeLabel: 'Odstrani', + removeTitle: 'Počisti izbrane datoteke', + cancelLabel: 'Prekliči', + cancelTitle: 'Prekliči nalaganje', + uploadLabel: 'Naloži', + uploadTitle: 'Naloži izbrane datoteke', + msgNo: 'Ne', + msgNoFilesSelected: 'Nobena datoteka ni izbrana', + msgCancelled: 'Preklicano', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Podroben predogled', + msgSizeTooLarge: 'Datoteka "{name}" (<b>{size} KB</b>) presega največjo dovoljeno velikost za nalaganje <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Za nalaganje morate izbrati vsaj <b>{n}</b> {files}.', + msgFilesTooMany: 'Število datotek, izbranih za nalaganje <b>({n})</b> je prekoračilo največjo dovoljeno število <b>{m}</b>.', + msgFileNotFound: 'Datoteka "{name}" ni bila najdena!', + msgFileSecured: 'Zaradi varnostnih omejitev nisem mogel prebrati datoteko "{name}".', + msgFileNotReadable: 'Datoteka "{name}" ni berljiva.', + msgFilePreviewAborted: 'Predogled datoteke "{name}" preklican.', + msgFilePreviewError: 'Pri branju datoteke "{name}" je prišlo do napake.', + msgInvalidFileType: 'Napačen tip datoteke "{name}". Samo "{types}" datoteke so podprte.', + msgInvalidFileExtension: 'Napačna končnica datoteke "{name}". Samo "{extensions}" datoteke so podprte.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Nalaganje datoteke je bilo preklicano', + msgUploadThreshold: 'Procesiram...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Napaki pri validiranju', + msgLoading: 'Nalaganje datoteke {index} od {files} …', + msgProgress: 'Nalaganje datoteke {index} od {files} - {name} - {percent}% dokončano.', + msgSelected: '{n} {files} izbrano', + msgFoldersNotAllowed: 'Povlecite in spustite samo datoteke! Izpuščenih je bilo {n} map.', + msgImageWidthSmall: 'Širina slike "{name}" mora biti vsaj {size} px.', + msgImageHeightSmall: 'Višina slike "{name}" mora biti vsaj {size} px.', + msgImageWidthLarge: 'Širina slike "{name}" ne sme preseči {size} px.', + msgImageHeightLarge: 'Višina slike "{name}" ne sme preseči {size} px.', + msgImageResizeError: 'Nisem mogel pridobiti dimenzij slike za spreminjanje velikosti.', + msgImageResizeException: 'Napaka pri spreminjanju velikosti slike.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Povlecite in spustite datoteke sem …', + dropZoneClickTitle: '<br>(ali kliknite sem za izbiro {files})', + fileActionSettings: { + removeTitle: 'Odstrani datoteko', + uploadTitle: 'Naloži datoteko', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Poglej podrobnosti', + dragTitle: 'Premaki / Razporedi', + indicatorNewTitle: 'Še ni naloženo', + indicatorSuccessTitle: 'Naloženo', + indicatorErrorTitle: 'Napaka pri nalaganju', + indicatorLoadingTitle: 'Nalagam ...' + }, + previewZoomButtonTitles: { + prev: 'Poglej prejšno datoteko', + next: 'Poglej naslednjo datoteko', + toggleheader: 'Preklopi glavo', + fullscreen: 'Preklopi celozaslonski način', + borderless: 'Preklopi način brez robov', + close: 'Zapri predogled podrobnosti' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sv.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sv.js new file mode 100644 index 00000000..038b1d99 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/sv.js @@ -0,0 +1,99 @@ +/*! + * FileInput <_LANG_> Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['sv'] = { + fileSingle: 'fil', + filePlural: 'filer', + browseLabel: 'Bläddra …', + removeLabel: 'Ta bort', + removeTitle: 'Rensa valda filer', + cancelLabel: 'Avbryt', + cancelTitle: 'Avbryt pågående uppladdning', + uploadLabel: 'Ladda upp', + uploadTitle: 'Ladda upp valda filer', + msgNo: 'Nej', + msgNoFilesSelected: 'Inga filer valda', + msgCancelled: 'Avbruten', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'detaljerad förhandsgranskning', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'Filen "{name}" (<b>{size} KB</b>) är för liten och måste vara större än <b>{minSize} KB</b>.', + msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) överstiger högsta tillåtna uppladdningsstorlek <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Du måste välja minst <b>{n}</b> {files} för att ladda upp.', + msgFilesTooMany: 'Antal filer valda för uppladdning <b>({n})</b> överstiger högsta tillåtna gränsen <b>{m}</b>.', + msgFileNotFound: 'Filen "{name}" kunde inte hittas!', + msgFileSecured: 'Säkerhetsbegränsningar förhindrar att läsa filen "{name}".', + msgFileNotReadable: 'Filen "{name}" är inte läsbar.', + msgFilePreviewAborted: 'Filförhandsvisning avbröts för "{name}".', + msgFilePreviewError: 'Ett fel uppstod vid inläsning av filen "{name}".', + msgInvalidFileName: 'Ogiltiga eller tecken som inte stöds i filnamnet "{name}".', + msgInvalidFileType: 'Ogiltig typ för filen "{name}". Endast "{types}" filtyper stöds.', + msgInvalidFileExtension: 'Ogiltigt filtillägg för filen "{name}". Endast "{extensions}" filer stöds.', + msgFileTypes: { + 'image': 'bild', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'ljud', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'objekt' + }, + msgUploadAborted: 'Filöverföringen avbröts', + msgUploadThreshold: 'Bearbetar...', + msgUploadBegin: 'Påbörjar...', + msgUploadEnd: 'Färdig', + msgUploadEmpty: 'Ingen giltig data tillgänglig för uppladdning.', + msgUploadError: 'Error', + msgValidationError: 'Valideringsfel', + msgLoading: 'Laddar fil {index} av {files} …', + msgProgress: 'Laddar fil {index} av {files} - {name} - {percent}% färdig.', + msgSelected: '{n} {files} valda', + msgFoldersNotAllowed: 'Endast drag & släppfiler! Skippade {n} släpta mappar.', + msgImageWidthSmall: 'Bredd på bildfilen "{name}" måste minst vara {size} pixlar.', + msgImageHeightSmall: 'Höjden på bildfilen "{name}" måste minst vara {size} pixlar.', + msgImageWidthLarge: 'Bredd på bildfil "{name}" kan inte överstiga {size} pixlar.', + msgImageHeightLarge: 'Höjden på bildfilen "{name}" kan inte överstiga {size} pixlar.', + msgImageResizeError: 'Det gick inte att hämta bildens dimensioner för att ändra storlek.', + msgImageResizeException: 'Fel vid storleksändring av bilden.<pre>{errors}</pre>', + msgAjaxError: 'Något gick fel med {operation} operationen. Försök igen senare!', + msgAjaxProgressError: '{operation} misslyckades', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Drag & släpp filer här …', + dropZoneClickTitle: '<br>(eller klicka för att markera {files})', + fileActionSettings: { + removeTitle: 'Ta bort fil', + uploadTitle: 'Ladda upp fil', + uploadRetryTitle: 'Retry upload', + zoomTitle: 'Visa detaljer', + dragTitle: 'Flytta / Ändra ordning', + indicatorNewTitle: 'Inte uppladdat ännu', + indicatorSuccessTitle: 'Uppladdad', + indicatorErrorTitle: 'Uppladdningsfel', + indicatorLoadingTitle: 'Laddar upp...' + }, + previewZoomButtonTitles: { + prev: 'Visa föregående fil', + next: 'Visa nästa fil', + toggleheader: 'Rubrik', + fullscreen: 'Fullskärm', + borderless: 'Gränslös', + close: 'Stäng detaljerad förhandsgranskning' + } + }; +})(window.jQuery);
\ No newline at end of file diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/th.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/th.js new file mode 100644 index 00000000..7a2d0460 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/th.js @@ -0,0 +1,100 @@ +/*! + * FileInput Thai Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['th'] = { + fileSingle: 'ไฟล์', + filePlural: 'ไฟล์', + browseLabel: 'เลือกดู …', + removeLabel: 'ลบทิ้ง', + removeTitle: 'ลบไฟล์ที่เลือกทิ้ง', + cancelLabel: 'ยกเลิก', + cancelTitle: 'ยกเลิกการอัพโหลด', + uploadLabel: 'อัพโหลด', + uploadTitle: 'อัพโหลดไฟล์ที่เลือก', + msgNo: 'ไม่', + msgNoFilesSelected: '', + msgCancelled: 'ยกเลิก', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'ตัวอย่างละเอียด', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'ไฟล์ "{name}" (<b>{size} KB</b>) มีขนาดเกินที่ระบบอนุญาตที่ <b>{maxSize} KB</b>, กรุณาลองใหม่อีกครั้ง!', + msgFilesTooLess: 'คุณต้องเลือกไฟล์จำนวนอย่างน้อย <b>{n}</b> {files} เพื่ออัพโหลด, กรุณาลองใหม่อีกครั้ง!', + msgFilesTooMany: 'ไฟล์ที่คุณเลือกมีจำนวน <b>({n})</b> ซึ่งเกินกว่าที่ระบบอนุญาตที่ <b>{m}</b>, กรุณาลองใหม่อีกครั้ง!', + msgFileNotFound: 'ไม่พบไฟล์ "{name}" !', + msgFileSecured: 'ระบบความปลอดภัยไม่อนุญาตให้อ่านไฟล์ "{name}".', + msgFileNotReadable: 'ไม่สามารถอ่านไฟล์ "{name}" ได้', + msgFilePreviewAborted: 'ไฟล์ "{name}" ไม่อนุญาตให้ดูตัวอย่าง', + msgFilePreviewError: 'พบปัญหาในการดูตัวอย่างไฟล์ "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'ไฟล์ "{name}" เป็นประเภทไฟล์ที่ไม่ถูกต้อง, อนุญาตเฉพาะไฟล์ประเภท "{types}"', + msgInvalidFileExtension: 'ไฟล์ "{name}" เป็น extension ที่ไมถูกต้อง, อนุญาตเฉพาะไฟล์ extension "{extensions}"', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'อัปโหลดไฟล์ถูกยกเลิก', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'ข้อผิดพลาดในการตรวจสอบ', + msgLoading: 'กำลังโหลดไฟล์ {index} จาก {files} …', + msgProgress: 'กำลังโหลดไฟล์ {index} จาก {files} - {name} - {percent}%', + msgSelected: '{n} {files} ถูกเลือก', + msgFoldersNotAllowed: 'Drag & drop เฉพาะไฟล์เท่านั้น! ข้าม dropped folder จำนวน {n}', + msgImageWidthSmall: 'ความกว้างของภาพไฟล์ "{name}" ต้องมีอย่างน้อย {size} px.', + msgImageHeightSmall: 'ความสูงของภาพไฟล์ "{name}" ต้องมีอย่างน้อย {size} px.', + msgImageWidthLarge: 'ความกว้างของภาพไฟล์ "{name}" ไม่เกิน {size} พิกเซล.', + msgImageHeightLarge: 'ความสูงของไฟล์ภาพ "{name}" ไม่เกิน {size} พิกเซล.', + msgImageResizeError: 'ไม่สามารถรับขนาดภาพเพื่อปรับขนาด', + msgImageResizeException: 'ข้อผิดพลาดขณะปรับขนาดภาพ<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Drag & drop ไฟล์ตรงนี้ …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'ลบไฟล์', + uploadTitle: 'อัปโหลดไฟล์', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'ดูรายละเอียด', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'ยังไม่ได้อัปโหลด', + indicatorSuccessTitle: 'อัพโหลด', + indicatorErrorTitle: 'อัปโหลดข้อผิดพลาด', + indicatorLoadingTitle: 'อัพโหลด ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery);
\ No newline at end of file diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/tr.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/tr.js new file mode 100644 index 00000000..ff4d9555 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/tr.js @@ -0,0 +1,99 @@ +/*! + * FileInput Turkish Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['tr'] = { + fileSingle: 'dosya', + filePlural: 'dosyalar', + browseLabel: 'Gözat …', + removeLabel: 'Sil', + removeTitle: 'Seçilen dosyaları sil', + cancelLabel: 'İptal', + cancelTitle: 'Devam eden yüklemeyi iptal et', + uploadLabel: 'Yükle', + uploadTitle: 'Seçilen dosyaları yükle', + msgNo: 'Hayır', + msgNoFilesSelected: '', + msgCancelled: 'İptal edildi', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Detaylı Önizleme', + msgFileRequired: 'Yüklemek için bir dosya seçmelisiniz.', + msgSizeTooSmall: '"{name}"(<b>{size} KB</b>) dosyası çok küçük ve <b>{minSize} KB</b> boyutundan büyük olmalıdır.', + msgSizeTooLarge: '"{name}" dosyasının boyutu (<b>{size} KB</b>) izin verilen azami dosya boyutu olan <b>{maxSize} KB</b>\'tan büyük.', + msgFilesTooLess: 'Yüklemek için en az <b>{n}</b> {files} dosya seçmelisiniz.', + msgFilesTooMany: 'Yüklemek için seçtiğiniz dosya sayısı <b>({n})</b> azami limitin <b>({m})</b> altında olmalıdır.', + msgFileNotFound: '"{name}" dosyası bulunamadı!', + msgFileSecured: 'Güvenlik kısıtlamaları "{name}" dosyasının okunmasını engelliyor.', + msgFileNotReadable: '"{name}" dosyası okunabilir değil.', + msgFilePreviewAborted: '"{name}" dosyası için önizleme iptal edildi.', + msgFilePreviewError: '"{name}" dosyası okunurken bir hata oluştu.', + msgInvalidFileName: '"{name}" dosya adında geçersiz veya desteklenmeyen karakterler var.', + msgInvalidFileType: '"{name}" dosyasının türü geçerli değil. Yalnızca "{types}" türünde dosyalara izin veriliyor.', + msgInvalidFileExtension: '"{name}" dosyasının uzantısı geçersiz. Yalnızca "{extensions}" uzantılı dosyalara izin veriliyor.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Dosya yükleme iptal edildi', + msgUploadThreshold: 'İşlem yapılıyor...', + msgUploadBegin: 'Başlıyor...', + msgUploadEnd: 'Başarılı', + msgUploadEmpty: 'Yüklemek için geçerli veri mevcut değil.', + msgUploadError: 'Error', + msgValidationError: 'Doğrulama Hatası', + msgLoading: 'Dosya yükleniyor {index} / {files} …', + msgProgress: 'Dosya yükleniyor {index} / {files} - {name} - %{percent} tamamlandı.', + msgSelected: '{n} {files} seçildi', + msgFoldersNotAllowed: 'Yalnızca dosyaları sürükleyip bırakabilirsiniz! {n} dizin(ler) göz ardı edildi.', + msgImageWidthSmall: '"{name}" adlı görüntü dosyasının genişliği en az {size} piksel olmalıdır.', + msgImageHeightSmall: '"{name}" adlı görüntü dosyasının yüksekliği en az {size} piksel olmalıdır.', + msgImageWidthLarge: '"{name}" adlı görüntü dosyasının genişliği {size} pikseli geçemez.', + msgImageHeightLarge: '"{name}" adlı görüntü dosyasının yüksekliği {size} pikseli geçemez.', + msgImageResizeError: 'Görüntü boyutlarını yeniden boyutlandıramadı.', + msgImageResizeException: 'Görüntü boyutlandırma sırasında hata.<pre>{errors}</pre>', + msgAjaxError: '{operation} işlemi ile ilgili bir şeyler ters gitti. Lütfen daha sonra tekrar deneyiniz!', + msgAjaxProgressError: '{operation} işlemi başarısız oldu.', + ajaxOperations: { + deleteThumb: 'dosya silme', + uploadThumb: 'dosya yükleme', + uploadBatch: 'toplu dosya yükleme', + uploadExtra: 'form verisi yükleme' + }, + dropZoneTitle: 'Dosyaları buraya sürükleyip bırakın', + dropZoneClickTitle: '<br>(ya da {files} seçmek için tıklayınız)', + fileActionSettings: { + removeTitle: 'Dosyayı kaldır', + uploadTitle: 'Dosyayı yükle', + uploadRetryTitle: 'Retry upload', + zoomTitle: 'Ayrıntıları görüntüle', + dragTitle: 'Taşı / Yeniden düzenle', + indicatorNewTitle: 'Henüz yüklenmedi', + indicatorSuccessTitle: 'Yüklendi', + indicatorErrorTitle: 'Yükleme Hatası', + indicatorLoadingTitle: 'Yükleniyor ...' + }, + previewZoomButtonTitles: { + prev: 'Önceki dosyayı göster', + next: 'Sonraki dosyayı göster', + toggleheader: 'Üst bilgi geçiş', + fullscreen: 'Tam ekran geçiş', + borderless: 'Çerçevesiz moda geçiş', + close: 'Detaylı önizlemeyi kapat' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/uk.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/uk.js new file mode 100644 index 00000000..99294f19 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/uk.js @@ -0,0 +1,101 @@ +/*! + * FileInput Ukrainian Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author CyanoFresh <cyanofresh@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['uk'] = { + fileSingle: 'файл', + filePlural: 'файли', + browseLabel: 'Вибрати …', + removeLabel: 'Видалити', + removeTitle: 'Видалити вибрані файли', + cancelLabel: 'Скасувати', + cancelTitle: 'Скасувати поточну загрузку', + uploadLabel: 'Загрузити', + uploadTitle: 'Загрузити вибрані файли', + msgNo: 'Немає', + msgNoFilesSelected: '', + msgCancelled: 'Cкасовано', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Детальний превью', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) перевищує максимальний розмір <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Ви повинні вибрати як мінімум <b>{n}</b> {files} для загрузки.', + msgFilesTooMany: 'Кількість вибраних файлів <b>({n})</b> перевищує максимально допустиму кількість <b>{m}</b>.', + msgFileNotFound: 'Файл "{name}" не знайдено!', + msgFileSecured: 'Обмеження безпеки перешкоджають читанню файла "{name}".', + msgFileNotReadable: 'Файл "{name}" неможливо прочитати.', + msgFilePreviewAborted: 'Перегляд скасований для файла "{name}".', + msgFilePreviewError: 'Сталася помилка під час читання файла "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Заборонений тип файла для "{name}". Тільки "{types}" дозволені.', + msgInvalidFileExtension: 'Заборонене розширення для файла "{name}". Тільки "{extensions}" дозволені.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Вивантаження файлу перервана', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Помилка перевірки', + msgLoading: 'Загрузка файла {index} із {files} …', + msgProgress: 'Загрузка файла {index} із {files} - {name} - {percent}% завершено.', + msgSelected: '{n} {files} вибрано', + msgFoldersNotAllowed: 'Дозволено перетягувати тільки файли! Пропущено {n} папок.', + msgImageWidthSmall: 'Ширина зображення "{name}" повинна бути не менше {size} px.', + msgImageHeightSmall: 'Висота зображення "{name}" повинна бути не менше {size} px.', + msgImageWidthLarge: 'Ширина зображення "{name}" не може перевищувати {size} px.', + msgImageHeightLarge: 'Висота зображення "{name}" не може перевищувати {size} px.', + msgImageResizeError: 'Не вдалося розміри зображення, щоб змінити розмір.', + msgImageResizeException: 'Помилка при зміні розміру зображення.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Перетягніть файли сюди …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: 'Видалити файл', + uploadTitle: 'Загрузити файл', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Подивитися деталі', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: 'Ще не загружено', + indicatorSuccessTitle: 'Загружено', + indicatorErrorTitle: 'Помилка при загрузці', + indicatorLoadingTitle: 'Загрузка ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/vi.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/vi.js new file mode 100644 index 00000000..7d140b5e --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/vi.js @@ -0,0 +1,101 @@ +/*! + * FileInput Vietnamese Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ + +(function ($) { + "use strict"; + + $.fn.fileinputLocales['vi'] = { + fileSingle: 'tập tin', + filePlural: 'các tập tin', + browseLabel: 'Duyệt …', + removeLabel: 'Gỡ bỏ', + removeTitle: 'Bỏ tập tin đã chọn', + cancelLabel: 'Hủy', + cancelTitle: 'Hủy upload', + uploadLabel: 'Upload', + uploadTitle: 'Upload tập tin đã chọn', + msgNo: 'Không', + msgNoFilesSelected: 'Không tập tin nào được chọn', + msgCancelled: 'Đã hủy', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Chi tiết xem trước', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: 'Tập tin "{name}" (<b>{size} KB</b>) vượt quá kích thước giới hạn cho phép <b>{maxSize} KB</b>.', + msgFilesTooLess: 'Bạn phải chọn ít nhất <b>{n}</b> {files} để upload.', + msgFilesTooMany: 'Số lượng tập tin upload <b>({n})</b> vượt quá giới hạn cho phép là <b>{m}</b>.', + msgFileNotFound: 'Không tìm thấy tập tin "{name}"!', + msgFileSecured: 'Các hạn chế về bảo mật không cho phép đọc tập tin "{name}".', + msgFileNotReadable: 'Không đọc được tập tin "{name}".', + msgFilePreviewAborted: 'Đã dừng xem trước tập tin "{name}".', + msgFilePreviewError: 'Đã xảy ra lỗi khi đọc tập tin "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Tập tin "{name}" không hợp lệ. Chỉ hỗ trợ loại tập tin "{types}".', + msgInvalidFileExtension: 'Phần mở rộng của tập tin "{name}" không hợp lệ. Chỉ hỗ trợ phần mở rộng "{extensions}".', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'Đã dừng upload', + msgUploadThreshold: 'Đang xử lý...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Lỗi xác nhận', + msgLoading: 'Đang nạp {index} tập tin trong số {files} …', + msgProgress: 'Đang nạp {index} tập tin trong số {files} - {name} - {percent}% hoàn thành.', + msgSelected: '{n} {files} được chọn', + msgFoldersNotAllowed: 'Chỉ kéo thả tập tin! Đã bỏ qua {n} thư mục.', + msgImageWidthSmall: 'Chiều rộng của hình ảnh "{name}" phải tối thiểu là {size} px.', + msgImageHeightSmall: 'Chiều cao của hình ảnh "{name}" phải tối thiểu là {size} px.', + msgImageWidthLarge: 'Chiều rộng của hình ảnh "{name}" không được quá {size} px.', + msgImageHeightLarge: 'Chiều cao của hình ảnh "{name}" không được quá {size} px.', + msgImageResizeError: 'Không lấy được kích thước của hình ảnh để resize.', + msgImageResizeException: 'Resize hình ảnh bị lỗi.<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Kéo thả tập tin vào đây …', + dropZoneClickTitle: '<br>(hoặc click để chọn {files})', + fileActionSettings: { + removeTitle: 'Gỡ bỏ', + uploadTitle: 'Upload tập tin', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: 'Phóng lớn', + dragTitle: 'Di chuyển / Sắp xếp lại', + indicatorNewTitle: 'Chưa được upload', + indicatorSuccessTitle: 'Đã upload', + indicatorErrorTitle: 'Upload bị lỗi', + indicatorLoadingTitle: 'Đang upload ...' + }, + previewZoomButtonTitles: { + prev: 'Xem tập tin phía trước', + next: 'Xem tập tin tiếp theo', + toggleheader: 'Ẩn/hiện tiêu đề', + fullscreen: 'Bật/tắt toàn màn hình', + borderless: 'Bật/tắt chế độ không viền', + close: 'Đóng' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/zh-TW.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/zh-TW.js new file mode 100644 index 00000000..3f7986a9 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/zh-TW.js @@ -0,0 +1,102 @@ +/*! + * FileInput Chinese Traditional Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author kangqf <kangqingfei@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['zh-TW'] = { + fileSingle: '單一檔案', + filePlural: '複選檔案', + browseLabel: '瀏覽 …', + removeLabel: '移除', + removeTitle: '清除選取檔案', + cancelLabel: '取消', + cancelTitle: '取消上傳中檔案', + uploadLabel: '上傳', + uploadTitle: '上傳選取檔案', + msgNo: '沒有', + msgNoFilesSelected: '', + msgCancelled: '取消', + zoomTitle: '詳細資料', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: '內容預覽', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.', + msgSizeTooLarge: '檔案 "{name}" (<b>{size} KB</b>) 大小超過上限 <b>{maxSize} KB</b>.', + msgFilesTooLess: '最少必須選擇 <b>{n}</b> {files} 來上傳. ', + msgFilesTooMany: '上傳的檔案數量 <b>({n})</b> 超過最大檔案上傳限制 <b>{m}</b>.', + msgFileNotFound: '檔案 "{name}" 未發現!', + msgFileSecured: '安全限制,禁止讀取檔案 "{name}".', + msgFileNotReadable: '文件 "{name}" 不可讀取.', + msgFilePreviewAborted: '檔案 "{name}" 預覽中止.', + msgFilePreviewError: '讀取 "{name}" 發生錯誤.', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: '檔案類型錯誤 "{name}". 只能使用 "{types}" 類型的檔案.', + msgInvalidFileExtension: '附檔名錯誤 "{name}". 只能使用 "{extensions}" 的檔案.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: '該文件上傳被中止', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: '驗證錯誤', + msgLoading: '載入第 {index} 個檔案,共 {files} …', + msgProgress: '載入第 {index} 個檔案,共 {files} - {name} - {percent}% 成功.', + msgSelected: '{n} {files} 選取', + msgFoldersNotAllowed: '只支援單檔拖曳! 無法使用 {n} 拖拽的資料夹.', + msgImageWidthSmall: '圖檔寬度"{name}"必須至少為{size}像素(px).', + msgImageHeightSmall: '圖檔高度"{name}"必須至少為{size}像素(px).', + msgImageWidthLarge: '圖檔寬度"{name}"不能超過{size}像素(px).', + msgImageHeightLarge: '圖檔高度"{name}"不能超過{size}像素(px).', + msgImageResizeError: '無法獲取的圖像尺寸調整。', + msgImageResizeException: '錯誤而調整圖像大小。<pre>{errors}</pre>', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: '拖曳檔案至此 …', + dropZoneClickTitle: '<br>(or click to select {files})', + fileActionSettings: { + removeTitle: '刪除檔案', + uploadTitle: '上傳檔案', + uploadRetryTitle: 'Retry upload', + downloadTitle: 'Download file', + zoomTitle: '詳細資料', + dragTitle: 'Move / Rearrange', + indicatorNewTitle: '尚未上傳', + indicatorSuccessTitle: '上傳成功', + indicatorErrorTitle: '上傳失敗', + indicatorLoadingTitle: '上傳中 ...' + }, + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/zh.js b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/zh.js new file mode 100644 index 00000000..0e2ed3a5 --- /dev/null +++ b/kvision-modules/kvision-upload/src/main/resources/js/locales/bootstrap-fileinput/zh.js @@ -0,0 +1,100 @@ +/*! + * FileInput Chinese Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author kangqf <kangqingfei@gmail.com> + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['zh'] = { + fileSingle: '文件', + filePlural: '个文件', + browseLabel: '选择 …', + removeLabel: '移除', + removeTitle: '清除选中文件', + cancelLabel: '取消', + cancelTitle: '取消进行中的上传', + uploadLabel: '上传', + uploadTitle: '上传选中文件', + msgNo: '没有', + msgNoFilesSelected: '', + msgCancelled: '取消', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: '详细预览', + msgFileRequired: '必须选择一个文件上传.', + msgSizeTooSmall: '文件 "{name}" (<b>{size} KB</b>) 必须大于限定大小 <b>{minSize} KB</b>.', + msgSizeTooLarge: '文件 "{name}" (<b>{size} KB</b>) 超过了允许大小 <b>{maxSize} KB</b>.', + msgFilesTooLess: '你必须选择最少 <b>{n}</b> {files} 来上传. ', + msgFilesTooMany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>.', + msgFileNotFound: '文件 "{name}" 未找到!', + msgFileSecured: '安全限制,为了防止读取文件 "{name}".', + msgFileNotReadable: '文件 "{name}" 不可读.', + msgFilePreviewAborted: '取消 "{name}" 的预览.', + msgFilePreviewError: '读取 "{name}" 时出现了一个错误.', + msgInvalidFileName: '文件名 "{name}" 包含非法字符.', + msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.', + msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: '该文件上传被中止', + msgUploadThreshold: '处理中...', + msgUploadBegin: '正在初始化...', + msgUploadEnd: '完成', + msgUploadEmpty: '无效的文件上传.', + msgUploadError: 'Error', + msgValidationError: '验证错误', + msgLoading: '加载第 {index} 文件 共 {files} …', + msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.', + msgSelected: '{n} {files} 选中', + msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.', + msgImageWidthSmall: '图像文件的"{name}"的宽度必须是至少{size}像素.', + msgImageHeightSmall: '图像文件的"{name}"的高度必须至少为{size}像素.', + msgImageWidthLarge: '图像文件"{name}"的宽度不能超过{size}像素.', + msgImageHeightLarge: '图像文件"{name}"的高度不能超过{size}像素.', + msgImageResizeError: '无法获取的图像尺寸调整。', + msgImageResizeException: '调整图像大小时发生错误。<pre>{errors}</pre>', + msgAjaxError: '{operation} 发生错误. 请重试!', + msgAjaxProgressError: '{operation} 失败', + ajaxOperations: { + deleteThumb: '删除文件', + uploadThumb: '上传文件', + uploadBatch: '批量上传', + uploadExtra: '表单数据上传' + }, + dropZoneTitle: '拖拽文件到这里 …<br>支持多文件同时上传', + dropZoneClickTitle: '<br>(或点击{files}按钮选择文件)', + fileActionSettings: { + removeTitle: '删除文件', + uploadTitle: '上传文件', + uploadRetryTitle: 'Retry upload', + zoomTitle: '查看详情', + dragTitle: '移动 / 重置', + indicatorNewTitle: '没有上传', + indicatorSuccessTitle: '上传', + indicatorErrorTitle: '上传错误', + indicatorLoadingTitle: '上传 ...' + }, + previewZoomButtonTitles: { + prev: '预览上一个文件', + next: '预览下一个文件', + toggleheader: '缩放', + fullscreen: '全屏', + borderless: '无边界模式', + close: '关闭当前预览' + } + }; +})(window.jQuery); diff --git a/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt b/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt new file mode 100644 index 00000000..1da1fe1a --- /dev/null +++ b/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision + +import org.w3c.dom.Element +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.panel.Root +import kotlin.browser.document +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +interface TestSpec { + fun beforeTest() + + fun afterTest() + + fun run(code: () -> Unit) { + beforeTest() + code() + afterTest() + } +} + +interface SimpleSpec : TestSpec { + + override fun beforeTest() { + } + + override fun afterTest() { + } + +} + +interface DomSpec : TestSpec { + + override fun beforeTest() { + val fixture = "<div style=\"display: none\" id=\"pretest\">" + + "<div id=\"test\"></div></div>" + document.body?.insertAdjacentHTML("afterbegin", fixture) + } + + override fun afterTest() { + val div = document.getElementById("pretest") + div?.let { jQuery(it).remove() } + jQuery(`object` = ".modal-backdrop").remove() + } + + fun assertEqualsHtml(expected: String?, actual: String?, message: String?) { + if (expected != null && actual != null) { + val exp = jQuery(html = expected) + val act = jQuery(html = actual) + val result = exp[0]?.isEqualNode(act[0]) + if (result == true) { + assertTrue(result == true, message) + } else { + assertEquals(expected, actual, message) + } + } else { + assertEquals(expected, actual, message) + } + } +} + +interface WSpec : DomSpec { + + fun runW(code: (widget: Widget, element: Element?) -> Unit) { + run { + val root = Root("test", true) + val widget = Widget() + widget.id = "test_id" + root.add(widget) + val element = document.getElementById("test_id") + code(widget, element) + } + } + +} + +external fun require(name: String): dynamic diff --git a/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/form/upload/UploadInputSpec.kt b/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/form/upload/UploadInputSpec.kt new file mode 100644 index 00000000..626b70e4 --- /dev/null +++ b/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/form/upload/UploadInputSpec.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.upload + +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.form.upload.UploadInput +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class UploadInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val upi = UploadInput(multiple = true).apply { + id = "idti" + } + root.add(upi) + val content = document.getElementById("test")?.let { jQuery(it).find("input.form-control")[0]?.outerHTML } + assertEqualsHtml( + "<input class=\"form-control\" id=\"idti\" type=\"file\" multiple=\"true\">", + content, + "Should render correct file input control for multiple files" + ) + upi.multiple = false + val content2 = document.getElementById("test")?.let { jQuery(it).find("input.form-control")[0]?.outerHTML } + assertEqualsHtml( + "<input class=\"form-control\" id=\"idti\" type=\"file\">", + content2, + "Should render correct file input control for single file" + ) + } + } + +} diff --git a/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/form/upload/UploadSpec.kt b/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/form/upload/UploadSpec.kt new file mode 100644 index 00000000..bea4ddee --- /dev/null +++ b/kvision-modules/kvision-upload/src/test/kotlin/test/pl/treksoft/kvision/form/upload/UploadSpec.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.form.upload + +import pl.treksoft.jquery.jQuery +import pl.treksoft.kvision.form.upload.Upload +import pl.treksoft.kvision.panel.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class UploadSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", true) + val upi = Upload(multiple = true) + val id = upi.input.id + root.add(upi) + val content = document.getElementById("test")?.let { jQuery(it).find("input.form-control")[0]?.outerHTML } + assertEqualsHtml( + "<input class=\"form-control\" id=\"$id\" type=\"file\" multiple=\"true\">", + content, + "Should render correct file input control for multiple files" + ) + upi.multiple = false + val content2 = document.getElementById("test")?.let { jQuery(it).find("input.form-control")[0]?.outerHTML } + assertEqualsHtml( + "<input class=\"form-control\" id=\"$id\" type=\"file\">", + content2, + "Should render correct file input control for single file" + ) + } + } + +} diff --git a/kvision-modules/shared.gradle b/kvision-modules/shared.gradle new file mode 100644 index 00000000..4ded9c6c --- /dev/null +++ b/kvision-modules/shared.gradle @@ -0,0 +1,65 @@ +apply plugin: 'kotlin-platform-js' +apply plugin: 'org.jetbrains.kotlin.frontend' +apply plugin: 'kotlinx-serialization' + +kotlinFrontend { + + webpackBundle { + bundleName = "main" + contentPath = file('src/main/web') + mode = production ? "production" : "development" + } + + define "PRODUCTION", production +} + + +dependencies { + if (!project.gradle.startParameter.taskNames.contains("generatePomFileForMavenProjectPublication")) { + compile project(":kvision-modules:kvision-base") + } else { + compile rootProject + } +} + +task cleanLibs(type: Delete) { + delete 'build/js', 'build/libs' +} + +if (project.gradle.startParameter.taskNames.contains("jar")) { + compileKotlin2Js.dependsOn 'cleanLibs' +} + +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +compileKotlin2Js { + kotlinOptions.metaInfo = true + kotlinOptions.outputFile = "$project.buildDir.path/js/${project.name}.js" + kotlinOptions.sourceMap = !production + kotlinOptions.moduleKind = 'umd' +} + +compileTestKotlin2Js { + kotlinOptions.metaInfo = true + kotlinOptions.outputFile = "$project.buildDir.path/js-tests/${project.name}-tests.js" + kotlinOptions.sourceMap = !production + kotlinOptions.moduleKind = 'umd' +} + +task copyResources(type: Copy) { + from "src/main/resources" + into file(buildDir.path + "/js") +} + +task copyResourcesForTests(type: Copy) { + from "src/main/resources" + into file(buildDir.path + "/js-tests/") +} + +afterEvaluate { + tasks.getByName("webpack-bundle") { dependsOn(copyResources) } + tasks.getByName("webpack-run") { dependsOn(copyResources) } + tasks.getByName("karma-start") { dependsOn(copyResources, copyResourcesForTests) } +} |