diff --git a/lib/dsl/html.ex b/lib/dsl/html.ex index ec3cf75..69aa842 100644 --- a/lib/dsl/html.ex +++ b/lib/dsl/html.ex @@ -46,52 +46,68 @@ defmodule Dsl.Html do el = unquote(el) quote do - unquote(el)([], nil) + put_open_tag(var!(buff, Dsl.Html), unquote(el), []) + put_close_tag(var!(buff, Dsl.Html), unquote(el)) end end - defmacro unquote(el)(attrs) when is_list(attrs) do - el = unquote(el) - {inner, attrs} = Keyword.pop(attrs, :do, nil) - - quote do - unquote(el)(unquote(attrs), unquote(inner)) - end - end - - defmacro unquote(el)(content) when is_binary(content) do + defmacro unquote(el)([{:do, inner} | attrs]) do el = unquote(el) quote do - unquote(el)(unquote(content), []) + put_open_tag(var!(buff, Dsl.Html), unquote(el), unquote(attrs)) + _ = unquote(inner) + put_close_tag(var!(buff, Dsl.Html), unquote(el)) end end - defmacro unquote(el)(content, attrs) when not is_list(content) and is_list(attrs) do + defmacro unquote(el)(attrs_or_content) do el = unquote(el) - text = {:text, [], [content]} quote do - unquote(el)(unquote(attrs), unquote(text)) + put_open_tag(var!(buff, Dsl.Html), unquote(el), unquote(attrs_or_content)) + put_close_tag(var!(buff, Dsl.Html), unquote(el)) end end - defmacro unquote(el)(attrs, inner) when is_list(attrs) do + defmacro unquote(el)(attrs, [{:do, inner}]) do el = unquote(el) quote do attrs = unquote(attrs) - put_buffer(var!(buff, Dsl.Html), "<#{unquote(el)}#{compile_attrs(attrs)}>") - unquote(inner) - put_buffer(var!(buff, Dsl.Html), "") + put_open_tag(var!(buff, Dsl.Html), unquote(el), attrs) + _ = unquote(inner) + put_close_tag(var!(buff, Dsl.Html), unquote(el)) + end + end + + defmacro unquote(el)(content, attrs) do + el = unquote(el) + + quote do + attrs = unquote(attrs) + put_open_tag(var!(buff, Dsl.Html), unquote(el), attrs) + text unquote(content) + put_close_tag(var!(buff, Dsl.Html), unquote(el)) end end end - for el <- @void_elements do - defmacro unquote(el)(attrs \\ []) + def put_open_tag(buff, el, attrs) when is_list(attrs) do + put_buffer(buff, "<#{el}#{compile_attrs(attrs)}>") + end - defmacro unquote(el)(attrs) do + def put_open_tag(buff, el, content) when is_binary(content) do + put_buffer(buff, "<#{el}>") + put_buffer(buff, content) + end + + def put_close_tag(buff, el) do + put_buffer(buff, "") + end + + for el <- @void_elements do + defmacro unquote(el)(attrs \\ []) do el = unquote(el) quote do @@ -142,9 +158,7 @@ defmodule Dsl.Html do defmacro defcomponent(name, do: block) do quote do - defmacro unquote(name)(props \\ []) - - defmacro unquote(name)(props) do + defmacro unquote(name)(props \\ []) do outer = unquote(Macro.escape(block)) name = unquote(name) diff --git a/test/dsl/html_test.exs b/test/dsl/html_test.exs index 07b7acf..60dabfd 100644 --- a/test/dsl/html_test.exs +++ b/test/dsl/html_test.exs @@ -56,8 +56,19 @@ defmodule Dsl.HtmlTest do end end end + + defcomponent :variable_as_prop do + div id: @bob + end + + defcomponent :variable_as_prop_with_block do + div id: @bob do + @children + end + end end + describe "non-void elements" do test "renders two divs" do {:safe, result} = @@ -79,6 +90,41 @@ defmodule Dsl.HtmlTest do assert result == "
" end + test "renders an el that taks attrs and a block" do + {:safe, result} = + htm do + div class: "bob" do + span() + span() + end + end + + assert result == ~s{
} + end + + test "renders one els nested inside an el" do + {:safe, result} = + htm do + div do + span() + end + end + + assert result == "
" + end + + test "renders two els nested inside an el" do + {:safe, result} = + htm do + div do + span() + span() + end + end + + assert result == "
" + end + test "renders two divs that are rendered by a loop" do {:safe, result} = htm do @@ -122,6 +168,20 @@ defmodule Dsl.HtmlTest do assert result == ~s{
} end + test "renders an attribute on a div passed as a variable" do + attrs1 = [class: "hello"] + attrs2 = [class: "hi"] + + {:safe, result} = + htm do + div attrs1 do + div(attrs2) + end + end + + assert result == ~s{
} + end + test "renders multiple attributes on a div without block" do {:safe, result} = htm do @@ -140,6 +200,18 @@ defmodule Dsl.HtmlTest do assert result == ~s{
CONTENT
MORE
} end + + test "can accept content as first argument passed as a variable" do + content = "CONTENT" + more = "MORE" + {:safe, result} = + htm do + div(content) + div(more, class: "hi") + end + + assert result == ~s{
CONTENT
MORE
} + end end describe "void elements" do @@ -286,6 +358,36 @@ defmodule Dsl.HtmlTest do ~s|
:atom
%{key: "value"}
{:status, :tuple}
"string"
1
[1, 2, 3]
| end + test "can pass a variable as a prop" do + import Component + + bob = "hi" + + {:safe, result} = + htm do + variable_as_prop bob: bob + end + + assert result == + ~s|
| + end + + test "can pass a variable as a prop to a component with a block" do + import Component + + bob = "hi" + class = "joe" + + {:safe, result} = + htm do + variable_as_prop_with_block bob: bob do + div() + end + end + + assert result == ~s|
| + end + test "can use string interpolation in props" do interop = "hi"