Skip to content

Instantly share code, notes, and snippets.

@stickupkid
Created January 18, 2012 16:53
Show Gist options
  • Save stickupkid/1634008 to your computer and use it in GitHub Desktop.
Save stickupkid/1634008 to your computer and use it in GitHub Desktop.
Kotlin: HTML Builder Experiments
package html
import java.util.*
fun main(args : Array<String>) {
val result =
html {
head {
script {
+"var text = \"Hello, World!\""
}
script (src="http://path/to/url")
}
body {
p {
+"Some text"
}
}
}
println(result)
}
trait Element {
fun render(builder : StringBuilder, indent : String)
fun toString() : String? {
val builder = StringBuilder()
render(builder, "")
return builder.toString()
}
}
class TextElement(val text : String) : Element {
override fun render(builder : StringBuilder, indent : String) {
builder.append("$indent$text\n")
}
}
abstract class Tag(val name : String) : Element {
val children = ArrayList<Element>()
val attributes = HashMap<String, String>()
open fun initTag<T : Element>(tag : T, init : T.() -> Unit) : T {
tag.init()
children.add(tag)
return tag
}
override fun render(builder : StringBuilder, indent : String) {
builder.append("$indent<$name${renderAttributes()}>\n")
for (c in children) {
c.render(builder, indent + " ")
}
builder.append("$indent</$name>\n")
}
private fun renderAttributes() : String? {
val builder = StringBuilder()
for (a in attributes.keySet()) {
builder.append(" $a=\"${attributes[a]}\"")
}
return builder.toString()
}
}
abstract class TagWithText(name : String) : Tag(name) {
fun String.plus() {
children.add(TextElement(this))
}
}
class HTML() : TagWithText("html") {
fun head(init : Head.() -> Unit) = initTag(Head(), init)
fun body(init : Body.() -> Unit) = initTag(Body(), init)
}
class Head() : TagWithText("head") {
fun title(init : Title.() -> Unit) = initTag(Title(), init)
fun script(src : String, contentType : String = "type/javascript") {
val s = initTag(ExternalScript(), {})
s.src = src
s.contentType = contentType
}
fun script(contentType : String = "type/javscript", init : Script.() -> Unit) {
val s = initTag(Script(), init)
s.contentType = contentType
}
}
class Title() : TagWithText("title")
class ExternalScript() : Tag("script") {
public var src : String?
get() = attributes["src"]
set(value) {
attributes["src"] = value.toString()
}
public var contentType : String?
get() = attributes["type"]
set(value) {
attributes["type"] = value.toString()
}
}
class Script() : TagWithText("script") {
public var contentType : String?
get() = attributes["type"]
set(value) {
attributes["type"] = value.toString()
}
}
abstract class BodyTag(name : String) : TagWithText(name) {
fun b(init : B.() -> Unit) = initTag(B(), init)
fun p(init : P.() -> Unit) = initTag(P(), init)
fun h1(init : H1.() -> Unit) = initTag(H1(), init)
fun ul(init : UL.() -> Unit) = initTag(UL(), init)
fun a(href : String, init : A.() -> Unit) {
val a = initTag(A(), init)
a.href = href
}
}
class Body() : BodyTag("body")
class UL() : BodyTag("ul") {
fun li(init : LI.() -> Unit) = initTag(LI(), init)
}
class B() : BodyTag("b")
class LI() : BodyTag("li")
class P() : BodyTag("p")
class H1() : BodyTag("h1")
class A() : BodyTag("a") {
public var href : String?
get() = attributes["href"]
set(value) {
attributes["href"] = value.toString()
}
}
fun html(init : HTML.() -> Unit) : HTML {
val html = HTML()
html.init()
return html
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment