diff --git a/lib/phoenix_html/form.ex b/lib/phoenix_html/form.ex index 53a7eec..2207254 100644 --- a/lib/phoenix_html/form.ex +++ b/lib/phoenix_html/form.ex @@ -60,25 +60,25 @@ defmodule Phoenix.HTML.Form do id: nil, name: nil, data: nil, + action: nil, hidden: [], params: %{}, errors: [], options: [], - index: nil, - action: nil + index: nil @type t :: %Form{ source: Phoenix.HTML.FormData.t(), name: String.t(), data: %{field => term}, + action: nil | String.t() | atom(), params: %{binary => term}, hidden: Keyword.t(), options: Keyword.t(), errors: [{field, term}], impl: module, id: String.t(), - index: nil | non_neg_integer, - action: nil | String.t() + index: nil | non_neg_integer } @type field :: atom | String.t() @@ -189,18 +189,32 @@ defmodule Phoenix.HTML.Form do @doc """ Receives two forms structs and checks if the given field changed. - The field will have changed if either its associated value or errors - changed. This is mostly used for optimization engines as an extension - of the `Access` behaviour. + The field will have changed if either its associated value, errors, + action, or implementation changed. This is mostly used for optimization + engines as an extension of the `Access` behaviour. """ @spec input_changed?(t, t, field()) :: boolean() def input_changed?( - %Form{impl: impl1, id: id1, name: name1, errors: errors1, source: source1} = form1, - %Form{impl: impl2, id: id2, name: name2, errors: errors2, source: source2} = form2, + %Form{ + impl: impl1, + id: id1, + name: name1, + errors: errors1, + source: source1, + action: action1 + } = form1, + %Form{ + impl: impl2, + id: id2, + name: name2, + errors: errors2, + source: source2, + action: action2 + } = form2, field ) when is_atom(field) or is_binary(field) do - impl1 != impl2 or id1 != id2 or name1 != name2 or + impl1 != impl2 or id1 != id2 or name1 != name2 or action1 != action2 or field_errors(errors1, field) != field_errors(errors2, field) or impl1.input_value(source1, form1, field) != impl2.input_value(source2, form2, field) end diff --git a/lib/phoenix_html/form_data.ex b/lib/phoenix_html/form_data.ex index 1444d35..3389d2b 100644 --- a/lib/phoenix_html/form_data.ex +++ b/lib/phoenix_html/form_data.ex @@ -56,6 +56,8 @@ defprotocol Phoenix.HTML.FormData do applies if the field value is a list and no parameters were sent through the form. + * `:action` - The user defined action being taken by the form, such + as `:validate`, `:save`, etc. """ @spec to_form(t, Phoenix.HTML.Form.t(), Phoenix.HTML.Form.field(), Keyword.t()) :: [Phoenix.HTML.Form.t()] @@ -86,6 +88,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do def to_form(conn_or_atom_or_map, opts) do {name, params, opts} = name_params_and_opts(conn_or_atom_or_map, opts) {errors, opts} = Keyword.pop(opts, :errors, []) + {action, opts} = Keyword.pop(opts, :action, nil) id = Keyword.get(opts, :id) || name unless is_binary(id) or is_nil(id) do @@ -100,6 +103,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do params: params, data: %{}, errors: errors, + action: action, options: opts } end @@ -146,6 +150,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do {name, opts} = Keyword.pop(opts, :as) {id, opts} = Keyword.pop(opts, :id) {hidden, opts} = Keyword.pop(opts, :hidden, []) + {action, opts} = Keyword.pop(opts, :action) id = to_string(id || form.id <> "_#{field}") name = to_string(name || form.name <> "[#{field}]") @@ -161,6 +166,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do id: id, name: name, data: default, + action: action, params: params || %{}, hidden: hidden, options: opts @@ -185,6 +191,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do source: conn_or_atom_or_map, impl: __MODULE__, index: index, + action: action, id: id <> "_" <> index_string, name: name <> "[" <> index_string <> "]", data: data, diff --git a/mix.exs b/mix.exs index 5e44310..7a996f9 100644 --- a/mix.exs +++ b/mix.exs @@ -3,7 +3,7 @@ defmodule PhoenixHTML.Mixfile do # Also change package.json version @source_url "https://github.com/phoenixframework/phoenix_html" - @version "3.3.3" + @version "3.3.4" def project do [ diff --git a/mix.lock b/mix.lock index 273e659..05cd081 100644 --- a/mix.lock +++ b/mix.lock @@ -1,11 +1,11 @@ %{ - "earmark_parser": {:hex, :earmark_parser, "1.4.37", "2ad73550e27c8946648b06905a57e4d454e4d7229c2dafa72a0348c99d8be5f7", [:mix], [], "hexpm", "6b19783f2802f039806f375610faa22da130b8edc21209d0bff47918bb48360e"}, - "ex_doc": {:hex, :ex_doc, "0.30.6", "5f8b54854b240a2b55c9734c4b1d0dd7bdd41f71a095d42a70445c03cf05a281", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bd48f2ddacf4e482c727f9293d9498e0881597eae6ddc3d9562bd7923375109f"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, + "ex_doc": {:hex, :ex_doc, "0.34.0", "ab95e0775db3df71d30cf8d78728dd9261c355c81382bcd4cefdc74610bef13e", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "60734fb4c1353f270c3286df4a0d51e65a2c1d9fba66af3940847cc65a8066d7"}, + "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "plug": {:hex, :plug, "1.11.0", "f17217525597628298998bc3baed9f8ea1fa3f1160aa9871aee6df47a6e4d38e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2d9c633f0499f9dc5c2fd069161af4e2e7756890b81adcbb2ceaa074e8308876"}, "plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"}, "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, diff --git a/package.json b/package.json index 03bf9bd..8c20dc9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "phoenix_html", - "version": "3.3.3", + "version": "3.3.4", "main": "./priv/static/phoenix_html.js", "repository": {}, "files": [ diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs index da2e9df..5834573 100644 --- a/test/phoenix_html/form_test.exs +++ b/test/phoenix_html/form_test.exs @@ -103,9 +103,9 @@ defmodule Phoenix.HTML.FormTest do {:safe, ["2017-09-21", ?T, "20:21"]} assert normalize_value("datetime-local", "2017-09-21 20:21:53") == - {:safe, "2017-09-21 20:21:53"} + "2017-09-21 20:21:53" - assert normalize_value("datetime-local", "other") == {:safe, "other"} + assert normalize_value("datetime-local", "other") == "other" end test "for textarea" do @@ -138,6 +138,12 @@ defmodule Phoenix.HTML.FormTest do assert input_changed?(form, form(%{"foo" => "bar"}), "foo") end + test "input_changed? with changed action or method" do + form = form(%{}, action: :validate) + refute input_changed?(form, %{form | action: :validate}, :foo) + assert input_changed?(form, %{form | action: :save}, :foo) + end + describe "access" do test "without name and atom keys" do form =