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,260 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'string input' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ describe "when object is provided" do
14
+ before do
15
+ concat(semantic_form_for(@new_post) do |builder|
16
+ concat(builder.input(:title, :as => :string))
17
+ end)
18
+ end
19
+
20
+ it_should_have_input_wrapper_with_class(:string)
21
+ it_should_have_input_wrapper_with_class(:input)
22
+ it_should_have_input_wrapper_with_class(:stringish)
23
+ it_should_have_input_wrapper_with_id("post_title_input")
24
+ it_should_have_label_with_text(/Title/)
25
+ it_should_have_label_for("post_title")
26
+ it_should_have_input_with_id("post_title")
27
+ it_should_have_input_with_type(:text)
28
+ it_should_have_input_with_name("post[title]")
29
+ it_should_have_maxlength_matching_column_limit
30
+ it_should_use_default_text_field_size_when_not_nil(:string)
31
+ it_should_not_use_default_text_field_size_when_nil(:string)
32
+ it_should_apply_custom_input_attributes_when_input_html_provided(:string)
33
+ it_should_apply_custom_for_to_label_when_input_html_id_provided(:string)
34
+ it_should_apply_error_logic_for_input_type(:string)
35
+
36
+ def input_field_for_method_should_have_maxlength(method, maxlength)
37
+ concat(semantic_form_for(@new_post) do |builder|
38
+ concat(builder.input(method))
39
+ end)
40
+ output_buffer.should have_tag("form li input[@maxlength='#{maxlength}']")
41
+ end
42
+
43
+ describe 'and its a ActiveModel' do
44
+ let(:default_maxlength) { 50 }
45
+
46
+ before do
47
+ @new_post.stub(:class).and_return(::PostModel)
48
+ end
49
+
50
+ after do
51
+ @new_post.stub(:class).and_return(::Post)
52
+ end
53
+
54
+ describe 'and validates_length_of was called for the method' do
55
+ def should_have_maxlength(maxlength, options)
56
+ @new_post.class.should_receive(:validators_on).with(:title).at_least(1).and_return([
57
+ active_model_length_validator([:title], options[:options])
58
+ ])
59
+
60
+ concat(semantic_form_for(@new_post) do |builder|
61
+ concat(builder.input(:title))
62
+ end)
63
+
64
+ output_buffer.should have_tag("form li input##{@new_post.class.name.underscore}_title[@maxlength='#{maxlength}']")
65
+ end
66
+
67
+ it 'should have maxlength if the optional :if or :unless options are not supplied' do
68
+ should_have_maxlength(42, :options => {:maximum => 42})
69
+ end
70
+
71
+ it 'should have default maxlength if the optional :if condition is not satisifed' do
72
+ should_have_maxlength(default_maxlength, :options => {:maximum => 42, :if => false})
73
+ end
74
+
75
+ it 'should have default_maxlength if the optional :if proc evaluates to false' do
76
+ should_have_maxlength(default_maxlength, :options => {:maximum => 42, :if => proc { |record| false }})
77
+ end
78
+
79
+ it 'should have maxlength if the optional :if proc evaluates to true' do
80
+ should_have_maxlength(42, :options => { :maximum => 42, :if => proc { |record| true } })
81
+ end
82
+
83
+ it 'should have default maxlength if the optional :if with a method name evaluates to false' do
84
+ @new_post.should_receive(:specify_maxlength).at_least(1).and_return(false)
85
+ should_have_maxlength(default_maxlength, :options => { :maximum => 42, :if => :specify_maxlength })
86
+ end
87
+
88
+ it 'should have maxlength if the optional :if with a method name evaluates to true' do
89
+ @new_post.should_receive(:specify_maxlength).at_least(1).and_return(true)
90
+ should_have_maxlength(42, :options => { :maximum => 42, :if => :specify_maxlength })
91
+ end
92
+
93
+ it 'should have default maxlength if the optional :unless proc evaluates to true' do
94
+ should_have_maxlength(default_maxlength, :options => { :maximum => 42, :unless => proc { |record| true } })
95
+ end
96
+
97
+ it 'should have maxlength if the optional :unless proc evaluates to false' do
98
+ should_have_maxlength(42, :options => { :maximum => 42, :unless => proc { |record| false } })
99
+ end
100
+
101
+ it 'should have default maxlength if the optional :unless with a method name evaluates to true' do
102
+ @new_post.should_receive(:specify_maxlength).at_least(1).and_return(true)
103
+ should_have_maxlength(default_maxlength, :options => { :maximum => 42, :unless => :specify_maxlength })
104
+ end
105
+
106
+ it 'should have maxlength if the optional :unless with a method name evaluates to false' do
107
+ @new_post.should_receive(:specify_maxlength).at_least(1).and_return(false)
108
+ should_have_maxlength(42, :options => { :maximum => 42, :unless => :specify_maxlength })
109
+ end
110
+ end
111
+
112
+ describe 'any conditional validation' do
113
+ describe 'proc that calls an instance method' do
114
+ it 'calls the method on the object' do
115
+ @new_post.should_receive(:something?)
116
+ @new_post.class.should_receive(:validators_on).with(:title).at_least(1).and_return([
117
+ active_model_presence_validator([:title], { :unless => -> { something? } })
118
+ ])
119
+ concat(semantic_form_for(@new_post) do |builder|
120
+ concat(builder.input(:title))
121
+ end)
122
+ end
123
+ end
124
+
125
+ describe 'proc with arity that calls an instance method' do
126
+ it 'calls the method on the object' do
127
+ @new_post.should_receive(:something?)
128
+ @new_post.class.should_receive(:validators_on).with(:title).at_least(1).and_return([
129
+ active_model_presence_validator([:title], { :unless => ->(user) { user.something? } })
130
+ ])
131
+ concat(semantic_form_for(@new_post) do |builder|
132
+ concat(builder.input(:title))
133
+ end)
134
+ end
135
+ end
136
+
137
+ describe 'symbol method name' do
138
+ it 'calls the method on the object if the method exists' do
139
+ @new_post.should_receive(:something?)
140
+ @new_post.class.should_receive(:validators_on).with(:title).at_least(1).and_return([
141
+ active_model_presence_validator([:title], { :unless => :something? })
142
+ ])
143
+ concat(semantic_form_for(@new_post) do |builder|
144
+ concat(builder.input(:title))
145
+ end)
146
+ end
147
+ end
148
+
149
+ describe 'any other conditional' do
150
+ it 'does not raise an error' do
151
+ @conditional = double()
152
+ @new_post.class.should_receive(:validators_on).with(:title).at_least(1).and_return([
153
+ active_model_presence_validator([:title], { :unless => @conditional })
154
+ ])
155
+ concat(semantic_form_for(@new_post) do |builder|
156
+ concat(builder.input(:title))
157
+ end)
158
+ end
159
+ end
160
+
161
+ end
162
+
163
+ end
164
+ end
165
+
166
+ describe "when namespace is provided" do
167
+
168
+ before do
169
+ concat(semantic_form_for(@new_post, :namespace => 'context2') do |builder|
170
+ concat(builder.input(:title, :as => :string))
171
+ end)
172
+ end
173
+
174
+ it_should_have_input_wrapper_with_id("context2_post_title_input")
175
+ it_should_have_label_and_input_with_id("context2_post_title")
176
+
177
+ end
178
+
179
+ describe "when index is provided" do
180
+
181
+ before do
182
+ @output_buffer = ''
183
+ mock_everything
184
+
185
+ concat(semantic_form_for(@new_post) do |builder|
186
+ concat(builder.fields_for(:author, :index => 3) do |author|
187
+ concat(author.input(:name, :as => :string))
188
+ end)
189
+ end)
190
+ end
191
+
192
+ it 'should index the id of the wrapper' do
193
+ output_buffer.should have_tag("li#post_author_attributes_3_name_input")
194
+ end
195
+
196
+ it 'should index the id of the select tag' do
197
+ output_buffer.should have_tag("input#post_author_attributes_3_name")
198
+ end
199
+
200
+ it 'should index the name of the select tag' do
201
+ output_buffer.should have_tag("input[@name='post[author_attributes][3][name]']")
202
+ end
203
+
204
+ end
205
+
206
+
207
+ describe "when no object is provided" do
208
+ before do
209
+ concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
210
+ concat(builder.input(:title, :as => :string))
211
+ end)
212
+ end
213
+
214
+ it_should_have_label_with_text(/Title/)
215
+ it_should_have_label_for("project_title")
216
+ it_should_have_input_with_id("project_title")
217
+ it_should_have_input_with_type(:text)
218
+ it_should_have_input_with_name("project[title]")
219
+ end
220
+
221
+ describe "when size is nil" do
222
+ before do
223
+ concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
224
+ concat(builder.input(:title, :as => :string, :input_html => {:size => nil}))
225
+ end)
226
+ end
227
+
228
+ it "should have no size attribute" do
229
+ output_buffer.should_not have_tag("input[@size]")
230
+ end
231
+ end
232
+
233
+ describe "when required" do
234
+
235
+ context "and configured to use HTML5 attribute" do
236
+ it "should add the required attribute to the input's html options" do
237
+ with_config :use_required_attribute, true do
238
+ concat(semantic_form_for(@new_post) do |builder|
239
+ concat(builder.input(:title, :as => :string, :required => true))
240
+ end)
241
+ output_buffer.should have_tag("input[@required]")
242
+ end
243
+ end
244
+ end
245
+
246
+ context "and configured to not use HTML5 attribute" do
247
+ it "should add the required attribute to the input's html options" do
248
+ with_config :use_required_attribute, false do
249
+ concat(semantic_form_for(@new_post) do |builder|
250
+ concat(builder.input(:title, :as => :string, :required => true))
251
+ end)
252
+ output_buffer.should_not have_tag("input[@required]")
253
+ end
254
+ end
255
+ end
256
+
257
+ end
258
+
259
+ end
260
+
@@ -0,0 +1,187 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'text input' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+
12
+ concat(semantic_form_for(@new_post) do |builder|
13
+ concat(builder.input(:body, :as => :text))
14
+ end)
15
+ end
16
+
17
+ it_should_have_input_wrapper_with_class("text")
18
+ it_should_have_input_wrapper_with_class(:input)
19
+ it_should_have_input_wrapper_with_id("post_body_input")
20
+ it_should_have_label_with_text(/Body/)
21
+ it_should_have_label_for("post_body")
22
+ it_should_have_textarea_with_id("post_body")
23
+ it_should_have_textarea_with_name("post[body]")
24
+ it_should_apply_error_logic_for_input_type(:number)
25
+
26
+ it 'should use input_html to style inputs' do
27
+ output_buffer.replace ''
28
+ concat(semantic_form_for(@new_post) do |builder|
29
+ concat(builder.input(:title, :as => :text, :input_html => { :class => 'myclass' }))
30
+ end)
31
+ output_buffer.should have_tag("form li textarea.myclass")
32
+ end
33
+
34
+ it "should have a cols attribute when :cols is a number in :input_html" do
35
+ output_buffer.replace ''
36
+ concat(semantic_form_for(@new_post) do |builder|
37
+ concat(builder.input(:title, :as => :text, :input_html => { :cols => 42 }))
38
+ end)
39
+ output_buffer.should have_tag("form li textarea[@cols='42']")
40
+ end
41
+
42
+ it "should not have a cols attribute when :cols is nil in :input_html" do
43
+ output_buffer.replace ''
44
+ concat(semantic_form_for(@new_post) do |builder|
45
+ concat(builder.input(:title, :as => :text, :input_html => { :cols => nil }))
46
+ end)
47
+ output_buffer.should_not have_tag("form li textarea[@cols]")
48
+ end
49
+
50
+ it "should have a rows attribute when :rows is a number in :input_html" do
51
+ output_buffer.replace ''
52
+ concat(semantic_form_for(@new_post) do |builder|
53
+ concat(builder.input(:title, :as => :text, :input_html => { :rows => 42 }))
54
+ end)
55
+ output_buffer.should have_tag("form li textarea[@rows='42']")
56
+
57
+ end
58
+
59
+ it "should not have a rows attribute when :rows is nil in :input_html" do
60
+ output_buffer.replace ''
61
+ concat(semantic_form_for(@new_post) do |builder|
62
+ concat(builder.input(:title, :as => :text, :input_html => { :rows => nil }))
63
+ end)
64
+ output_buffer.should_not have_tag("form li textarea[@rows]")
65
+ end
66
+
67
+ describe "when namespace is provided" do
68
+
69
+ before do
70
+ @output_buffer = ''
71
+ mock_everything
72
+
73
+ concat(semantic_form_for(@new_post, :namespace => 'context2') do |builder|
74
+ concat(builder.input(:body, :as => :text))
75
+ end)
76
+ end
77
+
78
+ it_should_have_input_wrapper_with_id("context2_post_body_input")
79
+ it_should_have_textarea_with_id("context2_post_body")
80
+ it_should_have_label_for("context2_post_body")
81
+
82
+ end
83
+
84
+ describe "when index is provided" do
85
+
86
+ before do
87
+ @output_buffer = ''
88
+ mock_everything
89
+
90
+ concat(semantic_form_for(@new_post) do |builder|
91
+ concat(builder.fields_for(:author, :index => 3) do |author|
92
+ concat(author.input(:name, :as => :text))
93
+ end)
94
+ end)
95
+ end
96
+
97
+ it 'should index the id of the wrapper' do
98
+ output_buffer.should have_tag("li#post_author_attributes_3_name_input")
99
+ end
100
+
101
+ it 'should index the id of the select tag' do
102
+ output_buffer.should have_tag("textarea#post_author_attributes_3_name")
103
+ end
104
+
105
+ it 'should index the name of the select tag' do
106
+ output_buffer.should have_tag("textarea[@name='post[author_attributes][3][name]']")
107
+ end
108
+
109
+ end
110
+
111
+ context "when required" do
112
+ it "should add the required attribute to the input's html options" do
113
+ with_config :use_required_attribute, true do
114
+ concat(semantic_form_for(@new_post) do |builder|
115
+ concat(builder.input(:title, :as => :text, :required => true))
116
+ end)
117
+ output_buffer.should have_tag("textarea[@required]")
118
+ end
119
+ end
120
+ end
121
+
122
+ context "when :autofocus is provided in :input_html" do
123
+ before(:each) do
124
+ concat(semantic_form_for(@new_post) do |builder|
125
+ concat(builder.input(:title, :input_html => {:autofocus => true}))
126
+ end)
127
+ end
128
+
129
+ it_should_have_input_wrapper_with_class("autofocus")
130
+
131
+ it "should add the autofocus attribute to the input's html options" do
132
+ output_buffer.should have_tag("input[@autofocus]")
133
+ end
134
+ end
135
+
136
+ context "when :rows is missing in :input_html" do
137
+ before do
138
+ output_buffer.replace ''
139
+ end
140
+
141
+ it "should have a rows attribute matching default_text_area_height if numeric" do
142
+ with_config :default_text_area_height, 12 do
143
+ concat(semantic_form_for(@new_post) do |builder|
144
+ concat(builder.input(:title, :as => :text))
145
+ end)
146
+ output_buffer.should have_tag("form li textarea[@rows='12']")
147
+ end
148
+ end
149
+
150
+ it "should not have a rows attribute if default_text_area_height is nil" do
151
+ with_config :default_text_area_height, nil do
152
+ concat(semantic_form_for(@new_post) do |builder|
153
+ concat(builder.input(:title, :as => :text))
154
+ end)
155
+ output_buffer.should_not have_tag("form li textarea[@rows]")
156
+ end
157
+
158
+ end
159
+ end
160
+
161
+ context "when :cols is missing in :input_html" do
162
+ before do
163
+ output_buffer.replace ''
164
+ end
165
+
166
+ it "should have a cols attribute matching default_text_area_width if numeric" do
167
+ with_config :default_text_area_width, 10 do
168
+ concat(semantic_form_for(@new_post) do |builder|
169
+ concat(builder.input(:title, :as => :text))
170
+ end)
171
+ output_buffer.should have_tag("form li textarea[@cols='10']")
172
+ end
173
+ end
174
+
175
+ it "should not have a cols attribute if default_text_area_width is nil" do
176
+ with_config :default_text_area_width, nil do
177
+ concat(semantic_form_for(@new_post) do |builder|
178
+ concat(builder.input(:title, :as => :text))
179
+ end)
180
+ output_buffer.should_not have_tag("form li textarea[@cols]")
181
+ end
182
+
183
+ end
184
+ end
185
+
186
+ end
187
+
@@ -0,0 +1,455 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'time_picker input' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ context "with an object" do
14
+ before do
15
+ concat(semantic_form_for(@new_post) do |builder|
16
+ concat(builder.input(:publish_at, :as => :time_picker))
17
+ end)
18
+ end
19
+
20
+ it_should_have_input_wrapper_with_class(:time_picker)
21
+ it_should_have_input_wrapper_with_class(:input)
22
+ it_should_have_input_wrapper_with_class(:stringish)
23
+ it_should_have_input_wrapper_with_id("post_publish_at_input")
24
+ it_should_have_label_with_text(/Publish at/)
25
+ it_should_have_label_for("post_publish_at")
26
+ it_should_have_input_with_id("post_publish_at")
27
+ it_should_have_input_with_type(:time)
28
+ it_should_have_input_with_name("post[publish_at]")
29
+ it_should_apply_custom_input_attributes_when_input_html_provided(:date_picker)
30
+ it_should_apply_custom_for_to_label_when_input_html_id_provided(:date_picker)
31
+ # TODO why does this blow-up it_should_apply_error_logic_for_input_type(:date_picker)
32
+
33
+ end
34
+
35
+ describe "size attribute" do
36
+
37
+ it "defaults to 5 chars (HH:MM)" do
38
+ concat(
39
+ semantic_form_for(@new_post) do |f|
40
+ concat(f.input(:publish_at, :as => :time_picker))
41
+ end
42
+ )
43
+ output_buffer.should have_tag "input[size='5']"
44
+ end
45
+
46
+ it "can be set from :input_html options" do
47
+ concat(
48
+ semantic_form_for(@new_post) do |f|
49
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :size => "11" }))
50
+ end
51
+ )
52
+ output_buffer.should have_tag "input[size='11']"
53
+ end
54
+
55
+ it "can be set from options (ignoring input_html)" do
56
+ concat(
57
+ semantic_form_for(@new_post) do |f|
58
+ concat(f.input(:publish_at, :as => :time_picker, :size => '12', :input_html => { :size => "11" }))
59
+ end
60
+ )
61
+ output_buffer.should have_tag "input[size='12']"
62
+ end
63
+
64
+ end
65
+
66
+ describe "maxlength attribute" do
67
+
68
+ it "defaults to 5 chars (HH:MM:SS)" do
69
+ concat(
70
+ semantic_form_for(@new_post) do |f|
71
+ concat(f.input(:publish_at, :as => :time_picker))
72
+ end
73
+ )
74
+ output_buffer.should have_tag "input[maxlength='5']"
75
+ end
76
+
77
+ it "can be set from :input_html options" do
78
+ concat(
79
+ semantic_form_for(@new_post) do |f|
80
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :maxlength => "11" }))
81
+ end
82
+ )
83
+ output_buffer.should have_tag "input[maxlength='11']"
84
+ end
85
+
86
+ it "can be set from options (ignoring input_html)" do
87
+ concat(
88
+ semantic_form_for(@new_post) do |f|
89
+ concat(f.input(:publish_at, :as => :time_picker, :maxlength => 12, :input_html => { :maxlength => "11" }))
90
+ end
91
+ )
92
+ output_buffer.should have_tag "input[maxlength='12']"
93
+ end
94
+
95
+ end
96
+
97
+ describe "value attribute" do
98
+
99
+ context "when method returns nil" do
100
+
101
+ it "has no value" do
102
+ concat(
103
+ semantic_form_for(@new_post) do |f|
104
+ concat(f.input(:publish_at, :as => :time_picker ))
105
+ end
106
+ )
107
+ output_buffer.should_not have_tag "li input[value]"
108
+ end
109
+
110
+ it "can be set from :input_html options" do
111
+ concat(
112
+ semantic_form_for(@new_post) do |f|
113
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :value => "12:00" }))
114
+ end
115
+ )
116
+ output_buffer.should have_tag "input[value='12:00']"
117
+ end
118
+
119
+ end
120
+
121
+ context "when method returns a Date" do
122
+
123
+ before do
124
+ @date = Date.new(2000, 11, 11)
125
+ @new_post.stub(:publish_at).and_return(@date)
126
+ end
127
+
128
+ it "renders 00:00" do
129
+ concat(
130
+ semantic_form_for(@new_post) do |f|
131
+ concat(f.input(:publish_at, :as => :time_picker ))
132
+ end
133
+ )
134
+ output_buffer.should have_tag "input[value='00:00']"
135
+ end
136
+
137
+ it "can be set from :input_html options" do
138
+ concat(
139
+ semantic_form_for(@new_post) do |f|
140
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :value => "23:59" }))
141
+ end
142
+ )
143
+ output_buffer.should have_tag "input[value='23:59']"
144
+ end
145
+
146
+ end
147
+
148
+ context "when method returns a Time" do
149
+
150
+ before do
151
+ @time = Time.utc(2000,11,11,11,11,11)
152
+ @new_post.stub(:publish_at).and_return(@time)
153
+ end
154
+
155
+ it "renders the time as a HH:MM" do
156
+ concat(
157
+ semantic_form_for(@new_post) do |f|
158
+ concat(f.input(:publish_at, :as => :time_picker ))
159
+ end
160
+ )
161
+ output_buffer.should have_tag "input[value='11:11']"
162
+ end
163
+
164
+ it "can be set from :input_html options" do
165
+ concat(
166
+ semantic_form_for(@new_post) do |f|
167
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :value => "12:12" }))
168
+ end
169
+ )
170
+ output_buffer.should have_tag "input[value='12:12']"
171
+ end
172
+
173
+ end
174
+
175
+ context "when method returns an empty String" do
176
+
177
+ before do
178
+ @new_post.stub(:publish_at).and_return("")
179
+ end
180
+
181
+ it "will be empty" do
182
+ concat(
183
+ semantic_form_for(@new_post) do |f|
184
+ concat(f.input(:publish_at, :as => :time_picker ))
185
+ end
186
+ )
187
+ output_buffer.should have_tag "input[value='']"
188
+ end
189
+
190
+ it "can be set from :input_html options" do
191
+ concat(
192
+ semantic_form_for(@new_post) do |f|
193
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :value => "12:12:12" }))
194
+ end
195
+ )
196
+ output_buffer.should have_tag "input[value='12:12:12']"
197
+ end
198
+
199
+ end
200
+
201
+ context "when method returns a String" do
202
+
203
+ before do
204
+ @new_post.stub(:publish_at).and_return("yeah")
205
+ end
206
+
207
+ it "will be the string" do
208
+ concat(
209
+ semantic_form_for(@new_post) do |f|
210
+ concat(f.input(:publish_at, :as => :time_picker ))
211
+ end
212
+ )
213
+ output_buffer.should have_tag "input[value='yeah']"
214
+ end
215
+
216
+ it "can be set from :input_html options" do
217
+ concat(
218
+ semantic_form_for(@new_post) do |f|
219
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :value => "12:12:12" }))
220
+ end
221
+ )
222
+ output_buffer.should have_tag "input[value='12:12:12']"
223
+ end
224
+
225
+ end
226
+
227
+ end
228
+
229
+ describe "min attribute" do
230
+
231
+ it "will be omitted by default" do
232
+ concat(
233
+ semantic_form_for(@new_post) do |f|
234
+ concat(f.input(:publish_at, :as => :time_picker))
235
+ end
236
+ )
237
+ output_buffer.should_not have_tag "input[min]"
238
+ end
239
+
240
+ it "can be set from :input_html options" do
241
+ concat(
242
+ semantic_form_for(@new_post) do |f|
243
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :min => "13:00" }))
244
+ end
245
+ )
246
+ output_buffer.should have_tag "input[min='13:00']"
247
+ end
248
+
249
+ end
250
+
251
+ describe "max attribute" do
252
+
253
+ it "will be omitted by default" do
254
+ concat(
255
+ semantic_form_for(@new_post) do |f|
256
+ concat(f.input(:publish_at, :as => :time_picker))
257
+ end
258
+ )
259
+ output_buffer.should_not have_tag "input[max]"
260
+ end
261
+
262
+ it "can be set from :input_html options" do
263
+ concat(
264
+ semantic_form_for(@new_post) do |f|
265
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :max => "13:00" }))
266
+ end
267
+ )
268
+ output_buffer.should have_tag "input[max='13:00']"
269
+ end
270
+
271
+ end
272
+
273
+ describe "step attribute" do
274
+
275
+ it "defaults to 60 (seconds)" do
276
+ concat(
277
+ semantic_form_for(@new_post) do |f|
278
+ concat(f.input(:publish_at, :as => :time_picker))
279
+ end
280
+ )
281
+ output_buffer.should have_tag "input[step='60']"
282
+ end
283
+
284
+ it "can be set from :input_html options" do
285
+ concat(
286
+ semantic_form_for(@new_post) do |f|
287
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :step => "3600" }))
288
+ end
289
+ )
290
+ output_buffer.should have_tag "input[step='3600']"
291
+ end
292
+
293
+ describe "macros" do
294
+ before do
295
+ concat(
296
+ semantic_form_for(@new_post) do |f|
297
+ concat(f.input(:publish_at, :as => :date_picker, :input_html => { :step => step }))
298
+ end
299
+ )
300
+ end
301
+
302
+ context ":second" do
303
+ let(:step) { :second }
304
+ it "uses 1" do
305
+ output_buffer.should have_tag "input[step='1']"
306
+ end
307
+ end
308
+
309
+ context ":minute" do
310
+ let(:step) { :minute }
311
+ it "uses 60" do
312
+ output_buffer.should have_tag "input[step='60']"
313
+ end
314
+ end
315
+
316
+ context ":fifteen_minutes" do
317
+ let(:step) { :fifteen_minutes }
318
+ it "uses 900" do
319
+ output_buffer.should have_tag "input[step='900']"
320
+ end
321
+ end
322
+
323
+ context ":quarter_hour" do
324
+ let(:step) { :quarter_hour }
325
+ it "uses 900" do
326
+ output_buffer.should have_tag "input[step='900']"
327
+ end
328
+ end
329
+
330
+ context ":thirty_minutes" do
331
+ let(:step) { :thirty_minutes }
332
+ it "uses 1800" do
333
+ output_buffer.should have_tag "input[step='1800']"
334
+ end
335
+ end
336
+
337
+ context ":half_hour" do
338
+ let(:step) { :half_hour }
339
+ it "uses 1800" do
340
+ output_buffer.should have_tag "input[step='1800']"
341
+ end
342
+ end
343
+
344
+ context ":hour" do
345
+ let(:step) { :hour }
346
+ it "uses 3600" do
347
+ output_buffer.should have_tag "input[step='3600']"
348
+ end
349
+ end
350
+
351
+ context ":sixty_minutes" do
352
+ let(:step) { :sixty_minutes }
353
+ it "uses 3600" do
354
+ output_buffer.should have_tag "input[step='3600']"
355
+ end
356
+ end
357
+
358
+ end
359
+
360
+ end
361
+
362
+ describe "placeholder attribute" do
363
+
364
+ it "will be omitted" do
365
+ concat(
366
+ semantic_form_for(@new_post) do |f|
367
+ concat(f.input(:publish_at, :as => :time_picker))
368
+ end
369
+ )
370
+ output_buffer.should_not have_tag "input[placeholder]"
371
+ end
372
+
373
+ it "can be set from :input_html options" do
374
+ concat(
375
+ semantic_form_for(@new_post) do |f|
376
+ concat(f.input(:publish_at, :as => :time_picker, :input_html => { :placeholder => "HH:MM" }))
377
+ end
378
+ )
379
+ output_buffer.should have_tag "input[placeholder='HH:MM']"
380
+ end
381
+
382
+ context "with i18n set" do
383
+ before do
384
+ ::I18n.backend.store_translations :en, :formtastic => { :placeholders => { :publish_at => 'HH:MM' }}
385
+ end
386
+
387
+ it "can be set with i18n" do
388
+ with_config :i18n_lookups_by_default, true do
389
+ concat(semantic_form_for(@new_post) do |builder|
390
+ concat(builder.input(:publish_at, :as => :time_picker))
391
+ end)
392
+ output_buffer.should have_tag('input[@placeholder="HH:MM"]')
393
+ end
394
+ end
395
+
396
+ it "can be set with input_html, trumping i18n" do
397
+ with_config :i18n_lookups_by_default, true do
398
+ concat(semantic_form_for(@new_post) do |builder|
399
+ concat(builder.input(:publish_at, :as => :time_picker, :input_html => { :placeholder => "Something" }))
400
+ end)
401
+ output_buffer.should have_tag('input[@placeholder="Something"]')
402
+ end
403
+ end
404
+ end
405
+
406
+ end
407
+
408
+ describe "when namespace is provided" do
409
+ before do
410
+ concat(semantic_form_for(@new_post, :namespace => "context2") do |builder|
411
+ concat(builder.input(:publish_at, :as => :time_picker))
412
+ end)
413
+ end
414
+
415
+ it_should_have_input_wrapper_with_id("context2_post_publish_at_input")
416
+ it_should_have_label_and_input_with_id("context2_post_publish_at")
417
+ end
418
+
419
+ describe "when index is provided" do
420
+ before do
421
+ @output_buffer = ''
422
+ mock_everything
423
+
424
+ concat(semantic_form_for(@new_post) do |builder|
425
+ concat(builder.fields_for(:author, :index => 3) do |author|
426
+ concat(author.input(:created_at, :as => :time_picker))
427
+ end)
428
+ end)
429
+ end
430
+
431
+ it 'should index the id of the wrapper' do
432
+ output_buffer.should have_tag("li#post_author_attributes_3_created_at_input")
433
+ end
434
+
435
+ it 'should index the id of the select tag' do
436
+ output_buffer.should have_tag("input#post_author_attributes_3_created_at")
437
+ end
438
+
439
+ it 'should index the name of the select tag' do
440
+ output_buffer.should have_tag("input[@name='post[author_attributes][3][created_at]']")
441
+ end
442
+ end
443
+
444
+ describe "when required" do
445
+ it "should add the required attribute to the input's html options" do
446
+ with_config :use_required_attribute, true do
447
+ concat(semantic_form_for(@new_post) do |builder|
448
+ concat(builder.input(:publish_at, :as => :time_picker, :required => true))
449
+ end)
450
+ output_buffer.should have_tag("input[@required]")
451
+ end
452
+ end
453
+ end
454
+
455
+ end