Implement remaining from helpers

This commit is contained in:
Mitchell Hanberg 2019-06-01 00:02:49 -04:00
parent 3a435b1727
commit 6b55fc7665
8 changed files with 711 additions and 7 deletions

View file

@ -1,2 +1 @@
use Mix.Config

View file

@ -125,7 +125,7 @@ defmodule Dsl do
If a block is passed to the component, it can be referenced by a special assign called `@children`.
## Example
```
defcomponent :flex do
div id: @id, class: "flex" do

View file

@ -51,14 +51,172 @@ defmodule Dsl.Form do
end
end
@helpers [
:checkbox,
:color_input,
:date_input,
:date_select,
:datetime_local_input,
:datetime_select,
:email_input,
:file_input,
:hidden_input,
:number_input,
:password_input,
:range_input,
:search_input,
:telephone_input,
:textarea,
:text_input,
:time_input,
:time_select,
:url_input
]
for helper <- @helpers do
@doc """
Please see `Phoenix.HTML.Form.#{helper}/3` for details.
"""
defmacro unquote(helper)(form, field, opts \\ []) do
helper = unquote(helper)
quote do
{:safe, input} =
apply(Phoenix.HTML.Form, unquote(helper), [unquote_splicing([form, field, opts])])
Utils.put_buffer(var!(buff, Dsl.Tags), input)
end
end
end
@doc """
Please see `Phoenix.HTML.Form.text_input/3` for details.
Please see `Phoenix.HTML.Form.reset/2` for details.
"""
defmacro text_input(form, field, opts \\ []) do
defmacro reset(value, opts \\ []) do
quote do
{:safe, input} = HTML.Form.text_input(unquote_splicing([form, field, opts]))
{:safe, input} = Phoenix.HTML.Form.reset(unquote_splicing([value, opts]))
Utils.put_buffer(var!(buff, Dsl.Tags), input)
end
end
@doc """
Please see `Phoenix.HTML.Form.label/2` for details.
"""
defmacro phx_label(form, field) do
quote do
{:safe, input} = Phoenix.HTML.Form.label(unquote_splicing([form, field]))
Utils.put_buffer(var!(buff, Dsl.Tags), input)
end
end
@doc """
Please see `Phoenix.HTML.Form.label/3` for details.
"""
defmacro phx_label(form, field, text_or_opts_or_block) do
quote do
{:safe, input} =
Phoenix.HTML.Form.label(unquote_splicing([form, field, text_or_opts_or_block]))
Utils.put_buffer(var!(buff, Dsl.Tags), input)
end
end
@doc """
Please see `Phoenix.HTML.Form.label/4` for details.
"""
defmacro phx_label(form, field, text_or_opts, opts_or_block) do
quote do
{:safe, input} =
Phoenix.HTML.Form.label(unquote_splicing([form, field, text_or_opts, opts_or_block]))
Utils.put_buffer(var!(buff, Dsl.Tags), input)
end
end
@doc """
Please see `Phoenix.HTML.Form.multiple_select/4` for details.
"""
defmacro multiple_select(form, field, options, attrs \\ []) do
quote do
{:safe, input} =
Phoenix.HTML.Form.multiple_select(unquote_splicing([form, field, options, attrs]))
Utils.put_buffer(var!(buff, Dsl.Tags), input)
end
end
@doc """
Please see `Phoenix.HTML.Form.select/4` for details.
"""
defmacro select(form, field, options, attrs \\ []) do
quote do
{:safe, input} = Phoenix.HTML.Form.select(unquote_splicing([form, field, options, attrs]))
Utils.put_buffer(var!(buff, Dsl.Tags), input)
end
end
@doc """
Generate a new form builder for the given parameter in form.
The form builder will be available inside the block through the `inner_form` variable.
This is a wrapper around the `Phoenix.HTML.Form.inputs_for/4` function and accepts all of the same options.
## Example
```
htm do
form_for @parent, Routes.some_path(@conn, :create) do
text_input form, :name
inputs_for form, :job do
text_input inner_form, :description
end
inputs_for form, :children do
text_input inner_form, :name
end
end
end
# {:safe,
# "<form accept-charset=\"UTF-8\" action=\"/\" method=\"post\">
# <input name=\"_csrf_token\" type=\"hidden\" value=\"AS5qfX1gcns6eU56BlQgBlwCDgMlNgAAiJ0MR91Kh3v3bbCS5SKjuw==\">
# <input name=\"_utf8\" type=\"hidden\" value=\"✓\">
# <input id=\"name\" name=\"parent[name]\" type=\"text\">
#
# <input id=\"name\" name=\"parent[job][description]\" type=\"text\">
#
# <input id=\"name\" name=\"parent[children][1][name]\" type=\"text\">
# <input id=\"name\" name=\"parent[children][2][name]\" type=\"text\">
# </form>"}
```
"""
defmacro inputs_for(form, field, options \\ [], do: block) do
quote do
form = unquote(form)
field = unquote(field)
options = unquote(options)
options =
form.options
|> Keyword.take([:multipart])
|> Keyword.merge(options)
form.impl.to_form(form.source, form, field, options)
|> Enum.each(fn form ->
Enum.map(form.hidden, fn {k, v} ->
Phoenix.HTML.Form.hidden_input(form, k, value: v)
end)
|> Enum.each(&Utils.put_buffer(var!(buff, Dsl.Tags), &1))
var!(inner_form) = form
_ = unquote(block)
end)
end
end
end

View file

@ -51,7 +51,6 @@ defmodule Dsl.Tags do
# <input name=\"comments\" placeholder=\"Enter a comment...\">"
# }
```
"""
@nonvoid_elements ~w[

View file

@ -11,7 +11,7 @@ defmodule Mix.Tasks.UpdateMdnDocs do
el = to_string(el)
page =
if Enum.any?(["h1", "h2", "h3", "h4", "h5", "h6"], & &1 == el) do
if Enum.any?(["h1", "h2", "h3", "h4", "h5", "h6"], &(&1 == el)) do
"Heading_Elements"
else
el

View file

@ -37,6 +37,8 @@ defmodule Dsl.MixProject do
defp deps do
[
{:phoenix_html, "~> 2.13"},
{:ecto, "~> 3.0", optional: true},
{:phoenix_ecto, "~> 4.0", optional: true},
{:ex_doc, "~> 0.0", only: [:dev], runtime: false},
{:html_sanitize_ex, "~> 1.3", only: [:dev, :test], runtime: false},
{:phoenix, "~> 1.4", optional: true},

View file

@ -1,7 +1,9 @@
%{
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"decimal": {:hex, :decimal, "1.7.0", "30d6b52c88541f9a66637359ddf85016df9eb266170d53105f02e4a67e00c5aa", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "3.1.4", "69d852da7a9f04ede725855a35ede48d158ca11a404fe94f8b2fb3b2162cd3c9", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"erlex": {:hex, :erlex, "0.2.1", "cee02918660807cbba9a7229cae9b42d1c6143b768c781fa6cee1eaf03ad860b", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.20.2", "1bd0dfb0304bade58beb77f20f21ee3558cc3c753743ae0ddbb0fd7ba2912331", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
@ -16,6 +18,7 @@
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.4.3", "8eed4a64ff1e12372cd634724bddd69185938f52c18e1396ebac76375d85677d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.13.2", "f5d27c9b10ce881a60177d2b5227314fc60881e6b66b41dfe3349db6ed06cf57", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"},
"plug": {:hex, :plug, "1.8.0", "9d2685cb007fe5e28ed9ac27af2815bc262b7817a00929ac10f56f169f43b977", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},

View file

@ -52,4 +52,547 @@ defmodule Dsl.FormTest do
assert result =~ ~s{</form>}
end
end
defmodule Person do
use Ecto.Schema
embedded_schema do
field(:name)
belongs_to(:company, Company)
has_many(:responsibilities, Reponsibility)
end
end
defmodule Company do
use Ecto.Schema
embedded_schema do
field(:name)
field(:field)
end
end
defmodule Responsibility do
use Ecto.Schema
embedded_schema do
field(:description)
end
end
describe "inputs_for" do
test "generates inputs for belongs_to" do
person = %Person{company: %Company{}}
changeset = Ecto.Changeset.change(person)
action = "/"
opts = []
{:safe, result} =
htm do
form_for changeset, action, opts do
text_input(form, :name)
inputs_for form, :company do
text_input(inner_form, :name)
_ = "Bob"
text_input(inner_form, :field)
end
end
end
assert result =~ ~s{<form}
assert result =~ ~s{<input}
assert result =~ ~s{type="text"}
assert result =~ ~s{name="person[company][name]"}
assert result =~ ~s{name="person[company][field]"}
assert result =~ ~s{</form>}
refute result =~ ~s{Bob}
end
test "generates inputs for has_many" do
person = %Person{responsibilities: [%Responsibility{}, %Responsibility{}]}
changeset = Ecto.Changeset.change(person)
action = "/"
opts = []
{:safe, result} =
htm do
form_for changeset, action, opts do
text_input(form, :name)
inputs_for form, :responsibilities do
text_input(inner_form, :description)
_ = "Bob"
end
end
end
assert result =~ ~s{<form}
assert result =~ ~s{<input}
assert result =~ ~s{type="text"}
assert result =~ ~s{name="person[responsibilities][0][description]"}
assert result =~ ~s{name="person[responsibilities][1][description]"}
assert result =~ ~s{</form>}
refute result =~ ~s{Bob}
end
end
describe "helpers" do
test "generates a checkbox input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
checkbox(form, :bob, class: "styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="checkbox"}
assert result =~ ~s{class="styles"}
assert result =~ ~s{name="bob"}
end
test "generates a color input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
color_input(form, :bob, class: "styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="color"}
assert result =~ ~s{class="styles"}
assert result =~ ~s{name="bob"}
end
test "generates a date input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
date_input(form, :bob, class: "date-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="date"}
assert result =~ ~s{class="date-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a date select input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
date_select(form, :bob, class: "date-styles")
end
end
assert result =~ ~s{<select}
end
test "generates a datetime_local_input input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
datetime_local_input(form, :bob, class: "date-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="datetime-local"}
assert result =~ ~s{class="date-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a datetime_select input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
datetime_select(form, :bob, class: "datetime-select-styles")
end
end
assert result =~ ~s{<select}
end
test "generates a email input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
email_input(form, :bob, class: "email-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="email"}
assert result =~ ~s{class="email-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a file input" do
conn = %Plug.Conn{}
action = "/"
opts = [multipart: true]
{:safe, result} =
htm do
form_for conn, action, opts do
file_input(form, :bob, class: "file-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="file"}
assert result =~ ~s{class="file-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a hidden input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
hidden_input(form, :bob, class: "hidden-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="hidden"}
assert result =~ ~s{class="hidden-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a number input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
number_input(form, :bob, class: "number-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="number"}
assert result =~ ~s{class="number-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a password input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
password_input(form, :bob, class: "password-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="password"}
assert result =~ ~s{class="password-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a range input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
range_input(form, :bob, class: "range-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="range"}
assert result =~ ~s{class="range-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a search input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
search_input(form, :bob, class: "search-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="search"}
assert result =~ ~s{class="search-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a telephone input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
telephone_input(form, :bob, class: "telephone-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="tel"}
assert result =~ ~s{class="telephone-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a textarea" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
textarea(form, :bob, class: "textarea-styles")
end
end
assert result =~ ~s{<textarea}
assert result =~ ~s{class="textarea-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a time input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
time_input(form, :bob, class: "time-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="time"}
assert result =~ ~s{class="time-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a time_select input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
time_select(form, :bob)
end
end
assert result =~ ~s{<select}
end
test "generates a url input" do
conn = %Plug.Conn{}
action = "/"
opts = []
{:safe, result} =
htm do
form_for conn, action, opts do
url_input(form, :bob, class: "url-styles")
end
end
assert result =~ ~s{<input}
assert result =~ ~s{type="url"}
assert result =~ ~s{class="url-styles"}
assert result =~ ~s{name="bob"}
end
test "generates a reset input" do
{:safe, result} =
htm do
reset("Reset", class: "reset-styles")
end
assert result =~ ~s{<input}
assert result =~ ~s{type="reset}
assert result =~ ~s{class="reset-styles"}
end
test "generates a phx_label/2 tag" do
{:safe, result} =
htm do
phx_label(:user, :name)
end
assert result =~ ~s{<label}
assert result =~ ~s{for="user_name"}
assert result =~ ~s{Name}
assert result =~ ~s{</label>}
end
test "generates a phx_label/3 with attrs" do
{:safe, result} =
htm do
phx_label(:user, :name, class: "label-style")
end
assert result =~ ~s{<label}
assert result =~ ~s{for="user_name"}
assert result =~ ~s{class="label-style"}
assert result =~ ~s{Name}
assert result =~ ~s{</label>}
end
test "generates a phx_label/3 with text" do
{:safe, result} =
htm do
phx_label(:user, :name, "Name")
end
assert result =~ ~s{<label}
assert result =~ ~s{for="user_name"}
assert result =~ ~s{Name}
assert result =~ ~s{</label>}
end
test "generates a phx_label/3 with block" do
{:safe, result} =
htm do
phx_label :user, :name do
"Name"
end
end
assert result =~ ~s{<label}
assert result =~ ~s{for="user_name"}
assert result =~ ~s{Name}
assert result =~ ~s{</label>}
end
test "generates a phx_label/4 with text and opts" do
{:safe, result} =
htm do
phx_label(:user, :name, "Name", class: "label-style")
end
assert result =~ ~s{<label}
assert result =~ ~s{for="user_name"}
assert result =~ ~s{class="label-style"}
assert result =~ ~s{Name}
assert result =~ ~s{</label>}
end
test "generates a phx_label/4 with block" do
{:safe, result} =
htm do
phx_label :user, :name, class: "label-style" do
"Name"
end
end
assert result =~ ~s{<label}
assert result =~ ~s{for="user_name"}
assert result =~ ~s{class="label-style"}
assert result =~ ~s{Name}
assert result =~ ~s{</label>}
end
test "generates a multiple_select tag" do
options = [
Alice: 1,
Bob: 2,
Carol: 3
]
{:safe, result} =
htm do
multiple_select(:user, :name, options, class: "label-style")
end
assert result =~ ~s{<select}
assert result =~ ~s{name="user[name][]"}
assert result =~ ~s{class="label-style"}
assert result =~ ~s{multiple=""}
assert result =~ ~s{<option}
assert result =~ ~s{value="1"}
assert result =~ ~s{Alice}
assert result =~ ~s{value="2"}
assert result =~ ~s{Bob}
assert result =~ ~s{value="3"}
assert result =~ ~s{Carol}
assert result =~ ~s{</select>}
end
test "generates a select tag" do
options = [
Alice: 1,
Bob: 2,
Carol: 3
]
{:safe, result} =
htm do
select :user, :name, options, class: "label-style"
end
assert result =~ ~s{<select}
assert result =~ ~s{name="user[name]"}
assert result =~ ~s{class="label-style"}
assert result =~ ~s{<option}
assert result =~ ~s{value="1"}
assert result =~ ~s{Alice}
assert result =~ ~s{value="2"}
assert result =~ ~s{Bob}
assert result =~ ~s{value="3"}
assert result =~ ~s{Carol}
assert result =~ ~s{</select>}
refute result =~ ~s{multiple=""}
end
end
end