Module: Decidim::DecidimFormHelper

Included in:
ScopesHelper, TaxonomiesHelper
Defined in:
decidim-core/app/helpers/decidim/decidim_form_helper.rb

Overview

A helper to expose an easy way to add authorization forms in a view.

Instance Method Summary collapse

Instance Method Details

#areas_for_select(organization) ⇒ Object

Handle which collection to pass to Decidim::FilterFormBuilder.areas_select



217
218
219
220
221
222
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 217

def areas_for_select(organization)
  return organization.areas if organization.area_types.blank?
  return organization.areas if organization.area_types.all? { |at| at.area_ids.empty? }

  organization.area_types
end

#base_error_messages(record) ⇒ Object



209
210
211
212
213
214
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 209

def base_error_messages(record)
  return unless record.respond_to?(:errors)
  return unless record.errors[:base].any?

  alert_box(record.errors.full_messages_for(:base).join(","), :alert, false)
end

#decidim_form_for(record, options = {}) ⇒ Object

A custom form for that injects client side validations with Abide.

record - The object to build the form for. options - A Hash of options to pass to the form builder. &block - The block to execute as content of the form.

Returns a String.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 13

def decidim_form_for(record, options = {}, &)
  options[:data] ||= {}
  options[:data].update(:abide => true, "live-validate" => true, "validate-on-blur" => true)

  options[:html] ||= {}
  options[:html].update(novalidate: true) unless options[:html].has_key?(:novalidate)

  # Generally called by form_for but we need the :url option generated
  # already before that.
  #
  # See:
  # https://github.com/rails/rails/blob/master/actionview/lib/action_view/helpers/form_helper.rb#L459
  if record.is_a?(ActiveRecord::Base)
    object = record.is_a?(Array) ? record.last : record
    format = options[:format]
    apply_form_for_options!(object, options) if object
    options[:format] = format if format
  end

  output = ""
  output += base_error_messages(record).to_s
  output += form_for(record, options, &).to_s

  output.html_safe
end

#decidim_form_slug_url(prepend_path = "", value = "") ⇒ Object

Helper method to show how slugs will look like. Intended to be used in forms together with some JavaScript code. More precisely, this will most probably show in help texts in forms. The space slug is surrounded with a ‘span` so the slug can be updated via JavaScript with the input value.

prepend_path - a path to prepend to the slug, without final slash value - the initial value of the slug field, so that edit forms have a value

Returns an HTML-safe String.



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 182

def decidim_form_slug_url(prepend_path = "", value = "")
  prepend_slug_path = if prepend_path.present?
                        "/#{prepend_path}/"
                      else
                        "/"
                      end
  (:span, class: "slug-url") do
    [
      request.protocol,
      request.host_with_port,
      prepend_slug_path
    ].join.html_safe +
      (:span, value, class: "slug-url-value")
  end
end

#editor_field_tag(name, value, options = {}) ⇒ Object

A custom helper to include an editor field without requiring a form object

name - The input name value - The input value options - The set of options to send to the field

:label   - The Boolean value to create or not the input label (optional) (default: true)
:toolbar - The String value to configure WYSIWYG toolbar. It should be 'basic' or
           or 'full' (optional) (default: 'basic')
:lines   - The Integer to indicate how many lines should editor have (optional)

Returns a rich editor to be included in an html template.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 50

def editor_field_tag(name, value, options = {})
  options[:toolbar] ||= "basic"
  options[:lines] ||= 10

  (:div, class: "editor") do
    template = ""
    template += label_tag(name, options[:label]) if options[:label] != false
    template += hidden_field_tag(name, value, options)
    template += (:div, nil, class: "editor-container", data: {
                              toolbar: options[:toolbar]
                            }, style: "height: #{options[:lines]}rem")
    template.html_safe
  end
end

#form_field_has_error?(object, attribute) ⇒ Boolean

Returns:

  • (Boolean)


169
170
171
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 169

def form_field_has_error?(object, attribute)
  object.respond_to?(:errors) && object.errors[attribute].present?
end

#form_required_explanationObject

Helper method to show an explanation for the form’s required fields that are marked with an asterisk character. This improves the accessibility of the forms.

Returns an HTML-safe String.



203
204
205
206
207
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 203

def form_required_explanation
  (:div, class: "help-text") do
    I18n.t("forms.required_explanation")
  end
end

#name_with_locale(name, locale) ⇒ Object

Helper method used by ‘translated_field_tag`



165
166
167
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 165

def name_with_locale(name, locale)
  "#{name}_#{locale.to_s.gsub("-", "__")}"
end

#ordered_scopes_descendants(root = nil) ⇒ Object



224
225
226
227
228
229
230
231
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 224

def ordered_scopes_descendants(root = nil)
  root = try(:current_participatory_space)&.scope if root == false
  if root.present?
    root.descendants
  else
    current_organization.scopes
  end.sort { |a, b| a.part_of.reverse <=> b.part_of.reverse }
end

#ordered_scopes_descendants_for_select(root = nil) ⇒ Object



233
234
235
236
237
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 233

def ordered_scopes_descendants_for_select(root = nil)
  ordered_scopes_descendants(root).map do |scope|
    [" #{"&nbsp;" * 4 * (scope.part_of.count - 1)} #{translated_attribute(scope.name)}".html_safe, scope&.id]
  end
end

#scopes_picker_field_tag(name, value, id: nil) ⇒ Object

A custom helper to include a scope picker field without requiring a form object

name - The input name value - The input value as a scope id options - The set of options to send to the field

:id - The id to generate for the element (optional)

Returns a scopes picker tag to be included in an html template.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 74

def scopes_picker_field_tag(name, value, id: nil)
  picker_options = {
    id: id || sanitize_to_id(name),
    class: "picker-single",
    name:
  }

  prompt_params = yield(nil)
  selected_scopes = value ? Decidim::Scope.where(id: value) : []
  scopes = selected_scopes.map { |scope| [scope, yield(scope)] }

  template = ""
  template += render("decidim/scopes/scopes_picker_input",
                     picker_options:,
                     prompt_params:,
                     scopes:,
                     values_on_top: true)
  template.html_safe
end

#tab_element_class_for(type, index) ⇒ Object

Helper method used by ‘translated_field_tag`



158
159
160
161
162
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 158

def tab_element_class_for(type, index)
  element_class = "tabs-#{type}"
  element_class += " is-active" if index.zero?
  element_class
end

#translated_field_tag(type, object_name, name, value = {}, options = {}) ⇒ Object

A custom helper to include a translated field without requiring a form object.

type - The type of the translated input field. object_name - The object name used to identify the Foundation tabs. name - The name of the input which will be suffixed with the corresponding locales. value - A hash containing the value for each locale. options - An optional hash of options.

* enable_tabs: Adds the data-tabs attribute so Foundation picks up automatically.
* tabs_id: The id to identify the Foundation tabs element.
* label: The label used for the field.

Returns a Foundation tabs element with the translated input field.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'decidim-core/app/helpers/decidim/decidim_form_helper.rb', line 106

def translated_field_tag(type, object_name, name, value = {}, options = {})
  locales = available_locales

  field_label = label_tag(name, options[:label])

  if locales.count == 1
    field_name = "#{name}_#{locales.first.to_s.gsub("-", "__")}"
    field_input = send(
      type,
      "#{object_name}[#{field_name}]",
      value[locales.first.to_s]
    )

    return safe_join [field_label, field_input]
  end

  tabs_id = options[:tabs_id] || "#{object_name}-#{name}-tabs".underscore
  enabled_tabs = options[:enable_tabs].nil? ? true : options[:enable_tabs]
  tabs_panels_data = enabled_tabs ? { tabs: true } : {}

  label_tabs = (:div, class: "label--tabs") do
    tabs_panels = "".html_safe
    if options[:label] != false
      tabs_panels = (:ul, class: "tabs tabs--lang", id: tabs_id, data: tabs_panels_data) do
        locales.each_with_index.inject("".html_safe) do |string, (locale, index)|
          string + (:li, class: tab_element_class_for("title", index)) do
            title = I18n.with_locale(locale) { I18n.t("name", scope: "locale") }
            element_class = nil
            element_class = "is-tab-error" if form_field_has_error?(options[:object], name_with_locale(name, locale))
            tab_content_id = "#{tabs_id}-#{name}-panel-#{index}"
            (:a, title, href: "##{tab_content_id}", class: element_class)
          end
        end
      end
    end

    safe_join [field_label, tabs_panels]
  end

  tabs_content = (:div, class: "tabs-content", data: { tabs_content: tabs_id }) do
    locales.each_with_index.inject("".html_safe) do |string, (locale, index)|
      tab_content_id = "#{tabs_id}-#{name}-panel-#{index}"
      string + (:div, class: tab_element_class_for("panel", index), id: tab_content_id) do
        send(type, "#{object_name}[#{name_with_locale(name, locale)}]", value[locale.to_s], options.merge(id: "#{tabs_id}_#{name}_#{locale}", label: false))
      end
    end
  end

  safe_join [label_tabs, tabs_content]
end