diff options
author | Robert Jaros <rjaros@finn.pl> | 2017-09-03 02:40:21 +0200 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2017-09-03 02:40:21 +0200 |
commit | c056275c522db3f2f391ce44a405da0cedae60ca (patch) | |
tree | 2fe29b341182223b20bc50fd0909e94f6e7641ef | |
parent | 64e2bca354a1eb6018086427365336c3acb75cb8 (diff) | |
download | kvision-c056275c522db3f2f391ce44a405da0cedae60ca.tar.gz kvision-c056275c522db3f2f391ce44a405da0cedae60ca.tar.bz2 kvision-c056275c522db3f2f391ce44a405da0cedae60ca.zip |
Link widget
Tag, List, DropDown widget refactoring
Unit tests
15 files changed, 283 insertions, 42 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt index 2a376f17..019b6681 100644 --- a/src/main/kotlin/pl/treksoft/kvision/Showcase.kt +++ b/src/main/kotlin/pl/treksoft/kvision/Showcase.kt @@ -25,9 +25,16 @@ class Showcase : ApplicationBase() { label.hide() label.show() - val dd = DropDown("Dropdown", listOf("DAsdasd asdasdas das", "dasdasd asdasdas das"), "flag") + val link = Link("test", "http://www.google.pl") + link.add(Tag(TAG.P, "Cośtam")) + root.add(link) + + val dd = DropDown("Dropdown", listOf("abc" to "#!/x", "def" to "#!/y"), "flag") root.add(dd) + val dd2 = DropDown("Dropdown2", listOf("abc" to "#!/abc", "def" to "#!/def"), "flag") + root.add(dd2) + val p = Tag(TAG.P, "To jest prawo", align = ALIGN.RIGHT) p.title = "Tytuł" root.add(p) @@ -37,6 +44,12 @@ class Showcase : ApplicationBase() { val list = ListTag(LIST.DL_HORIZ, listOf("abc", "de<b>fdasdasdasddasd</b>tdasdas", "Dasdsada", "dasdasdads"), true) root.add(list) + val list2 = ListTag(LIST.OL, null) + list2.add(Tag(TAG.H4, "ABC")) + list2.add(Button("To jest button")) + list2.add(Image(Img("kotlin.png"))) + root.add(list2) + val img = Image(Img("kotlin.png"), "Image", true, IMAGE_SHAPE.ROUNDED) root.add(img) diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt index 575fa73b..e21fd669 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<String> = setOf()) : Widget(classes) { - private val children: MutableList<Widget> = mutableListOf() + protected val children: MutableList<Widget> = mutableListOf() override fun render(): VNode { return kvh("div", childrenVNodes()) @@ -19,6 +19,12 @@ open class Container(classes: Set<String> = setOf()) : Widget(classes) { refresh() } + open fun addAll(children: List<Widget>) { + this.children.addAll(children) + children.map { it.parent = this } + refresh() + } + open fun remove(child: Widget) { children.remove(child) child.clearParent() diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Img.kt b/src/main/kotlin/pl/treksoft/kvision/core/Img.kt index 08063a4a..80c65e0b 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Img.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Img.kt @@ -3,8 +3,8 @@ package pl.treksoft.kvision.core typealias ResString = String object Img { - operator fun invoke(src: ResString) = at(src) + operator fun invoke(src: String) = at(src) @Suppress("UnsafeCastFromDynamic", "NOTHING_TO_INLINE") - private inline fun at(src: ResString): String = pl.treksoft.kvision.require("./img/" + src) + private inline fun at(src: String): ResString = pl.treksoft.kvision.require("./img/" + src) } diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt index eef229e4..1a3f63c9 100644 --- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt +++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt @@ -1,23 +1,27 @@ package pl.treksoft.kvision.dropdown -import com.github.snabbdom.VNode -import com.github.snabbdom.h import pl.treksoft.kvision.core.Container -import pl.treksoft.kvision.core.KVManager import pl.treksoft.kvision.core.ResString import pl.treksoft.kvision.html.* import pl.treksoft.kvision.snabbdom.StringPair -open class DropDown(text: String, elements: List<String>, icon: String? = null, style: BUTTON_STYLE = BUTTON_STYLE.DEFAULT, size: BUTTON_SIZE? = null, +open class DropDown(text: String, elements: List<StringPair>, icon: String? = null, style: BUTTON_STYLE = BUTTON_STYLE.DEFAULT, size: BUTTON_SIZE? = null, block: Boolean = false, disabled: Boolean = false, image: ResString? = null, classes: Set<String> = setOf()) : Container(classes) { - val idk = "abc" - val button: DropDownButton = DropDownButton(idk, text, icon, style, size, block, disabled, image, setOf("dropdown")) - val list: DropDownListTag = DropDownListTag(idk, elements, setOf("dropdown-menu")) + val idc = "kv_dropdown_" + counter + val button: DropDownButton = DropDownButton(idc, text, icon, style, size, block, disabled, image, setOf("dropdown")) + val list: DropDownListTag = DropDownListTag(idc, setOf("dropdown-menu")) init { this.addCssClass("dropdown") + val children = elements.map { Link(it.first, it.second) } + list.addAll(children) this.add(button) this.add(list) + counter++ + } + + companion object { + var counter = 0 } } @@ -34,21 +38,7 @@ open class DropDownButton(id: String, text: String, icon: String? = null, style: } } -open class DropDownListTag(val ariaId: String, elements: List<String>, classes: Set<String> = setOf()) : ListTag(LIST.UL, elements, true, classes) { - - override fun render(): VNode { - val children = elements.map { el -> element("li", el, true) }.toTypedArray() - return kvh(type.tagName, children) - } - - private fun element(name: String, value: String, rich: Boolean): VNode { - if (rich) { - return h(name, arrayOf(KVManager.virtualize("<a href='#'>$value</a>"))) - } else { - return h(name, value) - } - } - +open class DropDownListTag(val ariaId: String, classes: Set<String> = setOf()) : ListTag(LIST.UL, null, false, classes) { override fun getSnAttrs(): List<StringPair> { return super.getSnAttrs() + listOf("aria-labelledby" to ariaId) } diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Link.kt b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt new file mode 100644 index 00000000..e201da48 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/html/Link.kt @@ -0,0 +1,26 @@ +package pl.treksoft.kvision.html + +import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.snabbdom.StringPair + +open class Link(label: String, url: String, classes: Set<String> = setOf()) : Container(classes) { + var label = label + set(value) { + field = value + refresh() + } + var url = url + set(value) { + field = value + refresh() + } + + override fun render(): VNode { + return kvh("a", arrayOf(label) + childrenVNodes()) + } + + override fun getSnAttrs(): List<StringPair> { + return super.getSnAttrs() + ("href" to url) + } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/html/List.kt b/src/main/kotlin/pl/treksoft/kvision/html/List.kt index 918f1576..b2801ce9 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/List.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/List.kt @@ -1,7 +1,9 @@ package pl.treksoft.kvision.html import com.github.snabbdom.VNode +import com.github.snabbdom.array import com.github.snabbdom.h +import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.core.KVManager import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.snabbdom.StringBoolPair @@ -15,7 +17,7 @@ enum class LIST(val tagName: String) { DL_HORIZ("dl") } -open class ListTag(type: LIST, elements: List<String>, rich: Boolean = false, classes: Set<String> = setOf()) : Widget(classes) { +open class ListTag(type: LIST, elements: List<String>? = null, rich: Boolean = false, classes: Set<String> = setOf()) : Container(classes) { var type = type set(value) { field = value @@ -33,11 +35,24 @@ open class ListTag(type: LIST, elements: List<String>, rich: Boolean = false, cl } override fun render(): VNode { - val children = 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 -> element(if (index % 2 == 0) "dt" else "dd", el, rich) } - }.toTypedArray() - return kvh(type.tagName, children) + 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 -> element(if (index % 2 == 0) "dt" else "dd", el, rich) } + }?.toTypedArray() + if (childrenElements != null) { + return kvh(type.tagName, childrenElements + childrenVNodes()) + } else { + return kvh(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 -> h("li", arrayOf(v.render())) } + LIST.DL, LIST.DL_HORIZ -> childrenElements.mapIndexed { index, v -> h(if (index % 2 == 0) "dt" else "dd", arrayOf(v.render())) } + } + return res.toTypedArray() } private fun element(name: String, value: String, rich: Boolean): VNode { diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt index 4178fbfb..cbaa611e 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt @@ -1,8 +1,8 @@ package pl.treksoft.kvision.html import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.core.KVManager -import pl.treksoft.kvision.core.Widget import pl.treksoft.kvision.snabbdom.StringBoolPair enum class TAG(val tagName: String) { @@ -44,7 +44,7 @@ enum class ALIGN(val className: String) { NOWRAP("text-nowrap") } -open class Tag(type: TAG, text: String, rich: Boolean = false, align: ALIGN = ALIGN.NONE, classes: Set<String> = setOf()) : Widget(classes) { +open class Tag(type: TAG, text: String? = null, rich: Boolean = false, align: ALIGN = ALIGN.NONE, classes: Set<String> = setOf()) : Container(classes) { var type = type set(value) { field = value @@ -67,10 +67,14 @@ open class Tag(type: TAG, text: String, rich: Boolean = false, align: ALIGN = AL } override fun render(): VNode { - if (rich) { - return kvh(type.tagName, arrayOf(KVManager.virtualize("<span>$text</span>"))) + if (text != null) { + if (rich) { + return kvh(type.tagName, arrayOf(KVManager.virtualize("<span>$text</span>")) + childrenVNodes()) + } else { + return kvh(type.tagName, arrayOf(text) + childrenVNodes()) + } } else { - return kvh(type.tagName, arrayOf(text)) + return kvh(type.tagName, childrenVNodes()) } } diff --git a/src/test/kotlin/test/pl/treksoft/kvision/basic/LabelSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/basic/LabelSpec.kt new file mode 100644 index 00000000..c3019cc9 --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/basic/LabelSpec.kt @@ -0,0 +1,23 @@ +package test.pl.treksoft.kvision.basic + +import pl.treksoft.kvision.basic.Label +import pl.treksoft.kvision.core.Root +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class LabelSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test") + val label = Label("This is a label") + root.add(label) + val element = document.getElementById("test") + assertEquals("<span>This is a label</span>", element?.innerHTML, "Should render correct label") + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt index f79d24df..d9d59c4c 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt @@ -29,6 +29,23 @@ class ContainerSpec : DomSpec { } @Test + fun addAll() { + run { + val root = Root("test") + val container = Container() + val child1 = Widget() + child1.id = "child1" + val child2 = Widget() + child2.id = "child2" + container.addAll(listOf(child1, child2)) + root.add(container) + val elem1 = document.getElementById("child1") + val elem2 = document.getElementById("child2") + assertTrue("Container renders children") { elem1 != null && elem2 != null } + } + } + + @Test fun remove() { run { val root = Root("test") diff --git a/src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt new file mode 100644 index 00000000..878119dc --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/dropdown/DropDownSpec.kt @@ -0,0 +1,23 @@ +package test.pl.treksoft.kvision.dropdown + +import pl.treksoft.kvision.core.Root +import pl.treksoft.kvision.dropdown.DropDown +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class DropDownSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test") + val dd = DropDown("Dropdown", listOf("abc" to "#!/x", "def" to "#!/y"), "flag") + root.add(dd) + val element = document.getElementById("test") + assertEquals("<div class=\"dropdown\"><button class=\"dropdown btn btn-default\" id=\"kv_dropdown_0\" type=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\"><span class=\"glyphicon glyphicon-flag\"></span> Dropdown</button><ul class=\"dropdown-menu\" aria-labelledby=\"kv_dropdown_0\"><li><a href=\"#!/x\">abc</a></li><li><a href=\"#!/y\">def</a></li></ul></div>", element?.innerHTML, "Should render correct drop down") + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/html/ButtonSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/html/ButtonSpec.kt new file mode 100644 index 00000000..6019b912 --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/html/ButtonSpec.kt @@ -0,0 +1,25 @@ +package test.pl.treksoft.kvision.html + +import pl.treksoft.kvision.core.Root +import pl.treksoft.kvision.html.BUTTON_SIZE +import pl.treksoft.kvision.html.BUTTON_STYLE +import pl.treksoft.kvision.html.Button +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class ButtonSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test") + val button = Button("Cancel", "fa-bars", BUTTON_STYLE.PRIMARY, BUTTON_SIZE.LARGE, true) + root.add(button) + val element = document.getElementById("test") + assertEquals("<button class=\"btn btn-primary btn-lg btn-block\" type=\"button\"><i class=\"fa fa-bars fa-lg\"></i> Cancel</button>", element?.innerHTML, "Should render correct html button") + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/html/ImageSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/html/ImageSpec.kt new file mode 100644 index 00000000..7d8e37fe --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/html/ImageSpec.kt @@ -0,0 +1,26 @@ +package test.pl.treksoft.kvision.html + +import pl.treksoft.kvision.core.Img +import pl.treksoft.kvision.core.Root +import pl.treksoft.kvision.html.IMAGE_SHAPE +import pl.treksoft.kvision.html.Image +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class ImageSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test") + val res = Img("kotlin.png") + val image = Image(res, "Image", true, IMAGE_SHAPE.ROUNDED, true) + root.add(image) + val element = document.getElementById("test") + assertEquals("<img class=\"img-responsive center-block img-rounded\" src=\"$res\" alt=\"Image\">", element?.innerHTML, "Should render correct html image") + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/html/LinkSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/html/LinkSpec.kt new file mode 100644 index 00000000..1f4b6d2c --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/html/LinkSpec.kt @@ -0,0 +1,23 @@ +package test.pl.treksoft.kvision.html + +import pl.treksoft.kvision.core.Root +import pl.treksoft.kvision.html.Link +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class LinkSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test") + val link = Link("Google", "http://www.google.com") + root.add(link) + val element = document.getElementById("test") + assertEquals("<a href=\"http://www.google.com\">Google</a>", element?.innerHTML, "Should render correct html link") + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/html/ListSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/html/ListSpec.kt new file mode 100644 index 00000000..78631076 --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/html/ListSpec.kt @@ -0,0 +1,39 @@ +package test.pl.treksoft.kvision.html + +import pl.treksoft.kvision.core.Root +import pl.treksoft.kvision.html.LIST +import pl.treksoft.kvision.html.ListTag +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test +import kotlin.test.assertEquals + +class ListSpec : DomSpec { + + @Test + fun render_Elements() { + run { + val root = Root("test") + val list = ListTag(LIST.DL_HORIZ, listOf("a1", "a2", "b1", "b2")) + root.add(list) + val element = document.getElementById("test") + assertEquals("<dl class=\"dl-horizontal\"><dt>a1</dt><dd>a2</dd><dt>b1</dt><dd>b2</dd></dl>", element?.innerHTML, "Should render correct html list") + } + } + + @Test + fun render_AsContainer() { + run { + val root = Root("test") + val list = ListTag(LIST.UL) + list.add(Tag(TAG.PRE, "pre")) + list.add(Tag(TAG.DEL, "del")) + root.add(list) + val element = document.getElementById("test") + assertEquals("<ul><li><pre>pre</pre></li><li><del>del</del></li></ul>", element?.innerHTML, "Should render correct html list") + } + } + +}
\ No newline at end of file diff --git a/src/test/kotlin/test/pl/treksoft/kvision/html/TagSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/html/TagSpec.kt index 1ba7f97b..997714db 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/html/TagSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/html/TagSpec.kt @@ -2,13 +2,13 @@ package test.pl.treksoft.kvision.html import pl.treksoft.kvision.core.Root import pl.treksoft.kvision.html.ALIGN +import pl.treksoft.kvision.html.Link import pl.treksoft.kvision.html.TAG import pl.treksoft.kvision.html.Tag import test.pl.treksoft.kvision.DomSpec import kotlin.browser.document import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertTrue class TagSpec : DomSpec { @@ -24,15 +24,26 @@ class TagSpec : DomSpec { } @Test - fun render_rich() { + fun render_Rich() { run { val root = Root("test") - val tag = Tag(TAG.H1, "This is <b>h1</b>", rich = true, align = ALIGN.CENTER) + val tag = Tag(TAG.H1, "This is <b>h1</b>", rich = true, align = ALIGN.RIGHT) root.add(tag) val element = document.getElementById("test") - assertEquals("<h1 class=\"text-center\"><span>This is <b>h1</b></span></h1>", element?.innerHTML, "Should render correct html tag") + assertEquals("<h1 class=\"text-right\"><span>This is <b>h1</b></span></h1>", element?.innerHTML, "Should render correct html tag") } } - + @Test + fun render_AsContainer() { + run { + val root = Root("test") + val tag = Tag(TAG.P, align = ALIGN.RIGHT) + tag.add(Tag(TAG.DEL, "This is test")) + tag.add(Link("abc", "/x")) + root.add(tag) + val element = document.getElementById("test") + assertEquals("<p class=\"text-right\"><del>This is test</del><a href=\"/x\">abc</a></p>", element?.innerHTML, "Should render correct html tag with children") + } + } }
\ No newline at end of file |