diff options
Diffstat (limited to 'src/main/kotlin/pl/treksoft/kvision')
66 files changed, 4004 insertions, 265 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/KVManager.kt b/src/main/kotlin/pl/treksoft/kvision/KVManager.kt index 5d5c03fa..b60764df 100644 --- a/src/main/kotlin/pl/treksoft/kvision/KVManager.kt +++ b/src/main/kotlin/pl/treksoft/kvision/KVManager.kt @@ -1,5 +1,23 @@ -/** - * @author Robert Jaros +/* + * 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 diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Component.kt b/src/main/kotlin/pl/treksoft/kvision/core/Component.kt index c322892c..7125536a 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Component.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Component.kt @@ -1,3 +1,24 @@ +/* + * 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.core import com.github.snabbdom.VNode @@ -5,20 +26,91 @@ import org.w3c.dom.Node import pl.treksoft.jquery.JQuery import pl.treksoft.kvision.panel.Root +/** + * Base interface for all components. + */ interface Component { + /** + * Parent of the current component. + */ var parent: Component? + /** + * Visibility state of the current component. + */ var visible: Boolean - fun addCssClass(css: String): Widget - fun removeCssClass(css: String): Widget - fun addSurroundingCssClass(css: String): Widget - fun removeSurroundingCssClass(css: String): Widget + /** + * Adds given value to the set of CSS classes generated in html code of current component. + * @param css CSS class name + * @return current component + */ + fun addCssClass(css: String): Component + /** + * Removes given value from the set of CSS classes generated in html code of current component. + * @param css CSS class name + * @return current component + */ + fun removeCssClass(css: String): Component + + /** + * Adds given value to the set of CSS classes generated in html code of parent component. + * @param css CSS class name + * @return current component + */ + fun addSurroundingCssClass(css: String): Component + + /** + * Removes given value from the set of CSS classes generated in html code of parent component. + * @param css CSS class name + * @return current component + */ + fun removeSurroundingCssClass(css: String): Component + + /** + * @suppress + * Internal function + * Renders current component as a Snabbdom vnode. + * @return Snabbdom vnode + */ fun renderVNode(): VNode + + /** + * Returns DOM element bound to the current component. + * @return DOM element + */ fun getElement(): Node? + + /** + * Returns JQuery element bound to the current component. + * @return JQuery element + */ fun getElementJQuery(): JQuery? + + /** + * Returns JQuery element bound to the current component as a *dynamic* type. + * @return JQuery element as a *dynamic* type + */ fun getElementJQueryD(): dynamic + + /** + * @suppress + * Internal function. + * Sets **parent** property of current component to null. + * @return current component + */ fun clearParent(): Component + /** + * @suppress + * Internal function. + * Returns root component - the root node of components tree + * @return root component + */ fun getRoot(): Root? + /** + * @suppress + * Internal function + * Cleans resources allocated by the current component. + */ fun dispose() } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt index da436aba..a428ad14 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt @@ -1,14 +1,60 @@ +/* + * 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.core -import com.github.snabbdom.VNode - -interface Container { - var parent: Component? - var visible: Boolean - fun renderVNode(): VNode +/** + * Base interface for all containers. + */ +interface Container : Component { + /** + * Adds given component to the current container. + * @param child child component + * @return current container + */ fun add(child: Component): Container + + /** + * Adds a list of components to the current container. + * @param children list of child components + * @return current container + */ fun addAll(children: List<Component>): Container + + /** + * Removes given component from the current container. + * @param child child component + * @return current container + */ fun remove(child: Component): Container + + /** + * Removes all children from the current container. + * @return current container + */ fun removeAll(): Container + + /** + * Returns a list of children of the current container. + * @return list of children + */ fun getChildren(): List<Component> } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Css.kt b/src/main/kotlin/pl/treksoft/kvision/core/Css.kt index 80860647..8aeee71a 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Css.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Css.kt @@ -1,10 +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.core import pl.treksoft.kvision.utils.asString import pl.treksoft.kvision.utils.toHexString +/** + * Definitions of CSS units. + */ @Suppress("EnumNaming", "EnumEntryName") -enum class UNIT(val unit: String) { +enum class UNIT(internal val unit: String) { px("px"), pt("pt"), em("em"), @@ -22,7 +46,10 @@ enum class UNIT(val unit: String) { auto("auto") } -enum class BORDERSTYLE(val borderStyle: String) { +/** + * Definitions of CSS border styles. + */ +enum class BORDERSTYLE(internal val borderStyle: String) { NONE("none"), HIDDEN("hidden"), DOTTED("dotted"), @@ -37,7 +64,10 @@ enum class BORDERSTYLE(val borderStyle: String) { INHERIT("inherit") } -enum class COLOR(val color: String) { +/** + * Definitions of CSS color names. + */ +enum class COLOR(internal val color: String) { ALICEBLUE("aliceblue"), ANTIQUEWHITE("antiquewhite"), AQUA("aqua"), @@ -181,63 +211,114 @@ enum class COLOR(val color: String) { YELLOWGREEN("yellowgreen") } -enum class BGSIZE(val size: String) { +/** + * Definitions of CSS background size. + */ +enum class BGSIZE(internal val size: String) { COVER("cover"), CONTAIN("contain") } -enum class BGREPEAT(val repeat: String) { +/** + * Definitions of CSS background repeat options. + */ +enum class BGREPEAT(internal val repeat: String) { REPEAT("repeat"), REPEATX("repeat-x"), REPEATY("repeat-y"), NOREPEAT("no-repeat") } -enum class BGATTACH(val attachment: String) { +/** + * Definitions of CSS background attachment options. + */ +enum class BGATTACH(internal val attachment: String) { SCROLL("scroll"), FIXED("fixed"), LOCAL("local") } -enum class BGORIGIN(val origin: String) { +/** + * Definitions of CSS background origin options. + */ +enum class BGORIGIN(internal val origin: String) { PADDING("padding-box"), BORDER("border-box"), CONTENT("content-box") } -enum class BGCLIP(val clip: String) { +/** + * Definitions of CSS background clipping options. + */ +enum class BGCLIP(internal val clip: String) { PADDING("padding-box"), BORDER("border-box"), CONTENT("content-box") } +/** + * Type-safe definition of CSS border. + */ class Border private constructor( private val width: CssSize? = null, private val style: BORDERSTYLE? = null, private val color: String? = null ) { + /** + * Creates CSS Border with given width and style. + * @param width width of the border + * @param style style of the border + */ constructor(width: CssSize? = null, style: BORDERSTYLE? = null) : this(width, style, null) + + /** + * Creates CSS Border with given width, style and color given in hex format. + * @param width width of the border + * @param style style of the border + * @param color color in hex format + */ constructor(width: CssSize? = null, style: BORDERSTYLE? = null, color: Int) : this( width, style, "#" + color.toHexString() ) + /** + * Creates CSS Border with given width, style and color given with named constant. + * @param width width of the border + * @param style style of the border + * @param color color named constant + */ constructor(width: CssSize? = null, style: BORDERSTYLE? = null, color: COLOR) : this(width, style, color.color) - fun asString(): String { + internal fun asString(): String { val w = width?.asString() return w.orEmpty() + " " + (style?.borderStyle).orEmpty() + " " + color.orEmpty() } } +/** + * Type-safe definition of CSS color. + */ class Color private constructor(private val color: String? = null) { + /** + * Creates CSS Color with color given in hex format. + * @param color color in hex format + */ constructor(color: Int) : this("#" + color.toHexString()) + + /** + * Creates CSS Color with color given with named constant. + * @param color color named constant + */ constructor(color: COLOR) : this(color.color) - fun asString(): String { + internal fun asString(): String { return color.orEmpty() } } +/** + * Type-safe definition of CSS background. + */ class Background private constructor( private val color: String? = null, private val image: ResString? = null, private val positionX: CssSize? = null, private val positionY: CssSize? = null, @@ -246,6 +327,19 @@ class Background private constructor( private val origin: BGORIGIN? = null, private val clip: BGCLIP? = null, private val attachment: BGATTACH? = null ) { + /** + * Creates CSS Background with given parameters. + * @param image background image + * @param positionX horizontal position of the background image + * @param positionY vertical position of the background image + * @param sizeX horizontal size of the background image + * @param sizeY vertical size of the background image + * @param size resize of the background image + * @param repeat repeat option of the background image + * @param origin origin option of the background image + * @param clip clipping option of the background image + * @param attachment attachment option of the background image + */ constructor( image: ResString? = null, positionX: CssSize? = null, positionY: CssSize? = null, sizeX: CssSize? = null, sizeY: CssSize? = null, size: BGSIZE? = null, @@ -256,6 +350,20 @@ class Background private constructor( image, positionX, positionY, sizeX, sizeY, size, repeat, origin, clip, attachment ) + /** + * Creates CSS Background with given parameters. + * @param color color of the background in hex format + * @param image background image + * @param positionX horizontal position of the background image + * @param positionY vertical position of the background image + * @param sizeX horizontal size of the background image + * @param sizeY vertical size of the background image + * @param size resize of the background image + * @param repeat repeat option of the background image + * @param origin origin option of the background image + * @param clip clipping option of the background image + * @param attachment attachment option of the background image + */ constructor( color: Int, image: ResString? = null, positionX: CssSize? = null, positionY: CssSize? = null, @@ -268,6 +376,20 @@ class Background private constructor( attachment ) + /** + * Creates CSS Background with given parameters. + * @param color color of the background with named constant + * @param image background image + * @param positionX horizontal position of the background image + * @param positionY vertical position of the background image + * @param sizeX horizontal size of the background image + * @param sizeY vertical size of the background image + * @param size resize of the background image + * @param repeat repeat option of the background image + * @param origin origin option of the background image + * @param clip clipping option of the background image + * @param attachment attachment option of the background image + */ constructor( color: COLOR, image: ResString? = null, positionX: CssSize? = null, positionY: CssSize? = null, sizeX: CssSize? = null, sizeY: CssSize? = null, @@ -278,7 +400,7 @@ class Background private constructor( positionX, positionY, sizeX, sizeY, size, repeat, origin, clip, attachment ) - fun asString(): String { + internal fun asString(): String { val img = image?.let { "url($image)" } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt b/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt index ed6def5f..f0ceb587 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/StyledComponent.kt @@ -1,134 +1,247 @@ +/* + * 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.core import pl.treksoft.kvision.utils.asString +/** + * Base class for components supporting CSS styling. + */ abstract class StyledComponent : Component { - + /** + * Width of the current component. + */ open var width: CssSize? = null set(value) { field = value refresh() } + /** + * Minimal width of the current component. + */ var minWidth: CssSize? = null set(value) { field = value refresh() } + /** + * Maximal width of the current component. + */ var maxWidth: CssSize? = null set(value) { field = value refresh() } + /** + * Height of the current component. + */ var height: CssSize? = null set(value) { field = value refresh() } + /** + * Minimal height of the current component. + */ var minHeight: CssSize? = null set(value) { field = value refresh() } + /** + * Maximal height of the current component. + */ var maxHeight: CssSize? = null set(value) { field = value refresh() } + /** + * Border of the current component. + */ var border: Border? = null set(value) { field = value refresh() } + /** + * Top border of the current component. + */ var borderTop: Border? = null set(value) { field = value refresh() } + /** + * Right border of the current component. + */ var borderRight: Border? = null set(value) { field = value refresh() } + /** + * Bottom border of the current component. + */ var borderBottom: Border? = null set(value) { field = value refresh() } + /** + * Left border of the current component. + */ var borderLeft: Border? = null set(value) { field = value refresh() } + /** + * Margin of the current component. + */ var margin: CssSize? = null set(value) { field = value refresh() } + /** + * Top margin of the current component. + */ var marginTop: CssSize? = null set(value) { field = value refresh() } + /** + * Right margin of the current component. + */ var marginRight: CssSize? = null set(value) { field = value refresh() } + /** + * Bottom margin of the current component. + */ var marginBottom: CssSize? = null set(value) { field = value refresh() } + /** + * Left margin of the current component. + */ var marginLeft: CssSize? = null set(value) { field = value refresh() } + /** + * Padding of the current component. + */ var padding: CssSize? = null set(value) { field = value refresh() } + /** + * Top padding of the current component. + */ var paddingTop: CssSize? = null set(value) { field = value refresh() } + /** + * Right padding of the current component. + */ var paddingRight: CssSize? = null set(value) { field = value refresh() } + /** + * Bottom padding of the current component. + */ var paddingBottom: CssSize? = null set(value) { field = value refresh() } + /** + * Left padding of the current component. + */ var paddingLeft: CssSize? = null set(value) { field = value refresh() } + /** + * Text color for the current component. + */ var color: Color? = null set(value) { field = value refresh() } + /** + * Text color for the current component given in hex format (write only). + * + * This property gives a convenient way to set the value of [color] property e.g.: + * + * c.colorHex = 0x00ff00 + * + * The value read from this property is always null. + */ var colorHex: Int? get() = null set(value) { color = if (value != null) Color(value) else null } + /** + * Text color for the current component given with named constant (write only). + * + * This property gives a convenient way to set the value of [color] property e.g.: + * + * c.colorName = COLOR.GREEN + * + * The value read from this property is always null. + */ var colorName: COLOR? get() = null set(value) { color = if (value != null) Color(value) else null } + /** + * Opacity of the current component. + */ var opacity: Double? = null set(value) { field = value refresh() } + /** + * Background of the current component. + */ var background: Background? = null set(value) { field = value @@ -138,12 +251,18 @@ abstract class StyledComponent : Component { private var snStyleCache: List<StringPair>? = null + /** + * @suppress + * Internal function + * Re-renders the current component. + * @return current component + */ open fun refresh(): StyledComponent { snStyleCache = null return this } - protected fun getSnStyleInternal(): List<StringPair> { + internal fun getSnStyleInternal(): List<StringPair> { return snStyleCache ?: { val s = getSnStyle() snStyleCache = s @@ -151,6 +270,10 @@ abstract class StyledComponent : Component { }() } + /** + * Returns the list of String pairs defining CSS style attributes and their values. + * @return the list of attributes and their values + */ @Suppress("ComplexMethod", "LongMethod") protected open fun getSnStyle(): List<StringPair> { val snstyle = mutableListOf<StringPair>() diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Types.kt b/src/main/kotlin/pl/treksoft/kvision/core/Types.kt index 05a4bec7..0817b3ae 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Types.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Types.kt @@ -1,9 +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.core + /** + * This type is used for accessing resources with CommonJS **require** function. + * + * e.g. require("./img/picture.png") + */ typealias ResString = String + /** + * Helper type used to define CSS style attributes. + */ typealias StringPair = Pair<String, String> + /** + * Helper type used to define CSS classes. + */ typealias StringBoolPair = Pair<String, Boolean> + /** + * This type is used for defining CSS dimensions (width, heights, margins, paddings, etc.). + */ typealias CssSize = Pair<Int, UNIT> diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt index 08e67da0..5f664563 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt @@ -1,3 +1,24 @@ +/* + * 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.core import com.github.snabbdom.VNode @@ -17,6 +38,14 @@ import pl.treksoft.kvision.utils.snClasses import pl.treksoft.kvision.utils.snOpt import pl.treksoft.kvision.utils.snStyle +/** + * Base widget class. The parent of all component classes. + * + * A simple widget is rendered as HTML DIV element. + * + * @constructor Creates basic Widget with given CSS class names. + * @param classes Set of CSS class names + */ @Suppress("TooManyFunctions", "LargeClass") open class Widget(classes: Set<String> = setOf()) : StyledComponent() { @@ -33,22 +62,31 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { field = value if (oldField != field) refresh() } + /** + * A title attribute of generated HTML element. + */ var title: String? = null set(value) { field = value refresh() } + /** + * An ID attribute of generated HTML element. + */ var id: String? = null set(value) { field = value refresh() } + /** + * A role attribute of generated HTML element. + */ var role: String? = null set(value) { field = value refresh() } - var surroundingSpan: Boolean = false + internal var surroundingSpan: Boolean = false set(value) { field = value refresh() @@ -62,7 +100,7 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { private var snOnCache: com.github.snabbdom.On? = null private var snHooksCache: com.github.snabbdom.Hooks? = null - protected fun <T> singleRender(block: () -> T): T { + internal fun <T> singleRender(block: () -> T): T { getRoot()?.renderDisabled = true val t = block() getRoot()?.renderDisabled = false @@ -89,18 +127,38 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { } } + /** + * Renders current component as a Snabbdom vnode. + * @return Snabbdom vnode + */ protected open fun render(): VNode { - return kvh("div") + return render("div") } - protected open fun kvh(s: String): VNode { - return h(s, getSnOpt()) + /** + * Renders current component as a Snabbdom vnode. + * @param elementName HTML element name + * @return Snabbdom vnode + */ + protected open fun render(elementName: String): VNode { + return h(elementName, getSnOpt()) } - protected open fun kvh(s: String, children: Array<dynamic>): VNode { - return h(s, getSnOpt(), children) + /** + * Renders current component as a Snabbdom vnode. + * @param elementName HTML element name + * @param children array of children nodes + * @return Snabbdom vnode + */ + protected open fun render(elementName: String, children: Array<dynamic>): VNode { + return h(elementName, getSnOpt(), children) } + /** + * Generates VNodeData to creating Snabbdom VNode. + * + * Optimizes creating process by keeping configuration attributes in a cache. + */ private fun getSnOpt(): VNodeData { return snOpt { attrs = snAttrs(getSnAttrsInternal()) @@ -143,10 +201,18 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { }() } + /** + * Returns list of CSS class names for current widget in the form of a List<StringBoolPair>. + * @return list of CSS class names + */ protected open fun getSnClass(): List<StringBoolPair> { return classes.map { c -> c to true } + if (visible) listOf() else listOf("hidden" to true) } + /** + * Returns list of element attributes in the form of a List<StringPair>. + * @return list of element attributes + */ protected open fun getSnAttrs(): List<StringPair> { val snattrs = mutableListOf<StringPair>() id?.let { @@ -161,6 +227,10 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return snattrs } + /** + * Returns list of event handlers in the form of a Snabbdom *On* object. + * @return list of event handlers + */ protected open fun getSnOn(): com.github.snabbdom.On? { return if (internalListeners.size > 0 || listeners.size > 0) { val internalHandlers = on(this) @@ -209,6 +279,10 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { } } + /** + * Returns list of hooks in the form of a Snabbdom *Hooks* object. + * @return list of hooks + */ protected open fun getSnHooks(): com.github.snabbdom.Hooks? { val hooks = hooks() hooks.apply { @@ -236,6 +310,10 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return hooks } + /** + * @suppress + * Internal function + */ @Suppress("UNCHECKED_CAST") protected fun <T : Widget> setInternalEventListener(block: SnOn<T>.() -> Unit): Widget { internalListeners.add(block as SnOn<Widget>.() -> Unit) @@ -243,12 +321,31 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return this } + /** + * @suppress + * Internal function + */ protected fun setInternalEventListener(block: SnOn<Widget>.() -> Unit): Widget { internalListeners.add(block) refresh() return this } + /** + * Sets an event listener for current widget, keeping the actual type of component. + * @param T widget type + * @param block event handler + * @return current widget + * + * Example: + * + * button.setEventListener<Button> { + * dblclick = { + * Alert.show("Button double clicked!") + * // self is of type Button here + * } + * } + */ @Suppress("UNCHECKED_CAST") open fun <T : Widget> setEventListener(block: SnOn<T>.() -> Unit): Widget { listeners.add(block as SnOn<Widget>.() -> Unit) @@ -256,28 +353,58 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return this } + /** + * Sets an event listener for current widget. + * @param block event handler + * @return current widget + * + * Example: + * + * button.setEventListener { + * dblclick = { + * Alert.show("Button double clicked!") + * // self is of type Widget here + * } + * } + */ open fun setEventListener(block: SnOn<Widget>.() -> Unit): Widget { listeners.add(block) refresh() return this } + /** + * Removes all event listeners from current widget. + * @return current widget + */ open fun removeEventListeners(): Widget { listeners.clear() refresh() return this } + /** + * Makes current widget visible. + * @return current widget + */ open fun show(): Widget { visible = true return this } + /** + * Makes current widget invisible. + * @return current widget + */ open fun hide(): Widget { visible = false return this } + /** + * Toggles visibility of current widget. + * @return current widget + */ open fun toggleVisible(): Widget { return if (visible) hide() else show() } @@ -333,15 +460,27 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return this } + /** + * Method called after creating Snabbdom vnode. + */ protected open fun afterCreate(node: VNode) { } + /** + * Method called after inserting Snabbdom vnode into the DOM. + */ protected open fun afterInsert(node: VNode) { } + /** + * Method called after updating Snabbdom vnode. + */ protected open fun afterPostpatch(node: VNode) { } + /** + * Method called after destroying Snabbdom vnode. + */ protected open fun afterDestroy() { } @@ -349,6 +488,10 @@ open class Widget(classes: Set<String> = setOf()) : StyledComponent() { return this.parent?.getRoot() } + /** + * @suppress + * Internal function + */ protected open fun createLabelWithIcon( label: String, icon: String? = null, image: ResString? = null diff --git a/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt b/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt index 26f9308d..47470c83 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/WidgetWrapper.kt @@ -1,29 +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 pl.treksoft.kvision.core import com.github.snabbdom.VNode -open class WidgetWrapper(internal var delegate: Component?, classes: Set<String> = setOf()) : Widget(classes) { +/** + * This class allows to wrap a component into separately styled DIV element. + * + * @constructor + * @param wrapped wrapped component + * @param classes Set of CSS class names + */ +open class WidgetWrapper(internal var wrapped: Component?, classes: Set<String> = setOf()) : Widget(classes) { override var visible - get() = delegate?.visible == true + get() = wrapped?.visible == true set(value) { - delegate?.visible = value + wrapped?.visible = value } init { @Suppress("LeakingThis") - delegate?.parent = this + wrapped?.parent = this } override fun render(): VNode { - return delegate?.let { - kvh("div", arrayOf(it.renderVNode())) - } ?: kvh("div") + return wrapped?.let { + render("div", arrayOf(it.renderVNode())) + } ?: render("div") } override fun dispose() { - delegate?.clearParent() - delegate = null + wrapped?.clearParent() + wrapped = null } } diff --git a/src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt b/src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt index 6eef6f98..4e5b92d5 100644 --- a/src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt +++ b/src/main/kotlin/pl/treksoft/kvision/data/DataComponent.kt @@ -1,12 +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.data import kotlin.properties.ObservableProperty import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty +/** + * Base interface for observable data model. + */ interface DataComponent { + /** + * @suppress + * Internal property + */ var container: DataUpdatable? + /** + * @suppress + * Internal function for observable properties + */ fun <T> obs(initialValue: T): ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) { override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) { container?.update() @@ -14,6 +46,9 @@ interface DataComponent { } } -open class BaseDataComponent : DataComponent { +/** + * Base abstract class for creating observable data model. + */ +abstract class BaseDataComponent : DataComponent { override var container: DataUpdatable? = null } diff --git a/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt b/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt index af53807c..209c9ae6 100644 --- a/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt +++ b/src/main/kotlin/pl/treksoft/kvision/data/DataContainer.kt @@ -1,3 +1,24 @@ +/* + * 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.data import com.github.snabbdom.VNode @@ -7,8 +28,18 @@ import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.panel.VPanel -class DataContainer<M : DataComponent, C : Widget>( - val model: ObservableList<M>, +/** + * A container class with support for observable data model. + * + * @constructor Creates DataContainer bound to given data model. + * @param M base data model type + * @param C base component type + * @param model data model of type *ObservableList<M>* + * @param binding a function which creates component C from data model at given index + * @param child internal container (defaults to [VPanel]) + */ +class DataContainer<M : DataComponent, C : Component>( + private val model: ObservableList<M>, private val binding: (Int) -> C, private val child: Container = VPanel() ) : @@ -58,8 +89,9 @@ class DataContainer<M : DataComponent, C : Widget>( return this.child.renderVNode() } - fun get(index: Int): M = model[index] - + /** + * Updates view from the current data model state. + */ override fun update() { model.forEach { it.container = this } singleRender { @@ -69,11 +101,20 @@ class DataContainer<M : DataComponent, C : Widget>( onUpdateHandler?.invoke() } + /** + * Sets a notification handler called after every update. + * @param handler notification handler + * @return current container + */ fun onUpdate(handler: () -> Unit): DataContainer<M, C> { onUpdateHandler = handler return this } + /** + * Clears notification handler. + * @return current container + */ fun clearOnUpdate(): DataContainer<M, C> { onUpdateHandler = null return this diff --git a/src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt b/src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt index 5f9b7563..7c54e864 100644 --- a/src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt +++ b/src/main/kotlin/pl/treksoft/kvision/data/DataUpdatable.kt @@ -1,5 +1,29 @@ +/* + * 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.data +/** + * Interface for updatable container. + */ interface DataUpdatable { fun update() } diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt index 2e32ff7c..b80c6dc5 100644 --- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt +++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt @@ -1,31 +1,69 @@ +/* + * 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.dropdown import com.github.snabbdom.VNode import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.CssSize +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.html.BUTTONSTYLE import pl.treksoft.kvision.html.Button -import pl.treksoft.kvision.html.LIST +import pl.treksoft.kvision.html.LISTTYPE import pl.treksoft.kvision.html.Link import pl.treksoft.kvision.html.ListTag import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag import pl.treksoft.kvision.panel.SimplePanel -import pl.treksoft.kvision.core.StringBoolPair -import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.utils.obj -enum class DD(val type: String) { +/** + * Useful options for use in DropDown's *elements* parameter. + */ +enum class DD(val option: String) { HEADER("DD#HEADER"), DISABLED("DD#DISABLED"), SEPARATOR("DD#SEPARATOR") } +/** + * Bootstrap dropdown component. + * + * @constructor + * @param text the label of the dropdown button + * @param elements an optional list of link elements (special options from [DD] enum class can be used as values) + * @param icon the icon of the dropdown button + * @param style the style of the dropdown button + * @param disabled determines if the component is disabled on start + * @param classes a set of CSS class names + */ open class DropDown( text: String, elements: List<StringPair>? = null, icon: String? = null, style: BUTTONSTYLE = BUTTONSTYLE.DEFAULT, disabled: Boolean = false, classes: Set<String> = setOf() ) : SimplePanel(classes) { + /** + * Label of the dropdown button. + */ var text get() = button.text set(value) { @@ -36,41 +74,65 @@ open class DropDown( field = value setChildrenFromElements() } + /** + * The icon of the dropdown button. + */ var icon get() = button.icon set(value) { button.icon = value } + /** + * The style of the dropdown button. + */ var style get() = button.style set(value) { button.style = value } + /** + * The size of the dropdown button. + */ var size get() = button.size set(value) { button.size = value } + /** + * Determines if the dropdown button takes all the space horizontally. + */ var block get() = button.block set(value) { button.block = value } + /** + * Determines if the dropdown is disabled. + */ var disabled get() = button.disabled set(value) { button.disabled = value } + /** + * The image on the dropdown button. + */ var image get() = button.image set(value) { button.image = value } + /** + * Determines if the dropdown is showing upwards. + */ var dropup = false set(value) { field = value refresh() } + /** + * Width of the dropdown button. + */ override var width: CssSize? get() = super.width set(value) { @@ -93,7 +155,7 @@ open class DropDown( } companion object { - var counter = 0 + internal var counter = 0 } override fun add(child: Component): SimplePanel { @@ -126,13 +188,13 @@ open class DropDown( elements?.let { elems -> val c = elems.map { when (it.second) { - DD.HEADER.type -> Tag(TAG.LI, it.first, classes = setOf("dropdown-header")) - DD.SEPARATOR.type -> { + DD.HEADER.option -> Tag(TAG.LI, it.first, classes = setOf("dropdown-header")) + DD.SEPARATOR.option -> { val tag = Tag(TAG.LI, it.first, classes = setOf("divider")) tag.role = "separator" tag } - DD.DISABLED.type -> { + DD.DISABLED.option -> { val tag = Tag(TAG.LI, classes = setOf("disabled")) tag.add(Link(it.first, "#")) tag @@ -169,12 +231,15 @@ open class DropDown( return cl } + /** + * Toggles dropdown visibility. + */ open fun toggle() { this.list.getElementJQueryD()?.dropdown("toggle") } } -open class DropDownButton( +internal class DropDownButton( id: String, text: String, icon: String? = null, style: BUTTONSTYLE = BUTTONSTYLE.DEFAULT, disabled: Boolean = false, classes: Set<String> = setOf() ) : @@ -192,8 +257,8 @@ open class DropDownButton( } } -open class DropDownListTag(private val ariaId: String, classes: Set<String> = setOf()) : ListTag( - LIST.UL, null, +internal class DropDownListTag(private val ariaId: String, classes: Set<String> = setOf()) : ListTag( + LISTTYPE.UL, null, false, classes ) { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt index 81275070..b4be8f8e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FieldLabel.kt @@ -1,9 +1,39 @@ +/* + * 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 +import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag -import pl.treksoft.kvision.core.StringPair +/** + * Helper class for HTML label element. + * + * @constructor + * @param forId the value of *for* attribute + * @param text the text of the label + * @param rich determines if [text] can contain HTML code + * @param classes a set of CSS class names + */ open class FieldLabel( internal val forId: String, text: String? = null, rich: Boolean = false, classes: Set<String> = setOf("control-label") diff --git a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt index 1f97311d..e91002e9 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/Form.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/Form.kt @@ -1,22 +1,63 @@ +/* + * 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 import kotlin.js.Date import kotlin.js.Json -data class FieldParams<in F : FormControl>( +/** + * Internal data class containing form field parameters. + */ +internal data class FieldParams<in F : FormControl>( val required: Boolean = false, val validatorMessage: ((F) -> String?)? = null, val validator: ((F) -> Boolean?)? = null ) -open class Form<K>(private val panel: FormPanel<K>? = null, private val modelFactory: (Map<String, Any?>) -> K) { +/** + * The form definition class. Can be used directly or indirectly inside a [FormPanel]. + * + * @constructor Creates a form with a given modelFactory function + * @param K model class type + * @param panel optional instance of [FormPanel] + * @param modelFactory function transforming a Map<String, Any?> to a data model of class K + */ +class Form<K>(private val panel: FormPanel<K>? = null, private val modelFactory: (Map<String, Any?>) -> K) { internal val fields: MutableMap<String, FormControl> = mutableMapOf() internal val fieldsParams: MutableMap<String, Any> = mutableMapOf() internal var validatorMessage: ((Form<K>) -> String?)? = null internal var validator: ((Form<K>) -> Boolean?)? = null - open fun <C : FormControl> add( + /** + * Adds a control to the form. + * @param key key identifier of the control + * @param control the form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form + */ + fun <C : FormControl> add( key: String, control: C, required: Boolean = false, validatorMessage: ((C) -> String?)? = null, validator: ((C) -> Boolean?)? = null @@ -26,53 +67,91 @@ open class Form<K>(private val panel: FormPanel<K>? = null, private val modelFac return this } - open fun remove(key: String): Form<K> { + /** + * Removes a control from the form. + * @param key key identifier of the control + * @return current form + */ + fun remove(key: String): Form<K> { this.fields.remove(key) return this } - open fun removeAll(): Form<K> { + /** + * Removes all controls from the form. + * @return current form + */ + fun removeAll(): Form<K> { this.fields.clear() return this } - open fun getControl(key: String): FormControl? { + /** + * Returns a control of given key. + * @param key key identifier of the control + * @return selected control + */ + fun getControl(key: String): FormControl? { return this.fields[key] } + /** + * Returns a value of the control of given key. + * @param key key identifier of the control + * @return value of the control + */ operator fun get(key: String): Any? { return getControl(key)?.getValue() } - open fun setData(data: K) { + /** + * Sets the values of all the controls from the model. + * @param model data model + */ + fun setData(model: K) { fields.forEach { it.value.setValue(null) } - val map = data.asDynamic().map as? Map<String, Any?> + val map = model.asDynamic().map as? Map<String, Any?> if (map != null) { map.forEach { fields[it.key]?.setValue(it.value) } } else { - for (key in js("Object").keys(data)) { + for (key in js("Object").keys(model)) { @Suppress("UnsafeCastFromDynamic") - fields[key]?.setValue(data.asDynamic()[key]) + fields[key]?.setValue(model.asDynamic()[key]) } } } - open fun clearData() { + /** + * Sets the values of all controls to null. + */ + fun clearData() { fields.forEach { it.value.setValue(null) } } - open fun getData(): K { + /** + * Returns current data model. + * @return data model + */ + fun getData(): K { val map = fields.entries.associateBy({ it.key }, { it.value.getValue() }) return modelFactory(map.withDefault { null }) } - open fun getDataJson(): Json { + /** + * Returns current data model as JSON. + * @return data model as JSON + */ + fun getDataJson(): Json { return fields.entries.associateBy({ it.key }, { it.value.getValue() }).asJson() } - open fun validate(): Boolean { + /** + * Invokes validator function and validates the form. + * @return validation result + */ + fun validate(): Boolean { val fieldWithError = fieldsParams.mapNotNull { entry -> fields[entry.key]?.let { control -> @Suppress("UNCHECKED_CAST") @@ -95,7 +174,7 @@ open class Form<K>(private val panel: FormPanel<K>? = null, private val modelFac }.find { it } val validatorPassed = validator?.invoke(this) ?: true panel?.validatorError = if (!validatorPassed) { - panel?.validatorMessage?.invoke(this) ?: "Invalid form data" + validatorMessage?.invoke(this) ?: "Invalid form data" } else { null } @@ -103,11 +182,29 @@ open class Form<K>(private val panel: FormPanel<K>? = null, private val modelFac } } +/** + * Returns given value from the map as a String. + */ fun Map<String, Any?>.string(key: String): String? = this[key] as? String + +/** + * Returns given value from the map as a Number. + */ fun Map<String, Any?>.number(key: String): Number? = this[key] as? Number + +/** + * Returns given value from the map as a Boolean. + */ fun Map<String, Any?>.bool(key: String): Boolean? = this[key] as? Boolean + +/** + * Returns given value from the map as a Date. + */ fun Map<String, Any?>.date(key: String): Date? = this[key] as? Date +/** + * Returns map values in JSON format. + */ fun Map<String, Any?>.asJson(): Json { val array = this.entries.map { it.component1() to it.component2() }.toTypedArray() @Suppress("SpreadOperator") diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt index d0858d4e..b8e9a1b4 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FormControl.kt @@ -1,23 +1,90 @@ +/* + * 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 import pl.treksoft.kvision.core.Component import kotlin.js.Date +/** + * Input controls sizes. + */ enum class INPUTSIZE(val className: String) { LARGE("input-lg"), SMALL("input-sm") } +/** + * Base interface of a form control. + */ interface FormControl : Component { + /** + * Determines if the field is disabled. + */ var disabled: Boolean + /** + * Input control size. + */ var size: INPUTSIZE? + /** + * The actual input component. + */ val input: Component + /** + * Form field label. + */ val flabel: FieldLabel + /** + * Validation info component. + */ val validationInfo: HelpBlock + + /** + * Returns the value of the control. + * @return the value + */ fun getValue(): Any? + + /** + * Sets the value of the control. + * @param v the value + */ fun setValue(v: Any?) + + /** + * Returns the value of the control as a String. + */ fun getValueAsString(): String? + + /** + * @suppress + * Internal function + * Re-renders the current component. + * @return current component + */ fun refresh(): Component + + /** + * Validator error message. + */ var validatorError: String? get() = validationInfo.text set(value) { @@ -27,8 +94,15 @@ interface FormControl : Component { } } +/** + * Base interface of a form control with a text value. + */ interface StringFormControl : FormControl { + /** + * Text value. + */ var value: String? + override fun getValue(): String? = value override fun setValue(v: Any?) { value = v as? String @@ -37,8 +111,15 @@ interface StringFormControl : FormControl { override fun getValueAsString(): String? = value } +/** + * Base interface of a form control with a numeric value. + */ interface NumberFormControl : FormControl { + /** + * Numeric value. + */ var value: Number? + override fun getValue(): Number? = value override fun setValue(v: Any?) { value = v as? Number @@ -47,8 +128,15 @@ interface NumberFormControl : FormControl { override fun getValueAsString(): String? = value?.toString() } +/** + * Base interface of a form control with a boolean value. + */ interface BoolFormControl : FormControl { + /** + * Boolean value. + */ var value: Boolean + override fun getValue(): Boolean = value override fun setValue(v: Any?) { value = v as? Boolean ?: false @@ -57,8 +145,15 @@ interface BoolFormControl : FormControl { override fun getValueAsString(): String? = value.toString() } +/** + * Base interface of a form control with a date value. + */ interface DateFormControl : FormControl { + /** + * Date value. + */ var value: Date? + override fun getValue(): Date? = value override fun setValue(v: Any?) { value = v as? Date diff --git a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt index 4ab94df5..0a12f818 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/FormPanel.kt @@ -1,29 +1,68 @@ +/* + * 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 import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.form.check.CheckBox import pl.treksoft.kvision.form.check.Radio import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag import pl.treksoft.kvision.panel.SimplePanel -import pl.treksoft.kvision.core.StringBoolPair import kotlin.js.Json -enum class FORMTYPE(val formType: String) { +/** + * Bootstrap form layout options. + */ +enum class FORMTYPE(internal val formType: String) { INLINE("form-inline"), HORIZONTAL("form-horizontal") } +/** + * Bootstrap form component. + * + * @constructor + * @param K model class type + * @param type form layout + * @param classes set of CSS class names + * @param modelFactory function transforming a Map<String, Any?> to a data model of class K + */ open class FormPanel<K>( private val type: FORMTYPE? = null, classes: Set<String> = setOf(), modelFactory: (Map<String, Any?>) -> K ) : SimplePanel(classes) { + /** + * Function returning validation message. + */ var validatorMessage get() = form.validatorMessage set(value) { form.validatorMessage = value } + /** + * Validation function. + */ var validator get() = form.validator set(value) { @@ -38,8 +77,16 @@ open class FormPanel<K>( refresh() } + /** + * @suppress + * Internal property. + */ @Suppress("LeakingThis") protected val form = Form(this, modelFactory) + /** + * @suppress + * Internal property. + */ protected val validationAlert = Tag(TAG.H5, classes = setOf("alert", "alert-danger")).apply { role = "alert" visible = false @@ -50,7 +97,7 @@ open class FormPanel<K>( } override fun render(): VNode { - return kvh("form", childrenVNodes()) + return render("form", childrenVNodes()) } override fun getSnClass(): List<StringBoolPair> { @@ -61,6 +108,15 @@ open class FormPanel<K>( return cl } + /** + * Adds a control to the form panel. + * @param key key identifier of the control + * @param control the form control + * @param required determines if the control is required + * @param validatorMessage optional function returning validation message + * @param validator optional validation function + * @return current form panel + */ open fun <C : FormControl> add( key: String, control: C, required: Boolean = false, validatorMessage: ((C) -> String?)? = null, @@ -82,7 +138,12 @@ open class FormPanel<K>( return this } - fun remove(key: String): FormPanel<K> { + /** + * Removes a control from the form panel. + * @param key key identifier of the control + * @return current form panel + */ + open fun remove(key: String): FormPanel<K> { form.getControl(key)?.let { super.remove(it) } @@ -97,30 +158,59 @@ open class FormPanel<K>( return this } + /** + * Returns a control of given key. + * @param key key identifier of the control + * @return selected control + */ open fun getControl(key: String): FormControl? { return form.getControl(key) } + /** + * Returns a value of the control of given key. + * @param key key identifier of the control + * @return value of the control + */ operator fun get(key: String): Any? { return getControl(key)?.getValue() } - open fun setData(data: K) { - form.setData(data) + /** + * Sets the values of all the controls from the model. + * @param model data model + */ + open fun setData(model: K) { + form.setData(model) } + /** + * Sets the values of all controls to null. + */ open fun clearData() { form.clearData() } + /** + * Returns current data model. + * @return data model + */ open fun getData(): K { return form.getData() } + /** + * Returns current data model as JSON. + * @return data model as JSON + */ open fun getDataJson(): Json { return form.getDataJson() } + /** + * Invokes validator function and validates the form. + * @return validation result + */ open fun validate(): Boolean { return form.validate() } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt b/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt index dcfd185e..db9aebc5 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/HelpBlock.kt @@ -1,8 +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.form import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag +/** + * Helper class for Bootstrap help block element. + * + * @constructor + * @param text the text of the label + * @param rich determines if [text] can contain HTML code + */ open class HelpBlock(text: String? = null, rich: Boolean = false) : Tag( TAG.SPAN, text, rich, classes = setOf("help-block", "small") diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt index ea41c429..0bad8440 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckBox.kt @@ -1,15 +1,39 @@ +/* + * 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.check import org.w3c.dom.events.MouseEvent +import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.BoolFormControl import pl.treksoft.kvision.form.FieldLabel import pl.treksoft.kvision.form.HelpBlock import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn -import pl.treksoft.kvision.core.StringBoolPair -enum class CHECKBOXSTYLE(val className: String) { +/** + * Checkbox style options. + */ +enum class CHECKBOXSTYLE(internal val className: String) { DEFAULT("checkbox-default"), PRIMARY("checkbox-primary"), SUCCESS("checkbox-success"), @@ -18,21 +42,41 @@ enum class CHECKBOXSTYLE(val className: String) { DANGER("checkbox-danger"), } +/** + * The form field component rendered as HTML *input type="checkbox"*. + * + * @constructor + * @param value selection state + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ open class CheckBox( value: Boolean = false, label: String? = null, rich: Boolean = false ) : SimplePanel(setOf("checkbox")), BoolFormControl { + /** + * The selection state of the checkbox. + */ 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 input selection state. + */ var startValue get() = input.startValue set(value) { input.startValue = value } + /** + * The name attribute of the generated HTML input element. + */ var name get() = input.name set(value) { @@ -43,31 +87,49 @@ open class CheckBox( set(value) { input.disabled = value } + /** + * The label text bound to the input element. + */ var label get() = flabel.text set(value) { flabel.text = value } + /** + * Determines if [label] can contain HTML code. + */ var rich get() = flabel.rich set(value) { flabel.rich = value } + /** + * The style (one of Bootstrap standard colors) of the input. + */ var style: CHECKBOXSTYLE? = null set(value) { field = value refresh() } + /** + * Determines if the checkbox is rendered as a circle. + */ var circled: Boolean = false set(value) { field = value refresh() } + /** + * Determines if the checkbox is rendered inline. + */ var inline: Boolean = false set(value) { field = value refresh() } + /** + * The size of the input. + */ override var size get() = input.size set(value) { @@ -92,7 +154,7 @@ open class CheckBox( } companion object { - var counter = 0 + internal var counter = 0 } @Suppress("UNCHECKED_CAST") @@ -128,6 +190,9 @@ open class CheckBox( return cl } + /** + * A convenient helper for easy setting onClick event handler. + */ open fun onClick(handler: CheckBox.(MouseEvent) -> Unit): CheckBox { this.setEventListener<CheckBox> { click = { e -> diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt index a7d562a2..26a06fa7 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/CheckInput.kt @@ -1,17 +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.form.check import com.github.snabbdom.VNode import org.w3c.dom.events.MouseEvent -import pl.treksoft.kvision.core.Widget -import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.form.INPUTSIZE -enum class CHECKINPUTTYPE(val type: String) { +/** + * Type of the check input control (checkbox or radio). + */ +enum class CHECKINPUTTYPE(internal val type: String) { CHECKBOX("checkbox"), RADIO("radio") } +/** + * The basic input component rendered as HTML *input type="checkbox"* or *input type="radio"*. + * + * @constructor + * @param type type of the input control + * @param value selection state + * @param classes a set of CSS class names + */ open class CheckInput( type: CHECKINPUTTYPE = CHECKINPUTTYPE.CHECKBOX, value: Boolean = false, classes: Set<String> = setOf() @@ -30,37 +62,61 @@ open class CheckInput( } } + /** + * The selection state of the input. + */ var value: Boolean = value set(value) { field = 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 input selection state. + */ var startValue: Boolean = value set(value) { field = value this.value = value refresh() } + /** + * The type of the generated HTML input element. + */ var type: CHECKINPUTTYPE = type set(value) { field = value refresh() } + /** + * The name attribute of the generated HTML input element. + */ var name: String? = null set(value) { field = value refresh() } + /** + * Determines if the field is disabled. + */ var disabled: Boolean = false set(value) { field = value refresh() } + /** + * The additional String value used for the radio button group. + */ var extraValue: String? = null set(value) { field = value refresh() } + /** + * The size of the input. + */ var size: INPUTSIZE? = null set(value) { field = value @@ -68,7 +124,7 @@ open class CheckInput( } override fun render(): VNode { - return kvh("input") + return render("input") } override fun getSnClass(): List<StringBoolPair> { @@ -112,6 +168,9 @@ open class CheckInput( } } + /** + * A convenient helper for easy setting onClick event handler. + */ open fun onClick(handler: CheckInput.(MouseEvent) -> Unit): CheckInput { this.setEventListener<CheckInput> { click = { e -> diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt index ac6df5b1..a8059230 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/Radio.kt @@ -1,15 +1,39 @@ +/* + * 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.check import org.w3c.dom.events.MouseEvent +import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.BoolFormControl import pl.treksoft.kvision.form.FieldLabel import pl.treksoft.kvision.form.HelpBlock import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn -import pl.treksoft.kvision.core.StringBoolPair -enum class RADIOSTYLE(val className: String) { +/** + * Radio style options. + */ +enum class RADIOSTYLE(internal val className: String) { DEFAULT("radio-default"), PRIMARY("radio-primary"), SUCCESS("radio-success"), @@ -18,26 +42,51 @@ enum class RADIOSTYLE(val className: String) { DANGER("radio-danger"), } +/** + * The form field component rendered as HTML *input type="radio"*. + * + * @constructor + * @param value selection state + * @param extraValue the additional String value used for the radio button group + * @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 Radio( value: Boolean = false, extraValue: String? = null, name: String? = null, label: String? = null, rich: Boolean = false ) : SimplePanel(), BoolFormControl { + /** + * The selection state of the radio button. + */ 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 input selection state. + */ var startValue get() = input.startValue set(value) { input.startValue = value } + /** + * The additional String value used for the radio button group. + */ var extraValue get() = input.extraValue set(value) { input.extraValue = value } + /** + * The name attribute of the generated HTML input element. + */ var name get() = input.name set(value) { @@ -48,31 +97,49 @@ open class Radio( set(value) { input.disabled = value } + /** + * The label text bound to the input element. + */ var label get() = flabel.text set(value) { flabel.text = value } + /** + * Determines if [label] can contain HTML code. + */ var rich get() = flabel.rich set(value) { flabel.rich = value } + /** + * The style (one of Bootstrap standard colors) of the input. + */ var style: RADIOSTYLE? = null set(value) { field = value refresh() } + /** + * Determines if the radio button is rendered as a square. + */ var squared: Boolean = false set(value) { field = value refresh() } + /** + * Determines if the radio button is rendered inline. + */ var inline: Boolean = false set(value) { field = value refresh() } + /** + * The size of the input. + */ override var size get() = input.size set(value) { @@ -98,7 +165,7 @@ open class Radio( } companion object { - var counter = 0 + internal var counter = 0 } @Suppress("UNCHECKED_CAST") @@ -143,6 +210,9 @@ open class Radio( return cl } + /** + * A convenient helper for easy setting onClick event handler. + */ open fun onClick(handler: Radio.(MouseEvent) -> Unit): Radio { this.setEventListener<Radio> { click = { e -> diff --git a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt index 5060b6cb..7bd13d4e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/check/RadioGroup.kt @@ -1,5 +1,28 @@ +/* + * 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.check +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 @@ -7,27 +30,47 @@ import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.form.StringFormControl import pl.treksoft.kvision.form.select.Select import pl.treksoft.kvision.panel.SimplePanel -import pl.treksoft.kvision.core.StringBoolPair -import pl.treksoft.kvision.core.StringPair +/** + * The form field component rendered as a group of HTML *input type="radio"* elements with the same name attribute. + * + * The radio group can be populated directly from *options* parameter or manually by adding + * [Radio] components to the container. + * + * @constructor + * @param options an optional list of options (label to value pairs) for the group + * @param value selected option + * @param inline determines if the options are rendered inline + * @param label label text of the options group + * @param rich determines if [label] can contain HTML code + */ open class RadioGroup( options: List<StringPair>? = null, value: String? = null, inline: Boolean = false, label: String? = null, rich: Boolean = false ) : SimplePanel(setOf("form-group")), StringFormControl { - internal var options = options + /** + * A list of options (label to value pairs) for the group. + */ + var options = options set(value) { field = value setChildrenFromOptions() } + /** + * A value of the selected option. + */ override var value = value set(value) { field = value setValueToChildren(value) } + /** + * Determines if the options are rendered inline. + */ var inline: Boolean = inline set(value) { field = value @@ -39,11 +82,17 @@ open class RadioGroup( set(value) { setDisabledToChildren(value) } + /** + * The label text of the options group. + */ var label get() = flabel.text set(value) { flabel.text = value } + /** + * Determines if [label] can contain HTML code. + */ var rich get() = flabel.rich set(value) { @@ -62,7 +111,7 @@ open class RadioGroup( } companion object { - var counter = 0 + internal var counter = 0 } override fun getSnClass(): List<StringBoolPair> { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt index 774bb654..c026ccfd 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt @@ -1,3 +1,24 @@ +/* + * 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 @@ -5,12 +26,18 @@ import pl.treksoft.kvision.KVManager.AJAX_REQUEST_DELAY import pl.treksoft.kvision.KVManager.KVNULL import pl.treksoft.kvision.utils.obj -enum class HttpType(val type: String) { +/** + * HTTP protocol type for the AJAX call. + */ +enum class HTTPTYPE(internal val type: String) { GET("GET"), POST("POST") } -enum class DataType(val type: String) { +/** + * Data type for the AJAX call. + */ +enum class DATATYPE(internal val type: String) { JSON("json"), JSONP("jsonp"), XML("xml"), @@ -18,18 +45,53 @@ enum class DataType(val type: String) { 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 processData: (dynamic) -> dynamic, val beforeSend: ((JQueryXHR) -> dynamic)? = null, - val processParams: dynamic = null, val httpType: HttpType = HttpType.GET, - val dataType: DataType = DataType.JSON, val minLength: Int = 0, + 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.processData(data) + val processedData = this.preprocessData(data) if (emptyOption) { val ret = mutableListOf(obj { this.value = KVNULL @@ -45,9 +107,9 @@ fun AjaxOptions.toJs(emptyOption: Boolean): dynamic { return obj { this.ajax = obj { this.url = url - this.type = httpType.type + this.type = HTTPTYPE.type this.dataType = dataType.type - this.data = processParams + this.data = data this.beforeSend = beforeSend } this.preprocessData = procData diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt index 49259ab1..e8494d58 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/Select.kt @@ -1,15 +1,50 @@ +/* + * 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.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 -import pl.treksoft.kvision.core.StringBoolPair -import pl.treksoft.kvision.core.StringPair +/** + * 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 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, @@ -17,66 +52,97 @@ open class Select( 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 } - var startValue - get() = input.startValue - set(value) { - input.startValue = value - } + /** + * The name attribute of the generated HTML select element. + */ var name get() = input.name set(value) { input.name = 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) { @@ -87,11 +153,25 @@ open class Select( set(value) { input.disabled = 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.text set(value) { flabel.text = value } + /** + * Determines if [label] can contain HTML code. + */ var rich get() = flabel.rich set(value) { @@ -121,7 +201,7 @@ open class Select( } companion object { - var counter = 0 + internal var counter = 0 } override fun getSnClass(): List<StringBoolPair> { @@ -172,19 +252,24 @@ open class Select( 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() } - - open fun deselect() { - input.deselect() - } } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt index 83eca138..7374a30d 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectInput.kt @@ -1,22 +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 pl.treksoft.kvision.form.select import com.github.snabbdom.VNode +import pl.treksoft.kvision.KVManager.KVNULL import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.CssSize -import pl.treksoft.kvision.KVManager.KVNULL +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.html.BUTTONSTYLE import pl.treksoft.kvision.panel.SimplePanel -import pl.treksoft.kvision.core.StringBoolPair -import pl.treksoft.kvision.core.StringPair -import pl.treksoft.kvision.utils.obj import pl.treksoft.kvision.utils.asString +import pl.treksoft.kvision.utils.obj -enum class SELECTWIDTHTYPE(val value: String) { +/** + * 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, @@ -24,85 +61,122 @@ open class SelectInput( classes: Set<String> = setOf() ) : SimplePanel(classes) { + /** + * A list of options (label to value pairs) for the select control. + */ internal var options = options set(value) { field = value setChildrenFromOptions() } - + /** + * A value of the selected option. + */ var value: String? = value set(value) { field = value refreshState() } - - var startValue: String? = value - set(value) { - field = value - this.value = value - refresh() - } + /** + * The name attribute of the generated HTML select element. + */ var name: String? = null set(value) { field = value refresh() } + /** + * Determines if multiple value selection is allowed. + */ var multiple: Boolean = multiple set(value) { field = value refresh() } + /** + * Additional options for remote (AJAX) data source. + */ var ajaxOptions: AjaxOptions? = ajaxOptions set(value) { field = value if (value != null) liveSearch = true refresh() } + /** + * Maximal number of selected options. + */ var maxOptions: Int? = null set(value) { field = value refresh() } + /** + * Determines if live search is available. + */ var liveSearch: Boolean = false set(value) { field = value refresh() } + /** + * The placeholder for the select control. + */ var placeholder: String? = null set(value) { field = value refresh() } + /** + * The style of the select control. + */ var style: BUTTONSTYLE? = null set(value) { field = value refresh() } + /** + * The width of the select control. + */ var selectWidth: CssSize? = null set(value) { field = value refresh() } + /** + * The width type of the select control. + */ var selectWidthType: SELECTWIDTHTYPE? = null set(value) { field = value refresh() } + /** + * Determines if an empty option is automatically generated. + */ var emptyOption: Boolean = false set(value) { field = value setChildrenFromOptions() } + /** + * Determines if the field is disabled. + */ var disabled: Boolean = false set(value) { field = value refresh() } + /** + * Determines if the select is automatically focused. + */ var autofocus: Boolean? = null set(value) { field = value refresh() } + /** + * The size of the input. + */ var size: INPUTSIZE? = null set(value) { field = value @@ -141,7 +215,7 @@ open class SelectInput( } override fun render(): VNode { - return kvh("select", childrenVNodes()) + return render("select", childrenVNodes()) } override fun add(child: Component): SimplePanel { @@ -184,22 +258,27 @@ open class SelectInput( 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") } - open fun deselect() { - getElementJQueryD()?.selectpicker("deselectAll") - } - override fun getSnClass(): List<StringBoolPair> { val cl = super.getSnClass().toMutableList() cl.add("selectpicker" to true) @@ -209,7 +288,7 @@ open class SelectInput( return cl } - fun refreshSelectInput() { + private fun refreshSelectInput() { getElementJQueryD()?.selectpicker("refresh") refreshState() } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt index 391ee6a3..6819961f 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOptGroup.kt @@ -1,29 +1,74 @@ +/* + * 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.panel.SimplePanel 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: String = label set(value) { field = value refresh() } - private var options = options + /** + * A list of options (label to value pairs) for the group. + */ + var options = options set(value) { field = value setChildrenFromOptions() } + /** + * Maximal number of selected options in the group. + */ var maxOptions: Int? = maxOptions set(value) { field = value refresh() } + /** + * Determines if the group is disabled. + */ var disabled: Boolean = disabled set(value) { field = value @@ -35,7 +80,7 @@ open class SelectOptGroup( } override fun render(): VNode { - return kvh("optgroup", childrenVNodes()) + return render("optgroup", childrenVNodes()) } private fun setChildrenFromOptions() { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt index f5ea25cd..e7a49120 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/select/SelectOption.kt @@ -1,45 +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.Widget 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: String? = value set(value) { field = value refresh() } - + /** + * The label of the option. + */ var label: String? = label set(value) { field = value refresh() } - + /** + * The subtext after the label of the option. + */ var subtext: String? = subtext set(value) { field = value refresh() } - + /** + * The icon before the label of the option. + */ var icon: String? = icon set(value) { field = value refresh() } - + /** + * Determines if the option should be rendered as divider. + */ var divider: Boolean = divider set(value) { field = value refresh() } - + /** + * Determines if the option should be disabled. + */ var disabled: Boolean = disabled set(value) { field = value @@ -48,9 +94,9 @@ open class SelectOption( override fun render(): VNode { return if (!divider) { - kvh("option", arrayOf(label ?: value)) + render("option", arrayOf(label ?: value)) } else { - kvh("option") + render("option") } } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt b/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt index c6b49684..4d7a3150 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/spinner/Spinner.kt @@ -1,13 +1,48 @@ +/* + * 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.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 -import pl.treksoft.kvision.core.StringBoolPair +/** + * The form field 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 label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ open class Spinner( value: Number? = null, min: Int = 0, max: Int = DEFAULT_MAX, step: Double = DEFAULT_STEP, decimals: Int = 0, buttonsType: BUTTONSTYPE = BUTTONSTYPE.VERTICAL, @@ -15,46 +50,84 @@ open class Spinner( 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 } + /** + * The name attribute of the generated HTML input element. + */ var name get() = input.name set(value) { @@ -65,21 +138,33 @@ open class Spinner( set(value) { input.disabled = 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.text set(value) { flabel.text = value } + /** + * Determines if [label] can contain HTML code. + */ var rich get() = flabel.rich set(value) { @@ -107,7 +192,7 @@ open class Spinner( } companion object { - var counter = 0 + internal var counter = 0 } override fun getSnClass(): List<StringBoolPair> { @@ -138,11 +223,17 @@ open class Spinner( 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 diff --git a/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt index ae064cdb..63ad0852 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/spinner/SpinnerInput.kt @@ -1,29 +1,69 @@ +/* + * 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.Widget -import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.utils.obj +/** + * Spinner buttons layout types. + */ enum class BUTTONSTYPE { NONE, HORIZONTAL, VERTICAL } -enum class FORCETYPE(val value: String) { +/** + * Spinner force rounding types. + */ +enum class FORCETYPE(internal val value: String) { NONE("none"), ROUND("round"), FLOOR("floor"), CEIL("cail") } -const val DEFAULT_STEP = 1.0 -const val DEFAULT_MAX = 100 +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, @@ -53,72 +93,117 @@ open class SpinnerInput( } } + /** + * Spinner value. + */ var value: Number? = value set(value) { field = 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: Number? = value set(value) { field = value this.value = value refresh() } + /** + * Minimal value. + */ var min: Int = min set(value) { field = value refreshSpinner() } + /** + * Maximal value. + */ var max: Int = max set(value) { field = value refreshSpinner() } + /** + * Step value. + */ var step: Double = step set(value) { field = value refreshSpinner() } + /** + * Number of decimal digits value. + */ var decimals: Int = decimals set(value) { field = value refreshSpinner() } + /** + * Spinner buttons type. + */ var buttonsType: BUTTONSTYPE = buttonsType set(value) { field = value refreshSpinner() } + /** + * Spinner force rounding type. + */ var forceType: FORCETYPE = forceType set(value) { field = value refreshSpinner() } + /** + * The placeholder for the spinner input. + */ var placeholder: String? = null set(value) { field = value refresh() } + /** + * The name attribute of the generated HTML input element. + */ var name: String? = null set(value) { field = value refresh() } + /** + * Determines if the field is disabled. + */ var disabled: Boolean = false set(value) { field = value refresh() } + /** + * Determines if the spinner is automatically focused. + */ var autofocus: Boolean? = null set(value) { field = value refresh() } + /** + * Determines if the spinner is read-only. + */ var readonly: Boolean? = null set(value) { field = value refresh() } + /** + * The size of the input. + */ var size: INPUTSIZE? = null set(value) { field = value @@ -128,7 +213,7 @@ open class SpinnerInput( private var siblings: JQuery? = null override fun render(): VNode { - return kvh("input") + return render("input") } override fun getSnClass(): List<StringBoolPair> { @@ -206,15 +291,25 @@ open class SpinnerInput( 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 diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt index a3c89514..26a88f1e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractText.kt @@ -1,36 +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 pl.treksoft.kvision.form.text +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.StringFormControl import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn -import pl.treksoft.kvision.core.StringBoolPair +/** + * Base class for form field text components. + * + * @constructor + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ abstract class AbstractText(label: String? = null, rich: Boolean = false) : SimplePanel(setOf("form-group")), StringFormControl { + /** + * Text input 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 text input value. + */ var startValue get() = input.startValue set(value) { input.startValue = value } + /** + * The placeholder for the text input. + */ var placeholder get() = input.placeholder set(value) { input.placeholder = value } + /** + * The name attribute of the generated HTML input element. + */ var name get() = input.name set(value) { input.name = value } + /** + * Maximal length of the text input value. + */ var maxlength get() = input.maxlength set(value) { @@ -41,21 +87,33 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) : 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 text input is read-only. + */ var readonly get() = input.readonly set(value) { input.readonly = value } + /** + * The label text bound to the text input element. + */ var label get() = flabel.text set(value) { flabel.text = value } + /** + * Determines if [label] can contain HTML code. + */ var rich get() = flabel.rich set(value) { @@ -67,6 +125,10 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) : input.size = value } + /** + * @suppress + * Internal property + */ protected val idc = "kv_form_text_" + counter abstract override val input: AbstractTextInput final override val flabel: FieldLabel = FieldLabel(idc, label, rich) @@ -78,7 +140,7 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) : } companion object { - var counter = 0 + internal var counter = 0 } override fun getSnClass(): List<StringBoolPair> { @@ -104,4 +166,18 @@ abstract class AbstractText(label: String? = null, rich: Boolean = false) : input.removeEventListeners() return this } + + /** + * Makes the input element focused. + */ + open fun focus() { + input.focus() + } + + /** + * Makes the input element blur. + */ + open fun blur() { + input.blur() + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt index 95a5d98b..17a6689b 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/AbstractTextInput.kt @@ -1,11 +1,39 @@ +/* + * 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.kvision.core.Widget -import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.form.INPUTSIZE +/** + * Base class for basic text components. + * + * @constructor + * @param value text input value + * @param classes a set of CSS class names + */ abstract class AbstractTextInput( value: String? = null, classes: Set<String> = setOf() @@ -19,47 +47,77 @@ abstract class AbstractTextInput( } } + /** + * Text input value. + */ var value: String? = value set(value) { field = 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 text input value. + */ var startValue: String? = value set(value) { field = value this.value = value refresh() } + /** + * The placeholder for the text input. + */ var placeholder: String? = null set(value) { field = value refresh() } + /** + * The name attribute of the generated HTML input element. + */ var name: String? = null set(value) { field = value refresh() } + /** + * Maximal length of the text input value. + */ var maxlength: Int? = null set(value) { field = value refresh() } + /** + * Determines if the field is disabled. + */ var disabled: Boolean = false set(value) { field = value refresh() } + /** + * Determines if the text input is automatically focused. + */ var autofocus: Boolean? = null set(value) { field = value refresh() } + /** + * Determines if the text input is read-only. + */ var readonly: Boolean? = null set(value) { field = value refresh() } + /** + * The size of the input. + */ var size: INPUTSIZE? = null set(value) { field = value @@ -105,12 +163,20 @@ abstract class AbstractTextInput( refreshState() } + /** + * @suppress + * Internal function + */ protected open fun refreshState() { value?.let { getElementJQuery()?.`val`(it) } ?: getElementJQueryD()?.`val`(null) } + /** + * @suppress + * Internal function + */ protected open fun changeValue() { val v = getElementJQuery()?.`val`() as String? if (v != null && v.isNotEmpty()) { @@ -119,4 +185,18 @@ abstract class AbstractTextInput( this.value = null } } + + /** + * Makes the input element focused. + */ + open fun focus() { + getElementJQuery()?.focus() + } + + /** + * Makes the input element blur. + */ + open fun blur() { + getElementJQuery()?.blur() + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/Password.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/Password.kt index cbdd7adf..f3f50a63 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/Password.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/Password.kt @@ -1,5 +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.form.text +/** + * Form field password component. + * + * @constructor + * @param value text input value + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ open class Password(value: String? = null, label: String? = null, rich: Boolean = false) : Text( TEXTINPUTTYPE.PASSWORD, value, label, rich diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt index 6e1f8929..39083577 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/RichText.kt @@ -1,10 +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.form.text +/** + * Form field rich text component. + * + * @constructor + * @param value text input value + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ open class RichText( value: String? = null, label: String? = null, rich: Boolean = false ) : AbstractText(label, rich) { + /** + * Rich input control height. + */ var inputHeight get() = input.height set(value) { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt index 9df58266..ffdcc045 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/RichTextInput.kt @@ -1,3 +1,24 @@ +/* + * 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 @@ -5,13 +26,20 @@ import pl.treksoft.jquery.jQuery 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 kvh("trix-editor") + return render("trix-editor") } override fun getSnAttrs(): List<StringPair> { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt index a17c1b5d..298a3209 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/Text.kt @@ -1,16 +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 pl.treksoft.kvision.form.text - +/** + * Form field text component. + * + * @constructor + * @param type text input type (default "text") + * @param value text input value + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ open class Text( type: TEXTINPUTTYPE = TEXTINPUTTYPE.TEXT, value: String? = null, label: String? = null, rich: Boolean = false ) : AbstractText(label, rich) { + /** + * Text input type. + */ var type get() = input.type set(value) { input.type = value } + /** + * Determines if autocomplete is enabled for the input element. + */ var autocomplete get() = input.autocomplete set(value) { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt index e45d990d..02a64136 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/TextArea.kt @@ -1,20 +1,60 @@ +/* + * 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 +/** + * Form field textarea component. + * + * @constructor + * @param cols number of columns + * @param rows number of rows + * @param value text input value + * @param label label text bound to the input element + * @param rich determines if [label] can contain HTML code + */ open class TextArea( cols: Int? = null, rows: Int? = null, value: String? = null, label: String? = null, rich: Boolean = false ) : AbstractText(label, rich) { + /** + * Number of columns. + */ var cols get() = input.cols set(value) { input.cols = value } + /** + * Number of rows. + */ var rows get() = input.rows set(value) { input.rows = value } + /** + * Determines if hard wrapping is enabled for the textarea element. + */ var wrapHard get() = input.wrapHard set(value) { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt index 8efe0318..fd42de9c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/TextAreaInput.kt @@ -1,21 +1,60 @@ +/* + * 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.kvision.core.StringPair +/** + * Basic textarea component. + * + * @constructor + * @param cols number of columns + * @param rows number of rows + * @param value text input value + * @param classes a set of CSS class names + */ open class TextAreaInput(cols: Int? = null, rows: Int? = null, value: String? = null, classes: Set<String> = setOf()) : AbstractTextInput(value, classes + "form-control") { + /** + * Number of columns. + */ var cols: Int? = cols set(value) { field = value refresh() } + /** + * Number of rows. + */ var rows: Int? = rows set(value) { field = value refresh() } + /** + * Determines if hard wrapping is enabled for the textarea element. + */ var wrapHard: Boolean = false set(value) { field = value @@ -24,8 +63,8 @@ open class TextAreaInput(cols: Int? = null, rows: Int? = null, value: String? = override fun render(): VNode { return startValue?.let { - kvh("textarea", arrayOf(it)) - } ?: kvh("textarea") + render("textarea", arrayOf(it)) + } ?: render("textarea") } override fun getSnAttrs(): List<StringPair> { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt index bd945590..72791239 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/text/TextInput.kt @@ -1,21 +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.form.text import com.github.snabbdom.VNode import pl.treksoft.kvision.core.StringPair -enum class TEXTINPUTTYPE(val type: String) { +/** + * Text input types. + */ +enum class TEXTINPUTTYPE(internal val type: String) { TEXT("text"), - PASSWORD("password") + PASSWORD("password"), + EMAIL("email"), + TEL("tel"), + COLOR("color"), + SEARCH("search"), + URL("url") } +/** + * Basic text component. + * + * @constructor + * @param type text input type (default "text") + * @param value text input value + * @param classes a set of CSS class names + */ open class TextInput(type: TEXTINPUTTYPE = TEXTINPUTTYPE.TEXT, value: String? = null, classes: Set<String> = setOf()) : AbstractTextInput(value, classes + "form-control") { + /** + * Text input type. + */ var type: TEXTINPUTTYPE = type set(value) { field = value refresh() } + /** + * Determines if autocomplete is enabled for the input element. + */ var autocomplete: Boolean? = null set(value) { field = value @@ -23,7 +66,7 @@ open class TextInput(type: TEXTINPUTTYPE = TEXTINPUTTYPE.TEXT, value: String? = } override fun render(): VNode { - return kvh("input") + return render("input") } override fun getSnAttrs(): List<StringPair> { diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt index 1750c1bd..426e0644 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTime.kt @@ -1,34 +1,76 @@ +/* + * 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.StringBoolPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.form.DateFormControl import pl.treksoft.kvision.form.FieldLabel import pl.treksoft.kvision.form.HelpBlock import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.utils.SnOn -import pl.treksoft.kvision.core.StringBoolPair import kotlin.js.Date +/** + * Form field date/time chooser component. + * + * @constructor + * @param value date/time input value + * @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, 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 } + /** + * The name attribute of the generated HTML input element. + */ var name get() = input.name set(value) { @@ -39,56 +81,89 @@ open class DateTime( set(value) { input.disabled = 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.text set(value) { flabel.text = value } + /** + * Determines if [label] can contain HTML code. + */ var rich get() = flabel.rich set(value) { @@ -100,7 +175,7 @@ open class DateTime( input.size = value } - protected val idc = "kv_form_time_" + counter + private val idc = "kv_form_time_" + counter final override val input: DateTimeInput = DateTimeInput(value, format).apply { id = idc } final override val flabel: FieldLabel = FieldLabel(idc, label, rich) final override val validationInfo: HelpBlock = HelpBlock().apply { visible = false } @@ -115,7 +190,7 @@ open class DateTime( } companion object { - var counter = 0 + internal var counter = 0 } override fun getSnClass(): List<StringBoolPair> { @@ -142,10 +217,16 @@ open class DateTime( return this } + /** + * Open date/time chooser popup. + */ open fun showPopup() { input.showPopup() } + /** + * Hides date/time chooser popup. + */ open fun hidePopup() { input.hidePopup() } diff --git a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt index cac9fbda..a49f1d5f 100644 --- a/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt +++ b/src/main/kotlin/pl/treksoft/kvision/form/time/DateTimeInput.kt @@ -1,25 +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.form.time import com.github.snabbdom.VNode -import pl.treksoft.kvision.core.Widget -import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.form.INPUTSIZE import pl.treksoft.kvision.utils.obj import pl.treksoft.kvision.utils.toDateF import pl.treksoft.kvision.utils.toStringF import kotlin.js.Date -const val DEFAULT_MINUTE_STEP = 5 -const val MAX_VIEW = 4 +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: Date? = null, format: String = "YYYY-MM-DD HH:mm", classes: Set<String> = setOf() ) : Widget(classes + "form-control") { - init { this.setInternalEventListener<DateTimeInput> { change = { @@ -28,76 +56,121 @@ open class DateTimeInput( } } + /** + * Date/time input value. + */ var value: Date? = value set(value) { field = value refreshState() } + /** + * Date/time format. + */ var format: String = format set(value) { field = value refreshDatePicker() } + /** + * The placeholder for the date/time input. + */ var placeholder: String? = null set(value) { field = value refresh() } + /** + * The name attribute of the generated HTML input element. + */ var name: String? = null set(value) { field = value refresh() } + /** + * Determines if the field is disabled. + */ var disabled: Boolean = false set(value) { field = value refresh() } + /** + * Determines if the text input is automatically focused. + */ var autofocus: Boolean? = null set(value) { field = value refresh() } + /** + * Determines if the date/time input is read-only. + */ var readonly: Boolean? = null set(value) { field = value refresh() } + /** + * The size of the input. + */ var size: INPUTSIZE? = null set(value) { field = value refresh() } + /** + * Day of the week start. 0 (Sunday) to 6 (Saturday). + */ var weekStart: Int = 0 set(value) { field = value refreshDatePicker() } + /** + * Days of the week that should be disabled. Multiple values should be comma separated. + */ var daysOfWeekDisabled: Array<Int> = arrayOf() set(value) { field = value refreshDatePicker() } + /** + * Determines if *Clear* button should be visible. + */ var clearBtn: Boolean = true set(value) { field = value refreshDatePicker() } + /** + * Determines if *Today* button should be visible. + */ var todayBtn: Boolean = false set(value) { field = value refreshDatePicker() } + /** + * Determines if the current day should be highlighted. + */ var todayHighlight: Boolean = false set(value) { field = value refreshDatePicker() } + /** + * The increment used to build the hour view. + */ var minuteStep: Int = DEFAULT_MINUTE_STEP set(value) { field = value refreshDatePicker() } + /** + * Determines if meridian views are visible in day and hour views. + */ var showMeridian: Boolean = false set(value) { field = value @@ -105,7 +178,7 @@ open class DateTimeInput( } override fun render(): VNode { - return kvh("input") + return render("input") } override fun getSnClass(): List<StringBoolPair> { @@ -170,10 +243,16 @@ open class DateTimeInput( } } + /** + * Open date/time chooser popup. + */ open fun showPopup() { getElementJQueryD()?.datetimepicker("show") } + /** + * Hides date/time chooser popup. + */ open fun hidePopup() { getElementJQueryD()?.datetimepicker("hide") } @@ -216,6 +295,10 @@ open class DateTimeInput( }) } + /** + * Get value of date/time input control as String + * @return value as a String + */ fun getValueAsString(): String? { return value?.toStringF(format) } diff --git a/src/main/kotlin/pl/treksoft/kvision/hmr/ApplicationBase.kt b/src/main/kotlin/pl/treksoft/kvision/hmr/ApplicationBase.kt index ceea0fbc..bd92bc25 100644 --- a/src/main/kotlin/pl/treksoft/kvision/hmr/ApplicationBase.kt +++ b/src/main/kotlin/pl/treksoft/kvision/hmr/ApplicationBase.kt @@ -1,5 +1,23 @@ -/** - * @author Robert Jaros +/* + * 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.hmr diff --git a/src/main/kotlin/pl/treksoft/kvision/hmr/HMR.kt b/src/main/kotlin/pl/treksoft/kvision/hmr/HMR.kt index 59b6fe00..62cde4d9 100644 --- a/src/main/kotlin/pl/treksoft/kvision/hmr/HMR.kt +++ b/src/main/kotlin/pl/treksoft/kvision/hmr/HMR.kt @@ -1,5 +1,23 @@ -/** - * @author Robert Jaros +/* + * 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.hmr diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt index bb48558f..874c4182 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt @@ -1,13 +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.html import com.github.snabbdom.VNode import org.w3c.dom.events.MouseEvent import pl.treksoft.kvision.core.ResString -import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget -enum class BUTTONSTYLE(val className: String) { +/** + * Button styles. + */ +enum class BUTTONSTYLE(internal val className: String) { DEFAULT("btn-default"), PRIMARY("btn-primary"), SUCCESS("btn-success"), @@ -17,46 +41,81 @@ enum class BUTTONSTYLE(val className: String) { LINK("btn-link") } -enum class BUTTONSIZE(val className: String) { +/** + * Button sizes. + */ +enum class BUTTONSIZE(internal val className: String) { LARGE("btn-lg"), SMALL("btn-sm"), XSMALL("btn-xs") } +/** + * Button component. + * + * @constructor + * @param text button label + * @param icon button icon + * @param style button style + * @param disabled button state + * @param classes a set of CSS class names + */ open class Button( text: String, icon: String? = null, style: BUTTONSTYLE = BUTTONSTYLE.DEFAULT, disabled: Boolean = false, classes: Set<String> = setOf() ) : Widget(classes) { + + /** + * Button label. + */ var text = text set(value) { field = value refresh() } + /** + * Button icon. + */ var icon = icon set(value) { field = value refresh() } + /** + * Button style. + */ var style = style set(value) { field = value refresh() } + /** + * Determines if button is disabled. + */ var disabled = disabled set(value) { field = value refresh() } + /** + * Button image. + */ var image: ResString? = null set(value) { field = value refresh() } + /** + * Button size. + */ var size: BUTTONSIZE? = null set(value) { field = value refresh() } + /** + * Determines if the button takes all the space horizontally. + */ var block = false set(value) { field = value @@ -65,7 +124,7 @@ open class Button( override fun render(): VNode { val t = createLabelWithIcon(text, icon, image) - return kvh("button", t) + return render("button", t) } override fun getSnClass(): List<StringBoolPair> { @@ -88,6 +147,9 @@ open class Button( return super.getSnAttrs() + ("type" to "button") } + /** + * A convenient helper for easy setting onClick event handler. + */ open fun onClick(handler: Button.(MouseEvent) -> Unit): Button { this.setEventListener<Button> { click = { e -> diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Image.kt b/src/main/kotlin/pl/treksoft/kvision/html/Image.kt index 38b8825a..9321b4dc 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Image.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Image.kt @@ -1,49 +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 pl.treksoft.kvision.html import com.github.snabbdom.VNode import pl.treksoft.kvision.core.ResString -import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget -enum class IMAGESHAPE(val className: String) { +/** + * Image shapes. + */ +enum class IMAGESHAPE(internal val className: String) { ROUNDED("img-rounded"), CIRCLE("img-circle"), THUMBNAIL("img-thumbnail") } +/** + * Image component. + * + * @constructor + * @param src image URL + * @param alt alternative text + * @param responsive determines if the image is rendered as responsive + * @param shape image shape + * @param centered determines if the image is rendered centered + * @param classes a set of CSS class names + */ open class Image( src: ResString, alt: String? = null, responsive: Boolean = false, shape: IMAGESHAPE? = null, centered: Boolean = false, classes: Set<String> = setOf() ) : Widget(classes) { - internal var src = src + /** + * URL of the image. + */ + var src = src set(value) { field = value refresh() } - private var alt = alt + /** + * The alternative text of the image. + */ + var alt = alt set(value) { field = value refresh() } - private var responsive = responsive + /** + * Determines if the image is rendered as responsive. + */ + var responsive = responsive set(value) { field = value refresh() } - private var shape = shape + /** + * The shape of the image. + */ + var shape = shape set(value) { field = value refresh() } - private var centered = centered + /** + * Determines if the image is rendered as centered. + */ + var centered = centered set(value) { field = value refresh() } override fun render(): VNode { - return kvh("img") + return render("img") } override fun getSnAttrs(): List<StringPair> { diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Label.kt b/src/main/kotlin/pl/treksoft/kvision/html/Label.kt index 3ce23639..1701150e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Label.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Label.kt @@ -1,6 +1,31 @@ +/* + * 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.html -import pl.treksoft.kvision.html.TAG -import pl.treksoft.kvision.html.Tag - +/** + * Simple label component rendered as *span*. + * + * @constructor + * @param text label text + * @param rich determines if [text] can contain HTML code + */ open class Label(text: String, rich: Boolean = false) : Tag(TAG.SPAN, text, rich) diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt index 83f03676..ad8897d5 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt @@ -1,30 +1,73 @@ +/* + * 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.html import com.github.snabbdom.VNode import pl.treksoft.kvision.core.ResString -import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.panel.SimplePanel +/** + * Link component. + * + * @constructor + * @param label link label + * @param url link URL address + * @param icon link icon + * @param image link image + * @param classes a set of CSS class names + */ open class Link( label: String, url: String, icon: String? = null, image: ResString? = null, classes: Set<String> = setOf() ) : SimplePanel(classes) { - private var label = label + /** + * Link label. + */ + var label = label set(value) { field = value refresh() } - private var url = url + /** + * Link URL address. + */ + var url = url set(value) { field = value refresh() } - private var icon = icon + /** + * Link icon. + */ + var icon = icon set(value) { field = value refresh() } - private var image = image + /** + * Link image. + */ + var image = image set(value) { field = value refresh() @@ -32,7 +75,7 @@ open class Link( override fun render(): VNode { val t = createLabelWithIcon(label, icon, image) - return kvh("a", t + childrenVNodes()) + return render("a", t + childrenVNodes()) } override fun getSnAttrs(): List<StringPair> { diff --git a/src/main/kotlin/pl/treksoft/kvision/html/List.kt b/src/main/kotlin/pl/treksoft/kvision/html/List.kt index c4aed749..c8252080 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/List.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/List.kt @@ -1,12 +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.html import com.github.snabbdom.VNode import com.github.snabbdom.h import pl.treksoft.kvision.KVManager -import pl.treksoft.kvision.panel.SimplePanel +import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.panel.SimplePanel -enum class LIST(val tagName: String) { +/** + * HTML list types. + */ +enum class LISTTYPE(internal val tagName: String) { UL("ul"), OL("ol"), UNSTYLED("ul"), @@ -15,21 +40,42 @@ enum class LIST(val tagName: String) { DL_HORIZ("dl") } +/** + * HTML list component. + * + * The list component can be populated directly from *elements* parameter or manually by adding + * any [Component] to the container. + * + * @constructor + * @param type list type + * @param elements optional list of elements + * @param rich determines if [elements] can contain HTML code + * @param classes a set of CSS class names + */ open class ListTag( - type: LIST, elements: List<String>? = null, rich: Boolean = false, + type: LISTTYPE, elements: List<String>? = null, rich: Boolean = false, classes: Set<String> = setOf() ) : SimplePanel(classes) { + /** + * List type. + */ var type = type set(value) { field = value refresh() } - private var elements = elements + /** + * List of elements. + */ + var elements = elements set(value) { field = value refresh() } - private var rich = rich + /** + * Determines if [elements] can contain HTML code. + */ + var rich = rich set(value) { field = value refresh() @@ -37,29 +83,31 @@ open class ListTag( override fun render(): VNode { val childrenElements = when (type) { - LIST.UL, LIST.OL, LIST.UNSTYLED, LIST.INLINE -> elements?.map { el -> element("li", el, rich) } - LIST.DL, LIST.DL_HORIZ -> elements?.mapIndexed { index, el -> + LISTTYPE.UL, LISTTYPE.OL, LISTTYPE.UNSTYLED, LISTTYPE.INLINE -> elements?.map { el -> + element("li", el, rich) + } + LISTTYPE.DL, LISTTYPE.DL_HORIZ -> elements?.mapIndexed { index, el -> element(if (index % 2 == 0) "dt" else "dd", el, rich) } }?.toTypedArray() return if (childrenElements != null) { - kvh(type.tagName, childrenElements + childrenVNodes()) + render(type.tagName, childrenElements + childrenVNodes()) } else { - kvh(type.tagName, childrenVNodes()) + render(type.tagName, childrenVNodes()) } } override fun childrenVNodes(): Array<VNode> { val childrenElements = children.filter { it.visible } val res = when (type) { - LIST.UL, LIST.OL, LIST.UNSTYLED, LIST.INLINE -> childrenElements.map { v -> + LISTTYPE.UL, LISTTYPE.OL, LISTTYPE.UNSTYLED, LISTTYPE.INLINE -> childrenElements.map { v -> if (v is Tag && v.type == TAG.LI) { v.renderVNode() } else { h("li", arrayOf(v.renderVNode())) } } - LIST.DL, LIST.DL_HORIZ -> childrenElements.mapIndexed { index, v -> + LISTTYPE.DL, LISTTYPE.DL_HORIZ -> childrenElements.mapIndexed { index, v -> if (v is Tag && v.type == TAG.LI) { v.renderVNode() } else { @@ -82,9 +130,9 @@ open class ListTag( val cl = super.getSnClass().toMutableList() @Suppress("NON_EXHAUSTIVE_WHEN") when (type) { - LIST.UNSTYLED -> cl.add("list-unstyled" to true) - LIST.INLINE -> cl.add("list-inline" to true) - LIST.DL_HORIZ -> cl.add("dl-horizontal" to true) + LISTTYPE.UNSTYLED -> cl.add("list-unstyled" to true) + LISTTYPE.INLINE -> cl.add("list-inline" to true) + LISTTYPE.DL_HORIZ -> cl.add("dl-horizontal" to true) } return cl } diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt index 11c935b2..557784b0 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt @@ -1,12 +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.html import com.github.snabbdom.VNode import pl.treksoft.kvision.KVManager -import pl.treksoft.kvision.panel.SimplePanel import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.panel.SimplePanel +/** + * HTML tags. + */ @Suppress("EnumNaming") -enum class TAG(val tagName: String) { +enum class TAG(internal val tagName: String) { H1("h1"), H2("h2"), H3("h3"), @@ -43,6 +67,9 @@ enum class TAG(val tagName: String) { LI("li") } +/** + * CSS align attributes. + */ enum class ALIGN(val className: String) { LEFT("text-left"), CENTER("text-center"), @@ -51,25 +78,48 @@ enum class ALIGN(val className: String) { NOWRAP("text-nowrap") } +/** + * HTML tag component. + * + * @constructor + * @param type tag type + * @param text text content of the tag + * @param rich determines if [text] can contain HTML code + * @param align text align + * @param classes a set of CSS class names + */ open class Tag( type: TAG, text: String? = null, rich: Boolean = false, align: ALIGN? = null, classes: Set<String> = setOf() ) : SimplePanel(classes) { + + /** + * Tag type. + */ var type = type set(value) { field = value refresh() } + /** + * Text content of the tag. + */ var text = text set(value) { field = value refresh() } + /** + * Determines if [text] can contain HTML code. + */ var rich = rich set(value) { field = value refresh() } + /** + * Text align. + */ var align = align set(value) { field = value @@ -79,12 +129,12 @@ open class Tag( override fun render(): VNode { return if (text != null) { if (rich) { - kvh(type.tagName, arrayOf(KVManager.virtualize("<span>$text</span>")) + childrenVNodes()) + render(type.tagName, arrayOf(KVManager.virtualize("<span>$text</span>")) + childrenVNodes()) } else { - kvh(type.tagName, childrenVNodes() + arrayOf(text)) + render(type.tagName, childrenVNodes() + arrayOf(text)) } } else { - kvh(type.tagName, childrenVNodes()) + render(type.tagName, childrenVNodes()) } } diff --git a/src/main/kotlin/pl/treksoft/kvision/modal/Alert.kt b/src/main/kotlin/pl/treksoft/kvision/modal/Alert.kt index 6e343dc5..f5062615 100644 --- a/src/main/kotlin/pl/treksoft/kvision/modal/Alert.kt +++ b/src/main/kotlin/pl/treksoft/kvision/modal/Alert.kt @@ -1,3 +1,24 @@ +/* + * 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.modal import pl.treksoft.kvision.core.Widget @@ -6,22 +27,45 @@ import pl.treksoft.kvision.html.BUTTONSTYLE import pl.treksoft.kvision.html.Button import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag +import pl.treksoft.kvision.utils.ENTER_KEY +/** + * Alert window based on Bootstrap modal. + * + * @constructor + * @param caption window title + * @param text window content text. + * @param rich determines if [text] can contain HTML code + * @param align text align + * @param size modal window size + * @param animation determines if animations are used + * @param callback a function called after closing window with OK button + */ open class Alert( caption: String? = null, text: String? = null, rich: Boolean = false, align: ALIGN? = null, size: MODALSIZE? = null, animation: Boolean = true, private val callback: (() -> Unit)? = null ) : Modal(caption, true, size, animation) { + + /** + * Window content text. + */ var text get() = content.text set(value) { content.text = value } + /** + * Determines if [text] can contain HTML code. + */ var rich get() = content.rich set(value) { content.rich = value } + /** + * Text align. + */ var align get() = content.align set(value) { @@ -39,6 +83,13 @@ open class Alert( } } this.addButton(okButton) + this.setInternalEventListener { + keydown = { e -> + if (e.keyCode == ENTER_KEY) { + hide() + } + } + } } override fun hide(): Widget { @@ -48,6 +99,16 @@ open class Alert( } companion object { + /** + * Helper function for opening Alert window. + * @param caption window title + * @param text window content text. + * @param rich determines if [text] can contain HTML code + * @param align text align + * @param size modal window size + * @param animation determines if animations are used + * @param callback a function called after closing window with OK button + */ @Suppress("LongParameterList") fun show( caption: String? = null, text: String? = null, rich: Boolean = false, diff --git a/src/main/kotlin/pl/treksoft/kvision/modal/CloseIcon.kt b/src/main/kotlin/pl/treksoft/kvision/modal/CloseIcon.kt index 8751b03c..5f0440a6 100644 --- a/src/main/kotlin/pl/treksoft/kvision/modal/CloseIcon.kt +++ b/src/main/kotlin/pl/treksoft/kvision/modal/CloseIcon.kt @@ -1,15 +1,39 @@ +/* + * 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.modal import com.github.snabbdom.VNode import pl.treksoft.kvision.KVManager -import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.Widget -open class CloseIcon(classes: Set<String> = setOf()) : Widget(classes) { +/** + * Helper class for close icon component. + */ +open class CloseIcon : Widget(setOf()) { override fun render(): VNode { - return kvh("button", arrayOf(KVManager.virtualize("<span aria-hidden='true'>×</span>"))) + return render("button", arrayOf(KVManager.virtualize("<span aria-hidden='true'>×</span>"))) } override fun getSnClass(): List<StringBoolPair> { @@ -21,5 +45,4 @@ open class CloseIcon(classes: Set<String> = setOf()) : Widget(classes) { override fun getSnAttrs(): List<StringPair> { return super.getSnAttrs() + listOf("type" to "button", "aria-label" to "Close") } - } diff --git a/src/main/kotlin/pl/treksoft/kvision/modal/Confirm.kt b/src/main/kotlin/pl/treksoft/kvision/modal/Confirm.kt index 80a6e4f5..33512a7e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/modal/Confirm.kt +++ b/src/main/kotlin/pl/treksoft/kvision/modal/Confirm.kt @@ -1,3 +1,24 @@ +/* + * 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.modal import pl.treksoft.kvision.html.ALIGN @@ -6,6 +27,20 @@ import pl.treksoft.kvision.html.Button import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag +/** + * Confirm window based on Bootstrap modal. + * + * @constructor + * @param caption window title + * @param text window content text. + * @param rich determines if [text] can contain HTML code + * @param align text align + * @param size modal window size + * @param animation determines if animations are used + * @param cancelVisible determines if Cancel button is visible + * @param noCallback a function called after closing window with No button + * @param yesCallback a function called after closing window with Yes button + */ open class Confirm( caption: String? = null, text: String? = null, rich: Boolean = false, align: ALIGN? = null, size: MODALSIZE? = null, animation: Boolean = true, @@ -13,22 +48,34 @@ open class Confirm( private val noCallback: (() -> Unit)? = null, private val yesCallback: (() -> Unit)? = null ) : Modal(caption, false, size, animation, false) { + /** + * Window content text. + */ var text get() = content.text set(value) { content.text = value } + /** + * Determines if [text] can contain HTML code. + */ var rich get() = content.rich set(value) { content.rich = value } + /** + * Text align. + */ var align get() = content.align set(value) { content.align = value } - private var cancelVisible = cancelVisible + /** + * Determines if Cancel button is visible. + */ + var cancelVisible = cancelVisible set(value) { field = value refreshCancelButton() @@ -75,6 +122,18 @@ open class Confirm( } companion object { + /** + * Helper function for opening Confirm window. + * @param caption window title + * @param text window content text. + * @param rich determines if [text] can contain HTML code + * @param align text align + * @param size modal window size + * @param animation determines if animations are used + * @param cancelVisible determines if Cancel button is visible + * @param noCallback a function called after closing window with No button + * @param yesCallback a function called after closing window with Yes button + */ @Suppress("LongParameterList") fun show( caption: String? = null, text: String? = null, rich: Boolean = false, diff --git a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt index b5c985b7..874b4370 100644 --- a/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt +++ b/src/main/kotlin/pl/treksoft/kvision/modal/Modal.kt @@ -1,46 +1,94 @@ +/* + * 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.modal import com.github.snabbdom.VNode import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.html.Button import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag import pl.treksoft.kvision.panel.Root import pl.treksoft.kvision.panel.SimplePanel -import pl.treksoft.kvision.core.StringBoolPair -import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.utils.obj +/** + * Modal window sizes. + */ enum class MODALSIZE(val className: String) { LARGE("modal-lg"), SMALL("modal-sm") } +/** + * Configurable modal window based on Bootstrap modal. + * + * @constructor + * @param caption window title + * @param closeButton determines if Close button is visible + * @param size modal window size + * @param animation determines if animations are used + * @param escape determines if dialog can be closed with Esc key + * @param classes a set of CSS class names + */ @Suppress("TooManyFunctions") open class Modal( caption: String? = null, closeButton: Boolean = true, size: MODALSIZE? = null, animation: Boolean = true, private val escape: Boolean = true, classes: Set<String> = setOf() ) : SimplePanel(classes) { - private var caption + + /** + * Window content text. + */ + var caption get() = captionTag.text set(value) { captionTag.text = value checkHeaderVisibility() } - private var closeButton + /** + * Determines if Close button is visible. + */ + var closeButton get() = closeIcon.visible set(value) { closeIcon.visible = value checkHeaderVisibility() } + /** + * Window size. + */ var size get() = dialog.size set(value) { dialog.size = value } - private var animation = animation + /** + * Determines if animations are used. + */ + var animation = animation set(value) { field = value refresh() @@ -48,8 +96,16 @@ open class Modal( private val dialog = ModalDialog(size) private val header = SimplePanel(setOf("modal-header")) + /** + * @suppress + * Internal property. + */ protected val closeIcon = CloseIcon() private val captionTag = Tag(TAG.H4, caption, classes = setOf("modal-title")) + /** + * @suppress + * Internal property. + */ protected val body = SimplePanel(setOf("modal-body")) private val footer = SimplePanel(setOf("modal-footer")) @@ -99,16 +155,30 @@ open class Modal( return this } + /** + * Adds given button to the bottom section of dialog window. + * @param button a [Button] component + * @return this modal + */ open fun addButton(button: Button): Modal { footer.add(button) return this } + /** + * Removes given button from the bottom section of dialog window. + * @param button a [Button] component + * @return this modal + */ open fun removeButton(button: Button): Modal { footer.remove(button) return this } + /** + * Removes all buttons from the bottom section of dialog window. + * @return this modal + */ open fun removeAllButtons(): Modal { footer.removeAll() return this @@ -155,6 +225,9 @@ open class Modal( return super.hide() } + /** + * Toggle modal window visibility. + */ open fun toggle() { if (visible) hide() @@ -173,7 +246,17 @@ open class Modal( } } -open class ModalDialog(size: MODALSIZE?) : SimplePanel(setOf("modal-dialog")) { +/** + * Internal helper class for modal content. + * + * @constructor + * @param size modal window size + */ +internal class ModalDialog(size: MODALSIZE?) : SimplePanel(setOf("modal-dialog")) { + + /** + * Modal window size. + */ var size = size set(value) { field = value diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt index e9670c1a..7f32a61c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/DockPanel.kt @@ -1,7 +1,31 @@ +/* + * 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.panel import pl.treksoft.kvision.core.Component +/** + * Dock layout directions. + */ enum class SIDE { LEFT, RIGHT, @@ -10,17 +34,51 @@ enum class SIDE { DOWN } +/** + * The container with dock layout (up, down, left, right and center positions). + * + * @constructor + * @param classes a set of CSS class names + */ open class DockPanel(classes: Set<String> = setOf()) : SimplePanel(classes = classes) { + /** + * @suppress + * Internal property. + */ protected var left: Component? = null + /** + * @suppress + * Internal property. + */ protected var center: Component? = null + /** + * @suppress + * Internal property. + */ protected var right: Component? = null + /** + * @suppress + * Internal property. + */ protected var up: Component? = null + /** + * @suppress + * Internal property. + */ protected var down: Component? = null + /** + * @suppress + * Internal property. + */ protected val mainContainer = FlexPanel( direction = FLEXDIR.COLUMN, justify = FLEXJUSTIFY.SPACEBETWEEN, alignItems = FLEXALIGNITEMS.STRETCH ) + /** + * @suppress + * Internal property. + */ protected val subContainer = FlexPanel(justify = FLEXJUSTIFY.SPACEBETWEEN, alignItems = FLEXALIGNITEMS.CENTER) init { @@ -28,33 +86,39 @@ open class DockPanel(classes: Set<String> = setOf()) : SimplePanel(classes = cla mainContainer.add(subContainer, 2) } + /** + * Adds a component to the dock container. + * @param child child component + * @param position position in the dock + * @return current container + */ @Suppress("MagicNumber") - open fun add(widget: Component, position: SIDE): DockPanel { + open fun add(child: Component, position: SIDE): DockPanel { when (position) { SIDE.UP -> { up?.let { mainContainer.remove(it) } - up = widget - mainContainer.add(widget, 1, alignSelf = FLEXALIGNITEMS.CENTER) + up = child + mainContainer.add(child, 1, alignSelf = FLEXALIGNITEMS.CENTER) } SIDE.CENTER -> { center?.let { subContainer.remove(it) } - center = widget - subContainer.add(widget, 2) + center = child + subContainer.add(child, 2) } SIDE.LEFT -> { left?.let { subContainer.remove(it) } - left = widget - subContainer.add(widget, 1) + left = child + subContainer.add(child, 1) } SIDE.RIGHT -> { right?.let { subContainer.remove(it) } - right = widget - subContainer.add(widget, 3) + right = child + subContainer.add(child, 3) } SIDE.DOWN -> { down?.let { mainContainer.remove(it) } - down = widget - mainContainer.add(widget, 3, alignSelf = FLEXALIGNITEMS.CENTER) + down = child + mainContainer.add(child, 3, alignSelf = FLEXALIGNITEMS.CENTER) } } return this @@ -78,6 +142,11 @@ open class DockPanel(classes: Set<String> = setOf()) : SimplePanel(classes = cla return this } + /** + * Removes child from given position in the dock. + * @param position position in the dock + * @return current container + */ open fun removeAt(position: SIDE): DockPanel { when (position) { SIDE.UP -> { diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt index ad3522ea..266612fe 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/FlexPanel.kt @@ -1,25 +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 pl.treksoft.kvision.panel import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.core.StyledComponent import pl.treksoft.kvision.core.WidgetWrapper -import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.utils.px -enum class FLEXDIR(val dir: String) { +/** + * CSS flexbox directions. + */ +enum class FLEXDIR(internal val dir: String) { ROW("row"), ROWREV("row-reverse"), COLUMN("column"), COLUMNREV("column-reverse") } -enum class FLEXWRAP(val wrap: String) { +/** + * CSS flexbox wrap modes. + */ +enum class FLEXWRAP(internal val wrap: String) { NOWRAP("nowrap"), WRAP("wrap"), WRAPREV("wrap-reverse") } -enum class FLEXJUSTIFY(val justify: String) { +/** + * CSS flexbox justification options. + */ +enum class FLEXJUSTIFY(internal val justify: String) { FLEXSTART("flex-start"), FLEXEND("flex-end"), CENTER("center"), @@ -28,7 +58,10 @@ enum class FLEXJUSTIFY(val justify: String) { SPACEEVENLY("space-evenly") } -enum class FLEXALIGNITEMS(val alignItems: String) { +/** + * CSS flexbox alignments options. + */ +enum class FLEXALIGNITEMS(internal val alignItems: String) { FLEXSTART("flex-start"), FLEXEND("flex-end"), CENTER("center"), @@ -36,7 +69,10 @@ enum class FLEXALIGNITEMS(val alignItems: String) { STRETCH("stretch") } -enum class FLEXALIGNCONTENT(val alignContent: String) { +/** + * CSS flexbox content alignment options. + */ +enum class FLEXALIGNCONTENT(internal val alignContent: String) { FLEXSTART("flex-start"), FLEXEND("flex-end"), CENTER("center"), @@ -45,37 +81,68 @@ enum class FLEXALIGNCONTENT(val alignContent: String) { STRETCH("stretch") } +/** + * The container with CSS flexbox layout support. + * + * @constructor + * @param direction flexbox direction + * @param wrap flexbox wrap + * @param justify flexbox content justification + * @param alignItems flexbox items alignment + * @param alignContent flexbox content alignment + * @param spacing spacing between columns/rows + * @param classes a set of CSS class names + */ open class FlexPanel( direction: FLEXDIR? = null, wrap: FLEXWRAP? = null, justify: FLEXJUSTIFY? = null, alignItems: FLEXALIGNITEMS? = null, alignContent: FLEXALIGNCONTENT? = null, spacing: Int? = null, classes: Set<String> = setOf() ) : SimplePanel(classes) { + + /** + * CSS flexbox direction. + */ var direction = direction set(value) { field = value refreshSpacing() refresh() } + /** + * CSS flexbox wrap mode. + */ var wrap = wrap set(value) { field = value refresh() } + /** + * CSS flexbox content justification. + */ var justify = justify set(value) { field = value refresh() } + /** + * CSS flexbox items alignment. + */ var alignItems = alignItems set(value) { field = value refresh() } + /** + * CSS flexbox content alignment. + */ var alignContent = alignContent set(value) { field = value refresh() } + /** + * The spacing between columns/rows. + */ var spacing = spacing set(value) { field = value @@ -83,6 +150,16 @@ open class FlexPanel( refresh() } + /** + * Adds a component to the flexbox container. + * @param child child component + * @param order child flexbox ordering + * @param grow child flexbox grow + * @param shrink child flexbox shrink + * @param basis child flexbox basis + * @param alignSelf child self alignment + * @param classes a set of CSS class names + */ @Suppress("LongParameterList") fun add( child: Component, order: Int? = null, grow: Int? = null, shrink: Int? = null, @@ -123,7 +200,7 @@ open class FlexPanel( } override fun remove(child: Component): FlexPanel { - children.find { (it as FlexWrapper).delegate == child }?.let { + children.find { (it as FlexWrapper).wrapped == child }?.let { super.remove(it) it.dispose() } @@ -162,7 +239,10 @@ open class FlexPanel( } } -class FlexWrapper( +/** + * Helper class form CSS flexbox layout. + */ +internal class FlexWrapper( delegate: Component, private val order: Int? = null, private val grow: Int? = null, private val shrink: Int? = null, private val basis: Int? = null, private val alignSelf: FLEXALIGNITEMS? = null, diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt index 549f7631..b6f1d3a5 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/GridPanel.kt @@ -1,24 +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 pl.treksoft.kvision.panel import pl.treksoft.kvision.core.Component -import pl.treksoft.kvision.core.WidgetWrapper import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.core.WidgetWrapper -enum class GRIDJUSTIFY(val justify: String) { +/** + * CSS grid justification options. + */ +enum class GRIDJUSTIFY(internal val justify: String) { START("start"), END("end"), CENTER("center"), STRETCH("stretch") } -enum class GRIDALIGN(val align: String) { +/** + * CSS grid alignment options. + */ +enum class GRIDALIGN(internal val align: String) { START("start"), END("end"), CENTER("center"), STRETCH("stretch") } -enum class GRIDJUSTIFYCONTENT(val justifyContent: String) { +/** + * CSS grid content justification options. + */ +enum class GRIDJUSTIFYCONTENT(internal val justifyContent: String) { START("start"), END("end"), CENTER("center"), @@ -28,7 +58,10 @@ enum class GRIDJUSTIFYCONTENT(val justifyContent: String) { SPACEEVENLY("space-evenly") } -enum class GRIDALIGNCONTENT(val alignContent: String) { +/** + * CSS grid content alignment options. + */ +enum class GRIDALIGNCONTENT(internal val alignContent: String) { START("start"), END("end"), CENTER("center"), @@ -38,13 +71,34 @@ enum class GRIDALIGNCONTENT(val alignContent: String) { SPACEEVENLY("space-evenly") } -enum class GRIDFLOW(val flow: String) { +/** + * CSS grid flow options. + */ +enum class GRIDFLOW(internal val flow: String) { ROW("row"), COLUMN("column"), ROWDENSE("row dense"), COLUMNDENSE("column dense") } +/** + * The container with CSS grid layout support. + * + * @constructor + * @param autoColumns grid auto columns + * @param autoRows grid auto rows + * @param autoFlow grid auto flow + * @param templateColumns grid columns template + * @param templateRows grid rows template + * @param templateAreas grid areas template + * @param columnGap grid column gap + * @param rowGap grid row gap + * @param justifyItems grid items justification + * @param alignItems grid items alignment + * @param justifyContent flexbox content justification + * @param alignContent flexbox content alignment + * @param classes a set of CSS class names + */ open class GridPanel( autoColumns: String? = null, autoRows: String? = null, autoFlow: GRIDFLOW? = null, templateColumns: String? = null, templateRows: String? = null, templateAreas: List<String>? = null, @@ -52,67 +106,117 @@ open class GridPanel( alignItems: GRIDALIGN? = null, justifyContent: GRIDJUSTIFYCONTENT? = null, alignContent: GRIDALIGNCONTENT? = null, classes: Set<String> = setOf() ) : SimplePanel(classes) { + + /** + * CSS grid auto columns. + */ var autoColumns = autoColumns set(value) { field = value refresh() } + /** + * CSS grid auto rows. + */ var autoRows = autoRows set(value) { field = value refresh() } + /** + * CSS grid auto flow. + */ var autoFlow = autoFlow set(value) { field = value refresh() } + /** + * CSS grid columns template. + */ var templateColumns = templateColumns set(value) { field = value refresh() } + /** + * CSS grid rows template. + */ var templateRows = templateRows set(value) { field = value refresh() } + /** + * CSS grid areas template. + */ var templateAreas = templateAreas set(value) { field = value refresh() } + /** + * CSS grid column gap. + */ var columnGap = columnGap set(value) { field = value refresh() } + /** + * CSS grid row gap. + */ var rowGap = rowGap set(value) { field = value refresh() } + /** + * CSS grid items justification. + */ var justifyItems = justifyItems set(value) { field = value refresh() } + /** + * CSS grid items alignment. + */ var alignItems = alignItems set(value) { field = value refresh() } + /** + * CSS grid content justification. + */ var justifyContent = justifyContent set(value) { field = value refresh() } + /** + * CSS grid content alignment. + */ var alignContent = alignContent set(value) { field = value refresh() } + /** + * Adds a component to the grid container. + * @param child child component + * @param columnStart number of starting column + * @param rowStart number of starting row + * @param columnEnd number of ending column + * @param rowEnd number of ending row + * @param area grid area + * @param justifySelf child self justification + * @param alignSelf child self alignment + * @param classes a set of CSS class names + * @return current container + */ @Suppress("LongParameterList") fun add( child: Component, columnStart: Int? = null, rowStart: Int? = null, @@ -133,7 +237,7 @@ open class GridPanel( } override fun remove(child: Component): GridPanel { - children.find { (it as GridWrapper).delegate == child }?.let { + children.find { (it as GridWrapper).wrapped == child }?.let { super.remove(it) it.dispose() } diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/HPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/HPanel.kt index 841985ba..7639ca3b 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/HPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/HPanel.kt @@ -1,5 +1,38 @@ +/* + * 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.panel +/** + * The container with horizontal layout. + * + * This is a special case of the flexbox layout. + * + * @constructor + * @param wrap flexbox wrap + * @param justify flexbox content justification + * @param alignItems flexbox items alignment + * @param spacing spacing between columns/rows + * @param classes a set of CSS class names + */ open class HPanel( wrap: FLEXWRAP? = null, justify: FLEXJUSTIFY? = null, alignItems: FLEXALIGNITEMS? = null, spacing: Int? = null, classes: Set<String> = setOf() diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt index f4630298..93588617 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/ResponsiveGridPanel.kt @@ -1,3 +1,24 @@ +/* + * 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.panel import pl.treksoft.kvision.core.Component @@ -6,31 +27,57 @@ import pl.treksoft.kvision.html.ALIGN import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag -enum class GRIDSIZE(val size: String) { +/** + * Bootstrap grid sizes. + */ +enum class GRIDSIZE(internal val size: String) { XS("xs"), SM("sm"), MD("md"), LG("lg") } -const val MAX_COLUMNS = 12 +internal const val MAX_COLUMNS = 12 internal data class WidgetParam(val widget: Component, val size: Int, val offset: Int) +/** + * The container with support for Bootstrap responsive grid layout. + * + * @constructor + * @param gridsize grid size + * @param rows number of rows + * @param cols number of columns + * @param align text align of grid cells + * @param classes a set of CSS class names + */ open class ResponsiveGridPanel( private val gridsize: GRIDSIZE = GRIDSIZE.MD, private var rows: Int = 0, private var cols: Int = 0, align: ALIGN? = null, classes: Set<String> = setOf() ) : SimplePanel(classes) { - protected var align = align + + /** + * Text align of grid cells. + */ + var align = align set(value) { field = value - refresh() + refreshRowContainers() } internal val map = mutableMapOf<Int, MutableMap<Int, WidgetParam>>() private var auto: Boolean = true + /** + * Adds child component to the grid. + * @param child child component + * @param col column number + * @param row row number + * @param size cell size (colspan) + * @param offset cell offset + * @return this container + */ open fun add(child: Component, col: Int, row: Int, size: Int = 0, offset: Int = 0): ResponsiveGridPanel { val cRow = if (row < 0) 0 else row val cCol = if (col < 0) 0 else col @@ -68,6 +115,12 @@ open class ResponsiveGridPanel( return this } + /** + * Removes child component at given location (column, row). + * @param col column number + * @param row row number + * @return this container + */ open fun removeAt(col: Int, row: Int): ResponsiveGridPanel { map[row]?.remove(col) refreshRowContainers() @@ -75,7 +128,7 @@ open class ResponsiveGridPanel( } @Suppress("ComplexMethod", "NestedBlockDepth") - protected open fun refreshRowContainers() { + private fun refreshRowContainers() { singleRender { clearRowContainers() val num = MAX_COLUMNS / cols diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt b/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt index 88634bea..e10fdc86 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/Root.kt @@ -1,10 +1,43 @@ +/* + * 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.panel import com.github.snabbdom.VNode import pl.treksoft.kvision.KVManager -import pl.treksoft.kvision.modal.Modal import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.modal.Modal +/** + * Root container. + * + * This container is bound to the specific element in the main HTML file of the project. + * It is always the root of components tree and it is responsible for rendering and updating + * Snabbdom virtual DOM. + * + * @constructor + * @param id ID attribute of element in the main HTML file + * @param fixed if false, the container is rendered with Bootstrap "container-fluid" class, + * otherwise it's rendered with "container" class (default is false) + */ class Root(id: String, private val fixed: Boolean = false) : SimplePanel() { private val modals: MutableList<Modal> = mutableListOf() private var rootVnode: VNode = renderVNode() @@ -18,7 +51,7 @@ class Root(id: String, private val fixed: Boolean = false) : SimplePanel() { } override fun render(): VNode { - return kvh("div#" + id, childrenVNodes() + modalsVNodes()) + return render("div#" + id, childrenVNodes() + modalsVNodes()) } internal fun addModal(modal: Modal) { diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt index 51c42a06..b210f2cb 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/SimplePanel.kt @@ -1,3 +1,24 @@ +/* + * 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.panel import com.github.snabbdom.VNode @@ -5,17 +26,32 @@ import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.core.Widget +/** + * Basic container class, rendered as a DIV element with all children directly within. + * + * @constructor + * @param classes a set of CSS class names + */ open class SimplePanel(classes: Set<String> = setOf()) : Widget(classes), Container { internal val children: MutableList<Component> = mutableListOf() override fun render(): VNode { - return kvh("div", childrenVNodes()) + return render("div", childrenVNodes()) } + /** + * Returns the array of the children Snabbdom vnodes. + * @return array of children vnodes + */ protected open fun childrenVNodes(): Array<VNode> { return children.filter { it.visible }.map { it.renderVNode() }.toTypedArray() } + /** + * Protected and final method to add given component to the current container. + * @param child child component + * @return current container + */ protected fun addInternal(child: Component): SimplePanel { children.add(child) child.parent = this diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt index 10595a37..cfeadd58 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt @@ -1,3 +1,24 @@ +/* + * 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.panel import com.github.snabbdom.VNode @@ -9,11 +30,24 @@ import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag import pl.treksoft.kvision.utils.obj -enum class DIRECTION(val dir: String) { +/** + * Split panel direction. + */ +enum class DIRECTION(internal val dir: String) { HORIZONTAL("horizontal"), VERTICAL("vertical") } +/** + * The container with draggable splitter. + * + * It is required to have exactly two children, for both sides of the splitter. Otherwise it will be + * rendered as empty. + * + * @constructor + * @param direction direction of the splitter + * @param classes a set of CSS class names + */ open class SplitPanel( private val direction: DIRECTION = DIRECTION.VERTICAL, classes: Set<String> = setOf() @@ -59,7 +93,7 @@ open class SplitPanel( } } -class Splitter(private val splitPanel: SplitPanel, direction: DIRECTION) : Tag( +internal class Splitter(private val splitPanel: SplitPanel, direction: DIRECTION) : Tag( TAG.DIV, classes = setOf("splitter-" + direction.dir) ) { @@ -75,6 +109,6 @@ class Splitter(private val splitPanel: SplitPanel, direction: DIRECTION) : Tag( } companion object { - var counter = 0 + internal var counter = 0 } } diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt index e69cc416..672c8690 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt @@ -1,13 +1,47 @@ +/* + * 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.panel import com.github.snabbdom.VNode import pl.treksoft.kvision.core.Component import pl.treksoft.kvision.routing.routing +/** + * The container with only one active (visible) child at any moment. + * + * It supports activating children by a JavaScript route. + * + * @constructor + * @param activateLast determines if added component is automatically activated (default true) + * @param classes a set of CSS class names + */ open class StackPanel( private val activateLast: Boolean = true, classes: Set<String> = setOf() ) : SimplePanel(classes) { + + /** + * The index of active (visible) child. + */ var activeIndex = -1 set(value) { field = value @@ -22,6 +56,12 @@ open class StackPanel( } } + /** + * Adds given component and bounds it's activation to a given route. + * @param panel child component + * @param route JavaScript route to activate given child + * @return current container + */ open fun add(panel: Component, route: String): StackPanel { add(panel) val currentIndex = children.size - 1 diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt index 411c4a57..9072d261 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/TabPanel.kt @@ -1,3 +1,24 @@ +/* + * 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.panel import pl.treksoft.kvision.core.Component @@ -7,7 +28,19 @@ import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag import pl.treksoft.kvision.routing.routing -open class TabPanel : SimplePanel(setOf()) { +/** + * The container rendering it's children as tabs. + * + * It supports activating children by a JavaScript route. + * + * @constructor + * @param classes a set of CSS class names + */ +open class TabPanel(classes: Set<String> = setOf()) : SimplePanel(classes) { + + /** + * The index of active (visible) tab. + */ var activeIndex get() = content.activeIndex set(value) { @@ -30,6 +63,15 @@ open class TabPanel : SimplePanel(setOf()) { this.addInternal(content) } + /** + * Adds new tab and optionally bounds it's activation to a given route. + * @param title title of the tab + * @param panel child component + * @param icon icon of the tab + * @param image image of the tab + * @param route JavaScript route to activate given child + * @return current container + */ open fun addTab( title: String, panel: Component, icon: String? = null, image: ResString? = null, route: String? = null @@ -59,6 +101,9 @@ open class TabPanel : SimplePanel(setOf()) { return this } + /** + * Removes tab at given index. + */ open fun removeTab(index: Int): TabPanel { nav.remove(nav.children[index]) content.remove(content.children[index]) diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/VPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/VPanel.kt index 7870b67a..91ee4a6a 100644 --- a/src/main/kotlin/pl/treksoft/kvision/panel/VPanel.kt +++ b/src/main/kotlin/pl/treksoft/kvision/panel/VPanel.kt @@ -1,5 +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.panel +/** + * The container with vertical layout. + * + * This is a special case of the flexbox layout. + * + * @constructor + * @param justify flexbox content justification + * @param alignItems flexbox items alignment + * @param spacing spacing between columns/rows + * @param classes a set of CSS class names + */ open class VPanel( justify: FLEXJUSTIFY? = null, alignItems: FLEXALIGNITEMS? = null, spacing: Int? = null, classes: Set<String> = setOf() diff --git a/src/main/kotlin/pl/treksoft/kvision/routing/Routing.kt b/src/main/kotlin/pl/treksoft/kvision/routing/Routing.kt index 4c9aa98d..950dfe1c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/routing/Routing.kt +++ b/src/main/kotlin/pl/treksoft/kvision/routing/Routing.kt @@ -1,18 +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 pl.treksoft.kvision.routing import pl.treksoft.navigo.Navigo +/** + * A helper class for Navigo JavaScript router. + */ open class Routing : Navigo(null, true, "#!") { companion object { + /** + * Init default routing. + */ fun start() { routing = Routing() } + /** + * Shutdown default routing. + */ fun shutdown() { routing.destroy() } } } +/** + * Default JavaScript router. + */ var routing = Routing() diff --git a/src/main/kotlin/pl/treksoft/kvision/utils/Keys.kt b/src/main/kotlin/pl/treksoft/kvision/utils/Keys.kt new file mode 100644 index 00000000..d7e2927a --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/utils/Keys.kt @@ -0,0 +1,31 @@ +/* + * 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.utils + +/** + * Keycode of the ENTER key. + */ +const val ENTER_KEY = 13 +/** + * Keycode of the ESC key. + */ +const val ESC_KEY = 27 diff --git a/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt b/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt index 269fa6cb..e719d133 100644 --- a/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt +++ b/src/main/kotlin/pl/treksoft/kvision/utils/Snabbdom.kt @@ -1,3 +1,24 @@ +/* + * 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.utils import com.github.snabbdom.Attrs @@ -14,8 +35,14 @@ import pl.treksoft.kvision.core.StringBoolPair import pl.treksoft.kvision.core.StringPair import pl.treksoft.kvision.core.Widget +/** + * JavaScript Object type + */ external class Object +/** + * Helper function for creating JavaScript objects. + */ fun obj(init: dynamic.() -> Unit): dynamic { return (Object()).apply(init) } @@ -23,15 +50,26 @@ fun obj(init: dynamic.() -> Unit): dynamic { @Suppress("UnsafeCastFromDynamic") private fun vNodeData(): VNodeData = js("({})") +/** + * @suppress + * Internal interface. + */ interface KvJQueryEventObject : JQueryEventObject { val clickedIndex: Int } +/** + * Helper class for defining custom events. + */ @Suppress("UnsafeCastFromDynamic") class KvEvent(type: String, eventInitDict: CustomEventInit) : CustomEvent(type, eventInitDict) { override val detail: KvJQueryEventObject = obj {} } +/** + * @suppress + * Internal interface. + */ interface BtOn : On { var showBsDropdown: ((KvEvent) -> kotlin.Unit)? var shownBsDropdown: ((KvEvent) -> kotlin.Unit)? @@ -59,10 +97,17 @@ interface BtOn : On { var updateModel: ((KvEvent) -> kotlin.Unit)? } +/** + * @suppress + * Internal interface. + */ interface SnOn<T> : BtOn { var self: T } +/** + * Helper function for creating object parameters for Snabbdom. + */ fun snOpt(block: VNodeData.() -> Unit) = (vNodeData()::apply)(block) @Suppress("UnsafeCastFromDynamic") @@ -77,6 +122,9 @@ internal fun hooks(): Hooks { return js("({})") } +/** + * Helper function for creating style parameters for Snabbdom. + */ @Suppress("UnsafeCastFromDynamic") fun snStyle(pairs: List<StringPair>): VNodeStyle { return obj { @@ -84,6 +132,9 @@ fun snStyle(pairs: List<StringPair>): VNodeStyle { } } +/** + * Helper function for creating properties parameters for Snabbdom. + */ @Suppress("UnsafeCastFromDynamic") fun snProps(pairs: List<StringPair>): Props { return obj { @@ -91,6 +142,9 @@ fun snProps(pairs: List<StringPair>): Props { } } +/** + * Helper function for creating classes parameters for Snabbdom. + */ @Suppress("UnsafeCastFromDynamic") fun snClasses(pairs: List<StringBoolPair>): Classes { return obj { @@ -98,6 +152,9 @@ fun snClasses(pairs: List<StringBoolPair>): Classes { } } +/** + * Helper function for creating attributes parameters for Snabbdom. + */ @Suppress("UnsafeCastFromDynamic") fun snAttrs(pairs: List<StringPair>): Attrs { return obj { diff --git a/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt b/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt index 7ba01135..36aae88d 100644 --- a/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt +++ b/src/main/kotlin/pl/treksoft/kvision/utils/Utils.kt @@ -1,3 +1,24 @@ +/* + * 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("TooManyFunctions") package pl.treksoft.kvision.utils @@ -7,24 +28,85 @@ import pl.treksoft.kvision.core.CssSize import pl.treksoft.kvision.core.UNIT import kotlin.js.Date +/** + * Extension function to convert Int to CSS px units. + */ fun Int.px(): CssSize = Pair(this, UNIT.px) + +/** + * Extension function to convert Int to CSS em units. + */ fun Int.em(): CssSize = Pair(this, UNIT.em) + +/** + * Extension function to convert Int to CSS pt units. + */ fun Int.pt(): CssSize = Pair(this, UNIT.pt) + +/** + * Extension function to convert Int to CSS percent units. + */ fun Int.perc(): CssSize = Pair(this, UNIT.perc) + +/** + * Extension function to convert Int to CSS rem units. + */ fun Int.rem(): CssSize = Pair(this, UNIT.rem) + +/** + * Extension function to convert Int to CSS ch units. + */ fun Int.ch(): CssSize = Pair(this, UNIT.ch) + +/** + * Extension function to convert Int to CSS cm units. + */ fun Int.cm(): CssSize = Pair(this, UNIT.cm) + +/** + * Extension function to convert Int to CSS mm units. + */ fun Int.mm(): CssSize = Pair(this, UNIT.mm) + +/** + * Extension function to convert Int to CSS in units. + */ @Suppress("FunctionNaming") fun Int.`in`(): CssSize = Pair(this, UNIT.`in`) +/** + * Extension function to convert Int to CSS pc units. + */ fun Int.pc(): CssSize = Pair(this, UNIT.pc) + +/** + * Extension function to convert Int to CSS vh units. + */ fun Int.vh(): CssSize = Pair(this, UNIT.vh) + +/** + * Extension function to convert Int to CSS vw units. + */ fun Int.vw(): CssSize = Pair(this, UNIT.vw) + +/** + * Extension function to convert Int to CSS vmin units. + */ fun Int.vmin(): CssSize = Pair(this, UNIT.vmin) + +/** + * Extension function to convert Int to CSS vmax units. + */ fun Int.vmax(): CssSize = Pair(this, UNIT.vmax) + +/** + * Helper function to describe CSS auto value. + */ fun auto(): CssSize = Pair(0, UNIT.auto) +/** + * Extension function to convert CssSize to String. + */ fun CssSize.asString(): String { return if (this.second != UNIT.auto) { this.first.toString() + this.second.unit @@ -35,6 +117,9 @@ fun CssSize.asString(): String { private val hex = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f") +/** + * Extension function to convert Int to hex format. + */ @Suppress("MagicNumber") fun Int.toHexString(): String { var result = "" @@ -46,11 +131,21 @@ fun Int.toHexString(): String { return result } +/** + * Extension function to convert String to Date with a given date format. + * @param format date/time format + * @return Date object + */ @Suppress("UnsafeCastFromDynamic") fun String.toDateF(format: String = "YYYY-MM-DD HH:mm:ss"): Date { return KVManager.fecha.parse(this, format) } +/** + * Extension function to convert Date to String with a given date format. + * @param format date/time format + * @return String object + */ @Suppress("UnsafeCastFromDynamic") fun Date.toStringF(format: String = "YYYY-MM-DD HH:mm:ss"): String { return KVManager.fecha.format(this, format) |