Class: Decidim::FormBuilder

Inherits:
FoundationRailsHelper::FormBuilder
  • Object
show all
Includes:
ActionView::Context
Defined in:
lib/decidim/form_builder.rb

Overview

This custom FormBuilder adds fields needed to deal with translatable fields, following the conventions set on ‘Decidim::TranslatableAttributes`.

Direct Known Subclasses

AuthorizationFormBuilder, FilterFormBuilder

Instance Method Summary collapse

Instance Method Details

#categories_select(name, collection, options = {}) ⇒ Object

Public: Generates a select field with the categories. Only leaf categories can be set as selected.

name - The name of the field (usually category_id) collection - A collection of categories. options - An optional Hash with options:

  • prompt - An optional String with the text to display as prompt.

  • disable_parents - A Boolean to disable parent categories. Defaults to ‘true`.

Returns a String.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/decidim/form_builder.rb', line 115

def categories_select(name, collection, options = {})
  options = {
    disable_parents: true
  }.merge(options)

  disable_parents = options[:disable_parents]

  selected = object.send(name)
  categories = categories_for_select(collection)
  disabled = if disable_parents
               disabled_categories_for(collection)
             else
               []
             end
  html_options = {}

  select(name, @template.options_for_select(categories, selected: selected, disabled: disabled), options, html_options)
end

#check_box(attribute, options = {}, checked_value = "1", unchecked_value = "0") ⇒ Object

Public: Override so checkboxes are rendered before the label.



160
161
162
163
164
165
166
# File 'lib/decidim/form_builder.rb', line 160

def check_box(attribute, options = {}, checked_value = "1", unchecked_value = "0")
  custom_label(attribute, options[:label], options[:label_options], true, false) do
    options.delete(:label)
    options.delete(:label_options)
    @template.check_box(@object_name, attribute, objectify_options(options), checked_value, unchecked_value)
  end + error_and_help_text(attribute, options)
end

#collection_check_boxes(attribute, collection, value_attribute, text_attribute, options = {}, html_options = {}) ⇒ Object

Public: generates a check boxes input from a collection and adds help text and errors.

attribute - the name of the field collection - the collection from which we will render the check boxes value_attribute - a Symbol or a Proc defining how to find the value

attribute

text_attribute - a Symbol or a Proc defining how to find the text

attribute

options - a Hash with options html_options - a Hash with options

Renders a collection of check boxes. rubocop:disable Metrics/ParameterLists



25
26
27
# File 'lib/decidim/form_builder.rb', line 25

def collection_check_boxes(attribute, collection, value_attribute, text_attribute, options = {}, html_options = {})
  super + error_and_help_text(attribute, options)
end

#date_field(attribute, options = {}) ⇒ Object

Public: Override so the date fields are rendered using foundation datepicker library



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/decidim/form_builder.rb', line 170

def date_field(attribute, options = {})
  value = object.send(attribute)
  data = { datepicker: "" }
  data[:startdate] = I18n.localize(value, format: :datepicker) if value.present?
  iso_value = value.present? ? value.strftime("%Y-%m-%d") : ""

  template = ""
  template += label(attribute, label_for(attribute) + required_for_attribute(attribute))
  template += @template.text_field(
    @object_name,
    attribute,
    options.merge(name: nil,
                  id: "date_field_#{@object_name}_#{attribute}",
                  data: data)
  )
  template += @template.hidden_field(@object_name, attribute, value: iso_value)
  template += error_and_help_text(attribute, options)
  template.html_safe
end

#datetime_field(attribute, options = {}) ⇒ Object

Public: Generates a timepicker field using foundation datepicker library



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/decidim/form_builder.rb', line 192

def datetime_field(attribute, options = {})
  value = object.send(attribute)
  if value.present?
    iso_value = value.strftime("%Y-%m-%dT%H:%M:%S")
    formatted_value = I18n.localize(value, format: :timepicker)
  end
  template = ""
  template += label(attribute, label_for(attribute) + required_for_attribute(attribute))
  template += @template.text_field(
    @object_name,
    attribute,
    options.merge(value: formatted_value,
                  name: nil,
                  id: "datetime_field_#{@object_name}_#{attribute}",
                  data: { datepicker: "", timepicker: "" })
  )
  template += @template.hidden_field(@object_name, attribute, value: iso_value)
  template += error_and_help_text(attribute, options)
  template.html_safe
end

#editor(name, options = {}) ⇒ Object

Public: generates a hidden field and a container for WYSIWYG editor

name - The name of the field 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) (default: 10)

Renders a container with both hidden field and editor container



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/decidim/form_builder.rb', line 90

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

  (:div, class: "editor") do
    template = ""
    template += label(name, options[:label].to_s || name) if options[:label] != false
    template += hidden_field(name, options)
    template += (:div, nil, class: "editor-container", data: {
                              toolbar: options[:toolbar]
                            }, style: "height: #{options[:lines]}rem")
    template += error_for(name, options) if error?(name)
    template.html_safe
  end
end

#scopes_select(name, options = {}) ⇒ Object

Public: Generates a select field with the scopes.

name - The name of the field (usually scope_id) collection - A collection of scopes. options - An optional Hash with options:

  • prompt - An optional String with the text to display as prompt.

Returns a String.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/decidim/form_builder.rb', line 142

def scopes_select(name, options = {})
  selected = object.send(name)
  if selected.present?
    selected = selected.values if selected.is_a?(Hash)
    selected = [selected] unless selected.is_a?(Array)
    scopes = Decidim::Scope.where(id: selected.map(&:to_i)).map { |scope| [scope.name[I18n.locale.to_s], scope.id] }
  else
    scopes = []
  end
  prompt = options.delete(:prompt)
  remote_path = options.delete(:remote_path) || false
  multiple = options.delete(:multiple) || false
  html_options = { multiple: multiple, class: "select2", "data-remote-path" => remote_path, "data-placeholder" => prompt }

  select(name, @template.options_for_select(scopes, selected: selected), options, html_options)
end

#translated(type, name, options = {}) ⇒ Object

Public: Generates an form field for each locale.

type - The form field’s type, like ‘text_area` or `text_input` name - The name of the field options - The set of options to send to the field

Renders form fields for each locale.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/decidim/form_builder.rb', line 36

def translated(type, name, options = {})
  if locales.count == 1
    return send(
      type,
      "#{name}_#{locales.first.to_s.gsub("-", "__")}",
      options.merge(label: options[:label] || label_for(name))
    )
  end

  tabs_id = options[:tabs_id] || "#{object_name}-#{name}-tabs"

  label_tabs = (:div, class: "label--tabs") do
    field_label = label_i18n(name, options[:label] || label_for(name))

    tabs_panels = "".html_safe
    if options[:label] != false
      tabs_panels = (:ul, class: "tabs tabs--lang", id: tabs_id, data: { tabs: true }) 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 error?(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, name_with_locale(name, locale), options.merge(label: false))
      end
    end
  end

  safe_join [label_tabs, tabs_content]
end

#upload(attribute, options = {}) ⇒ Object

Public: Generates a file upload field and sets the form as multipart. If the file is an image it displays the default image if present or the current one. By default it also generates a checkbox to delete the file. This checkbox can be hidden if ‘options` is passed as `false`.

attribute - The String name of the attribute to buidl the field. options - A Hash with options to build the field.

* optional: Whether the file can be optional or not.


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/decidim/form_builder.rb', line 221

def upload(attribute, options = {})
  self.multipart = true
  options[:optional] = options[:optional].nil? ? true : options[:optional]

  file = object.send attribute
  template = ""
  template += label(attribute, label_for(attribute) + required_for_attribute(attribute))
  template += @template.file_field @object_name, attribute

  if file_is_image?(file)
    template += if file.present?
                  @template. :label, I18n.t("current_image", scope: "decidim.forms")
                else
                  @template. :label, I18n.t("default_image", scope: "decidim.forms")
                end
    template += @template.link_to @template.image_tag(file.url), file.url, target: "_blank"
  elsif file_is_present?(file)
    template += @template.label_tag I18n.t("current_file", scope: "decidim.forms")
    template += @template.link_to file.file.filename, file.url, target: "_blank"
  end

  if file_is_present?(file)
    if options[:optional]
      template +=  :div, class: "field" do
        safe_join([
                    @template.check_box(@object_name, "remove_#{attribute}"),
                    label("remove_#{attribute}", I18n.t("remove_this_file", scope: "decidim.forms"))
                  ])
      end
    end
  end

  if object.errors[attribute].any?
    template +=  :p, class: "is-invalid-label" do
      safe_join object.errors[attribute], "<br/>"
    end
  end

  template.html_safe
end