diff options
6 files changed, 183 insertions, 8 deletions
diff --git a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt index 653f4a79..41d9426a 100644 --- a/src/main/kotlin/pl/treksoft/kvision/core/Container.kt +++ b/src/main/kotlin/pl/treksoft/kvision/core/Container.kt @@ -21,6 +21,8 @@ */ package pl.treksoft.kvision.core +import pl.treksoft.kvision.html.TextNode + /** * Base interface for all containers. */ @@ -66,4 +68,11 @@ interface Container : Component { * @return list of children */ fun getChildren(): List<Component> + + /** + * An operator to add a text node to the container. + */ + operator fun String.unaryPlus() { + add(TextNode(this)) + } } diff --git a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt index f133401d..b1dc4257 100644 --- a/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt +++ b/src/main/kotlin/pl/treksoft/kvision/html/Tag.kt @@ -199,11 +199,8 @@ open class Tag( return cl } - operator fun String.unaryPlus() { - if (content == null) - content = this - else - content += translate(this) + override operator fun String.unaryPlus() { + add(TextNode(this, rich)) } } diff --git a/src/main/kotlin/pl/treksoft/kvision/html/TextNode.kt b/src/main/kotlin/pl/treksoft/kvision/html/TextNode.kt new file mode 100644 index 00000000..33bb767f --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/html/TextNode.kt @@ -0,0 +1,80 @@ +/* + * 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.core.Container +import pl.treksoft.kvision.core.Widget + +/** + * Simple component for rendering text DOM node. + * + * @constructor + * @param content node text + * @param rich determines if [content] can contain HTML code + * @param init an initializer extension function + */ +open class TextNode( + content: String, rich: Boolean = false, + init: (TextNode.() -> Unit)? = null +) : Widget() { + + /** + * Text content of the tag. + */ + var content by refreshOnUpdate(content) + + /** + * Determines if [content] can contain HTML code. + */ + var rich by refreshOnUpdate(rich) + + init { + @Suppress("LeakingThis") + init?.invoke(this) + } + + @Suppress("UnsafeCastFromDynamic") + override fun render(): VNode { + val translatedContent = translate(content) + return if (rich) { + KVManager.virtualize("<span>$translatedContent</span>") + } else { + translatedContent.asDynamic() + } + } +} + +/** + * DSL builder extension function. + * + * It takes the same parameters as the constructor of the built component. + */ +fun Container.textNode( + content: String, rich: Boolean = false, + init: (TextNode.() -> Unit)? = null +): TextNode { + val textNode = TextNode(content, rich).apply { init?.invoke(this) } + this.add(textNode) + return textNode +} 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 39f8f04c..907cab35 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/core/ContainerSpec.kt @@ -21,8 +21,8 @@ */ package test.pl.treksoft.kvision.core -import pl.treksoft.kvision.panel.Root import pl.treksoft.kvision.core.Widget +import pl.treksoft.kvision.panel.Root import pl.treksoft.kvision.panel.SimplePanel import test.pl.treksoft.kvision.DomSpec import kotlin.browser.document @@ -120,4 +120,23 @@ class ContainerSpec : DomSpec { assertTrue("Returns children of current element") { childern.size == 2 } } } + + @Test + fun unaryPlus() { + run { + val root = Root("test", containerType = pl.treksoft.kvision.panel.ContainerType.FIXED) + val container = SimplePanel { + +"This is test 1" + +" " + +"This is test 2" + } + root.add(container) + val element = document.getElementById("test") + assertEqualsHtml( + "<div>This is test 1 This is test 2</div>", + element?.innerHTML, + "Should render correct text nodes" + ) + } + } }
\ 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 2d9c8c48..cc465bd3 100644 --- a/src/test/kotlin/test/pl/treksoft/kvision/html/TagSpec.kt +++ b/src/test/kotlin/test/pl/treksoft/kvision/html/TagSpec.kt @@ -80,7 +80,7 @@ class TagSpec : DomSpec { } @Test - fun renderUnaryPlus() { + fun unaryPlus() { run { val root = Root("test", containerType = pl.treksoft.kvision.panel.ContainerType.FIXED) val tag = Tag(TAG.H1, rich = true) { @@ -91,7 +91,7 @@ class TagSpec : DomSpec { assertEqualsHtml( "<h1><span>This is <b>h1</b></span></h1>", element?.innerHTML, - "Should render correct html tag with children" + "Should render correct HTML markup for children" ) } } diff --git a/src/test/kotlin/test/pl/treksoft/kvision/html/TextNodeSpec.kt b/src/test/kotlin/test/pl/treksoft/kvision/html/TextNodeSpec.kt new file mode 100644 index 00000000..d52e34ad --- /dev/null +++ b/src/test/kotlin/test/pl/treksoft/kvision/html/TextNodeSpec.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package test.pl.treksoft.kvision.html + +import pl.treksoft.kvision.html.TextNode +import pl.treksoft.kvision.html.bold +import pl.treksoft.kvision.html.div +import pl.treksoft.kvision.html.span +import pl.treksoft.kvision.html.textNode +import pl.treksoft.kvision.panel.Root +import pl.treksoft.kvision.utils.px +import test.pl.treksoft.kvision.DomSpec +import kotlin.browser.document +import kotlin.test.Test + +class TextNodeSpec : DomSpec { + + @Test + fun render() { + run { + val root = Root("test", containerType = pl.treksoft.kvision.panel.ContainerType.FIXED) + val textNode = TextNode("This is some text") + root.add(textNode) + val element = document.getElementById("test") + assertEqualsHtml("This is some text", element?.innerHTML, "Should render correct text") + } + } + + @Test + fun complexMarkup() { + run { + Root("test", containerType = pl.treksoft.kvision.panel.ContainerType.FIXED) { + div { + bold("Some bold text") + textNode(" and now normal text ") { + margin = 20.px + } + span("and some text inside span") + textNode("and <i>text</i> with formatting", rich = true) + textNode(".") + } + } + val element = document.getElementById("test") + assertEqualsHtml( + "<div><b>Some bold text</b> and now normal text <span>and some text inside span</span><span>and <i>text</i> with formatting</span>.</div>", + element?.innerHTML, + "Should render complex markup" + ) + } + } +} |