Skip to content

Commit

Permalink
Enable bootstrap forms
Browse files Browse the repository at this point in the history
  • Loading branch information
danschultzer committed Aug 11, 2018
1 parent 2d41bd2 commit 2cb16e4
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 40 deletions.
52 changes: 52 additions & 0 deletions lib/pow/phoenix/html/bootstrap.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

defmodule Pow.Phoenix.HTML.Bootstrap do
@moduledoc """
Module that helps build HTML for Phoenix with Bootstrap CSS.
"""
import Pow.Phoenix.HTML.FormTemplate, only: [inspect_key: 1]

@form_template EEx.compile_string """
<%%= form_for @changeset, @action, [as: :user], fn f -> %>
<%%= if @changeset.action do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<%% end %>
<%= for {label, input, error} <- inputs, input do %>
<div class="form-group">
<%= label %>
<%= input %>
<%= error %>
</div>
<% end %>
<div class="form-group">
<%%= submit <%= inspect button_label %>, class: "btn btn-primary" %>
</div>
<%% end %>
"""

@doc """
Renders a form.
"""
@spec render_form(list(), binary()) :: Macro.t()
def render_form(inputs, button_label) do
inputs = for {type, key} <- inputs, do: input(type, key)

unquote(@form_template)
end

defp input(:text, key) do
{label(key), ~s(<%= text_input f, #{inspect_key(key)}, class: "form-control" %>), error(key)}
end
defp input(:password, key) do
{label(key), ~s(<%= password_input f, #{inspect_key(key)}, class: "form-control" %>), error(key)}
end

defp label(key) do
~s(<%= label f, #{inspect_key(key)}, class: "control-label" %>)
end

defp error(key) do
~s(<%= error_tag f, #{inspect_key(key)} %>)
end
end
29 changes: 22 additions & 7 deletions lib/pow/phoenix/html/form_template.ex
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@

defmodule Pow.Phoenix.HTML.FormTemplate do
@moduledoc """
Module that can build user form templates for Phoenix.
This module is build to support Phoenix 1.4 with minimalist CSS. Another
module `Pow.Phoenix.HTML.Bootstrap` exists to ensure Phoenix 1.3 templates
can be rendered with Bootstrap CSS classes. This is the default behaviour
until Phoenix 1.4 is released.
"""
alias Pow.Phoenix.HTML.Bootstrap

@template EEx.compile_string """
<%%= form_for @changeset, @action, [as: :user], fn f -> %>
<%%= if @changeset.action do %>
Expand All @@ -26,18 +32,25 @@ defmodule Pow.Phoenix.HTML.FormTemplate do
## Options
* `:button_label` - the submit button label, defaults to "Submit"
* `:button_label` - the submit button label, defaults to "Submit".
* `:bootstrap` - to render form as bootstrap, defaults to true.
"""
@spec render(list(), Keyword.t()) :: Macro.t()
def render(inputs, opts \\ []) do
inputs = for {type, key} <- inputs, do: input(type, key)
button_label = Keyword.get(opts, :button_label, "Submit")

case Keyword.get(opts, :bootstrap, true) do
true -> Bootstrap.render_form(inputs, button_label)
_any -> render_form(inputs, button_label)
end
end

defp render_form(inputs, button_label) do
inputs = for {type, key} <- inputs, do: input(type, key)

unquote(@template)
end

@doc false
@spec input(atom(), atom()) :: {binary(), binary(), binary()}
defp input(:text, key) do
{label(key), ~s(<%= text_input f, #{inspect_key(key)} %>), error(key)}
end
Expand All @@ -53,6 +66,8 @@ defmodule Pow.Phoenix.HTML.FormTemplate do
~s(<%= error_tag f, #{inspect_key(key)} %>)
end

defp inspect_key({:changeset, :pow_user_id_field}), do: "@changeset.data.__struct__.pow_user_id_field()"
defp inspect_key(key), do: inspect(key)
@doc false
@spec inspect_key(any()) :: binary()
def inspect_key({:changeset, :pow_user_id_field}), do: "@changeset.data.__struct__.pow_user_id_field()"
def inspect_key(key), do: inspect(key)
end
2 changes: 0 additions & 2 deletions lib/pow/phoenix/template.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ defmodule Pow.Phoenix.Template do
use Pow.Phoenix.Template
template :new, :html, "<%= content_tag(:span, "Template") %>"
template :edit, :html, {:form, [{:text, :custom}]}
end
MyApp.ResourceTemplate.render("new.html", assigns)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ defmodule PowResetPassword.Phoenix.ResetPasswordControllerTest do
conn = get(conn, Routes.pow_reset_password_reset_password_path(conn, :new))

assert html = html_response(conn, 200)
assert html =~ "<label for=\"user_email\">Email</label>"
assert html =~ "<input id=\"user_email\" name=\"user[email]\" type=\"text\">"
assert html =~ "<label class=\"control-label\" for=\"user_email\">Email</label>"
assert html =~ "<input class=\"form-control\" id=\"user_email\" name=\"user[email]\" type=\"text\">"
end

test "already signed in", %{conn: conn} do
Expand Down Expand Up @@ -90,10 +90,10 @@ defmodule PowResetPassword.Phoenix.ResetPasswordControllerTest do
conn = get conn, Routes.pow_reset_password_reset_password_path(conn, :edit, @valid_token)

assert html = html_response(conn, 200)
assert html =~ "<label for=\"user_password\">Password</label>"
assert html =~ "<input id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<label for=\"user_confirm_password\">Confirm password</label>"
assert html =~ "<input id=\"user_confirm_password\" name=\"user[confirm_password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_password\">Password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_confirm_password\">Confirm password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_confirm_password\" name=\"user[confirm_password]\" type=\"password\">"
end
end

Expand Down Expand Up @@ -139,8 +139,8 @@ defmodule PowResetPassword.Phoenix.ResetPasswordControllerTest do
conn = put conn, Routes.pow_reset_password_reset_password_path(conn, :update, @valid_token, @invalid_params)

assert html = html_response(conn, 200)
assert html =~ "<label for=\"user_password\">Password</label>"
assert html =~ "<input id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_password\">Password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<span class=\"help-block\">not same as password</span>"

changeset = conn.assigns[:changeset]
Expand Down
34 changes: 17 additions & 17 deletions test/pow/phoenix/controllers/registration_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ defmodule Pow.Phoenix.RegistrationControllerTest do

assert html = html_response(conn, 200)
assert html =~ Routes.pow_registration_path(conn, :create)
assert html =~ "<label for=\"user_email\">Email</label>"
assert html =~ "<input id=\"user_email\" name=\"user[email]\" type=\"text\">"
assert html =~ "<label for=\"user_password\">Password</label>"
assert html =~ "<input id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<label for=\"user_confirm_password\">Confirm password</label>"
assert html =~ "<input id=\"user_confirm_password\" name=\"user[confirm_password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_email\">Email</label>"
assert html =~ "<input class=\"form-control\" id=\"user_email\" name=\"user[email]\" type=\"text\">"
assert html =~ "<label class=\"control-label\" for=\"user_password\">Password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_confirm_password\">Confirm password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_confirm_password\" name=\"user[confirm_password]\" type=\"password\">"
end

test "already signed in", %{conn: conn} do
Expand Down Expand Up @@ -50,9 +50,9 @@ defmodule Pow.Phoenix.RegistrationControllerTest do
test "with invalid params", %{conn: conn} do
conn = post conn, Routes.pow_registration_path(conn, :create, @invalid_params)
assert html = html_response(conn, 200)
assert html =~ "<input id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<label for=\"user_password\">Password</label>"
assert html =~ "<input id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<input class=\"form-control\" id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<label class=\"control-label\" for=\"user_password\">Password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<span class=\"help-block\">should be at least 10 character(s)</span>"
assert errors = conn.assigns[:changeset].errors
assert errors[:password]
Expand All @@ -69,10 +69,10 @@ defmodule Pow.Phoenix.RegistrationControllerTest do
|> get(Routes.pow_registration_path(conn, :edit))

assert html = html_response(conn, 200)
assert html =~ "<label for=\"user_email\">Email</label>"
assert html =~ "<input id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<label for=\"user_current_password\">Current password</label>"
assert html =~ "<input id=\"user_current_password\" name=\"user[current_password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_email\">Email</label>"
assert html =~ "<input class=\"form-control\" id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<label class=\"control-label\" for=\"user_current_password\">Current password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_current_password\" name=\"user[current_password]\" type=\"password\">"
end

test "not signed in", %{conn: conn} do
Expand Down Expand Up @@ -112,10 +112,10 @@ defmodule Pow.Phoenix.RegistrationControllerTest do
conn = put(conn, Routes.pow_registration_path(conn, :update, @invalid_params))

assert html = html_response(conn, 200)
assert html =~ "<label for=\"user_email\">Email</label>"
assert html =~ "<input id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<label for=\"user_current_password\">Current password</label>"
assert html =~ "<input id=\"user_current_password\" name=\"user[current_password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_email\">Email</label>"
assert html =~ "<input class=\"form-control\" id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<label class=\"control-label\" for=\"user_current_password\">Current password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_current_password\" name=\"user[current_password]\" type=\"password\">"
assert html =~ "<span class=\"help-block\">can&#39;t be blank</span>"
assert errors = conn.assigns[:changeset].errors
assert errors[:current_password]
Expand Down
12 changes: 6 additions & 6 deletions test/pow/phoenix/controllers/session_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ defmodule Pow.Phoenix.SessionControllerTest do
assert html = html_response(conn, 200)
assert html =~ Routes.pow_session_path(conn, :create)
refute html =~ "request_path="
assert html =~ "<label for=\"user_email\">Email</label>"
assert html =~ "<input id=\"user_email\" name=\"user[email]\" type=\"text\">"
assert html =~ "<label for=\"user_password\">Password</label>"
assert html =~ "<input id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<label class=\"control-label\" for=\"user_email\">Email</label>"
assert html =~ "<input class=\"form-control\" id=\"user_email\" name=\"user[email]\" type=\"text\">"
assert html =~ "<label class=\"control-label\" for=\"user_password\">Password</label>"
assert html =~ "<input class=\"form-control\" id=\"user_password\" name=\"user[password]\" type=\"password\">"
end

test "with request_path", %{conn: conn} do
Expand Down Expand Up @@ -57,8 +57,8 @@ defmodule Pow.Phoenix.SessionControllerTest do
conn = post conn, Routes.pow_session_path(conn, :create, @invalid_params)
assert html = html_response(conn, 200)
assert get_flash(conn, :error) == "The provided login details did not work. Please verify your credentials, and try again."
assert html =~ "<input id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<input id=\"user_password\" name=\"user[password]\" type=\"password\">"
assert html =~ "<input class=\"form-control\" id=\"user_email\" name=\"user[email]\" type=\"text\" value=\"[email protected]\">"
assert html =~ "<input class=\"form-control\" id=\"user_password\" name=\"user[password]\" type=\"password\">"
refute Plug.current_user(conn)
refute conn.private[:plug_session]["auth"]
refute html =~ "request_path"
Expand Down
32 changes: 32 additions & 0 deletions test/pow/phoenix/html/form_template_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule Pow.Phoenix.HTML.FormTemplateTest do
use ExUnit.Case
doctest Pow.Phoenix.HTML.FormTemplate

alias Pow.Phoenix.HTML.FormTemplate

test "render/2 with bootstrap" do
inputs = [
{:text, {:changeset, :pow_user_id_field}},
{:password, :password},
{:password, :confirm_password}]
html = FormTemplate.render(inputs, [bootstrap: true])

assert html =~ "<div class=\"form-group\">"
assert html =~ "<%= label f, :password, class: \"control-label\" %>"
assert html =~ "<%= password_input f, :password, class: \"form-control\" %>"
assert html =~ "<%= error_tag f, :password %>"
end

test "render/2 with minimalist" do
inputs = [
{:text, {:changeset, :pow_user_id_field}},
{:password, :password},
{:password, :confirm_password}]
html = FormTemplate.render(inputs, [bootstrap: false])

refute html =~ "<div class=\"form-group\">"
assert html =~ "<%= label f, :password %>"
assert html =~ "<%= password_input f, :password %>"
assert html =~ "<%= error_tag f, :password %>"
end
end

0 comments on commit 2cb16e4

Please sign in to comment.