formtastic-rails3 0.9.10.1 → 1.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/README.textile +32 -16
  2. data/Rakefile +11 -11
  3. data/lib/formtastic.rb +95 -30
  4. data/lib/formtastic/railtie.rb +1 -1
  5. data/lib/formtastic/util.rb +3 -2
  6. data/lib/generators/formtastic/form/form_generator.rb +4 -4
  7. data/spec/buttons_spec.rb +1 -1
  8. data/spec/commit_button_spec.rb +1 -1
  9. data/spec/custom_builder_spec.rb +1 -1
  10. data/spec/defaults_spec.rb +1 -1
  11. data/spec/error_proc_spec.rb +1 -1
  12. data/spec/errors_spec.rb +1 -1
  13. data/spec/form_helper_spec.rb +1 -1
  14. data/spec/helpers/layout_helper_spec.rb +21 -0
  15. data/spec/i18n_spec.rb +1 -1
  16. data/spec/include_blank_spec.rb +1 -1
  17. data/spec/input_spec.rb +99 -93
  18. data/spec/inputs/boolean_input_spec.rb +1 -1
  19. data/spec/inputs/check_boxes_input_spec.rb +120 -6
  20. data/spec/inputs/country_input_spec.rb +1 -1
  21. data/spec/inputs/date_input_spec.rb +1 -1
  22. data/spec/inputs/datetime_input_spec.rb +1 -1
  23. data/spec/inputs/file_input_spec.rb +1 -1
  24. data/spec/inputs/hidden_input_spec.rb +1 -1
  25. data/spec/inputs/numeric_input_spec.rb +1 -1
  26. data/spec/inputs/password_input_spec.rb +1 -1
  27. data/spec/inputs/radio_input_spec.rb +61 -2
  28. data/spec/inputs/select_input_spec.rb +1 -1
  29. data/spec/inputs/string_input_spec.rb +36 -19
  30. data/spec/inputs/text_input_spec.rb +1 -1
  31. data/spec/inputs/time_input_spec.rb +24 -2
  32. data/spec/inputs/time_zone_input_spec.rb +1 -1
  33. data/spec/inputs_spec.rb +37 -2
  34. data/spec/label_spec.rb +42 -1
  35. data/spec/semantic_errors_spec.rb +1 -1
  36. data/spec/semantic_fields_for_spec.rb +1 -1
  37. data/spec/spec_helper.rb +15 -39
  38. data/spec/{custom_macros.rb → support/custom_macros.rb} +0 -7
  39. data/spec/support/output_buffer.rb +4 -0
  40. data/spec/support/test_environment.rb +45 -0
  41. metadata +20 -14
  42. data/spec/layout_helper_spec.rb +0 -31
data/README.textile CHANGED
@@ -77,20 +77,33 @@ h2. Documentation
77
77
  RDoc documentation _should_ be automatically generated after each commit and made available on the "rdoc.info website":http://rdoc.info/projects/justinfrench/formtastic.
78
78
 
79
79
 
80
- h2. Installation
80
+ h2. A Note About Rails 3 Support
81
81
 
82
- The gem is hosted on gemcutter, so *if you haven't already*, add it as a gem source:
82
+ Formtastic 1.0 will only support the latest stable Rails 2.x. We're maintaining a rails3 branch which aims to provide both Rails 2.x and 3.x support, which is targeted for the 1.1 release soon after 1.0, around the same time Rails 3.0 ships.
83
+
84
+ If you have a Rails 3 project and would like to use Formtastic's rails3 branch, bundler provides you with the ability to do this easily. Just add Formtastic as a git dependency in your Gemfile with the :branch option:
83
85
 
84
86
  <pre>
85
- sudo gem sources -a http://gemcutter.org/
87
+ gem 'formtastic', :git => "http://github.com/justinfrench/formtastic.git", :branch => "rails3"
86
88
  </pre>
87
89
 
88
- Then install the Formtastic gem:
90
+ Please be aware that Rails 3 is still under heavy development (even in the later betas), as is Formtastic, so our rails3 branch is very much "on the edge", just like Rails. if you find issues, compatibility issues with Rails 2 or 3, please report an issue on Github.
91
+
92
+
93
+ h2. Installation under Rails 2.x
94
+
95
+ Install the Formtastic gem:
89
96
 
90
97
  <pre>
91
98
  sudo gem install formtastic
92
99
  </pre>
93
100
 
101
+ Or try the 1.0.0.beta2:
102
+
103
+ <pre>
104
+ sudo gem install formtastic --pre
105
+ </pre>
106
+
94
107
  And add it to your environment.rb configuration as a gem dependency:
95
108
 
96
109
  <pre>
@@ -113,6 +126,7 @@ A proof-of-concept stylesheet is provided which you can include in your layout.
113
126
  </head>
114
127
  </pre>
115
128
 
129
+
116
130
  h2. Usage
117
131
 
118
132
  Forms are really boring to code... you want to get onto the good stuff as fast as possible.
@@ -517,12 +531,18 @@ If you want to add your own input types to encapsulate your own logic or interfa
517
531
 
518
532
  @Formtastic::SemanticFormHelper.builder = MyCustomBuilder@
519
533
 
534
+ h2. Security
535
+
536
+ By default formtastic escapes html entities in both labels and hints unless a string is marked as html_safe. If you are using an older rails version which doesn't know html_safe, or you want to globally turn this feature off, you can set the following in your initializer:
520
537
 
538
+ Formtastic::SemanticFormBuilder.escape_html_entities_in_hints_and_labels = false
521
539
 
522
540
 
523
- h2. Status
541
+ h2. Focus
524
542
 
525
- Formtastic has been in active development for about a year. We've just recently jumped to an 0.9 version number, signaling that we consider this a 1.0 release candidate, and that the API won't change significantly for the 1.x series.
543
+ Formtastic is close to shipping a 1.0 release candidate after more than a year of active development. 1.0 will be compatible with Rails 2, and this is our top priority right now. We've also been working hard on a Rails 2 *and* 3 compatible version in the rails3 branch, targeting a 1.1 release shortly after Rails 3.0 ships.
544
+
545
+ There's heaps more we want to do, but we have to do this first.
526
546
 
527
547
 
528
548
  h2. Dependencies
@@ -536,18 +556,14 @@ There are none, but...
536
556
 
537
557
  h2. Compatibility
538
558
 
539
- I'm only testing Formtastic with the latest Rails 2.4.x stable release, and it should be fine under Rails 2.3.x as well (including nested forms). Patches are welcome to allow backwards compatibility, but I don't have the energy!
540
-
541
- h2. Got TextMate?
542
-
543
- Well...there's a TextMate-bundle in town, dedicated to make usage of Formtastic in the "TextMate":http://macromates.com/ editor even more of a breeze:
544
-
545
- "Formtastic.tmbundle":http://github.com/grimen/formtastic_tmbundle
546
-
559
+ * We're only testing Formtastic with the latest Rails 2.x stable release. Patches are welcome to allow backwards compatibility with older versions of Rails, of course.
560
+ * Development of a Rails 2 *and* 3 compatible version of Formtastic is underway in the rails3 branch, targeting a Formtastic 1.1 release shortly after Rails 3.0 ships.
561
+ * Formtastic, much like Rails 2, is very ActiveRecord-centric. Many people are using Formtastic (especially the rails3 branch) successfully with other ActiveModel-like ORMs and classes (DataMapper, MongoMapper, Mongoid, Authlogic, Devise...) but we're not guaranteeing anything at this stage. Patches are welcome, but it's not our core focus right now. Shipping a solid 1.0 and Rails 3 compatible 1.1 is.
562
+
547
563
 
548
564
  h2. How to contribute
549
565
 
550
- *Before you send a pull request*, please ensure that you provide appropriate spec/test coverage and ensure the documentation is up-to-date. Bonus points if you perform your changes in a clean topic branch rather than master.
566
+ Please ensure that you provide appropriate spec/test coverage and ensure the documentation is up-to-date. Bonus points if you perform your changes in a clean topic branch rather than master, and if you create an issue on GH for us to discuss your changes. Pull requests tend to get lost.
551
567
 
552
568
  Please also keep your commits *atomic* so that they are more likely to apply cleanly. That means that each commit should contain the smallest possible logical change. Don't commit two features at once, don't update the gemspec at the same time you add a feature, don't fix a whole bunch of whitespace in a file at the same time you change a few lines, etc, etc.
553
569
 
@@ -556,7 +572,7 @@ For significant changes, you may wish to discuss your idea on the Formtastic Goo
556
572
 
557
573
  h2. Maintainers & Contributors
558
574
 
559
- Formtastic is maintained by "Justin French":http://justinfrench.com, "José Valim":http://github.com/josevalim and "Jonas Grimfelt":http://github.com/grimen, but it wouldn't be as awesome as it is today without help from over 40 contributors.
575
+ Formtastic is maintained by "Justin French":http://github.com/justinfrench, "Morton Jonuschat":http://github.com/yabawock and "Gabriel Sobrinho":http://github.com/sobrinho. "Denis Major":http://github.com/denismajor1 is doing some amazing documentation work in the wiki, and we very much appreciate the past efforts of "José Valim":http://github.com/josevalim and "Jonas Grimfelt":http://github.com/grimen and over 40 other contributors.
560
576
 
561
577
  @git shortlog -n -s --no-merges@
562
578
 
data/Rakefile CHANGED
@@ -37,14 +37,14 @@ begin
37
37
  Find out more and get involved:
38
38
  http://github.com/justinfrench/formtastic
39
39
  http://groups.google.com.au/group/formtastic
40
-
40
+
41
41
  All credit goes to the original author, Justin French.
42
42
  ========================================================================
43
43
  }
44
-
44
+
45
45
  gem 'jeweler', '>= 1.0.0'
46
46
  require 'jeweler'
47
-
47
+
48
48
  Jeweler::Tasks.new do |s|
49
49
  s.name = GEM
50
50
  s.summary = SUMMARY
@@ -53,21 +53,21 @@ begin
53
53
  s.description = SUMMARY
54
54
  s.author = AUTHOR
55
55
  s.post_install_message = INSTALL_MESSAGE
56
-
56
+
57
57
  s.require_path = 'lib'
58
58
  s.files = %w(MIT-LICENSE README.textile Rakefile) + Dir.glob("{rails,lib,generators,spec}/**/*")
59
-
59
+
60
60
  # Runtime dependencies: When installing Formtastic these will be checked if they are installed.
61
61
  # Will be offered to install these if they are not already installed.
62
62
  s.add_dependency 'activesupport', '>= 3.0.0beta3'
63
63
  s.add_dependency 'actionpack', '>= 3.0.0beta3'
64
-
64
+
65
65
  # Development dependencies. Not installed by default.
66
66
  # Install with: sudo gem install formtastic --development
67
67
  s.add_development_dependency 'rspec-rails', '>= 1.2.6'
68
68
  s.add_development_dependency 'rspec_tag_matchers', '>= 1.0.0'
69
69
  end
70
-
70
+
71
71
  Jeweler::GemcutterTasks.new
72
72
  rescue LoadError
73
73
  puts "[formtastic:] Jeweler - or one of its dependencies - is not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
@@ -106,19 +106,19 @@ if defined?(Spec)
106
106
  end
107
107
  end
108
108
 
109
- if defined?(Rspec)
109
+ if defined?(RSpec)
110
110
  desc 'Test the formtastic plugin.'
111
- Rspec::Core::RakeTask.new('spec') do |t|
111
+ RSpec::Core::RakeTask.new('spec') do |t|
112
112
  t.pattern = FileList['spec/**/*_spec.rb']
113
113
  end
114
114
 
115
115
  desc 'Test the formtastic plugin with specdoc formatting and colors'
116
- Rspec::Core::RakeTask.new('specdoc') do |t|
116
+ RSpec::Core::RakeTask.new('specdoc') do |t|
117
117
  t.pattern = FileList['spec/**/*_spec.rb']
118
118
  end
119
119
 
120
120
  desc "Run all examples with RCov"
121
- Rspec::Core::RakeTask.new('examples_with_rcov') do |t|
121
+ RSpec::Core::RakeTask.new('examples_with_rcov') do |t|
122
122
  t.pattern = FileList['spec/**/*_spec.rb']
123
123
  t.rcov = true
124
124
  t.rcov_opts = ['--exclude', 'spec,Library']
data/lib/formtastic.rb CHANGED
@@ -20,11 +20,12 @@ module Formtastic #:nodoc:
20
20
  @@file_methods = [ :file?, :public_filename, :filename ]
21
21
  @@priority_countries = ["Australia", "Canada", "United Kingdom", "United States"]
22
22
  @@i18n_lookups_by_default = false
23
+ @@escape_html_entities_in_hints_and_labels = true
23
24
  @@default_commit_button_accesskey = nil
24
25
 
25
26
  cattr_accessor :default_text_field_size, :default_text_area_height, :all_fields_required_by_default, :include_blank_for_select_by_default,
26
27
  :required_string, :optional_string, :inline_errors, :label_str_method, :collection_label_methods,
27
- :inline_order, :file_methods, :priority_countries, :i18n_lookups_by_default, :default_commit_button_accesskey
28
+ :inline_order, :file_methods, :priority_countries, :i18n_lookups_by_default, :escape_html_entities_in_hints_and_labels, :default_commit_button_accesskey
28
29
 
29
30
  RESERVED_COLUMNS = [:created_at, :updated_at, :created_on, :updated_on, :lock_version, :version]
30
31
 
@@ -483,7 +484,7 @@ module Formtastic #:nodoc:
483
484
  # Collects association columns (relation columns) for the current form object class.
484
485
  #
485
486
  def association_columns(*by_associations) #:nodoc:
486
- if @object.present?
487
+ if @object.present? && @object.class.respond_to?(:reflections)
487
488
  @object.class.reflections.collect do |name, _|
488
489
  if by_associations.present?
489
490
  name if by_associations.include?(_.macro)
@@ -528,9 +529,17 @@ module Formtastic #:nodoc:
528
529
  raise ArgumentError, 'You gave :for option with a block to inputs method, ' <<
529
530
  'but the block does not accept any argument.' if block.arity <= 0
530
531
 
531
- proc { |f| return f.inputs(*args){ block.call(f) } }
532
+ lambda do |f|
533
+ contents = f.inputs(*args){ block.call(f) }
534
+ template.concat(contents) if ::Formtastic::Util.rails3?
535
+ contents
536
+ end
532
537
  else
533
- proc { |f| return f.inputs(*args) }
538
+ lambda do |f|
539
+ contents = f.inputs(*args)
540
+ template.concat(contents) if ::Formtastic::Util.rails3?
541
+ contents
542
+ end
534
543
  end
535
544
 
536
545
  fields_for_args = [options.delete(:for), options.delete(:for_options) || {}].flatten
@@ -541,7 +550,7 @@ module Formtastic #:nodoc:
541
550
  #
542
551
  def strip_formtastic_options(options) #:nodoc:
543
552
  options.except(:value_method, :label_method, :collection, :required, :label,
544
- :as, :hint, :input_html, :label_html, :value_as_class)
553
+ :as, :hint, :input_html, :label_html, :value_as_class, :find_options)
545
554
  end
546
555
 
547
556
  # Determins if the attribute (eg :title) should be considered required or not.
@@ -889,15 +898,20 @@ module Formtastic #:nodoc:
889
898
  html_options[:checked] = selected_value == value if selected_option_is_present
890
899
 
891
900
  li_content = template.content_tag(:label,
892
- Formtastic::Util.html_safe("#{self.radio_button(input_name, value, html_options)} #{label}"),
901
+ Formtastic::Util.html_safe("#{self.radio_button(input_name, value, html_options)} #{escape_html_entities(label)}"),
893
902
  :for => input_id
894
903
  )
895
904
 
896
905
  li_options = value_as_class ? { :class => [method.to_s.singularize, value.to_s.downcase].join('_') } : {}
897
906
  template.content_tag(:li, Formtastic::Util.html_safe(li_content), li_options)
898
907
  end
899
-
900
- field_set_and_list_wrapping_for_method(method, options, list_item_content)
908
+
909
+ template.content_tag(:fieldset,
910
+ template.content_tag(:legend,
911
+ template.label_tag(nil, localized_string(method, options[:label], :label) || humanized_attribute_name(method), :for => nil), :class => :label
912
+ ) <<
913
+ template.content_tag(:ol, Formtastic::Util.html_safe(list_item_content.join))
914
+ )
901
915
  end
902
916
  alias :boolean_radio_input :radio_input
903
917
 
@@ -1016,6 +1030,7 @@ module Formtastic #:nodoc:
1016
1030
  i18n_date_order = ::I18n.t(:order, :scope => [:date])
1017
1031
  i18n_date_order = nil unless i18n_date_order.is_a?(Array)
1018
1032
  inputs = options.delete(:order) || i18n_date_order || [:year, :month, :day]
1033
+ inputs = [] if options[:ignore_date]
1019
1034
  labels = options.delete(:labels) || {}
1020
1035
 
1021
1036
  time_inputs = [:hour, :minute]
@@ -1123,6 +1138,15 @@ module Formtastic #:nodoc:
1123
1138
  # f.input :authors, :as => :check_boxes, :selected => Author.most_popular.collect(&:id)
1124
1139
  # f.input :authors, :as => :check_boxes, :selected => nil # override any defaults: select none
1125
1140
  #
1141
+ #
1142
+ # Formtastic works around a bug in rails handling of check box collections by
1143
+ # not generating the hidden fields for state checking of the checkboxes
1144
+ # The :hidden_fields option provides a way to re-enable these hidden inputs by
1145
+ # setting it to true.
1146
+ #
1147
+ # f.input :authors, :as => :check_boxes, hidden_fields => false
1148
+ # f.input :authors, :as => :check_boxes, hidden_fields => true
1149
+ #
1126
1150
  # Finally, you can set :value_as_class => true if you want the li wrapper around each checkbox / label
1127
1151
  # combination to contain a class with the value of the radio button (useful for applying specific
1128
1152
  # CSS or Javascript to a particular checkbox).
@@ -1132,15 +1156,13 @@ module Formtastic #:nodoc:
1132
1156
  html_options = options.delete(:input_html) || {}
1133
1157
 
1134
1158
  input_name = generate_association_input_name(method)
1159
+ hidden_fields = options.delete(:hidden_fields)
1135
1160
  value_as_class = options.delete(:value_as_class)
1136
1161
  unchecked_value = options.delete(:unchecked_value) || ''
1137
1162
  html_options = { :name => "#{@object_name}[#{input_name}][]" }.merge(html_options)
1138
1163
  input_ids = []
1139
1164
 
1140
- selected_option_is_present = [:selected, :checked].any? { |k| options.key?(k) }
1141
- selected_values = (options.key?(:checked) ? options[:checked] : options[:selected]) if selected_option_is_present
1142
- selected_values = [*selected_values].compact
1143
-
1165
+ selected_values = find_selected_values_for_column(method, options)
1144
1166
  disabled_option_is_present = options.key?(:disabled)
1145
1167
  disabled_values = [*options[:disabled]] if disabled_option_is_present
1146
1168
 
@@ -1150,12 +1172,12 @@ module Formtastic #:nodoc:
1150
1172
  input_id = generate_html_id(input_name, value.to_s.gsub(/\s/, '_').gsub(/\W/, '').downcase)
1151
1173
  input_ids << input_id
1152
1174
 
1153
- html_options[:checked] = selected_values.include?(value) if selected_option_is_present
1175
+ html_options[:checked] = selected_values.include?(value)
1154
1176
  html_options[:disabled] = disabled_values.include?(value) if disabled_option_is_present
1155
1177
  html_options[:id] = input_id
1156
1178
 
1157
1179
  li_content = template.content_tag(:label,
1158
- Formtastic::Util.html_safe("#{self.check_box(input_name, html_options, value, unchecked_value)} #{label}"),
1180
+ Formtastic::Util.html_safe("#{self.create_check_boxes(input_name, html_options, value, unchecked_value, hidden_fields)} #{escape_html_entities(label)}"),
1159
1181
  :for => input_id
1160
1182
  )
1161
1183
 
@@ -1163,7 +1185,40 @@ module Formtastic #:nodoc:
1163
1185
  template.content_tag(:li, Formtastic::Util.html_safe(li_content), li_options)
1164
1186
  end
1165
1187
 
1166
- field_set_and_list_wrapping_for_method(method, options, list_item_content)
1188
+ template.content_tag(:fieldset,
1189
+ template.content_tag(:legend,
1190
+ template.label_tag(nil, localized_string(method, options[:label], :label) || humanized_attribute_name(method), :for => nil), :class => :label
1191
+ ) <<
1192
+ template.content_tag(:ol, Formtastic::Util.html_safe(list_item_content.join))
1193
+ )
1194
+ end
1195
+
1196
+ # Used by check_boxes input. The selected values will be set either by:
1197
+ #
1198
+ # * Explicitly provided through :selected or :checked
1199
+ # * Values retrieved through an association
1200
+ #
1201
+ # If the collection is not a hash or an array of strings, fixnums or symbols,
1202
+ # we use value_method to retrieve an array with the values
1203
+ #
1204
+ def find_selected_values_for_column(method, options)
1205
+ selected_option_is_present = [:selected, :checked].any? { |k| options.key?(k) }
1206
+ if selected_option_is_present
1207
+ selected_values = (options.key?(:checked) ? options[:checked] : options[:selected])
1208
+ elsif object.respond_to?(method)
1209
+ collection = [object.send(method)].compact.flatten
1210
+ label, value = detect_label_and_value_method!(collection, options)
1211
+ selected_values = collection.map { |o| send_or_call(value, o) }
1212
+ end
1213
+ selected_values = [*selected_values].compact
1214
+ selected_values
1215
+ end
1216
+
1217
+ # Outputs a checkbox tag. If called with no_hidden_input = true a plain check_box_tag is returned,
1218
+ # otherwise the helper uses the output generated by the rails check_box method.
1219
+ def create_check_boxes(input_name, html_options = {}, checked_value = "1", unchecked_value = "0", hidden_fields = false)
1220
+ return template.check_box_tag(input_name, checked_value, html_options[:checked], html_options) unless hidden_fields == true
1221
+ self.check_box(input_name, html_options, checked_value, unchecked_value)
1167
1222
  end
1168
1223
 
1169
1224
  # Outputs a country select input, wrapping around a regular country_select helper.
@@ -1224,7 +1279,7 @@ module Formtastic #:nodoc:
1224
1279
  #
1225
1280
  def inline_hints_for(method, options) #:nodoc:
1226
1281
  options[:hint] = localized_string(method, options[:hint], :hint)
1227
- return if options[:hint].blank?
1282
+ return if options[:hint].blank? or options[:hint].kind_of? Hash
1228
1283
  template.content_tag(:p, Formtastic::Util.html_safe(options[:hint]), :class => 'inline-hints')
1229
1284
  end
1230
1285
 
@@ -1311,7 +1366,7 @@ module Formtastic #:nodoc:
1311
1366
  html_options.except(:builder, :parent)
1312
1367
  )
1313
1368
 
1314
- template.concat(fieldset) if block_given? && (!defined?(Rails::VERSION) || Rails::VERSION::MAJOR == 2)
1369
+ template.concat(fieldset) if block_given? && !Formtastic::Util.rails3?
1315
1370
  fieldset
1316
1371
  end
1317
1372
 
@@ -1402,7 +1457,8 @@ module Formtastic #:nodoc:
1402
1457
 
1403
1458
  # Return if we have an Array of strings, fixnums or arrays
1404
1459
  return collection if (collection.instance_of?(Array) || collection.instance_of?(Range)) &&
1405
- [Array, Fixnum, String, Symbol].include?(collection.first.class)
1460
+ [Array, Fixnum, String, Symbol].include?(collection.first.class) &&
1461
+ !(options.include?(:label_method) || options.include?(:value_method))
1406
1462
 
1407
1463
  label, value = detect_label_and_value_method!(collection, options)
1408
1464
  collection.map { |o| [send_or_call(label, o), send_or_call(value, o)] }
@@ -1419,7 +1475,6 @@ module Formtastic #:nodoc:
1419
1475
  if conditions = reflection.options[:conditions]
1420
1476
  options[:find_options][:conditions] = reflection.klass.merge_conditions(conditions, options[:find_options][:conditions])
1421
1477
  end
1422
-
1423
1478
  reflection.klass.find(:all, options[:find_options])
1424
1479
  else
1425
1480
  create_boolean_collection(options)
@@ -1542,7 +1597,8 @@ module Formtastic #:nodoc:
1542
1597
  elsif type == :numeric || column.nil? || column.limit.nil?
1543
1598
  { :size => @@default_text_field_size }
1544
1599
  else
1545
- { :maxlength => column.limit, :size => [column.limit, @@default_text_field_size].min }
1600
+ { :maxlength => column.limit,
1601
+ :size => @@default_text_field_size && [column.limit, @@default_text_field_size].min }
1546
1602
  end
1547
1603
  end
1548
1604
 
@@ -1622,7 +1678,7 @@ module Formtastic #:nodoc:
1622
1678
  key = value if value.is_a?(::Symbol)
1623
1679
 
1624
1680
  if value.is_a?(::String)
1625
- value
1681
+ escape_html_entities(value)
1626
1682
  else
1627
1683
  use_i18n = value.nil? ? @@i18n_lookups_by_default : (value != false)
1628
1684
 
@@ -1644,6 +1700,7 @@ module Formtastic #:nodoc:
1644
1700
 
1645
1701
  i18n_value = ::Formtastic::I18n.t(defaults.shift,
1646
1702
  options.merge(:default => defaults, :scope => type.to_s.pluralize.to_sym))
1703
+ i18n_value = escape_html_entities(i18n_value) if i18n_value.is_a?(::String)
1647
1704
  i18n_value.blank? ? nil : i18n_value
1648
1705
  end
1649
1706
  end
@@ -1676,6 +1733,14 @@ module Formtastic #:nodoc:
1676
1733
  options
1677
1734
  end
1678
1735
 
1736
+ def escape_html_entities(string) #:nodoc:
1737
+ if @@escape_html_entities_in_hints_and_labels
1738
+ # Acceppt html_safe flag as indicator to skip escaping
1739
+ string = template.escape_once(string) unless string.respond_to?(:html_safe?) && string.html_safe? == true
1740
+ end
1741
+ string
1742
+ end
1743
+
1679
1744
  end
1680
1745
 
1681
1746
  # Wrappers around form_for (etc) with :builder => SemanticFormBuilder.
@@ -1713,9 +1778,7 @@ module Formtastic #:nodoc:
1713
1778
  module SemanticFormHelper
1714
1779
  @@builder = ::Formtastic::SemanticFormBuilder
1715
1780
  mattr_accessor :builder
1716
-
1717
- @@default_field_error_proc = nil
1718
-
1781
+
1719
1782
  # Override the default ActiveRecordHelper behaviour of wrapping the input.
1720
1783
  # This gets taken care of semantically by adding an error class to the LI tag
1721
1784
  # containing the input.
@@ -1725,11 +1788,11 @@ module Formtastic #:nodoc:
1725
1788
  end
1726
1789
 
1727
1790
  def with_custom_field_error_proc(&block)
1728
- @@default_field_error_proc = ::ActionView::Base.field_error_proc
1791
+ default_field_error_proc = ::ActionView::Base.field_error_proc
1729
1792
  ::ActionView::Base.field_error_proc = FIELD_ERROR_PROC
1730
- result = yield
1731
- ::ActionView::Base.field_error_proc = @@default_field_error_proc
1732
- result
1793
+ yield
1794
+ ensure
1795
+ ::ActionView::Base.field_error_proc = default_field_error_proc
1733
1796
  end
1734
1797
 
1735
1798
  def semantic_remote_form_for_wrapper(record_or_name_or_array, *args, &proc)
@@ -1749,12 +1812,14 @@ module Formtastic #:nodoc:
1749
1812
  options[:builder] ||= @@builder
1750
1813
  options[:html] ||= {}
1751
1814
 
1815
+ singularizer = defined?(ActiveModel::Naming.singular) ? ActiveModel::Naming.method(:singular) : ActionController::RecordIdentifier.method(:singular_class_name)
1816
+
1752
1817
  class_names = options[:html][:class] ? options[:html][:class].split(" ") : []
1753
1818
  class_names << "formtastic"
1754
1819
  class_names << case record_or_name_or_array
1755
1820
  when String, Symbol then record_or_name_or_array.to_s # :post => "post"
1756
- when Array then ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array.last.class) # [@post, @comment] # => "comment"
1757
- else ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array.class) # @post => "post"
1821
+ when Array then singularizer.call(record_or_name_or_array.last.class) # [@post, @comment] # => "comment"
1822
+ else singularizer.call(record_or_name_or_array.class) # @post => "post"
1758
1823
  end
1759
1824
  options[:html][:class] = class_names.join(" ")
1760
1825