Class: BootstrapFormBuilder::HorizontalFormBuilder

Inherits:
ActionView::Helpers::FormBuilder
  • Object
show all
Defined in:
lib/bootstrap_form_builder/horizontal_form_builder.rb

Overview

A form build that adheres to Bootstrap horizontal form conventions.

Instance Method Summary collapse

Instance Method Details

#cancel_button(cancel_path) ⇒ Object



196
197
198
199
200
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 196

def cancel_button(cancel_path)
  @template.link_to(I18n.t('helpers.button.cancel'),
                    cancel_path,
                    :class => 'btn btn-default')
end

#check_box(name, opts = {}) ⇒ Object



57
58
59
60
61
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 57

def check_box(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    simple_check_box(name, opts)
  end
end

#col_wrap(html) ⇒ Object



153
154
155
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 153

def col_wrap(html)
  @template.(:div, html, :class => 'field')
end

#date_field(name, opts = {}) ⇒ Object



41
42
43
44
45
46
47
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 41

def date_field(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    super(name, opts.reverse_merge(:class => 'form-control',
                                   :placeholder => help(name)).
                     reverse_merge(validation_attributes(name)))
  end
end

#email_field(name, opts = {}) ⇒ Object



4
5
6
7
8
9
10
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 4

def email_field(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    super(name, opts.reverse_merge(:class => 'form-control',
                                   :placeholder => help(name)).
                     reverse_merge(validation_attributes(name)))
  end
end

#errors(name) ⇒ Object



163
164
165
166
167
168
169
170
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 163

def errors(name)
  if @object.errors.has_key?(name)
    errors = @object.errors.full_messages_for(name).join('. ')
    @template.(:span, errors, :class => 'help-text text-danger')
  else
    ''
  end
end

#form_group(name, options = {}, &block) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 138

def form_group(name, options = {}, &block)
  group_options = options.fetch(:group_options, {})
  classes = Array(group_options[:class]) << 'form-group'

  if @object.errors.has_key?(name)
    classes << 'has-error'
  end

  @template.(:div,
                        label(name, options.fetch(:label_options, {})) +
                        col_wrap(block.call + errors(name)) +
                        tip(name, options.fetch(:tip_options, {})),
                        group_options.merge(:class => classes.join(' ')))
end

#help(name) ⇒ Object



172
173
174
175
176
177
178
179
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 172

def help(name)
  i18n_name = "helpers.hints.#{object_name}.#{name}"
  if I18n.exists?(i18n_name)
    I18n.t(i18n_name)
  else
    nil
  end
end

#justified_radio_button_group(name, button_options, opts = {}) ⇒ Object

uses bootstrap option to stretch the buttons to the full enclosing width if you use this, you may need to add the following style to your stylesheet to re-hide the radio-button circle (because Bootstrap’s one is too specific to deal with this):

data-toggle=“buttons”

.btn input

position: absolute;
z-index: -1;
opacity: 0;
filter: alpha(opacity=0);



87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 87

def justified_radio_button_group(name, button_options, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    buttons = button_options.map do |button|
      @template.(:div, radio_button_label(name, button), :class => 'btn-group')
    end.join("\n").html_safe

    @template.(:div,
                          buttons,
                          :class => 'btn-group btn-group-justified',
                          :data => { :toggle => 'buttons' })
  end
end

#label(name, opts = {}) ⇒ Object



157
158
159
160
161
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 157

def label(name, opts = {})
  classes = Array(opts.fetch(:class, nil))
  classes << 'control-label' if classes.empty?
  super(name, opts.merge(:class => classes.join(' ')))
end

#label_description(name) ⇒ Object



181
182
183
184
185
186
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 181

def label_description(name)
  # use description if provided, default to the label-text
  desc = I18n.t("helpers.label.#{object_name}.#{name}_description", :default => "")
  return desc if desc.present?
  I18n.t("helpers.label.#{object_name}.#{name}", :default => "")
end

#number_field(name, opts = {}) ⇒ Object



49
50
51
52
53
54
55
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 49

def number_field(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    super(name, opts.reverse_merge(:class => 'form-control',
                                   :placeholder => help(name)).
                     reverse_merge(validation_attributes(name)))
  end
end

#password_field(name, opts = {}) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 33

def password_field(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    super(name, opts.reverse_merge(:class => 'form-control',
                                   :placeholder => help(name)).
                     reverse_merge(validation_attributes(name)))
  end
end

#radio_button_group(name, button_options, opts = {}) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 100

def radio_button_group(name, button_options, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    buttons = button_options.map do |button|
      radio_button_label(name, button)
    end.join("\n").html_safe

    @template.(:div,
                          buttons,
                          :class => 'btn-group',
                          :data => { :toggle => 'buttons' }.
                            merge(validation_attributes(name)))
  end
end

#radio_button_label(name, button) ⇒ Object



114
115
116
117
118
119
120
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 114

def radio_button_label(name, button)
  label(name, :value => button, :class => 'btn btn-default') do
    radio_button(name, button) +
      I18n.t("#{object_name}.#{name}_options.#{button}",
             :scope => "helpers.label")
  end
end

#search_field(name, opts = {}) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 20

def search_field(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    @template.(:div,
                super(name, opts.reverse_merge(:class => 'form-control',
                                               :placeholder => help(name)).
                                 reverse_merge(validation_attributes(name))) +
                @template.(:span,
                                      @template.(:span, '', :class => 'glyphicon glyphicon-search'),
                                      :class => 'input-group-addon'),
                :class => 'input-group')
  end
end

#select(name, choices, options = {}, html_options = {}) ⇒ Object



122
123
124
125
126
127
128
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 122

def select(name, choices, options = {}, html_options = {})
  form_group(name, options.slice(:label_options, :group_options, :tip_options)) do
    super(name, choices, options,
          html_options.reverse_merge(:class => 'form-control').
                       reverse_merge(validation_attributes(name)))
  end
end

#simple_check_box(name, options = {}, checked_value = '1', unchecked_value = '0') ⇒ Object

A checkbox without the form group and control label



64
65
66
67
68
69
70
71
72
73
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 64

def simple_check_box(name, options = {}, checked_value = '1', unchecked_value = '0')
  @template.(:div,
                        @template.(:label,
                                              @template.check_box(@object_name, name,
                                                                  objectify_options(options),
                                                                  checked_value,
                                                                  unchecked_value) +
                                                                  label_description(name).html_safe),
                        :class => 'checkbox', :data => validation_attributes(name))
end

#submit_and_cancel(cancel_path) ⇒ Object



211
212
213
214
215
216
217
218
219
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 211

def submit_and_cancel(cancel_path)
  @template.(:div,
                        @template.
                          (:div,
                                      submit(:class => 'btn btn-primary') +
                                      " " + cancel_button(cancel_path),
                                      :class => 'button-group'),
                        :class => 'form-group')
end

#submit_button(label = "", opts = {}) ⇒ Object



202
203
204
205
206
207
208
209
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 202

def submit_button(label = "", opts = {})
  @template.(:div,
                        @template.
                          (:div,
                                      submit(label, opts.merge(:class => 'btn btn-primary')),
                                      :class => 'button-group'),
                        :class => 'form-group')
end

#text_area(name, opts = {}) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 130

def text_area(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    super(name, opts.reverse_merge(:class => 'form-control',
                                   :placeholder => help(name)).
                     reverse_merge(validation_attributes(name)))
  end
end

#text_field(name, opts = {}) ⇒ Object



12
13
14
15
16
17
18
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 12

def text_field(name, opts = {})
  form_group(name, opts.slice(:label_options, :group_options, :tip_options)) do
    super(name, opts.reverse_merge(:class => 'form-control',
                                   :placeholder => help(name)).
                     reverse_merge(validation_attributes(name)))
  end
end

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



188
189
190
191
192
193
194
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 188

def tip(name, options = {})
  i18n_name = "helpers.tips.#{object_name}.#{name}"
  if I18n.exists?(i18n_name)
    options[:class] = (Array(options[:class]) + ['help-block']).join(' ')
    @template.(:span, I18n.t(i18n_name), options)
  end
end

#validation_attributes(name) ⇒ Object



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
# File 'lib/bootstrap_form_builder/horizontal_form_builder.rb', line 221

def validation_attributes(name)
  return {} unless options[:validations]
  return {} unless object.respond_to?(:_validators)

  validation_attribute_map = {
    ActiveModel::Validations::PresenceValidator => proc { { :required => true } },
    ActiveModel::Validations::InclusionValidator => proc {|validator|
      # Inclusion is weird, in Rails if you have a radio button
      # where you want one of the options selected, and they map
      # to a boolean then using :presence doesn't work, because
      # the presence check on false fails. Instead you have to use
      # inclusion, so we can handle this here and map it to required
      # validation attribute, this is kinda getting a bit hacky though,
      # and may come back to bite us in the foot, so we limit the use
      # to only those cases where true and false are the only options.
      if validator.options[:in] == [true,false]
        { :required => true }
      else
        { }
      end
    }
  }

  validators = object._validators.fetch(name, [])

  validators.reduce({}) do |attributes, validator|
    attributes.merge(validation_attribute_map.fetch(validator.class, proc {}).call(validator))
  end
end