Module: Incline::Extensions::FormBuilder

Defined in:
lib/incline/extensions/form_builder.rb

Overview

Adds additional helper methods to form builders.

Instance Method Summary collapse

Instance Method Details

#check_box_form_group(method, options = {}) ⇒ Object

Creates a standard form group with a checkbox field.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group.

h_align

Create a checkbox aligned to a certain column (1-12) if set. If not set, then a regular form group is generated.

For label options, see #label_w_small. For field options, see FormHelper#check_box.



488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/incline/extensions/form_builder.rb', line 488

def check_box_form_group(method, options = {})
  gopt, lopt, fopt = split_form_group_options({ class: 'checkbox', field_class: ''}.merge(options))

  if gopt[:h_align]
    gopt[:class] = gopt[:class].blank? ?
        "col-sm-#{12-gopt[:h_align]} col-sm-offset-#{gopt[:h_align]}" :
        "#{gopt[:class]} col-sm-#{12-gopt[:h_align]} col-sm-offset-#{gopt[:h_align]}"
  end

  lbl = label method do
    check_box(method, fopt) +
        CGI::escape_html(lopt[:text] || method.to_s.humanize) +
        (lopt[:small_text] ? " <small>(#{CGI::escape_html lopt[:small_text]})</small>" : '').html_safe
  end

  "<div class=\"#{gopt[:h_align] ? 'row' : 'form-group'}\"><div class=\"#{gopt[:class]}\">#{lbl}</div></div>".html_safe
end

#currency_field(method, options = {}) ⇒ Object

Creates a currency entry field.

*Valid options:*

currency_symbol

A string used to prefix the input field. Defaults to ‘$’.

All other options will be passed through to the FormHelper#text_field method.

The value will be formatted with comma delimiters and two decimal places.

f.currency :pay_rate


249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/incline/extensions/form_builder.rb', line 249

def currency_field(method, options = {})
  # get the symbol for the field.
  sym = options.delete(:currency_symbol) || '$'

  # get the value
  if (val = object.send(method))
    options[:value] = number_with_precision val, precision: 2, delimiter: ','
  end

  # build the field
  fld = text_field(method, options)

  # return the value.
  "<div class=\"input-symbol\"><span>#{CGI::escape_html sym}</span>#{fld}</div>".html_safe
end

#currency_form_group(method, options = {}) ⇒ Object

Creates a standard form group with a label and currency field.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small. For field options, see #currency_field.



379
380
381
382
383
384
# File 'lib/incline/extensions/form_builder.rb', line 379

def currency_form_group(method, options = {})
  gopt, lopt, fopt = split_form_group_options(options)
  lbl = label_w_small(method, lopt)
  fld = gopt[:wrap].call(currency_field(method, fopt))
  form_group lbl, fld, gopt
end

#date_picker(method, options = {}) ⇒ Object

Creates a date picker selection field using a bootstrap input group.

*Valid options:*

input_group_size

Valid optional sizes are ‘small’ or ‘large’.

readonly

Set to true to make the input field read only.

pre_calendar

Set to true to put a calendar icon before the input field.

post_calendar

Set to true to put a calendar icon after the input field. This is the default setting if no other pre/post is selected.

pre_label

Set to a text value to put a label before the input field. Replaces pre_calendar if specified.

post_label

Set to a text value to put a label after the input field. Replaces post_calendar if specified.

f.date_picker :end_date, :pre_label => 'End'


30
31
32
33
34
35
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
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/incline/extensions/form_builder.rb', line 30

def date_picker(method, options = {})
  options = {
      class:            'form-control',
      read_only:        false,
      pre_calendar:     false,
      pre_label:        nil,
      post_calendar:    false,
      post_label:       false,
      attrib_val:       { },
      style:            { },
      input_group_size: ''
  }.merge(options)

  style = ''
  options[:style].each { |k,v| style += "#{k}: #{v};" }

  attrib = options[:attrib_val]
  attrib[:class] = options[:class]
  attrib[:style] = style
  attrib[:readonly] = 'readonly' if options[:read_only]

  if %w(sm small input-group-sm).include?(options[:input_group_size])
    options[:input_group_size] = 'input-group-sm'
  elsif %w(lg large input-group-lg).include?(options[:input_group_size])
    options[:input_group_size] = 'input-group-lg'
  else
    options[:input_group_size] = ''
  end

  attrib[:value] = object.send(method).strftime('%m/%d/%Y') if object.send(method)
  fld = text_field(method, attrib)

  # must have at least one attachment, default to post-calendar.
  options[:post_calendar] = true unless options[:pre_calendar] || options[:pre_label] || options[:post_label]

  # labels override calendars.
  options[:pre_calendar] = false if options[:pre_label]
  options[:post_calendar] = false if options[:post_label]

  # construct the prefix
  if options[:pre_calendar]
    pre = '<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>'
  elsif options[:pre_label]
    pre = "<span class=\"input-group-addon\">#{CGI::escape_html options[:pre_label]}</span>"
  else
    pre = ''
  end

  # construct the postfix
  if options[:post_calendar]
    post = '<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>'
  elsif options[:post_label]
    post = "<span class=\"input-group-addon\">#{CGI::escape_html options[:post_label]}</span>"
  else
    post = ''
  end

  # and then the return value.
  "<div class=\"input-group date #{options[:input_group_size]}\">#{pre}#{fld}#{post}</div>".html_safe
end

#datepicker_form_group(method, options = {}) ⇒ Object

Creates a standard form group with a datepicker field.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small. For field options, see #date_picker.



433
434
435
436
437
438
# File 'lib/incline/extensions/form_builder.rb', line 433

def datepicker_form_group(method, options = {})
  gopt, lopt, fopt = split_form_group_options(options)
  lbl = label_w_small(method, lopt)
  fld = gopt[:wrap].call(date_picker(method, fopt))
  form_group lbl, fld, gopt
end

#label_w_small(method, options = {}) ⇒ Object

Creates a label followed by an optional small text description.

For instance, <label>Hello</label> <small>(World)</small>

Valid options:

text

The text for the label. If not set, the method name is humanized and that value will be used.

small_text

The small text to follow the label. If not set, then no small text will be included. This is useful for flagging fields as optional.

For additional options, see FormHelper#label.



279
280
281
282
283
284
# File 'lib/incline/extensions/form_builder.rb', line 279

def label_w_small(method, options = {})
  text = options.delete(:text) || method.to_s.humanize
  small_text = options.delete(:small_text)
  label(method, text, options) +
      (small_text ? " <small>(#{CGI::escape_html small_text})</small>" : '').html_safe
end

#multi_input(methods, options = {}) ⇒ Object

Creates a multiple input field control for the provided form.

The methods parameter can be either an array of method names, or a hash with method names as the keys and labels as the values.

For instance:

[ :alpha, :bravo, :charlie ]
{ :alpha => 'The first item', :bravo => 'The second item', :charlie => 'The third item' }

*Valid options:*

class

The CSS class to apply. Defaults to ‘form-control’.

read_only

Should the control be read-only? Defaults to false.

style

A hash containing CSS styling attributes to apply to the input fields. Width is generated automatically or specified individually using the “field_n” option.

input_group_size

You can specific small or large to change the control’s overall size.

attrib

Any additional attributes you want to apply to the input fields.

field_n

Sets specific attributes for field “n”. These values will override the “attrib” and “style” options.

f.multi_input [ :city, :state, :zip ],
    :field_1 => { :maxlength => 30, :style => { :width => '65%' } },
    :field_2 => { :maxlength => 2 },
    :field_3 => { :maxlength => 10, :style => { :width => '25%' } }

Raises:

  • (ArgumentError)


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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/incline/extensions/form_builder.rb', line 127

def multi_input(methods, options = {})
  raise ArgumentError.new('methods must be either a Hash or an Array') unless methods.is_a?(::Hash) || methods.is_a?(::Array)
  options = options.dup

  # add some defaults.
  options = {
      class: 'form-control',
      read_only: false,
      attrib: { },
      style: { },
      input_group_size: ''
  }.merge(options)

  # build the style attribute.
  options[:attrib][:style] ||= ''
  options[:style].each do |k,v|
    if k.to_s == 'width'
      options[:input_group_width] = "width: #{v};"
    else
      options[:attrib][:style] += "#{k}: #{v};"
    end
  end

  # Standardize the "methods" list to be an array of arrays.
  if methods.is_a?(::Hash)
    methods = methods.to_a
  elsif methods.is_a?(::Array)
    methods = methods.map{|v| v.is_a?(::Array) ? v : [ v, v.to_s.humanize ] }
  end

  # Extract field attributes.
  fields = { }
  index = 1
  methods.each do |(meth,label)|
    fields[meth] = options[:attrib].merge(options.delete(:"field_#{index}") || {})
    fields[meth][:readonly] = 'readonly' if options[:read_only]
    fields[meth][:class] ||= options[:class]
    if fields[meth][:style].is_a?(::Hash)
      fields[meth][:style] = fields[meth][:style].to_a.map{|v| v.map(&:to_s).join(':') + ';'}.join(' ')
    end
    fields[meth][:placeholder] ||= label
  end

  if %w(sm small input-group-sm).include?(options[:input_group_size])
    options[:input_group_size] = 'input-group-sm'
  elsif %w(lg large input-group-lg).include?(options[:input_group_size])
    options[:input_group_size] = 'input-group-lg'
  else
    options[:input_group_size] = ''
  end

  # We want each field to have a width specified.
  remaining_width = 100.0
  remaining_fields = fields.count
  width_match_1 = /^width:([^;]);/
  width_match_2 = /;\s*width:([^;]);/

  # pass 1, compute remaining width.
  fields.each do |meth, attr|
    width = width_match_1.match(attr[:style]) || width_match_2.match(attr[:style])
    if width
      if width[-1] == '%'
        width = width[0...-1].strip.to_f
        if width > remaining_width
          Incline::Log::warn "Field width adds up to more than 100% in multi_input affecting field \"#{meth}\"."
          width = remaining_width
          attr[:style] = attr[:style].gsub(width_match_1, '').gsub(width_match_2, '') + "width: #{width}%;"
        end
        remaining_width -= width
        remaining_width = 0 if remaining_width < 0
        remaining_fields -= 1
      else
        # we do not support pixel, em, etc, so dump the unsupported width.
        Incline::Log::warn "Unsupported width style in multi_input affecting field \"#{meth}\": #{width}"
        attr[:style] = attr[:style].gsub(width_match_1, '').gsub(width_match_2, '')
      end
    end
  end

  # pass 2, fill in missing widths.
  fields.each do |meth, attr|
    width = width_match_1.match(attr[:style]) || width_match_2.match(attr[:style])
    unless width
      width =
        if remaining_fields > 1
          (remaining_width / remaining_fields).to_i
        else
          remaining_width
        end

      Incline::Log::warn "Computed field width of 0% in multi_input affecting field \"#{meth}\"." if width == 0

      attr[:style] += "width: #{width}%;"
      remaining_width -= width
      remaining_fields -= 1
      remaining_width = 0 if remaining_width < 0
    end
  end

  fld = []
  fields.each do |meth, attr|
    attr[:value] = object.send(meth)
    fld << text_field(meth, attr)
  end

  "<div class=\"input-group #{options[:input_group_size]}\" style=\"#{options[:input_group_width]}\">#{fld.join}</div>".html_safe
end

#multi_input_form_group(methods, options = {}) ⇒ Object

Creates a standard form group with a multiple input control.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small. For field options, see #multi_input_field.



458
459
460
461
462
463
464
465
466
467
# File 'lib/incline/extensions/form_builder.rb', line 458

def multi_input_form_group(methods, options = {})
  gopt, lopt, fopt = split_form_group_options(options)
  lopt[:text] ||= gopt[:label]
  if lopt[:text].blank?
    lopt[:text] = methods.map {|k,_| k.to_s.humanize }.join(', ')
  end
  lbl = label_w_small(methods.map{|k,_| k}.first, lopt)
  fld = gopt[:wrap].call(multi_input(methods, fopt))
  form_group lbl, fld, gopt
end

#password_form_group(method, options = {}) ⇒ Object

Creates a standard form group with a label and password field.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small. For field options, see FormHelper#password_field.



329
330
331
332
333
334
# File 'lib/incline/extensions/form_builder.rb', line 329

def password_form_group(method, options = {})
  gopt, lopt, fopt = split_form_group_options(options)
  lbl = label_w_small(method, lopt)
  fld = gopt[:wrap].call(password_field(method, fopt))
  form_group lbl, fld, gopt
end

#recaptcha(method, options = {}) ⇒ Object

Adds a recaptcha challenge to the form configured to set the specified attribute to the recaptcha response.

Valid options:

theme

Can be :dark or :light, defaults to :light.

type

Can be :image or :audio, defaults to :image.

size

Can be :compact or :normal, defaults to :normal.

tab_index

Can be any valid integer if you want a specific tab order, defaults to 0.



559
560
561
# File 'lib/incline/extensions/form_builder.rb', line 559

def recaptcha(method, options = {})
  Incline::Recaptcha::Tag.new(@object_name, method, @template, options).render
end

#select_form_group(method, collection, value_method = :to_s, text_method = :to_s, options = {}) ⇒ Object

Creates a standard form group with a collection select field.

The collection should be an enumerable object (responds to ‘each’).

The value_method would be the method to call on the objects in the collection to get the value. This default to ‘to_s’ and is appropriate for any array of strings.

The text_method would be the method to call on the objects in the collection to get the display text. This defaults to ‘to_s’ as well, and should be appropriate for most objects.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small. For field options, see FormOptionsHelper#collection_select.



532
533
534
535
536
537
538
539
540
541
542
543
544
# File 'lib/incline/extensions/form_builder.rb', line 532

def select_form_group(method, collection, value_method = :to_s, text_method = :to_s, options = {})
  gopt, lopt, fopt = split_form_group_options({ field_include_blank: true }.merge(options))
  lbl = label_w_small(method, lopt)
  opt = {}
  [:include_blank, :prompt, :include_hidden].each do |attr|
    if fopt[attr] != nil
      opt[attr] = fopt[attr]
      fopt.except! attr
    end
  end
  fld = gopt[:wrap].call(collection_select(method, collection, value_method, text_method, opt, fopt))
  form_group lbl, fld, gopt
end

#static_form_group(method, options = {}) ⇒ Object

Creates a standard form group with a label and a static text field.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small.

Field options:

value

Allows you to specify a value for the static field, otherwise the value from method will be used.



408
409
410
411
412
413
# File 'lib/incline/extensions/form_builder.rb', line 408

def static_form_group(method, options = {})
  gopt, lopt, fopt = split_form_group_options(options)
  lbl = label_w_small(method, lopt)
  fld = gopt[:wrap].call("<input type=\"text\" class=\"form-control disabled\" readonly=\"readonly\" value=\"#{CGI::escape_html(fopt[:value] || object.send(method))}\">")
  form_group lbl, fld, gopt
end

#text_form_group(method, options = {}) ⇒ Object

Creates a standard form group with a label and text field.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small. For field options, see FormHelper#text_field.



304
305
306
307
308
309
# File 'lib/incline/extensions/form_builder.rb', line 304

def text_form_group(method, options = {})
  gopt, lopt, fopt = split_form_group_options(options)
  lbl = label_w_small(method, lopt)
  fld = gopt[:wrap].call(text_field(method, fopt))
  form_group lbl, fld, gopt
end

#textarea_form_group(method, options = {}) ⇒ Object

Creates a form group including a label and a text area.

The options is a hash containing label, field, and group options. Prefix label options with label_ and field options with field_. All other options will apply to the group itself.

Group options:

class

The CSS class for the form group. Defaults to ‘form-group’.

style

Any styles to apply to the form group.

For label options, see #label_w_small. For field options, see FormHelper#text_area.



354
355
356
357
358
359
# File 'lib/incline/extensions/form_builder.rb', line 354

def textarea_form_group(method, options = {})
  gopt, lopt, fopt = split_form_group_options(options)
  lbl = label_w_small method, lopt
  fld = gopt[:wrap].call(text_area(method, fopt))
  form_group lbl, fld, gopt
end