Class: ItsSwiss::FormBuilder

Inherits:
ActionView::Helpers::FormBuilder
  • Object
show all
Defined in:
lib/its_swiss/form_builder.rb

Overview

One shape for every field: a label, a control, and — when there is something to say — a hint or the reason it was refused.

Written by a builder rather than by hand because the parts that get left out by hand are the parts nobody sees missing. A label whose for does not match its input is a label that does not enlarge the target. A hint beside a control is a hint a screen reader never reaches. A refused field coloured by CSS alone is a refusal that only some readers get.

Constant Summary collapse

TEXT_FIELDS =

Everything that is a line of text under a rule. They differ only in the keyboard a phone puts up, which is not a difference the markup has.

%i[
  text_field email_field password_field number_field url_field
  telephone_field phone_field search_field date_field time_field
  datetime_field color_field text_area
].freeze

Instance Method Summary collapse

Instance Method Details

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

A checkbox and its label are a pair on one line — the label says what ticking it means, and reading that above an empty box says nothing.



39
40
41
42
43
# File 'lib/its_swiss/form_builder.rb', line 39

def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
  field(method, options, label_beside: true) do |opts|
    super(method, opts, checked_value, unchecked_value)
  end
end

#collection_select(method, collection, value_method, text_method, options = {}, html_options = {}) ⇒ Object



31
32
33
34
35
# File 'lib/its_swiss/form_builder.rb', line 31

def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
  field(method, html_options) do |opts|
    super(method, collection, value_method, text_method, options, opts)
  end
end

#field(method, options = {}, label_beside: false, label_for_value: nil, &control) ⇒ Object

The wrapper on its own, for a control the library does not know about.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/its_swiss/form_builder.rb', line 63

def field(method, options = {}, label_beside: false, label_for_value: nil, &control)
  options = options.symbolize_keys
  hint, label_option = options.delete(:hint), options.delete(:label)
  errors = errors_on(method)

  ids = describers(method, hint, errors)
  options[:"aria-describedby"] = ids.join(" ") if ids.any?
  options[:"aria-invalid"] = "true" if errors.any?

  label = rendered_label(method, label_option, label_for_value)
  options[:"aria-label"] ||= default_label(method) if label.nil?
  body = @template.capture { control.call(options) }
  body = @template.tag.span(safe_join([ body, label ]), class: "choice") if label_beside && label

  @template.tag.div(class: field_classes(errors)) do
    safe_join([
      (label unless label_beside),
      body,
      hint_tag(method, hint),
      *errors.map.with_index { |message, index| error_tag(method, index, message) }
    ].compact)
  end
end

#radio_button(method, tag_value, options = {}) ⇒ Object



45
46
47
48
49
# File 'lib/its_swiss/form_builder.rb', line 45

def radio_button(method, tag_value, options = {})
  field(method, options, label_beside: true, label_for_value: tag_value) do |opts|
    super(method, tag_value, opts)
  end
end

#select(method, choices = nil, options = {}, html_options = {}, &block) ⇒ Object



25
26
27
28
29
# File 'lib/its_swiss/form_builder.rb', line 25

def select(method, choices = nil, options = {}, html_options = {}, &block)
  field(method, html_options) do |opts|
    super(method, choices, options, opts, &block)
  end
end

#submit(value = nil, options = {}) ⇒ Object

A



55
56
57
58
59
60
# File 'lib/its_swiss/form_builder.rb', line 55

def submit(value = nil, options = {})
  value ||= submit_default_value
  options = { class: "button button--primary" }.merge(options.symbolize_keys)

  @template.tag.button(value, **options, type: "submit")
end