ShadowBelmolve-formtastic 0.2.1 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.textile +191 -176
  2. data/Rakefile +65 -22
  3. data/generators/form/USAGE +16 -0
  4. data/generators/form/form_generator.rb +120 -0
  5. data/generators/form/templates/view__form.html.erb +5 -0
  6. data/generators/form/templates/view__form.html.haml +4 -0
  7. data/generators/formtastic/formtastic_generator.rb +24 -0
  8. data/generators/{formtastic_stylesheets → formtastic}/templates/formtastic.css +2 -0
  9. data/generators/formtastic/templates/formtastic.rb +51 -0
  10. data/generators/{formtastic_stylesheets → formtastic}/templates/formtastic_changes.css +0 -0
  11. data/generators/formtastic_stylesheets/formtastic_stylesheets_generator.rb +5 -10
  12. data/lib/formtastic.rb +1234 -895
  13. data/lib/formtastic/i18n.rb +32 -0
  14. data/lib/locale/en.yml +2 -2
  15. data/rails/init.rb +1 -1
  16. data/spec/buttons_spec.rb +149 -0
  17. data/spec/commit_button_spec.rb +344 -0
  18. data/spec/custom_builder_spec.rb +62 -0
  19. data/spec/custom_macros.rb +561 -0
  20. data/spec/defaults_spec.rb +20 -0
  21. data/spec/error_proc_spec.rb +27 -0
  22. data/spec/errors_spec.rb +85 -0
  23. data/spec/form_helper_spec.rb +120 -0
  24. data/spec/i18n_spec.rb +131 -0
  25. data/spec/include_blank_spec.rb +70 -0
  26. data/spec/input_spec.rb +608 -0
  27. data/spec/inputs/boolean_input_spec.rb +93 -0
  28. data/spec/inputs/check_boxes_input_spec.rb +162 -0
  29. data/spec/inputs/country_input_spec.rb +80 -0
  30. data/spec/inputs/date_input_spec.rb +45 -0
  31. data/spec/inputs/datetime_input_spec.rb +155 -0
  32. data/spec/inputs/file_input_spec.rb +33 -0
  33. data/spec/inputs/hidden_input_spec.rb +52 -0
  34. data/spec/inputs/numeric_input_spec.rb +44 -0
  35. data/spec/inputs/password_input_spec.rb +46 -0
  36. data/spec/inputs/radio_input_spec.rb +149 -0
  37. data/spec/inputs/select_input_spec.rb +459 -0
  38. data/spec/inputs/string_input_spec.rb +47 -0
  39. data/spec/inputs/text_input_spec.rb +33 -0
  40. data/spec/inputs/time_input_spec.rb +44 -0
  41. data/spec/inputs/time_zone_input_spec.rb +102 -0
  42. data/spec/inputs_spec.rb +395 -0
  43. data/spec/label_spec.rb +48 -0
  44. data/spec/nested_forms_spec.rb +50 -0
  45. data/spec/semantic_fields_for_spec.rb +44 -0
  46. data/spec/spec.opts +2 -0
  47. data/spec/spec_helper.rb +212 -0
  48. metadata +121 -16
  49. data/lib/justin_french/formtastic.rb +0 -10
  50. data/spec/formtastic_spec.rb +0 -3072
  51. data/spec/test_helper.rb +0 -14
@@ -1,10 +0,0 @@
1
- module JustinFrench #:nodoc:
2
- module Formtastic #:nodoc:
3
- class SemanticFormBuilder < ::Formtastic::SemanticFormBuilder #:nodoc:
4
- def initialize(*args)
5
- ::ActiveSupport::Deprecation.warn("JustinFrench::Formtastic::SemanticFormBuilder is deprecated. User Formtastic::SemanticFormBuilder instead", caller)
6
- super
7
- end
8
- end
9
- end
10
- end
@@ -1,3072 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
- require 'formtastic'
3
-
4
- module FormtasticSpecHelper
5
- def default_input_type(column_type, column_name = :generic_column_name)
6
- @new_post.stub!(column_name)
7
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => column_type)) unless column_type.nil?
8
-
9
- semantic_form_for(@new_post) do |builder|
10
- @default_type = builder.send(:default_input_type, column_name)
11
- end
12
-
13
- return @default_type
14
- end
15
- end
16
-
17
- describe 'Formtastic' do
18
-
19
- include ActionView::Helpers::FormHelper
20
- include ActionView::Helpers::FormTagHelper
21
- include ActionView::Helpers::FormOptionsHelper
22
- include ActionView::Helpers::UrlHelper
23
- include ActionView::Helpers::TagHelper
24
- include ActionView::Helpers::TextHelper
25
- include ActionView::Helpers::ActiveRecordHelper
26
- include ActionView::Helpers::RecordIdentificationHelper
27
- include ActionView::Helpers::DateHelper
28
- include ActionView::Helpers::CaptureHelper
29
- include ActiveSupport
30
- include ActionController::PolymorphicRoutes
31
-
32
- include Formtastic::SemanticFormHelper
33
-
34
- attr_accessor :output_buffer
35
-
36
- def protect_against_forgery?; false; end
37
-
38
- before do
39
- Formtastic::SemanticFormBuilder.label_str_method = :humanize
40
-
41
- @output_buffer = ''
42
-
43
- # Resource-oriented styles like form_for(@post) will expect a path method for the object,
44
- # so we're defining some here.
45
- def post_path(o); "/posts/1"; end
46
- def posts_path; "/posts"; end
47
- def new_post_path; "/posts/new"; end
48
-
49
- def author_path(o); "/authors/1"; end
50
- def authors_path; "/authors"; end
51
- def new_author_path; "/authors/new"; end
52
-
53
- # Sometimes we need some classes
54
- class Post;
55
- def id; end
56
- end
57
- class Author; end
58
-
59
- @fred = mock('user')
60
- @fred.stub!(:class).and_return(Author)
61
- @fred.stub!(:to_label).and_return('Fred Smith')
62
- @fred.stub!(:login).and_return('fred_smith')
63
- @fred.stub!(:id).and_return(37)
64
- @fred.stub!(:new_record?).and_return(false)
65
- @fred.stub!(:errors).and_return(mock('errors', :[] => nil))
66
-
67
- @bob = mock('user')
68
- @bob.stub!(:class).and_return(Author)
69
- @bob.stub!(:to_label).and_return('Bob Rock')
70
- @bob.stub!(:login).and_return('bob')
71
- @bob.stub!(:id).and_return(42)
72
- @bob.stub!(:posts).and_return([])
73
- @bob.stub!(:post_ids).and_return([])
74
- @bob.stub!(:new_record?).and_return(false)
75
- @bob.stub!(:errors).and_return(mock('errors', :[] => nil))
76
-
77
- Author.stub!(:find).and_return([@fred, @bob])
78
- Author.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
79
- Author.stub!(:human_name).and_return('Author')
80
- Author.stub!(:reflect_on_all_validations).and_return([])
81
- Author.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Post, :macro => :has_many) if column_name == :posts }
82
-
83
- # Sometimes we need a mock @post object and some Authors for belongs_to
84
- @new_post = mock('post')
85
- @new_post.stub!(:class).and_return(Post)
86
- @new_post.stub!(:id).and_return(nil)
87
- @new_post.stub!(:new_record?).and_return(true)
88
- @new_post.stub!(:errors).and_return(mock('errors', :[] => nil))
89
- @new_post.stub!(:author).and_return(nil)
90
-
91
- @freds_post = mock('post')
92
- @freds_post.stub!(:class).and_return(Post)
93
- @freds_post.stub!(:to_label).and_return('Fred Smith')
94
- @freds_post.stub!(:id).and_return(19)
95
- @freds_post.stub!(:author).and_return(@fred)
96
- @freds_post.stub!(:author_id).and_return(@fred.id)
97
- @freds_post.stub!(:authors).and_return([@fred])
98
- @freds_post.stub!(:author_ids).and_return([@fred.id])
99
- @freds_post.stub!(:new_record?).and_return(false)
100
- @freds_post.stub!(:errors).and_return(mock('errors', :[] => nil))
101
- @fred.stub!(:posts).and_return([@freds_post])
102
- @fred.stub!(:post_ids).and_return([@freds_post.id])
103
-
104
- Post.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
105
- Post.stub!(:human_name).and_return('Post')
106
- Post.stub!(:reflect_on_all_validations).and_return([])
107
- Post.stub!(:reflect_on_association).and_return do |column_name|
108
- case column_name
109
- when :author, :author_status
110
- mock('reflection', :options => {}, :klass => Author, :macro => :belongs_to)
111
- when :authors
112
- mock('reflection', :options => {}, :klass => Author, :macro => :has_and_belongs_to_many)
113
- end
114
- end
115
- Post.stub!(:find).and_return([@freds_post])
116
- end
117
-
118
- describe 'JustinFrench::Formtastic::SemanticFormBuilder' do
119
- require 'justin_french/formtastic'
120
- it 'should be deprecated' do
121
- ::ActiveSupport::Deprecation.should_receive(:warn).with(/JustinFrench\:\:Formtastic\:\:SemanticFormBuilder/, anything())
122
- form_for(@new_post, :builder => JustinFrench::Formtastic::SemanticFormBuilder) do |builder|
123
- end
124
- end
125
- end
126
-
127
- describe 'SemanticFormHelper' do
128
-
129
- describe '#semantic_form_for' do
130
-
131
- it 'yields an instance of SemanticFormBuilder' do
132
- semantic_form_for(:post, Post.new, :url => '/hello') do |builder|
133
- builder.class.should == Formtastic::SemanticFormBuilder
134
- end
135
- end
136
-
137
- it 'adds a class of "formtastic" to the generated form' do
138
- semantic_form_for(:post, Post.new, :url => '/hello') do |builder|
139
- end
140
- output_buffer.should have_tag("form.formtastic")
141
- end
142
-
143
- it 'adds class matching the object name to the generated form when a symbol is provided' do
144
- semantic_form_for(:post, Post.new, :url => '/hello') do |builder|
145
- end
146
- output_buffer.should have_tag("form.post")
147
-
148
- semantic_form_for(:project, :url => '/hello') do |builder|
149
- end
150
- output_buffer.should have_tag("form.project")
151
- end
152
-
153
- it 'adds class matching the object\'s class to the generated form when an object is provided' do
154
- semantic_form_for(@new_post) do |builder|
155
- end
156
- output_buffer.should have_tag("form.post")
157
- end
158
-
159
- describe 'allows :html options' do
160
- before(:each) do
161
- semantic_form_for(:post, Post.new, :url => '/hello', :html => { :id => "something-special", :class => "something-extra", :multipart => true }) do |builder|
162
- end
163
- end
164
-
165
- it 'to add a id of "something-special" to generated form' do
166
- output_buffer.should have_tag("form#something-special")
167
- end
168
-
169
- it 'to add a class of "something-extra" to generated form' do
170
- output_buffer.should have_tag("form.something-extra")
171
- end
172
-
173
- it 'to add enctype="multipart/form-data"' do
174
- output_buffer.should have_tag('form[@enctype="multipart/form-data"]')
175
- end
176
- end
177
-
178
- it 'can be called with a resource-oriented style' do
179
- semantic_form_for(@new_post) do |builder|
180
- builder.object.class.should == Post
181
- builder.object_name.should == "post"
182
- end
183
- end
184
-
185
- it 'can be called with a generic style and instance variable' do
186
- semantic_form_for(:post, @new_post, :url => new_post_path) do |builder|
187
- builder.object.class.should == Post
188
- builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
189
- end
190
- end
191
-
192
- it 'can be called with a generic style and inline object' do
193
- semantic_form_for(:post, Post.new, :url => new_post_path) do |builder|
194
- builder.object.class.should == Post
195
- builder.object_name.to_s.should == "post" # TODO: is this forced .to_s a bad assumption somewhere?
196
- end
197
- end
198
-
199
- end
200
-
201
- describe '#semantic_fields_for' do
202
- it 'yields an instance of SemanticFormBuilder' do
203
- semantic_fields_for(:post, Post.new, :url => '/hello') do |builder|
204
- builder.class.should == Formtastic::SemanticFormBuilder
205
- end
206
- end
207
- end
208
-
209
- describe '#semantic_form_remote_for' do
210
- it 'yields an instance of SemanticFormBuilder' do
211
- semantic_form_remote_for(:post, Post.new, :url => '/hello') do |builder|
212
- builder.class.should == Formtastic::SemanticFormBuilder
213
- end
214
- end
215
- end
216
-
217
- describe '#semantic_form_for_remote' do
218
- it 'yields an instance of SemanticFormBuilder' do
219
- semantic_form_remote_for(:post, Post.new, :url => '/hello') do |builder|
220
- builder.class.should == Formtastic::SemanticFormBuilder
221
- end
222
- end
223
- end
224
-
225
- end
226
-
227
- describe 'SemanticFormBuilder' do
228
-
229
- include FormtasticSpecHelper
230
-
231
- describe "@@builder" do
232
- before do
233
- @new_post.stub!(:title)
234
- @new_post.stub!(:body)
235
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
236
- end
237
-
238
- after do
239
- Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
240
- end
241
-
242
- it "can be overridden" do
243
-
244
- class CustomFormBuilder < Formtastic::SemanticFormBuilder
245
- def custom(arg1, arg2, options = {})
246
- [arg1, arg2, options]
247
- end
248
- end
249
-
250
- Formtastic::SemanticFormHelper.builder = CustomFormBuilder
251
-
252
- semantic_form_for(@new_post) do |builder|
253
- builder.class.should == CustomFormBuilder
254
- builder.custom("one", "two").should == ["one", "two", {}]
255
- end
256
- end
257
-
258
- end
259
-
260
- describe 'Formtastic::SemanticFormBuilder#semantic_fields_for' do
261
- before do
262
- @new_post.stub!(:author).and_return(Author.new)
263
- end
264
-
265
- it 'yields an instance of SemanticFormBuilder' do
266
- semantic_form_for(@new_post) do |builder|
267
- builder.semantic_fields_for(:author) do |nested_builder|
268
- nested_builder.class.should == Formtastic::SemanticFormBuilder
269
- end
270
- end
271
- end
272
-
273
- it 'nests the object name' do
274
- semantic_form_for(@new_post) do |builder|
275
- builder.semantic_fields_for(@bob) do |nested_builder|
276
- nested_builder.object_name.should == 'post[author]'
277
- end
278
- end
279
- end
280
-
281
- it 'should sanitize html id for li tag' do
282
- @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
283
- semantic_form_for(@new_post) do |builder|
284
- builder.semantic_fields_for(@bob, :index => 1) do |nested_builder|
285
- concat(nested_builder.inputs(:login))
286
- end
287
- end
288
- output_buffer.should have_tag('form fieldset.inputs #post_author_1_login_input')
289
- output_buffer.should_not have_tag('form fieldset.inputs #post[author]_1_login_input')
290
- end
291
- end
292
-
293
- describe '#label' do
294
- it 'should humanize the given attribute' do
295
- semantic_form_for(@new_post) do |builder|
296
- builder.label(:login).should have_tag('label', :with => /Login/)
297
- end
298
- end
299
-
300
- it 'should be printed as span' do
301
- semantic_form_for(@new_post) do |builder|
302
- builder.label(:login, nil, { :required => true, :as_span => true }).should have_tag('span.label abbr')
303
- end
304
- end
305
-
306
- describe 'when required is given' do
307
- it 'should append a required note' do
308
- semantic_form_for(@new_post) do |builder|
309
- builder.label(:login, nil, :required => true).should have_tag('label abbr')
310
- end
311
- end
312
-
313
- it 'should allow require option to be given as second argument' do
314
- semantic_form_for(@new_post) do |builder|
315
- builder.label(:login, :required => true).should have_tag('label abbr')
316
- end
317
- end
318
- end
319
-
320
- describe 'when label is given' do
321
- it 'should allow the text to be given as label option' do
322
- semantic_form_for(@new_post) do |builder|
323
- builder.label(:login, :required => true, :label => 'My label').should have_tag('label', :with => /My label/)
324
- end
325
- end
326
-
327
- it 'should return nil if label is false' do
328
- semantic_form_for(@new_post) do |builder|
329
- builder.label(:login, :label => false).should be_blank
330
- end
331
- end
332
- end
333
- end
334
-
335
- describe '#errors_on' do
336
- before(:each) do
337
- @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
338
- @errors = mock('errors')
339
- @errors.stub!(:[]).with(:title).and_return(@title_errors)
340
- @errors.stub!(:[]).with(:body).and_return(nil)
341
- @new_post.stub!(:errors).and_return(@errors)
342
- end
343
-
344
- describe 'and the errors will be displayed as a sentence' do
345
- it 'should render a paragraph with the errors joined into a sentence' do
346
- Formtastic::SemanticFormBuilder.inline_errors = :sentence
347
- semantic_form_for(@new_post) do |builder|
348
- builder.errors_on(:title).should have_tag('p.inline-errors', @title_errors.to_sentence)
349
- end
350
- end
351
- end
352
-
353
- describe 'and the errors will be displayed as a list' do
354
- it 'should render an unordered list with the class errors' do
355
- Formtastic::SemanticFormBuilder.inline_errors = :list
356
- semantic_form_for(@new_post) do |builder|
357
- builder.errors_on(:title).should have_tag('ul.errors')
358
- end
359
- end
360
-
361
- it 'should include a list element for each of the errors within the unordered list' do
362
- Formtastic::SemanticFormBuilder.inline_errors = :list
363
- semantic_form_for(@new_post) do |builder|
364
- @title_errors.each do |error|
365
- builder.errors_on(:title).should have_tag('ul.errors li', error)
366
- end
367
- end
368
- end
369
- end
370
-
371
- describe 'but the errors will not be shown' do
372
- it 'should return nil' do
373
- Formtastic::SemanticFormBuilder.inline_errors = :none
374
- semantic_form_for(@new_post) do |builder|
375
- builder.errors_on(:title).should be_nil
376
- end
377
- end
378
- end
379
-
380
- describe 'and no error is found on the method' do
381
- it 'should return nil' do
382
- Formtastic::SemanticFormBuilder.inline_errors = :sentence
383
- semantic_form_for(@new_post) do |builder|
384
- builder.errors_on(:body).should be_nil
385
- end
386
- end
387
- end
388
- end
389
-
390
- describe '#input' do
391
-
392
- before do
393
- @new_post.stub!(:title)
394
- @new_post.stub!(:body)
395
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
396
- end
397
-
398
- describe 'with inline order customization' do
399
- it 'should allow input, hints, errors as order' do
400
- Formtastic::SemanticFormBuilder.inline_order = [:input, :hints, :errors]
401
-
402
- semantic_form_for(@new_post) do |builder|
403
- builder.should_receive(:inline_input_for).once.ordered
404
- builder.should_receive(:inline_hints_for).once.ordered
405
- builder.should_receive(:inline_errors_for).once.ordered
406
- concat(builder.input(:title))
407
- end
408
- end
409
-
410
- it 'should allow hints, input, errors as order' do
411
- Formtastic::SemanticFormBuilder.inline_order = [:hints, :input, :errors]
412
-
413
- semantic_form_for(@new_post) do |builder|
414
- builder.should_receive(:inline_hints_for).once.ordered
415
- builder.should_receive(:inline_input_for).once.ordered
416
- builder.should_receive(:inline_errors_for).once.ordered
417
- concat(builder.input(:title))
418
- end
419
- end
420
- end
421
-
422
- describe 'arguments and options' do
423
-
424
- it 'should require the first argument (the method on form\'s object)' do
425
- lambda {
426
- semantic_form_for(@new_post) do |builder|
427
- concat(builder.input()) # no args passed in at all
428
- end
429
- }.should raise_error(ArgumentError)
430
- end
431
-
432
- describe ':required option' do
433
-
434
- describe 'when true' do
435
-
436
- before do
437
- @string = Formtastic::SemanticFormBuilder.required_string = " required yo!" # ensure there's something in the string
438
- @new_post.class.should_not_receive(:reflect_on_all_validations)
439
- end
440
-
441
- after do
442
- Formtastic::SemanticFormBuilder.required_string = %{<abbr title="required">*</abbr>}
443
- end
444
-
445
- it 'should set a "required" class' do
446
- semantic_form_for(@new_post) do |builder|
447
- concat(builder.input(:title, :required => true))
448
- end
449
- output_buffer.should_not have_tag('form li.optional')
450
- output_buffer.should have_tag('form li.required')
451
- end
452
-
453
- it 'should append the "required" string to the label' do
454
- semantic_form_for(@new_post) do |builder|
455
- concat(builder.input(:title, :required => true))
456
- end
457
- output_buffer.should have_tag('form li.required label', /#{@string}$/)
458
- end
459
-
460
- end
461
-
462
- describe 'when false' do
463
-
464
- before do
465
- @string = Formtastic::SemanticFormBuilder.optional_string = " optional yo!" # ensure there's something in the string
466
- @new_post.class.should_not_receive(:reflect_on_all_validations)
467
- end
468
-
469
- after do
470
- Formtastic::SemanticFormBuilder.optional_string = ''
471
- end
472
-
473
- it 'should set an "optional" class' do
474
- semantic_form_for(@new_post) do |builder|
475
- concat(builder.input(:title, :required => false))
476
- end
477
- output_buffer.should_not have_tag('form li.required')
478
- output_buffer.should have_tag('form li.optional')
479
- end
480
-
481
- it 'should append the "optional" string to the label' do
482
- semantic_form_for(@new_post) do |builder|
483
- concat(builder.input(:title, :required => false))
484
- end
485
- output_buffer.should have_tag('form li.optional label', /#{@string}$/)
486
- end
487
-
488
- end
489
-
490
- describe 'when not provided' do
491
-
492
- describe 'and an object was not given' do
493
-
494
- it 'should use the default value' do
495
- Formtastic::SemanticFormBuilder.all_fields_required_by_default.should == true
496
- Formtastic::SemanticFormBuilder.all_fields_required_by_default = false
497
-
498
- semantic_form_for(:project, :url => 'http://test.host/') do |builder|
499
- concat(builder.input(:title))
500
- end
501
- output_buffer.should_not have_tag('form li.required')
502
- output_buffer.should have_tag('form li.optional')
503
-
504
- Formtastic::SemanticFormBuilder.all_fields_required_by_default = true
505
- end
506
-
507
- end
508
-
509
- describe 'and an object was given' do
510
-
511
- describe 'and the validation reflection plugin is available' do
512
-
513
- before do
514
- @new_post.class.stub!(:method_defined?).with(:reflect_on_all_validations).and_return(true)
515
- end
516
-
517
- describe 'and validates_presence_of was called for the method' do
518
- before do
519
- @new_post.class.should_receive(:reflect_on_all_validations).and_return([
520
- mock('MacroReflection', :macro => :validates_presence_of, :name => :title)
521
- ])
522
- end
523
-
524
- it 'should be required' do
525
- semantic_form_for(@new_post) do |builder|
526
- concat(builder.input(:title))
527
- end
528
- output_buffer.should have_tag('form li.required')
529
- output_buffer.should_not have_tag('form li.optional')
530
- end
531
- end
532
-
533
- describe 'and validates_presence_of was not called for the method' do
534
- before do
535
- @new_post.class.should_receive(:reflect_on_all_validations).and_return([])
536
- end
537
-
538
- it 'should not be required' do
539
- semantic_form_for(@new_post) do |builder|
540
- concat(builder.input(:title))
541
- end
542
- output_buffer.should_not have_tag('form li.required')
543
- output_buffer.should have_tag('form li.optional')
544
- end
545
- end
546
-
547
- end
548
-
549
- describe 'and the validation reflection plugin is not available' do
550
-
551
- it 'should use the default value' do
552
- Formtastic::SemanticFormBuilder.all_fields_required_by_default.should == true
553
- Formtastic::SemanticFormBuilder.all_fields_required_by_default = false
554
-
555
- semantic_form_for(@new_post) do |builder|
556
- concat(builder.input(:title))
557
- end
558
- output_buffer.should_not have_tag('form li.required')
559
- output_buffer.should have_tag('form li.optional')
560
-
561
- Formtastic::SemanticFormBuilder.all_fields_required_by_default = true
562
- end
563
-
564
- end
565
-
566
- end
567
-
568
- end
569
-
570
- end
571
-
572
- describe ':as option' do
573
-
574
- describe 'when not provided' do
575
-
576
- it 'should default to a string for forms without objects unless column is password' do
577
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
578
- concat(builder.input(:anything))
579
- end
580
- output_buffer.should have_tag('form li.string')
581
- end
582
-
583
- it 'should default to password for forms without objects if column is password' do
584
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
585
- concat(builder.input(:password))
586
- concat(builder.input(:password_confirmation))
587
- concat(builder.input(:confirm_password))
588
- end
589
- output_buffer.should have_tag('form li.password', :count => 3)
590
- end
591
-
592
- it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do
593
- @new_post.stub!(:method_without_a_database_column)
594
- @new_post.stub!(:column_for_attribute).and_return(nil)
595
- default_input_type(nil, :method_without_a_database_column).should == :string
596
- end
597
-
598
- it 'should default to :password for methods that don\'t have a column in the database but "password" is in the method name' do
599
- @new_post.stub!(:password_method_without_a_database_column)
600
- @new_post.stub!(:column_for_attribute).and_return(nil)
601
- default_input_type(nil, :password_method_without_a_database_column).should == :password
602
- end
603
-
604
- it 'should default to :password for methods on objects that don\'t respond to "column_for_attribute" but "password" is in the method name' do
605
- @new_post.stub!(:password_method_without_a_database_column)
606
- @new_post.stub!(:column_for_attribute).and_return(nil)
607
- default_input_type(nil, :password_method_without_a_database_column).should == :password
608
- end
609
-
610
- it 'should default to :select for column names ending in "_id"' do
611
- default_input_type(:integer, :user_id).should == :select
612
- default_input_type(:integer, :section_id).should == :select
613
- end
614
-
615
- it 'should default to :password for :string column types with "password" in the method name' do
616
- default_input_type(:string, :password).should == :password
617
- default_input_type(:string, :hashed_password).should == :password
618
- default_input_type(:string, :password_hash).should == :password
619
- end
620
-
621
- it 'should default to :text for :text column types' do
622
- default_input_type(:text).should == :text
623
- end
624
-
625
- it 'should default to :date for :date column types' do
626
- default_input_type(:date).should == :date
627
- end
628
-
629
- it 'should default to :datetime for :datetime and :timestamp column types' do
630
- default_input_type(:datetime).should == :datetime
631
- default_input_type(:timestamp).should == :datetime
632
- end
633
-
634
- it 'should default to :time for :time column types' do
635
- default_input_type(:time).should == :time
636
- end
637
-
638
- it 'should default to :boolean for :boolean column types' do
639
- default_input_type(:boolean).should == :boolean
640
- end
641
-
642
- it 'should default to :string for :string column types' do
643
- default_input_type(:string).should == :string
644
- end
645
-
646
- it 'should default to :numeric for :integer, :float and :decimal column types' do
647
- default_input_type(:integer).should == :numeric
648
- default_input_type(:float).should == :numeric
649
- default_input_type(:decimal).should == :numeric
650
- end
651
-
652
- it 'should default to :country for :string columns named country' do
653
- default_input_type(:string, :country).should == :country
654
- end
655
-
656
- describe 'defaulting to file column' do
657
- Formtastic::SemanticFormBuilder.file_methods.each do |method|
658
- it "should default to :file for attributes that respond to ##{method}" do
659
- @new_post.stub!(:column_for_attribute).and_return(nil)
660
- column = mock('column')
661
-
662
- Formtastic::SemanticFormBuilder.file_methods.each do |test|
663
- column.stub!(:respond_to?).with(test).and_return(method == test)
664
- end
665
-
666
- @new_post.should_receive(method).and_return(column)
667
-
668
- semantic_form_for(@new_post) do |builder|
669
- builder.send(:default_input_type, method).should == :file
670
- end
671
- end
672
- end
673
-
674
- end
675
- end
676
-
677
- it 'should call the corresponding input method' do
678
- [:select, :time_zone, :radio, :date, :datetime, :time, :boolean, :check_boxes, :hidden].each do |input_style|
679
- @new_post.stub!(:generic_column_name)
680
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
681
- semantic_form_for(@new_post) do |builder|
682
- builder.should_receive(:"#{input_style}_input").once.and_return("fake HTML output from #input")
683
- concat(builder.input(:generic_column_name, :as => input_style))
684
- end
685
- end
686
-
687
- Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.keys.each do |input_style|
688
- @new_post.stub!(:generic_column_name)
689
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
690
- semantic_form_for(@new_post) do |builder|
691
- builder.should_receive(:input_simple).once.and_return("fake HTML output from #input")
692
- concat(builder.input(:generic_column_name, :as => input_style))
693
- end
694
- end
695
- end
696
-
697
- end
698
-
699
- describe ':label option' do
700
-
701
- describe 'when provided' do
702
- it 'should be passed down to the label tag' do
703
- semantic_form_for(@new_post) do |builder|
704
- concat(builder.input(:title, :label => "Kustom"))
705
- end
706
- output_buffer.should have_tag("form li label", /Kustom/)
707
- end
708
-
709
- it 'should not generate a label if false' do
710
- semantic_form_for(@new_post) do |builder|
711
- concat(builder.input(:title, :label => false))
712
- end
713
- output_buffer.should_not have_tag("form li label")
714
- end
715
-
716
- it 'should be dupped if frozen' do
717
- semantic_form_for(@new_post) do |builder|
718
- concat(builder.input(:title, :label => "Kustom".freeze))
719
- end
720
- output_buffer.should have_tag("form li label", /Kustom/)
721
- end
722
- end
723
-
724
- describe 'when not provided' do
725
- describe 'when localized label is NOT provided' do
726
- describe 'and object is not given' do
727
- it 'should default the humanized method name, passing it down to the label tag' do
728
- Formtastic::SemanticFormBuilder.label_str_method = :humanize
729
-
730
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
731
- concat(builder.input(:meta_description))
732
- end
733
-
734
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
735
- end
736
- end
737
-
738
- describe 'and object is given' do
739
- it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
740
- @new_post.stub!(:meta_description) # a two word method name
741
- @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
742
-
743
- semantic_form_for(@new_post) do |builder|
744
- concat(builder.input(:meta_description))
745
- end
746
-
747
- output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
748
- end
749
- end
750
- end
751
-
752
- describe 'when localized label is provided' do
753
- before do
754
- @localized_label_text = 'Localized title'
755
- @default_localized_label_text = 'Default localized title'
756
- ::I18n.backend.store_translations :en,
757
- :formtastic => {
758
- :labels => {
759
- :title => @default_localized_label_text,
760
- :post => {
761
- :title => @localized_label_text
762
- }
763
- }
764
- }
765
- ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
766
- end
767
-
768
- it 'should render a label with localized label (I18n)' do
769
- semantic_form_for(@new_post) do |builder|
770
- concat(builder.input(:title, :label => true))
771
- end
772
- output_buffer.should have_tag('form li label', @localized_label_text)
773
- end
774
-
775
- it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
776
- ::I18n.backend.store_translations :en,
777
- :formtastic => {
778
- :labels => {
779
- :post => {
780
- :title => nil
781
- }
782
- }
783
- }
784
- semantic_form_for(@new_post) do |builder|
785
- concat(builder.input(:title, :label => true))
786
- end
787
- output_buffer.should have_tag('form li label', @default_localized_label_text)
788
- end
789
- end
790
- end
791
-
792
- end
793
-
794
- describe ':hint option' do
795
-
796
- describe 'when provided' do
797
- it 'should be passed down to the paragraph tag' do
798
- hint_text = "this is the title of the post"
799
- semantic_form_for(@new_post) do |builder|
800
- concat(builder.input(:title, :hint => hint_text))
801
- end
802
- output_buffer.should have_tag("form li p.inline-hints", hint_text)
803
- end
804
- end
805
-
806
- describe 'when not provided' do
807
- describe 'when localized hint (I18n) is provided' do
808
- before do
809
- @localized_hint_text = "This is the localized hint."
810
- @default_localized_hint_text = "This is the default localized hint."
811
- ::I18n.backend.store_translations :en,
812
- :formtastic => {
813
- :hints => {
814
- :title => @default_localized_hint_text,
815
- :post => {
816
- :title => @localized_hint_text
817
- }
818
- }
819
- }
820
- ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
821
- end
822
-
823
- describe 'when provided value (hint value) is set to TRUE' do
824
- it 'should render a hint paragraph containing a localized hint (I18n)' do
825
- semantic_form_for(@new_post) do |builder|
826
- concat(builder.input(:title, :hint => true))
827
- end
828
- output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
829
- end
830
-
831
- it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
832
- ::I18n.backend.store_translations :en,
833
- :formtastic => {
834
- :hints => {
835
- :post => {
836
- :title => nil
837
- }
838
- }
839
- }
840
- semantic_form_for(@new_post) do |builder|
841
- concat(builder.input(:title, :hint => true))
842
- end
843
- output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text)
844
- end
845
- end
846
-
847
- describe 'when provided value (label value) is set to FALSE' do
848
- it 'should not render a hint paragraph' do
849
- semantic_form_for(@new_post) do |builder|
850
- concat(builder.input(:title, :hint => false))
851
- end
852
- output_buffer.should_not have_tag('form li p.inline-hints', @localized_hint_text)
853
- end
854
- end
855
- end
856
-
857
- describe 'when localized hint (I18n) is not provided' do
858
- it 'should not render a hint paragraph' do
859
- semantic_form_for(@new_post) do |builder|
860
- concat(builder.input(:title))
861
- end
862
- output_buffer.should_not have_tag('form li p.inline-hints')
863
- end
864
- end
865
- end
866
-
867
- end
868
-
869
- describe ':wrapper_html option' do
870
-
871
- describe 'when provided' do
872
- it 'should be passed down to the li tag' do
873
- semantic_form_for(@new_post) do |builder|
874
- concat(builder.input(:title, :wrapper_html => {:id => :another_id}))
875
- end
876
- output_buffer.should have_tag("form li#another_id")
877
- end
878
-
879
- it 'should append given classes to li default classes' do
880
- semantic_form_for(@new_post) do |builder|
881
- concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true))
882
- end
883
- output_buffer.should have_tag("form li.string")
884
- output_buffer.should have_tag("form li.required")
885
- output_buffer.should have_tag("form li.another_class")
886
- end
887
-
888
- it 'should allow classes to be an array' do
889
- semantic_form_for(@new_post) do |builder|
890
- concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
891
- end
892
- output_buffer.should have_tag("form li.string")
893
- output_buffer.should have_tag("form li.my_class")
894
- output_buffer.should have_tag("form li.another_class")
895
- end
896
- end
897
-
898
- describe 'when not provided' do
899
- it 'should use default id and class' do
900
- semantic_form_for(@new_post) do |builder|
901
- concat(builder.input(:title))
902
- end
903
- output_buffer.should have_tag("form li#post_title_input")
904
- output_buffer.should have_tag("form li.string")
905
- end
906
- end
907
-
908
- end
909
- end
910
-
911
- describe ':as any type of input' do
912
-
913
- it 'should create a list item for each input' do
914
- semantic_form_for(@new_post) do |builder|
915
- concat(builder.input(:title))
916
- concat(builder.input(:body))
917
- end
918
- output_buffer.should have_tag('form li', :count => 2)
919
- end
920
-
921
- describe 'when there are errors on the object for this method' do
922
- before do
923
- @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
924
- @errors = mock('errors')
925
- @errors.stub!(:[]).with(:title).and_return(@title_errors)
926
- @new_post.stub!(:errors).and_return(@errors)
927
- end
928
-
929
- it 'should apply an errors class to the list item' do
930
- semantic_form_for(@new_post) do |builder|
931
- concat(builder.input(:title))
932
- end
933
- output_buffer.should have_tag('form li.error')
934
- end
935
-
936
- it 'should not wrap the input with the Rails default error wrapping' do
937
- semantic_form_for(@new_post) do |builder|
938
- concat(builder.input(:title))
939
- end
940
- output_buffer.should_not have_tag('div.fieldWithErrors')
941
- end
942
-
943
- it 'should render a paragraph for the errors' do
944
- Formtastic::SemanticFormBuilder.inline_errors = :sentence
945
- semantic_form_for(@new_post) do |builder|
946
- concat(builder.input(:title))
947
- end
948
- output_buffer.should have_tag('form li.error p.inline-errors')
949
- end
950
-
951
- it 'should not display an error list' do
952
- Formtastic::SemanticFormBuilder.inline_errors = :list
953
- semantic_form_for(@new_post) do |builder|
954
- concat(builder.input(:title))
955
- end
956
- output_buffer.should have_tag('form li.error ul.errors')
957
- end
958
- end
959
-
960
- describe 'when there are no errors on the object for this method' do
961
- before do
962
- semantic_form_for(@new_post) do |builder|
963
- concat(builder.input(:title))
964
- end
965
- end
966
-
967
- it 'should not apply an errors class to the list item' do
968
- output_buffer.should_not have_tag('form li.error')
969
- end
970
-
971
- it 'should not render a paragraph for the errors' do
972
- output_buffer.should_not have_tag('form li.error p.inline-errors')
973
- end
974
-
975
- it 'should not display an error list' do
976
- output_buffer.should_not have_tag('form li.error ul.errors')
977
- end
978
- end
979
-
980
- describe 'when no object is provided' do
981
- before do
982
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
983
- concat(builder.input(:title))
984
- end
985
- end
986
-
987
- it 'should not apply an errors class to the list item' do
988
- output_buffer.should_not have_tag('form li.error')
989
- end
990
-
991
- it 'should not render a paragraph for the errors' do
992
- output_buffer.should_not have_tag('form li.error p.inline-errors')
993
- end
994
-
995
- it 'should not display an error list' do
996
- output_buffer.should_not have_tag('form li.error ul.errors')
997
- end
998
- end
999
- end
1000
-
1001
- # Test string_mappings: :string, :password and :numeric
1002
- string_mappings = Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.slice(*Formtastic::SemanticFormBuilder::STRING_MAPPINGS)
1003
- string_mappings.each do |type, template_method|
1004
- describe ":as => #{type.inspect}" do
1005
-
1006
- before do
1007
- @new_post.stub!(:title)
1008
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => 50))
1009
-
1010
- semantic_form_for(@new_post) do |builder|
1011
- concat(builder.input(:title, :as => type))
1012
- end
1013
- end
1014
-
1015
- it "should have a #{type} class on the wrapper" do
1016
- output_buffer.should have_tag("form li.#{type}")
1017
- end
1018
-
1019
- it 'should have a post_title_input id on the wrapper' do
1020
- output_buffer.should have_tag('form li#post_title_input')
1021
- end
1022
-
1023
- it 'should generate a label for the input' do
1024
- output_buffer.should have_tag('form li label')
1025
- output_buffer.should have_tag('form li label[@for="post_title"')
1026
- output_buffer.should have_tag('form li label', /Title/)
1027
- end
1028
-
1029
- input_type = template_method.to_s.split('_').first
1030
-
1031
- it "should generate a #{input_type} input" do
1032
- output_buffer.should have_tag("form li input")
1033
- output_buffer.should have_tag("form li input#post_title")
1034
- output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
1035
- output_buffer.should have_tag("form li input[@name=\"post[title]\"]")
1036
- end
1037
-
1038
- unless type == :numeric
1039
- it 'should have a maxlength matching the column limit' do
1040
- @new_post.column_for_attribute(:title).limit.should == 50
1041
- output_buffer.should have_tag("form li input[@maxlength='50']")
1042
- end
1043
-
1044
- it 'should use default_text_field_size for columns longer than default_text_field_size' do
1045
- default_size = Formtastic::SemanticFormBuilder.default_text_field_size
1046
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => default_size * 2))
1047
-
1048
- semantic_form_for(@new_post) do |builder|
1049
- concat(builder.input(:title, :as => type))
1050
- end
1051
-
1052
- output_buffer.should have_tag("form li input[@size='#{default_size}']")
1053
- end
1054
-
1055
- it 'should use the column size for columns shorter than default_text_field_size' do
1056
- column_limit_shorted_than_default = 1
1057
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type, :limit => column_limit_shorted_than_default))
1058
-
1059
- semantic_form_for(@new_post) do |builder|
1060
- concat(builder.input(:title, :as => type))
1061
- end
1062
-
1063
- output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
1064
- end
1065
- end
1066
-
1067
- it 'should use default_text_field_size for methods without database columns' do
1068
- default_size = Formtastic::SemanticFormBuilder.default_text_field_size
1069
- @new_post.stub!(:column_for_attribute).and_return(nil) # Return a nil column
1070
-
1071
- semantic_form_for(@new_post) do |builder|
1072
- concat(builder.input(:title, :as => type))
1073
- end
1074
-
1075
- output_buffer.should have_tag("form li input[@size='#{default_size}']")
1076
- end
1077
-
1078
- it 'should use input_html to style inputs' do
1079
- semantic_form_for(@new_post) do |builder|
1080
- concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
1081
- end
1082
- output_buffer.should have_tag("form li input.myclass")
1083
- end
1084
-
1085
- it 'should consider input_html :id in labels' do
1086
- semantic_form_for(@new_post) do |builder|
1087
- concat(builder.input(:title, :as => type, :input_html => { :id => 'myid' }))
1088
- end
1089
- output_buffer.should have_tag('form li label[@for="myid"]')
1090
- end
1091
-
1092
- it 'should generate input and labels even if no object is given' do
1093
- semantic_form_for(:project, :url => 'http://test.host/') do |builder|
1094
- concat(builder.input(:title, :as => type))
1095
- end
1096
-
1097
- output_buffer.should have_tag('form li label')
1098
- output_buffer.should have_tag('form li label[@for="project_title"')
1099
- output_buffer.should have_tag('form li label', /Title/)
1100
-
1101
- output_buffer.should have_tag("form li input")
1102
- output_buffer.should have_tag("form li input#project_title")
1103
- output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
1104
- output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
1105
- end
1106
-
1107
- end
1108
- end
1109
-
1110
- # Test other mappings that are not strings: :text and :file.
1111
- other_mappings = Formtastic::SemanticFormBuilder::INPUT_MAPPINGS.except(*Formtastic::SemanticFormBuilder::STRING_MAPPINGS)
1112
- other_mappings.each do |type, template_method|
1113
- describe ":as => #{type.inspect}" do
1114
-
1115
- before do
1116
- @new_post.stub!(:body)
1117
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => type))
1118
-
1119
- semantic_form_for(@new_post) do |builder|
1120
- concat(builder.input(:body, :as => type))
1121
- end
1122
- end
1123
-
1124
- it "should have a #{type} class on the wrapper" do
1125
- output_buffer.should have_tag('form li.#{type}')
1126
- end
1127
-
1128
- it 'should have a post_title_input id on the wrapper' do
1129
- output_buffer.should have_tag('form li#post_body_input')
1130
- end
1131
-
1132
- it 'should generate a label for the input' do
1133
- output_buffer.should have_tag('form li label')
1134
- output_buffer.should have_tag('form li label[@for="post_body"')
1135
- output_buffer.should have_tag('form li label', /Body/)
1136
- end
1137
-
1138
- input_type = template_method.to_s.gsub(/_field|_/, '')
1139
-
1140
- if template_method.to_s =~ /_field$/ # password_field
1141
-
1142
- it "should generate a #{input_type} input" do
1143
- output_buffer.should have_tag("form li input")
1144
- output_buffer.should have_tag("form li input#post_body")
1145
- output_buffer.should have_tag("form li input[@name=\"post[body]\"]")
1146
- output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
1147
- end
1148
-
1149
- it 'should use input_html to style inputs' do
1150
- semantic_form_for(@new_post) do |builder|
1151
- concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
1152
- end
1153
- output_buffer.should have_tag("form li input.myclass")
1154
- end
1155
-
1156
- else # text_area
1157
-
1158
- it "should generate a #{input_type} input" do
1159
- output_buffer.should have_tag("form li #{input_type}")
1160
- output_buffer.should have_tag("form li #{input_type}#post_body")
1161
- output_buffer.should have_tag("form li #{input_type}[@name=\"post[body]\"]")
1162
- end
1163
-
1164
- it 'should use input_html to style inputs' do
1165
- semantic_form_for(@new_post) do |builder|
1166
- concat(builder.input(:title, :as => type, :input_html => { :class => 'myclass' }))
1167
- end
1168
- output_buffer.should have_tag("form li #{input_type}.myclass")
1169
- end
1170
-
1171
- end
1172
-
1173
- describe 'when no object is given' do
1174
- before(:each) do
1175
- semantic_form_for(:project, :url => 'http://test.host/') do |builder|
1176
- concat(builder.input(:title, :as => type))
1177
- end
1178
- end
1179
-
1180
- it 'should generate input' do
1181
- if template_method.to_s =~ /_field$/ # password_field
1182
- output_buffer.should have_tag("form li input")
1183
- output_buffer.should have_tag("form li input#project_title")
1184
- output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
1185
- output_buffer.should have_tag("form li input[@name=\"project[title]\"]")
1186
- else
1187
- output_buffer.should have_tag("form li #{input_type}")
1188
- output_buffer.should have_tag("form li #{input_type}#project_title")
1189
- output_buffer.should have_tag("form li #{input_type}[@name=\"project[title]\"]")
1190
- end
1191
- end
1192
-
1193
- it 'should generate labels' do
1194
- output_buffer.should have_tag('form li label')
1195
- output_buffer.should have_tag('form li label[@for="project_title"')
1196
- output_buffer.should have_tag('form li label', /Title/)
1197
- end
1198
- end
1199
-
1200
- end
1201
- end
1202
-
1203
- describe ":as => :hidden" do
1204
- before do
1205
- @new_post.stub!(:hidden)
1206
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
1207
-
1208
- semantic_form_for(@new_post) do |builder|
1209
- concat(builder.input(:hidden, :as => :hidden))
1210
- end
1211
- end
1212
-
1213
- it "should have a hidden class on the wrapper" do
1214
- output_buffer.should have_tag('form li.hidden')
1215
- end
1216
-
1217
- it 'should have a post_hidden_input id on the wrapper' do
1218
- output_buffer.should have_tag('form li#post_hidden_input')
1219
- end
1220
-
1221
- it 'should not generate a label for the input' do
1222
- output_buffer.should_not have_tag('form li label')
1223
- end
1224
-
1225
- it "should generate a input field" do
1226
- output_buffer.should have_tag("form li input#post_hidden")
1227
- output_buffer.should have_tag("form li input[@type=\"hidden\"]")
1228
- output_buffer.should have_tag("form li input[@name=\"post[hidden]\"]")
1229
- end
1230
- end
1231
-
1232
- describe ":as => :time_zone" do
1233
- before do
1234
- @new_post.stub!(:time_zone)
1235
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
1236
-
1237
- semantic_form_for(@new_post) do |builder|
1238
- concat(builder.input(:time_zone))
1239
- end
1240
- end
1241
-
1242
- it "should have a time_zone class on the wrapper" do
1243
- output_buffer.should have_tag('form li.time_zone')
1244
- end
1245
-
1246
- it 'should have a post_title_input id on the wrapper' do
1247
- output_buffer.should have_tag('form li#post_time_zone_input')
1248
- end
1249
-
1250
- it 'should generate a label for the input' do
1251
- output_buffer.should have_tag('form li label')
1252
- output_buffer.should have_tag('form li label[@for="post_time_zone"')
1253
- output_buffer.should have_tag('form li label', /Time zone/)
1254
- end
1255
-
1256
- it "should generate a select" do
1257
- output_buffer.should have_tag("form li select")
1258
- output_buffer.should have_tag("form li select#post_time_zone")
1259
- output_buffer.should have_tag("form li select[@name=\"post[time_zone]\"]")
1260
- end
1261
-
1262
- it 'should use input_html to style inputs' do
1263
- semantic_form_for(@new_post) do |builder|
1264
- concat(builder.input(:time_zone, :input_html => { :class => 'myclass' }))
1265
- end
1266
- output_buffer.should have_tag("form li select.myclass")
1267
- end
1268
-
1269
- describe 'when no object is given' do
1270
- before(:each) do
1271
- semantic_form_for(:project, :url => 'http://test.host/') do |builder|
1272
- concat(builder.input(:time_zone, :as => :time_zone))
1273
- end
1274
- end
1275
-
1276
- it 'should generate labels' do
1277
- output_buffer.should have_tag('form li label')
1278
- output_buffer.should have_tag('form li label[@for="project_time_zone"')
1279
- output_buffer.should have_tag('form li label', /Time zone/)
1280
- end
1281
-
1282
- it 'should generate select inputs' do
1283
- output_buffer.should have_tag("form li select")
1284
- output_buffer.should have_tag("form li select#project_time_zone")
1285
- output_buffer.should have_tag("form li select[@name=\"project[time_zone]\"]")
1286
- end
1287
- end
1288
- end
1289
-
1290
- describe ":as => :country" do
1291
-
1292
- before do
1293
- @new_post.stub!(:country)
1294
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
1295
- end
1296
-
1297
- describe "when country_select is not available as a helper from a plugin" do
1298
-
1299
- it "should raise an error, sugesting the author installs a plugin" do
1300
- lambda {
1301
- semantic_form_for(@new_post) do |builder|
1302
- concat(builder.input(:country, :as => :country))
1303
- end
1304
- }.should raise_error
1305
- end
1306
-
1307
- end
1308
-
1309
- describe "when country_select is available as a helper (from a plugin)" do
1310
-
1311
- before do
1312
- semantic_form_for(@new_post) do |builder|
1313
- builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1314
- concat(builder.input(:country, :as => :country))
1315
- end
1316
- end
1317
-
1318
- it "should have a time_zone class on the wrapper" do
1319
- output_buffer.should have_tag('form li.country')
1320
- end
1321
-
1322
- it 'should have a post_title_input id on the wrapper' do
1323
- output_buffer.should have_tag('form li#post_country_input')
1324
- end
1325
-
1326
- it 'should generate a label for the input' do
1327
- output_buffer.should have_tag('form li label')
1328
- output_buffer.should have_tag('form li label[@for="post_country"')
1329
- output_buffer.should have_tag('form li label', /Country/)
1330
- end
1331
-
1332
- it "should generate a select" do
1333
- output_buffer.should have_tag("form li select")
1334
- end
1335
-
1336
- end
1337
-
1338
- describe ":priority_countries option" do
1339
-
1340
- it "should be passed down to the country_select helper when provided" do
1341
- priority_countries = ["Foo", "Bah"]
1342
- semantic_form_for(@new_post) do |builder|
1343
- builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1344
- builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1345
-
1346
- concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
1347
- end
1348
- end
1349
-
1350
- it "should default to the @@priority_countries config when absent" do
1351
- priority_countries = Formtastic::SemanticFormBuilder.priority_countries
1352
- priority_countries.should_not be_empty
1353
- priority_countries.should_not be_nil
1354
-
1355
- semantic_form_for(@new_post) do |builder|
1356
- builder.stub!(:country_select).and_return("<select><option>...</option></select>")
1357
- builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
1358
-
1359
- concat(builder.input(:country, :as => :country))
1360
- end
1361
- end
1362
-
1363
- end
1364
-
1365
- end
1366
-
1367
- describe ':as => :radio' do
1368
-
1369
- before do
1370
- @new_post.stub!(:author).and_return(@bob)
1371
- @new_post.stub!(:author_id).and_return(@bob.id)
1372
- Post.stub!(:reflect_on_association).and_return { |column_name| mock('reflection', :options => {}, :klass => Author, :macro => :belongs_to) }
1373
- end
1374
-
1375
- describe 'for belongs_to association' do
1376
- before do
1377
- semantic_form_for(@new_post) do |builder|
1378
- concat(builder.input(:author, :as => :radio, :value_as_class => true))
1379
- end
1380
- end
1381
-
1382
- it 'should have a radio class on the wrapper' do
1383
- output_buffer.should have_tag('form li.radio')
1384
- end
1385
-
1386
- it 'should have a post_author_input id on the wrapper' do
1387
- output_buffer.should have_tag('form li#post_author_input')
1388
- end
1389
-
1390
- it 'should generate a fieldset and legend containing label text for the input' do
1391
- output_buffer.should have_tag('form li fieldset')
1392
- output_buffer.should have_tag('form li fieldset legend')
1393
- output_buffer.should have_tag('form li fieldset legend', /Author/)
1394
- end
1395
-
1396
- it 'should generate an ordered list with a list item for each choice' do
1397
- output_buffer.should have_tag('form li fieldset ol')
1398
- output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1399
- end
1400
-
1401
- it 'should have one option with a "checked" attribute' do
1402
- output_buffer.should have_tag('form li input[@checked]', :count => 1)
1403
- end
1404
-
1405
- describe "each choice" do
1406
-
1407
- it 'should contain a label for the radio input with a nested input and label text' do
1408
- Author.find(:all).each do |author|
1409
- output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1410
- output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_id_#{author.id}']")
1411
- end
1412
- end
1413
-
1414
- it 'should use values as li.class when value_as_class is true' do
1415
- Author.find(:all).each do |author|
1416
- output_buffer.should have_tag("form li fieldset ol li.#{author.id} label")
1417
- end
1418
- end
1419
-
1420
- it "should have a radio input" do
1421
- Author.find(:all).each do |author|
1422
- output_buffer.should have_tag("form li fieldset ol li label input#post_author_id_#{author.id}")
1423
- output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1424
- output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1425
- output_buffer.should have_tag("form li fieldset ol li label input[@name='post[author_id]']")
1426
- end
1427
- end
1428
-
1429
- it "should mark input as checked if it's the the existing choice" do
1430
- @new_post.author_id.should == @bob.id
1431
- @new_post.author.id.should == @bob.id
1432
- @new_post.author.should == @bob
1433
-
1434
- semantic_form_for(@new_post) do |builder|
1435
- concat(builder.input(:author, :as => :radio))
1436
- end
1437
-
1438
- output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1439
- end
1440
- end
1441
-
1442
- describe 'and no object is given' do
1443
- before(:each) do
1444
- output_buffer.replace ''
1445
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1446
- concat(builder.input(:author_id, :as => :radio, :collection => Author.find(:all)))
1447
- end
1448
- end
1449
-
1450
- it 'should generate a fieldset with legend' do
1451
- output_buffer.should have_tag('form li fieldset legend', /Author/)
1452
- end
1453
-
1454
- it 'shold generate an li tag for each item in the collection' do
1455
- output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1456
- end
1457
-
1458
- it 'should generate labels for each item' do
1459
- Author.find(:all).each do |author|
1460
- output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1461
- output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1462
- end
1463
- end
1464
-
1465
- it 'should generate inputs for each item' do
1466
- Author.find(:all).each do |author|
1467
- output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1468
- output_buffer.should have_tag("form li fieldset ol li label input[@type='radio']")
1469
- output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1470
- output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id]']")
1471
- end
1472
- end
1473
- end
1474
- end
1475
- end
1476
-
1477
- describe ':as => :select' do
1478
-
1479
- before do
1480
- @new_post.stub!(:author).and_return(@bob)
1481
- @new_post.stub!(:author_id).and_return(@bob.id)
1482
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1483
- end
1484
-
1485
- describe 'for a belongs_to association' do
1486
- before do
1487
- semantic_form_for(@new_post) do |builder|
1488
- concat(builder.input(:author, :as => :select))
1489
- end
1490
- end
1491
-
1492
- it 'should have a select class on the wrapper' do
1493
- output_buffer.should have_tag('form li.select')
1494
- end
1495
-
1496
- it 'should have a post_author_input id on the wrapper' do
1497
- output_buffer.should have_tag('form li#post_author_input')
1498
- end
1499
-
1500
- it 'should have a label inside the wrapper' do
1501
- output_buffer.should have_tag('form li label')
1502
- output_buffer.should have_tag('form li label', /Author/)
1503
- output_buffer.should have_tag("form li label[@for='post_author_id']")
1504
- end
1505
-
1506
- it 'should have a select inside the wrapper' do
1507
- output_buffer.should have_tag('form li select')
1508
- output_buffer.should have_tag('form li select#post_author_id')
1509
- end
1510
-
1511
- it 'should not create a multi-select' do
1512
- output_buffer.should_not have_tag('form li select[@multiple]')
1513
- end
1514
-
1515
- it 'should create a select without size' do
1516
- output_buffer.should_not have_tag('form li select[@size]')
1517
- end
1518
-
1519
- it 'should have a blank option' do
1520
- output_buffer.should have_tag("form li select option[@value='']")
1521
- end
1522
-
1523
- it 'should have a select option for each Author' do
1524
- output_buffer.should have_tag('form li select option', :count => Author.find(:all).size + 1)
1525
- Author.find(:all).each do |author|
1526
- output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1527
- end
1528
- end
1529
-
1530
- it 'should have one option with a "selected" attribute' do
1531
- output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1532
- end
1533
-
1534
- it 'should not singularize the association name' do
1535
- @new_post.stub!(:author_status).and_return(@bob)
1536
- @new_post.stub!(:author_status_id).and_return(@bob.id)
1537
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1538
-
1539
- semantic_form_for(@new_post) do |builder|
1540
- concat(builder.input(:author_status, :as => :select))
1541
- end
1542
-
1543
- output_buffer.should have_tag('form li select#post_author_status_id')
1544
- end
1545
- end
1546
-
1547
- describe 'for a has_many association' do
1548
- before do
1549
- semantic_form_for(@fred) do |builder|
1550
- concat(builder.input(:posts, :as => :select))
1551
- end
1552
- end
1553
-
1554
- it 'should have a select class on the wrapper' do
1555
- output_buffer.should have_tag('form li.select')
1556
- end
1557
-
1558
- it 'should have a post_author_input id on the wrapper' do
1559
- output_buffer.should have_tag('form li#author_posts_input')
1560
- end
1561
-
1562
- it 'should have a label inside the wrapper' do
1563
- output_buffer.should have_tag('form li label')
1564
- output_buffer.should have_tag('form li label', /Post/)
1565
- output_buffer.should have_tag("form li label[@for='author_post_ids']")
1566
- end
1567
-
1568
- it 'should have a select inside the wrapper' do
1569
- output_buffer.should have_tag('form li select')
1570
- output_buffer.should have_tag('form li select#author_post_ids')
1571
- end
1572
-
1573
- it 'should have a multi-select select' do
1574
- output_buffer.should have_tag('form li select[@multiple="multiple"]')
1575
- end
1576
-
1577
- it 'should have a select option for each Post' do
1578
- output_buffer.should have_tag('form li select option', :count => Post.find(:all).size)
1579
- Post.find(:all).each do |post|
1580
- output_buffer.should have_tag("form li select option[@value='#{post.id}']", /#{post.to_label}/)
1581
- end
1582
- end
1583
-
1584
- it 'should not have a blank option' do
1585
- output_buffer.should_not have_tag("form li select option[@value='']")
1586
- end
1587
-
1588
- it 'should have one option with a "selected" attribute' do
1589
- output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1590
- end
1591
- end
1592
-
1593
- describe 'for a has_and_belongs_to_many association' do
1594
- before do
1595
- semantic_form_for(@freds_post) do |builder|
1596
- concat(builder.input(:authors, :as => :select))
1597
- end
1598
- end
1599
-
1600
- it 'should have a select class on the wrapper' do
1601
- output_buffer.should have_tag('form li.select')
1602
- end
1603
-
1604
- it 'should have a post_author_input id on the wrapper' do
1605
- output_buffer.should have_tag('form li#post_authors_input')
1606
- end
1607
-
1608
- it 'should have a label inside the wrapper' do
1609
- output_buffer.should have_tag('form li label')
1610
- output_buffer.should have_tag('form li label', /Author/)
1611
- output_buffer.should have_tag("form li label[@for='post_author_ids']")
1612
- end
1613
-
1614
- it 'should have a select inside the wrapper' do
1615
- output_buffer.should have_tag('form li select')
1616
- output_buffer.should have_tag('form li select#post_author_ids')
1617
- end
1618
-
1619
- it 'should have a multi-select select' do
1620
- output_buffer.should have_tag('form li select[@multiple="multiple"]')
1621
- end
1622
-
1623
- it 'should have a select option for each Author' do
1624
- output_buffer.should have_tag('form li select option', :count => Author.find(:all).size)
1625
- Author.find(:all).each do |author|
1626
- output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1627
- end
1628
- end
1629
-
1630
- it 'should not have a blank option' do
1631
- output_buffer.should_not have_tag("form li select option[@value='']")
1632
- end
1633
-
1634
- it 'should have one option with a "selected" attribute' do
1635
- output_buffer.should have_tag('form li select option[@selected]', :count => 1)
1636
- end
1637
- end
1638
-
1639
- describe 'when :include_blank is not set' do
1640
- before do
1641
- @new_post.stub!(:author_id).and_return(nil)
1642
- semantic_form_for(@new_post) do |builder|
1643
- concat(builder.input(:author, :as => :select))
1644
- end
1645
- end
1646
-
1647
- it 'should have a blank option by default' do
1648
- output_buffer.should have_tag("form li select option[@value='']", "")
1649
- end
1650
- end
1651
-
1652
- describe 'when :include_blank is set to false' do
1653
- before do
1654
- @new_post.stub!(:author_id).and_return(nil)
1655
- semantic_form_for(@new_post) do |builder|
1656
- concat(builder.input(:author, :as => :select, :include_blank => false))
1657
- end
1658
- end
1659
-
1660
- it 'should not have a blank option' do
1661
- output_buffer.should_not have_tag("form li select option[@value='']", "")
1662
- end
1663
- end
1664
-
1665
- describe 'when :prompt => "choose something" is set' do
1666
- before do
1667
- @new_post.stub!(:author_id).and_return(nil)
1668
- semantic_form_for(@new_post) do |builder|
1669
- concat(builder.input(:author, :as => :select, :prompt => "choose author"))
1670
- end
1671
- end
1672
-
1673
- it 'should have a select with prompt' do
1674
- output_buffer.should have_tag("form li select option[@value='']", /choose author/)
1675
- end
1676
-
1677
- it 'should not have a blank select option' do
1678
- output_buffer.should_not have_tag("form li select option[@value='']", "")
1679
- end
1680
- end
1681
-
1682
- describe 'when no object is given' do
1683
- before(:each) do
1684
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1685
- concat(builder.input(:author, :as => :select, :collection => Author.find(:all)))
1686
- end
1687
- end
1688
-
1689
- it 'should generate label' do
1690
- output_buffer.should have_tag('form li label', /Author/)
1691
- output_buffer.should have_tag("form li label[@for='project_author']")
1692
- end
1693
-
1694
- it 'should generate select inputs' do
1695
- output_buffer.should have_tag('form li select#project_author')
1696
- output_buffer.should have_tag('form li select option', :count => Author.find(:all).size + 1)
1697
- end
1698
-
1699
- it 'should generate an option to each item' do
1700
- Author.find(:all).each do |author|
1701
- output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
1702
- end
1703
- end
1704
- end
1705
- end
1706
-
1707
- describe ':as => :check_boxes' do
1708
-
1709
- describe 'for a has_many association' do
1710
- before do
1711
- semantic_form_for(@fred) do |builder|
1712
- concat(builder.input(:posts, :as => :check_boxes, :value_as_class => true))
1713
- end
1714
- end
1715
-
1716
- it 'should have a check_boxes class on the wrapper' do
1717
- output_buffer.should have_tag('form li.check_boxes')
1718
- end
1719
-
1720
- it 'should have a author_posts_input id on the wrapper' do
1721
- output_buffer.should have_tag('form li#author_posts_input')
1722
- end
1723
-
1724
- it 'should generate a fieldset and legend containing label text for the input' do
1725
- output_buffer.should have_tag('form li fieldset')
1726
- output_buffer.should have_tag('form li fieldset legend')
1727
- output_buffer.should have_tag('form li fieldset legend', /Posts/)
1728
- end
1729
-
1730
- it 'should generate an ordered list with a list item for each choice' do
1731
- output_buffer.should have_tag('form li fieldset ol')
1732
- output_buffer.should have_tag('form li fieldset ol li', :count => Post.find(:all).size)
1733
- end
1734
-
1735
- it 'should have one option with a "checked" attribute' do
1736
- output_buffer.should have_tag('form li input[@checked]', :count => 1)
1737
- end
1738
-
1739
- it 'should generate hidden inputs with default value blank' do
1740
- output_buffer.should have_tag("form li fieldset ol li label input[@type='hidden'][@value='']", :count => Post.find(:all).size)
1741
- end
1742
-
1743
- describe "each choice" do
1744
-
1745
- it 'should contain a label for the radio input with a nested input and label text' do
1746
- Post.find(:all).each do |post|
1747
- output_buffer.should have_tag('form li fieldset ol li label', /#{post.to_label}/)
1748
- output_buffer.should have_tag("form li fieldset ol li label[@for='author_post_ids_#{post.id}']")
1749
- end
1750
- end
1751
-
1752
- it 'should use values as li.class when value_as_class is true' do
1753
- Post.find(:all).each do |post|
1754
- output_buffer.should have_tag("form li fieldset ol li.#{post.id} label")
1755
- end
1756
- end
1757
-
1758
- it 'should have a checkbox input for each post' do
1759
- Post.find(:all).each do |post|
1760
- output_buffer.should have_tag("form li fieldset ol li label input#author_post_ids_#{post.id}")
1761
- output_buffer.should have_tag("form li fieldset ol li label input[@name='author[post_ids][]']", :count => 2)
1762
- end
1763
- end
1764
-
1765
- it "should mark input as checked if it's the the existing choice" do
1766
- Post.find(:all).include?(@fred.posts.first).should be_true
1767
- output_buffer.should have_tag("form li fieldset ol li label input[@checked='checked']")
1768
- end
1769
- end
1770
-
1771
- describe 'and no object is given' do
1772
- before(:each) do
1773
- output_buffer.replace ''
1774
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
1775
- concat(builder.input(:author_id, :as => :check_boxes, :collection => Author.find(:all)))
1776
- end
1777
- end
1778
-
1779
- it 'should generate a fieldset with legend' do
1780
- output_buffer.should have_tag('form li fieldset legend', /Author/)
1781
- end
1782
-
1783
- it 'shold generate an li tag for each item in the collection' do
1784
- output_buffer.should have_tag('form li fieldset ol li', :count => Author.find(:all).size)
1785
- end
1786
-
1787
- it 'should generate labels for each item' do
1788
- Author.find(:all).each do |author|
1789
- output_buffer.should have_tag('form li fieldset ol li label', /#{author.to_label}/)
1790
- output_buffer.should have_tag("form li fieldset ol li label[@for='project_author_id_#{author.id}']")
1791
- end
1792
- end
1793
-
1794
- it 'should generate inputs for each item' do
1795
- Author.find(:all).each do |author|
1796
- output_buffer.should have_tag("form li fieldset ol li label input#project_author_id_#{author.id}")
1797
- output_buffer.should have_tag("form li fieldset ol li label input[@type='checkbox']")
1798
- output_buffer.should have_tag("form li fieldset ol li label input[@value='#{author.id}']")
1799
- output_buffer.should have_tag("form li fieldset ol li label input[@name='project[author_id][]']")
1800
- end
1801
- end
1802
- end
1803
- end
1804
- end
1805
-
1806
- describe 'for collections' do
1807
-
1808
- before do
1809
- @new_post.stub!(:author).and_return(@bob)
1810
- @new_post.stub!(:author_id).and_return(@bob.id)
1811
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :integer, :limit => 255))
1812
- end
1813
-
1814
- { :select => :option, :radio => :input, :check_boxes => :'input[@type="checkbox"]' }.each do |type, countable|
1815
-
1816
- describe ":as => #{type.inspect}" do
1817
- describe 'when the :collection option is not provided' do
1818
- it 'should perform a basic find on the association class' do
1819
- Author.should_receive(:find)
1820
-
1821
- semantic_form_for(@new_post) do |builder|
1822
- concat(builder.input(:author, :as => type))
1823
- end
1824
- end
1825
-
1826
- it 'should show a deprecation warning if user gives the association using _id' do
1827
- # Check for deprecation message
1828
- ::ActiveSupport::Deprecation.should_receive(:warn).with(/association/, anything())
1829
-
1830
- Author.should_receive(:find)
1831
- semantic_form_for(@new_post) do |builder|
1832
- concat(builder.input(:author_id, :as => type))
1833
- end
1834
- end
1835
- end
1836
-
1837
- describe 'when the :collection option is provided' do
1838
-
1839
- before do
1840
- @authors = Author.find(:all) * 2
1841
- output_buffer.replace '' # clears the output_buffer from the before block, hax!
1842
- end
1843
-
1844
- it 'should not call find() on the parent class' do
1845
- Author.should_not_receive(:find)
1846
- semantic_form_for(@new_post) do |builder|
1847
- concat(builder.input(:author, :as => type, :collection => @authors))
1848
- end
1849
- end
1850
-
1851
- it 'should use the provided collection' do
1852
- semantic_form_for(@new_post) do |builder|
1853
- concat(builder.input(:author, :as => type, :collection => @authors))
1854
- end
1855
- output_buffer.should have_tag("form li.#{type} #{countable}", :count => @authors.size + (type == :select ? 1 : 0))
1856
- end
1857
-
1858
- describe 'and the :collection is an array of strings' do
1859
- before do
1860
- @new_post.stub!(:category_name).and_return('')
1861
- @categories = [ 'General', 'Design', 'Development' ]
1862
- end
1863
-
1864
- it "should use the string as the label text and value for each #{countable}" do
1865
- semantic_form_for(@new_post) do |builder|
1866
- concat(builder.input(:category_name, :as => type, :collection => @categories))
1867
- end
1868
-
1869
- @categories.each do |value|
1870
- output_buffer.should have_tag("form li.#{type}", /#{value}/)
1871
- output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1872
- end
1873
- end
1874
-
1875
- if type == :radio
1876
- it 'should generate a sanitized label for attribute' do
1877
- @bob.stub!(:category_name).and_return(@categories)
1878
- semantic_form_for(@new_post) do |builder|
1879
- builder.semantic_fields_for(@bob) do |bob_builder|
1880
- concat(bob_builder.input(:category_name, :as => type, :collection => @categories))
1881
- end
1882
- end
1883
-
1884
- @categories.each do |item|
1885
- output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_#{item.downcase}']")
1886
- end
1887
- end
1888
- end
1889
- end
1890
-
1891
- describe 'and the :collection is a hash of strings' do
1892
- before do
1893
- @new_post.stub!(:category_name).and_return('')
1894
- @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }
1895
- end
1896
-
1897
- it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
1898
- semantic_form_for(@new_post) do |builder|
1899
- concat(builder.input(:category_name, :as => type, :collection => @categories))
1900
- end
1901
-
1902
- @categories.each do |label, value|
1903
- output_buffer.should have_tag("form li.#{type}", /#{label}/)
1904
- output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value}']")
1905
- end
1906
- end
1907
- end
1908
-
1909
- describe 'and the :collection is an array of arrays' do
1910
- before do
1911
- @new_post.stub!(:category_name).and_return('')
1912
- @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }.to_a
1913
- end
1914
-
1915
- it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
1916
- semantic_form_for(@new_post) do |builder|
1917
- concat(builder.input(:category_name, :as => type, :collection => @categories))
1918
- end
1919
-
1920
- @categories.each do |text, value|
1921
- label = type == :select ? :option : :label
1922
- output_buffer.should have_tag("form li.#{type} #{label}", /#{text}/i)
1923
- output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1924
- end
1925
- end
1926
- end
1927
-
1928
- describe 'and the :collection is an array of symbols' do
1929
- before do
1930
- @new_post.stub!(:category_name).and_return('')
1931
- @categories = [ :General, :Design, :Development ]
1932
- end
1933
-
1934
- it "should use the symbol as the label text and value for each #{countable}" do
1935
- semantic_form_for(@new_post) do |builder|
1936
- concat(builder.input(:category_name, :as => type, :collection => @categories))
1937
- end
1938
-
1939
- @categories.each do |value|
1940
- label = type == :select ? :option : :label
1941
- output_buffer.should have_tag("form li.#{type} #{label}", /#{value}/i)
1942
- output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{value.to_s}']")
1943
- end
1944
- end
1945
- end
1946
-
1947
- describe 'when the :label_method option is provided' do
1948
- before do
1949
- semantic_form_for(@new_post) do |builder|
1950
- concat(builder.input(:author, :as => type, :label_method => :login))
1951
- end
1952
- end
1953
-
1954
- it 'should have options with text content from the specified method' do
1955
- Author.find(:all).each do |author|
1956
- output_buffer.should have_tag("form li.#{type}", /#{author.login}/)
1957
- end
1958
- end
1959
- end
1960
-
1961
- describe 'when the :label_method option is not provided' do
1962
- Formtastic::SemanticFormBuilder.collection_label_methods.each do |label_method|
1963
-
1964
- describe "when the collection objects respond to #{label_method}" do
1965
- before do
1966
- @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method }
1967
- Author.find(:all).each { |a| a.stub!(label_method).and_return('The Label Text') }
1968
-
1969
- semantic_form_for(@new_post) do |builder|
1970
- concat(builder.input(:author, :as => type))
1971
- end
1972
- end
1973
-
1974
- it "should render the options with #{label_method} as the label" do
1975
- Author.find(:all).each do |author|
1976
- output_buffer.should have_tag("form li.#{type}", /The Label Text/)
1977
- end
1978
- end
1979
- end
1980
-
1981
- end
1982
- end
1983
-
1984
- describe 'when the :value_method option is provided' do
1985
- before do
1986
- semantic_form_for(@new_post) do |builder|
1987
- concat(builder.input(:author, :as => type, :value_method => :login))
1988
- end
1989
- end
1990
-
1991
- it 'should have options with values from specified method' do
1992
- Author.find(:all).each do |author|
1993
- output_buffer.should have_tag("form li.#{type} #{countable}[@value='#{author.login}']")
1994
- end
1995
- end
1996
- end
1997
-
1998
- end
1999
- end
2000
- end
2001
-
2002
- describe 'for boolean attributes' do
2003
-
2004
- { :select => :option, :radio => :input }.each do |type, countable|
2005
- checked_or_selected = { :select => :selected, :radio => :checked }[type]
2006
-
2007
- describe ":as => #{type.inspect}" do
2008
-
2009
- before do
2010
- @new_post.stub!(:allow_comments)
2011
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2012
-
2013
- semantic_form_for(@new_post) do |builder|
2014
- concat(builder.input(:allow_comments, :as => type))
2015
- end
2016
- end
2017
-
2018
- it "should have a #{type} class on the wrapper" do
2019
- output_buffer.should have_tag("form li.#{type}")
2020
- end
2021
-
2022
- it 'should have a post_allow_comments_input id on the wrapper' do
2023
- output_buffer.should have_tag('form li#post_allow_comments_input')
2024
- end
2025
-
2026
- it 'should generate a fieldset containing a legend' do
2027
- output_buffer.should have_tag("form li.#{type}", /Allow comments/)
2028
- end
2029
-
2030
- it "should generate two #{countable}" do
2031
- output_buffer.should have_tag("form li.#{type} #{countable}", :count => (type == :select ? 3 : 2))
2032
- output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"]})
2033
- output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"]})
2034
- end
2035
-
2036
- describe 'when the locale sets the label text' do
2037
- before do
2038
- I18n.backend.store_translations 'en', :formtastic => {:yes => 'Absolutely!', :no => 'Never!'}
2039
-
2040
- semantic_form_for(@new_post) do |builder|
2041
- concat(builder.input(:allow_comments, :as => type))
2042
- end
2043
- end
2044
-
2045
- after do
2046
- I18n.backend.store_translations 'en', :formtastic => {:yes => nil, :no => nil}
2047
- end
2048
-
2049
- it 'should allow translation of the labels' do
2050
- output_buffer.should have_tag("form li.#{type}", /Absolutely\!/)
2051
- output_buffer.should have_tag("form li.#{type}", /Never\!/)
2052
- end
2053
- end
2054
-
2055
- describe 'when the value is nil' do
2056
- before do
2057
- @new_post.stub!(:allow_comments).and_return(nil)
2058
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2059
-
2060
- semantic_form_for(@new_post) do |builder|
2061
- concat(builder.input(:allow_comments, :as => type))
2062
- end
2063
- end
2064
-
2065
- it "should not mark either #{countable} as #{checked_or_selected}" do
2066
- output_buffer.should_not have_tag(%{form li.#{type} input[@#{checked_or_selected}="#{checked_or_selected}"]})
2067
- end
2068
- end
2069
-
2070
- describe 'when the value is true' do
2071
- before do
2072
- @new_post.stub!(:allow_comments).and_return(true)
2073
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2074
- semantic_form_for(@new_post) do |builder|
2075
- concat(builder.input(:allow_comments, :as => type))
2076
- end
2077
- end
2078
-
2079
- it "should mark the true #{countable} as #{checked_or_selected}" do
2080
- output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="true"][@#{checked_or_selected}="#{checked_or_selected}"]}, :count => 1)
2081
- end
2082
-
2083
- it "should not mark the false #{countable} as #{checked_or_selected}" do
2084
- output_buffer.should_not have_tag(%{form li.#{type} #{countable}[@value="false"][@#{checked_or_selected}="#{checked_or_selected}"]})
2085
- end
2086
- end
2087
-
2088
- describe 'when the value is false' do
2089
- before do
2090
- @new_post.stub!(:allow_comments).and_return(false)
2091
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2092
- semantic_form_for(@new_post) do |builder|
2093
- concat(builder.input(:allow_comments, :as => type))
2094
- end
2095
- end
2096
-
2097
- it "should not mark the true #{countable} as #{checked_or_selected}" do
2098
- output_buffer.should_not have_tag(%{form li.#{type} #{countable}[@value="true"][@#{checked_or_selected}="#{checked_or_selected}"]})
2099
- end
2100
-
2101
- it "should mark the false #{countable} as #{checked_or_selected}" do
2102
- output_buffer.should have_tag(%{form li.#{type} #{countable}[@value="false"][@#{checked_or_selected}="#{checked_or_selected}"]}, :count => 1)
2103
- end
2104
- end
2105
-
2106
- describe 'when :true and :false options are provided' do
2107
- before do
2108
- @new_post.stub!(:allow_comments)
2109
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2110
- semantic_form_for(@new_post) do |builder|
2111
- concat(builder.input(:allow_comments, :as => type, :true => "Absolutely", :false => "No Way"))
2112
- end
2113
- end
2114
-
2115
- it 'should use them as labels' do
2116
- output_buffer.should have_tag("form li.#{type}", /Absolutely/)
2117
- output_buffer.should have_tag("form li.#{type}", /No Way/)
2118
- end
2119
- end
2120
- end
2121
-
2122
- end
2123
- end
2124
- end
2125
-
2126
- describe ':as => :date' do
2127
-
2128
- before do
2129
- @new_post.stub!(:publish_at)
2130
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :date))
2131
-
2132
- semantic_form_for(@new_post) do |@builder|
2133
- concat(@builder.input(:publish_at, :as => :date))
2134
- end
2135
- end
2136
-
2137
- it 'should have a date class on the wrapper li' do
2138
- output_buffer.should have_tag('form li.date')
2139
- end
2140
-
2141
- it 'should have a fieldset inside the li wrapper' do
2142
- output_buffer.should have_tag('form li.date fieldset')
2143
- end
2144
-
2145
- it 'should have a legend containing the label text inside the fieldset' do
2146
- output_buffer.should have_tag('form li.date fieldset legend', /Publish at/)
2147
- end
2148
-
2149
- it 'should have an ordered list of three items inside the fieldset' do
2150
- output_buffer.should have_tag('form li.date fieldset ol')
2151
- output_buffer.should have_tag('form li.date fieldset ol li', :count => 3)
2152
- end
2153
-
2154
- it 'should have three labels for year, month and day' do
2155
- output_buffer.should have_tag('form li.date fieldset ol li label', :count => 3)
2156
- output_buffer.should have_tag('form li.date fieldset ol li label', /year/i)
2157
- output_buffer.should have_tag('form li.date fieldset ol li label', /month/i)
2158
- output_buffer.should have_tag('form li.date fieldset ol li label', /day/i)
2159
- end
2160
-
2161
- it 'should have three selects for year, month and day' do
2162
- output_buffer.should have_tag('form li.date fieldset ol li select', :count => 3)
2163
- end
2164
- end
2165
-
2166
- describe ':as => :datetime' do
2167
-
2168
- before do
2169
- @new_post.stub!(:publish_at)
2170
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :datetime))
2171
-
2172
- semantic_form_for(@new_post) do |builder|
2173
- concat(builder.input(:publish_at, :as => :datetime))
2174
- end
2175
- end
2176
-
2177
- it 'should have a datetime class on the wrapper li' do
2178
- output_buffer.should have_tag('form li.datetime')
2179
- end
2180
-
2181
- it 'should have a fieldset inside the li wrapper' do
2182
- output_buffer.should have_tag('form li.datetime fieldset')
2183
- end
2184
-
2185
- it 'should have a legend containing the label text inside the fieldset' do
2186
- output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
2187
- end
2188
-
2189
- it 'should have an ordered list of five items inside the fieldset' do
2190
- output_buffer.should have_tag('form li.datetime fieldset ol')
2191
- output_buffer.should have_tag('form li.datetime fieldset ol li', :count => 5)
2192
- end
2193
-
2194
- it 'should have five labels for year, month, day, hour and minute' do
2195
- output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
2196
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /year/i)
2197
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /month/i)
2198
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /day/i)
2199
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /hour/i)
2200
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /minute/i)
2201
- end
2202
-
2203
- it 'should have five selects for year, month, day, hour and minute' do
2204
- output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2205
- end
2206
-
2207
- it 'should generate a sanitized label and matching ids for attribute' do
2208
- @bob.stub!(:publish_at)
2209
- @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :datetime))
2210
-
2211
- semantic_form_for(@new_post) do |builder|
2212
- builder.semantic_fields_for(@bob, :index => 10) do |bob_builder|
2213
- concat(bob_builder.input(:publish_at, :as => :datetime))
2214
- end
2215
- end
2216
-
2217
- 1.upto(5) do |i|
2218
- output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_10_publish_at_#{i}i']")
2219
- output_buffer.should have_tag("form li fieldset ol li #post_author_10_publish_at_#{i}i")
2220
- end
2221
- end
2222
-
2223
- describe 'when :discard_input => true is set' do
2224
- it 'should use default hidden value equals to 1 when attribute returns nil' do
2225
- semantic_form_for(@new_post) do |builder|
2226
- concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
2227
- end
2228
-
2229
- output_buffer.should have_tag("form li input[@type='hidden'][@value='1']")
2230
- end
2231
-
2232
- it 'should use default attribute value when it is not nil' do
2233
- @new_post.stub!(:publish_at).and_return(Date.new(2007,12,27))
2234
- semantic_form_for(@new_post) do |builder|
2235
- concat(builder.input(:publish_at, :as => :datetime, :discard_day => true))
2236
- end
2237
-
2238
- output_buffer.should have_tag("form li input[@type='hidden'][@value='27']")
2239
- end
2240
- end
2241
-
2242
- describe 'when :include_blank => true is set' do
2243
- before do
2244
- semantic_form_for(@new_post) do |builder|
2245
- concat(builder.input(:publish_at, :as => :datetime, :include_blank => true))
2246
- end
2247
- end
2248
-
2249
- it 'should have a blank select option' do
2250
- output_buffer.should have_tag("option[@value='']", "")
2251
- end
2252
- end
2253
-
2254
- describe 'inputs order' do
2255
- it 'should have a default' do
2256
- semantic_form_for(@new_post) do |builder|
2257
- self.should_receive(:select_year).once.ordered.and_return('')
2258
- self.should_receive(:select_month).once.ordered.and_return('')
2259
- self.should_receive(:select_day).once.ordered.and_return('')
2260
- builder.input(:publish_at, :as => :datetime)
2261
- end
2262
- end
2263
-
2264
- it 'should be specified with :order option' do
2265
- I18n.backend.store_translations 'en', :date => { :order => [:month, :year, :day] }
2266
- semantic_form_for(@new_post) do |builder|
2267
- self.should_receive(:select_month).once.ordered.and_return('')
2268
- self.should_receive(:select_year).once.ordered.and_return('')
2269
- self.should_receive(:select_day).once.ordered.and_return('')
2270
- builder.input(:publish_at, :as => :datetime)
2271
- end
2272
- end
2273
-
2274
- it 'should be changed through I18n' do
2275
- semantic_form_for(@new_post) do |builder|
2276
- self.should_receive(:select_day).once.ordered.and_return('')
2277
- self.should_receive(:select_month).once.ordered.and_return('')
2278
- self.should_receive(:select_year).once.ordered.and_return('')
2279
- builder.input(:publish_at, :as => :datetime, :order => [:day, :month, :year])
2280
- end
2281
- end
2282
- end
2283
-
2284
- describe 'when the locale changes the label text' do
2285
- before do
2286
- I18n.backend.store_translations 'en', :datetime => {:prompts => {
2287
- :year => 'The Year', :month => 'The Month', :day => 'The Day',
2288
- :hour => 'The Hour', :minute => 'The Minute'
2289
- }}
2290
- semantic_form_for(@new_post) do |builder|
2291
- concat(builder.input(:publish_at, :as => :datetime))
2292
- end
2293
- end
2294
-
2295
- after do
2296
- I18n.backend.store_translations 'en', :formtastic => {
2297
- :year => nil, :month => nil, :day => nil,
2298
- :hour => nil, :minute => nil
2299
- }
2300
- end
2301
-
2302
- it 'should have translated labels for year, month, day, hour and minute' do
2303
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Year/)
2304
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Month/)
2305
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Day/)
2306
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Hour/)
2307
- output_buffer.should have_tag('form li.datetime fieldset ol li label', /The Minute/)
2308
- end
2309
- end
2310
-
2311
- describe 'when no object is given' do
2312
- before(:each) do
2313
- output_buffer.replace ''
2314
- semantic_form_for(:project, :url => 'http://test.host') do |@builder|
2315
- concat(@builder.input(:publish_at, :as => :datetime))
2316
- end
2317
- end
2318
-
2319
- it 'should have fieldset with legend' do
2320
- output_buffer.should have_tag('form li.datetime fieldset legend', /Publish at/)
2321
- end
2322
-
2323
- it 'should have labels for each input' do
2324
- output_buffer.should have_tag('form li.datetime fieldset ol li label', :count => 5)
2325
- end
2326
-
2327
- it 'should have selects for each inputs' do
2328
- output_buffer.should have_tag('form li.datetime fieldset ol li select', :count => 5)
2329
- end
2330
- end
2331
- end
2332
-
2333
- describe ':as => :time' do
2334
- before do
2335
- @new_post.stub!(:publish_at)
2336
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :time))
2337
-
2338
- semantic_form_for(@new_post) do |builder|
2339
- concat(builder.input(:publish_at, :as => :time))
2340
- end
2341
- end
2342
-
2343
- it 'should have a time class on the wrapper li' do
2344
- output_buffer.should have_tag('form li.time')
2345
- end
2346
-
2347
- it 'should have a fieldset inside the li wrapper' do
2348
- output_buffer.should have_tag('form li.time fieldset')
2349
- end
2350
-
2351
- it 'should have a legend containing the label text inside the fieldset' do
2352
- output_buffer.should have_tag('form li.time fieldset legend', /Publish at/)
2353
- end
2354
-
2355
- it 'should have an ordered list of two items inside the fieldset' do
2356
- output_buffer.should have_tag('form li.time fieldset ol')
2357
- output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2358
- end
2359
-
2360
- it 'should have five labels for hour and minute' do
2361
- output_buffer.should have_tag('form li.time fieldset ol li label', :count => 2)
2362
- output_buffer.should have_tag('form li.time fieldset ol li label', /hour/i)
2363
- output_buffer.should have_tag('form li.time fieldset ol li label', /minute/i)
2364
- end
2365
-
2366
- it 'should have two selects for hour and minute' do
2367
- #output_buffer.should have_tag('form li.time fieldset ol li select', :count => 2)
2368
- output_buffer.should have_tag('form li.time fieldset ol li', :count => 2)
2369
- end
2370
- end
2371
-
2372
- [:boolean_select, :boolean_radio].each do |type|
2373
- describe ":as => #{type.inspect}" do
2374
- it 'should show a deprecation warning' do
2375
- @new_post.stub!(:allow_comments)
2376
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2377
-
2378
- ::ActiveSupport::Deprecation.should_receive(:warn).with(/select|radio/, anything())
2379
-
2380
- semantic_form_for(@new_post) do |builder|
2381
- concat(builder.input(:allow_comments, :as => type))
2382
- end
2383
- end
2384
- end
2385
- end
2386
-
2387
- describe ':as => :boolean' do
2388
-
2389
- before do
2390
- @new_post.stub!(:allow_comments)
2391
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :boolean))
2392
-
2393
- semantic_form_for(@new_post) do |builder|
2394
- concat(builder.input(:allow_comments, :as => :boolean))
2395
- end
2396
- end
2397
-
2398
- it 'should have a boolean class on the wrapper' do
2399
- output_buffer.should have_tag('form li.boolean')
2400
- end
2401
-
2402
- it 'should have a post_allow_comments_input id on the wrapper' do
2403
- output_buffer.should have_tag('form li#post_allow_comments_input')
2404
- end
2405
-
2406
- it 'should generate a label containing the input' do
2407
- output_buffer.should have_tag('form li label')
2408
- output_buffer.should have_tag('form li label[@for="post_allow_comments"')
2409
- output_buffer.should have_tag('form li label', /Allow comments/)
2410
- output_buffer.should have_tag('form li label input[@type="checkbox"]')
2411
- end
2412
-
2413
- it 'should generate a checkbox input' do
2414
- output_buffer.should have_tag('form li label input')
2415
- output_buffer.should have_tag('form li label input#post_allow_comments')
2416
- output_buffer.should have_tag('form li label input[@type="checkbox"]')
2417
- output_buffer.should have_tag('form li label input[@name="post[allow_comments]"]')
2418
- output_buffer.should have_tag('form li label input[@type="checkbox"][@value="1"]')
2419
- end
2420
-
2421
- it 'should allow checked and unchecked values to be sent' do
2422
- semantic_form_for(@new_post) do |builder|
2423
- concat(builder.input(:allow_comments, :as => :boolean, :checked_value => 'checked', :unchecked_value => 'unchecked'))
2424
- end
2425
-
2426
- output_buffer.should have_tag('form li label input[@type="checkbox"][@value="checked"]')
2427
- output_buffer.should have_tag('form li label input[@type="hidden"][@value="unchecked"]')
2428
- end
2429
-
2430
- it 'should generate a label and a checkbox even if no object is given' do
2431
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
2432
- concat(builder.input(:allow_comments, :as => :boolean))
2433
- end
2434
-
2435
- output_buffer.should have_tag('form li label[@for="project_allow_comments"')
2436
- output_buffer.should have_tag('form li label', /Allow comments/)
2437
- output_buffer.should have_tag('form li label input[@type="checkbox"]')
2438
-
2439
- output_buffer.should have_tag('form li label input#project_allow_comments')
2440
- output_buffer.should have_tag('form li label input[@type="checkbox"]')
2441
- output_buffer.should have_tag('form li label input[@name="project[allow_comments]"]')
2442
- end
2443
-
2444
- end
2445
- end
2446
-
2447
- describe '#inputs' do
2448
-
2449
- describe 'with a block' do
2450
-
2451
- describe 'when no options are provided' do
2452
- before do
2453
- output_buffer.replace 'before_builder' # clear the output buffer and sets before_builder
2454
- semantic_form_for(@new_post) do |builder|
2455
- @inputs_output = builder.inputs do
2456
- concat('hello')
2457
- end
2458
- end
2459
- end
2460
-
2461
- it 'should output just the content wrapped in inputs, not the whole template' do
2462
- output_buffer.should =~ /before_builder/
2463
- @inputs_output.should_not =~ /before_builder/
2464
- end
2465
-
2466
- it 'should render a fieldset inside the form, with a class of "inputs"' do
2467
- output_buffer.should have_tag("form fieldset.inputs")
2468
- end
2469
-
2470
- it 'should render an ol inside the fieldset' do
2471
- output_buffer.should have_tag("form fieldset.inputs ol")
2472
- end
2473
-
2474
- it 'should render the contents of the block inside the ol' do
2475
- output_buffer.should have_tag("form fieldset.inputs ol", /hello/)
2476
- end
2477
-
2478
- it 'should not render a legend inside the fieldset' do
2479
- output_buffer.should_not have_tag("form fieldset.inputs legend")
2480
- end
2481
-
2482
- it 'should render a fieldset even if no object is given' do
2483
- semantic_form_for(:project, :url => 'http://test.host/') do |builder|
2484
- @inputs_output = builder.inputs do
2485
- concat('bye')
2486
- end
2487
- end
2488
-
2489
- output_buffer.should have_tag("form fieldset.inputs ol", /bye/)
2490
- end
2491
- end
2492
-
2493
- describe 'when a :for option is provided' do
2494
- it 'should render nested inputs' do
2495
- @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
2496
-
2497
- semantic_form_for(@new_post) do |builder|
2498
- builder.inputs :for => [:author, @bob] do |bob_builder|
2499
- concat(bob_builder.input(:login))
2500
- end
2501
- end
2502
-
2503
- output_buffer.should have_tag("form fieldset.inputs #post_author_login")
2504
- output_buffer.should_not have_tag("form fieldset.inputs #author_login")
2505
- end
2506
-
2507
- it 'should raise an error if :for and block with no argument is given' do
2508
- semantic_form_for(@new_post) do |builder|
2509
- proc {
2510
- builder.inputs(:for => [:author, @bob]) do
2511
- #
2512
- end
2513
- }.should raise_error(ArgumentError, 'You gave :for option with a block to inputs method, ' <<
2514
- 'but the block does not accept any argument.')
2515
- end
2516
- end
2517
-
2518
- it 'should pass options down to semantic_fields_for' do
2519
- @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
2520
-
2521
- semantic_form_for(@new_post) do |builder|
2522
- builder.inputs :for => [:author, @bob], :for_options => { :index => 10 } do |bob_builder|
2523
- concat(bob_builder.input(:login))
2524
- end
2525
- end
2526
-
2527
- output_buffer.should have_tag('form fieldset ol li #post_author_10_login')
2528
- end
2529
-
2530
- it 'should not add builder as a fieldset attribute tag' do
2531
- semantic_form_for(@new_post) do |builder|
2532
- builder.inputs :for => [:author, @bob], :for_options => { :index => 10 } do |bob_builder|
2533
- concat('input')
2534
- end
2535
- end
2536
-
2537
- output_buffer.should_not have_tag('fieldset[@builder="Formtastic::SemanticFormHelper"]')
2538
- end
2539
-
2540
- it 'should send parent_builder as an option to allow child index interpolation' do
2541
- semantic_form_for(@new_post) do |builder|
2542
- builder.instance_variable_set('@nested_child_index', 0)
2543
- builder.inputs :for => [:author, @bob], :name => 'Author #%i' do |bob_builder|
2544
- concat('input')
2545
- end
2546
- end
2547
-
2548
- output_buffer.should have_tag('fieldset legend', 'Author #1')
2549
- end
2550
-
2551
- it 'should also provide child index interpolation when nested child index is a hash' do
2552
- semantic_form_for(@new_post) do |builder|
2553
- builder.instance_variable_set('@nested_child_index', :author => 10)
2554
- builder.inputs :for => [:author, @bob], :name => 'Author #%i' do |bob_builder|
2555
- concat('input')
2556
- end
2557
- end
2558
-
2559
- output_buffer.should have_tag('fieldset legend', 'Author #11')
2560
- end
2561
- end
2562
-
2563
- describe 'when a :name option is provided' do
2564
- before do
2565
- @legend_text = "Advanced options"
2566
-
2567
- semantic_form_for(@new_post) do |builder|
2568
- builder.inputs :name => @legend_text do
2569
- end
2570
- end
2571
- end
2572
-
2573
- it 'should render a fieldset inside the form' do
2574
- output_buffer.should have_tag("form fieldset legend", /#{@legend_text}/)
2575
- end
2576
- end
2577
-
2578
- describe 'when other options are provided' do
2579
- before do
2580
- @id_option = 'advanced'
2581
- @class_option = 'wide'
2582
-
2583
- semantic_form_for(@new_post) do |builder|
2584
- builder.inputs :id => @id_option, :class => @class_option do
2585
- end
2586
- end
2587
- end
2588
-
2589
- it 'should pass the options into the fieldset tag as attributes' do
2590
- output_buffer.should have_tag("form fieldset##{@id_option}")
2591
- output_buffer.should have_tag("form fieldset.#{@class_option}")
2592
- end
2593
- end
2594
-
2595
- end
2596
-
2597
- describe 'without a block' do
2598
-
2599
- before do
2600
- Post.stub!(:reflections).and_return({:author => mock('reflection', :options => {}, :macro => :belongs_to),
2601
- :comments => mock('reflection', :options => {}, :macro => :has_many) })
2602
- Post.stub!(:content_columns).and_return([mock('column', :name => 'title'), mock('column', :name => 'body'), mock('column', :name => 'created_at')])
2603
- Author.stub!(:find).and_return([@fred, @bob])
2604
-
2605
- @new_post.stub!(:title)
2606
- @new_post.stub!(:body)
2607
- @new_post.stub!(:author_id)
2608
-
2609
- @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :string, :limit => 255))
2610
- @new_post.stub!(:column_for_attribute).with(:body).and_return(mock('column', :type => :text))
2611
- @new_post.stub!(:column_for_attribute).with(:created_at).and_return(mock('column', :type => :datetime))
2612
- @new_post.stub!(:column_for_attribute).with(:author).and_return(nil)
2613
- end
2614
-
2615
- describe 'with no args' do
2616
- before do
2617
- semantic_form_for(@new_post) do |builder|
2618
- concat(builder.inputs)
2619
- end
2620
- end
2621
-
2622
- it 'should render a form' do
2623
- output_buffer.should have_tag('form')
2624
- end
2625
-
2626
- it 'should render a fieldset inside the form' do
2627
- output_buffer.should have_tag('form > fieldset.inputs')
2628
- end
2629
-
2630
- it 'should not render a legend in the fieldset' do
2631
- output_buffer.should_not have_tag('form > fieldset.inputs > legend')
2632
- end
2633
-
2634
- it 'should render an ol in the fieldset' do
2635
- output_buffer.should have_tag('form > fieldset.inputs > ol')
2636
- end
2637
-
2638
- it 'should render a list item in the ol for each column and reflection' do
2639
- # Remove the :has_many macro and :created_at column
2640
- count = Post.content_columns.size + Post.reflections.size - 2
2641
- output_buffer.should have_tag('form > fieldset.inputs > ol > li', :count => count)
2642
- end
2643
-
2644
- it 'should render a string list item for title' do
2645
- output_buffer.should have_tag('form > fieldset.inputs > ol > li.string')
2646
- end
2647
-
2648
- it 'should render a text list item for body' do
2649
- output_buffer.should have_tag('form > fieldset.inputs > ol > li.text')
2650
- end
2651
-
2652
- it 'should render a select list item for author_id' do
2653
- output_buffer.should have_tag('form > fieldset.inputs > ol > li.select', :count => 1)
2654
- end
2655
-
2656
- it 'should not render timestamps inputs by default' do
2657
- output_buffer.should_not have_tag('form > fieldset.inputs > ol > li.datetime')
2658
- end
2659
- end
2660
-
2661
- describe 'with column names as args' do
2662
- describe 'and an object is given' do
2663
- it 'should render a form with a fieldset containing two list items' do
2664
- semantic_form_for(@new_post) do |builder|
2665
- concat(builder.inputs(:title, :body))
2666
- end
2667
-
2668
- output_buffer.should have_tag('form > fieldset.inputs > ol > li', :count => 2)
2669
- output_buffer.should have_tag('form > fieldset.inputs > ol > li.string')
2670
- output_buffer.should have_tag('form > fieldset.inputs > ol > li.text')
2671
- end
2672
- end
2673
-
2674
- describe 'and no object is given' do
2675
- it 'should render a form with a fieldset containing two list items' do
2676
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
2677
- concat(builder.inputs(:title, :body))
2678
- end
2679
-
2680
- output_buffer.should have_tag('form > fieldset.inputs > ol > li.string', :count => 2)
2681
- end
2682
- end
2683
- end
2684
-
2685
- describe 'when a :for option is provided' do
2686
- describe 'and an object is given' do
2687
- it 'should render nested inputs' do
2688
- @bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
2689
-
2690
- semantic_form_for(@new_post) do |builder|
2691
- concat(builder.inputs(:login, :for => @bob))
2692
- end
2693
-
2694
- output_buffer.should have_tag("form fieldset.inputs #post_author_login")
2695
- output_buffer.should_not have_tag("form fieldset.inputs #author_login")
2696
- end
2697
- end
2698
-
2699
- describe 'and no object is given' do
2700
- it 'should render nested inputs' do
2701
- semantic_form_for(:project, :url => 'http://test.host/') do |builder|
2702
- concat(builder.inputs(:login, :for => @bob))
2703
- end
2704
-
2705
- output_buffer.should have_tag("form fieldset.inputs #project_author_login")
2706
- output_buffer.should_not have_tag("form fieldset.inputs #project_login")
2707
- end
2708
- end
2709
- end
2710
-
2711
- describe 'with column names and an options hash as args' do
2712
- before do
2713
- semantic_form_for(@new_post) do |builder|
2714
- concat(builder.inputs(:title, :body, :name => "Legendary Legend Text", :id => "my-id"))
2715
- end
2716
- end
2717
-
2718
- it 'should render a form with a fieldset containing two list items' do
2719
- output_buffer.should have_tag('form > fieldset.inputs > ol > li', :count => 2)
2720
- end
2721
-
2722
- it 'should pass the options down to the fieldset' do
2723
- output_buffer.should have_tag('form > fieldset#my-id.inputs')
2724
- end
2725
-
2726
- it 'should use the special :name option as a text for the legend tag' do
2727
- output_buffer.should have_tag('form > fieldset#my-id.inputs > legend', /Legendary Legend Text/)
2728
- end
2729
- end
2730
-
2731
- end
2732
-
2733
- end
2734
-
2735
- describe '#buttons' do
2736
-
2737
- describe 'with a block' do
2738
- describe 'when no options are provided' do
2739
- before do
2740
- semantic_form_for(@new_post) do |builder|
2741
- builder.buttons do
2742
- concat('hello')
2743
- end
2744
- end
2745
- end
2746
-
2747
- it 'should render a fieldset inside the form, with a class of "inputs"' do
2748
- output_buffer.should have_tag("form fieldset.buttons")
2749
- end
2750
-
2751
- it 'should render an ol inside the fieldset' do
2752
- output_buffer.should have_tag("form fieldset.buttons ol")
2753
- end
2754
-
2755
- it 'should render the contents of the block inside the ol' do
2756
- output_buffer.should have_tag("form fieldset.buttons ol", /hello/)
2757
- end
2758
-
2759
- it 'should not render a legend inside the fieldset' do
2760
- output_buffer.should_not have_tag("form fieldset.buttons legend")
2761
- end
2762
- end
2763
-
2764
- describe 'when a :name option is provided' do
2765
- before do
2766
- @legend_text = "Advanced options"
2767
-
2768
- semantic_form_for(@new_post) do |builder|
2769
- builder.buttons :name => @legend_text do
2770
- end
2771
- end
2772
- end
2773
- it 'should render a fieldset inside the form' do
2774
- output_buffer.should have_tag("form fieldset legend", /#{@legend_text}/)
2775
- end
2776
- end
2777
-
2778
- describe 'when other options are provided' do
2779
- before do
2780
- @id_option = 'advanced'
2781
- @class_option = 'wide'
2782
-
2783
- semantic_form_for(@new_post) do |builder|
2784
- builder.buttons :id => @id_option, :class => @class_option do
2785
- end
2786
- end
2787
- end
2788
- it 'should pass the options into the fieldset tag as attributes' do
2789
- output_buffer.should have_tag("form fieldset##{@id_option}")
2790
- output_buffer.should have_tag("form fieldset.#{@class_option}")
2791
- end
2792
- end
2793
-
2794
- end
2795
-
2796
- describe 'without a block' do
2797
-
2798
- describe 'with no args (default buttons)' do
2799
-
2800
- before do
2801
- semantic_form_for(@new_post) do |builder|
2802
- concat(builder.buttons)
2803
- end
2804
- end
2805
-
2806
- it 'should render a form' do
2807
- output_buffer.should have_tag('form')
2808
- end
2809
-
2810
- it 'should render a buttons fieldset inside the form' do
2811
- output_buffer.should have_tag('form fieldset.buttons')
2812
- end
2813
-
2814
- it 'should not render a legend in the fieldset' do
2815
- output_buffer.should_not have_tag('form fieldset.buttons legend')
2816
- end
2817
-
2818
- it 'should render an ol in the fieldset' do
2819
- output_buffer.should have_tag('form fieldset.buttons ol')
2820
- end
2821
-
2822
- it 'should render a list item in the ol for each default button' do
2823
- output_buffer.should have_tag('form fieldset.buttons ol li', :count => 1)
2824
- end
2825
-
2826
- it 'should render a commit list item for the commit button' do
2827
- output_buffer.should have_tag('form fieldset.buttons ol li.commit')
2828
- end
2829
-
2830
- end
2831
-
2832
- describe 'with button names as args' do
2833
-
2834
- before do
2835
- semantic_form_for(@new_post) do |builder|
2836
- concat(builder.buttons(:commit))
2837
- end
2838
- end
2839
-
2840
- it 'should render a form with a fieldset containing a list item for each button arg' do
2841
- output_buffer.should have_tag('form > fieldset.buttons > ol > li', :count => 1)
2842
- output_buffer.should have_tag('form > fieldset.buttons > ol > li.commit')
2843
- end
2844
-
2845
- end
2846
-
2847
- describe 'with button names as args and an options hash' do
2848
-
2849
- before do
2850
- semantic_form_for(@new_post) do |builder|
2851
- concat(builder.buttons(:commit, :name => "Now click a button", :id => "my-id"))
2852
- end
2853
- end
2854
-
2855
- it 'should render a form with a fieldset containing a list item for each button arg' do
2856
- output_buffer.should have_tag('form > fieldset.buttons > ol > li', :count => 1)
2857
- output_buffer.should have_tag('form > fieldset.buttons > ol > li.commit', :count => 1)
2858
- end
2859
-
2860
- it 'should pass the options down to the fieldset' do
2861
- output_buffer.should have_tag('form > fieldset#my-id.buttons')
2862
- end
2863
-
2864
- it 'should use the special :name option as a text for the legend tag' do
2865
- output_buffer.should have_tag('form > fieldset#my-id.buttons > legend', /Now click a button/)
2866
- end
2867
-
2868
- end
2869
-
2870
- end
2871
-
2872
- end
2873
-
2874
- describe '#commit_button' do
2875
-
2876
- describe 'when used on any record' do
2877
-
2878
- before do
2879
- @new_post.stub!(:new_record?).and_return(false)
2880
- semantic_form_for(@new_post) do |builder|
2881
- concat(builder.commit_button)
2882
- end
2883
- end
2884
-
2885
- it 'should render a commit li' do
2886
- output_buffer.should have_tag('li.commit')
2887
- end
2888
-
2889
- it 'should render an input with a type attribute of "submit"' do
2890
- output_buffer.should have_tag('li.commit input[@type="submit"]')
2891
- end
2892
-
2893
- it 'should render an input with a name attribute of "commit"' do
2894
- output_buffer.should have_tag('li.commit input[@name="commit"]')
2895
- end
2896
-
2897
- it 'should pass options given in :button_html to the button' do
2898
- @new_post.stub!(:new_record?).and_return(false)
2899
- semantic_form_for(@new_post) do |builder|
2900
- concat(builder.commit_button('text', :button_html => {:class => 'my_class', :id => 'my_id'}))
2901
- end
2902
-
2903
- output_buffer.should have_tag('li.commit input#my_id')
2904
- output_buffer.should have_tag('li.commit input.my_class')
2905
- end
2906
-
2907
- end
2908
-
2909
- describe 'when the first option is a string and the second is a hash' do
2910
-
2911
- before do
2912
- @new_post.stub!(:new_record?).and_return(false)
2913
- semantic_form_for(@new_post) do |builder|
2914
- concat(builder.commit_button("a string", :button_html => { :class => "pretty"}))
2915
- end
2916
- end
2917
-
2918
- it "should render the string as the value of the button" do
2919
- output_buffer.should have_tag('li input[@value="a string"]')
2920
- end
2921
-
2922
- it "should deal with the options hash" do
2923
- output_buffer.should have_tag('li input.pretty')
2924
- end
2925
-
2926
- end
2927
-
2928
- describe 'when the first option is a hash' do
2929
-
2930
- before do
2931
- @new_post.stub!(:new_record?).and_return(false)
2932
- semantic_form_for(@new_post) do |builder|
2933
- concat(builder.commit_button(:button_html => { :class => "pretty"}))
2934
- end
2935
- end
2936
-
2937
- it "should deal with the options hash" do
2938
- output_buffer.should have_tag('li input.pretty')
2939
- end
2940
-
2941
- end
2942
-
2943
- describe 'when used on an existing record' do
2944
-
2945
- it 'should render an input with a value attribute of "Save Post"' do
2946
- @new_post.stub!(:new_record?).and_return(false)
2947
- semantic_form_for(@new_post) do |builder|
2948
- concat(builder.commit_button)
2949
- end
2950
- output_buffer.should have_tag('li.commit input[@value="Save Post"]')
2951
- end
2952
-
2953
- describe 'when the locale sets the label text' do
2954
- before do
2955
- I18n.backend.store_translations 'en', :formtastic => {:save => 'Save Changes To' }
2956
- @new_post.stub!(:new_record?).and_return(false)
2957
- semantic_form_for(@new_post) do |builder|
2958
- concat(builder.commit_button)
2959
- end
2960
- end
2961
-
2962
- after do
2963
- I18n.backend.store_translations 'en', :formtastic => {:save => nil}
2964
- end
2965
-
2966
- it 'should allow translation of the labels' do
2967
- output_buffer.should have_tag('li.commit input[@value="Save Changes To Post"]')
2968
- end
2969
- end
2970
- end
2971
-
2972
- describe 'when used on a new record' do
2973
-
2974
- it 'should render an input with a value attribute of "Create Post"' do
2975
- @new_post.stub!(:new_record?).and_return(true)
2976
- semantic_form_for(@new_post) do |builder|
2977
- concat(builder.commit_button)
2978
- end
2979
- output_buffer.should have_tag('li.commit input[@value="Create Post"]')
2980
- end
2981
-
2982
- describe 'when the locale sets the label text' do
2983
- before do
2984
- I18n.backend.store_translations 'en', :formtastic => {:create => 'Make' }
2985
- semantic_form_for(@new_post) do |builder|
2986
- concat(builder.commit_button)
2987
- end
2988
- end
2989
-
2990
- after do
2991
- I18n.backend.store_translations 'en', :formtastic => {:create => nil}
2992
- end
2993
-
2994
- it 'should allow translation of the labels' do
2995
- output_buffer.should have_tag('li.commit input[@value="Make Post"]')
2996
- end
2997
- end
2998
-
2999
- end
3000
-
3001
- describe 'when used without object' do
3002
-
3003
- it 'should render an input with a value attribute of "Submit"' do
3004
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
3005
- concat(builder.commit_button)
3006
- end
3007
-
3008
- output_buffer.should have_tag('li.commit input[@value="Submit Project"]')
3009
- end
3010
-
3011
- describe 'when the locale sets the label text' do
3012
- before do
3013
- I18n.backend.store_translations 'en', :formtastic => { :submit => 'Send' }
3014
- semantic_form_for(:project, :url => 'http://test.host') do |builder|
3015
- concat(builder.commit_button)
3016
- end
3017
- end
3018
-
3019
- after do
3020
- I18n.backend.store_translations 'en', :formtastic => {:submit => nil}
3021
- end
3022
-
3023
- it 'should allow translation of the labels' do
3024
- output_buffer.should have_tag('li.commit input[@value="Send Project"]')
3025
- end
3026
- end
3027
-
3028
- end
3029
-
3030
- end
3031
-
3032
- describe "Nested Js Helpers" do
3033
-
3034
- it "should have a add method" do
3035
- @new_post.stub!(:authors).and_return(@mock_authors = mock("Authors", :build => []))
3036
-
3037
- semantic_form_for(@new_post) do |builder|
3038
- builder.inputs :name => "Contacts" do
3039
- concat(builder.add_associated_link(:name, :authors))
3040
- end
3041
- end
3042
-
3043
- output_buffer.should eql("<form action=\"/posts\" class=\"formtastic post\" id=\"new_post\" method=\"post\"><fieldset class=\"inputs\"><legend><span>Contacts</span></legend><ol><a href=\"#\" onclick=\"if (typeof formtastic_next_array_id == 'undefined') formtastic_next_array_id = 0;\n $('#arrays').append($.template(null), { number: --formtastic_next_array_id});; return false;\">name</a></ol></fieldset></form>")
3044
- end
3045
-
3046
- it "should have a remove method" do
3047
- semantic_form_for(@new_post) do |builder|
3048
- builder.semantic_fields_for(:links) do |link_builder|
3049
- concat(link_builder.remove_link("Remove"))
3050
- end
3051
- end
3052
-
3053
- output_buffer.should eql("<form action=\"/posts\" class=\"formtastic post\" id=\"new_post\" method=\"post\"><input id=\"post_links__delete\" name=\"post[links][_delete]\" type=\"hidden\" /><a href=\"#\" onclick=\";$(this).parents('.nil_class').hide(); $(this).prev(':input').val('1');; return false;\">Remove</a></form>")
3054
- end
3055
-
3056
- it "should have a show method" do
3057
- @new_post.stub!(:authors).and_return(@mock_authors = mock("Authors"))
3058
- pending
3059
- semantic_form_for(@new_post) do |builder|
3060
- builder.inputs :name => "Contacts" do
3061
- concat(builder.render_associated_form @new_post.authors)
3062
- end
3063
- end
3064
-
3065
- output_buffer.should eql("<form action=\"/posts\" class=\"formtastic post\" id=\"new_post\" method=\"post\"><fieldset class=\"inputs\"><legend><span>Contacts</span></legend><ol><a href=\"#\" onclick=\"if (typeof formtastic_next_array_id == 'undefined') formtastic_next_array_id = 0;\n $('#arrays').append($.template(null), { number: --formtastic_next_array_id});; return false;\">name</a></ol></fieldset></form>")
3066
- end
3067
-
3068
- end
3069
-
3070
- end
3071
-
3072
- end