aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Jaros <rjaros@finn.pl>2018-03-11 23:47:07 +0100
committerRobert Jaros <rjaros@finn.pl>2018-03-12 00:03:27 +0100
commit567a42eb216381b951fe5c6bcc199bcba835ffa6 (patch)
treeec49858d37556ff37cd156f401cb680c26558482 /src
parent0c9f1189a40f361484cf29fd89e74d9b83aba321 (diff)
downloadkvision-567a42eb216381b951fe5c6bcc199bcba835ffa6.tar.gz
kvision-567a42eb216381b951fe5c6bcc199bcba835ffa6.tar.bz2
kvision-567a42eb216381b951fe5c6bcc199bcba835ffa6.zip
Bootstrap Navbar component.
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt47
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt55
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt56
-rw-r--r--src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt171
-rw-r--r--src/main/resources/css/style.css7
5 files changed, 326 insertions, 10 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
index 44396951..9a349707 100644
--- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
+++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt
@@ -22,16 +22,17 @@
package pl.treksoft.kvision.dropdown
import com.github.snabbdom.VNode
+import pl.treksoft.kvision.KVManager
import pl.treksoft.kvision.core.Component
import pl.treksoft.kvision.core.Container
import pl.treksoft.kvision.core.CssSize
import pl.treksoft.kvision.core.StringBoolPair
import pl.treksoft.kvision.core.StringPair
-import pl.treksoft.kvision.html.ButtonStyle
import pl.treksoft.kvision.html.Button
-import pl.treksoft.kvision.html.ListType
+import pl.treksoft.kvision.html.ButtonStyle
import pl.treksoft.kvision.html.Link
import pl.treksoft.kvision.html.ListTag
+import pl.treksoft.kvision.html.ListType
import pl.treksoft.kvision.html.TAG
import pl.treksoft.kvision.html.Tag
import pl.treksoft.kvision.panel.SimplePanel
@@ -55,11 +56,12 @@ enum class DD(val option: String) {
* @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 forNavbar determines if the component will be used in a navbar
* @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,
+ style: ButtonStyle = ButtonStyle.DEFAULT, disabled: Boolean = false, val forNavbar: Boolean = false,
classes: Set<String> = setOf()
) : SimplePanel(classes) {
/**
@@ -136,7 +138,7 @@ open class DropDown(
private val idc = "kv_dropdown_$counter"
internal val button: DropDownButton = DropDownButton(
idc, text, icon, style,
- disabled, setOf("dropdown")
+ disabled, forNavbar, setOf("dropdown")
)
internal val list: DropDownListTag = DropDownListTag(idc, setOf("dropdown-menu"))
@@ -147,6 +149,14 @@ open class DropDown(
counter++
}
+ override fun render(): VNode {
+ return if (forNavbar) {
+ render("li", childrenVNodes())
+ } else {
+ render("div", childrenVNodes())
+ }
+ }
+
override fun add(child: Component): SimplePanel {
list.add(child)
return this
@@ -171,7 +181,6 @@ open class DropDown(
return list.getChildren()
}
-
private fun setChildrenFromElements() {
list.removeAll()
elements?.let { elems ->
@@ -237,10 +246,10 @@ open class DropDown(
*/
fun Container.dropDown(
text: String, elements: List<StringPair>? = null, icon: String? = null,
- style: ButtonStyle = ButtonStyle.DEFAULT, disabled: Boolean = false,
+ style: ButtonStyle = ButtonStyle.DEFAULT, disabled: Boolean = false, navbar: Boolean = false,
classes: Set<String> = setOf(), init: (DropDown.() -> Unit)? = null
): DropDown {
- val dropDown = DropDown(text, elements, icon, style, disabled, classes).apply { init?.invoke(this) }
+ val dropDown = DropDown(text, elements, icon, style, disabled, navbar, classes).apply { init?.invoke(this) }
this.add(dropDown)
return dropDown
}
@@ -249,7 +258,7 @@ open class DropDown(
internal class DropDownButton(
id: String, text: String, icon: String? = null, style: ButtonStyle = ButtonStyle.DEFAULT,
- disabled: Boolean = false, classes: Set<String> = setOf()
+ disabled: Boolean = false, val forNavbar: Boolean = false, classes: Set<String> = setOf()
) :
Button(text, icon, style, disabled, classes) {
@@ -257,10 +266,30 @@ internal class DropDownButton(
this.id = id
}
+ override fun render(): VNode {
+ val text = createLabelWithIcon(text, icon, image)
+ return if (forNavbar) {
+ val textWithCarret = text.toMutableList()
+ textWithCarret.add(" ")
+ textWithCarret.add(KVManager.virtualize("<span class='caret'></span>"))
+ render("a", textWithCarret.toTypedArray())
+ } else {
+ render("button", text)
+ }
+ }
+
+ override fun getSnClass(): List<StringBoolPair> {
+ return if (forNavbar) {
+ listOf("dropdown" to true)
+ } else {
+ super.getSnClass()
+ }
+ }
+
override fun getSnAttrs(): List<StringPair> {
return super.getSnAttrs() + listOf(
"data-toggle" to "dropdown", "aria-haspopup" to "true",
- "aria-expanded" to "false"
+ "aria-expanded" to "false", "role" to "button", "href" to "#"
)
}
}
diff --git a/src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt b/src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt
new file mode 100644
index 00000000..79b69290
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018. Robert Jaros
+ */
+package pl.treksoft.kvision.navbar
+
+import pl.treksoft.kvision.core.StringBoolPair
+import pl.treksoft.kvision.html.TAG
+import pl.treksoft.kvision.html.Tag
+
+/**
+ * The Bootstrap Nav container.
+ *
+ * @constructor
+ * @param rightAlign determines if the nav is aligned to the right
+ * @param classes a set of CSS class names
+ * @param init an initializer extension function
+ */
+open class Nav(rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (Nav.() -> Unit)? = null) :
+ Tag(TAG.UL, classes = classes) {
+
+ /**
+ * Determines if the nav is aligned to the right.
+ */
+ var rightAlign by refreshOnUpdate(rightAlign)
+
+ init {
+ @Suppress("LeakingThis")
+ init?.invoke(this)
+ }
+
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ cl.add("nav" to true)
+ cl.add("navbar-nav" to true)
+ if (rightAlign) {
+ cl.add("navbar-right" to true)
+ }
+ return cl
+ }
+
+ companion object {
+ /**
+ * DSL builder extension function.
+ *
+ * It takes the same parameters as the constructor of the built component.
+ */
+ fun Navbar.nav(
+ rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (Nav.() -> Unit)? = null
+ ): Nav {
+ val nav = Nav(rightAlign, classes).apply { init?.invoke(this) }
+ this.add(nav)
+ return nav
+ }
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt b/src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt
new file mode 100644
index 00000000..69755155
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018. Robert Jaros
+ */
+package pl.treksoft.kvision.navbar
+
+import pl.treksoft.kvision.core.StringBoolPair
+import pl.treksoft.kvision.html.TAG
+import pl.treksoft.kvision.html.Tag
+
+/**
+ * The Bootstrap Nav form container.
+ *
+ * @constructor
+ * @param rightAlign determines if the nav form is aligned to the right
+ * @param classes a set of CSS class names
+ * @param init an initializer extension function
+ */
+open class NavForm(rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (NavForm.() -> Unit)? = null) :
+ Tag(TAG.FORM, classes = classes) {
+
+ /**
+ * Determines if the nav form is aligned to the right.
+ */
+ var rightAlign by refreshOnUpdate(rightAlign)
+
+ init {
+ @Suppress("LeakingThis")
+ init?.invoke(this)
+ }
+
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ cl.add("navbar-form" to true)
+ if (rightAlign) {
+ cl.add("navbar-right" to true)
+ } else {
+ cl.add("navbar-left" to true)
+ }
+ return cl
+ }
+
+ companion object {
+ /**
+ * DSL builder extension function.
+ *
+ * It takes the same parameters as the constructor of the built component.
+ */
+ fun Navbar.navForm(
+ rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (NavForm.() -> Unit)? = null
+ ): NavForm {
+ val navForm = NavForm(rightAlign, classes).apply { init?.invoke(this) }
+ this.add(navForm)
+ return navForm
+ }
+ }
+}
diff --git a/src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt b/src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt
new file mode 100644
index 00000000..ee131731
--- /dev/null
+++ b/src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2018. Robert Jaros
+ */
+package pl.treksoft.kvision.navbar
+
+import com.github.snabbdom.VNode
+import pl.treksoft.kvision.core.Component
+import pl.treksoft.kvision.core.Container
+import pl.treksoft.kvision.core.StringBoolPair
+import pl.treksoft.kvision.core.StringPair
+import pl.treksoft.kvision.html.Link
+import pl.treksoft.kvision.html.TAG
+import pl.treksoft.kvision.html.Tag.Companion.tag
+import pl.treksoft.kvision.panel.SimplePanel
+
+/**
+ * Navbar types.
+ */
+enum class NavbarType(internal val navbarType: String) {
+ FIXEDTOP("navbar-fixed-top"),
+ FIXEDBOTTOM("navbar-fixed-bottom"),
+ STATICTOP("navbar-static-top")
+}
+
+/**
+ * The Bootstrap Navbar container.
+ *
+ * @constructor
+ * @param label the navbar label
+ * @param type the navbar type
+ * @param inverted determines if the navbar is inverted
+ * @param classes a set of CSS class names
+ * @param init an initializer extension function
+ */
+open class Navbar(
+ label: String = "",
+ type: NavbarType? = null,
+ inverted: Boolean = false,
+ classes: Set<String> = setOf(), init: (Navbar.() -> Unit)? = null
+) : SimplePanel(classes) {
+
+ /**
+ * The navbar header label.
+ */
+ var label
+ get() = brandLink.label
+ set(value) {
+ brandLink.label = value
+ }
+
+ /**
+ * The navbar type.
+ */
+ var type by refreshOnUpdate(type)
+ /**
+ * Determines if the navbar is inverted.
+ */
+ var inverted by refreshOnUpdate(inverted)
+
+ private val idc = "kv_navbar_$counter"
+
+ private val brandLink = Link(label, "#", classes = setOf("navbar-brand"))
+ protected val container = SimplePanel(setOf("collapse", "navbar-collapse")) {
+ id = idc
+ }
+
+ init {
+ val c = SimplePanel(setOf("container-fluid")) {
+ simplePanel(setOf("navbar-header")) {
+ add(NavbarButton(idc))
+ add(brandLink)
+ }
+ add(container)
+ }
+ addInternal(c)
+ counter++
+ @Suppress("LeakingThis")
+ init?.invoke(this)
+ }
+
+ override fun render(): VNode {
+ return render("nav", childrenVNodes())
+ }
+
+ override fun add(child: Component): Navbar {
+ container.add(child)
+ return this
+ }
+
+ override fun addAll(children: List<Component>): Navbar {
+ container.addAll(children)
+ return this
+ }
+
+ override fun remove(child: Component): Navbar {
+ container.remove(child)
+ return this
+ }
+
+ override fun removeAll(): Navbar {
+ container.removeAll()
+ return this
+ }
+
+ override fun getChildren(): List<Component> {
+ return container.getChildren()
+ }
+
+ override fun getSnClass(): List<StringBoolPair> {
+ val cl = super.getSnClass().toMutableList()
+ cl.add("navbar" to true)
+ type?.let {
+ cl.add(it.navbarType to true)
+ }
+ if (inverted) {
+ cl.add("navbar-inverse" to true)
+ } else {
+ cl.add("navbar-default" to true)
+ }
+ return cl
+ }
+
+ companion object {
+ internal var counter = 0
+
+ /**
+ * DSL builder extension function.
+ *
+ * It takes the same parameters as the constructor of the built component.
+ */
+ fun Container.navbarPanel(
+ text: String = "",
+ type: NavbarType? = null,
+ inverted: Boolean = false,
+ classes: Set<String> = setOf(), init: (Navbar.() -> Unit)? = null
+ ): Navbar {
+ val navbarPanel = Navbar(text, type, inverted, classes, init)
+ this.add(navbarPanel)
+ return navbarPanel
+ }
+ }
+}
+
+/**
+ * @suppress
+ * Internal component.
+ * The Bootstrap Navbar header button.
+ */
+internal class NavbarButton(private val idc: String, toggle: String = "Toggle navigation") :
+ SimplePanel(setOf("navbar-toggle", "collapsed")) {
+
+ init {
+ tag(TAG.SPAN, toggle, classes = setOf("sr-only"))
+ tag(TAG.SPAN, classes = setOf("icon-bar"))
+ tag(TAG.SPAN, classes = setOf("icon-bar"))
+ tag(TAG.SPAN, classes = setOf("icon-bar"))
+ }
+
+ override fun render(): VNode {
+ return render("button", childrenVNodes())
+ }
+
+ override fun getSnAttrs(): List<StringPair> {
+ return super.getSnAttrs() + listOf(
+ "type" to "button",
+ "data-toggle" to "collapse",
+ "data-target" to "#$idc",
+ "aria-expanded" to "false"
+ )
+ }
+}
diff --git a/src/main/resources/css/style.css b/src/main/resources/css/style.css
index 444bf5c2..82747e59 100644
--- a/src/main/resources/css/style.css
+++ b/src/main/resources/css/style.css
@@ -2,6 +2,11 @@
padding: 0px;
}
+.navbar .container-fluid {
+ padding-left: 15px;
+ padding-right: 15px;
+}
+
.splitpanel-vertical {
display: flex;
flex-direction: row;
@@ -73,7 +78,7 @@ trix-toolbar .trix-button-group {
margin-right:6px;
}
-.form-inline .form-group .form-control {
+.form-inline .form-group .form-control, .navbar-form .form-group .form-control {
margin-left:6px;
}