Current section

Files

Jump to
sneeze lib sneeze.ex
Raw

lib/sneeze.ex

defmodule Sneeze do
alias Sneeze.Internal
@doc ~s"""
Render a data-structure, containing 'elements' to html.
An element is either:
- [tag, attribute_map | body]
- [tag, attribute_map]
- [tag | body]
- [tag]
- [:@__raw_html, html_string]
- A bare, stringable value (such as a string or number)
- A list of elements
Examples:
```
render([:p, %{class: "outlined"}, "hello"])
render([:br])
render([[:span, "one"], [:span, "two"]])
render([:ul, %{id: "some-list"},
[:li, [:a, %{href: "/"}, "Home"]],
[:li, [:a, %{href: "/about"}, "About"]]])
```
"""
def render(data) do
_render(data)
end
defp _render(data) do
case data do
[] ->
""
# list with tag
[tag] when is_atom(tag) ->
if Internal.is_void_tag?(tag) do
Internal.render_void_tag(tag)
else
Internal.render_tag(tag)
end
# list with tag and attribute map
[tag, attributes] when is_atom(tag) and is_map(attributes) ->
if Internal.is_void_tag?(tag) do
Internal.render_void_tag(tag, attributes)
else
Internal.render_tag(tag, attributes)
end
[:__@raw_html, html_string] ->
html_string
# list with tag, attribute map and child nodes
[tag, attributes | body] when is_map(attributes) ->
if Internal.is_void_tag?(tag) do
Internal.render_void_tag(tag, attributes)
<> _render(body) # not actually body, next elements
else
Internal.render_opening_tag(tag, attributes)
<> _render_body(body)
<> Internal.render_closing_tag(tag)
end
# list with tag and child nodes
[tag | body] when is_atom(tag) ->
if Internal.is_void_tag?(tag) do
Internal.render_void_tag(tag)
<> _render_body(body) # not actually body, next elements
else
Internal.render_opening_tag(tag)
<> _render_body(body)
<> Internal.render_closing_tag(tag)
end
# list with list of child nodes
[node] when is_list(node) ->
_render node
# list with sub-list as first element
[node | rest] when is_list(node) ->
_render(node) <> _render(rest)
# list with single, stringible member
[node] ->
to_string(node) |> HtmlEntities.encode
# any non-list node
bare_node ->
to_string(bare_node) |> HtmlEntities.encode
end
end
defp _render_body(body_elements) do
body_elements
|> Enum.map(&_render/1)
|> Enum.join("")
end
end