formtastic 2.0.2 → 2.1.0.beta1

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 (116) hide show
  1. data/.gitignore +4 -1
  2. data/Appraisals +11 -0
  3. data/CHANGELOG +2 -2
  4. data/Gemfile +0 -2
  5. data/README.textile +183 -151
  6. data/Rakefile +9 -5
  7. data/app/assets/stylesheets/formtastic.css +16 -3
  8. data/formtastic.gemspec +6 -2
  9. data/gemfiles/rails-3.0.gemfile +7 -0
  10. data/gemfiles/rails-3.1.gemfile +7 -0
  11. data/gemfiles/rails-3.2.gemfile +7 -0
  12. data/lib/formtastic.rb +10 -2
  13. data/lib/formtastic/actions.rb +11 -0
  14. data/lib/formtastic/actions/base.rb +156 -0
  15. data/lib/formtastic/actions/button_action.rb +72 -0
  16. data/lib/formtastic/actions/buttonish.rb +17 -0
  17. data/lib/formtastic/actions/input_action.rb +68 -0
  18. data/lib/formtastic/actions/link_action.rb +87 -0
  19. data/lib/formtastic/engine.rb +5 -1
  20. data/lib/formtastic/form_builder.rb +3 -0
  21. data/lib/formtastic/helpers.rb +2 -1
  22. data/lib/formtastic/helpers/action_helper.rb +109 -0
  23. data/lib/formtastic/helpers/actions_helper.rb +168 -0
  24. data/lib/formtastic/helpers/buttons_helper.rb +22 -9
  25. data/lib/formtastic/helpers/errors_helper.rb +0 -54
  26. data/lib/formtastic/helpers/fieldset_wrapper.rb +10 -5
  27. data/lib/formtastic/helpers/form_helper.rb +2 -2
  28. data/lib/formtastic/helpers/input_helper.rb +1 -10
  29. data/lib/formtastic/helpers/inputs_helper.rb +6 -3
  30. data/lib/formtastic/i18n.rb +3 -2
  31. data/lib/formtastic/inputs/base.rb +11 -3
  32. data/lib/formtastic/inputs/base/choices.rb +6 -1
  33. data/lib/formtastic/inputs/base/collections.rb +36 -13
  34. data/lib/formtastic/inputs/base/grouped_collections.rb +1 -1
  35. data/lib/formtastic/inputs/base/numeric.rb +50 -0
  36. data/lib/formtastic/inputs/base/options.rb +1 -1
  37. data/lib/formtastic/inputs/base/placeholder.rb +17 -0
  38. data/lib/formtastic/inputs/base/stringish.rb +2 -7
  39. data/lib/formtastic/inputs/base/timeish.rb +21 -5
  40. data/lib/formtastic/inputs/base/validations.rb +1 -1
  41. data/lib/formtastic/inputs/base/wrapping.rb +10 -3
  42. data/lib/formtastic/inputs/boolean_input.rb +10 -2
  43. data/lib/formtastic/inputs/check_boxes_input.rb +18 -9
  44. data/lib/formtastic/inputs/country_input.rb +2 -2
  45. data/lib/formtastic/inputs/date_input.rb +19 -1
  46. data/lib/formtastic/inputs/datetime_input.rb +1 -1
  47. data/lib/formtastic/inputs/email_input.rb +2 -1
  48. data/lib/formtastic/inputs/file_input.rb +1 -1
  49. data/lib/formtastic/inputs/hidden_input.rb +1 -1
  50. data/lib/formtastic/inputs/number_input.rb +6 -36
  51. data/lib/formtastic/inputs/password_input.rb +2 -1
  52. data/lib/formtastic/inputs/phone_input.rb +3 -2
  53. data/lib/formtastic/inputs/radio_input.rb +1 -1
  54. data/lib/formtastic/inputs/range_input.rb +8 -32
  55. data/lib/formtastic/inputs/search_input.rb +2 -1
  56. data/lib/formtastic/inputs/select_input.rb +56 -28
  57. data/lib/formtastic/inputs/string_input.rb +3 -1
  58. data/lib/formtastic/inputs/text_input.rb +5 -4
  59. data/lib/formtastic/inputs/time_input.rb +4 -8
  60. data/lib/formtastic/inputs/time_zone_input.rb +1 -1
  61. data/lib/formtastic/inputs/url_input.rb +2 -1
  62. data/lib/formtastic/localized_string.rb +6 -94
  63. data/lib/formtastic/localizer.rb +110 -0
  64. data/lib/formtastic/version.rb +1 -1
  65. data/lib/generators/formtastic/form/form_generator.rb +105 -0
  66. data/lib/generators/templates/_form.html.erb +2 -2
  67. data/lib/generators/templates/_form.html.haml +4 -4
  68. data/lib/generators/templates/_form.html.slim +2 -2
  69. data/lib/generators/templates/formtastic.rb +4 -0
  70. data/lib/locale/en.yml +2 -0
  71. data/sample/basic_inputs.html +22 -0
  72. data/spec/actions/button_action_spec.rb +63 -0
  73. data/spec/actions/generic_action_spec.rb +484 -0
  74. data/spec/actions/input_action_spec.rb +59 -0
  75. data/spec/actions/link_action_spec.rb +92 -0
  76. data/spec/builder/semantic_fields_for_spec.rb +14 -0
  77. data/spec/generators/formtastic/form/form_generator_spec.rb +118 -0
  78. data/spec/generators/formtastic/install/install_generator_spec.rb +47 -0
  79. data/spec/helpers/action_helper_spec.rb +365 -0
  80. data/spec/helpers/actions_helper_spec.rb +143 -0
  81. data/spec/helpers/buttons_helper_spec.rb +39 -23
  82. data/spec/helpers/commit_button_helper_spec.rb +153 -93
  83. data/spec/helpers/inputs_helper_spec.rb +14 -0
  84. data/spec/i18n_spec.rb +11 -0
  85. data/spec/inputs/boolean_input_spec.rb +31 -2
  86. data/spec/inputs/check_boxes_input_spec.rb +29 -1
  87. data/spec/inputs/date_input_spec.rb +95 -0
  88. data/spec/inputs/datetime_input_spec.rb +49 -0
  89. data/spec/inputs/email_input_spec.rb +28 -0
  90. data/spec/inputs/file_input_spec.rb +28 -0
  91. data/spec/inputs/hidden_input_spec.rb +28 -0
  92. data/spec/inputs/include_blank_spec.rb +53 -45
  93. data/spec/inputs/number_input_spec.rb +34 -4
  94. data/spec/inputs/password_input_spec.rb +28 -0
  95. data/spec/inputs/phone_input_spec.rb +28 -0
  96. data/spec/inputs/placeholder_spec.rb +10 -10
  97. data/spec/inputs/radio_input_spec.rb +51 -6
  98. data/spec/inputs/range_input_spec.rb +30 -2
  99. data/spec/inputs/search_input_spec.rb +27 -0
  100. data/spec/inputs/select_input_spec.rb +52 -6
  101. data/spec/inputs/string_input_spec.rb +28 -0
  102. data/spec/inputs/text_input_spec.rb +27 -0
  103. data/spec/inputs/time_input_spec.rb +67 -1
  104. data/spec/inputs/time_zone_input_spec.rb +28 -0
  105. data/spec/inputs/url_input_spec.rb +28 -0
  106. data/spec/inputs/with_options_spec.rb +43 -0
  107. data/spec/spec_helper.rb +22 -6
  108. data/spec/support/custom_macros.rb +6 -134
  109. data/spec/support/test_environment.rb +0 -1
  110. metadata +104 -17
  111. data/lib/formtastic/helpers/semantic_form_helper.rb +0 -11
  112. data/lib/formtastic/inputs/numeric_input.rb +0 -21
  113. data/lib/formtastic/railtie.rb +0 -12
  114. data/lib/formtastic/semantic_form_builder.rb +0 -11
  115. data/spec/builder/errors_spec.rb +0 -203
  116. data/spec/inputs/numeric_input_spec.rb +0 -41
@@ -78,9 +78,9 @@ module Formtastic
78
78
  # @example Include seconds with times (excluded by default)
79
79
  # <%= f.input :publish_at, :as => :time, :include_seconds => true %>
80
80
  #
81
- # @example Specify if there should be a blank option at the start of each select or not
82
- # <%= f.input :publish_at, :as => :time, :include_blank=> true %>
83
- # <%= f.input :publish_at, :as => :time, :include_blank=> false %>
81
+ # @example Specify if there should be a blank option at the start of each select or not. Note that, unlike select inputs, :include_blank does not accept a string value.
82
+ # <%= f.input :publish_at, :as => :time, :include_blank => true %>
83
+ # <%= f.input :publish_at, :as => :time, :include_blank => false %>
84
84
  #
85
85
  # @todo Document i18n
86
86
  # @todo Check what other Rails options are supported (`start_year`, `end_year`, `use_month_numbers`, `use_short_month`, `add_month_numbers`, `prompt`), write tests for them, and otherwise support them
@@ -156,10 +156,18 @@ module Formtastic
156
156
  end
157
157
 
158
158
  def fragment_input_html(fragment)
159
- opts = input_options.merge(:prefix => object_name, :field_name => fragment_name(fragment), :default => value, :include_blank => include_blank?)
159
+ opts = input_options.merge(:prefix => fragment_prefix, :field_name => fragment_name(fragment), :default => value, :include_blank => include_blank?)
160
160
  template.send(:"select_#{fragment}", value, opts, input_html_options.merge(:id => fragment_id(fragment)))
161
161
  end
162
162
 
163
+ def fragment_prefix
164
+ if builder.options.key?(:index)
165
+ object_name + "[#{builder.options[:index]}]"
166
+ else
167
+ object_name
168
+ end
169
+ end
170
+
163
171
  # TODO extract to BlankOptions or similar -- Select uses similar code
164
172
  def include_blank?
165
173
  options.key?(:include_blank) ? options[:include_blank] : builder.include_blank_for_select_by_default
@@ -193,7 +201,7 @@ module Formtastic
193
201
  def fragments_label
194
202
  if render_label?
195
203
  template.content_tag(:legend,
196
- builder.label(method, label_text, :for => "#{input_html_options[:id]}_1i"),
204
+ builder.label(method, label_text, :for => fragment_id(fragments.first)),
197
205
  :class => "label"
198
206
  )
199
207
  else
@@ -211,6 +219,14 @@ module Formtastic
211
219
  "".html_safe
212
220
  end
213
221
 
222
+ def hidden_field_name(fragment)
223
+ if builder.options.key?(:index)
224
+ "#{object_name}[#{builder.options[:index]}][#{fragment_name(fragment)}]"
225
+ else
226
+ "#{object_name}[#{fragment_name(fragment)}]"
227
+ end
228
+ end
229
+
214
230
  end
215
231
  end
216
232
  end
@@ -108,7 +108,7 @@ module Formtastic
108
108
  validation.kind == :numericality
109
109
  end
110
110
  if validation
111
- validation.options[:step]
111
+ validation.options[:step] || (1 if validation_integer_only?)
112
112
  else
113
113
  nil
114
114
  end
@@ -14,9 +14,16 @@ module Formtastic
14
14
  end
15
15
 
16
16
  def wrapper_html_options
17
- opts = options[:wrapper_html] || {}
18
- opts[:class] ||= []
19
- opts[:class] = [opts[:class].to_s] unless opts[:class].is_a?(Array)
17
+ opts = (options[:wrapper_html] || {}).dup
18
+ opts[:class] =
19
+ case opts[:class]
20
+ when Array
21
+ opts[:class].dup
22
+ when nil
23
+ []
24
+ else
25
+ [opts[:class].to_s]
26
+ end
20
27
  opts[:class] << as
21
28
  opts[:class] << "input"
22
29
  opts[:class] << "error" if errors?
@@ -28,7 +28,7 @@ module Formtastic
28
28
  # @example Set the values for the checked and unchecked states
29
29
  # <%= f.input :published, :checked_value => "yes", :unchecked_value => "no" %>
30
30
  #
31
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
31
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
32
32
  class BooleanInput
33
33
  include Base
34
34
 
@@ -84,7 +84,15 @@ module Formtastic
84
84
  end
85
85
 
86
86
  def input_html_options
87
- {:name => "#{object_name}[#{method}]"}.merge(super)
87
+ {:name => input_html_options_name}.merge(super)
88
+ end
89
+
90
+ def input_html_options_name
91
+ if builder.options.key?(:index)
92
+ "#{object_name}[#{builder.options[:index]}][#{method}]"
93
+ else
94
+ "#{object_name}[#{method}]"
95
+ end
88
96
  end
89
97
 
90
98
  def checked?
@@ -73,7 +73,7 @@ module Formtastic
73
73
  # @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
74
74
  # <%= f.input :categories, :as => :check_boxes, :value_as_class => true %>
75
75
  #
76
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
76
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
77
77
  # @see Formtastic::Inputs::BooleanInput BooleanInput for a single checkbox for boolean (checked = true) inputs
78
78
  #
79
79
  # @todo Do/can we support the per-item HTML options like RadioInput?
@@ -152,13 +152,7 @@ module Formtastic
152
152
  end
153
153
 
154
154
  def selected_values
155
- if object.respond_to?(method)
156
- selected_items = [object.send(method)].compact.flatten
157
-
158
- [*selected_items.map { |o| send_or_call_or_object(value_method, o) }].compact
159
- else
160
- []
161
- end
155
+ @selected_values ||= make_selected_values
162
156
  end
163
157
 
164
158
  def disabled_values
@@ -172,9 +166,24 @@ module Formtastic
172
166
  end
173
167
 
174
168
  def input_name
175
- "#{object_name}[#{association_primary_key || method}][]"
169
+ if builder.options.key?(:index)
170
+ "#{object_name}[#{builder.options[:index]}][#{association_primary_key || method}][]"
171
+ else
172
+ "#{object_name}[#{association_primary_key || method}][]"
173
+ end
176
174
  end
177
175
 
176
+ protected
177
+
178
+ def make_selected_values
179
+ if object.respond_to?(method)
180
+ selected_items = [object.send(method)].compact.flatten
181
+
182
+ [*selected_items.map { |o| send_or_call_or_object(value_method, o) }].compact
183
+ else
184
+ []
185
+ end
186
+ end
178
187
  end
179
188
  end
180
189
  end
@@ -8,7 +8,7 @@ module Formtastic
8
8
  # * install any other country_select plugin that behaves in a similar way
9
9
  # * roll your own `country_select` helper with the same args and options as the Rails one
10
10
  #
11
- # By default, Formtastic includes a handfull of English-speaking countries as "priority
11
+ # By default, Formtastic includes a handful of English-speaking countries as "priority
12
12
  # counties", which can be set in the `priority_countries` configuration array in the
13
13
  # formtastic.rb initializer to suit your market and user base (see README for more info on
14
14
  # configuration). Additionally, it is possible to set the :priority_countries on a per-input
@@ -45,7 +45,7 @@ module Formtastic
45
45
  # # ...
46
46
  # </li>
47
47
  #
48
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
48
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
49
49
  class CountryInput
50
50
  include Base
51
51
 
@@ -2,7 +2,7 @@ module Formtastic
2
2
  module Inputs
3
3
  # Outputs a series of select boxes for the fragments that make up a date (year, month, day).
4
4
  #
5
- # @see Formtastic::Inputs::Timeish Timeish module for documetation of date, time and datetime input options.
5
+ # @see Formtastic::Inputs::Base::Timeish Timeish module for documentation of date, time and datetime input options.
6
6
  class DateInput
7
7
  include Base
8
8
  include Base::Timeish
@@ -11,6 +11,24 @@ module Formtastic
11
11
  def time_fragments
12
12
  []
13
13
  end
14
+
15
+ def hidden_date_fragments
16
+ default_date_fragments - date_fragments
17
+ end
18
+
19
+ def hidden_fragments
20
+ hidden_date_fragments.map do |fragment|
21
+ template.hidden_field_tag(hidden_field_name(fragment), fragment_value(fragment), :id => fragment_id(fragment), :disabled => input_html_options[:disabled] )
22
+ end.join.html_safe
23
+ end
24
+
25
+ def fragment_value(fragment)
26
+ if fragment == :year
27
+ Time.now.year
28
+ else
29
+ '1'
30
+ end
31
+ end
14
32
  end
15
33
  end
16
34
  end
@@ -3,7 +3,7 @@ module Formtastic
3
3
 
4
4
  # Outputs a series of select boxes for the fragments that make up a date and time (year, month, day, hour, minute, second).
5
5
  #
6
- # @see Formtastic::Inputs::Timeish Timeish module for documetation of date, time and datetime input options.
6
+ # @see Formtastic::Inputs::Base::Timeish Timeish module for documentation of date, time and datetime input options.
7
7
  class DatetimeInput
8
8
  include Base
9
9
  include Base::Timeish
@@ -24,10 +24,11 @@ module Formtastic
24
24
  # </fieldset>
25
25
  # </form>
26
26
  #
27
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
28
28
  class EmailInput
29
29
  include Base
30
30
  include Base::Stringish
31
+ include Base::Placeholder
31
32
 
32
33
  def to_html
33
34
  input_wrapping do
@@ -28,7 +28,7 @@ module Formtastic
28
28
  # </fieldset>
29
29
  # </form>
30
30
  #
31
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
31
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
32
32
  class FileInput
33
33
  include Base
34
34
  def to_html
@@ -27,7 +27,7 @@ module Formtastic
27
27
  #
28
28
  # form.formtastic li.hidden { display:none; }
29
29
  #
30
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
30
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
31
31
  class HiddenInput
32
32
  include Base
33
33
 
@@ -65,11 +65,12 @@ module Formtastic
65
65
  # <%= f.input :shoe_size, :as => :number, :in => 3..15, :step => 1 %>
66
66
  # <%= f.input :shoe_size, :as => :number, :input_html => { :in => 3..15, :step => 1 } %>
67
67
  #
68
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
68
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
69
69
  # @see http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of Rails' Numericality validation documentation
70
70
  class NumberInput
71
71
  include Base
72
- include Base::Stringish
72
+ include Base::Numeric
73
+ include Base::Placeholder
73
74
 
74
75
  def to_html
75
76
  input_wrapping do
@@ -77,42 +78,11 @@ module Formtastic
77
78
  builder.number_field(method, input_html_options)
78
79
  end
79
80
  end
80
-
81
- def input_html_options
82
- defaults = super
83
-
84
- if in_option
85
- defaults[:min] = in_option.to_a.min
86
- defaults[:max] = in_option.to_a.max
87
- else
88
- defaults[:min] ||= min_option
89
- defaults[:max] ||= max_option
90
- end
91
- defaults[:step] ||= step_option
92
- defaults
93
- end
94
-
81
+
95
82
  def step_option
96
- return options[:step] if options.key?(:step)
97
- return validation_step if validation_step
98
- return 1 if validation_integer_only?
99
- "any"
100
- end
101
-
102
- def min_option
103
- return options[:min] if options.key?(:min)
104
- validation_min
83
+ super || "any"
105
84
  end
106
-
107
- def max_option
108
- return options[:max] if options.key?(:max)
109
- validation_max
110
- end
111
-
112
- def in_option
113
- options[:in]
114
- end
115
-
85
+
116
86
  end
117
87
  end
118
88
  end
@@ -24,10 +24,11 @@ module Formtastic
24
24
  # </fieldset>
25
25
  # </form>
26
26
  #
27
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
28
28
  class PasswordInput
29
29
  include Base
30
30
  include Base::Stringish
31
+ include Base::Placeholder
31
32
 
32
33
  def to_html
33
34
  input_wrapping do
@@ -18,16 +18,17 @@ module Formtastic
18
18
  # <ol>
19
19
  # <li class="phone">
20
20
  # <label for="user_mobile">Mobile</label>
21
- # <input type="phone" id="user_mobile" name="user[mobile]">
21
+ # <input type="tel" id="user_mobile" name="user[mobile]">
22
22
  # </li>
23
23
  # </ol>
24
24
  # </fieldset>
25
25
  # </form>
26
26
  #
27
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
27
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
28
28
  class PhoneInput
29
29
  include Base
30
30
  include Base::Stringish
31
+ include Base::Placeholder
31
32
 
32
33
  def to_html
33
34
  input_wrapping do
@@ -114,7 +114,7 @@ module Formtastic
114
114
  # @example Set HTML options on a specific radio input option with a 3rd element in the array for a collection member
115
115
  # <%= f.input :author, :as => :radio, :collection => [["Test", 'test'], ["Try", "try", {:disabled => true}]]
116
116
  #
117
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
117
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
118
118
  # @see Formtastic::Inputs::RadioInput as an alternative for `belongs_to` associations
119
119
  #
120
120
  # @todo :disabled like CheckBoxes?
@@ -64,13 +64,12 @@ module Formtastic
64
64
  # <%= f.input :shoe_size, :as => :range, :in => 3..15, :step => 1 %>
65
65
  # <%= f.input :shoe_size, :as => :range, :input_html => { :in => 3..15, :step => 1 } %>
66
66
  #
67
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
67
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
68
68
  # @see http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of Rails' Numericality validation documentation
69
69
  #
70
- # @todo Is it still correct for this to be Stringish?
71
70
  class RangeInput
72
71
  include Base
73
- include Base::Stringish
72
+ include Base::Numeric
74
73
 
75
74
  def to_html
76
75
  input_wrapping do
@@ -78,40 +77,17 @@ module Formtastic
78
77
  builder.range_field(method, input_html_options)
79
78
  end
80
79
  end
81
-
82
- def input_html_options
83
- defaults = super
84
-
85
- if in_option
86
- defaults[:min] = in_option.to_a.min
87
- defaults[:max] = in_option.to_a.max
88
- else
89
- defaults[:min] ||= min_option
90
- defaults[:max] ||= max_option
91
- end
92
- defaults[:step] ||= step_option
93
- defaults
94
- end
95
-
96
- def step_option
97
- return options[:step] if options.key?(:step)
98
- return validation_step if validation_step
99
- return 1 if validation_integer_only?
100
- 1
101
- end
102
-
80
+
103
81
  def min_option
104
- return options[:min] if options.key?(:min)
105
- validation_min || 1
82
+ super || 1
106
83
  end
107
84
 
108
85
  def max_option
109
- return options[:max] if options.key?(:max)
110
- validation_max || 100
86
+ super || 100
111
87
  end
112
-
113
- def in_option
114
- options[:in]
88
+
89
+ def step_option
90
+ super || 1
115
91
  end
116
92
 
117
93
  end
@@ -23,10 +23,11 @@ module Formtastic
23
23
  # </fieldset>
24
24
  # </form>
25
25
  #
26
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
26
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
27
27
  class SearchInput
28
28
  include Base
29
29
  include Base::Stringish
30
+ include Base::Placeholder
30
31
 
31
32
  def to_html
32
33
  input_wrapping do
@@ -108,12 +108,12 @@ module Formtastic
108
108
  #
109
109
  # @example The `:member_label` can be used to call a different method (or a Proc) on each object in the collection for rendering the label text (it'll try the methods like `to_s` in `collection_label_methods` config by default)
110
110
  # <%= f.input :author, :as => :select, :member_label => :name %>
111
- # <%= f.input :author, :as => :select, :member_label => :name_with_post_count
112
- # <%= f.input :author, :as => :select, :member_label => Proc.new { |a| "#{c.name} (#{pluralize("post", a.posts.count)})" }
111
+ # <%= f.input :author, :as => :select, :member_label => :name_with_post_count %>
112
+ # <%= f.input :author, :as => :select, :member_label => Proc.new { |a| "#{c.name} (#{pluralize("post", a.posts.count)})" } %>
113
113
  #
114
114
  # @example The `:member_value` can be used to call a different method (or a Proc) on each object in the collection for rendering the value for each checkbox (it'll try the methods like `id` in `collection_value_methods` config by default)
115
115
  # <%= f.input :author, :as => :select, :member_value => :login %>
116
- # <%= f.input :author, :as => :select, :member_value => Proc.new { |c| c.full_name.downcase.underscore }
116
+ # <%= f.input :author, :as => :select, :member_value => Proc.new { |c| c.full_name.downcase.underscore } %>
117
117
  #
118
118
  # @example Set HTML attributes on the `<select>` tag with `:input_html`
119
119
  # <%= f.input :authors, :as => :select, :input_html => { :size => 20, :multiple => true, :class => "special" } %>
@@ -121,15 +121,21 @@ module Formtastic
121
121
  # @example Set HTML attributes on the `<li>` wrapper with `:wrapper_html`
122
122
  # <%= f.input :authors, :as => :select, :wrapper_html => { :class => "special" } %>
123
123
  #
124
- # @example Exclude or include the blank option at the top of the select, or change the prompt
125
- # <%= f.input :author, :as => :select, :input_html => { :include_blank => false } %>
126
- # <%= f.input :author, :as => :select, :input_html => { :include_blank => true } %>
127
- # <%= f.input :author, :as => :select, :input_html => { :prompt => "Please select an Author..." } %>
124
+ # @example Exclude, include, or customize the blank option at the top of the select. Always shown, even if the field already has a value. Suitable for optional inputs.
125
+ # <%= f.input :author, :as => :select, :include_blank => false %>
126
+ # <%= f.input :author, :as => :select, :include_blank => true %> => <option value=""></option>
127
+ # <%= f.input :author, :as => :select, :include_blank => "No author" %>
128
+ #
129
+ # @example Exclude, include, or customize the prompt at the top of the select. Only shown if the field does not have a value. Suitable for required inputs.
130
+ # <%= f.input :author, :as => :select, :prompt => false %>
131
+ # <%= f.input :author, :as => :select, :prompt => true %> => <option value="">Please select</option>
132
+ # <%= f.input :author, :as => :select, :prompt => "Please select an author" %>
133
+ #
128
134
  #
129
135
  # @example Group options an `<optgroup>` with the `:group_by` and `:group_label` options (`belongs_to` associations only)
130
136
  # <%= f.input :author, :as => :select, :group_by => :continent %>
131
137
  #
132
- # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documetation of all possible options.
138
+ # @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
133
139
  # @see Formtastic::Inputs::CheckBoxesInput CheckBoxesInput as an alternative for `has_many` and `has_and_belongs_to_many` associations
134
140
  # @see Formtastic::Inputs::RadioInput RadioInput as an alternative for `belongs_to` associations
135
141
  #
@@ -138,46 +144,56 @@ module Formtastic
138
144
  include Base
139
145
  include Base::Collections
140
146
  include Base::GroupedCollections
141
-
147
+
142
148
  def to_html
143
149
  input_wrapping do
150
+ hidden_input <<
144
151
  label_html <<
145
152
  (options[:group_by] ? grouped_select_html : select_html)
146
153
  end
147
154
  end
148
-
155
+
149
156
  def select_html
150
157
  builder.select(input_name, collection, input_options, input_html_options)
151
158
  end
152
-
159
+
153
160
  def grouped_select_html
154
161
  builder.grouped_collection_select(
155
- input_name,
162
+ input_name,
156
163
  grouped_collection,
157
- group_association,
164
+ group_association,
158
165
  group_label_method,
159
- value_method,
166
+ value_method,
160
167
  label_method,
161
- input_options,
168
+ input_options,
162
169
  input_html_options
163
170
  )
164
171
  end
172
+
173
+ def include_blank
174
+ options.key?(:include_blank) ? options[:include_blank] : (single? && builder.include_blank_for_select_by_default)
175
+ end
165
176
 
166
- def include_blank?
167
- return options[:prompt] if options.key?(:prompt)
168
- return options[:include_blank] if options.key?(:include_blank)
169
- return true if (single? && builder.include_blank_for_select_by_default)
170
- false
177
+ def hidden_input
178
+ if multiple?
179
+ template.hidden_field_tag(input_html_options_name_multiple, '', :id => nil)
180
+ else
181
+ "".html_safe
182
+ end
183
+ end
184
+
185
+ def prompt?
186
+ !!options[:prompt]
171
187
  end
172
188
 
173
189
  def label_html_options
174
190
  super.merge(:for => input_html_options[:id])
175
191
  end
176
-
192
+
177
193
  def input_options
178
- super.merge({:include_blank => include_blank?, :prompt => nil})
194
+ super.merge :include_blank => (include_blank unless prompt?)
179
195
  end
180
-
196
+
181
197
  def input_html_options
182
198
  extra_input_html_options.merge(super)
183
199
  end
@@ -185,22 +201,34 @@ module Formtastic
185
201
  def extra_input_html_options
186
202
  {
187
203
  :multiple => multiple?,
188
- :name => "#{object_name}[#{association_primary_key}]#{'[]' if multiple?}"
204
+ :name => multiple? ? input_html_options_name_multiple : input_html_options_name
189
205
  }
190
206
  end
191
207
 
208
+ def input_html_options_name
209
+ if builder.options.key?(:index)
210
+ "#{object_name}[#{builder.options[:index]}][#{association_primary_key}]"
211
+ else
212
+ "#{object_name}[#{association_primary_key}]"
213
+ end
214
+ end
215
+
216
+ def input_html_options_name_multiple
217
+ input_html_options_name + "[]"
218
+ end
219
+
192
220
  def multiple_by_association?
193
221
  reflection && [ :has_many, :has_and_belongs_to_many ].include?(reflection.macro)
194
222
  end
195
-
223
+
196
224
  def multiple_by_options?
197
225
  options[:multiple] || (options[:input_html] && options[:input_html][:multiple])
198
226
  end
199
-
227
+
200
228
  def multiple?
201
- multiple_by_options? || multiple_by_association?
229
+ multiple_by_options? || multiple_by_association?
202
230
  end
203
-
231
+
204
232
  def single?
205
233
  !multiple?
206
234
  end