Newer
Older
k2html / src / nl / astraeus / tag / TagCreator.kt
package nl.astraeus.tag

import java.util.*

/**
 * Created by rnentjes on 15-9-15.
 */
fun escape(s: String): String {
    if ("" == s) {
        return ""
    }

    val out = StringBuilder(Math.max(16, s.length))
    for (i in 0..s.length - 1) {
        val c = s.get(i)
        if (c.toInt() > 127 || c == '"' || c == '<' || c == '>' || c == '&') {
            out.append("&#")
            out.append(c.toInt())
            out.append(';')
        } else {
            out.append(c)
        }
    }

    return out.toString()
}

object Attr {
    val HIDDEN: String = "hidden"
    val HIGH: String = "high"
    val HREF: String = "href"
    val HREFLANG: String = "hreflang"
    val HTTP_EQUIV: String = "http-equiv"
    val ICON: String = "icon"
    val ID: String = "id"
    val ISMAP: String = "ismap"
    val ITEMPROP: String = "itemprop"
    val KEYTYPE: String = "keytype"
    val KIND: String = "kind"
    val LABEL: String = "label"
    val LANG: String = "lang"
    val LANGUAGE: String = "language"
    val LIST: String = "list"
    val LOOP: String = "loop"
    val LOW: String = "low"
    val MANIFEST: String = "manifest"
    val MAX: String = "max"
    val MAXLENGTH: String = "maxlength"
    val MEDIA: String = "media"
    val METHOD: String = "method"
    val MIN: String = "min"
    val MULTIPLE: String = "multiple"
    val NAME: String = "name"
    val NOVALIDATE: String = "novalidate"
    val OPEN: String = "open"
    val OPTIMUM: String = "optimum"
    val PATTERN: String = "pattern"
    val PING: String = "ping"
    val PLACEHOLDER: String = "placeholder"
    val POSTER: String = "poster"
    val PRELOAD: String = "preload"
    val PUBDATE: String = "pubdate"
    val RADIOGROUP: String = "radiogroup"
    val READONLY: String = "readonly"
    val REL: String = "rel"
    val REQUIRED: String = "required"
    val REVERSED: String = "reversed"
    val ROWS: String = "rows"
    val ROWSPAN: String = "rowspan"
    val SANDBOX: String = "sandbox"
    val SPELLCHECK: String = "spellcheck"
    val SCOPE: String = "scope"
    val SCOPED: String = "scoped"
    val SEAMLESS: String = "seamless"
    val SELECTED: String = "selected"
    val SHAPE: String = "shape"
    val SIZE: String = "size"
    val SIZES: String = "sizes"
    val SPAN: String = "span"
    val SRC: String = "src"
    val SRCDOC: String = "srcdoc"
    val SRCLANG: String = "srclang"
    val SRCSET: String = "srcset"
    val START: String = "start"
    val STEP: String = "step"
    val STYLE: String = "style"
    val SUMMARY: String = "summary"
    val TABINDEX: String = "tabindex"
    val TARGET: String = "target"
    val TITLE: String = "title"
    val TYPE: String = "type"
    val USEMAP: String = "usemap"
    val VALUE: String = "value"
    val WIDTH: String = "width"
    val WRAP: String = "wrap"
    val BORDER: String = "border"
    val BUFFERED: String = "buffered"
    val CHALLENGE: String = "challenge"
    val CHARSET: String = "charset"
    val CHECKED: String = "checked"
    val CITE: String = "cite"
    val CLASS: String = "class"
    val COLOR: String = "color"
    val COLS: String = "cols"
    val COLSPAN: String = "colspan"
    val CONTENT: String = "content"
    val CONTENTEDITABLE: String = "contenteditable"
    val CONTEXTMENU: String = "contextmenu"
    val CONTROLS: String = "controls"
    val COORDS: String = "coords"
    val DATA: String = "data"
    val DATETIME: String = "datetime"
    val DEFAULT: String = "default"
    val DEFER: String = "defer"
    val DIR: String = "dir"
    val DIRNAME: String = "dirname"
    val DISABLED: String = "disabled"
    val DOWNLOAD: String = "download"
    val DRAGGABLE: String = "draggable"
    val DROPZONE: String = "dropzone"
    val ENCTYPE: String = "enctype"
    val FOR: String = "for"
    val FORM: String = "form"
    val FORMACTION: String = "formaction"
    val HEADERS: String = "headers"
    val HEIGHT: String = "height"
    val ACCEPT: String = "accept"
    val ACCEPT_CHARSET: String = "accept-charset"
    val ACCESSKEY: String = "accesskey"
    val ACTION: String = "action"
    val ALIGN: String = "align"
    val ALT: String = "alt"
    val ASYNC: String = "async"
    val AUTOCOMPLETE: String = "autocomplete"
    val AUTOFOCUS: String = "autofocus"
    val AUTOPLAY: String = "autoplay"
    val AUTOSAVE: String = "autosave"
}

class Attribute {
    var name: String
        private set
    private var value: String? = null

    constructor(name: String, value: String) {
        this.name = name
        this.value = escape(value)
    }

    constructor(name: String) {
        this.name = name
        this.value = null
    }

    fun render(): String {
        if (value == null) {
            return " " + name
        }
        return (" $name=\"$value\"")
    }

    override fun toString() = this.render()

    fun setValue(value: String) {
        this.value = value
    }
}

abstract class Tag protected constructor(protected var tag: String) {
    protected var attributes: ArrayList<Attribute> = ArrayList()
    var parent: Tag? = null

    /**
     * Sets an attribute on an element

     * @param name  the attribute
     * *
     * @param value the attribute value
     */
    fun setAttribute(name: String, value: String?): Boolean {
        if (value == null) {
            return attributes.add(Attribute(name))
        }
        for (attribute in attributes) {
            if (attribute.name == name) {
                attribute.setValue(value) //update with new value
                return true
            }
        }
        return attributes.add(Attribute(name, value))
    }

    fun indent(indent: Int): String {
        val result = StringBuilder()

        for(i in 1..indent) {
            result.append(" ")
        }

        return result.toString()
    }

    open fun render(indent: Int = 0, pretty: Boolean = false): String {
        val result = StringBuilder()

        if (pretty) {
            result.append(indent(indent))
        }

        result.append(renderOpenTag())
        result.append(renderCloseTag())

        return result.toString()
    }

    override fun toString() = this.render()

    fun renderOpenTag(): String {
        var tagAttributes = ""
        for (attribute in attributes) {
            tagAttributes += attribute.render()
        }
        return "<$tag$tagAttributes>"
    }

    fun renderCloseTag() = "</$tag>"
}

class EmptyTag(tagType: String) : Tag(tagType) {
    /**
     * Sets a custom attribute

     * @param attribute the attribute name
     * *
     * @param value     the attribute value
     * *
     * @return itself for easy chaining
     */
    fun attr(attribute: String, value: String?): EmptyTag {
        setAttribute(attribute, value)
        return this
    }

    /**
     * Call attr-method based on condition
     * [.attr]
     */
    fun condAttr(condition: Boolean, attribute: String, value: String?): EmptyTag {
        return if (condition) attr(attribute, value) else this
    }

    override fun render(indent: Int, pretty: Boolean): String {
        var tagAttributes = ""
        for (attribute in attributes) {
            tagAttributes += attribute
        }

        if (pretty) {
            return indent(indent) + "<$tag$tagAttributes/>"
        } else {
            return "<$tag$tagAttributes/>"
        }
    }

    override fun toString() = this.render()

    /**
     * Methods below this point are convenience methods
     * that call attr with a predefined attribute.
     */

    //TODO: TEST ?
    fun isAutoComplete() = attr(Attr.AUTOCOMPLETE, null)
    fun isAutoFocus() = attr(Attr.AUTOFOCUS, null)
    fun isHidden() = attr(Attr.HIDDEN, null)
    fun isRequired() = attr(Attr.REQUIRED, null)
    fun withAlt(alt: String) = attr(Attr.ALT, alt)
    fun withAction(action: String) = attr(Attr.ACTION, action)
    fun withCharset(charset: String) = attr(Attr.CHARSET, charset)
    fun withClass(className: String) = attr(Attr.CLASS, className)
    fun withContent(content: String) = attr(Attr.CONTENT, content)
    fun withHref(href: String) = attr(Attr.HREF, href)
    fun withId(id: String) = attr(Attr.ID, id)
    fun withData(dataAttr: String, value: String) = attr(Attr.DATA + "-" + dataAttr, value)
    fun withMethod(method: String) = attr(Attr.METHOD, method)
    fun withName(name: String) = attr(Attr.NAME, name)
    fun withPlaceholder(placeholder: String) = attr(Attr.PLACEHOLDER, placeholder)
    fun withTarget(target: String) = attr(Attr.TARGET, target)
    fun withType(type: String) = attr(Attr.TYPE, type)
    fun withRel(rel: String) = attr(Attr.REL, rel)
    fun withSrc(src: String) = attr(Attr.SRC, src)
    fun withValue(value: String) = attr(Attr.VALUE, value)
    fun withCondAutoComplete(condition: Boolean) = condAttr(condition, Attr.AUTOCOMPLETE, null)
    fun withCondAutoFocus(condition: Boolean) = condAttr(condition, Attr.AUTOFOCUS, null)
    fun withCondHidden(condition: Boolean) = condAttr(condition, Attr.HIDDEN, null)
    fun withCondRequired(condition: Boolean) = condAttr(condition, Attr.REQUIRED, null)
    fun withCondAlt(condition: Boolean, alt: String) = condAttr(condition, Attr.ALT, alt)
    fun withCondAction(condition: Boolean, action: String) = condAttr(condition, Attr.ACTION, action)
    fun withCharset(condition: Boolean, charset: String) = condAttr(condition, Attr.CHARSET, charset)
    fun withCondClass(condition: Boolean, className: String) = condAttr(condition, Attr.CLASS, className)
    fun withCondContent(condition: Boolean, content: String) = condAttr(condition, Attr.CONTENT, content)
    fun withCondHref(condition: Boolean, href: String) = condAttr(condition, Attr.HREF, href)
    fun withCondId(condition: Boolean, id: String) = condAttr(condition, Attr.ID, id)
    fun withCondData(condition: Boolean, dataAttr: String, value: String) = condAttr(condition, Attr.DATA + "-" + dataAttr, value)
    fun withCondMethod(condition: Boolean, method: String) = condAttr(condition, Attr.METHOD, method)
    fun withCondName(condition: Boolean, name: String) = condAttr(condition, Attr.NAME, name)
    fun withCondPlaceholder(condition: Boolean, placeholder: String) = condAttr(condition, Attr.PLACEHOLDER, placeholder)
    fun withCondTarget(condition: Boolean, target: String) = condAttr(condition, Attr.TARGET, target)
    fun withCondType(condition: Boolean, type: String) = condAttr(condition, Attr.TYPE, type)
    fun withCondRel(condition: Boolean, rel: String) = condAttr(condition, Attr.REL, rel)
    fun withCondSrc(condition: Boolean, src: String) = condAttr(condition, Attr.SRC, src)
    fun withCondValue(condition: Boolean, value: String) = condAttr(condition, Attr.VALUE, value)
}

class Text(text: String) : Tag(text) {
    override fun render(indent: Int, pretty: Boolean): String {
        if (pretty) {
            return indent(indent) + escape(super.tag)
        } else {
            return escape(super.tag)
        }
    }
}

class UnescapedText(text: String) : Tag(text) {
    override fun render(indent: Int, pretty: Boolean): String {
        if (pretty ) {
            return indent(indent) + tag
        } else {
            return indent(indent) + tag
        }
    }

    override fun toString() = this.render()
}

class ContainerTag(tagType: String) : Tag(tagType), Cloneable {

    var children: MutableList<Tag> = ArrayList()

    /**
     * Appends a tag to the end of this element

     * @param child tag to be appended
     * *
     * @return itself for easy chaining
     */
    fun with(child: Tag): ContainerTag {
        if (this === child) {
            throw Error("Cannot append a tag to itself.")
        }
        child.parent = this
        children.add(child)
        return this
    }

    operator fun plus(child: Tag): ContainerTag {
        if (this === child) {
            throw Error("Cannot append a tag to itself.")
        }
        val result = copy()

        child.parent = this
        result.children.add(child)

        return result
    }

    operator fun mod(child: Tag): ContainerTag {
        return with(child)
    }

    fun copy(): ContainerTag {
        val result = ContainerTag(tag)
        result.children = ArrayList(children)
        return result;
    }

    /**
     * Call with-method based on condition
     * [.with]
     */
    fun condWith(condition: Boolean, child: Tag) = if (condition) this.with(child) else this

    /**
     * Appends a list of tags to the end of this element

     * @param children tags to be appended
     * *
     * @return itself for easy chaining
     */
    fun with(children: List<Tag>?): ContainerTag {
        children?.forEach { this.with(it) }

        return this
    }

    /**
     * Call with-method based on condition
     * [.with]
     */
    fun condWith(condition: Boolean, children: List<Tag>) = if (condition) this.with(children) else this

    /**
     * Appends the tags to the end of this element

     * @param children tags to be appended
     * *
     * @return itself for easy chaining
     */
    fun with(vararg children: Tag): ContainerTag {
        for (aChildren in children) {
            with(aChildren)
        }
        return this
    }

    /**
     * Call with-method based on condition
     * [.with]
     */
    fun condWith(condition: Boolean, vararg children: Tag) = if (condition) this.with(*children) else this

    /**
     * Appends a text tag to this element

     * @param text the text to be appended
     * *
     * @return itself for easy chaining
     */
    fun withText(text: String) = with(Text(text))

    /**
     * Sets a custom attribute

     * @param attribute the attribute name
     * *
     * @param value     the attribute value
     * *
     * @return itself for easy chaining
     */
    fun attr(attribute: String, value: String?): ContainerTag {
        setAttribute(attribute, value)
        return this
    }

    /**
     * Call attr-method based on condition
     * [.attr]
     */
    fun condAttr(condition: Boolean, attribute: String, value: String?) = if (condition) attr(attribute, value) else this

    /**
     * Render the tag and its children
     */
    override fun render(indent: Int, pretty: Boolean): String {
        //very slow
        //        return renderOpenTag() + children.stream().map(Tag::render).collect(Collectors.joining()) + renderCloseTag();

        //pretty fast
        //        StringBuilder rendered = new StringBuilder(renderOpenTag());
        //        children.forEach(rendered::append);
        //        rendered.append(renderCloseTag());
        //        return rendered.toString();


        //fastest
        val rendered = StringBuilder()

        if (pretty) { rendered.append(indent(indent)) }
        rendered.append(renderOpenTag())
        if (pretty && !children.isEmpty()) { rendered.append("\n") }

        for (child in children) {
            rendered.append(child.render(indent + 2, pretty))
            if (pretty) { rendered.append("\n") }
        }

        if (pretty && !children.isEmpty()) { rendered.append(indent(indent)) }
        rendered.append(renderCloseTag())

        return rendered.toString()
    }

    override fun toString(): String {
        return this.render()
    }

    /**
     * Methods below this point are convenience methods
     * that call attr with a predefined attribute.
     */

    fun isAutoComplete() = attr(Attr.AUTOCOMPLETE, null)
    fun isAutoFocus() = attr(Attr.AUTOFOCUS, null)
    fun isHidden() = attr(Attr.HIDDEN, null)
    fun isRequired() = attr(Attr.REQUIRED, null)
    fun withAlt(alt: String) = attr(Attr.ALT, alt)
    fun withAction(action: String) = attr(Attr.ACTION, action)
    fun withCharset(charset: String) = attr(Attr.CHARSET, charset)
    fun withClass(className: String) = attr(Attr.CLASS, className)
    fun withContent(content: String) = attr(Attr.CONTENT, content)
    fun withHref(href: String) = attr(Attr.HREF, href)
    fun withId(id: String) = attr(Attr.ID, id)
    fun withData(dataAttr: String, value: String) = attr(Attr.DATA + "-" + dataAttr, value)
    fun withMethod(method: String) = attr(Attr.METHOD, method)
    fun withName(name: String) = attr(Attr.NAME, name)
    fun withPlaceholder(placeholder: String) = attr(Attr.PLACEHOLDER, placeholder)
    fun withTarget(target: String) = attr(Attr.TARGET, target)
    fun withType(type: String) = attr(Attr.TYPE, type)
    fun withRel(rel: String) = attr(Attr.REL, rel)
    fun withSrc(src: String) = attr(Attr.SRC, src)
    fun withValue(value: String) = attr(Attr.VALUE, value)
    fun withCondAutoComplete(condition: Boolean) = condAttr(condition, Attr.AUTOCOMPLETE, null)
    fun withCondAutoFocus(condition: Boolean) = condAttr(condition, Attr.AUTOFOCUS, null)
    fun withCondHidden(condition: Boolean) = condAttr(condition, Attr.HIDDEN, null)
    fun withCondRequired(condition: Boolean) = condAttr(condition, Attr.REQUIRED, null)
    fun withCondAlt(condition: Boolean, alt: String) = condAttr(condition, Attr.ALT, alt)
    fun withCondAction(condition: Boolean, action: String) = condAttr(condition, Attr.ACTION, action)
    fun withCharset(condition: Boolean, charset: String) = condAttr(condition, Attr.CHARSET, charset)
    fun withCondClass(condition: Boolean, className: String) = condAttr(condition, Attr.CLASS, className)
    fun withCondContent(condition: Boolean, content: String) = condAttr(condition, Attr.CONTENT, content)
    fun withCondHref(condition: Boolean, href: String) = condAttr(condition, Attr.HREF, href)
    fun withCondId(condition: Boolean, id: String) = condAttr(condition, Attr.ID, id)
    fun withCondData(condition: Boolean, dataAttr: String, value: String) = condAttr(condition, Attr.DATA + "-" + dataAttr, value)
    fun withCondMethod(condition: Boolean, method: String) = condAttr(condition, Attr.METHOD, method)
    fun withCondName(condition: Boolean, name: String) = condAttr(condition, Attr.NAME, name)
    fun withCondPlaceholder(condition: Boolean, placeholder: String) = condAttr(condition, Attr.PLACEHOLDER, placeholder)
    fun withCondTarget(condition: Boolean, target: String) = condAttr(condition, Attr.TARGET, target)
    fun withCondType(condition: Boolean, type: String) = condAttr(condition, Attr.TYPE, type)
    fun withCondRel(condition: Boolean, rel: String) = condAttr(condition, Attr.REL, rel)
    fun withCondSrc(condition: Boolean, src: String) = condAttr(condition, Attr.SRC, src)
    fun withCondValue(condition: Boolean, value: String) = condAttr(condition, Attr.VALUE, value)
}

fun tag(tagName: String) = ContainerTag(tagName)
fun emptyTag(tagName: String) = EmptyTag(tagName)
fun text(text: String) = Text(text)
fun unsafeHtml(html: String) = UnescapedText(html)

//EmptyTags
fun area() = EmptyTag("area")
fun base() = EmptyTag("base")
fun br() = EmptyTag("br")
fun col() = EmptyTag("col")
fun document() = EmptyTag("!DOCTYPE html")
fun embed() = EmptyTag("embed")
fun hr() = EmptyTag("hr")
fun img() = EmptyTag("img")
fun input() = EmptyTag("input")
fun keygen() = EmptyTag("keygen")
fun link() = EmptyTag("link")
fun meta() = EmptyTag("meta")
fun param() = EmptyTag("param")
fun source() = EmptyTag("source")
fun track() = EmptyTag("track")
fun wbr() = EmptyTag("wbr")

// ContainerTags
fun a() = tag("a")
fun a(text: String) = tag("a").withText(text)
fun a(text: String, href: String) = tag("a").withText(text).withHref(href)
fun abbr() = ContainerTag("abbr")
fun address() = ContainerTag("address")
fun article() = ContainerTag("article")
fun aside() = ContainerTag("aside")
fun audio() = ContainerTag("audio")
fun b() = ContainerTag("b")
fun b(text: String) = ContainerTag("b").withText(text)
fun bdi() = ContainerTag("bdi")
fun bdi(text: String) = ContainerTag("bdi").withText(text)
fun bdo() = ContainerTag("bdo")
fun bdo(text: String) = ContainerTag("bdo").withText(text)
fun blockquote() = ContainerTag("blockquote")
fun blockquote(text: String) = ContainerTag("blockquote").withText(text)
fun body() = ContainerTag("body")
fun button() = ContainerTag("button")
fun button(text: String) = ContainerTag("button").withText(text)
fun canvas() = ContainerTag("canvas")
fun caption() = ContainerTag("caption")
fun caption(text: String) = ContainerTag("caption").withText(text)
fun cite() = ContainerTag("cite")
fun cite(text: String) = ContainerTag("cite").withText(text)
fun code() = ContainerTag("code")
fun colgroup() = ContainerTag("colgroup")
fun datalist() = ContainerTag("datalist")
fun dd() = ContainerTag("dd")
fun dd(text: String) = ContainerTag("dd").withText(text)
fun del() = ContainerTag("del")
fun del(text: String) = ContainerTag("del").withText(text)
fun details() = ContainerTag("details")
fun dfn() = ContainerTag("dfn")
fun dfn(text: String) = ContainerTag("dfn").withText(text)
fun dialog() = ContainerTag("dialog")
fun dialog(text: String) = ContainerTag("dialog").withText(text)
fun div() = ContainerTag("div")
fun dl() = ContainerTag("dl")
fun dt() = ContainerTag("dt")
fun dt(text: String) = ContainerTag("dt").withText(text)
fun em() = ContainerTag("em")
fun em(text: String) = ContainerTag("em").withText(text)
fun fieldset() = ContainerTag("fieldset")
fun figcaption() = ContainerTag("figcaption")
fun figcaption(text: String) = ContainerTag("figcaption").withText(text)
fun figure() = ContainerTag("figure")
fun footer() = ContainerTag("footer")
fun form() = ContainerTag("form")
fun h1() = ContainerTag("h1")
fun h1(text: String) = ContainerTag("h1").withText(text)
fun h2() = ContainerTag("h2")
fun h2(text: String) = ContainerTag("h2").withText(text)
fun h3() = ContainerTag("h3")
fun h3(text: String) = ContainerTag("h3").withText(text)
fun h4() = ContainerTag("h4")
fun h4(text: String) = ContainerTag("h4").withText(text)
fun h5() = ContainerTag("h5")
fun h5(text: String) = ContainerTag("h5").withText(text)
fun h6() = ContainerTag("h6")
fun h6(text: String) = ContainerTag("h6").withText(text)
fun head() = ContainerTag("head")
fun header() = ContainerTag("header")
fun html() = ContainerTag("html")
fun i() = ContainerTag("i")
fun i(text: String) = ContainerTag("i").withText(text)
fun iframe() = ContainerTag("iframe")
fun ins() = ContainerTag("ins")
fun ins(text: String) = ContainerTag("ins").withText(text)
fun kbd() = ContainerTag("kbd")
fun label() = ContainerTag("label")
fun label(text: String) = ContainerTag("label").withText(text)
fun legend() = ContainerTag("legend")
fun legend(text: String) = ContainerTag("legend").withText(text)
fun li() = ContainerTag("li")
fun li(text: String) = ContainerTag("li").withText(text)
fun main() = ContainerTag("main")
fun map() = ContainerTag("map")
fun mark() = ContainerTag("mark")
fun menu() = ContainerTag("menu")
fun menuitem() = ContainerTag("menuitem")
fun meter() = ContainerTag("meter")
fun nav() = ContainerTag("nav")
fun noscript() = ContainerTag("noscript")
fun object_() = ContainerTag("object")
fun ol() = ContainerTag("ol")
fun optgroup() = ContainerTag("optgroup")
fun option() = ContainerTag("option")
fun option(text: String) = ContainerTag("option").withText(text)
fun output() = ContainerTag("output")
fun p() = ContainerTag("p")
fun p(text: String) = ContainerTag("p").withText(text)
fun pre() = ContainerTag("pre")
fun progress() = ContainerTag("progress")
fun q() = ContainerTag("q")
fun q(text: String) = ContainerTag("q").withText(text)
fun rp() = ContainerTag("rp")
fun rt() = ContainerTag("rt")
fun ruby() = ContainerTag("ruby")
fun s() = ContainerTag("s")
fun s(text: String) = ContainerTag("s").withText(text)
fun samp() = ContainerTag("samp")
fun script() = ContainerTag("script")
fun section() = ContainerTag("section")
fun select() = ContainerTag("select")
fun small() = ContainerTag("small")
fun small(text: String) = ContainerTag("small").withText(text)
fun span() = ContainerTag("span")
fun span(text: String) = ContainerTag("span").withText(text)
fun strong() = ContainerTag("strong")
fun strong(text: String) = ContainerTag("strong").withText(text)
fun style() = ContainerTag("style")
fun sub() = ContainerTag("sub")
fun sub(text: String) = ContainerTag("sub").withText(text)
fun summary() = ContainerTag("summary")
fun summary(text: String) = ContainerTag("summary").withText(text)
fun sup() = ContainerTag("sup")
fun sup(text: String) = ContainerTag("sup").withText(text)
fun table() = ContainerTag("table")
fun tbody() = ContainerTag("tbody")
fun td() = ContainerTag("td")
fun td(text: String) = ContainerTag("td").withText(text)
fun textarea() = ContainerTag("textarea")
fun tfoot() = ContainerTag("tfoot")
fun th() = ContainerTag("th")
fun th(text: String) = ContainerTag("th").withText(text)
fun thead() = ContainerTag("thead")
fun time() = ContainerTag("time")
fun title() = ContainerTag("title")
fun title(text: String) = ContainerTag("title").withText(text)
fun tr() = ContainerTag("tr")
fun u() = ContainerTag("u")
fun u(text: String) = ContainerTag("u").withText(text)
fun ul() = ContainerTag("ul")
fun var_() = ContainerTag("var")
fun videa() = ContainerTag("video")