formtastic 1.2.4 → 3.1.5

Sign up to get free protection for your applications and to get access to all the features.
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