padrino-helpers 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/padrino-helpers.rb +4 -1
  3. data/lib/padrino-helpers/asset_tag_helpers.rb +17 -14
  4. data/lib/padrino-helpers/breadcrumb_helpers.rb +6 -6
  5. data/lib/padrino-helpers/form_builder/abstract_form_builder.rb +119 -163
  6. data/lib/padrino-helpers/form_builder/deprecated_builder_methods.rb +92 -0
  7. data/lib/padrino-helpers/form_helpers.rb +66 -347
  8. data/lib/padrino-helpers/form_helpers/errors.rb +138 -0
  9. data/lib/padrino-helpers/form_helpers/options.rb +97 -0
  10. data/lib/padrino-helpers/form_helpers/security.rb +70 -0
  11. data/lib/padrino-helpers/output_helpers.rb +1 -1
  12. data/lib/padrino-helpers/output_helpers/abstract_handler.rb +1 -1
  13. data/lib/padrino-helpers/render_helpers.rb +10 -9
  14. data/lib/padrino-helpers/tag_helpers.rb +2 -1
  15. data/lib/padrino/rendering.rb +378 -0
  16. data/lib/padrino/rendering/extensions/erubis.rb +74 -0
  17. data/lib/padrino/rendering/extensions/haml.rb +29 -0
  18. data/lib/padrino/rendering/extensions/slim.rb +21 -0
  19. data/padrino-helpers.gemspec +2 -1
  20. data/test/fixtures/apps/.components +6 -0
  21. data/test/fixtures/apps/.gitignore +7 -0
  22. data/test/fixtures/apps/render.rb +25 -0
  23. data/test/fixtures/apps/views/article/comment/show.slim +1 -0
  24. data/test/fixtures/apps/views/blog/post.erb +1 -0
  25. data/test/fixtures/apps/views/layouts/specific.erb +1 -0
  26. data/test/fixtures/apps/views/test/post.erb +1 -0
  27. data/test/fixtures/layouts/layout.erb +1 -0
  28. data/test/fixtures/markup_app/app.rb +0 -1
  29. data/test/fixtures/render_app/app.rb +25 -1
  30. data/test/fixtures/render_app/views/_unsafe.html.builder +2 -0
  31. data/test/fixtures/render_app/views/_unsafe_object.html.builder +2 -0
  32. data/test/fixtures/render_app/views/ruby_block_capture_erb.erb +1 -0
  33. data/test/fixtures/render_app/views/ruby_block_capture_haml.haml +1 -0
  34. data/test/fixtures/render_app/views/ruby_block_capture_slim.slim +1 -0
  35. data/test/helper.rb +65 -1
  36. data/test/test_asset_tag_helpers.rb +83 -79
  37. data/test/test_breadcrumb_helpers.rb +20 -20
  38. data/test/test_form_builder.rb +196 -196
  39. data/test/test_form_helpers.rb +163 -163
  40. data/test/test_format_helpers.rb +65 -65
  41. data/test/test_locale.rb +1 -1
  42. data/test/test_number_helpers.rb +10 -11
  43. data/test/test_output_helpers.rb +28 -28
  44. data/test/test_render_helpers.rb +89 -35
  45. data/test/test_rendering.rb +683 -0
  46. data/test/test_rendering_extensions.rb +14 -0
  47. data/test/test_tag_helpers.rb +23 -23
  48. metadata +57 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: abf7a7c5e2a12e941b018c62e94e24b47f1b9bf6
4
- data.tar.gz: c59d6ed08223958df60c85512571fa3b063e46af
3
+ metadata.gz: 9de9c68240b6a030c87053b1f781ef7152ef5bfc
4
+ data.tar.gz: a9a5d042cd4ed7d6dd52d9977b4421c0a40389e2
5
5
  SHA512:
6
- metadata.gz: b75a79d145a6a8027674b75713c11afa14fd727b02d6f60754bda869ded0c925f47c1f408158d4186f8ee70ee72826c829e92e4309708521b1fcba3f6d854e68
7
- data.tar.gz: 3be7c0827d6f9750bf536b41abb358745c474cbd5429c54e7e11619c2973a3aecb8583793f7dbbed8c96f888e28a58a30b8ac7e721c72806c59bfa7ee60eb3f3
6
+ metadata.gz: f0d72f6b0c05eaae7fb28d4fd7c85d7d76a9e2e7a7ef719f42040b0148cdbfb19ccdd3f790ef592328ec341edaf15acf74cda7b6e24b21aa4ce25beaa2af44fa
7
+ data.tar.gz: 97eb607b9c2caf7c9242c39afa18ceac5f63e7306d46c0e01d3041e93bf3008fef4e0a7b7f03bfc5ba9624b3cb6a7bd2fc9520e63cc9a85396af7d52c621e347
@@ -1,4 +1,4 @@
1
- require 'padrino-core/support_lite' unless defined?(SupportLite)
1
+ require 'padrino-support'
2
2
  require 'i18n'
3
3
  require 'enumerator'
4
4
  require 'active_support/time_with_zone' # next extension depends on this
@@ -6,6 +6,8 @@ require 'active_support/core_ext/string/conversions' # to_date
6
6
  require 'active_support/option_merger' # with_options
7
7
  require 'active_support/core_ext/object/with_options' # with_options
8
8
  require 'active_support/inflector' # humanize
9
+ require 'active_support/core_ext/hash/except' # Hash#except
10
+ require 'padrino/rendering'
9
11
 
10
12
  FileSet.glob_require('padrino-helpers/**/*.rb', __FILE__)
11
13
  I18n.load_path += Dir["#{File.dirname(__FILE__)}/padrino-helpers/locale/*.yml"]
@@ -41,6 +43,7 @@ module Padrino
41
43
  # end
42
44
  #
43
45
  def registered(app)
46
+ app.register Padrino::Rendering
44
47
  app.set :default_builder, 'StandardFormBuilder'
45
48
  app.helpers Padrino::Helpers::OutputHelpers
46
49
  app.helpers Padrino::Helpers::TagHelpers
@@ -32,11 +32,11 @@ module Padrino
32
32
  def flash_tag(*args)
33
33
  options = args.extract_options!
34
34
  bootstrap = options.delete(:bootstrap) if options[:bootstrap]
35
- args.inject(''.html_safe) do |html,kind|
36
- flash_text = flash[kind]
35
+ args.inject(ActiveSupport::SafeBuffer.new) do |html,kind|
36
+ flash_text = ActiveSupport::SafeBuffer.new << flash[kind]
37
37
  next html if flash_text.blank?
38
- flash_text << safe_content_tag(:button, "&times;", {:type => :button, :class => :close, :'data-dismiss' => :alert}) if bootstrap
39
- html << safe_content_tag(:div, flash_text, options.reverse_merge(:class => kind))
38
+ flash_text << content_tag(:button, '&times;'.html_safe, {:type => :button, :class => :close, :'data-dismiss' => :alert}) if bootstrap
39
+ html << content_tag(:div, flash_text, { :class => kind }.update(options))
40
40
  end
41
41
  end
42
42
 
@@ -230,11 +230,13 @@ module Padrino
230
230
  #
231
231
  # @api public.
232
232
  def stylesheet_link_tag(*sources)
233
- options = sources.extract_options!.symbolize_keys
234
- options.reverse_merge!(:media => 'screen', :rel => 'stylesheet', :type => 'text/css')
235
- sources.flatten.map { |source|
236
- tag(:link, options.reverse_merge(:href => asset_path(:css, source)))
237
- }.join("\n").html_safe
233
+ options = {
234
+ :rel => 'stylesheet',
235
+ :type => 'text/css'
236
+ }.update(sources.extract_options!.symbolize_keys)
237
+ sources.flatten.inject(ActiveSupport::SafeBuffer.new) do |all,source|
238
+ all << tag(:link, { :href => asset_path(:css, source) }.update(options))
239
+ end
238
240
  end
239
241
 
240
242
  ##
@@ -252,11 +254,12 @@ module Padrino
252
254
  # javascript_include_tag 'application', :extjs
253
255
  #
254
256
  def javascript_include_tag(*sources)
255
- options = sources.extract_options!.symbolize_keys
256
- options.reverse_merge!(:type => 'text/javascript')
257
- sources.flatten.map { |source|
258
- content_tag(:script, nil, options.reverse_merge(:src => asset_path(:js, source)))
259
- }.join("\n").html_safe
257
+ options = {
258
+ :type => 'text/javascript'
259
+ }.update(sources.extract_options!.symbolize_keys)
260
+ sources.flatten.inject(ActiveSupport::SafeBuffer.new) do |all,source|
261
+ all << content_tag(:script, nil, { :src => asset_path(:js, source) }.update(options))
262
+ end
260
263
  end
261
264
 
262
265
  ##
@@ -143,7 +143,7 @@ module Padrino
143
143
  # # </ul>
144
144
  #
145
145
  def breadcrumbs(breadcrumbs, bootstrap = false, active = "active", options = {})
146
- content = ""
146
+ content = ActiveSupport::SafeBuffer.new
147
147
  breadcrumbs.items[0..-2].each do |item|
148
148
  content << render_item(item, bootstrap)
149
149
  end
@@ -156,8 +156,8 @@ module Padrino
156
156
  classes[1] << active if active
157
157
  options[:class], last_options[:class] = classes.map { |class_name| class_name * " " }
158
158
 
159
- content << safe_content_tag(:li, last, last_options)
160
- safe_content_tag(:ul, content, options)
159
+ content << content_tag(:li, last, last_options)
160
+ content_tag(:ul, content, options)
161
161
  end
162
162
 
163
163
  private
@@ -173,10 +173,10 @@ module Padrino
173
173
  # @return [String] List item with breadcrumb
174
174
  #
175
175
  def render_item(item, bootstrap)
176
- content = ""
176
+ content = ActiveSupport::SafeBuffer.new
177
177
  content << link_to(item[:caption], item[:url])
178
- content << safe_content_tag(:span, "/", :class => "divider") if bootstrap
179
- safe_content_tag(:li, content, item[:options])
178
+ content << content_tag(:span, "/", :class => "divider") if bootstrap
179
+ content_tag(:li, content, item[:options])
180
180
  end
181
181
  end
182
182
  end
@@ -1,129 +1,119 @@
1
+ require 'padrino-helpers/form_builder/deprecated_builder_methods'
2
+
1
3
  module Padrino
2
4
  module Helpers
3
5
  module FormBuilder
6
+ # Base class for Padrino Form Builder
4
7
  class AbstractFormBuilder
5
8
  attr_accessor :template, :object, :multipart
9
+ attr_reader :namespace, :is_nested, :parent_form, :nested_index, :attributes_name, :model_name
10
+
11
+ include DeprecatedBuilderMethods
6
12
 
7
13
  def initialize(template, object, options={})
8
14
  @template = template
9
- @object = build_object(object)
10
- @options = options
11
- raise "FormBuilder template must be initialized!" unless template
12
- raise "FormBuilder object must not be a nil value. If there's no object, use a symbol instead! (i.e :user)" unless object
15
+ fail "FormBuilder template must be initialized" unless template
16
+ @object = object.kind_of?(Symbol) ? build_object(object) : object
17
+ fail "FormBuilder object must be present. If there's no object, use a symbol instead (i.e. :user)" unless object
18
+ @options = options
19
+ @namespace = options[:namespace]
20
+ @model_name = options[:as] || @object.class.to_s.underscore.gsub(/\//, '_')
21
+ nested = options[:nested]
22
+ if @is_nested = nested && (nested_parent = nested[:parent]) && nested_parent.respond_to?(:object)
23
+ @parent_form = nested_parent
24
+ @nested_index = nested[:index]
25
+ @attributes_name = "#{nested[:association]}_attributes"
26
+ end
13
27
  end
14
28
 
15
29
  def error_messages(*params)
16
- params.unshift object
17
- @template.error_messages_for(*params)
30
+ @template.error_messages_for object, *params
18
31
  end
19
32
 
20
33
  def error_message_on(field, options={})
21
- @template.error_message_on(object, field, options)
34
+ @template.error_message_on object, field, options
22
35
  end
23
36
 
24
37
  def label(field, options={}, &block)
25
- options.reverse_merge!(:caption => "#{field_human_name(field)}: ")
26
- @template.label_tag(field_id(field), options, &block)
38
+ options[:caption] ||= I18n.t("#{model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models) + ': '
39
+ @template.label_tag(field_id(field), default_options(field, options), &block)
27
40
  end
28
41
 
29
42
  def hidden_field(field, options={})
30
- options.reverse_merge!(:value => field_value(field), :id => field_id(field))
31
- @template.hidden_field_tag field_name(field), options
43
+ @template.hidden_field_tag field_name(field), default_options(field, options)
32
44
  end
33
45
 
34
46
  def text_field(field, options={})
35
- merge_default_options!(field, options)
36
- @template.text_field_tag field_name(field), options
47
+ @template.text_field_tag field_name(field), default_options(field, options)
37
48
  end
38
49
 
39
50
  def number_field(field, options={})
40
- merge_default_options!(field, options)
41
- @template.number_field_tag field_name(field), options
51
+ @template.number_field_tag field_name(field), default_options(field, options)
42
52
  end
43
53
 
44
54
  def telephone_field(field, options={})
45
- merge_default_options!(field, options)
46
- @template.telephone_field_tag field_name(field), options
55
+ @template.telephone_field_tag field_name(field), default_options(field, options)
47
56
  end
48
57
  alias_method :phone_field, :telephone_field
49
58
 
50
59
  def email_field(field, options={})
51
- merge_default_options!(field, options)
52
- @template.email_field_tag field_name(field), options
60
+ @template.email_field_tag field_name(field), default_options(field, options)
53
61
  end
54
62
 
55
63
  def search_field(field, options={})
56
- merge_default_options!(field, options)
57
- @template.search_field_tag field_name(field), options
64
+ @template.search_field_tag field_name(field), default_options(field, options)
58
65
  end
59
66
 
60
67
  def url_field(field, options={})
61
- merge_default_options!(field, options)
62
- @template.url_field_tag field_name(field), options
68
+ @template.url_field_tag field_name(field), default_options(field, options)
63
69
  end
64
70
 
65
71
  def text_area(field, options={})
66
- merge_default_options!(field, options)
67
- @template.text_area_tag field_name(field), options
72
+ @template.text_area_tag field_name(field), default_options(field, options)
68
73
  end
69
74
 
70
75
  def password_field(field, options={})
71
- merge_default_options!(field, options)
72
- @template.password_field_tag field_name(field), options
76
+ @template.password_field_tag field_name(field), default_options(field, options)
73
77
  end
74
78
 
75
79
  def select(field, options={})
76
- options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
77
- options.merge!(:class => field_error(field, options))
78
- @template.select_tag field_name(field), options
80
+ @template.select_tag field_name(field), default_options(field, options)
79
81
  end
80
82
 
81
83
  def check_box_group(field, options={})
82
- selected_values = Array(options[:selected] || field_value(field))
83
- if options[:collection]
84
- fields = options[:fields] || [:name, :id]
85
- selected_values = selected_values.map{ |v| (v.respond_to?(fields[0]) ? v.send(fields[1]) : v).to_s }
86
- end
87
- labeled_group( field, options ) do |variant|
88
- @template.check_box_tag( field_name(field)+'[]', :value => variant[1], :id => variant[2], :checked => selected_values.include?(variant[1]) )
84
+ labeled_group(field, options) do |attributes|
85
+ @template.check_box_tag(field_name(field)+'[]', attributes)
89
86
  end
90
87
  end
91
88
 
92
89
  def radio_button_group(field, options={})
93
- fields = options[:fields] || [:name, :id]
94
- selected_value = options[:selected] || field_value(field)
95
- selected_value = selected_value.send(fields[1]) if selected_value.respond_to?(fields[0])
96
- labeled_group( field, options ) do |variant|
97
- @template.radio_button_tag( field_name(field), :value => variant[1], :id => variant[2], :checked => variant[1] == selected_value.to_s )
90
+ labeled_group(field, options) do |attributes|
91
+ @template.radio_button_tag(field_name(field), attributes)
98
92
  end
99
93
  end
100
94
 
101
95
  def check_box(field, options={})
102
- html = ActiveSupport::SafeBuffer.new
103
- unchecked_value = options.delete(:uncheck_value) || '0'
104
- options.reverse_merge!(:id => field_id(field), :value => '1')
105
- options.reverse_merge!(:checked => true) if values_matches_field?(field, options[:value])
106
- html << @template.hidden_field_tag(options[:name] || field_name(field), :value => unchecked_value, :id => nil)
107
- html << @template.check_box_tag(field_name(field), options)
96
+ options = default_options(field, options, :value => '1')
97
+ options[:checked] = true if is_checked?(field, options)
98
+ name = field_name(field)
99
+ html = @template.hidden_field_tag(name, :value => options.delete(:uncheck_value) || '0')
100
+ html << @template.check_box_tag(name, options)
108
101
  end
109
102
 
110
103
  def radio_button(field, options={})
111
- options.reverse_merge!(:id => field_id(field, options[:value]))
112
- options.reverse_merge!(:checked => true) if values_matches_field?(field, options[:value])
104
+ options = default_options(field, options)
105
+ options[:checked] = true if is_checked?(field, options)
106
+ options[:id] = field_id(field, options[:value])
113
107
  @template.radio_button_tag field_name(field), options
114
108
  end
115
109
 
116
110
  def file_field(field, options={})
117
111
  self.multipart = true
118
- options.reverse_merge!(:id => field_id(field))
119
- options.merge!(:class => field_error(field, options))
120
- @template.file_field_tag field_name(field), options
112
+ @template.file_field_tag field_name(field), default_options(field, options).except(:value)
121
113
  end
122
114
 
123
115
  def submit(*args)
124
- options = args[-1].is_a?(Hash) ? args.pop : {}
125
- caption = args.length >= 1 ? args.shift : "Submit"
126
- @template.submit_tag caption, options
116
+ @template.submit_tag *args
127
117
  end
128
118
 
129
119
  def image_submit(source, options={})
@@ -136,24 +126,16 @@ module Padrino
136
126
  # f.fields_for :addresses, address
137
127
  # f.fields_for :addresses, @addresses
138
128
  # f.fields_for :addresses, address, index: i
139
- def fields_for(child_association, instance_or_collection=nil, options={}, &block)
129
+ def fields_for(child_association, collection=nil, options={}, &block)
140
130
  default_collection = self.object.send(child_association)
141
-
131
+ collection ||= default_collection
142
132
  include_index = default_collection.respond_to?(:each)
143
- custom_index = options.has_key?(:index)
144
133
 
145
134
  nested_options = { :parent => self, :association => child_association }
146
- nested_objects = instance_or_collection ? Array(instance_or_collection) : Array(default_collection)
147
- nested_objects.each_with_index.map do |child_instance, index|
148
- if custom_index
149
- nested_options[:index] = options[:index]
150
- elsif include_index
151
- nested_options[:index] = index
152
- else
153
- nested_options[:index] = nil
154
- end
155
- @template.fields_for(child_instance, { :nested => nested_options }, &block)
156
- end.join("\n").html_safe
135
+ Array(collection).each_with_index.inject(ActiveSupport::SafeBuffer.new) do |all,(child_instance,index)|
136
+ nested_options[:index] = options[:index] || (include_index ? index : nil)
137
+ all << @template.fields_for(child_instance, { :nested => nested_options }, &block) << "\n"
138
+ end
157
139
  end
158
140
 
159
141
  def csrf_token_field
@@ -161,43 +143,21 @@ module Padrino
161
143
  end
162
144
 
163
145
  protected
146
+
164
147
  # Returns the known field types for a Formbuilder.
165
148
  def self.field_types
166
149
  [:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
167
150
  end
168
151
 
169
- ##
170
- # Returns true if the value matches the value in the field.
171
- # field_has_value?(:gender, 'male')
172
- def values_matches_field?(field, value)
173
- value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
174
- end
175
-
176
- ##
177
- # Add a :invalid css class to the field if it contain an error.
178
- #
179
- def field_error(field, options)
180
- error = @object.errors[field] rescue nil
181
- error.blank? ? options[:class] : [options[:class], :invalid].flatten.compact.join(" ")
182
- end
183
-
184
- ##
185
- # Returns the human name of the field. Look that use builtin I18n.
186
- #
187
- def field_human_name(field)
188
- I18n.translate("#{object_model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models)
189
- end
190
-
191
152
  ##
192
153
  # Returns the name for the given field.
193
154
  # field_name(:username) => "user[username]"
194
155
  # field_name(:number) => "user[telephone_attributes][number]"
195
156
  # field_name(:street) => "user[addresses_attributes][0][street]"
196
157
  def field_name(field=nil)
197
- result = field_result
198
- result << field_name_fragment if nested_form?
158
+ result = field_name_fragment
199
159
  result << "[#{field}]" unless field.blank?
200
- result.flatten.join
160
+ result
201
161
  end
202
162
 
203
163
  ##
@@ -207,118 +167,114 @@ module Padrino
207
167
  # field_name(:number) => "user_telephone_attributes_number"
208
168
  # field_name(:street) => "user_addresses_attributes_0_street"
209
169
  def field_id(field=nil, value=nil)
210
- result = []
211
- result << "#{@options[:namespace]}_" if @options[:namespace] && root_form?
212
- result << field_result
213
- result << field_id_fragment if nested_form?
170
+ result = (namespace && !is_nested) ? "#{namespace}_" : ''
171
+ result << field_id_fragment
214
172
  result << "_#{field}" unless field.blank?
215
173
  result << "_#{value}" unless value.blank?
216
- result.flatten.join
174
+ result
217
175
  end
218
176
 
219
177
  ##
220
178
  # Returns the child object if it exists.
221
179
  #
222
180
  def nested_object_id
223
- nested_form? && object.respond_to?(:new_record?) && !object.new_record? && object.id
224
- end
225
-
226
- ##
227
- # Returns true if this form object is nested in a parent form.
228
- #
229
- def nested_form?
230
- @options[:nested] && @options[:nested][:parent] && @options[:nested][:parent].respond_to?(:object)
181
+ is_nested && object.respond_to?(:new_record?) && !object.new_record? && object.id
231
182
  end
232
183
 
233
184
  ##
234
185
  # Returns the value for the object's field.
235
186
  #
236
187
  def field_value(field)
237
- @object && @object.respond_to?(field) ? @object.send(field) : ""
188
+ @object.respond_to?(field) ? @object.send(field) : ''
238
189
  end
239
190
 
240
191
  ##
241
- # Returns a new record of the type specified in the object
192
+ # Returns a record from template instance or create a record of specified class.
242
193
  #
243
- def build_object(object_or_symbol)
244
- object_or_symbol.is_a?(Symbol) ? @template.instance_variable_get("@#{object_or_symbol}") || object_class(object_or_symbol).new : object_or_symbol
194
+ def build_object(symbol)
195
+ @template.instance_variable_get("@#{symbol}") || symbol.to_s.camelize.constantize.new
245
196
  end
246
197
 
247
198
  ##
248
- # Returns the object's models name.
199
+ # Builds a group of labels for radios or checkboxes.
249
200
  #
250
- def object_model_name(explicit_object=object)
251
- return @options[:as] if root_form? && @options[:as].is_a?(Symbol)
252
- explicit_object.is_a?(Symbol) ? explicit_object : explicit_object.class.to_s.underscore.gsub(/\//, '_')
201
+ def labeled_group(field, options={})
202
+ options = { :id => field_id(field), :selected => field_value(field) }.update(options)
203
+ options.update(error_class(field)){ |_,*values| values.compact.join(' ') }
204
+ selected_values = resolve_checked_values(field, options)
205
+ variants_for_group(options).inject(ActiveSupport::SafeBuffer.new) do |html, (caption,value)|
206
+ variant_id = "#{options[:id]}_#{value}"
207
+ attributes = { :value => value, :id => variant_id, :checked => selected_values.include?(value) }
208
+ caption = yield(attributes) << ' ' << caption
209
+ html << @template.label_tag("#{field_name(field)}[]", :for => variant_id, :caption => caption)
210
+ end
253
211
  end
254
212
 
255
- ##
256
- # Returns the class type for the given object.
257
- #
258
- def object_class(explicit_object)
259
- explicit_object.is_a?(Symbol) ? explicit_object.to_s.camelize.constantize : explicit_object.class
260
- end
213
+ private
261
214
 
262
- ##
263
- # Returns true if this form is the top-level (not nested).
264
- #
265
- def root_form?
266
- !nested_form?
215
+ def is_checked?(field, options)
216
+ !options.has_key?(:checked) && [options[:value].to_s, 'true'].include?(field_value(field).to_s)
267
217
  end
268
218
 
269
- ##
270
- # Builds a group of labels for radios or checkboxes.
271
- #
272
- def labeled_group(field, options={})
273
- options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
274
- options.merge!(:class => field_error(field, options))
275
- variants = case
276
- when options[:options]
277
- options[:options].map{ |caption, value| [caption.to_s, (value||caption).to_s] }
278
- when options[:collection]
279
- fields = options[:fields] || [:name, :id]
280
- options[:collection].map{ |variant| [variant.send(fields.first).to_s, variant.send(fields.last).to_s] }
219
+ def variants_for_group(options)
220
+ if variants = options[:options]
221
+ variants.map{ |caption, value| [caption.to_s, (value||caption).to_s] }
222
+ elsif collection = options[:collection]
223
+ collection.map{ |variant| field_values(variant, options) }
281
224
  else
282
225
  []
283
226
  end
284
- variants.inject(''.html_safe) do |html, variant|
285
- variant[2] = "#{field_id(field)}_#{variant[1]}"
286
- caption = yield(variant) << ' ' << variant[0]
287
- html << @template.label_tag("#{field_name(field)}[]", :for => variant[2], :caption => caption)
227
+ end
228
+
229
+ def resolve_checked_values(field, options)
230
+ selected_values = Array(options[:selected] || field_value(field))
231
+ if options[:collection]
232
+ _, id_method = *field_methods(options)
233
+ selected_values.map do |value|
234
+ (value.respond_to?(id_method) ? value.send(id_method) : value).to_s
235
+ end
236
+ else
237
+ selected_values
288
238
  end
289
239
  end
290
240
 
291
- private
241
+ def field_methods(options)
242
+ options[:fields] || [:name, :id]
243
+ end
292
244
 
293
- def field_result
294
- result = []
295
- result << object_model_name if root_form?
296
- result
245
+ def field_values(object, options)
246
+ field_methods(options).map{ |field| object.send(field).to_s }
297
247
  end
298
248
 
299
249
  def field_name_fragment
300
- fragment = [result_options[:parent_form].field_name, "[#{result_options[:attributes_name]}", "]"]
301
- fragment.insert(2, "][#{result_options[:nested_index]}") if result_options[:nested_index]
302
- fragment
250
+ if is_nested
251
+ fragment = parent_form.field_name.dup << "[#{attributes_name}"
252
+ fragment << "][#{nested_index}" if nested_index
253
+ fragment << "]"
254
+ else
255
+ "#{model_name}"
256
+ end
303
257
  end
304
258
 
305
259
  def field_id_fragment
306
- fragment = [result_options[:parent_form].field_id, "_#{result_options[:attributes_name]}"]
307
- fragment.push("_#{result_options[:nested_index]}") if result_options[:nested_index]
308
- fragment
260
+ if is_nested
261
+ fragment = parent_form.field_id.dup << "_#{attributes_name}"
262
+ fragment << "_#{nested_index}" if nested_index
263
+ fragment
264
+ else
265
+ "#{model_name}"
266
+ end
309
267
  end
310
268
 
311
- def result_options
312
- {
313
- :parent_form => @options[:nested][:parent],
314
- :nested_index => @options[:nested][:index],
315
- :attributes_name => "#{@options[:nested][:association]}_attributes"
316
- }
269
+ def error_class(field)
270
+ error = @object.errors[field] if @object.respond_to?(:errors)
271
+ error.blank? ? {} : { :class => 'invalid' }
317
272
  end
318
273
 
319
- def merge_default_options!(field, options)
320
- options.reverse_merge!(:value => field_value(field), :id => field_id(field))
321
- options.merge!(:class => field_error(field, options))
274
+ def default_options(field, options, defaults={})
275
+ { :value => field_value(field),
276
+ :id => field_id(field)
277
+ }.update(defaults).update(options).update(error_class(field)){ |_,*values| values.compact.join(' ') }
322
278
  end
323
279
  end
324
280
  end