Current section
Files
Jump to
Current section
Files
src/htmz.gleam
import htmz/selector_parser.{ParseResult, parse_css_selector}
import gleam/string
import gleam/list as gleam_list
import gleam/option.{Some}
pub type Attr {
Attr(name: String, value: String)
}
type ElTuple =
#(String, List(Attr), List(Htmz))
pub type Htmz {
El(tag: String, attrs: List(Attr), children: List(Htmz))
Z(css_selector: String)
Text(text: String)
Nothing
Html
Head
Title
Body
Div
Form
Label
Input
A
Link
Meta
Abbr
Address
Article
Aside
Audio
B
Bdi
Bdo
Blockquote
Br
Button
Canvas
Caption
Cite
Code
Col
Colgroup
Data
Datalist
Dd
Del
Details
Dfn
Dialog
Dl
Dt
Em
Embed
Fieldset
Figcaption
Figure
Footer
H1
H2
H3
H4
H5
H6
Header
Hr
I
Iframe
Img
Ins
Kbd
Legend
Li
Main
Mark
Menu
Menuitem
Meter
Nav
Noscript
Object
Ol
Optgroup
Option
Output
P
Param
Picture
Pre
Progress
Q
Rp
Rt
Ruby
S
Samp
Script
Section
Select
Slot
Small
Source
Span
Strong
Sub
Summary
Sup
Table
Tbody
Td
Template
Textarea
Tfoot
Th
Thead
Time
Tr
Track
U
Ul
Var
Video
Wbr
}
pub fn escape(content: String) -> String {
do_escape("", content)
}
/// Taken from "HTMB" library, written by @lpil
fn do_escape(escaped: String, content: String) -> String {
case string.pop_grapheme(content) {
Ok(#("<", xs)) -> do_escape(escaped <> "<", xs)
Ok(#(">", xs)) -> do_escape(escaped <> ">", xs)
Ok(#("&", xs)) -> do_escape(escaped <> "&", xs)
Ok(#(x, xs)) -> do_escape(escaped <> x, xs)
Error(_) -> escaped <> content
}
}
fn children_to_string(children: List(Htmz)) -> String {
children
|> gleam_list.map(to_string)
|> string.join("")
}
fn attrs_to_string(attrs: List(Attr)) -> String {
let str =
attrs
|> gleam_list.map(fn(attr) {
let name = string.lowercase(attr.name)
case name {
"" -> ""
_ ->
case attr.value {
"" -> name
_ -> name <> "=\"" <> escape(attr.value) <> "\""
}
}
})
|> string.join(" ")
case str {
"" -> ""
_ -> " " <> str
}
}
pub fn to_string(el: Htmz) -> String {
case el {
Text(text) -> escape(text)
_ -> {
let #(tag, attrs, children) = to_tuple(el)
case tag {
"" -> ""
"input" | "br" | "hr" | "img" | "link" | "meta" -> {
"<" <> tag <> attrs_to_string(attrs) <> "/>\n"
}
_ -> {
"<" <> tag <> attrs_to_string(attrs) <> ">\n" <> children_to_string(
children,
) <> "</" <> tag <> ">"
}
}
}
}
}
fn to_tuple(el: Htmz) -> ElTuple {
case el {
El(tag, attrs, children) -> #(tag, attrs, children)
Z(css_selector) -> {
let assert Some(ParseResult(tag, attrs)) =
parse_css_selector(css_selector)
let attrs = gleam_list.map(attrs, fn(t) { Attr(t.0, t.1) })
#(tag, attrs, [])
}
Text(_) -> #("", [], [])
Nothing -> #("", [], [])
Html -> #("html", [], [])
Head -> #("head", [], [])
Title -> #("title", [], [])
Body -> #("body", [], [])
Div -> #("div", [], [])
Form -> #("form", [], [])
Label -> #("label", [], [])
Input -> #("input", [], [])
A -> #("a", [], [])
Link -> #("link", [], [])
Meta -> #("meta", [], [])
Abbr -> #("abbr", [], [])
Address -> #("address", [], [])
Article -> #("article", [], [])
Aside -> #("aside", [], [])
Audio -> #("audio", [], [])
B -> #("b", [], [])
Bdi -> #("bdi", [], [])
Bdo -> #("bdo", [], [])
Blockquote -> #("blockquote", [], [])
Br -> #("br", [], [])
Button -> #("button", [], [])
Canvas -> #("canvas", [], [])
Caption -> #("caption", [], [])
Cite -> #("cite", [], [])
Code -> #("code", [], [])
Col -> #("col", [], [])
Colgroup -> #("colgroup", [], [])
Data -> #("data", [], [])
Datalist -> #("datalist", [], [])
Dd -> #("dd", [], [])
Del -> #("del", [], [])
Details -> #("details", [], [])
Dfn -> #("dfn", [], [])
Dialog -> #("dialog", [], [])
Dl -> #("dl", [], [])
Dt -> #("dt", [], [])
Em -> #("em", [], [])
Embed -> #("embed", [], [])
Fieldset -> #("fieldset", [], [])
Figcaption -> #("figcaption", [], [])
Figure -> #("figure", [], [])
Footer -> #("footer", [], [])
H1 -> #("h1", [], [])
H2 -> #("h2", [], [])
H3 -> #("h3", [], [])
H4 -> #("h4", [], [])
H5 -> #("h5", [], [])
H6 -> #("h6", [], [])
Header -> #("header", [], [])
Hr -> #("hr", [], [])
I -> #("i", [], [])
Iframe -> #("iframe", [], [])
Img -> #("img", [], [])
Ins -> #("ins", [], [])
Kbd -> #("kbd", [], [])
Legend -> #("legend", [], [])
Li -> #("li", [], [])
Main -> #("main", [], [])
Mark -> #("mark", [], [])
Menu -> #("menu", [], [])
Menuitem -> #("menuitem", [], [])
Meter -> #("meter", [], [])
Nav -> #("nav", [], [])
Noscript -> #("noscript", [], [])
Object -> #("object", [], [])
Ol -> #("ol", [], [])
Optgroup -> #("optgroup", [], [])
Option -> #("option", [], [])
Output -> #("output", [], [])
P -> #("p", [], [])
Param -> #("param", [], [])
Picture -> #("picture", [], [])
Pre -> #("pre", [], [])
Progress -> #("progress", [], [])
Q -> #("q", [], [])
Rp -> #("rp", [], [])
Rt -> #("rt", [], [])
Ruby -> #("ruby", [], [])
S -> #("s", [], [])
Samp -> #("samp", [], [])
Script -> #("script", [], [])
Section -> #("section", [], [])
Select -> #("select", [], [])
Slot -> #("slot", [], [])
Small -> #("small", [], [])
Source -> #("source", [], [])
Span -> #("span", [], [])
Strong -> #("strong", [], [])
Sub -> #("sub", [], [])
Summary -> #("summary", [], [])
Sup -> #("sup", [], [])
Table -> #("table", [], [])
Tbody -> #("tbody", [], [])
Td -> #("td", [], [])
Template -> #("template", [], [])
Textarea -> #("textarea", [], [])
Tfoot -> #("tfoot", [], [])
Th -> #("th", [], [])
Thead -> #("thead", [], [])
Time -> #("time", [], [])
Tr -> #("tr", [], [])
Track -> #("track", [], [])
U -> #("u", [], [])
Ul -> #("ul", [], [])
Var -> #("var", [], [])
Video -> #("video", [], [])
Wbr -> #("wbr", [], [])
}
}
pub fn children(el: Htmz, children: List(Htmz)) -> Htmz {
let #(tag, attrs, _) = to_tuple(el)
El(tag, attrs, children)
}
pub fn child(el: Htmz, child: Htmz) -> Htmz {
let #(tag, attrs, children) = to_tuple(el)
El(tag, attrs, [child, ..children])
}
//
// ATTRIBUTES
//
pub fn remove_attr(el: Htmz, attr_name: String) -> Htmz {
let #(tag, attrs, children) = to_tuple(el)
let attrs =
attrs
|> gleam_list.filter(fn(attr) { attr.name != attr_name })
El(tag, attrs, children)
}
pub fn attr(el: Htmz, attr_name: String, attr_value: String) -> Htmz {
let #(tag, attrs, children) =
el
|> remove_attr(attr_name)
|> to_tuple()
let attrs = [Attr(attr_name, attr_value), ..attrs]
El(tag, attrs, children)
}
pub fn nothing(el: Htmz) -> Htmz {
attr(el, "", "")
}
pub fn text(el: Htmz, text: String) -> Htmz {
child(el, Text(text))
}
pub fn accept(el: Htmz, value: String) -> Htmz {
attr(el, "accept", value)
}
pub fn accept_charset(el: Htmz, value: String) -> Htmz {
attr(el, "acceptCharset", value)
}
pub fn accesskey(el: Htmz, value: String) -> Htmz {
attr(el, "accesskey", value)
}
pub fn action(el: Htmz, value: String) -> Htmz {
attr(el, "action", value)
}
pub fn alt(el: Htmz, value: String) -> Htmz {
attr(el, "alt", value)
}
pub fn async_attr(el: Htmz, value: String) -> Htmz {
attr(el, "async", value)
}
pub fn autocapitalize(el: Htmz, value: String) -> Htmz {
attr(el, "autocapitalize", value)
}
pub fn autofocus(el: Htmz, value: String) -> Htmz {
attr(el, "autofocus", value)
}
pub fn autocomplete(el: Htmz, value: String) -> Htmz {
attr(el, "autocomplete", value)
}
pub fn charset(el: Htmz, value: String) -> Htmz {
attr(el, "charset", value)
}
pub fn checked(el: Htmz, value: String) -> Htmz {
attr(el, "checked", value)
}
pub fn class(el: Htmz, value: String) -> Htmz {
attr(el, "class", value)
}
pub fn cols(el: Htmz, value: String) -> Htmz {
attr(el, "cols", value)
}
pub fn columngap(el: Htmz, value: String) -> Htmz {
attr(el, "columngap", value)
}
pub fn colspan(el: Htmz, value: String) -> Htmz {
attr(el, "colspan", value)
}
pub fn content(el: Htmz, value: String) -> Htmz {
attr(el, "content", value)
}
pub fn contenteditable(el: Htmz, value: String) -> Htmz {
attr(el, "contenteditable", value)
}
pub fn contextmenu(el: Htmz, value: String) -> Htmz {
attr(el, "contextmenu", value)
}
pub fn controls(el: Htmz, value: String) -> Htmz {
attr(el, "controls", value)
}
pub fn coords(el: Htmz, value: String) -> Htmz {
attr(el, "coords", value)
}
pub fn crossorigin(el: Htmz, value: String) -> Htmz {
attr(el, "crossorigin", value)
}
pub fn data(el: Htmz, key: String, value: String) -> Htmz {
attr(el, "data-" <> key, value)
}
pub fn datetime(el: Htmz, value: String) -> Htmz {
attr(el, "datetime", value)
}
pub fn defer(el: Htmz) -> Htmz {
attr(el, "defer", "")
}
pub fn dir(el: Htmz, value: String) -> Htmz {
attr(el, "dir", value)
}
pub fn dirname(el: Htmz, value: String) -> Htmz {
attr(el, "dirname", value)
}
pub fn disabled(el: Htmz) -> Htmz {
attr(el, "disabled", "")
}
pub fn download(el: Htmz, value: String) -> Htmz {
attr(el, "download", value)
}
pub fn draggable(el: Htmz, value: String) -> Htmz {
attr(el, "draggable", value)
}
pub fn dropzone(el: Htmz, value: String) -> Htmz {
attr(el, "dropzone", value)
}
pub fn enctype(el: Htmz, value: String) -> Htmz {
attr(el, "enctype", value)
}
pub fn enterkeyhint(el: Htmz, value: String) -> Htmz {
attr(el, "enterkeyhint", value)
}
pub fn for(el: Htmz, value: String) -> Htmz {
attr(el, "for", value)
}
pub fn formaction(el: Htmz, value: String) -> Htmz {
attr(el, "formaction", value)
}
pub fn formenctype(el: Htmz, value: String) -> Htmz {
attr(el, "formenctype", value)
}
pub fn formmethod(el: Htmz, value: String) -> Htmz {
attr(el, "formmethod", value)
}
pub fn formnovalidate(el: Htmz, value: String) -> Htmz {
attr(el, "formnovalidate", value)
}
pub fn formtarget(el: Htmz, value: String) -> Htmz {
attr(el, "formtarget", value)
}
pub fn frameborder(el: Htmz, value: String) -> Htmz {
attr(el, "frameborder", value)
}
pub fn headers(el: Htmz, value: String) -> Htmz {
attr(el, "headers", value)
}
pub fn height(el: Htmz, value: String) -> Htmz {
attr(el, "height", value)
}
pub fn hidden(el: Htmz, value: String) -> Htmz {
attr(el, "hidden", value)
}
pub fn high(el: Htmz, value: String) -> Htmz {
attr(el, "high", value)
}
pub fn href(el: Htmz, value: String) -> Htmz {
attr(el, "href", value)
}
pub fn hreflang(el: Htmz, value: String) -> Htmz {
attr(el, "hreflang", value)
}
pub fn http_equiv(el: Htmz, value: String) -> Htmz {
attr(el, "httpEquiv", value)
}
pub fn id(el: Htmz, value: String) -> Htmz {
attr(el, "id", value)
}
pub fn inputmode(el: Htmz, value: String) -> Htmz {
attr(el, "inputmode", value)
}
pub fn integrity(el: Htmz, value: String) -> Htmz {
attr(el, "integrity", value)
}
pub fn is(el: Htmz, value: String) -> Htmz {
attr(el, "is", value)
}
pub fn ismap(el: Htmz, value: String) -> Htmz {
attr(el, "ismap", value)
}
pub fn kind(el: Htmz, value: String) -> Htmz {
attr(el, "kind", value)
}
pub fn label(el: Htmz, value: String) -> Htmz {
attr(el, "label", value)
}
pub fn lang(el: Htmz, value: String) -> Htmz {
attr(el, "lang", value)
}
pub fn language(el: Htmz, value: String) -> Htmz {
attr(el, "language", value)
}
pub fn list(el: Htmz, value: String) -> Htmz {
attr(el, "list", value)
}
pub fn loop_attr(el: Htmz, value: String) -> Htmz {
attr(el, "loop", value)
}
pub fn low(el: Htmz, value: String) -> Htmz {
attr(el, "low", value)
}
pub fn max(el: Htmz, value: String) -> Htmz {
attr(el, "max", value)
}
pub fn maxlength(el: Htmz, value: String) -> Htmz {
attr(el, "maxlength", value)
}
pub fn method(el: Htmz, value: String) -> Htmz {
attr(el, "method", value)
}
pub fn min(el: Htmz, value: String) -> Htmz {
attr(el, "min", value)
}
pub fn minlength(el: Htmz, value: String) -> Htmz {
attr(el, "minlength", value)
}
pub fn multiple(el: Htmz, value: String) -> Htmz {
attr(el, "multiple", value)
}
pub fn name(el: Htmz, value: String) -> Htmz {
attr(el, "name", value)
}
pub fn novalidate(el: Htmz, value: String) -> Htmz {
attr(el, "novalidate", value)
}
pub fn on(el: Htmz, event: String, value: String) -> Htmz {
attr(el, "on" <> event, value)
}
pub fn open(el: Htmz, value: String) -> Htmz {
attr(el, "open", value)
}
pub fn pattern(el: Htmz, value: String) -> Htmz {
attr(el, "pattern", value)
}
pub fn placeholder(el: Htmz, value: String) -> Htmz {
attr(el, "placeholder", value)
}
pub fn poster(el: Htmz, value: String) -> Htmz {
attr(el, "poster", value)
}
pub fn preload(el: Htmz, value: String) -> Htmz {
attr(el, "preload", value)
}
pub fn readonly(el: Htmz, value: String) -> Htmz {
attr(el, "readonly", value)
}
pub fn rel(el: Htmz, value: String) -> Htmz {
attr(el, "rel", value)
}
pub fn required(el: Htmz) -> Htmz {
attr(el, "required", "")
}
pub fn reversed(el: Htmz, value: String) -> Htmz {
attr(el, "reversed", value)
}
pub fn rows(el: Htmz, value: String) -> Htmz {
attr(el, "rows", value)
}
pub fn rowspan(el: Htmz, value: String) -> Htmz {
attr(el, "rowspan", value)
}
pub fn sandbox(el: Htmz, value: String) -> Htmz {
attr(el, "sandbox", value)
}
pub fn scope(el: Htmz, value: String) -> Htmz {
attr(el, "scope", value)
}
pub fn selected(el: Htmz) -> Htmz {
attr(el, "selected", "")
}
pub fn shape(el: Htmz, value: String) -> Htmz {
attr(el, "shape", value)
}
pub fn size(el: Htmz, value: String) -> Htmz {
attr(el, "size", value)
}
pub fn sizes(el: Htmz, value: String) -> Htmz {
attr(el, "sizes", value)
}
pub fn slot(el: Htmz, value: String) -> Htmz {
attr(el, "slot", value)
}
pub fn spellcheck(el: Htmz, value: String) -> Htmz {
attr(el, "spellcheck", value)
}
pub fn src(el: Htmz, value: String) -> Htmz {
attr(el, "src", value)
}
pub fn srcdoc(el: Htmz, value: String) -> Htmz {
attr(el, "srcdoc", value)
}
pub fn srclang(el: Htmz, value: String) -> Htmz {
attr(el, "srclang", value)
}
pub fn start(el: Htmz, value: String) -> Htmz {
attr(el, "start", value)
}
pub fn step(el: Htmz, value: String) -> Htmz {
attr(el, "step", value)
}
pub fn style(el: Htmz, value: String) -> Htmz {
attr(el, "style", value)
}
pub fn tabindex(el: Htmz, value: String) -> Htmz {
attr(el, "tabindex", value)
}
pub fn target(el: Htmz, value: String) -> Htmz {
attr(el, "target", value)
}
pub fn title(el: Htmz, value: String) -> Htmz {
attr(el, "title", value)
}
pub fn translate(el: Htmz, value: String) -> Htmz {
attr(el, "translate", value)
}
pub fn type_(el: Htmz, value: String) -> Htmz {
attr(el, "type", value)
}
pub fn usemap(el: Htmz, value: String) -> Htmz {
attr(el, "usemap", value)
}
pub fn value(el: Htmz, value: String) -> Htmz {
attr(el, "value", value)
}
pub fn width(el: Htmz, value: String) -> Htmz {
attr(el, "width", value)
}
pub fn wrap(el: Htmz, value: String) -> Htmz {
attr(el, "wrap", value)
}
pub fn hx_boost(el: Htmz, value: String) -> Htmz {
attr(el, "hx-boost", value)
}
pub fn hx_confirm(el: Htmz, value: String) -> Htmz {
attr(el, "hx-confirm", value)
}
pub fn hx_delete(el: Htmz, value: String) -> Htmz {
attr(el, "hx-delete", value)
}
pub fn hx_disabled_elt(el: Htmz, value: String) -> Htmz {
attr(el, "hx-disabled-elt", value)
}
pub fn hx_sync(el: Htmz, value: String) -> Htmz {
attr(el, "hx-sync", value)
}
pub fn hx_disinherit(el: Htmz, value: String) -> Htmz {
attr(el, "hx-disinherit", value)
}
pub fn hx_encoding(el: Htmz, value: String) -> Htmz {
attr(el, "hx-encoding", value)
}
pub fn hx_ext(el: Htmz, value: String) -> Htmz {
attr(el, "hx-ext", value)
}
pub fn hx_get(el: Htmz, value: String) -> Htmz {
attr(el, "hx-get", value)
}
pub fn hx_headers(el: Htmz, value: String) -> Htmz {
attr(el, "hx-headers", value)
}
pub fn hx_history(el: Htmz, value: String) -> Htmz {
attr(el, "hx-history", value)
}
pub fn hx_history_elt(el: Htmz, value: String) -> Htmz {
attr(el, "hx-history-elt", value)
}
pub fn hx_include(el: Htmz, value: String) -> Htmz {
attr(el, "hx-include", value)
}
pub fn hx_indicator(el: Htmz, value: String) -> Htmz {
attr(el, "hx-indicator", value)
}
pub fn hx_on(el: Htmz, event: String, value: String) -> Htmz {
attr(el, "hx-on:" <> event, value)
}
pub fn hx_params(el: Htmz, value: String) -> Htmz {
attr(el, "hx-params", value)
}
pub fn hx_post(el: Htmz, value: String) -> Htmz {
attr(el, "hx-post", value)
}
pub fn hx_put(el: Htmz, value: String) -> Htmz {
attr(el, "hx-put", value)
}
pub fn hx_patch(el: Htmz, value: String) -> Htmz {
attr(el, "hx-patch", value)
}
pub fn hx_push_url(el: Htmz, value: String) -> Htmz {
attr(el, "hx-push-url", value)
}
pub fn hx_select(el: Htmz, value: String) -> Htmz {
attr(el, "hx-select", value)
}
pub fn hx_select_oob(el: Htmz, value: String) -> Htmz {
attr(el, "hx-select-oob", value)
}
pub fn hx_swap(el: Htmz, value: String) -> Htmz {
attr(el, "hx-swap", value)
}
pub fn hx_swap_oob(el: Htmz, value: String) -> Htmz {
attr(el, "hx-swap-oob", value)
}
pub fn hx_target(el: Htmz, value: String) -> Htmz {
attr(el, "hx-target", value)
}
pub fn hx_trigger(el: Htmz, value: String) -> Htmz {
attr(el, "hx-trigger", value)
}
pub fn hx_vals(el: Htmz, value: String) -> Htmz {
attr(el, "hx-vals", value)
}
pub fn x_data(el: Htmz, value: String) -> Htmz {
attr(el, "x-data", value)
}
pub fn x_init(el: Htmz, value: String) -> Htmz {
attr(el, "x-init", value)
}
pub fn x_show(el: Htmz, value: String) -> Htmz {
attr(el, "x-show", value)
}
pub fn x_bind(el: Htmz, field: String, value: String) -> Htmz {
attr(el, "x-bind:" <> field, value)
}
pub fn x_on(el: Htmz, event: String, value: String) -> Htmz {
attr(el, "x-on:" <> event, value)
}
pub fn x_text(el: Htmz, value: String) -> Htmz {
attr(el, "x-text", value)
}
pub fn x_html(el: Htmz, value: String) -> Htmz {
attr(el, "x-html", value)
}
pub fn x_model(el: Htmz, value: String) -> Htmz {
attr(el, "x-model", value)
}
pub fn x_modelable(el: Htmz, value: String) -> Htmz {
attr(el, "x-modelable", value)
}
pub fn x_for(el: Htmz, value: String) -> Htmz {
attr(el, "x-for", value)
}
pub fn x_transition(el: Htmz) -> Htmz {
attr(el, "x-transition", "")
}
pub fn x_transition_a(el: Htmz, modifier: String, value: String) -> Htmz {
attr(el, "x-transition:" <> modifier, value)
}
pub fn x_effect(el: Htmz, value: String) -> Htmz {
attr(el, "x-effect", value)
}
pub fn x_ignore(el: Htmz, value: String) -> Htmz {
attr(el, "x-ignore", value)
}
pub fn x_ref(el: Htmz, value: String) -> Htmz {
attr(el, "x-ref", value)
}
pub fn x_cloak(el: Htmz, value: String) -> Htmz {
attr(el, "x-cloak", value)
}
pub fn x_teleport(el: Htmz, value: String) -> Htmz {
attr(el, "x-teleport", value)
}
pub fn x_if(el: Htmz, value: String) -> Htmz {
attr(el, "x-if", value)
}
pub fn x_id(el: Htmz, value: String) -> Htmz {
attr(el, "x-id", value)
}