Enable passing content or attrs as variables
Before, the guards in the macro definitions would only work for content or attributes that were passed in as literals.
This commit is contained in:
parent
6c6bd8dd3b
commit
d81029c9be
2 changed files with 141 additions and 25 deletions
|
@ -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), "</#{unquote(el)}>")
|
||||
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
|
||||
|
||||
def put_open_tag(buff, el, attrs) when is_list(attrs) do
|
||||
put_buffer(buff, "<#{el}#{compile_attrs(attrs)}>")
|
||||
end
|
||||
|
||||
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, "</#{el}>")
|
||||
end
|
||||
|
||||
for el <- @void_elements do
|
||||
defmacro unquote(el)(attrs \\ [])
|
||||
|
||||
defmacro unquote(el)(attrs) 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)
|
||||
|
||||
|
|
|
@ -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 == "<div></div><span></span>"
|
||||
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{<div class="bob"><span></span><span></span></div>}
|
||||
end
|
||||
|
||||
test "renders one els nested inside an el" do
|
||||
{:safe, result} =
|
||||
htm do
|
||||
div do
|
||||
span()
|
||||
end
|
||||
end
|
||||
|
||||
assert result == "<div><span></span></div>"
|
||||
end
|
||||
|
||||
test "renders two els nested inside an el" do
|
||||
{:safe, result} =
|
||||
htm do
|
||||
div do
|
||||
span()
|
||||
span()
|
||||
end
|
||||
end
|
||||
|
||||
assert result == "<div><span></span><span></span></div>"
|
||||
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{<div class="hello"><div class="hi"></div></div>}
|
||||
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{<div class="hello"><div class="hi"></div></div>}
|
||||
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{<div>CONTENT</div><div class="hi">MORE</div>}
|
||||
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{<div>CONTENT</div><div class="hi">MORE</div>}
|
||||
end
|
||||
end
|
||||
|
||||
describe "void elements" do
|
||||
|
@ -286,6 +358,36 @@ defmodule Dsl.HtmlTest do
|
|||
~s|<div>:atom</div><div>%{key: "value"}</div><div>{:status, :tuple}</div><div>"string"</div><div>1</div><div>[1, 2, 3]</div>|
|
||||
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|<div id="hi"></div>|
|
||||
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|<div id="hi"><div></div></div>|
|
||||
end
|
||||
|
||||
test "can use string interpolation in props" do
|
||||
interop = "hi"
|
||||
|
||||
|
|
Reference in a new issue