From 176215818b2572eefc1df18401ddaa896ea8a1fb Mon Sep 17 00:00:00 2001 From: Robert Jaros Date: Sun, 24 Sep 2017 05:42:20 +0200 Subject: New containers: StackPanel, SplitPanel, Tabs --- src/main/kotlin/pl/treksoft/kvision/Showcase.kt | 39 +++++++++++--- .../kotlin/pl/treksoft/kvision/core/Container.kt | 5 +- .../kotlin/pl/treksoft/kvision/core/KVManager.kt | 4 ++ src/main/kotlin/pl/treksoft/kvision/core/Root.kt | 2 +- src/main/kotlin/pl/treksoft/kvision/core/Widget.kt | 34 +++++++++++- .../pl/treksoft/kvision/dropdown/DropDown.kt | 8 +-- src/main/kotlin/pl/treksoft/kvision/html/Button.kt | 13 +---- src/main/kotlin/pl/treksoft/kvision/html/Link.kt | 17 +++++- src/main/kotlin/pl/treksoft/kvision/html/Tag.kt | 2 + .../kotlin/pl/treksoft/kvision/panel/SplitPanel.kt | 63 ++++++++++++++++++++++ .../kotlin/pl/treksoft/kvision/panel/StackPanel.kt | 52 ++++++++++++++++++ src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt | 50 +++++++++++++++++ 12 files changed, 262 insertions(+), 27 deletions(-) create mode 100644 src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt create mode 100644 src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt create mode 100644 src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt (limited to 'src/main/kotlin/pl') diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt index 3bccdfb1..25bacd6b 100644 --- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt +++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt @@ -10,10 +10,11 @@ import pl.treksoft.kvision.html.* import pl.treksoft.kvision.html.TAG.H1 import pl.treksoft.kvision.modal.Alert import pl.treksoft.kvision.modal.Confirm -import pl.treksoft.kvision.modal.MODALSIZE import pl.treksoft.kvision.modal.Modal +import pl.treksoft.kvision.panel.DIRECTION +import pl.treksoft.kvision.panel.SplitPanel import pl.treksoft.kvision.routing.routing -import kotlin.browser.window +import pl.treksoft.kvision.tabs.Tabs class Showcase : ApplicationBase() { @@ -46,8 +47,8 @@ class Showcase : ApplicationBase() { hiddenBsDropdown = { e -> println("hidden" + e.detail) } } - val dd2 = DropDown("Dropdown2", listOf("abc" to "#!/abc", "def" to "#!/def", "xyz" to DISABLED.POS, - "Header" to HEADER.POS, "Separtatorek" to SEPARATOR.POS + val dd2 = DropDown("Dropdown2", listOf("abc" to "#!/abc", "def" to "#!/def", "xyz" to DISABLED.type, + "Header" to HEADER.type, "Separtatorek" to SEPARATOR.type ), "flag", dropup = true) root.add(dd2) dd2.setEventListener { @@ -61,6 +62,27 @@ class Showcase : ApplicationBase() { dd3.add(Image(Img("kotlin.png"))) root.add(dd3) + val tabs2 = Tabs() + tabs2.addTab("XXX", Label("XXX"), "fa-flag") + tabs2.addTab("YYY", Label("YYY"), "fa-flag") + + val tabs = Tabs() + tabs.addTab("Test zakładki", Label("test zakładki"), "fa-flag") + tabs.addTab("Test zakładki2", Label("test zakładki2")) + tabs.addTab("Test zakładki3", tabs2, "fa-bars") + + val split = SplitPanel() + split.add(tabs) + + val split2 = SplitPanel(DIRECTION.HORIZONTAL) + split2.add(Tag(TAG.DIV, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nec fringilla turpis, vel molestie dolor. Vestibulum ut ex eget orci porta gravida eu sit amet tortor. Suspendisse vel fermentum purus, vel ornare tellus. Vivamus dictum, risus non viverra venenatis, magna mi pharetra purus, nec dignissim risus tortor a sem. Donec tincidunt dui ut eros laoreet consectetur. Nam dapibus vestibulum sem, eget accumsan ex vestibulum ac. Curabitur ac mi sit amet eros sodales dictum. Sed at felis at nunc aliquam finibus. Vestibulum lorem nulla, dictum ac libero non, mattis dictum nisl. Aenean semper lorem turpis. Praesent pellentesque ligula est, viverra molestie leo imperdiet ut. Nam vitae hendrerit justo. Nullam tincidunt et nibh ac volutpat. Aliquam vulputate mi aliquam fermentum rhoncus.\n" + + "\n" + + "Proin porttitor diam id massa eleifend aliquet. Morbi nec erat porttitor, placerat lorem et, dignissim lectus. Cras ultricies posuere arcu, et pharetra dui laoreet in. Sed nec ipsum in sapien vestibulum maximus eu id nunc. Ut finibus aliquam nisi id vehicula. Phasellus sodales lobortis orci, non interdum risus dignissim quis. Proin bibendum consectetur diam nec mattis. Suspendisse dictum vulputate metus at tincidunt.")) + split2.add(Tag(TAG.DIV, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce nec fringilla turpis, vel molestie dolor. Vestibulum ut ex eget orci porta gravida eu sit amet tortor. Suspendisse vel fermentum purus, vel ornare tellus. Vivamus dictum, risus non viverra venenatis, magna mi pharetra purus, nec dignissim risus tortor a sem. Donec tincidunt dui ut eros laoreet consectetur. Nam dapibus vestibulum sem, eget accumsan ex vestibulum ac. Curabitur ac mi sit amet eros sodales dictum. Sed at felis at nunc aliquam finibus. Vestibulum lorem nulla, dictum ac libero non, mattis dictum nisl. Aenean semper lorem turpis. Praesent pellentesque ligula est, viverra molestie leo imperdiet ut. Nam vitae hendrerit justo. Nullam tincidunt et nibh ac volutpat. Aliquam vulputate mi aliquam fermentum rhoncus.\n" + + "\n" + + "Proin porttitor diam id massa eleifend aliquet. Morbi nec erat porttitor, placerat lorem et, dignissim lectus. Cras ultricies posuere arcu, et pharetra dui laoreet in. Sed nec ipsum in sapien vestibulum maximus eu id nunc. Ut finibus aliquam nisi id vehicula. Phasellus sodales lobortis orci, non interdum risus dignissim quis. Proin bibendum consectetur diam nec mattis. Suspendisse dictum vulputate metus at tincidunt.")) + split.add(split2) + root.add(split) val p = Tag(TAG.P, "To jest prawo", align = ALIGN.RIGHT) p.title = "Tytuł" @@ -95,11 +117,16 @@ class Showcase : ApplicationBase() { dd3.text = "Zmiana" dd3.style = BUTTONSTYLE.WARNING dd3.disabled = true - modal.show() +/* modal.show() window.setTimeout({ modal.size = MODALSIZE.SMALL modal.animation = false - }, 2000) + }, 2000)*/ + if (split.visible) { + split.hide() + } else { + split.show() + } } } root.add(button) diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt index 61199a00..575405c6 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt @@ -3,7 +3,7 @@ package pl.treksoft.kvision.core import com.github.snabbdom.VNode open class Container(classes: Set = setOf()) : Widget(classes) { - protected val children: MutableList = mutableListOf() + internal val children: MutableList = mutableListOf() override fun render(): VNode { return kvh("div", childrenVNodes()) @@ -51,4 +51,7 @@ open class Container(classes: Set = setOf()) : Widget(classes) { return this } + open fun getChildren(): List { + return ArrayList(children) + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt index 1d937511..dfcbc87c 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/KVManager.kt @@ -8,19 +8,23 @@ import com.github.snabbdom.datasetModule import com.github.snabbdom.eventListenersModule import com.github.snabbdom.propsModule import com.github.snabbdom.styleModule +import org.w3c.dom.Node import pl.treksoft.jquery.jQuery import pl.treksoft.kvision.require import pl.treksoft.kvision.routing.routing +import pl.treksoft.kvision.snabbdom.obj import kotlin.browser.document import kotlin.dom.clear object KVManager { private val bootstrapWebpack = require("bootstrap-webpack") private val fontAwesomeWebpack = require("font-awesome-webpack") + private val resizable = require("jquery-resizable-dom") private val sdPatch = Snabbdom.init(arrayOf(classModule, attributesModule, propsModule, styleModule, eventListenersModule, datasetModule)) private val sdVirtualize = require("snabbdom-virtualize/strings").default + private val splitCss = require("./css/style.css") internal fun patch(id: String, vnode: VNode): VNode { val container = document.getElementById(id) diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Root.kt b/src/main/kotlin/pl/treksoft/kvision/core/Root.kt index b5562b3f..49b3a6f4 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Root.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Root.kt @@ -4,7 +4,7 @@ import com.github.snabbdom.VNode import pl.treksoft.kvision.modal.Modal import pl.treksoft.kvision.snabbdom.StringBoolPair -class Root(id: String, private val fluid: Boolean = false) : Container() { +class Root(id: String, private val fluid: Boolean = true) : Container() { private val modals: MutableList = mutableListOf() private var rootVnode: VNode = render() diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt index 38d39814..8db506e8 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Widget.kt @@ -46,6 +46,16 @@ open class Widget(classes: Set = setOf()) : KVObject { field = value refresh() } + var width: Int? = null + set(value) { + field = value + refresh() + } + var height: Int? = null + set(value) { + field = value + refresh() + } private var vnode: VNode? = null @@ -72,7 +82,14 @@ open class Widget(classes: Set = setOf()) : KVObject { } protected open fun getSnStyle(): List { - return listOf() + val snstyle = mutableListOf() + if (width != null) { + snstyle.add("width" to width.toString() + "px") + } + if (height != null) { + snstyle.add("height" to height.toString() + "px") + } + return snstyle } protected open fun getSnClass(): List { @@ -195,4 +212,19 @@ open class Widget(classes: Set = setOf()) : KVObject { internal open fun getRoot(): Root? { return this.parent?.getRoot() } + + protected open fun createLabelWithIcon(label: String, icon: String? = null, + image: ResString? = null): Array { + return if (icon != null) { + if (icon.startsWith("fa-") == true) { + arrayOf(KVManager.virtualize(""), " " + label) + } else { + arrayOf(KVManager.virtualize(""), " " + label) + } + } else if (image != null) { + arrayOf(KVManager.virtualize(""), " " + label) + } else { + arrayOf(label) + } + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt index eb7a0b50..8cc7eaf6 100644 --- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt +++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt @@ -17,7 +17,7 @@ import pl.treksoft.kvision.snabbdom.StringBoolPair import pl.treksoft.kvision.snabbdom.StringPair import pl.treksoft.kvision.snabbdom.obj -enum class DD(val POS: String) { +enum class DD(val type: String) { HEADER("DD#HEADER"), DISABLED("DD#DISABLED"), SEPARATOR("DD#SEPARATOR") @@ -111,13 +111,13 @@ open class DropDown(text: String, elements: List? = null, icon: Stri if (elems != null) { val c = elems.map { when (it.second) { - DD.HEADER.POS -> Tag(TAG.LI, it.first, classes = setOf("dropdown-header")) - DD.SEPARATOR.POS -> { + DD.HEADER.type -> Tag(TAG.LI, it.first, classes = setOf("dropdown-header")) + DD.SEPARATOR.type -> { val tag = Tag(TAG.LI, it.first, classes = setOf("divider")) tag.role = "separator" tag } - DD.DISABLED.POS -> { + DD.DISABLED.type -> { val tag = Tag(TAG.LI, classes = setOf("disabled")) tag.add(Link(it.first, "#")) tag diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt index 0fe2f559..74822401 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Button.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Button.kt @@ -1,7 +1,6 @@ package pl.treksoft.kvision.html import com.github.snabbdom.VNode -import pl.treksoft.kvision.core.KVManager import pl.treksoft.kvision.core.ResString import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.snabbdom.StringBoolPair @@ -63,17 +62,7 @@ open class Button(text: String, icon: String? = null, style: BUTTONSTYLE = BUTTO } override fun render(): VNode { - val t = if (icon != null) { - if (icon?.startsWith("fa-") == true) { - arrayOf(KVManager.virtualize(""), " " + text) - } else { - arrayOf(KVManager.virtualize(""), " " + text) - } - } else if (image != null) { - arrayOf(KVManager.virtualize(""), " " + text) - } else { - arrayOf(text) - } + val t = createLabelWithIcon(text, icon, image) return kvh("button", t) } diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt index e201da48..4f333482 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt @@ -2,9 +2,11 @@ package pl.treksoft.kvision.html import com.github.snabbdom.VNode import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.ResString import pl.treksoft.kvision.snabbdom.StringPair -open class Link(label: String, url: String, classes: Set = setOf()) : Container(classes) { +open class Link(label: String, url: String, icon: String? = null, image: ResString? = null, + classes: Set = setOf()) : Container(classes) { var label = label set(value) { field = value @@ -15,9 +17,20 @@ open class Link(label: String, url: String, classes: Set = setOf()) : Co field = value refresh() } + var icon = icon + set(value) { + field = value + refresh() + } + var image = image + set(value) { + field = value + refresh() + } override fun render(): VNode { - return kvh("a", arrayOf(label) + childrenVNodes()) + val t = createLabelWithIcon(label, icon, image) + return kvh("a", t + childrenVNodes()) } override fun getSnAttrs(): List { diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt index febee81b..109e5509 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt @@ -19,6 +19,8 @@ enum class TAG(val tagName: String) { BLOCKQUOTE("blockquote"), FOOTER("footer"), PRE("pre"), + UL("ul"), + OL("ol"), DIV("div"), MARK("mark"), diff --git a/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt new file mode 100644 index 00000000..234a9a20 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/panel/SplitPanel.kt @@ -0,0 +1,63 @@ +package pl.treksoft.kvision.panel + +import com.github.snabbdom.VNode +import pl.treksoft.jquery.JQuery +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag +import pl.treksoft.kvision.snabbdom.obj + +enum class DIRECTION(val dir: String) { + HORIZONTAL("horizontal"), + VERTICAL("vertical") +} + +open class SplitPanel(val direction: DIRECTION = DIRECTION.VERTICAL, + classes: Set = setOf()) : Container(classes + ("splitpanel-" + direction.dir)) { + + internal val splitter = Splitter(this, direction) + + internal fun afterInsertSplitter() { + if (children.size == 2) { + val horizontal = direction == DIRECTION.HORIZONTAL + children[0].getElementJQueryD().resizable(obj { + handleSelector = "#" + splitter.id + resizeWidth = !horizontal + resizeHeight = horizontal + onDragEnd = { _: dynamic, el: JQuery, _: dynamic -> + if (horizontal) { + children[0].height = el.height().toInt() + } else { + children[0].width = el.width().toInt() + } + } + }) + } + } + + override fun childrenVNodes(): Array { + return if (children.size == 2) { + arrayOf(children[0].render(), splitter.render(), children[1].render()) + } else { + arrayOf() + } + } +} + +class Splitter(val splitPanel: SplitPanel, direction: DIRECTION) : Tag(TAG.DIV, + classes = setOf("splitter-" + direction.dir)) { + private val idc = "kv_splitter_" + counter + + init { + counter++ + this.id = idc + } + + override fun afterInsert(node: VNode) { + splitPanel.afterInsertSplitter() + } + + companion object { + 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 new file mode 100644 index 00000000..24429d42 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/panel/StackPanel.kt @@ -0,0 +1,52 @@ +package pl.treksoft.kvision.panel + +import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.Widget + +open class StackPanel(private val activateLast: Boolean = true, + classes: Set = setOf()) : Container(classes) { + var activeIndex = -1 + set(value) { + field = value + refresh() + } + + override fun childrenVNodes(): Array { + return if (activeIndex >= 0 && activeIndex < children.size) { + arrayOf(children[activeIndex].render()) + } else { + arrayOf() + } + } + + override fun add(child: Widget): Container { + super.add(child) + if (activateLast) activeIndex = children.size - 1 + return this + } + + override fun addAll(children: List): Container { + super.addAll(children) + if (activateLast) activeIndex = this.children.size - 1 + return this + } + + override fun remove(child: Widget): Container { + super.remove(child) + if (activeIndex > children.size - 1) activeIndex = children.size - 1 + return this + } + + override fun removeAt(index: Int): Container { + super.removeAt(index) + if (activeIndex > children.size - 1) activeIndex = children.size - 1 + return this + } + + override fun removeAll(): Container { + super.removeAll() + if (activeIndex > children.size - 1) activeIndex = children.size - 1 + return this + } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt b/src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt new file mode 100644 index 00000000..4bc4d4b6 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/tabs/Tabs.kt @@ -0,0 +1,50 @@ +package pl.treksoft.kvision.tabs + +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.ResString +import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.html.Link +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag +import pl.treksoft.kvision.panel.StackPanel + +open class Tabs : Container(setOf()) { + internal var nav = Tag(TAG.UL, classes = setOf("nav", "nav-tabs")) + internal var content = StackPanel(false) + var activeIndex + get() = content.activeIndex + set(value) { + content.activeIndex = value + nav.children.forEach { it.removeCssClass("active") } + if (content.activeIndex >= 0 && content.activeIndex <= nav.children.size) { + nav.children[content.activeIndex].addCssClass("active") + } + } + + init { + this.add(nav) + this.add(content) + } + + open fun addTab(title: String, panel: Widget, icon: String? = null, + image: ResString? = null): Tabs { + val tag = Tag(TAG.LI) + tag.role = "presentation" + tag.add(Link(title, "#", icon, image)) + val index = nav.children.size + tag.setEventListener { + click = { e -> + activeIndex = index + e.preventDefault() + } + } + nav.add(tag) + if (nav.children.size == 1) { + tag.addCssClass("active") + activeIndex = 0 + } + content.add(panel) + return this + } + +} -- cgit