formtastic 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/formtastic.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ require File.join(File.dirname(__FILE__), *%w[formtastic i18n])
2
3
 
3
4
  module Formtastic #:nodoc:
4
5
 
@@ -7,7 +8,7 @@ module Formtastic #:nodoc:
7
8
  @@default_text_field_size = 50
8
9
  @@all_fields_required_by_default = true
9
10
  @@include_blank_for_select_by_default = true
10
- @@required_string = proc { %{<abbr title="#{I18n.t 'formtastic.required', :default => 'required'}">*</abbr>} }
11
+ @@required_string = proc { %{<abbr title="#{::Formtastic::I18n.t 'formtastic.required', :default => 'required'}">*</abbr>} }
11
12
  @@optional_string = ''
12
13
  @@inline_errors = :sentence
13
14
  @@label_str_method = :humanize
@@ -22,10 +23,14 @@ module Formtastic #:nodoc:
22
23
  :required_string, :optional_string, :inline_errors, :label_str_method, :collection_label_methods,
23
24
  :inline_order, :file_methods, :priority_countries, :i18n_lookups_by_default, :default_commit_button_accesskey
24
25
 
26
+ RESERVED_COLUMNS = [:created_at, :updated_at, :created_on, :updated_on, :lock_version, :version]
27
+
28
+ INLINE_ERROR_TYPES = [:sentence, :list, :first]
29
+
25
30
  I18N_SCOPES = [ '{{model}}.{{action}}.{{attribute}}',
26
31
  '{{model}}.{{attribute}}',
27
32
  '{{attribute}}']
28
-
33
+
29
34
  attr_accessor :template
30
35
 
31
36
  # Returns a suitable form input for the given +method+, using the database column information
@@ -65,7 +70,8 @@ module Formtastic #:nodoc:
65
70
  #
66
71
  # <% semantic_form_for @employee do |form| %>
67
72
  # <% form.inputs do -%>
68
- # <%= form.input :name, :label => "Full Name"%>
73
+ # <%= form.input :secret, :value => "Hello" %>
74
+ # <%= form.input :name, :label => "Full Name" %>
69
75
  # <%= form.input :manager_id, :as => :radio %>
70
76
  # <%= form.input :hired_at, :as => :date, :label => "Date Hired" %>
71
77
  # <%= form.input :phone, :required => false, :hint => "Eg: +1 555 1234" %>
@@ -136,11 +142,16 @@ module Formtastic #:nodoc:
136
142
  # <%= form.inputs %>
137
143
  # <% end %>
138
144
  #
145
+ # With a few arguments:
146
+ # <% semantic_form_for @post do |form| %>
147
+ # <%= form.inputs "Post details", :title, :body %>
148
+ # <% end %>
149
+ #
139
150
  # === Options
140
151
  #
141
- # All options (with the exception of :name) are passed down to the fieldset as HTML
142
- # attributes (id, class, style, etc). If provided, the :name option is passed into a
143
- # legend tag inside the fieldset (otherwise a legend is not generated).
152
+ # All options (with the exception of :name/:title) are passed down to the fieldset as HTML
153
+ # attributes (id, class, style, etc). If provided, the :name/:title option is passed into a
154
+ # legend tag inside the fieldset.
144
155
  #
145
156
  # # With a block:
146
157
  # <% semantic_form_for @post do |form| %>
@@ -154,6 +165,11 @@ module Formtastic #:nodoc:
154
165
  # <%= form.inputs :title, :body, :name => "Create a new post", :style => "border:1px;" %>
155
166
  # <% end %>
156
167
  #
168
+ # # ...or the equivalent:
169
+ # <% semantic_form_for @post do |form| %>
170
+ # <%= form.inputs "Create a new post", :title, :body, :style => "border:1px;" %>
171
+ # <% end %>
172
+ #
157
173
  # === It's basically a fieldset!
158
174
  #
159
175
  # Instead of hard-coding fieldsets & legends into your form to logically group related fields,
@@ -168,6 +184,9 @@ module Formtastic #:nodoc:
168
184
  # <%= f.input :created_at %>
169
185
  # <%= f.input :user_id, :label => "Author" %>
170
186
  # <% end %>
187
+ # <% f.inputs "Extra" do %>
188
+ # <%= f.input :update_at %>
189
+ # <% end %>
171
190
  # <% end %>
172
191
  #
173
192
  # # Output:
@@ -185,6 +204,12 @@ module Formtastic #:nodoc:
185
204
  # <li class="select">...</li>
186
205
  # </ol>
187
206
  # </fieldset>
207
+ # <fieldset class="inputs">
208
+ # <legend><span>Extra</span></legend>
209
+ # <ol>
210
+ # <li class="datetime">...</li>
211
+ # </ol>
212
+ # </fieldset>
188
213
  # </form>
189
214
  #
190
215
  # === Nested attributes
@@ -232,17 +257,19 @@ module Formtastic #:nodoc:
232
257
  if html_options[:for]
233
258
  inputs_for_nested_attributes(args, html_options, &block)
234
259
  elsif block_given?
235
- field_set_and_list_wrapping(html_options, &block)
260
+ field_set_and_list_wrapping(*(args << html_options), &block)
236
261
  else
237
262
  if @object && args.empty?
238
- args = @object.class.reflections.map { |n,_| n if _.macro == :belongs_to }
239
- args += @object.class.content_columns.map(&:name)
240
- args -= %w[created_at updated_at created_on updated_on lock_version version]
263
+ args = self.association_columns(:belongs_to)
264
+ args += self.content_columns
265
+ args -= RESERVED_COLUMNS
241
266
  args.compact!
242
267
  end
243
- contents = args.map { |method| input(method.to_sym) }
244
-
245
- field_set_and_list_wrapping(html_options, contents)
268
+ legend = args.shift if args.first.is_a?(::String)
269
+ contents = args.collect { |method| input(method.to_sym) }
270
+ args.unshift(legend) if legend.present?
271
+
272
+ field_set_and_list_wrapping(*((args << html_options) << contents))
246
273
  end
247
274
  end
248
275
  alias :input_field_set :inputs
@@ -295,7 +322,7 @@ module Formtastic #:nodoc:
295
322
  fallback_text ||= "#{key.to_s.humanize} {{model}}"
296
323
 
297
324
  text = (self.localized_string(key, text, :action, :model => object_name) ||
298
- ::I18n.t(key, :model => object_name, :default => fallback_text, :scope => [:formtastic])) unless text.is_a?(::String)
325
+ ::Formtastic::I18n.t(key, :model => object_name)) unless text.is_a?(::String)
299
326
 
300
327
  button_html = options.delete(:button_html) || {}
301
328
  button_html.merge!(:class => [button_html[:class], key].compact.join(' '))
@@ -326,7 +353,7 @@ module Formtastic #:nodoc:
326
353
  #
327
354
  def semantic_fields_for(record_or_name_or_array, *args, &block)
328
355
  opts = args.extract_options!
329
- opts.merge!(:builder => Formtastic::SemanticFormHelper.builder)
356
+ opts.merge!(:builder => ::Formtastic::SemanticFormHelper.builder)
330
357
  args.push(opts)
331
358
  fields_for(record_or_name_or_array, *args, &block)
332
359
  end
@@ -338,7 +365,6 @@ module Formtastic #:nodoc:
338
365
  # * :required - Appends an abbr tag if :required is true
339
366
  # * :label - An alternative form to give the label content. Whenever label
340
367
  # is false, a blank string is returned.
341
- # * :as_span - When true returns a span tag with class label instead of a label element
342
368
  # * :input_name - Gives the input to match for. This is needed when you want to
343
369
  # to call f.label :authors but it should match :author_ids.
344
370
  #
@@ -362,17 +388,12 @@ module Formtastic #:nodoc:
362
388
  end
363
389
  text = localized_string(method, text, :label) || humanized_attribute_name(method)
364
390
  text += required_or_optional_string(options.delete(:required))
365
-
391
+
366
392
  # special case for boolean (checkbox) labels, which have a nested input
367
393
  text = (options.delete(:label_prefix_for_nested_input) || "") + text
368
-
394
+
369
395
  input_name = options.delete(:input_name) || method
370
- if options.delete(:as_span)
371
- options[:class] ||= 'label'
372
- template.content_tag(:span, text, options)
373
- else
374
- super(input_name, text, options)
375
- end
396
+ super(input_name, text, options)
376
397
  end
377
398
 
378
399
  # Generates error messages for the given method. Errors can be shown as list,
@@ -387,15 +408,41 @@ module Formtastic #:nodoc:
387
408
  # end
388
409
  #
389
410
  def inline_errors_for(method, options=nil) #:nodoc:
390
- return nil unless @object && @object.respond_to?(:errors) && [:sentence, :list, :first].include?(@@inline_errors)
411
+ return nil unless @object && @object.respond_to?(:errors) && INLINE_ERROR_TYPES.include?(@@inline_errors)
391
412
 
392
413
  errors = @object.errors[method.to_sym]
393
- send("error_#{@@inline_errors}", Array(errors)) unless errors.blank?
414
+ send(:"error_#{@@inline_errors}", Array(errors)) unless errors.blank?
394
415
  end
395
416
  alias :errors_on :inline_errors_for
396
417
 
397
418
  protected
398
419
 
420
+ # Collects content columns (non-relation columns) for the current form object class.
421
+ #
422
+ def content_columns
423
+ if @object.present?
424
+ @object.class.name.constantize.content_columns.collect { |c| c.name.to_sym }.compact
425
+ else
426
+ @object_name.to_s.classify.constantize.content_columns.collect { |c| c.name.to_sym }.compact rescue []
427
+ end
428
+ end
429
+
430
+ # Collects association columns (relation columns) for the current form object class.
431
+ #
432
+ def association_columns(*by_associations)
433
+ if @object.present?
434
+ @object.class.reflections.collect do |name, _|
435
+ if by_associations.present?
436
+ name if by_associations.include?(_.macro)
437
+ else
438
+ name
439
+ end
440
+ end.compact
441
+ else
442
+ []
443
+ end
444
+ end
445
+
399
446
  # Prepare options to be sent to label
400
447
  #
401
448
  def options_for_label(options)
@@ -478,7 +525,7 @@ module Formtastic #:nodoc:
478
525
  html_options = options.delete(:input_html) || {}
479
526
  html_options = default_string_options(method, type).merge(html_options) if [:numeric, :string, :password].include?(type)
480
527
 
481
- self.label(method, options_for_label(options)) +
528
+ self.label(method, options_for_label(options)) <<
482
529
  self.send(form_helper_method, method, html_options)
483
530
  end
484
531
 
@@ -491,17 +538,17 @@ module Formtastic #:nodoc:
491
538
  def password_input(method, options)
492
539
  basic_input_helper(:password_field, :password, method, options)
493
540
  end
494
-
541
+
495
542
  # Outputs a label and standard Rails text field inside the wrapper.
496
543
  def numeric_input(method, options)
497
544
  basic_input_helper(:text_field, :numeric, method, options)
498
545
  end
499
-
546
+
500
547
  # Ouputs a label and standard Rails text area inside the wrapper.
501
548
  def text_input(method, options)
502
549
  basic_input_helper(:text_area, :text, method, options)
503
550
  end
504
-
551
+
505
552
  # Outputs a label and a standard Rails file field inside the wrapper.
506
553
  def file_input(method, options)
507
554
  basic_input_helper(:file_field, :file, method, options)
@@ -510,7 +557,12 @@ module Formtastic #:nodoc:
510
557
  # Outputs a hidden field inside the wrapper, which should be hidden with CSS.
511
558
  # Additionals options can be given and will be sent straight to hidden input
512
559
  # element.
560
+ #
513
561
  def hidden_input(method, options)
562
+ options ||= {}
563
+ if options[:input_html].present?
564
+ options[:value] = options[:input_html][:value] if options[:input_html][:value].present?
565
+ end
514
566
  self.hidden_field(method, set_options(options))
515
567
  end
516
568
 
@@ -625,12 +677,10 @@ module Formtastic #:nodoc:
625
677
  options[:include_blank] = false
626
678
  html_options[:multiple] ||= true
627
679
  html_options[:size] ||= 5
628
- end
629
-
680
+ end
630
681
  input_name = generate_association_input_name(method)
631
- self.label(method, options_for_label(options).merge(:input_name => input_name)) +
632
682
 
633
- if options[:group_by]
683
+ select_html = if options[:group_by]
634
684
  # The grouped_options_select is a bit counter intuitive and not optimised (mostly due to ActiveRecord).
635
685
  # The formtastic user however shouldn't notice this too much.
636
686
  raw_collection = find_raw_collection_for_column(method, options.reverse_merge(:find_options => { :include => options[:group_by] }))
@@ -648,6 +698,8 @@ module Formtastic #:nodoc:
648
698
  collection = find_collection_for_column(method, options)
649
699
  self.select(input_name, collection, set_options(options), html_options)
650
700
  end
701
+
702
+ self.label(method, options_for_label(options).merge(:input_name => input_name)) << select_html
651
703
  end
652
704
  alias :boolean_select_input :select_input
653
705
 
@@ -661,7 +713,7 @@ module Formtastic #:nodoc:
661
713
  def time_zone_input(method, options)
662
714
  html_options = options.delete(:input_html) || {}
663
715
 
664
- self.label(method, options_for_label(options)) +
716
+ self.label(method, options_for_label(options)) <<
665
717
  self.time_zone_select(method, options.delete(:priority_zones), set_options(options), html_options)
666
718
  end
667
719
 
@@ -732,22 +784,24 @@ module Formtastic #:nodoc:
732
784
 
733
785
  input_name = generate_association_input_name(method)
734
786
  value_as_class = options.delete(:value_as_class)
787
+ input_ids = []
735
788
 
736
789
  list_item_content = collection.map do |c|
737
790
  label = c.is_a?(Array) ? c.first : c
738
791
  value = c.is_a?(Array) ? c.last : c
739
792
  html_options[:checked] = options.delete(:selected) unless options[:selected].blank?
740
793
 
794
+ input_ids << input_id = generate_html_id(input_name, value.to_s.gsub(/\s/, '_').gsub(/\W/, '').downcase)
741
795
  li_content = template.content_tag(:label,
742
796
  "#{self.radio_button(input_name, value, html_options)} #{label}",
743
- :for => generate_html_id(input_name, value.to_s.gsub(/\s/, '_').gsub(/\W/, '').downcase)
797
+ :for => input_id
744
798
  )
745
799
 
746
800
  li_options = value_as_class ? { :class => value.to_s.downcase } : {}
747
801
  template.content_tag(:li, li_content, li_options)
748
802
  end
749
803
 
750
- field_set_and_list_wrapping_for_method(method, options, list_item_content)
804
+ field_set_and_list_wrapping_for_method(method, options.merge(:label_for => input_ids.first), list_item_content)
751
805
  end
752
806
  alias :boolean_radio_input :radio_input
753
807
 
@@ -761,7 +815,6 @@ module Formtastic #:nodoc:
761
815
  date_or_datetime_input(method, options.merge(:discard_hour => true))
762
816
  end
763
817
 
764
-
765
818
  # Outputs a fieldset with a legend for the method label, and a ordered list (ol) of list
766
819
  # items (li), one for each fragment for the date (year, month, day, hour, min, sec). Each li
767
820
  # contains a label (eg "Year") and a select box. See date_or_datetime_input for a more
@@ -773,7 +826,6 @@ module Formtastic #:nodoc:
773
826
  date_or_datetime_input(method, options)
774
827
  end
775
828
 
776
-
777
829
  # Outputs a fieldset with a legend for the method label, and a ordered list (ol) of list
778
830
  # items (li), one for each fragment for the time (hour, minute, second). Each li contains a label
779
831
  # (eg "Hour") and a select box. See date_or_datetime_input for a more detailed output example.
@@ -784,7 +836,6 @@ module Formtastic #:nodoc:
784
836
  date_or_datetime_input(method, options.merge(:discard_year => true, :discard_month => true, :discard_day => true))
785
837
  end
786
838
 
787
-
788
839
  # <fieldset>
789
840
  # <legend>Created At</legend>
790
841
  # <ol>
@@ -819,7 +870,8 @@ module Formtastic #:nodoc:
819
870
  #
820
871
  def date_or_datetime_input(method, options)
821
872
  position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 }
822
- i18n_date_order = I18n.translate(:'date.order').is_a?(Array) ? I18n.translate(:'date.order') : nil
873
+ i18n_date_order = ::I18n.t(:order, :scope => [:date])
874
+ i18n_date_order = nil unless i18n_date_order.is_a?(Array)
823
875
  inputs = options.delete(:order) || i18n_date_order || [:year, :month, :day]
824
876
 
825
877
  time_inputs = [:hour, :minute]
@@ -831,30 +883,31 @@ module Formtastic #:nodoc:
831
883
  # Gets the datetime object. It can be a Fixnum, Date or Time, or nil.
832
884
  datetime = @object ? @object.send(method) : nil
833
885
  html_options = options.delete(:input_html) || {}
886
+ input_ids = []
834
887
 
835
888
  (inputs + time_inputs).each do |input|
836
- html_id = generate_html_id(method, "#{position[input]}i")
889
+ input_ids << input_id = generate_html_id(method, "#{position[input]}i")
890
+
837
891
  field_name = "#{method}(#{position[input]}i)"
838
- if options["discard_#{input}".intern]
892
+ if options[:"discard_#{input}"]
839
893
  break if time_inputs.include?(input)
840
894
 
841
- hidden_value = datetime.respond_to?(input) ? datetime.send(input) : datetime
842
- hidden_fields_capture << template.hidden_field_tag("#{@object_name}[#{field_name}]", (hidden_value || 1), :id => html_id)
895
+ hidden_value = datetime.respond_to?(input) ? datetime.send(input.to_sym) : datetime
896
+ hidden_fields_capture << template.hidden_field_tag("#{@object_name}[#{field_name}]", (hidden_value || 1), :id => input_id)
843
897
  else
844
898
  opts = set_options(options).merge(:prefix => @object_name, :field_name => field_name)
845
- item_label_text = I18n.t(input.to_s, :default => input.to_s.humanize, :scope => [:datetime, :prompts])
899
+ item_label_text = ::I18n.t(input.to_s, :default => input.to_s.humanize, :scope => [:datetime, :prompts])
846
900
 
847
901
  list_items_capture << template.content_tag(:li,
848
- template.content_tag(:label, item_label_text, :for => html_id) +
849
- template.send("select_#{input}".intern, datetime, opts, html_options.merge(:id => html_id))
902
+ template.content_tag(:label, item_label_text, :for => input_id) <<
903
+ template.send(:"select_#{input}", datetime, opts, html_options.merge(:id => input_id))
850
904
  )
851
905
  end
852
906
  end
853
907
 
854
- hidden_fields_capture + field_set_and_list_wrapping_for_method(method, options, list_items_capture)
908
+ hidden_fields_capture << field_set_and_list_wrapping_for_method(method, options.merge(:label_for => input_ids.first), list_items_capture)
855
909
  end
856
910
 
857
-
858
911
  # Outputs a fieldset containing a legend for the label text, and an ordered list (ol) of list
859
912
  # items, one for each possible choice in the belongs_to association. Each li contains a
860
913
  # label and a check_box input.
@@ -868,7 +921,7 @@ module Formtastic #:nodoc:
868
921
  # Output:
869
922
  #
870
923
  # <fieldset>
871
- # <legend><span>Authors</span></legend>
924
+ # <legend class="label"><label>Authors</label></legend>
872
925
  # <ol>
873
926
  # <li>
874
927
  # <input type="hidden" name="book[author_id][1]" value="">
@@ -927,26 +980,27 @@ module Formtastic #:nodoc:
927
980
  value_as_class = options.delete(:value_as_class)
928
981
  unchecked_value = options.delete(:unchecked_value) || ''
929
982
  html_options = { :name => "#{@object_name}[#{input_name}][]" }.merge(html_options)
983
+ input_ids = []
930
984
 
931
985
  list_item_content = collection.map do |c|
932
986
  label = c.is_a?(Array) ? c.first : c
933
987
  value = c.is_a?(Array) ? c.last : c
934
988
 
935
- html_options.merge!(:id => generate_html_id(input_name, value.to_s.gsub(/\s/, '_').gsub(/\W/, '').downcase))
936
-
989
+ input_ids << input_id = generate_html_id(input_name, value.to_s.gsub(/\s/, '_').gsub(/\W/, '').downcase)
990
+ html_options.merge!(:id => input_id)
991
+
937
992
  li_content = template.content_tag(:label,
938
993
  "#{self.check_box(input_name, html_options, value, unchecked_value)} #{label}",
939
- :for => html_options[:id]
994
+ :for => input_id
940
995
  )
941
996
 
942
997
  li_options = value_as_class ? { :class => value.to_s.downcase } : {}
943
998
  template.content_tag(:li, li_content, li_options)
944
999
  end
945
1000
 
946
- field_set_and_list_wrapping_for_method(method, options, list_item_content)
1001
+ field_set_and_list_wrapping_for_method(method, options.merge(:label_for => input_ids.first), list_item_content)
947
1002
  end
948
-
949
-
1003
+
950
1004
  # Outputs a country select input, wrapping around a regular country_select helper.
951
1005
  # Rails doesn't come with a country_select helper by default any more, so you'll need to install
952
1006
  # the "official" plugin, or, if you wish, any other country_select plugin that behaves in the
@@ -967,10 +1021,9 @@ module Formtastic #:nodoc:
967
1021
  html_options = options.delete(:input_html) || {}
968
1022
  priority_countries = options.delete(:priority_countries) || @@priority_countries
969
1023
 
970
- self.label(method, options_for_label(options)) +
1024
+ self.label(method, options_for_label(options)) <<
971
1025
  self.country_select(method, priority_countries, set_options(options), html_options)
972
1026
  end
973
-
974
1027
 
975
1028
  # Outputs a label containing a checkbox and the label text. The label defaults
976
1029
  # to the column name (method name) and can be altered with the :label option.
@@ -991,7 +1044,7 @@ module Formtastic #:nodoc:
991
1044
 
992
1045
  # Generates an input for the given method using the type supplied with :as.
993
1046
  def inline_input_for(method, options)
994
- send("#{options.delete(:as)}_input", method, options)
1047
+ send(:"#{options.delete(:as)}_input", method, options)
995
1048
  end
996
1049
 
997
1050
  # Generates hints for the given method using the text supplied in :hint.
@@ -1050,12 +1103,29 @@ module Formtastic #:nodoc:
1050
1103
  #
1051
1104
  # f.inputs :name => 'Task #%i', :for => :tasks
1052
1105
  #
1106
+ # or the shorter equivalent:
1107
+ #
1108
+ # f.inputs 'Task #%i', :for => :tasks
1109
+ #
1053
1110
  # And it will generate a fieldset for each task with legend 'Task #1', 'Task #2',
1054
1111
  # 'Task #3' and so on.
1055
1112
  #
1056
- def field_set_and_list_wrapping(html_options, contents='', &block) #:nodoc:
1113
+ # Note: Special case for the inline inputs (non-block):
1114
+ # f.inputs "My little legend", :title, :body, :author # Explicit legend string => "My little legend"
1115
+ # f.inputs :my_little_legend, :title, :body, :author # Localized (118n) legend with I18n key => I18n.t(:my_little_legend, ...)
1116
+ # f.inputs :title, :body, :author # First argument is a column => (no legend)
1117
+ #
1118
+ def field_set_and_list_wrapping(*args, &block) #:nodoc:
1119
+ contents = args.last.is_a?(::Hash) ? '' : args.pop.flatten
1120
+ html_options = args.extract_options!
1121
+
1057
1122
  html_options[:name] ||= html_options.delete(:title)
1058
- html_options[:name] = localized_string(html_options[:name], html_options[:name], :title) if html_options[:name].is_a?(Symbol)
1123
+ if html_options[:name].blank?
1124
+ valid_name_classes = [::String, ::Symbol]
1125
+ valid_name_classes.delete(::Symbol) if !block_given? && (args.first.is_a?(::Symbol) && self.content_columns.include?(args.first))
1126
+ html_options[:name] = args.shift if valid_name_classes.any? { |valid_name_class| args.first.is_a?(valid_name_class) }
1127
+ end
1128
+ html_options[:name] = localized_string(html_options[:name], html_options[:name], :title) if html_options[:name].is_a?(::Symbol)
1059
1129
 
1060
1130
  legend = html_options.delete(:name).to_s
1061
1131
  legend %= parent_child_index(html_options[:parent]) if html_options[:parent]
@@ -1072,7 +1142,7 @@ module Formtastic #:nodoc:
1072
1142
  # Ruby 1.9: String#to_s behavior changed, need to make an explicit join.
1073
1143
  contents = contents.join if contents.respond_to?(:join)
1074
1144
  fieldset = template.content_tag(:fieldset,
1075
- legend + template.content_tag(:ol, contents),
1145
+ legend << template.content_tag(:ol, contents),
1076
1146
  html_options.except(:builder, :parent)
1077
1147
  )
1078
1148
 
@@ -1087,9 +1157,11 @@ module Formtastic #:nodoc:
1087
1157
  contents = contents.join if contents.respond_to?(:join)
1088
1158
 
1089
1159
  template.content_tag(:fieldset,
1090
- %{<legend>#{self.label(method, options_for_label(options).merge!(:as_span => true))}</legend>} +
1091
- template.content_tag(:ol, contents)
1092
- )
1160
+ template.content_tag(:legend,
1161
+ self.label(method, options_for_label(options).merge(:for => options.delete(:label_for))), :class => 'label'
1162
+ ) <<
1163
+ template.content_tag(:ol, contents)
1164
+ )
1093
1165
  end
1094
1166
 
1095
1167
  # For methods that have a database column, take a best guess as to what the input method
@@ -1142,7 +1214,7 @@ module Formtastic #:nodoc:
1142
1214
  collection = find_raw_collection_for_column(column, options)
1143
1215
 
1144
1216
  # Return if we have an Array of strings, fixnums or arrays
1145
- return collection if collection.instance_of?(Array) &&
1217
+ return collection if (collection.instance_of?(Array) || collection.instance_of?(Range)) &&
1146
1218
  [Array, Fixnum, String, Symbol].include?(collection.first.class)
1147
1219
 
1148
1220
  label, value = detect_label_and_value_method!(collection, options)
@@ -1189,8 +1261,8 @@ module Formtastic #:nodoc:
1189
1261
  # is provided.
1190
1262
  #
1191
1263
  def create_boolean_collection(options)
1192
- options[:true] ||= I18n.t('yes', :default => 'Yes', :scope => [:formtastic])
1193
- options[:false] ||= I18n.t('no', :default => 'No', :scope => [:formtastic])
1264
+ options[:true] ||= ::Formtastic::I18n.t(:yes)
1265
+ options[:false] ||= ::Formtastic::I18n.t(:no)
1194
1266
  options[:value_as_class] = true unless options.key?(:value_as_class)
1195
1267
 
1196
1268
  [ [ options.delete(:true), true], [ options.delete(:false), false ] ]
@@ -1213,7 +1285,7 @@ module Formtastic #:nodoc:
1213
1285
  end
1214
1286
  else
1215
1287
  method
1216
- end
1288
+ end.to_sym
1217
1289
  end
1218
1290
 
1219
1291
  # If an association method is passed in (f.input :author) try to find the
@@ -1301,7 +1373,7 @@ module Formtastic #:nodoc:
1301
1373
  # 'formtastic.labels.post.title'
1302
1374
  # 'formtastic.labels.title'
1303
1375
  #
1304
- # NOTE: Generic, but only used for form input labels/hints.
1376
+ # NOTE: Generic, but only used for form input titles/labels/hints/actions (titles = legends, actions = buttons).
1305
1377
  #
1306
1378
  def localized_string(key, value, type, options = {})
1307
1379
  key = value if value.is_a?(::Symbol)
@@ -1326,8 +1398,8 @@ module Formtastic #:nodoc:
1326
1398
  end
1327
1399
  defaults << ''
1328
1400
 
1329
- i18n_value = ::I18n.t(defaults.shift, options.merge(:default => defaults,
1330
- :scope => :"formtastic.#{type.to_s.pluralize}"))
1401
+ i18n_value = ::Formtastic::I18n.t(defaults.shift,
1402
+ options.merge(:default => defaults,:scope => type.to_s.pluralize.to_sym))
1331
1403
  i18n_value.blank? ? nil : i18n_value
1332
1404
  end
1333
1405
  end
@@ -1341,14 +1413,12 @@ module Formtastic #:nodoc:
1341
1413
  end
1342
1414
  end
1343
1415
 
1344
- private
1345
-
1346
- def set_include_blank(options)
1347
- unless options.key?(:include_blank) || options.key?(:prompt)
1348
- options[:include_blank] = @@include_blank_for_select_by_default
1349
- end
1350
- options
1416
+ def set_include_blank(options)
1417
+ unless options.key?(:include_blank) || options.key?(:prompt)
1418
+ options[:include_blank] = @@include_blank_for_select_by_default
1351
1419
  end
1420
+ options
1421
+ end
1352
1422
 
1353
1423
  end
1354
1424
 
@@ -1385,7 +1455,7 @@ module Formtastic #:nodoc:
1385
1455
  # ...
1386
1456
  # <% end %>
1387
1457
  module SemanticFormHelper
1388
- @@builder = Formtastic::SemanticFormBuilder
1458
+ @@builder = ::Formtastic::SemanticFormBuilder
1389
1459
  mattr_accessor :builder
1390
1460
 
1391
1461
  @@default_field_error_proc = nil
data/lib/locale/en.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  en:
2
2
  formtastic:
3
- "yes": 'Yes'
4
- "no": 'No'
3
+ :yes: 'Yes'
4
+ :no: 'No'
5
5
  create: 'Create'
6
6
  save: 'Save'
7
7
  submit: 'Submit'
@@ -46,12 +46,12 @@ describe 'SemanticFormBuilder#commit_button' do
46
46
  describe "its accesskey" do
47
47
 
48
48
  it 'should allow nil default' do
49
- Formtastic::SemanticFormBuilder.default_commit_button_accesskey.should == nil
49
+ ::Formtastic::SemanticFormBuilder.default_commit_button_accesskey.should == nil
50
50
  output_buffer.should_not have_tag('li.commit input[@accesskey]')
51
51
  end
52
52
 
53
53
  it 'should use the default if set' do
54
- Formtastic::SemanticFormBuilder.default_commit_button_accesskey = 's'
54
+ ::Formtastic::SemanticFormBuilder.default_commit_button_accesskey = 's'
55
55
  @new_post.stub!(:new_record?).and_return(false)
56
56
  semantic_form_for(@new_post) do |builder|
57
57
  concat(builder.commit_button('text', :button_html => {}))
@@ -60,7 +60,7 @@ describe 'SemanticFormBuilder#commit_button' do
60
60
  end
61
61
 
62
62
  it 'should use the value set in options over the default' do
63
- Formtastic::SemanticFormBuilder.default_commit_button_accesskey = 's'
63
+ ::Formtastic::SemanticFormBuilder.default_commit_button_accesskey = 's'
64
64
  @new_post.stub!(:new_record?).and_return(false)
65
65
  semantic_form_for(@new_post) do |builder|
66
66
  concat(builder.commit_button('text', :accesskey => 'o'))
@@ -70,7 +70,7 @@ describe 'SemanticFormBuilder#commit_button' do
70
70
  end
71
71
 
72
72
  it 'should use the value set in button_html over options' do
73
- Formtastic::SemanticFormBuilder.default_commit_button_accesskey = 's'
73
+ ::Formtastic::SemanticFormBuilder.default_commit_button_accesskey = 's'
74
74
  @new_post.stub!(:new_record?).and_return(false)
75
75
  semantic_form_for(@new_post) do |builder|
76
76
  concat(builder.commit_button('text', :accesskey => 'o', :button_html => {:accesskey => 't'}))
@@ -81,7 +81,7 @@ describe 'SemanticFormBuilder#commit_button' do
81
81
  end
82
82
 
83
83
  after do
84
- Formtastic::SemanticFormBuilder.default_commit_button_accesskey = nil
84
+ ::Formtastic::SemanticFormBuilder.default_commit_button_accesskey = nil
85
85
  end
86
86
 
87
87
  end
@@ -5,7 +5,7 @@ describe 'Formtastic::SemanticFormHelper.builder' do
5
5
 
6
6
  include FormtasticSpecHelper
7
7
 
8
- class MyCustomFormBuilder < Formtastic::SemanticFormBuilder
8
+ class MyCustomFormBuilder < ::Formtastic::SemanticFormBuilder
9
9
  def awesome_input(method, options)
10
10
  self.text_field(method)
11
11
  end
@@ -17,28 +17,28 @@ describe 'Formtastic::SemanticFormHelper.builder' do
17
17
  end
18
18
 
19
19
  it 'is the Formtastic::SemanticFormBuilder by default' do
20
- Formtastic::SemanticFormHelper.builder.should == Formtastic::SemanticFormBuilder
20
+ ::Formtastic::SemanticFormHelper.builder.should == ::Formtastic::SemanticFormBuilder
21
21
  end
22
22
 
23
23
  it 'can be configured to use your own custom form builder' do
24
24
  # Set it to a custom builder class
25
- Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
26
- Formtastic::SemanticFormHelper.builder.should == MyCustomFormBuilder
25
+ ::Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
26
+ ::Formtastic::SemanticFormHelper.builder.should == MyCustomFormBuilder
27
27
 
28
28
  # Reset it to the default
29
- Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
30
- Formtastic::SemanticFormHelper.builder.should == Formtastic::SemanticFormBuilder
29
+ ::Formtastic::SemanticFormHelper.builder = ::Formtastic::SemanticFormBuilder
30
+ ::Formtastic::SemanticFormHelper.builder.should == ::Formtastic::SemanticFormBuilder
31
31
  end
32
32
 
33
33
  describe "when using a custom builder" do
34
34
 
35
35
  before do
36
36
  @new_post.stub!(:title)
37
- Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
37
+ ::Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
38
38
  end
39
39
 
40
40
  after do
41
- Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
41
+ ::Formtastic::SemanticFormHelper.builder = ::Formtastic::SemanticFormBuilder
42
42
  end
43
43
 
44
44
  describe "semantic_form_for" do