kotlinx.html icon indicating copy to clipboard operation
kotlinx.html copied to clipboard

How to print content of a html extension function

Open KotlinIsland opened this issue 5 years ago • 3 comments
trafficstars

I often need to use html functions (fun FlowContent.foo() {) without a parent node, I just want to get the html as text. This is what I came up with, just wondering if there was a standard/cleaner way of doing this.

import kotlinx.html.*
import kotlinx.html.stream.HTMLStreamBuilder
import kotlinx.html.stream.createHTML

fun main() {
    println(createHTML(false).span { foo() }) // <span><div>asdf</div></span>
    println(getHTML(false) { foo() }) // <div>asdf</div>
}

fun FlowContent.foo() {
    div { +"asdf" }
}

fun getHTML(
    prettyPrint: Boolean = true,
    fn: CommonAttributeGroupFacadeFlowInteractivePhrasingContent.() -> Unit
): String {
    val c = Fakesumer(prettyPrint)
    return object : HTMLTag("FAKE", c, emptyMap, null, true, false),
        CommonAttributeGroupFacadeFlowInteractivePhrasingContent {}.visitAndFinalize(c, fn).toString()
}

class Fakesumer(
    prettyPrint: Boolean = true,
    val consumer: HTMLStreamBuilder<StringBuilder> = HTMLStreamBuilder(
        StringBuilder(1234),
        prettyPrint,
        false
    )
) : TagConsumer<StringBuilder> by consumer {

    var firstTag: Tag? = null
    override fun onTagStart(tag: Tag) {
        if (firstTag == null) {
            firstTag = tag
            return
        }
        consumer.onTagStart(tag)
    }

    override fun onTagEnd(tag: Tag) {
        if (tag === firstTag) return
        consumer.onTagStart(tag)
    }
}

Also, whats the receiver for a html extension function that can be used in any context?

KotlinIsland avatar Sep 11 '20 15:09 KotlinIsland

Does this not work? https://github.com/Kotlin/kotlinx.html/blob/c862d78f1c80a6f40bdaf05f25aa058ad4537358/src/commonMain/kotlin/stream.kt#L139

spand avatar Sep 14 '20 11:09 spand

I don't understand, I want to be able to create an html extension function but also use it independently, this is the only way I can see.

KotlinIsland avatar Sep 14 '20 11:09 KotlinIsland

This works for me:

val htmlFragment = createHTML()
    .filter { if (it.tagName in listOf("html", "body")) SKIP else PASS }
    .html {
        body {
            builder()
        }
    }

The builder is defined as FlowContent.() -> Unit, but anything that you can put in a body should work.

It's based on the interceptor example in the Wiki

dfrommi avatar Aug 28 '21 12:08 dfrommi