padrino-helpers 0.12.0 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
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