diff options
Diffstat (limited to 'kvision-modules/kvision-bootstrap-datetime')
9 files changed, 933 insertions, 0 deletions
diff --git a/kvision-modules/kvision-bootstrap-datetime/build.gradle b/kvision-modules/kvision-bootstrap-datetime/build.gradle new file mode 100644 index 00000000..8cb14799 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/build.gradle @@ -0,0 +1,13 @@ +apply from: "../shared.gradle" + +dependencies { + compile project(":kvision-modules:kvision-bootstrap") +} + +kotlinFrontend { + + npm { + dependency("pc-bootstrap4-datetimepicker", "4.17.50") + } + +} diff --git a/kvision-modules/kvision-bootstrap-datetime/package.json.d/project.info b/kvision-modules/kvision-bootstrap-datetime/package.json.d/project.info new file mode 100644 index 00000000..3d332806 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/package.json.d/project.info @@ -0,0 +1,3 @@ +{ + "description": "KVision Datetime module" +} diff --git a/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/KVManagerDatetime.kt b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/KVManagerDatetime.kt new file mode 100644 index 00000000..c02a116d --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/KVManagerDatetime.kt @@ -0,0 +1,36 @@ +/* + * 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. + */ +internal object KVManagerDatetime { + init { + require("pc-bootstrap4-datetimepicker/build/css/bootstrap-datetimepicker.min.css") + require("pc-bootstrap4-datetimepicker/build/js/bootstrap-datetimepicker.min.js") + } + + internal fun init() {} +} diff --git a/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt new file mode 100644 index 00000000..b7cf18ec --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.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.time + +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.form.DateFormControl +import pl.treksoft.kvision.form.FieldLabel +import pl.treksoft.kvision.form.InvalidFeedback +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.utils.SnOn +import kotlin.js.Date + +/** + * 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: Date? = null, name: String? = null, format: String = "YYYY-MM-DD HH:mm", label: String? = null, + rich: Boolean = false +) : SimplePanel(setOf("form-group")), DateFormControl { + + /** + * 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 + } + /** + * 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 showClear + get() = input.showClear + set(value) { + input.showClear = value + } + /** + * Determines if *Close* button should be visible. + */ + var showClose + get() = input.showClose + set(value) { + input.showClose = value + } + /** + * Determines if *Today* button should be visible. + */ + var showTodayButton + get() = input.showTodayButton + set(value) { + input.showTodayButton = value + } + /** + * The increment used to build the hour view. + */ + var stepping + get() = input.stepping + set(value) { + input.stepping = value + } + /** + * Prevents date selection before this date. + */ + var minDate + get() = input.minDate + set(value) { + input.minDate = value + } + /** + * Prevents date selection after this date. + */ + var maxDate + get() = input.maxDate + set(value) { + input.maxDate = value + } + /** + * Shows date and time pickers side by side. + */ + var sideBySide + get() = input.sideBySide + set(value) { + input.sideBySide = value + } + /** + * An array of enabled dates. + */ + var enabledDates + get() = input.enabledDates + set(value) { + input.enabledDates = value + } + /** + * An array of disabled dates. + */ + var disabledDates + get() = input.disabledDates + set(value) { + input.disabledDates = value + } + /** + * Allow date picker for readonly component.. + */ + var ignoreReadonly + get() = input.ignoreReadonly + set(value) { + input.ignoreReadonly = 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 invalidFeedback: InvalidFeedback = InvalidFeedback().apply { visible = false } + + init { + @Suppress("LeakingThis") + input.eventTarget = this + this.addInternal(flabel) + this.addInternal(input) + this.addInternal(invalidFeedback) + counter++ + } + + override fun getSnClass(): List<StringBoolPair> { + val cl = super.getSnClass().toMutableList() + if (validatorError != null) { + cl.add("text-danger" 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() + } + + /** + * Toggle date/time chooser popup. + */ + open fun togglePopup() { + input.togglePopup() + } + + 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: Date? = 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-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt new file mode 100644 index 00000000..626346b1 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt @@ -0,0 +1,377 @@ +/* + * 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.form.FormInput +import pl.treksoft.kvision.form.text.TextInput +import pl.treksoft.kvision.html.Div +import pl.treksoft.kvision.html.Icon +import pl.treksoft.kvision.html.Icon.Companion.icon +import pl.treksoft.kvision.html.Span.Companion.span +import pl.treksoft.kvision.i18n.I18n +import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.types.toDateF +import pl.treksoft.kvision.types.toStringF +import pl.treksoft.kvision.utils.obj +import kotlin.js.Date + +internal const val DEFAULT_STEPPING = 5 + +/** + * 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: Date? = null, format: String = "YYYY-MM-DD HH:mm", + classes: Set<String> = setOf() +) : SimplePanel(classes + "input-group" + "date"), FormInput { + + private var initialized = false + + internal val input = TextInput(value = value?.toStringF(format)) + private lateinit var icon: Icon + private val addon = Div(classes = setOf("input-group-append")) { + span(classes = setOf("input-group-text", "datepickerbutton")) { + icon = icon(getIconClass(format)) + } + } + + init { + addInternal(input) + addInternal(addon) + } + + /** + * Date/time input value. + */ + var value + get() = input.value?.toDateF(format) + set(value) { + input.value = value?.toStringF(format) + refreshState() + } + /** + * Date/time format. + */ + var format by refreshOnUpdate(format) { refreshDatePicker() } + /** + * The placeholder for the date/time input. + */ + var placeholder + get() = input.placeholder + set(value) { + input.placeholder = value + } + /** + * The name attribute of the generated HTML input element. + */ + override var name + get() = input.name + set(value) { + input.name = value + } + /** + * Determines if the field is disabled. + */ + override var disabled + get() = input.disabled + set(value) { + input.disabled = value + } + /** + * Determines if the text 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 + } + /** + * The size of the input. + */ + override var size + get() = input.size + set(value) { + input.size = value + } + /** + * The validation status of the input. + */ + override var validationStatus + get() = input.validationStatus + set(value) { + input.validationStatus = value + refresh() + } + /** + * 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 showClear by refreshOnUpdate(true) { refreshDatePicker() } + /** + * Determines if *Close* button should be visible. + */ + var showClose by refreshOnUpdate(true) { refreshDatePicker() } + /** + * Determines if *Today* button should be visible. + */ + var showTodayButton by refreshOnUpdate(true) { refreshDatePicker() } + /** + * The increment used to build the hour view. + */ + var stepping by refreshOnUpdate(DEFAULT_STEPPING) { refreshDatePicker() } + /** + * Prevents date selection before this date. + */ + var minDate: Date? by refreshOnUpdate { refreshDatePicker() } + /** + * Prevents date selection after this date. + */ + var maxDate: Date? by refreshOnUpdate { refreshDatePicker() } + /** + * Shows date and time pickers side by side. + */ + var sideBySide by refreshOnUpdate(false) { refreshDatePicker() } + /** + * An array of enabled dates. + */ + var enabledDates by refreshOnUpdate(arrayOf<Date>()) { refreshDatePicker() } + /** + * An array of disabled dates. + */ + var disabledDates by refreshOnUpdate(arrayOf<Date>()) { refreshDatePicker() } + /** + * Allow date picker for readonly component. + */ + var ignoreReadonly by refreshOnUpdate(false) { refreshDatePicker() } + + private fun refreshState() { + if (initialized) getElementJQueryD().data("DateTimePicker").date(value) + } + + private fun getIconClass(format: String): String { + return if (format.contains("YYYY") || format.contains("MM") || format.contains("DD")) { + "fas fa-calendar-alt" + } else { + "fas fa-clock" + } + } + + override fun getSnClass(): List<StringBoolPair> { + val cl = super.getSnClass().toMutableList() + validationStatus?.let { + cl.add(it.className to true) + } + return cl + } + + protected open fun refreshDatePicker() { + if (initialized) { + getElementJQueryD()?.data("DateTimePicker").destroy() + } + initDateTimePicker() + icon.icon = getIconClass(format) + } + + /** + * Open date/time chooser popup. + */ + open fun showPopup() { + if (initialized) getElementJQueryD()?.data("DateTimePicker").show() + } + + /** + * Hides date/time chooser popup. + */ + open fun hidePopup() { + if (initialized) getElementJQueryD()?.data("DateTimePicker").hide() + } + + /** + * Toggles date/time chooser popup. + */ + open fun togglePopup() { + if (initialized) getElementJQueryD()?.data("DateTimePicker").toggle() + } + + @Suppress("UnsafeCastFromDynamic") + override fun afterInsert(node: VNode) { + this.initDateTimePicker() + this.initEventHandlers() + initialized = true + } + + override fun afterDestroy() { + if (initialized) { + val comp = getElementJQueryD()?.data("DateTimePicker") + if (comp != null) comp.destroy() + initialized = false + } + } + + private fun initDateTimePicker() { + val language = I18n.language + val self = this + getElementJQueryD()?.datetimepicker(obj { + this.useCurrent = false + this.format = format + this.stepping = stepping + this.showClear = showClear + this.showClose = showClose + this.showTodayButton = showTodayButton + this.sideBySide = sideBySide + this.ignoreReadonly = ignoreReadonly + if (minDate != null) this.minDate = minDate + if (maxDate != null) this.maxDate = maxDate + if (daysOfWeekDisabled.isNotEmpty()) this.daysOfWeekDisabled = daysOfWeekDisabled + if (enabledDates.isNotEmpty()) this.enabledDates = enabledDates + if (disabledDates.isNotEmpty()) this.disabledDates = disabledDates + this.locale = language + this.icons = obj { + this.time = "far fa-clock" + this.date = "far fa-calendar" + this.up = "fas fa-arrow-up" + this.down = "fas fa-arrow-down" + this.previous = "fas fa-chevron-left" + this.next = "fas fa-chevron-right" + this.today = "fas fa-calendar-check" + this.clear = "far fa-trash-alt" + this.close = "far fa-times-circle" + } + this.tooltips = obj { + this.today = "" + this.clear = "" + this.close = "" + this.selectMonth = "" + this.prevMonth = "" + this.nextMonth = "" + this.selectYear = "" + this.prevYear = "" + this.nextYear = "" + this.selectDecade = "" + this.prevDecade = "" + this.nextDecade = "" + this.prevCentury = "" + this.nextCentury = "" + this.pickHour = "" + this.incrementHour = "" + this.decrementHour = "" + this.pickMinute = "" + this.incrementMinute = "" + this.decrementMinute = "" + this.pickSecond = "" + this.incrementSecond = "" + this.decrementSecond = "" + this.togglePeriod = "" + this.selectTime = "" + } + this.keyBinds = obj { + enter = { + self.togglePopup() + } + } + }) + } + + private fun initEventHandlers() { + this.getElementJQuery()?.on("dp.change") { e, _ -> + val moment = e.asDynamic().date + if (moment) { + this.value = moment.toDate() + } else { + this.value = null + } + @Suppress("UnsafeCastFromDynamic") + this.dispatchEvent("change", obj { detail = e }) + } + this.getElementJQuery()?.on("dp.error") { e, _ -> + this.value = null + @Suppress("UnsafeCastFromDynamic") + this.dispatchEvent("change", obj { detail = e }) + } + this.getElementJQuery()?.on("dp.show") { e, _ -> + @Suppress("UnsafeCastFromDynamic") + this.dispatchEvent("showBsDateTime", obj { detail = e }) + } + this.getElementJQuery()?.on("dp.hide") { e, _ -> + @Suppress("UnsafeCastFromDynamic") + this.dispatchEvent("hideBsDateTime", obj { detail = e }) + } + } + + /** + * 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. + */ + override fun focus() { + input.focus() + } + + /** + * Makes the input element blur. + */ + override fun blur() { + input.blur() + } + + companion object { + /** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ + fun Container.dateTimeInput( + value: Date? = 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-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt b/kvision-modules/kvision-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt new file mode 100644 index 00000000..13c8531b --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/TestUtil.kt @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package 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(".modal-backdrop").remove() + Root.shutdown() + } + + fun assertEqualsHtml(expected: String?, actual: String?, message: String?) { + if (expected != null && actual != null) { + val exp = jQuery(expected) + val act = jQuery(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", fixed = 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-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeInputSpec.kt b/kvision-modules/kvision-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeInputSpec.kt new file mode 100644 index 00000000..5cdb68c9 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeInputSpec.kt @@ -0,0 +1,55 @@ +/* + * 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.toStringF +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.js.Date +import kotlin.test.Test +import kotlin.test.assertEquals + +class DateTimeInputSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", fixed = true) + val data = Date() + val dti = DateTimeInput(value = data).apply { + placeholder = "place" + id = "idti" + } + root.add(dti) + val element = document.getElementById("test") + val datastr = data.toStringF(dti.format) + assertEquals( + "<div class=\"input-group date\" id=\"idti\"><input class=\"form-control\" placeholder=\"place\" type=\"text\" value=\"$datastr\"><div class=\"input-group-append\"><span class=\"input-group-text datepickerbutton\"><span class=\"fas fa-calendar-alt\"></span></span></div></div>", + element?.innerHTML, + "Should render date time input with correctly formatted value" + ) + } + } + +}
\ No newline at end of file diff --git a/kvision-modules/kvision-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeSpec.kt b/kvision-modules/kvision-bootstrap-datetime/src/test/kotlin/test/pl/treksoft/kvision/form/time/DateTimeSpec.kt new file mode 100644 index 00000000..a6714f0c --- /dev/null +++ b/kvision-modules/kvision-bootstrap-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.toStringF +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.js.Date +import kotlin.test.Test + +class DateTimeSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", fixed = true) + val data = Date() + 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><div class=\"input-group date\" id=\"$id\"><input class=\"form-control\" placeholder=\"place\" name=\"name\" disabled=\"\" type=\"text\" value=\"$datastr\"><div class=\"input-group-append\"><span class=\"input-group-text datepickerbutton\"><span class=\"fas fa-calendar-alt\"></span></span></div></div></div>", + element?.innerHTML, + "Should render correct date time input form control" + ) + ti.validatorError = "Validation Error" + assertEqualsHtml( + "<div class=\"form-group text-danger\"><label class=\"control-label\" for=\"$id\">Label</label><div class=\"input-group date is-invalid\" id=\"$id\"><input class=\"form-control is-invalid\" placeholder=\"place\" name=\"name\" disabled=\"\" type=\"text\" value=\"$datastr\"><div class=\"input-group-append\"><span class=\"input-group-text datepickerbutton\"><span class=\"fas fa-calendar-alt\"></span></span></div></div><div class=\"invalid-feedback\">Validation Error</div></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-bootstrap-datetime/webpack.config.d/css.js b/kvision-modules/kvision-bootstrap-datetime/webpack.config.d/css.js new file mode 100644 index 00000000..5d710d35 --- /dev/null +++ b/kvision-modules/kvision-bootstrap-datetime/webpack.config.d/css.js @@ -0,0 +1,2 @@ +config.module.rules.push({ test: /\.css$/, loader: "style-loader!css-loader" }); + |