Ejemplo: Html Builder (KotlinJS)

Ejemplo: Html Builder

Ejemplo para crear una web html con Kotlin ilustrando y ampliando el contenido expuesto en la entrada Introducción a KotlinJS: Desarrollo web con Kotlin.

Observa en el código que getHTML se refiere a una función que toma como argumento una expresión lambda que utiliza una instancia de la clase HTML, y headTag y bodyTag son funciones miembro de la clase HTML, y agregamos el texto a las etiquetas html invocando el operador String.unaryPlus(). Para más detalles puedes ver (en inglés): Type-Safe Builders
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>

<body>

    <script src="out/production/html/lib/kotlin.js"></script>
    <script src="out/production/html/html.js"></script>

</body>
</html>
//html.kt
package html

import kotlin.browser.document

fun main() {

    val codeHTML = getHTML {
        // <head>
        headTag {
            title { +"KotlinJS" }
        }
        // <body>
        bodyTag {
            h1Tag { +"Desarrollo web con Kotlin" }
            pTag {
                +"Página web con etiquetas de marcado"
                +"HTML <h1>, <p>, <b>, <a>, <ul>, <li>"
                +"desarrollada con Kotlin"
            }
            pTag {
                bTag { +"Kotlin Doc" }
                +"comparte y divulga en español"
                +"información y ejemplos sobre programación con Kotlin y Android. Visita"
                aTag(href = "https://kotlindoc.blogspot.com") {
                    +"Kotlin Doc"
                }
            }
            pTag {
                +"La tabla de multiplicar del 2 iterando sobre un rango con un bucle for:"
                ulTag { for (i in 1..10) li { +"$i * 2 = ${i * 2}" } }
            }
        }
    }
    document.body?.appendChild(codeHTML.elemento)
}

// Clase abstracta
abstract class TagHTML(name: String) {
    val elemento = document.createElement(name)
    protected fun <T : TagHTML> initTag(tag: T, init: T.() -> Unit): T {
        tag.init()
        elemento.appendChild(tag.elemento)
        return tag
    }
}

// Clase Abstracta que herada de TagHTML
abstract class TagTextHTML(name: String) : TagHTML(name) {
    operator fun String.unaryPlus() {
        elemento.appendChild(document.createTextNode("$this "))
    }
}

// Clases que heredan de TagTextHTML
class HTML : TagTextHTML("html") {
    fun headTag(init: Head.() -> Unit) = initTag(Head(), init)
    fun bodyTag(init: Body.() -> Unit) = initTag(Body(), init)
}

class Head : TagTextHTML("head") {
    fun title(init: Title.() -> Unit) = initTag(Title(), init)
}

class Title : TagTextHTML("title")

// Clase abstracta
abstract class BodyTag(name: String) : TagTextHTML(name) {
    fun bTag(init: B.() -> Unit) = initTag(B(), init)
    fun pTag(init: P.() -> Unit) = initTag(P(), init)
    fun h1Tag(init: H1.() -> Unit) = initTag(H1(), init)
    fun ulTag(init: UL.() -> Unit) = initTag(UL(), init)
    fun aTag(href: String, init: A.() -> Unit) {
        val a = initTag(A(), init)
        a.href = href
    }
}

// Clases que heredan de BodyTag
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") {
    var href: String
        get() = elemento.getAttribute("href") ?: ""
        set(value) = elemento.setAttribute("href", value)
}

// función que toma como argumento una expresión lambda que utiliza una instancia de la clase HTML
fun getHTML(init: HTML.() -> Unit): HTML {
    val html = HTML()
    html.init()
    return html
}

Lo que se visualiza en el navegador de esta manera:

Comentarios

Entradas populares

Recursos gratis para aprender Kotlin

I/O: entrada y salida de datos en consola

Lectura y escritura de archivos