diff --git a/lib/phoenix_html/form_data.ex b/lib/phoenix_html/form_data.ex
index 7ceef549..9a277dc4 100644
--- a/lib/phoenix_html/form_data.ex
+++ b/lib/phoenix_html/form_data.ex
@@ -149,12 +149,11 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom] do
def input_value(_conn_or_atom, %{data: data, params: params}, field)
when is_atom(field) or is_binary(field) do
- case Map.fetch(params, field_to_string(field)) do
- {:ok, value} ->
- value
+ key = field_to_string(field)
- :error ->
- Map.get(data, field)
+ case params do
+ %{^key => value} -> value
+ %{} -> Map.get(data, field)
end
end
diff --git a/lib/phoenix_html/link.ex b/lib/phoenix_html/link.ex
index 90f9cf5e..a39392c5 100644
--- a/lib/phoenix_html/link.ex
+++ b/lib/phoenix_html/link.ex
@@ -65,28 +65,28 @@ defmodule Phoenix.HTML.Link do
### Overriding the default confirm behaviour
- `phoenix_html.js` does trigger a custom event `phoenix.link.click` on the
+ `phoenix_html.js` does trigger a custom event `phoenix.link.click` on the
clicked DOM element when a click happened. This allows you to intercept the
- event on it's way bubbling up to `window` and do your own custom logic to
+ event on it's way bubbling up to `window` and do your own custom logic to
enhance or replace how the `data-confirm` attribute is handled.
- You could for example replace the browsers `confirm()` behavior with a
+ You could for example replace the browsers `confirm()` behavior with a
custom javascript implementation:
```javascript
- // listen on document.body, so it's executed before the default of
+ // listen on document.body, so it's executed before the default of
// phoenix_html, which is listening on the window object
document.body.addEventListener('phoenix.link.click', function (e) {
// Prevent default implementation
e.stopPropagation();
-
+
// Introduce alternative implementation
var message = e.target.getAttribute("data-confirm");
if(!message){ return true; }
vex.dialog.confirm({
message: message,
callback: function (value) {
- if (value == false) { e.preventDefault(); }
+ if (value == false) { e.preventDefault(); }
}
})
}, false);
@@ -105,7 +105,7 @@ defmodule Phoenix.HTML.Link do
}, false);
```
- The latter could also be bound to any `click` event, but this way you can be
+ The latter could also be bound to any `click` event, but this way you can be
sure your custom code is only executed when the code of `phoenix_html.js` is run.
## CSRF Protection
@@ -231,18 +231,13 @@ defmodule Phoenix.HTML.Link do
{[csrf: csrf], opts}
{true, opts} ->
- {[csrf: csrf_token(to)], opts}
+ {[csrf: Phoenix.HTML.Tag.csrf_token_value(to)], opts}
{false, opts} ->
{[], opts}
end
end
- defp csrf_token(to) do
- {mod, fun, args} = Application.fetch_env!(:phoenix_html, :csrf_token_reader)
- apply(mod, fun, [to | args])
- end
-
defp pop_required_option!(opts, key, error_message) do
{value, opts} = Keyword.pop(opts, key)
diff --git a/lib/phoenix_html/tag.ex b/lib/phoenix_html/tag.ex
index 447538b1..7d4ab241 100644
--- a/lib/phoenix_html/tag.ex
+++ b/lib/phoenix_html/tag.ex
@@ -282,7 +282,7 @@ defmodule Phoenix.HTML.Tag do
{extra <> ~s'', opts}
{true, opts} ->
- csrf_token = csrf_token(to)
+ csrf_token = csrf_token_value(to)
{extra <> ~s'', opts}
{false, opts} ->
@@ -290,7 +290,12 @@ defmodule Phoenix.HTML.Tag do
end
end
- defp csrf_token(to) do
+ @doc """
+ Returns the csrf_token value to be used by forms, meta tags, etc.
+
+ By default, CSRF tokens are generated through `Plug.CSRFProtection`.
+ """
+ def csrf_token_value(to) do
{mod, fun, args} = Application.fetch_env!(:phoenix_html, :csrf_token_reader)
apply(mod, fun, [to | args])
end
@@ -310,7 +315,7 @@ defmodule Phoenix.HTML.Tag do
:meta,
charset: "UTF-8",
name: "csrf-token",
- content: csrf_token(%URI{host: nil}),
+ content: csrf_token_value(%URI{host: nil}),
"csrf-param": @csrf_param,
"method-param": @method_param
)
diff --git a/test/phoenix_html/tag_test.exs b/test/phoenix_html/tag_test.exs
index bdbd624f..3537c01e 100644
--- a/test/phoenix_html/tag_test.exs
+++ b/test/phoenix_html/tag_test.exs
@@ -223,4 +223,25 @@ defmodule Phoenix.HTML.TagTest do
assert safe_to_string(csrf_meta_tag()) ==
~s()
end
+
+ describe "csrf_token_value" do
+ def custom_csrf(to, extra), do: "#{extra}:#{to}"
+
+ test "with default" do
+ assert csrf_token_value("/") == Plug.CSRFProtection.get_csrf_token()
+ end
+
+ @default_reader Application.fetch_env!(:phoenix_html, :csrf_token_reader)
+ test "with configured MFA" do
+ Application.put_env(
+ :phoenix_html,
+ :csrf_token_reader,
+ {__MODULE__, :custom_csrf, ["extra"]}
+ )
+
+ assert csrf_token_value("/foo") == "extra:/foo"
+ after
+ Application.put_env(:phoenix_html, :csrf_token_reader, @default_reader)
+ end
+ end
end