diff --git a/config/config.exs b/config/config.exs index 3c42a33..fbaa96d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -3,3 +3,9 @@ import Config config :logger, :console, colors: [enabled: false] config :phoenix_template, :json_library, Jason config :phoenix_template, :trim_on_html_eex_engine, true + +config :phoenix_template, :format_encoders, + markup: Phoenix.TemplateTest.MarkupEncoder, + custom: Phoenix.TemplateTest.CustomEncoder + +config :phoenix_template, :html_formats, [:markup] diff --git a/lib/phoenix/template.ex b/lib/phoenix/template.ex index a452d86..b7ccceb 100644 --- a/lib/phoenix/template.ex +++ b/lib/phoenix/template.ex @@ -40,6 +40,32 @@ defmodule Phoenix.Template do config :phoenix_template, :format_encoders, html: Phoenix.HTML.Engine + ### HTML formats + + `.html.eex` templates are compiled and encoded with `Phoenix.HTML.Engine`, + which provides HTML safety. Other formats are compiled with `EEx.SmartEngine`, + which interpolates values as is. + + A format that renders HTML-like markup but needs its own encoder, for + example one that post-processes the rendered markup, can be compiled + with `Phoenix.HTML.Engine` too by listing it in the `:html_formats` option: + + config :phoenix_template, :format_encoders, mjml: MyApp.MJML + config :phoenix_template, :html_formats, [:html, :mjml] + + Its templates are then compiled exactly like `.html.eex` ones. Interpolated + values are escaped unless they are marked as safe, such as with + `Phoenix.HTML.raw/1`, the `:trim_on_html_eex_engine` option applies, and + the format encoder receives the `{:safe, iodata}` tuple that they return: + + defmodule MyApp.MJML do + def encode_to_iodata!({:safe, mjml}), do: MyApp.MJML.to_html(mjml) + end + + In case the `{:safe, ...}` tuple is not received, you should raise, as it means + the user likely has not configured the `html_formats` accordingly. + + This requires `phoenix_html` as a dependency. """ @type path :: binary diff --git a/lib/phoenix/template/eex_engine.ex b/lib/phoenix/template/eex_engine.ex index 442023d..9eae2eb 100644 --- a/lib/phoenix/template/eex_engine.ex +++ b/lib/phoenix/template/eex_engine.ex @@ -20,37 +20,46 @@ defmodule Phoenix.Template.EExEngine do "template paths in Phoenix require the format extension, got: #{path}" end - case Phoenix.Template.format_encoder(format) do - Phoenix.HTML.Engine -> - unless Code.ensure_loaded?(Phoenix.HTML.Engine) do - raise "could not load Phoenix.HTML.Engine to use with .html.eex templates. " <> - "You can configure your own format encoder for HTML but we recommend " <> - "adding phoenix_html as a dependency as it provides XSS protection." - end - - trim = - case Application.get_env(:phoenix_template, :trim_on_html_eex_engine) do - nil -> - case Application.get_env(:phoenix_view, :trim_on_html_eex_engine) do - nil -> - Application.get_env(:phoenix, :trim_on_html_eex_engine, true) + if html_format?(format) do + if not Code.ensure_loaded?(Phoenix.HTML.Engine) do + raise "could not load Phoenix.HTML.Engine to use with .#{format}.eex templates. " <> + "You can configure your own format encoder for HTML but we recommend " <> + "adding phoenix_html as a dependency as it provides XSS protection." + end - boolean -> - IO.warn( - "config :phoenix_view, :trim_on_html_eex_engine is deprecated, please use config :phoenix_template, :trim_on_html_eex_engine instead" - ) + trim = + case Application.get_env(:phoenix_template, :trim_on_html_eex_engine) do + nil -> + case Application.get_env(:phoenix_view, :trim_on_html_eex_engine) do + nil -> + Application.get_env(:phoenix, :trim_on_html_eex_engine, true) - boolean - end + boolean -> + IO.warn( + "config :phoenix_view, :trim_on_html_eex_engine is deprecated, please use config :phoenix_template, :trim_on_html_eex_engine instead" + ) - boolean -> - boolean - end + boolean + end - [engine: Phoenix.HTML.Engine, trim: trim] + boolean -> + boolean + end - _ -> - [engine: EEx.SmartEngine] + [engine: Phoenix.HTML.Engine, trim: trim] + else + [engine: EEx.SmartEngine] end end + + defp html_format?(format) do + Phoenix.Template.format_encoder(format) == Phoenix.HTML.Engine or + format in html_formats() + end + + defp html_formats do + :phoenix_template + |> Application.get_env(:html_formats, []) + |> Enum.map(&to_string/1) + end end diff --git a/test/fixtures/templates/show.custom.eex b/test/fixtures/templates/show.custom.eex new file mode 100644 index 0000000..dfc0b3a --- /dev/null +++ b/test/fixtures/templates/show.custom.eex @@ -0,0 +1 @@ +