defmodule Formex.View do use Phoenix.HTML @spec formex_for(Formex.Form.t, String.t, Keyword.t (t::any -> Phoenix.HTML.unsafe)) :: Phoenix.HTML.safe def formex_for(form, action, options \\ [], fun) do Phoenix.HTML.Form.form_for(form.changeset, action, options, fn f -> form |> Map.put(:phoenix_form, f) |> fun.() end) end def generate_fields(form) do Enum.map(form.fields, fn field -> form_row(form, field.name) end) end def generate_fields_horizontal(form) do Enum.map(form.fields, fn field -> form_row_horizontal(form, field.name) end) end # @spec form_row(Formex.Form.t, Atom.t) :: Phoenix.HTML.safe def form_row(form, field_name) do field = get_field(form, field_name) field_html = generate_field_html(form, field) label_html = generate_label_html(form, field) field_html = attach_addon(field_html, field) tags = [label_html, field_html] |> attach_error(form, field) wrapper_class = ["form-group"] |> attach_error_class(form, field) |> attach_required_class(field) content_tag(:div, tags, class: Enum.join(wrapper_class, " ")) end @spec form_row_horizontal(Formex.Form.t, Atom.t) :: Phoenix.HTML.safe def form_row_horizontal(form, field_name) do field = get_field(form, field_name) field_html = generate_field_html(form, field) label_html = generate_label_html(form, field, "col-sm-2") field_html = attach_addon(field_html, field) tags = [field_html] |> attach_error(form, field) wrapper_class = ["form-group"] |> attach_error_class(form, field) |> attach_required_class(field) column = content_tag(:div, tags, class: "col-sm-10") content_tag(:div, [label_html, column], class: Enum.join(wrapper_class, " ")) end # @spec get_field(Formex.Form.t, Atom.t) :: Formex.Field.t defp get_field(form, field_name) do Enum.find(form.fields, fn field -> field.name == field_name end) end @spec generate_field_html(Formex.Form.t, Formex.Field.t) :: any defp generate_field_html(form, field) do type = field.type opts = field.opts data = field.data phoenix_opts = if opts[:phoenix_opts], do: opts[:phoenix_opts], else: [] class = if opts[:class], do: opts[:class], else: "" args = [form.phoenix_form, field.name] args = args ++ cond do Enum.member? [:select, :multiple_select], type -> [data[:options], Keyword.merge([class: class<>" form-control"], phoenix_opts) ] Enum.member? [:checkbox], type -> [Keyword.merge([class: class], phoenix_opts) ] Enum.member? [:file_input], type -> [Keyword.merge([class: class], phoenix_opts) ] true -> [Keyword.merge([class: class<>" form-control"], phoenix_opts) ] end input = apply(Phoenix.HTML.Form, type, args) cond do Enum.member? [:checkbox], type -> content_tag(:div, [ content_tag(:label, [ input ]) ], class: "checkbox") true -> input end end @spec generate_label_html(Formex.Form.t, Formex.Field.t, String.t) :: Phoenix.HTML.safe defp generate_label_html(form, field, class \\ "") do Phoenix.HTML.Form.label( form.phoenix_form, field.name, field.label, class: "control-label "<>class ) end defp generate_error_field(form, field) do text = Application.get_env(:formex, :translate_error).(form.phoenix_form.errors[field.name]) content_tag(:span, text, class: "help-block") end # defp attach_addon(field_html, field) do if field.opts[:addon] do addon = content_tag(:div, field.opts[:addon], class: "input-group-addon") content_tag(:div, [field_html, addon], class: "input-group" ) else field_html end end defp attach_error(tags, form, field) do if form.phoenix_form.errors[field.name] do tags ++ [generate_error_field(form, field)] else tags end end defp attach_error_class(wrapper_class, form, field) do if form.phoenix_form.errors[field.name] do wrapper_class ++ ["has-error"] else wrapper_class end end defp attach_required_class(wrapper_class, field) do if field.required do wrapper_class ++ ["required"] else wrapper_class end end end