Created
January 18, 2012 16:53
-
-
Save stickupkid/1634008 to your computer and use it in GitHub Desktop.
Kotlin: HTML Builder Experiments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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