formtastic 1.2.4 → 3.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +46 -0
  5. data/.yardopts +1 -0
  6. data/Appraisals +43 -0
  7. data/CHANGELOG +54 -0
  8. data/DEPRECATIONS +52 -0
  9. data/Gemfile +3 -0
  10. data/README.md +629 -0
  11. data/RELEASE_PROCESS +6 -0
  12. data/Rakefile +35 -0
  13. data/app/assets/stylesheets/formtastic.css +289 -0
  14. data/app/assets/stylesheets/formtastic_ie6.css +33 -0
  15. data/app/assets/stylesheets/formtastic_ie7.css +23 -0
  16. data/formtastic.gemspec +42 -0
  17. data/gemfiles/rails_3.2.gemfile +9 -0
  18. data/gemfiles/rails_4.0.4.gemfile +8 -0
  19. data/gemfiles/rails_4.1.gemfile +8 -0
  20. data/gemfiles/rails_4.2.gemfile +8 -0
  21. data/gemfiles/rails_4.gemfile +8 -0
  22. data/gemfiles/rails_5.0.gemfile +8 -0
  23. data/gemfiles/rails_edge.gemfile +15 -0
  24. data/lib/formtastic.rb +40 -1945
  25. data/lib/formtastic/action_class_finder.rb +18 -0
  26. data/lib/formtastic/actions.rb +11 -0
  27. data/lib/formtastic/actions/base.rb +156 -0
  28. data/lib/formtastic/actions/button_action.rb +67 -0
  29. data/lib/formtastic/actions/buttonish.rb +17 -0
  30. data/lib/formtastic/actions/input_action.rb +70 -0
  31. data/lib/formtastic/actions/link_action.rb +88 -0
  32. data/lib/formtastic/deprecation.rb +42 -0
  33. data/lib/formtastic/engine.rb +11 -0
  34. data/lib/formtastic/form_builder.rb +124 -0
  35. data/lib/formtastic/helpers.rb +16 -0
  36. data/lib/formtastic/helpers/action_helper.rb +162 -0
  37. data/lib/formtastic/helpers/actions_helper.rb +168 -0
  38. data/lib/formtastic/helpers/enum.rb +13 -0
  39. data/lib/formtastic/helpers/errors_helper.rb +81 -0
  40. data/lib/formtastic/helpers/fieldset_wrapper.rb +80 -0
  41. data/lib/formtastic/helpers/file_column_detection.rb +16 -0
  42. data/lib/formtastic/helpers/form_helper.rb +203 -0
  43. data/lib/formtastic/helpers/input_helper.rb +407 -0
  44. data/lib/formtastic/helpers/inputs_helper.rb +411 -0
  45. data/lib/formtastic/helpers/reflection.rb +37 -0
  46. data/lib/formtastic/html_attributes.rb +32 -0
  47. data/lib/formtastic/i18n.rb +4 -2
  48. data/lib/formtastic/input_class_finder.rb +18 -0
  49. data/lib/formtastic/inputs.rb +39 -0
  50. data/lib/formtastic/inputs/base.rb +76 -0
  51. data/lib/formtastic/inputs/base/associations.rb +31 -0
  52. data/lib/formtastic/inputs/base/choices.rb +108 -0
  53. data/lib/formtastic/inputs/base/collections.rb +159 -0
  54. data/lib/formtastic/inputs/base/database.rb +22 -0
  55. data/lib/formtastic/inputs/base/datetime_pickerish.rb +85 -0
  56. data/lib/formtastic/inputs/base/errors.rb +58 -0
  57. data/lib/formtastic/inputs/base/fileish.rb +23 -0
  58. data/lib/formtastic/inputs/base/hints.rb +31 -0
  59. data/lib/formtastic/inputs/base/html.rb +53 -0
  60. data/lib/formtastic/inputs/base/labelling.rb +52 -0
  61. data/lib/formtastic/inputs/base/naming.rb +42 -0
  62. data/lib/formtastic/inputs/base/numeric.rb +50 -0
  63. data/lib/formtastic/inputs/base/options.rb +17 -0
  64. data/lib/formtastic/inputs/base/placeholder.rb +17 -0
  65. data/lib/formtastic/inputs/base/stringish.rb +38 -0
  66. data/lib/formtastic/inputs/base/timeish.rb +241 -0
  67. data/lib/formtastic/inputs/base/validations.rb +215 -0
  68. data/lib/formtastic/inputs/base/wrapping.rb +50 -0
  69. data/lib/formtastic/inputs/boolean_input.rb +118 -0
  70. data/lib/formtastic/inputs/check_boxes_input.rb +197 -0
  71. data/lib/formtastic/inputs/color_input.rb +42 -0
  72. data/lib/formtastic/inputs/country_input.rb +86 -0
  73. data/lib/formtastic/inputs/datalist_input.rb +41 -0
  74. data/lib/formtastic/inputs/date_picker_input.rb +93 -0
  75. data/lib/formtastic/inputs/date_select_input.rb +34 -0
  76. data/lib/formtastic/inputs/datetime_picker_input.rb +103 -0
  77. data/lib/formtastic/inputs/datetime_select_input.rb +12 -0
  78. data/lib/formtastic/inputs/email_input.rb +41 -0
  79. data/lib/formtastic/inputs/file_input.rb +42 -0
  80. data/lib/formtastic/inputs/hidden_input.rb +62 -0
  81. data/lib/formtastic/inputs/number_input.rb +88 -0
  82. data/lib/formtastic/inputs/password_input.rb +41 -0
  83. data/lib/formtastic/inputs/phone_input.rb +42 -0
  84. data/lib/formtastic/inputs/radio_input.rb +163 -0
  85. data/lib/formtastic/inputs/range_input.rb +95 -0
  86. data/lib/formtastic/inputs/search_input.rb +41 -0
  87. data/lib/formtastic/inputs/select_input.rb +235 -0
  88. data/lib/formtastic/inputs/string_input.rb +36 -0
  89. data/lib/formtastic/inputs/text_input.rb +48 -0
  90. data/lib/formtastic/inputs/time_picker_input.rb +99 -0
  91. data/lib/formtastic/inputs/time_select_input.rb +38 -0
  92. data/lib/formtastic/inputs/time_zone_input.rb +58 -0
  93. data/lib/formtastic/inputs/url_input.rb +41 -0
  94. data/lib/formtastic/localized_string.rb +17 -0
  95. data/lib/formtastic/localizer.rb +152 -0
  96. data/lib/formtastic/namespaced_class_finder.rb +99 -0
  97. data/lib/formtastic/util.rb +35 -16
  98. data/lib/formtastic/version.rb +3 -0
  99. data/lib/generators/formtastic/form/form_generator.rb +64 -37
  100. data/lib/generators/formtastic/input/input_generator.rb +46 -0
  101. data/lib/generators/formtastic/install/install_generator.rb +13 -5
  102. data/lib/generators/templates/_form.html.erb +10 -4
  103. data/lib/generators/templates/_form.html.haml +8 -4
  104. data/lib/generators/templates/_form.html.slim +8 -0
  105. data/lib/generators/templates/formtastic.rb +77 -44
  106. data/lib/generators/templates/input.rb +19 -0
  107. data/lib/locale/en.yml +3 -0
  108. data/sample/basic_inputs.html +224 -0
  109. data/sample/config.ru +69 -0
  110. data/sample/index.html +14 -0
  111. data/spec/action_class_finder_spec.rb +12 -0
  112. data/spec/actions/button_action_spec.rb +63 -0
  113. data/spec/actions/generic_action_spec.rb +521 -0
  114. data/spec/actions/input_action_spec.rb +59 -0
  115. data/spec/actions/link_action_spec.rb +92 -0
  116. data/spec/builder/custom_builder_spec.rb +116 -0
  117. data/spec/builder/error_proc_spec.rb +27 -0
  118. data/spec/builder/semantic_fields_for_spec.rb +142 -0
  119. data/spec/fast_spec_helper.rb +12 -0
  120. data/spec/generators/formtastic/form/form_generator_spec.rb +131 -0
  121. data/spec/generators/formtastic/input/input_generator_spec.rb +124 -0
  122. data/spec/generators/formtastic/install/install_generator_spec.rb +47 -0
  123. data/spec/helpers/action_helper_spec.rb +19 -0
  124. data/spec/helpers/actions_helper_spec.rb +143 -0
  125. data/spec/helpers/form_helper_spec.rb +218 -0
  126. data/spec/helpers/input_helper_spec.rb +6 -0
  127. data/spec/helpers/inputs_helper_spec.rb +655 -0
  128. data/spec/helpers/namespaced_action_helper_spec.rb +43 -0
  129. data/spec/helpers/namespaced_input_helper_spec.rb +36 -0
  130. data/spec/helpers/reflection_helper_spec.rb +32 -0
  131. data/spec/helpers/semantic_errors_helper_spec.rb +112 -0
  132. data/spec/i18n_spec.rb +210 -0
  133. data/spec/input_class_finder_spec.rb +10 -0
  134. data/spec/inputs/base/collections_spec.rb +76 -0
  135. data/spec/inputs/base/validations_spec.rb +342 -0
  136. data/spec/inputs/boolean_input_spec.rb +254 -0
  137. data/spec/inputs/check_boxes_input_spec.rb +546 -0
  138. data/spec/inputs/color_input_spec.rb +97 -0
  139. data/spec/inputs/country_input_spec.rb +133 -0
  140. data/spec/inputs/custom_input_spec.rb +55 -0
  141. data/spec/inputs/datalist_input_spec.rb +61 -0
  142. data/spec/inputs/date_picker_input_spec.rb +449 -0
  143. data/spec/inputs/date_select_input_spec.rb +235 -0
  144. data/spec/inputs/datetime_picker_input_spec.rb +490 -0
  145. data/spec/inputs/datetime_select_input_spec.rb +193 -0
  146. data/spec/inputs/email_input_spec.rb +85 -0
  147. data/spec/inputs/file_input_spec.rb +89 -0
  148. data/spec/inputs/hidden_input_spec.rb +135 -0
  149. data/spec/inputs/include_blank_spec.rb +78 -0
  150. data/spec/inputs/label_spec.rb +149 -0
  151. data/spec/inputs/number_input_spec.rb +815 -0
  152. data/spec/inputs/password_input_spec.rb +99 -0
  153. data/spec/inputs/phone_input_spec.rb +85 -0
  154. data/spec/inputs/placeholder_spec.rb +71 -0
  155. data/spec/inputs/radio_input_spec.rb +328 -0
  156. data/spec/inputs/range_input_spec.rb +505 -0
  157. data/spec/inputs/readonly_spec.rb +50 -0
  158. data/spec/inputs/search_input_spec.rb +84 -0
  159. data/spec/inputs/select_input_spec.rb +615 -0
  160. data/spec/inputs/string_input_spec.rb +260 -0
  161. data/spec/inputs/text_input_spec.rb +187 -0
  162. data/spec/inputs/time_picker_input_spec.rb +455 -0
  163. data/spec/inputs/time_select_input_spec.rb +248 -0
  164. data/spec/inputs/time_zone_input_spec.rb +143 -0
  165. data/spec/inputs/url_input_spec.rb +85 -0
  166. data/spec/inputs/with_options_spec.rb +43 -0
  167. data/spec/localizer_spec.rb +130 -0
  168. data/spec/namespaced_class_finder_spec.rb +79 -0
  169. data/spec/spec.opts +2 -0
  170. data/spec/spec_helper.rb +525 -0
  171. data/spec/support/custom_macros.rb +564 -0
  172. data/spec/support/deprecation.rb +6 -0
  173. data/spec/support/shared_examples.rb +1313 -0
  174. data/spec/support/specialized_class_finder_shared_example.rb +27 -0
  175. data/spec/support/test_environment.rb +31 -0
  176. data/spec/util_spec.rb +66 -0
  177. metadata +434 -161
  178. data/README.textile +0 -682
  179. data/generators/form/USAGE +0 -16
  180. data/generators/form/form_generator.rb +0 -111
  181. data/generators/formtastic/formtastic_generator.rb +0 -26
  182. data/init.rb +0 -5
  183. data/lib/formtastic/layout_helper.rb +0 -12
  184. data/lib/formtastic/railtie.rb +0 -14
  185. data/lib/generators/templates/formtastic.css +0 -145
  186. data/lib/generators/templates/formtastic_changes.css +0 -14
  187. data/lib/generators/templates/rails2/_form.html.erb +0 -5
  188. data/lib/generators/templates/rails2/_form.html.haml +0 -4
  189. data/rails/init.rb +0 -2
@@ -0,0 +1,50 @@
1
+ module Formtastic
2
+ module Inputs
3
+ module Base
4
+ # @todo relies on `dom_id`, `required?`, `optional`, `errors?`, `association_primary_key` & `sanitized_method_name` methods from another module
5
+ module Wrapping
6
+
7
+ # Override this method if you want to change the display order (for example, rendering the
8
+ # errors before the body of the input).
9
+ def input_wrapping(&block)
10
+ template.content_tag(:li,
11
+ [template.capture(&block), error_html, hint_html].join("\n").html_safe,
12
+ wrapper_html_options
13
+ )
14
+ end
15
+
16
+ def wrapper_html_options
17
+ opts = wrapper_html_options_raw
18
+ opts[:class] = wrapper_classes
19
+ opts[:id] = wrapper_dom_id unless opts.has_key? :id
20
+ opts
21
+ end
22
+
23
+ def wrapper_html_options_raw
24
+ (options[:wrapper_html] || {}).dup
25
+ end
26
+
27
+ def wrapper_classes_raw
28
+ [*wrapper_html_options_raw[:class]]
29
+ end
30
+
31
+ def wrapper_classes
32
+ classes = wrapper_classes_raw
33
+ classes << as
34
+ classes << "input"
35
+ classes << "error" if errors?
36
+ classes << "optional" if optional?
37
+ classes << "required" if required?
38
+ classes << "autofocus" if autofocus?
39
+
40
+ classes.join(' ')
41
+ end
42
+
43
+ def wrapper_dom_id
44
+ @wrapper_dom_id ||= "#{dom_id.to_s.gsub((association_primary_key || method).to_s, sanitized_method_name.to_s)}_input"
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,118 @@
1
+ module Formtastic
2
+ module Inputs
3
+ # Boolean inputs are used to render an input for a single checkbox, typically for attributes
4
+ # with a simple yes/no or true/false value. Boolean inputs are used by default for boolean
5
+ # database columns.
6
+ #
7
+ # @example Full form context and markup
8
+ # <%= semantic_form_for @post %>
9
+ # <%= f.inputs do %>
10
+ # <%= f.input :published, :as => :boolean %>
11
+ # <% end %>
12
+ # <% end %>
13
+ #
14
+ # <form...>
15
+ # <fieldset>
16
+ # <ol>
17
+ # <li class="boolean" id="post_published_input">
18
+ # <input type="hidden" name="post[published]" id="post_published" value="0">
19
+ # <label for="post_published">
20
+ # <input type="checkbox" name="post[published]" id="post_published" value="1">
21
+ # Published?
22
+ # </label>
23
+ # </li>
24
+ # </ol>
25
+ # </fieldset>
26
+ # </form>
27
+ #
28
+ # @example Set the values for the checked and unchecked states
29
+ # <%= f.input :published, :checked_value => "yes", :unchecked_value => "no" %>
30
+ #
31
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
32
+ class BooleanInput
33
+ include Base
34
+
35
+ def to_html
36
+ input_wrapping do
37
+ hidden_field_html <<
38
+ label_with_nested_checkbox
39
+ end
40
+ end
41
+
42
+ def hidden_field_html
43
+ template.hidden_field_tag(input_html_options[:name], unchecked_value, :id => nil, :disabled => input_html_options[:disabled] )
44
+ end
45
+
46
+ def label_with_nested_checkbox
47
+ builder.label(
48
+ method,
49
+ label_text_with_embedded_checkbox,
50
+ label_html_options
51
+ )
52
+ end
53
+
54
+ def label_html_options
55
+ {
56
+ :for => input_html_options[:id],
57
+ :class => super[:class] - ['label'] # remove 'label' class
58
+ }
59
+ end
60
+
61
+ def label_text_with_embedded_checkbox
62
+ check_box_html << "" << label_text
63
+ end
64
+
65
+ def check_box_html
66
+ template.check_box_tag("#{object_name}[#{method}]", checked_value, checked?, input_html_options)
67
+ end
68
+
69
+ def unchecked_value
70
+ options[:unchecked_value] || '0'
71
+ end
72
+
73
+ def checked_value
74
+ options[:checked_value] || '1'
75
+ end
76
+
77
+ def responds_to_global_required?
78
+ false
79
+ end
80
+
81
+ def input_html_options
82
+ {:name => input_html_options_name}.merge(super)
83
+ end
84
+
85
+ def input_html_options_name
86
+ if builder.options.key?(:index)
87
+ "#{object_name}[#{builder.options[:index]}][#{method}]"
88
+ else
89
+ "#{object_name}[#{method}]"
90
+ end
91
+ end
92
+
93
+ def checked?
94
+ object && boolean_checked?(object.send(method), checked_value)
95
+ end
96
+
97
+ private
98
+
99
+ def boolean_checked?(value, checked_value)
100
+ case value
101
+ when TrueClass, FalseClass
102
+ value
103
+ when NilClass
104
+ false
105
+ when Integer
106
+ value == checked_value.to_i
107
+ when String
108
+ value == checked_value
109
+ when Array
110
+ value.include?(checked_value)
111
+ else
112
+ value.to_i != 0
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,197 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # A CheckBoxes input is used to render a series of checkboxes. This is an alternative input choice
5
+ # for `has_many` or `has_and_belongs_to_many` associations like a `Post` belonging to many
6
+ # `categories` (by default, a {SelectInput `:select`} input is used, allowing multiple selections).
7
+ #
8
+ # Within the standard `<li>` wrapper, the output is a `<fieldset>` with a `<legend>` to
9
+ # represent the "label" for the input, and an `<ol>` containing `<li>`s for each choice in
10
+ # the association. Each `<li>` choice contains a hidden `<input>` tag for the "unchecked"
11
+ # value (like Rails), and a `<label>` containing the checkbox `<input>` and the label text
12
+ # for each choice.
13
+ #
14
+ # @example Basic example with full form context
15
+ #
16
+ # <%= semantic_form_for @post do |f| %>
17
+ # <%= f.inputs do %>
18
+ # <%= f.input :categories, :as => :check_boxes %>
19
+ # <% end %>
20
+ # <% end %>
21
+ #
22
+ # <li class='check_boxes'>
23
+ # <fieldset>
24
+ # <legend class="label"><label>Categories</label></legend>
25
+ # <ol>
26
+ # <li>
27
+ # <input type="hidden" name="post[category_ids][1]" value="">
28
+ # <label for="post_category_ids_1"><input id="post_category_ids_1" name="post[category_ids][1]" type="checkbox" value="1" /> Ruby</label>
29
+ # </li>
30
+ # <li>
31
+ # <input type="hidden" name="post[category_ids][2]" value="">
32
+ # <label for="post_category_ids_2"><input id="post_category_ids_2" name="post[category_ids][2]" type="checkbox" value="2" /> Rails</label>
33
+ # </li>
34
+ # </ol>
35
+ # </fieldset>
36
+ # </li>
37
+ #
38
+ # @example `:collection` can be used to customize the choices
39
+ # <%= f.input :categories, :as => :check_boxes, :collection => @categories %>
40
+ # <%= f.input :categories, :as => :check_boxes, :collection => Category.all %>
41
+ # <%= f.input :categories, :as => :check_boxes, :collection => Category.some_named_scope %>
42
+ # <%= f.input :categories, :as => :check_boxes, :collection => Category.pluck(:label, :id) %>
43
+ # <%= f.input :categories, :as => :check_boxes, :collection => [Category.find_by_name("Ruby"), Category.find_by_name("Rails")] %>
44
+ # <%= f.input :categories, :as => :check_boxes, :collection => ["Ruby", "Rails"] %>
45
+ # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", "ruby"], ["Rails", "rails"]] %>
46
+ # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", "1"], ["Rails", "2"]] %>
47
+ # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", 1], ["Rails", 2]] %>
48
+ # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", 1, {'data-attr' => 'attr-value'}]] %>
49
+ # <%= f.input :categories, :as => :check_boxes, :collection => 1..5 %>
50
+ # <%= f.input :categories, :as => :check_boxes, :collection => [:ruby, :rails] %>
51
+ # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", :ruby], ["Rails", :rails]] %>
52
+ # <%= f.input :categories, :as => :check_boxes, :collection => Set.new([:ruby, :rails]) %>
53
+ #
54
+ # @example `:hidden_fields` can be used to skip Rails' rendering of a hidden field before every checkbox
55
+ # <%= f.input :categories, :as => :check_boxes, :hidden_fields => false %>
56
+ #
57
+ # @example `:disabled` can be used to disable any checkboxes with a value found in the given Array
58
+ # <%= f.input :categories, :as => :check_boxes, :collection => ["a", "b"], :disabled => ["a"] %>
59
+ #
60
+ # @example `:value_as_class` can be used to add a class to the `<li>` wrapped around each choice using the checkbox value for custom styling of each choice
61
+ # <%= f.input :categories, :as => :check_boxes, :value_as_class => true %>
62
+ #
63
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
64
+ # @see Formtastic::Inputs::BooleanInput BooleanInput for a single checkbox for boolean (checked = true) inputs
65
+ #
66
+ # @todo Do/can we support the per-item HTML options like RadioInput?
67
+ class CheckBoxesInput
68
+ include Base
69
+ include Base::Collections
70
+ include Base::Choices
71
+
72
+ def initialize(*args)
73
+ super
74
+ raise Formtastic::UnsupportedEnumCollection if collection_from_enum?
75
+ end
76
+
77
+ def to_html
78
+ input_wrapping do
79
+ choices_wrapping do
80
+ legend_html <<
81
+ hidden_field_for_all <<
82
+ choices_group_wrapping do
83
+ collection.map { |choice|
84
+ choice_wrapping(choice_wrapping_html_options(choice)) do
85
+ choice_html(choice)
86
+ end
87
+ }.join("\n").html_safe
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def choice_html(choice)
94
+ template.content_tag(
95
+ :label,
96
+ checkbox_input(choice) + choice_label(choice),
97
+ label_html_options.merge(:for => choice_input_dom_id(choice), :class => nil)
98
+ )
99
+ end
100
+
101
+ def hidden_field_for_all
102
+ if hidden_fields?
103
+ ''
104
+ else
105
+ options = {}
106
+ options[:class] = [method.to_s.singularize, 'default'].join('_') if value_as_class?
107
+ options[:id] = [object_name, method, 'none'].join('_')
108
+ template.hidden_field_tag(input_name, '', options)
109
+ end
110
+ end
111
+
112
+ def hidden_fields?
113
+ options[:hidden_fields]
114
+ end
115
+
116
+ def check_box_with_hidden_input(choice)
117
+ value = choice_value(choice)
118
+ builder.check_box(
119
+ association_primary_key || method,
120
+ extra_html_options(choice).merge(:id => choice_input_dom_id(choice), :name => input_name, :disabled => disabled?(value), :required => false),
121
+ value,
122
+ unchecked_value
123
+ )
124
+ end
125
+
126
+ def check_box_without_hidden_input(choice)
127
+ value = choice_value(choice)
128
+ template.check_box_tag(
129
+ input_name,
130
+ value,
131
+ checked?(value),
132
+ extra_html_options(choice).merge(:id => choice_input_dom_id(choice), :disabled => disabled?(value), :required => false)
133
+ )
134
+ end
135
+
136
+ def extra_html_options(choice)
137
+ input_html_options.merge(custom_choice_html_options(choice))
138
+ end
139
+
140
+ def checked?(value)
141
+ selected_values.include?(value)
142
+ end
143
+
144
+ def disabled?(value)
145
+ disabled_values.include?(value)
146
+ end
147
+
148
+ def selected_values
149
+ @selected_values ||= make_selected_values
150
+ end
151
+
152
+ def disabled_values
153
+ vals = options[:disabled] || []
154
+ vals = [vals] unless vals.is_a?(Array)
155
+ vals
156
+ end
157
+
158
+ def unchecked_value
159
+ options[:unchecked_value] || ''
160
+ end
161
+
162
+ def input_name
163
+ if builder.options.key?(:index)
164
+ "#{object_name}[#{builder.options[:index]}][#{association_primary_key || method}][]"
165
+ else
166
+ "#{object_name}[#{association_primary_key || method}][]"
167
+ end
168
+ end
169
+
170
+ protected
171
+
172
+ def checkbox_input(choice)
173
+ if hidden_fields?
174
+ check_box_with_hidden_input(choice)
175
+ else
176
+ check_box_without_hidden_input(choice)
177
+ end
178
+ end
179
+
180
+ def make_selected_values
181
+ if object.respond_to?(method)
182
+ selected_items = object.send(method)
183
+ # Construct an array from the return value, regardless of the return type
184
+ selected_items = [*selected_items].compact.flatten
185
+
186
+ selected = []
187
+ selected_items.map do |selected_item|
188
+ selected_item_id = selected_item.id if selected_item.respond_to? :id
189
+ item = send_or_call_or_object(value_method, selected_item) || selected_item_id
190
+ end.compact
191
+ else
192
+ []
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,42 @@
1
+ module Formtastic
2
+ module Inputs
3
+
4
+ # Outputs a simple `<label>` with a HTML5 `<input type="color">` wrapped in the standard
5
+ # `<li>` wrapper. This is the default input choice for attributes with a name matching
6
+ # `/color/`, but can be applied to any text-like input with `:as => :color`.
7
+ #
8
+ # @example Full form context and output
9
+ #
10
+ # <%= semantic_form_for(@user) do |f| %>
11
+ # <%= f.inputs do %>
12
+ # <%= f.input :color, :as => :color %>
13
+ # <% end %>
14
+ # <% end %>
15
+ #
16
+ # <form...>
17
+ # <fieldset>
18
+ # <ol>
19
+ # <li class="color">
20
+ # <label for="user_color">Color</label>
21
+ # <input type="color" id="user_color" name="user[color]">
22
+ # </li>
23
+ # </ol>
24
+ # </fieldset>
25
+ # </form>
26
+ #
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
28
+ class ColorInput
29
+ include Base
30
+ include Base::Stringish
31
+ include Base::Placeholder
32
+
33
+ def to_html
34
+ raise "The :color input requires the color_field form helper, which is only available in Rails 4+" unless builder.respond_to?(:color_field)
35
+ input_wrapping do
36
+ label_html <<
37
+ builder.color_field(method, input_html_options)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,86 @@
1
+ module Formtastic
2
+ module Inputs
3
+ # Outputs a country select input, wrapping around a regular country_select helper.
4
+ # Rails doesn't come with a `country_select` helper by default any more, so you'll need to do
5
+ # one of the following:
6
+ #
7
+ # * install the [country_select](https://github.com/stefanpenner/country_select) gem
8
+ # * install any other country_select plugin that behaves in a similar way
9
+ # * roll your own `country_select` helper with the same args and options as the Rails one
10
+ #
11
+ # Formtastic supports both 1.x and 2.x of stefanpenner/country_select, but if you're upgrading
12
+ # from 1.x, they behave quite differently, so please see their [upgrade instructions](https://github.com/stefanpenner/country_select/blob/master/UPGRADING.md).
13
+ #
14
+ # By default, Formtastic includes a handful of English-speaking countries as "priority
15
+ # countries", which can be set in the `priority_countries` configuration array in the
16
+ # formtastic.rb initializer to suit your market and user base (see README for more info on
17
+ # configuration). Additionally, it is possible to set the :priority_countries on a per-input
18
+ # basis through the `:priority_countries` option. These priority countries will be passed down
19
+ # to the `country_select` helper of your choice, and may or may not be used by the helper.
20
+ #
21
+ # @example Basic example with full form context using `priority_countries` from config
22
+ #
23
+ # <%= semantic_form_for @user do |f| %>
24
+ # <%= f.inputs do %>
25
+ # <%= f.input :nationality, :as => :country %>
26
+ # <% end %>
27
+ # <% end %>
28
+ #
29
+ # <li class='country'>
30
+ # <label for="user_nationality">Country</label>
31
+ # <select id="user_nationality" name="user[nationality]">
32
+ # <option value="...">...</option>
33
+ # # ...
34
+ # </li>
35
+ #
36
+ # @example `:priority_countries` set on a specific input (country_select 1.x)
37
+ #
38
+ # <%= semantic_form_for @user do |f| %>
39
+ # <%= f.inputs do %>
40
+ # <%= f.input :nationality, :as => :country, :priority_countries => ["Australia", "New Zealand"] %>
41
+ # <% end %>
42
+ # <% end %>
43
+ #
44
+ # <li class='country'>
45
+ # <label for="user_nationality">Country</label>
46
+ # <select id="user_nationality" name="user[nationality]">
47
+ # <option value="...">...</option>
48
+ # # ...
49
+ # </li>
50
+ #
51
+ # @example `:priority_countries` set on a specific input (country_select 2.x)
52
+ #
53
+ # <%= semantic_form_for @user do |f| %>
54
+ # <%= f.inputs do %>
55
+ # <%= f.input :nationality, :as => :country, :priority_countries => ["AU", "NZ"] %>
56
+ # <% end %>
57
+ # <% end %>
58
+ #
59
+ # <li class='country'>
60
+ # <label for="user_nationality">Country</label>
61
+ # <select id="user_nationality" name="user[nationality]">
62
+ # <option value="...">...</option>
63
+ # # ...
64
+ # </li>
65
+ #
66
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
67
+ class CountryInput
68
+ include Base
69
+
70
+ CountrySelectPluginMissing = Class.new(StandardError)
71
+
72
+ def to_html
73
+ raise CountrySelectPluginMissing, "To use the :country input, please install a country_select plugin, like this one: https://github.com/stefanpenner/country_select" unless builder.respond_to?(:country_select)
74
+ input_wrapping do
75
+ label_html <<
76
+ builder.country_select(method, priority_countries, input_options, input_html_options)
77
+ end
78
+ end
79
+
80
+ def priority_countries
81
+ options[:priority_countries] || builder.priority_countries
82
+ end
83
+
84
+ end
85
+ end
86
+ end