defmodule Formex.Template do alias Formex.Form alias Formex.Field @moduledoc """ Use this module to create a custom form template. Usage: ``` defmodule App.FormTemplate.SemanticUI do use Formex.Template def generate_row(form, field, _options \\\\ []) do # code that produces a Phoenix.HTML.safe # you can use here render_phoenix_input/2, translate_error/2, has_error/2 end end ``` If you want to create a several version of template (for example vertical and horizontal, as is already done with Bootstrap), you can move a common code to another module. Example: ``` defmodule App.FormTemplate.SemanticUIVertical do use Formex.Template, :main # note the :main argument import App.FormTemplate.SemanticUI def generate_row(form, field, _options \\\\ []) do # code that produces a Phoenix.HTML.safe end end ``` ``` defmodule App.FormTemplate.SemanticUIHorizontal do use Formex.Template, :main # note the :main argument import App.FormTemplate.SemanticUI def generate_row(form, field, _options \\\\ []) do # code that produces a Phoenix.HTML.safe end end ``` ``` defmodule App.FormTemplate.SemanticUI do use Formex.Template, :helper # note the :helper argument # a common code for both versions # you can use here render_phoenix_input/2, translate_error/2, has_error/2 end ``` Check the source code of [templates](https://github.com/jakub-zawislak/formex/tree/master/lib/templates) for more examples. """ @doc false def main do quote do use Phoenix.HTML alias Formex.Form alias Formex.Field alias Formex.Button @behaviour Formex.Template end end @doc false def helper do quote do use Phoenix.HTML alias Formex.Form alias Formex.Field alias Formex.Button import Formex.Template end end @doc """ Generates a HTML for a field. ## Arguments * `options` - any options that you want to use inside a form template. It can be set by `:template_options` inside a `Formex.View` functions, or in the `:formex` config. For example, `Formex.Template.BootstrapHorizontal` uses options that stores columns sizes. """ @callback generate_row(form :: Form.t, field :: Formex.Field.t, options :: Keyword.t) :: Phoenix.HTML.safe @callback generate_input(form :: Form.t, field_or_button :: any) :: Phoenix.HTML.safe @callback generate_label(form :: Form.t, field :: Field.t, class :: String.t) :: Phoenix.HTML.safe defmacro __using__(which) when is_atom(which) do apply(__MODULE__, which, []) end defmacro __using__(_) do main() helper() end # @doc """ Runs function from `Phoenix.HTML.Form` defined in a `Field.type` or `Button.type` """ @spec render_phoenix_input(item :: any, args :: Keyword.t) :: any def render_phoenix_input(item, args) do apply(Phoenix.HTML.Form, item.type, args) end @doc """ Translates error using function set in `:formex` config """ @spec translate_error(Form.t, Field.t) :: any def translate_error(form, field) do Application.get_env(:formex, :translate_error).(form.phoenix_form.errors[field.name]) end @doc """ Checks if given field has a changeset error """ @spec has_error(Form.t, Field.t) :: any def has_error(form, field) do form.phoenix_form.errors[field.name] end @doc """ Adds a CSS class to a `:phoenix_opts` keyword """ @spec add_class(phoenix_opts :: Keyword.t, class :: String.t) :: Keyword.t def add_class(phoenix_opts, class) do Keyword.merge(phoenix_opts, [class: class<>" "<>phoenix_opts[:class]]) end end