Properly emit boolean attributes (#139)

* Update some docs

* Properly emit boolean attributes.

* Account for quoted literals when compiling attributes

* Update changelog
This commit is contained in:
Mitchell Hanberg 2021-06-26 21:47:21 -04:00 committed by GitHub
parent d307fe35de
commit 9d05f74cdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 62 additions and 23 deletions

View File

@ -2,7 +2,9 @@
## Main
Nothing yet
### Enhancements
- [breaking] Attributes who values are boolean expressions will be emitted as boolean attributes.
## 0.6.2

View File

@ -22,15 +22,6 @@ def deps do
]
end
```
or
```elixir
def deps do
[{:temple, github: "mhanberg/temple"}]
end
```
## Goals
Currently Temple has the following things on which it won't compromise.
@ -140,7 +131,8 @@ config :phoenix, :template_engines,
# you can enable Elixir syntax highlighting in your editor
lexs: Temple.LiveViewEngine
# If you're going to be using live_view, make sure to set the `:mode`
# If you're going to be using live_view, make sure to set the `:mode` to `:live_view`.
# This is necessary for Temple to emit markup that is compatible.
config :temple, :mode, :live_view # defaults to normal
# config/dev.exs
@ -156,6 +148,7 @@ config :your_app, YourAppWeb.Endpoint,
```elixir
# app.html.exs
"<!DOCTYPE html>"
html lang: "en" do
head do
meta charset: "utf-8"
@ -163,7 +156,7 @@ html lang: "en" do
meta name: "viewport", content: "width=device-width, initial-scale=1.0"
title do: "YourApp · Phoenix Framework"
link rel: "stylesheet", href: Routes.static_path(@conn, "/css/app.css")
_link rel: "stylesheet", href: Routes.static_path(@conn, "/css/app.css")
end
body do

View File

@ -22,6 +22,8 @@ c Form, changeset: @changeset, action: @action do
text_input f, :author
error_tag(f, :author)
input type: "text", disabled: true, id: "disabled-input"
div do
submit "Save"
end

View File

@ -37,6 +37,7 @@ defmodule TempleDemoWeb.TempleFeatureTest do
s |> click(Query.option("21"))
end)
|> fill_in(Query.text_field("Author"), with: "Mitchelob Ultra")
|> assert_has(Query.css("#disabled-input[disabled]"))
|> click(Query.button("Save"))
|> assert_text("Post created successfully.")
end

View File

@ -19,6 +19,14 @@ defmodule Temple do
id
end
# Attributes that result in boolean values will be emitted as a boolean attribute. Examples of boolean attributes are `disabled` and `checked`.
input type: "text", disabled: true
# <input type="text" disabled>
input type: "text", disabled: false
# <input type="text">
# if and unless expressions can be used to conditionally render content
if 5 > 0 do
p do
@ -61,7 +69,9 @@ defmodule Temple do
There are two "modes", `:normal` (the default) and `:live_view`.
In `:live_view` mode, Temple emits markup that uses functions provided by Phoenix LiveView in order to be fully "diff trackable".
In `:live_view` mode, Temple emits markup that uses functions provided by Phoenix LiveView in order to be fully "diff trackable". These LiveView functions have not been released yet, so if you are going to combine Temple with LiveView, you need to use the latest unreleased default branch from GitHub.
You should use `:live_view` mode even if you only have a single LiveView.
```elixir
config :temple, :mode, :normal # default

View File

@ -18,11 +18,11 @@ defmodule Temple.Parser.Utils do
for {name, value} <- attrs, into: "" do
name = snake_to_kebab(name)
case value do
{_, _, _} = macro ->
" " <> name <> "=\"<%= " <> Macro.to_string(macro) <> " %>\""
cond do
(not is_binary(value) && Macro.quoted_literal?(value)) || match?({_, _, _}, value) ->
~s|<%= {:safe, Temple.Parser.Utils.build_attr("#{name}", #{Macro.to_string(value)})} %>|
value ->
true ->
" " <> name <> "=\"" <> to_string(value) <> "\""
end
end
@ -37,10 +37,22 @@ defmodule Temple.Parser.Utils do
for {name, value} <- attrs, name not in [:inner_block, :inner_content], into: "" do
name = snake_to_kebab(name)
" " <> name <> "=\"" <> to_string(value) <> "\""
build_attr(name, value)
end}
end
def build_attr(name, true) do
" " <> name
end
def build_attr(_name, false) do
""
end
def build_attr(name, value) do
" " <> name <> "=\"" <> to_string(value) <> "\""
end
def split_args(not_what_i_want) when is_nil(not_what_i_want) or is_atom(not_what_i_want),
do: {[], []}

View File

@ -96,7 +96,7 @@ defmodule Temple.Parser.NonvoidElementsAliasesTest do
|> Temple.Generator.to_eex()
assert result |> :erlang.iolist_to_binary() ==
~s|<div class="foo" id="<%= var %>">\n<select>\n<option>\nfoo\n\n</option>\n</select>\n</div>|
~s|<div class="foo"<%= {:safe, Temple.Parser.Utils.build_attr("id", var)} %>>\n<select>\n<option>\nfoo\n\n</option>\n</select>\n</div>|
end
end
end

View File

@ -67,7 +67,7 @@ defmodule Temple.Parser.TempleNamespaceNonvoidTest do
|> Temple.Generator.to_eex()
assert result |> :erlang.iolist_to_binary() ==
~s|<div class="foo" id="<%= var %>">\nfoo\n\n</div>|
~s|<div class="foo"<%= {:safe, Temple.Parser.Utils.build_attr("id", var)} %>>\nfoo\n\n</div>|
end
end
end

View File

@ -8,17 +8,19 @@ defmodule Temple.Parser.UtilsTest do
attrs_map = %{
class: "text-red",
id: "form1",
disabled: false,
inner_block: %{}
}
attrs_kw = [
class: "text-red",
id: "form1",
disabled: true,
inner_block: %{}
]
assert {:safe, ~s| class="text-red" id="form1"|} == Utils.runtime_attrs(attrs_map)
assert {:safe, ~s| class="text-red" id="form1"|} == Utils.runtime_attrs(attrs_kw)
assert {:safe, ~s| class="text-red" id="form1" disabled|} == Utils.runtime_attrs(attrs_kw)
end
end
end

View File

@ -89,7 +89,8 @@ defmodule TempleTest do
div class: foo <> " bar"
end
assert result == ~s{<div class="<%= foo <> " bar" %>"></div>}
assert result ==
~s|<div<%= {:safe, Temple.Parser.Utils.build_attr("class", foo <> " bar")} %>></div>|
end
test "renders an attribute on a div passed as a variable as eex" do
@ -101,7 +102,7 @@ defmodule TempleTest do
end
assert result ==
~s{<div class="<%= Enum.map([:one, :two], fn x -> x end) %>"><div class="hi"></div></div>}
~s|<div<%= {:safe, Temple.Parser.Utils.build_attr("class", Enum.map([:one, :two], fn x -> x end))} %>><div class="hi"></div></div>|
end
test "renders a for comprehension as eex" do
@ -335,4 +336,20 @@ defmodule TempleTest do
assert evaluate_template(result, assigns) ==
~s{<div>foo</div><hr><div>foo</div><hr class="foofoo"><div>bar</div><hr class="foofoo"><div>bar</div>}
end
test "boolean attributes" do
assigns = %{is_true: true, is_false: false}
result =
temple do
input type: "text", disabled: true
input type: "text", disabled: false
input type: "text", disabled: @is_true
input type: "text", disabled: @is_false
end
assert evaluate_template(result, assigns) ==
~s{<input type="text" disabled>\n<input type="text">\n<input type="text" disabled>\n<input type="text">}
end
end