From 71ec05005477ad036749fc3354bb1ed05cf3ed81 Mon Sep 17 00:00:00 2001 From: Tom Adam Date: Mon, 16 Apr 2018 18:04:56 +0200 Subject: [PATCH 1/2] Self-closing empty tags to be compatible with XHTML standard. --- jvm/src/test/kotlin/streaming.kt | 20 ++++++++++---------- jvm/src/test/kotlin/unsafe.kt | 2 +- shared/src/main/kotlin/stream.kt | 4 ++++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/jvm/src/test/kotlin/streaming.kt b/jvm/src/test/kotlin/streaming.kt index be7c495d..93948f33 100644 --- a/jvm/src/test/kotlin/streaming.kt +++ b/jvm/src/test/kotlin/streaming.kt @@ -181,7 +181,7 @@ class TestStreaming { } @test fun `test generated enum could be used`() { - assertEquals("", StringBuilder().appendHTML(false).link { + assertEquals("", StringBuilder().appendHTML(false).link { rel = LinkRel.stylesheet href = "/path" }.toString()) @@ -211,9 +211,9 @@ class TestStreaming { @test fun `test form with button`() { assertEquals("
" + - "var1" + - "var2" + - "" + + "var1" + + "var2" + + "" + "
", StringBuilder().appendHTML(false).form("/someurl") { checkBoxInput(name = "cb1") { @@ -283,8 +283,8 @@ class TestStreaming { } } - @test fun `we should print empty tags with no close tag`() { - assertEquals("", StringBuilder().appendHTML(false).img(src = "my.jpg").toString()) + @test fun `we should print empty tags with self-closing tag`() { + assertEquals("", StringBuilder().appendHTML(false).img(src = "my.jpg").toString()) } @test fun `pretty print should take into account inline tags`() { @@ -319,12 +319,12 @@ class TestStreaming { } @test fun `ticker attribute modification should work properly`() { - assertEquals("", createHTML(false).input { + assertEquals("", createHTML(false).input { type = InputType.checkBox checked = true }) - assertEquals("", createHTML(false).input { + assertEquals("", createHTML(false).input { type = InputType.checkBox checked = true checked = false @@ -332,8 +332,8 @@ class TestStreaming { } @test fun `meta tag should have name and content suggested attributes`() { - assertEquals("", createHTML(false).meta("name", "content")) - assertEquals("", createHTML(false).head { + assertEquals("", createHTML(false).meta("name", "content")) + assertEquals("", createHTML(false).head { meta("name", "content") }) } diff --git a/jvm/src/test/kotlin/unsafe.kt b/jvm/src/test/kotlin/unsafe.kt index d58f90ab..b7c1a4c5 100644 --- a/jvm/src/test/kotlin/unsafe.kt +++ b/jvm/src/test/kotlin/unsafe.kt @@ -45,7 +45,7 @@ class UnsafeContentTest { } } - assertEquals("Admin", text) + assertEquals("Admin", text) } @Test diff --git a/shared/src/main/kotlin/stream.kt b/shared/src/main/kotlin/stream.kt index 7cde231e..4f6c80d0 100644 --- a/shared/src/main/kotlin/stream.kt +++ b/shared/src/main/kotlin/stream.kt @@ -37,6 +37,10 @@ class HTMLStreamBuilder(val out : O, val prettyPrint : Boole } } + if (tag.emptyTag) { + out.append("/") + } + out.append(">") ln = false } From 9b2369353abc03fac370898bf0a98478fc14a640 Mon Sep 17 00:00:00 2001 From: Tom Adam Date: Thu, 19 Apr 2018 18:56:20 +0200 Subject: [PATCH 2/2] Added option to create empty tags with minimized tag syntax (that is ). --- jvm/src/test/kotlin/streaming.kt | 29 +++++++++++++++++++---------- jvm/src/test/kotlin/unsafe.kt | 2 +- shared/src/main/kotlin/stream.kt | 8 ++++---- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/jvm/src/test/kotlin/streaming.kt b/jvm/src/test/kotlin/streaming.kt index 93948f33..96ab79ca 100644 --- a/jvm/src/test/kotlin/streaming.kt +++ b/jvm/src/test/kotlin/streaming.kt @@ -181,7 +181,7 @@ class TestStreaming { } @test fun `test generated enum could be used`() { - assertEquals("", StringBuilder().appendHTML(false).link { + assertEquals("", StringBuilder().appendHTML(false).link { rel = LinkRel.stylesheet href = "/path" }.toString()) @@ -211,9 +211,9 @@ class TestStreaming { @test fun `test form with button`() { assertEquals("
" + - "var1" + - "var2" + - "" + + "var1" + + "var2" + + "" + "
", StringBuilder().appendHTML(false).form("/someurl") { checkBoxInput(name = "cb1") { @@ -283,8 +283,17 @@ class TestStreaming { } } - @test fun `we should print empty tags with self-closing tag`() { - assertEquals("", StringBuilder().appendHTML(false).img(src = "my.jpg").toString()) + @test fun `we should print empty tags with no close tag`() { + assertEquals("", StringBuilder().appendHTML( + prettyPrint = false + ).img(src = "my.jpg").toString()) + } + + @test fun `we should print empty tags with close tag if xhtmlCompatible flag is set to true`() { + assertEquals("", StringBuilder().appendHTML( + prettyPrint = false, + xhtmlCompatible = true + ).img(src = "my.jpg").toString()) } @test fun `pretty print should take into account inline tags`() { @@ -319,12 +328,12 @@ class TestStreaming { } @test fun `ticker attribute modification should work properly`() { - assertEquals("", createHTML(false).input { + assertEquals("", createHTML(false).input { type = InputType.checkBox checked = true }) - assertEquals("", createHTML(false).input { + assertEquals("", createHTML(false).input { type = InputType.checkBox checked = true checked = false @@ -332,8 +341,8 @@ class TestStreaming { } @test fun `meta tag should have name and content suggested attributes`() { - assertEquals("", createHTML(false).meta("name", "content")) - assertEquals("", createHTML(false).head { + assertEquals("", createHTML(false).meta("name", "content")) + assertEquals("", createHTML(false).head { meta("name", "content") }) } diff --git a/jvm/src/test/kotlin/unsafe.kt b/jvm/src/test/kotlin/unsafe.kt index b7c1a4c5..d58f90ab 100644 --- a/jvm/src/test/kotlin/unsafe.kt +++ b/jvm/src/test/kotlin/unsafe.kt @@ -45,7 +45,7 @@ class UnsafeContentTest { } } - assertEquals("Admin", text) + assertEquals("Admin", text) } @Test diff --git a/shared/src/main/kotlin/stream.kt b/shared/src/main/kotlin/stream.kt index 4f6c80d0..199ae6cd 100644 --- a/shared/src/main/kotlin/stream.kt +++ b/shared/src/main/kotlin/stream.kt @@ -4,7 +4,7 @@ import kotlinx.html.* import kotlinx.html.consumers.* import org.w3c.dom.events.Event -class HTMLStreamBuilder(val out : O, val prettyPrint : Boolean) : TagConsumer { +class HTMLStreamBuilder(val out : O, val prettyPrint : Boolean, val xhtmlCompatible: Boolean) : TagConsumer { private var level = 0 private var ln = true @@ -37,7 +37,7 @@ class HTMLStreamBuilder(val out : O, val prettyPrint : Boole } } - if (tag.emptyTag) { + if (xhtmlCompatible && tag.emptyTag) { out.append("/") } @@ -122,8 +122,8 @@ class HTMLStreamBuilder(val out : O, val prettyPrint : Boole } private val AVERAGE_PAGE_SIZE = 32768 -fun createHTML(prettyPrint: Boolean = true): TagConsumer = HTMLStreamBuilder(StringBuilder(AVERAGE_PAGE_SIZE), prettyPrint).onFinalizeMap { sb, _ -> sb.toString() }.delayed() -fun O.appendHTML(prettyPrint : Boolean = true) : TagConsumer = HTMLStreamBuilder(this, prettyPrint).delayed() +fun createHTML(prettyPrint: Boolean = true, xhtmlCompatible : Boolean = false): TagConsumer = HTMLStreamBuilder(StringBuilder(AVERAGE_PAGE_SIZE), prettyPrint, xhtmlCompatible).onFinalizeMap { sb, _ -> sb.toString() }.delayed() +fun O.appendHTML(prettyPrint : Boolean = true, xhtmlCompatible : Boolean = false) : TagConsumer = HTMLStreamBuilder(this, prettyPrint, xhtmlCompatible).delayed() private val escapeMap = mapOf( '<' to "<",