padrino-helpers 0.11.3 → 0.11.4

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 (50) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +1 -1
  3. data/lib/padrino-helpers.rb +3 -5
  4. data/lib/padrino-helpers/asset_tag_helpers.rb +32 -40
  5. data/lib/padrino-helpers/breadcrumb_helpers.rb +21 -39
  6. data/lib/padrino-helpers/form_builder/abstract_form_builder.rb +121 -118
  7. data/lib/padrino-helpers/form_builder/standard_form_builder.rb +6 -9
  8. data/lib/padrino-helpers/form_helpers.rb +190 -193
  9. data/lib/padrino-helpers/format_helpers.rb +29 -42
  10. data/lib/padrino-helpers/locale/cs.yml +14 -14
  11. data/lib/padrino-helpers/locale/da.yml +1 -1
  12. data/lib/padrino-helpers/locale/de.yml +1 -1
  13. data/lib/padrino-helpers/locale/en.yml +16 -16
  14. data/lib/padrino-helpers/locale/es.yml +16 -16
  15. data/lib/padrino-helpers/locale/fr.yml +1 -2
  16. data/lib/padrino-helpers/locale/hu.yml +16 -16
  17. data/lib/padrino-helpers/locale/it.yml +2 -2
  18. data/lib/padrino-helpers/locale/ja.yml +16 -16
  19. data/lib/padrino-helpers/locale/lv.yml +16 -16
  20. data/lib/padrino-helpers/locale/nl.yml +1 -1
  21. data/lib/padrino-helpers/locale/no.yml +1 -1
  22. data/lib/padrino-helpers/locale/pl.yml +7 -7
  23. data/lib/padrino-helpers/locale/pt_br.yml +16 -16
  24. data/lib/padrino-helpers/locale/ro.yml +16 -16
  25. data/lib/padrino-helpers/locale/ru.yml +16 -16
  26. data/lib/padrino-helpers/locale/sv.yml +16 -16
  27. data/lib/padrino-helpers/locale/tr.yml +16 -16
  28. data/lib/padrino-helpers/locale/uk.yml +16 -16
  29. data/lib/padrino-helpers/locale/zh_cn.yml +16 -16
  30. data/lib/padrino-helpers/locale/zh_tw.yml +16 -16
  31. data/lib/padrino-helpers/number_helpers.rb +10 -15
  32. data/lib/padrino-helpers/output_helpers.rb +49 -57
  33. data/lib/padrino-helpers/output_helpers/abstract_handler.rb +16 -18
  34. data/lib/padrino-helpers/output_helpers/erb_handler.rb +11 -12
  35. data/lib/padrino-helpers/output_helpers/haml_handler.rb +9 -9
  36. data/lib/padrino-helpers/output_helpers/slim_handler.rb +11 -13
  37. data/lib/padrino-helpers/render_helpers.rb +5 -6
  38. data/lib/padrino-helpers/tag_helpers.rb +18 -21
  39. data/lib/padrino-helpers/translation_helpers.rb +4 -6
  40. data/test/fixtures/markup_app/app.rb +7 -3
  41. data/test/fixtures/render_app/app.rb +1 -0
  42. data/test/test_asset_tag_helpers.rb +1 -1
  43. data/test/test_form_builder.rb +5 -6
  44. data/test/test_form_helpers.rb +24 -12
  45. data/test/test_format_helpers.rb +3 -3
  46. data/test/test_number_helpers.rb +4 -0
  47. data/test/test_output_helpers.rb +1 -1
  48. data/test/test_render_helpers.rb +1 -1
  49. data/test/test_tag_helpers.rb +1 -1
  50. metadata +9 -15
@@ -1,7 +1,7 @@
1
1
  module Padrino
2
2
  module Helpers
3
- module FormBuilder # @private
4
- class AbstractFormBuilder # @private
3
+ module FormBuilder
4
+ class AbstractFormBuilder
5
5
  attr_accessor :template, :object, :multipart
6
6
 
7
7
  def initialize(template, object, options={})
@@ -12,37 +12,32 @@ module Padrino
12
12
  raise "FormBuilder object must not be a nil value. If there's no object, use a symbol instead! (i.e :user)" unless object
13
13
  end
14
14
 
15
- # f.error_messages
16
15
  def error_messages(*params)
17
16
  params.unshift object
18
17
  @template.error_messages_for(*params)
19
18
  end
20
19
 
21
- # f.error_message_on(field)
22
20
  def error_message_on(field, options={})
23
21
  @template.error_message_on(object, field, options)
24
22
  end
25
23
 
26
- # f.label :username, :caption => "Nickname"
27
24
  def label(field, options={}, &block)
28
25
  options.reverse_merge!(:caption => "#{field_human_name(field)}: ")
29
26
  @template.label_tag(field_id(field), options, &block)
30
27
  end
31
28
 
32
- # f.hidden_field :session_id, :value => "45"
33
29
  def hidden_field(field, options={})
34
30
  options.reverse_merge!(:value => field_value(field), :id => field_id(field))
35
31
  @template.hidden_field_tag field_name(field), options
36
32
  end
37
33
 
38
- # f.text_field :username, :value => "(blank)", :id => 'username'
39
34
  def text_field(field, options={})
40
35
  options.reverse_merge!(:value => field_value(field), :id => field_id(field))
41
36
  options.merge!(:class => field_error(field, options))
42
37
  @template.text_field_tag field_name(field), options
43
38
  end
44
39
 
45
- def number_field(field, options={})
40
+ def number_field(field, options={})
46
41
  options.reverse_merge!(:value => field_value(field), :id => field_id(field))
47
42
  options.merge!(:class => field_error(field, options))
48
43
  @template.number_field_tag field_name(field), options
@@ -73,35 +68,28 @@ module Padrino
73
68
  @template.url_field_tag field_name(field), options
74
69
  end
75
70
 
76
- # f.text_area :summary, :value => "(enter summary)", :id => 'summary'
77
71
  def text_area(field, options={})
78
72
  options.reverse_merge!(:value => field_value(field), :id => field_id(field))
79
73
  options.merge!(:class => field_error(field, options))
80
74
  @template.text_area_tag field_name(field), options
81
75
  end
82
76
 
83
- # f.password_field :password, :id => 'password'
84
77
  def password_field(field, options={})
85
78
  options.reverse_merge!(:value => field_value(field), :id => field_id(field))
86
79
  options.merge!(:class => field_error(field, options))
87
80
  @template.password_field_tag field_name(field), options
88
81
  end
89
82
 
90
- # f.select :color, :options => ['red', 'green'], :include_blank => true
91
- # f.select :color, :collection => @colors, :fields => [:name, :id]
92
83
  def select(field, options={})
93
84
  options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
94
85
  options.merge!(:class => field_error(field, options))
95
86
  @template.select_tag field_name(field), options
96
87
  end
97
88
 
98
- # f.check_box_group :color, :options => ['red', 'green', 'blue'], :selected => ['red', 'blue']
99
- # f.check_box_group :color, :collection => @colors, :fields => [:name, :id]
100
89
  def check_box_group(field, options={})
101
90
  selected_values = Array(options[:selected] || field_value(field))
102
91
  if options[:collection]
103
92
  fields = options[:fields] || [:name, :id]
104
- # don't use map!, it will break some orms
105
93
  selected_values = selected_values.map{ |v| (v.respond_to?(fields[0]) ? v.send(fields[1]) : v).to_s }
106
94
  end
107
95
  labeled_group( field, options ) do |variant|
@@ -109,8 +97,6 @@ module Padrino
109
97
  end
110
98
  end
111
99
 
112
- # f.radio_button_group :color, :options => ['red', 'green']
113
- # f.radio_button_group :color, :collection => @colors, :fields => [:name, :id], :selected => @colors.first
114
100
  def radio_button_group(field, options={})
115
101
  fields = options[:fields] || [:name, :id]
116
102
  selected_value = options[:selected] || field_value(field)
@@ -120,7 +106,6 @@ module Padrino
120
106
  end
121
107
  end
122
108
 
123
- # f.check_box :remember_me, :value => 'true', :uncheck_value => '0'
124
109
  def check_box(field, options={})
125
110
  html = ActiveSupport::SafeBuffer.new
126
111
  unchecked_value = options.delete(:uncheck_value) || '0'
@@ -130,14 +115,12 @@ module Padrino
130
115
  html << @template.check_box_tag(field_name(field), options)
131
116
  end
132
117
 
133
- # f.radio_button :gender, :value => 'male'
134
118
  def radio_button(field, options={})
135
119
  options.reverse_merge!(:id => field_id(field, options[:value]))
136
120
  options.reverse_merge!(:checked => true) if values_matches_field?(field, options[:value])
137
121
  @template.radio_button_tag field_name(field), options
138
122
  end
139
123
 
140
- # f.file_field :photo, :class => 'avatar'
141
124
  def file_field(field, options={})
142
125
  self.multipart = true
143
126
  options.reverse_merge!(:id => field_id(field))
@@ -145,19 +128,18 @@ module Padrino
145
128
  @template.file_field_tag field_name(field), options
146
129
  end
147
130
 
148
- # f.submit "Update", :class => 'large'
149
131
  def submit(*args)
150
132
  options = args[-1].is_a?(Hash) ? args.pop : {}
151
133
  caption = args.length >= 1 ? args.shift : "Submit"
152
134
  @template.submit_tag caption, options
153
135
  end
154
136
 
155
- # f.image_submit "buttons/submit.png", :class => 'large'
156
137
  def image_submit(source, options={})
157
138
  @template.image_submit_tag source, options
158
139
  end
159
140
 
160
- # Supports nested fields for a child model within a form
141
+ ##
142
+ # Supports nested fields for a child model within a form.
161
143
  # f.fields_for :addresses
162
144
  # f.fields_for :addresses, address
163
145
  # f.fields_for :addresses, @addresses
@@ -166,7 +148,7 @@ module Padrino
166
148
  include_index = default_collection.respond_to?(:each)
167
149
  nested_options = { :parent => self, :association => child_association }
168
150
  nested_objects = instance_or_collection ? Array(instance_or_collection) : Array(default_collection)
169
- result = nested_objects.each_with_index.map do |child_instance, index|
151
+ nested_objects.each_with_index.map do |child_instance, index|
170
152
  nested_options[:index] = include_index ? index : nil
171
153
  @template.fields_for(child_instance, { :nested => nested_options }, &block)
172
154
  end.join("\n").html_safe
@@ -177,112 +159,133 @@ module Padrino
177
159
  end
178
160
 
179
161
  protected
180
- # Returns the known field types for a formbuilder
181
- def self.field_types
182
- [:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
183
- end
162
+ # Returns the known field types for a Formbuilder.
163
+ def self.field_types
164
+ [:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
165
+ end
184
166
 
185
- # Returns true if the value matches the value in the field
186
- # field_has_value?(:gender, 'male')
187
- def values_matches_field?(field, value)
188
- value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
189
- end
167
+ ##
168
+ # Returns true if the value matches the value in the field.
169
+ # field_has_value?(:gender, 'male')
170
+ def values_matches_field?(field, value)
171
+ value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
172
+ end
190
173
 
191
- # Add a :invalid css class to the field if it contain an error
192
- def field_error(field, options)
193
- error = @object.errors[field] rescue nil
194
- error.blank? ? options[:class] : [options[:class], :invalid].flatten.compact.join(" ")
195
- end
174
+ ##
175
+ # Add a :invalid css class to the field if it contain an error.
176
+ #
177
+ def field_error(field, options)
178
+ error = @object.errors[field] rescue nil
179
+ error.blank? ? options[:class] : [options[:class], :invalid].flatten.compact.join(" ")
180
+ end
196
181
 
197
- # Returns the human name of the field. Look that use builtin I18n.
198
- def field_human_name(field)
199
- I18n.translate("#{object_model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models)
200
- end
182
+ ##
183
+ # Returns the human name of the field. Look that use builtin I18n.
184
+ #
185
+ def field_human_name(field)
186
+ I18n.translate("#{object_model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models)
187
+ end
201
188
 
202
- # Returns the name for the given field
203
- # field_name(:username) => "user[username]"
204
- # field_name(:number) => "user[telephone_attributes][number]"
205
- # field_name(:street) => "user[addresses_attributes][0][street]"
206
- def field_name(field=nil)
207
- result = field_result
208
- result << field_name_fragment if nested_form?
209
- result << "[#{field}]" unless field.blank?
210
- result.flatten.join
211
- end
189
+ ##
190
+ # Returns the name for the given field.
191
+ # field_name(:username) => "user[username]"
192
+ # field_name(:number) => "user[telephone_attributes][number]"
193
+ # field_name(:street) => "user[addresses_attributes][0][street]"
194
+ def field_name(field=nil)
195
+ result = field_result
196
+ result << field_name_fragment if nested_form?
197
+ result << "[#{field}]" unless field.blank?
198
+ result.flatten.join
199
+ end
212
200
 
213
- # Returns the id for the given field
214
- # field_id(:username) => "user_username"
215
- # field_id(:gender, :male) => "user_gender_male"
216
- # field_name(:number) => "user_telephone_attributes_number"
217
- # field_name(:street) => "user_addresses_attributes_0_street"
218
- def field_id(field=nil, value=nil)
219
- result = []
220
- result << "#{@options[:namespace]}_" if @options[:namespace] && root_form?
221
- result << field_result
222
- result << field_id_fragment if nested_form?
223
- result << "_#{field}" unless field.blank?
224
- result << "_#{value}" unless value.blank?
225
- result.flatten.join
226
- end
201
+ ##
202
+ # Returns the id for the given field.
203
+ # field_id(:username) => "user_username"
204
+ # field_id(:gender, :male) => "user_gender_male"
205
+ # field_name(:number) => "user_telephone_attributes_number"
206
+ # field_name(:street) => "user_addresses_attributes_0_street"
207
+ def field_id(field=nil, value=nil)
208
+ result = []
209
+ result << "#{@options[:namespace]}_" if @options[:namespace] && root_form?
210
+ result << field_result
211
+ result << field_id_fragment if nested_form?
212
+ result << "_#{field}" unless field.blank?
213
+ result << "_#{value}" unless value.blank?
214
+ result.flatten.join
215
+ end
227
216
 
228
- # Returns the child object if it exists
229
- def nested_object_id
230
- nested_form? && object.respond_to?(:new_record?) && !object.new_record? && object.id
231
- end
217
+ ##
218
+ # Returns the child object if it exists.
219
+ #
220
+ def nested_object_id
221
+ nested_form? && object.respond_to?(:new_record?) && !object.new_record? && object.id
222
+ end
232
223
 
233
- # Returns true if this form object is nested in a parent form
234
- def nested_form?
235
- @options[:nested] && @options[:nested][:parent] && @options[:nested][:parent].respond_to?(:object)
236
- end
224
+ ##
225
+ # Returns true if this form object is nested in a parent form.
226
+ #
227
+ def nested_form?
228
+ @options[:nested] && @options[:nested][:parent] && @options[:nested][:parent].respond_to?(:object)
229
+ end
237
230
 
238
- # Returns the value for the object's field
239
- # field_value(:username) => "Joey"
240
- def field_value(field)
241
- @object && @object.respond_to?(field) ? @object.send(field) : ""
242
- end
231
+ ##
232
+ # Returns the value for the object's field.
233
+ #
234
+ def field_value(field)
235
+ @object && @object.respond_to?(field) ? @object.send(field) : ""
236
+ end
243
237
 
244
- # explicit_object is either a symbol or a record
245
- # Returns a new record of the type specified in the object
246
- def build_object(object_or_symbol)
247
- object_or_symbol.is_a?(Symbol) ? @template.instance_variable_get("@#{object_or_symbol}") || object_class(object_or_symbol).new : object_or_symbol
248
- end
238
+ ##
239
+ # Returns a new record of the type specified in the object
240
+ #
241
+ def build_object(object_or_symbol)
242
+ object_or_symbol.is_a?(Symbol) ? @template.instance_variable_get("@#{object_or_symbol}") || object_class(object_or_symbol).new : object_or_symbol
243
+ end
249
244
 
250
- # Returns the object's models name
251
- # => user_assignment
252
- def object_model_name(explicit_object=object)
253
- explicit_object.is_a?(Symbol) ? explicit_object : explicit_object.class.to_s.underscore.gsub(/\//, '_')
254
- end
245
+ ##
246
+ # Returns the object's models name.
247
+ #
248
+ def object_model_name(explicit_object=object)
249
+ explicit_object.is_a?(Symbol) ? explicit_object : explicit_object.class.to_s.underscore.gsub(/\//, '_')
250
+ end
255
251
 
256
- # Returns the class type for the given object
257
- def object_class(explicit_object)
258
- explicit_object.is_a?(Symbol) ? explicit_object.to_s.camelize.constantize : explicit_object.class
259
- end
252
+ ##
253
+ # Returns the class type for the given object.
254
+ #
255
+ def object_class(explicit_object)
256
+ explicit_object.is_a?(Symbol) ? explicit_object.to_s.camelize.constantize : explicit_object.class
257
+ end
260
258
 
261
- # Returns true if this form is the top-level (not nested)
262
- def root_form?
263
- !nested_form?
264
- end
259
+ ##
260
+ # Returns true if this form is the top-level (not nested).
261
+ #
262
+ def root_form?
263
+ !nested_form?
264
+ end
265
265
 
266
- # Builds a group of labels for radios or checkboxes
267
- def labeled_group(field, options={})
268
- options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
269
- options.merge!(:class => field_error(field, options))
270
- variants = case
271
- when options[:options]
272
- options[:options].map{ |caption, value| [caption.to_s, (value||caption).to_s] }
273
- when options[:collection]
274
- fields = options[:fields] || [:name, :id]
275
- options[:collection].map{ |variant| [variant.send(fields.first).to_s, variant.send(fields.last).to_s] }
276
- else
277
- []
278
- end
279
- variants.inject(''.html_safe) do |html, variant|
280
- variant[2] = "#{field_id(field)}_#{variant[1]}"
281
- html << @template.label_tag("#{field_name(field)}[]", :for => variant[2], :caption => "#{yield(variant)} #{variant[0]}")
282
- end
266
+ ##
267
+ # Builds a group of labels for radios or checkboxes.
268
+ #
269
+ def labeled_group(field, options={})
270
+ options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
271
+ options.merge!(:class => field_error(field, options))
272
+ variants = case
273
+ when options[:options]
274
+ options[:options].map{ |caption, value| [caption.to_s, (value||caption).to_s] }
275
+ when options[:collection]
276
+ fields = options[:fields] || [:name, :id]
277
+ options[:collection].map{ |variant| [variant.send(fields.first).to_s, variant.send(fields.last).to_s] }
278
+ else
279
+ []
280
+ end
281
+ variants.inject(''.html_safe) do |html, variant|
282
+ variant[2] = "#{field_id(field)}_#{variant[1]}"
283
+ html << @template.label_tag("#{field_name(field)}[]", :for => variant[2], :caption => "#{yield(variant)} #{variant[0]}")
283
284
  end
285
+ end
284
286
 
285
287
  private
288
+
286
289
  def field_result
287
290
  result = []
288
291
  result << object_model_name if root_form?
@@ -308,7 +311,7 @@ module Padrino
308
311
  :attributes_name => "#{@options[:nested][:association]}_attributes"
309
312
  }
310
313
  end
311
- end # AbstractFormBuilder
312
- end # FormBuilder
313
- end # Helpers
314
- end # Padrino
314
+ end
315
+ end
316
+ end
317
+ end
@@ -2,9 +2,8 @@ require File.expand_path(File.dirname(__FILE__) + '/abstract_form_builder') unle
2
2
 
3
3
  module Padrino
4
4
  module Helpers
5
- module FormBuilder # @private
6
- class StandardFormBuilder < AbstractFormBuilder # @private
7
-
5
+ module FormBuilder
6
+ class StandardFormBuilder < AbstractFormBuilder
8
7
  ##
9
8
  # StandardFormBuilder
10
9
  #
@@ -26,18 +25,16 @@ module Padrino
26
25
  EOF
27
26
  end
28
27
 
29
- # submit_block("Update")
30
28
  def submit_block(caption, options={})
31
29
  submit_html = self.submit(caption, options)
32
30
  @template.content_tag(:p, submit_html)
33
31
  end
34
32
 
35
- # image_submit_block("submit.png")
36
33
  def image_submit_block(source, options={})
37
34
  submit_html = self.image_submit(source, options)
38
35
  @template.content_tag(:p, submit_html)
39
36
  end
40
- end # StandardFormBuilder
41
- end # FormBuilder
42
- end # Helpers
43
- end # Padrino
37
+ end
38
+ end
39
+ end
40
+ end
@@ -7,16 +7,16 @@ module Padrino
7
7
  #
8
8
  module FormHelpers
9
9
  ##
10
- # Constructs a form for object using given or default form_builder
10
+ # Constructs a form for object using given or default form_builder.
11
11
  #
12
12
  # @param [Object] object
13
13
  # The object for which the form is being built.
14
- # @param [String] url
14
+ # @param [String] URL
15
15
  # The url this form will submit to.
16
16
  # @param [Hash] settings
17
17
  # The settings associated with this form.
18
18
  # Accepts a :namespace option that will be prepended to the id attributes of the form's elements.
19
- # Also accepts html options.
19
+ # Also accepts HTML options.
20
20
  # @option settings [String] :builder ("StandardFormBuilder")
21
21
  # The FormBuilder class to use such as StandardFormBuilder.
22
22
  # @param [Proc] block
@@ -30,7 +30,6 @@ module Padrino
30
30
  # form_for :user, '/register' do |f| ... end
31
31
  # form_for @user, '/register', :id => 'register' do |f| ... end
32
32
  #
33
- # @api public
34
33
  def form_for(object, url, settings={}, &block)
35
34
  instance = builder_instance(object, settings)
36
35
  html = capture_html(instance, &block)
@@ -40,13 +39,13 @@ module Padrino
40
39
  end
41
40
 
42
41
  ##
43
- # Constructs form fields for an object using given or default form_builder
44
- # Used within an existing form to allow alternate objects within one form
42
+ # Constructs form fields for an object using given or default form_builder.
43
+ # Used within an existing form to allow alternate objects within one form.
45
44
  #
46
45
  # @param [Object] object
47
46
  # The object for which the fields are being built.
48
47
  # @param [Hash] settings
49
- # The settings associated with these fields. Accepts html options.
48
+ # The settings associated with these fields. Accepts HTML options.
50
49
  # @param [Proc] block
51
50
  # The content inside this set of fields.
52
51
  #
@@ -56,7 +55,6 @@ module Padrino
56
55
  # fields_for @user.assignment do |assignment| ... end
57
56
  # fields_for :assignment do |assigment| ... end
58
57
  #
59
- # @api public
60
58
  def fields_for(object, settings={}, &block)
61
59
  instance = builder_instance(object, settings)
62
60
  fields_html = capture_html(instance, &block)
@@ -65,21 +63,20 @@ module Padrino
65
63
  end
66
64
 
67
65
  ##
68
- # Constructs a form without object based on options
66
+ # Constructs a form without object based on options.
69
67
  #
70
68
  # @param [String] url
71
- # The url this form will submit to.
69
+ # The URL this form will submit to.
72
70
  # @param [Hash] options
73
71
  # The html options associated with this form.
74
72
  # @param [Proc] block
75
73
  # The fields and content inside this form.
76
74
  #
77
- # @return [String] The html form with the specified options and input fields.
75
+ # @return [String] The HTML form with the specified options and input fields.
78
76
  #
79
77
  # @example
80
78
  # form_tag '/register', :class => "registration_form" do ... end
81
79
  #
82
- # @api public
83
80
  def form_tag(url, options={}, &block)
84
81
  desired_method = options[:method].to_s
85
82
  options.delete(:method) unless desired_method =~ /get|post/i
@@ -99,12 +96,12 @@ module Padrino
99
96
  end
100
97
 
101
98
  ##
102
- # Returns the hidden method field for 'put' and 'delete' forms
99
+ # Returns the hidden method field for 'put' and 'delete' forms.
103
100
  # Only 'get' and 'post' are allowed within browsers;
104
101
  # 'put' and 'delete' are just specified using hidden fields with form action still 'put'.
105
102
  #
106
103
  # @param [String] desired_method
107
- # The method this hidden field represents (i.e put or delete))
104
+ # The method this hidden field represents (i.e put or delete).
108
105
  #
109
106
  # @return [String] The hidden field representing the +desired_method+ for the form.
110
107
  #
@@ -112,14 +109,13 @@ module Padrino
112
109
  # # Generate: <input name="_method" value="delete" />
113
110
  # hidden_form_method_field('delete')
114
111
  #
115
- # @api semipublic
116
112
  def hidden_form_method_field(desired_method)
117
113
  return ActiveSupport::SafeBuffer.new if desired_method.blank? || desired_method.to_s =~ /get|post/i
118
114
  hidden_field_tag(:_method, :value => desired_method)
119
115
  end
120
116
 
121
117
  ##
122
- # Constructs a field_set to group fields with given options
118
+ # Constructs a field_set to group fields with given options.
123
119
  #
124
120
  # @overload field_set_tag(legend=nil, options={}, &block)
125
121
  # @param [String] legend The legend caption for the fieldset
@@ -135,7 +131,6 @@ module Padrino
135
131
  # field_set_tag(:class => "office-set") { }
136
132
  # field_set_tag("Office", :class => 'office-set') { }
137
133
  #
138
- # @api public
139
134
  def field_set_tag(*args, &block)
140
135
  options = args.extract_options!
141
136
  legend_text = args[0].is_a?(String) ? args.first : nil
@@ -145,13 +140,13 @@ module Padrino
145
140
  end
146
141
 
147
142
  ##
148
- # Constructs list html for the errors for a given symbol
143
+ # Constructs list HTML for the errors for a given symbol.
149
144
  #
150
145
  # @overload error_messages_for(*objects, options = {})
151
146
  # @param [Array<Object>] object Splat of objects to display errors for.
152
147
  # @param [Hash] options Error message display options.
153
148
  # @option options [String] :header_tag ("h2")
154
- # Used for the header of the error div
149
+ # Used for the header of the error div.
155
150
  # @option options [String] :id ("field-errors")
156
151
  # The id of the error div.
157
152
  # @option options [String] :class ("field-errors")
@@ -163,7 +158,7 @@ module Padrino
163
158
  # The object name to use in the header, or any text that you prefer.
164
159
  # If +:object_name+ is not set, the name of the first object will be used.
165
160
  # @option options [String] :header_message ("X errors prohibited this object from being saved")
166
- # The message in the header of the error div. Pass +nil+ or an empty string
161
+ # The message in the header of the error div. Pass +nil+ or an empty string
167
162
  # to avoid the header message altogether.
168
163
  # @option options [String] :message ("There were problems with the following fields:")
169
164
  # The explanation message after the header message and before
@@ -175,7 +170,6 @@ module Padrino
175
170
  # @example
176
171
  # error_messages_for :user
177
172
  #
178
- # @api public
179
173
  def error_messages_for(*objects)
180
174
  options = objects.extract_options!.symbolize_keys
181
175
  objects = objects.map { |object_name|
@@ -194,19 +188,19 @@ module Padrino
194
188
  end
195
189
  end
196
190
 
197
- options[:object_name] ||= objects.first.class
191
+ options[:object_name] ||= objects.first.class.to_s.underscore.gsub(/\//, ' ')
198
192
 
199
193
  I18n.with_options :locale => options[:locale], :scope => [:models, :errors, :template] do |locale|
200
194
  header_message = if options.include?(:header_message)
201
195
  options[:header_message]
202
196
  else
203
- object_name = options[:object_name].to_s.underscore.gsub(/\//, ' ')
197
+ object_name = options[:object_name]
204
198
  object_name = I18n.t(:name, :default => object_name.humanize, :scope => [:models, object_name], :count => 1)
205
199
  locale.t :header, :count => count, :model => object_name
206
200
  end
207
201
  message = options.include?(:message) ? options[:message] : locale.t(:body)
208
202
  error_messages = objects.map { |object|
209
- object_name = options[:object_name].to_s.underscore.gsub(/\//, ' ')
203
+ object_name = options[:object_name]
210
204
  object.errors.map { |f, msg|
211
205
  field = I18n.t(f, :default => f.to_s.humanize, :scope => [:models, object_name, :attributes])
212
206
  content_tag(:li, "%s %s" % [field, msg])
@@ -226,7 +220,8 @@ module Padrino
226
220
  end
227
221
 
228
222
  ##
229
- # Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
223
+ # Returns a string containing the error message attached to the
224
+ # +method+ on the +object+ if one exists.
230
225
  #
231
226
  # @param [Object] object
232
227
  # The object to display the error for.
@@ -262,7 +257,7 @@ module Padrino
262
257
  I18n.t("ohm.errors.messages.#{error[0]}", :default => error[0].to_s)
263
258
  else
264
259
  # Array(error).first is necessary because some ORMs
265
- # give us an array others directly a value
260
+ # give us an array others directly a value.
266
261
  Array(error)[0]
267
262
  end
268
263
 
@@ -277,7 +272,7 @@ module Padrino
277
272
  end
278
273
 
279
274
  ##
280
- # Constructs a label tag from the given options
275
+ # Constructs a label tag from the given options.
281
276
  #
282
277
  # @param [String] name
283
278
  # The name of the field to label.
@@ -294,7 +289,6 @@ module Padrino
294
289
  # label_tag :username, :class => 'long-label'
295
290
  # label_tag :username, :class => 'long-label' do ... end
296
291
  #
297
- # @api public
298
292
  def label_tag(name, options={}, &block)
299
293
  options.reverse_merge!(:caption => "#{name.to_s.humanize}: ", :for => name)
300
294
  caption_text = options.delete(:caption).html_safe
@@ -309,7 +303,7 @@ module Padrino
309
303
  end
310
304
 
311
305
  ##
312
- # Creates a text field input with the given name and options
306
+ # Creates a text field input with the given name and options.
313
307
  #
314
308
  # @macro [new] text_field
315
309
  # @param [Symbol] name
@@ -338,22 +332,22 @@ module Padrino
338
332
  # @option options [Boolean] :spellcheck
339
333
  # Specifies whether or not the field should have it's spelling and grammar checked for errors.
340
334
  # @option options [Boolean] :draggable
341
- # Specifies whether or not the field is draggable. (true, false, :auto)
335
+ # Specifies whether or not the field is draggable. (true, false, :auto).
342
336
  # @option options [String] :pattern
343
337
  # Specifies the regular expression pattern that the field's value is checked against.
344
338
  # @option options [Symbol] :autocomplete
345
- # Specifies whether or not the field should have autocomplete enabled. (:on, :off)
339
+ # Specifies whether or not the field should have autocomplete enabled. (:on, :off).
346
340
  # @option options [Boolean] :autofocus
347
341
  # Specifies whether or not the field should automatically get focus when the page loads.
348
342
  # @option options [Boolean] :required
349
- # Specifies whether or not the field is required to be completeled before the form is submitted.
343
+ # Specifies whether or not the field is required to be completed before the form is submitted.
350
344
  # @option options [Boolean] :readonly
351
345
  # Specifies whether or not the field is read only.
352
346
  # @option options [Boolean] :disabled
353
347
  # Specifies whether or not the field is disabled.
354
348
  #
355
349
  # @return [String]
356
- # Generated HTML with specified +options+
350
+ # Generated HTML with specified +options+.
357
351
  #
358
352
  # @example
359
353
  # text_field_tag :first_name, :maxlength => 40, :required => true
@@ -365,13 +359,12 @@ module Padrino
365
359
  # text_field_tag :username, :placeholder => 'Your Username'
366
360
  # # => <input name="username" placeholder="Your Username" type="text" />
367
361
  #
368
- # @api public
369
362
  def text_field_tag(name, options={})
370
363
  input_tag(:text, options.reverse_merge!(:name => name))
371
364
  end
372
365
 
373
366
  ##
374
- # Creates a number field input with the given name and options
367
+ # Creates a number field input with the given name and options.
375
368
  #
376
369
  # @macro [new] number_field
377
370
  # @param [Symbol] name
@@ -400,11 +393,11 @@ module Padrino
400
393
  # @option options [Boolean] :spellcheck
401
394
  # Specifies whether or not the field should have it's spelling and grammar checked for errors.
402
395
  # @option options [Boolean] :draggable
403
- # Specifies whether or not the field is draggable. (true, false, :auto)
396
+ # Specifies whether or not the field is draggable. (true, false, :auto).
404
397
  # @option options [String] :pattern
405
398
  # Specifies the regular expression pattern that the field's value is checked against.
406
399
  # @option options [Symbol] :autocomplete
407
- # Specifies whether or not the field should have autocomplete enabled. (:on, :off)
400
+ # Specifies whether or not the field should have autocomplete enabled. (:on, :off).
408
401
  # @option options [Boolean] :autofocus
409
402
  # Specifies whether or not the field should automatically get focus when the page loads.
410
403
  # @option options [Boolean] :required
@@ -415,11 +408,11 @@ module Padrino
415
408
  # Specifies whether or not the field is disabled.
416
409
  #
417
410
  # @return [String]
418
- # Generated HTML with specified +options+
411
+ # Generated HTML with specified +options+.
419
412
  #
420
413
  # @example
421
- # number_field_tag :quanity, :class => 'numeric'
422
- # # => <input name="quanity" class="numeric" type="number" />
414
+ # number_field_tag :quantity, :class => 'numeric'
415
+ # # => <input name="quantity" class="numeric" type="number" />
423
416
  #
424
417
  # number_field_tag :zip_code, :pattern => /[0-9]{5}/
425
418
  # # => <input name="zip_code" pattern="[0-9]{5}" type="number" />
@@ -430,13 +423,12 @@ module Padrino
430
423
  # number_field_tag :age, :min => 18, :max => 120, :step => 1
431
424
  # # => <input name="age" min="18" max="120" step="1" type="number" />
432
425
  #
433
- # @api public
434
426
  def number_field_tag(name, options={})
435
427
  input_tag(:number, options.reverse_merge(:name => name))
436
428
  end
437
429
 
438
430
  ##
439
- # Creates a telephone field input with the given name and options
431
+ # Creates a telephone field input with the given name and options.
440
432
  #
441
433
  # @macro text_field
442
434
  #
@@ -452,14 +444,13 @@ module Padrino
452
444
  # # => <input name="work_phone" tabindex="2" type="tel" />
453
445
  # # => <input name="home_phone" tabindex="3" type="tel" />
454
446
  #
455
- # @api public
456
447
  def telephone_field_tag(name, options={})
457
448
  input_tag(:tel, options.reverse_merge(:name => name))
458
449
  end
459
450
  alias_method :phone_field_tag, :telephone_field_tag
460
451
 
461
452
  ##
462
- # Creates an email field input with the given name and options
453
+ # Creates an email field input with the given name and options.
463
454
  #
464
455
  # @macro text_field
465
456
  #
@@ -470,13 +461,12 @@ module Padrino
470
461
  # email_field_tag :email, :value => 'padrinorb@gmail.com', :readonly => true
471
462
  # # => <input name="email" value="padrinorb@gmail.com" readonly type="email" />
472
463
  #
473
- # @api public
474
464
  def email_field_tag(name, options={})
475
465
  input_tag(:email, options.reverse_merge(:name => name))
476
466
  end
477
467
 
478
468
  ##
479
- # Creates a search field input with the given name and options
469
+ # Creates a search field input with the given name and options.
480
470
  #
481
471
  # @macro text_field
482
472
  #
@@ -493,13 +483,12 @@ module Padrino
493
483
  # search_field_tag :search, :autofocus => true
494
484
  # # => <input name="search" autofocus type="search" />
495
485
  #
496
- # @api public
497
486
  def search_field_tag(name, options={})
498
487
  input_tag(:search, options.reverse_merge(:name => name))
499
488
  end
500
489
 
501
490
  ##
502
- # Creates a url field input with the given name and options
491
+ # Creates a URL field input with the given name and options.
503
492
  #
504
493
  # @macro text_field
505
494
  #
@@ -510,43 +499,34 @@ module Padrino
510
499
  # url_field_tag :home_page, :class => 'string url'
511
500
  # <input name="home_page" class="string url", type="url" />
512
501
  #
513
- # @api public
514
502
  def url_field_tag(name, options={})
515
503
  input_tag(:url, options.reverse_merge(:name => name))
516
504
  end
517
505
 
518
506
  ##
519
- # Constructs a hidden field input from the given options
520
- #
521
- # @macro text_field
507
+ # Constructs a hidden field input from the given options.
522
508
  #
523
509
  # @example
524
510
  # hidden_field_tag :session_key, :value => "__secret__"
525
511
  #
526
- # @api public
527
512
  def hidden_field_tag(name, options={})
528
513
  options.reverse_merge!(:name => name)
529
514
  input_tag(:hidden, options)
530
515
  end
531
516
 
532
517
  ##
533
- # Constructs a text area input from the given options
534
- #
535
- # @macro text_field
518
+ # Constructs a text area input from the given options.
536
519
  #
537
520
  # @example
538
521
  # text_area_tag :username, :class => 'long', :value => "Demo?"
539
522
  #
540
- # @api public
541
523
  def text_area_tag(name, options={})
542
524
  options.reverse_merge!(:name => name, :rows => "", :cols => "")
543
525
  content_tag(:textarea, options.delete(:value).to_s, options)
544
526
  end
545
527
 
546
528
  ##
547
- # Constructs a password field input from the given options
548
- #
549
- # @macro text_field
529
+ # Constructs a password field input from the given options.
550
530
  #
551
531
  # @example
552
532
  # password_field_tag :password, :class => 'long'
@@ -558,37 +538,29 @@ module Padrino
558
538
  end
559
539
 
560
540
  ##
561
- # Constructs a check_box from the given options
562
- #
563
- # @macro text_field
541
+ # Constructs a check_box from the given options.
564
542
  #
565
543
  # @example
566
544
  # check_box_tag :remember_me, :value => 'Yes'
567
545
  #
568
- # @api public
569
546
  def check_box_tag(name, options={})
570
547
  options.reverse_merge!(:name => name, :value => '1')
571
548
  input_tag(:checkbox, options)
572
549
  end
573
550
 
574
551
  ##
575
- # Constructs a radio_button from the given options
576
- #
577
- # @macro text_field
552
+ # Constructs a radio_button from the given options.
578
553
  #
579
554
  # @example
580
555
  # radio_button_tag :remember_me, :value => 'true'
581
556
  #
582
- # @api public
583
557
  def radio_button_tag(name, options={})
584
558
  options.reverse_merge!(:name => name)
585
559
  input_tag(:radio, options)
586
560
  end
587
561
 
588
562
  ##
589
- # Constructs a file field input from the given options
590
- #
591
- # @macro text_field
563
+ # Constructs a file field input from the given options.
592
564
  #
593
565
  # @example
594
566
  # file_field_tag :photo, :class => 'long'
@@ -601,7 +573,7 @@ module Padrino
601
573
  end
602
574
 
603
575
  ##
604
- # Constructs a select from the given options
576
+ # Constructs a select from the given options.
605
577
  #
606
578
  # @example
607
579
  # options = [['caption', 'value'], ['Green', 'green1'], ['Blue', 'blue1'], ['Black', "black1"]]
@@ -638,9 +610,8 @@ module Padrino
638
610
  # @option options [Boolean] :multiple (false)
639
611
  # Allow multiple options to be selected at once.
640
612
  #
641
- # @return [String] The html input field based on the +options+ specified
613
+ # @return [String] The HTML input field based on the +options+ specified.
642
614
  #
643
- # @api public
644
615
  def select_tag(name, options={})
645
616
  options.reverse_merge!(:name => name)
646
617
  collection, fields = options.delete(:collection), options.delete(:fields)
@@ -657,7 +628,7 @@ module Padrino
657
628
  end
658
629
 
659
630
  ##
660
- # Constructs a button input from the given options
631
+ # Constructs a button input from the given options.
661
632
  #
662
633
  # @param [String] caption
663
634
  # The caption for the button.
@@ -669,14 +640,13 @@ module Padrino
669
640
  # @example
670
641
  # button_tag "Cancel", :class => 'clear'
671
642
  #
672
- # @api public
673
643
  def button_tag(caption, options = {})
674
644
  options.reverse_merge!(:value => caption)
675
645
  input_tag(:button, options)
676
646
  end
677
647
 
678
648
  ##
679
- # Constructs a submit button from the given options
649
+ # Constructs a submit button from the given options.
680
650
  #
681
651
  # @param [String] caption (defaults to: +Submit+)
682
652
  # The caption for the submit button.
@@ -689,7 +659,6 @@ module Padrino
689
659
  # submit_tag "Create", :class => 'success'
690
660
  # submit_tag :class => 'btn'
691
661
  #
692
- # @api public
693
662
  def submit_tag(*args)
694
663
  options = args[-1].is_a?(Hash) ? args.pop : {}
695
664
  caption = args.length >= 1 ? args.shift : "Submit"
@@ -697,7 +666,8 @@ module Padrino
697
666
  input_tag(:submit, options)
698
667
  end
699
668
 
700
- # Constructs a submit button from the given options
669
+ ##
670
+ # Constructs a submit button from the given options.
701
671
  #
702
672
  # @param [String] source
703
673
  # The source image path for the button.
@@ -709,12 +679,12 @@ module Padrino
709
679
  # @example
710
680
  # submit_tag "Create", :class => 'success'
711
681
  #
712
- # @api public
713
682
  def image_submit_tag(source, options={})
714
683
  options.reverse_merge!(:src => image_path(source))
715
684
  input_tag(:image, options)
716
685
  end
717
686
 
687
+ ##
718
688
  # Constructs a hidden field containing a CSRF token.
719
689
  #
720
690
  # @param [String] token
@@ -725,17 +695,28 @@ module Padrino
725
695
  # @example
726
696
  # csrf_token_field
727
697
  #
728
- # @api public
729
698
  def csrf_token_field(token = nil)
730
- if defined? session
731
- token ||= (session[:csrf] ||= SecureRandom.hex(32))
732
- end
699
+ hidden_field_tag csrf_param, :value => csrf_token
700
+ end
733
701
 
734
- hidden_field_tag :authenticity_token, :value => token
702
+ ##
703
+ # Constructs meta tags `csrf-param` and `csrf-token` with the name of the
704
+ # cross-site request forgery protection parameter and token, respectively.
705
+ #
706
+ # @return [String] The meta tags with the CSRF token and the param your app expects it in.
707
+ #
708
+ # @example
709
+ # csrf_meta_tags
710
+ #
711
+ def csrf_meta_tags
712
+ if is_protected_from_csrf?
713
+ meta_tag(csrf_param, :name => 'csrf-param') <<
714
+ meta_tag(csrf_token, :name => 'csrf-token')
715
+ end
735
716
  end
736
717
 
737
718
  ##
738
- # Creates a form containing a single button that submits to the url.
719
+ # Creates a form containing a single button that submits to the URL.
739
720
  #
740
721
  # @overload button_to(name, url, options={})
741
722
  # @param [String] caption The text caption.
@@ -752,6 +733,8 @@ module Padrino
752
733
  # Instructs ujs handler to handle the submit as ajax.
753
734
  # @option options [Symbol] :method
754
735
  # Instructs ujs handler to use different http method (i.e :post, :delete).
736
+ # @option options [Hash] :submit_options
737
+ # Hash of any options, that you want to pass to submit_tag (i.e :id, :class)
755
738
  #
756
739
  # @return [String] Form and button html with specified +options+.
757
740
  #
@@ -763,22 +746,22 @@ module Padrino
763
746
  # # <input type="submit" value="Delete" />
764
747
  # # </form>
765
748
  #
766
- # @api public
767
749
  def button_to(*args, &block)
768
750
  name, url = args[0], args[1]
769
751
  options = args.extract_options!
770
752
  options['data-remote'] = 'true' if options.delete(:remote)
753
+ submit_options = options.delete(:submit_options) || {}
771
754
  if block_given?
772
755
  form_tag(url, options, &block)
773
756
  else
774
757
  form_tag(url, options.merge!(:not_concat => true)) do
775
- submit_tag(name)
758
+ submit_tag(name, submit_options)
776
759
  end
777
760
  end
778
761
  end
779
762
 
780
763
  ##
781
- # Constructs a range tag from the given options
764
+ # Constructs a range tag from the given options.
782
765
  #
783
766
  # @example
784
767
  # range_field_tag('ranger_with_min_max', :min => 1, :max => 50)
@@ -789,14 +772,13 @@ module Padrino
789
772
  # @param [Hash] options
790
773
  # The html options for the range field.
791
774
  # @option options [Integer] :min
792
- # The min range of the range field
775
+ # The min range of the range field.
793
776
  # @option options [Integer] :max
794
- # The max range of the range field
777
+ # The max range of the range field.
795
778
  # @option options [range] :range
796
- # The range, in lieu of :min and :max. See examples for details
779
+ # The range, in lieu of :min and :max. See examples for details.
797
780
  # @return [String] The html range field
798
781
  #
799
- # @api public
800
782
  def range_field_tag(name, options = {})
801
783
  options.reverse_merge!(:name => name)
802
784
  if range = options.delete(:range)
@@ -807,116 +789,131 @@ module Padrino
807
789
 
808
790
  protected
809
791
 
810
- ##
811
- # Returns an array of option items for a select field based on the given collection
812
- # fields is an array containing the fields to display from each item in the collection
813
- #
814
- def options_from_collection(collection, fields)
815
- collection.map { |item| [ item.send(fields.first), item.send(fields.last) ] }
816
- end
792
+ ##
793
+ # Returns an array of option items for a select field based on the given collection.
794
+ #
795
+ # @param [Array] fields
796
+ # fields is an array containing the fields to display from each item in the collection.
797
+ #
798
+ def options_from_collection(collection, fields)
799
+ collection.map { |item| [ item.send(fields.first), item.send(fields.last) ] }
800
+ end
817
801
 
818
- #
819
- # Returns the options tags for a select based on the given option items
820
- #
821
- def options_for_select(option_items, selected_value=nil)
822
- return [] if option_items.blank?
823
- option_items.map do |caption, value, disabled|
824
- value ||= caption
825
- disabled ||= false
826
- content_tag(:option, caption, :value => value, :selected => option_is_selected?(value, caption, selected_value), :disabled => disabled)
827
- end
802
+ ##
803
+ # Returns the options tags for a select based on the given option items.
804
+ #
805
+ def options_for_select(option_items, selected_value=nil)
806
+ return [] if option_items.blank?
807
+ option_items.map do |caption, value, disabled|
808
+ value ||= caption
809
+ disabled ||= false
810
+ content_tag(:option, caption, :value => value, :selected => option_is_selected?(value, caption, selected_value), :disabled => disabled)
828
811
  end
812
+ end
829
813
 
830
- #
831
- # Returns the optgroups with options tags for a select based on the given :grouped_options items
832
- #
833
- def grouped_options_for_select(collection, selected=nil, prompt=false)
834
- if collection.is_a?(Hash)
835
- collection.map do |key, value|
836
- # Hash format:
837
- # {:first => [1,2,3], :second => [4,5,6]}
838
- # or:
839
- # {:first => [[1,2,3], {:disabled => true}], :second => [4,5,6]}
840
- attributes_hash = value.last.is_a?(Hash) ? value.pop : nil
841
- disabled ||= attributes_hash && attributes_hash.include?(:disabled) ? attributes_hash[:disabled] : false
842
- content_tag :optgroup, options_for_select(value, selected), :label => key, :disabled => disabled
843
- end
844
- elsif collection.is_a?(Array)
845
- # Array format:
846
- # ["Option Label", [:option1, :option2, ...]]
814
+ ##
815
+ # Returns the optgroups with options tags for a select based on the given :grouped_options items.
816
+ #
817
+ def grouped_options_for_select(collection, selected=nil, prompt=false)
818
+ if collection.is_a?(Hash)
819
+ collection.map do |key, value|
820
+ # Hash format:
821
+ # {:first => [1,2,3], :second => [4,5,6]}
847
822
  # or:
848
- # ["Option Label", [:option1, :option2, ...], true]
849
- # the last item tells if it is disabled or not. This is keeps it backwards compatible.
850
- collection.map do |optgroup|
851
- disabled ||= optgroup.count > 2 ? optgroup.pop : false
852
- content_tag :optgroup, options_for_select(optgroup.last, selected), :label => optgroup.first, :disabled => disabled
853
- end
823
+ # {:first => [[1,2,3], {:disabled => true}], :second => [4,5,6]}
824
+ attributes_hash = value.last.is_a?(Hash) ? value.pop : nil
825
+ disabled ||= attributes_hash && attributes_hash.include?(:disabled) ? attributes_hash[:disabled] : false
826
+ content_tag :optgroup, options_for_select(value, selected), :label => key, :disabled => disabled
854
827
  end
855
- end
856
-
857
- #
858
- # Returns the blank option serving as a prompt if passed
859
- #
860
- def blank_option(prompt)
861
- return unless prompt
862
- case prompt
863
- when String then content_tag(:option, prompt, :value => '')
864
- when Array then content_tag(:option, prompt.first, :value => prompt.last)
865
- else content_tag(:option, '', :value => '')
828
+ elsif collection.is_a?(Array)
829
+ # Array format:
830
+ # ["Option Label", [:option1, :option2, ...]]
831
+ # or:
832
+ # ["Option Label", [:option1, :option2, ...], true]
833
+ # the last item tells if it is disabled or not. This is keeps it backwards compatible.
834
+ collection.map do |optgroup|
835
+ disabled ||= optgroup.count > 2 ? optgroup.pop : false
836
+ content_tag :optgroup, options_for_select(optgroup.last, selected), :label => optgroup.first, :disabled => disabled
866
837
  end
867
838
  end
839
+ end
868
840
 
869
- private
870
- ##
871
- # Returns the FormBuilder class to use based on all available setting sources
872
- # If explicitly defined, returns that, otherwise returns defaults.
873
- #
874
- # @example
875
- # configured_form_builder_class(nil) => StandardFormBuilder
876
- #
877
- # @api private
878
- def configured_form_builder_class(explicit_builder=nil)
879
- default_builder = self.respond_to?(:settings) && self.settings.default_builder
880
- configured_builder = explicit_builder || default_builder || 'StandardFormBuilder'
881
- configured_builder = "Padrino::Helpers::FormBuilder::#{configured_builder}".constantize if configured_builder.is_a?(String)
882
- configured_builder
841
+ ##
842
+ # Returns the blank option serving as a prompt if passed.
843
+ #
844
+ def blank_option(prompt)
845
+ return unless prompt
846
+ case prompt
847
+ when String then content_tag(:option, prompt, :value => '')
848
+ when Array then content_tag(:option, prompt.first, :value => prompt.last)
849
+ else content_tag(:option, '', :value => '')
883
850
  end
851
+ end
884
852
 
885
- ##
886
- # Returns an initialized builder instance for the given object and settings
887
- #
888
- # @example
889
- # builder_instance(@account, :nested => { ... }) => <FormBuilder>
890
- #
891
- # @api private
892
- def builder_instance(object, settings={})
893
- builder_class = configured_form_builder_class(settings.delete(:builder))
894
- builder_class.new(self, object, settings)
895
- end
853
+ ##
854
+ # Returns whether the application is being protected from CSRF. Defaults to true.
855
+ #
856
+ def is_protected_from_csrf?
857
+ defined?(settings) ? settings.protect_from_csrf : true
858
+ end
896
859
 
897
- ##
898
- # Returns whether the option should be selected or not
899
- #
900
- # @example
901
- # option_is_selected?("red", "Red", ["red", "blue"]) => true
902
- # option_is_selected?("red", "Red", ["green", "blue"]) => false
903
- #
904
- # @api private
905
- def option_is_selected?(value, caption, selected_values)
906
- Array(selected_values).any? do |selected|
907
- [value.to_s, caption.to_s].include?(selected.to_s)
908
- end
909
- end
860
+ ##
861
+ # Returns the current CSRF token (based on the session). If it doesn't exist,
862
+ # it will create one and assign it to the session's `csrf` key.
863
+ #
864
+ def csrf_token
865
+ session[:csrf] ||= SecureRandom.hex(32) if defined?(session)
866
+ end
867
+
868
+ ##
869
+ # Returns the param/field name in which your CSRF token should be expected by your
870
+ # controllers. Defaults to `authenticity_token`.
871
+ #
872
+ # Set this in your application with `set :csrf_param, :something_else`.
873
+ #
874
+ def csrf_param
875
+ defined?(settings) && settings.respond_to?(:csrf_param) ?
876
+ settings.csrf_param : :authenticity_token
877
+ end
878
+
879
+ private
880
+ ##
881
+ # Returns the FormBuilder class to use based on all available setting sources
882
+ # If explicitly defined, returns that, otherwise returns defaults.
883
+ #
884
+ # @example
885
+ # configured_form_builder_class(nil) => StandardFormBuilder
886
+ #
887
+ def configured_form_builder_class(explicit_builder=nil)
888
+ default_builder = self.respond_to?(:settings) && self.settings.default_builder
889
+ configured_builder = explicit_builder || default_builder || 'StandardFormBuilder'
890
+ configured_builder = "Padrino::Helpers::FormBuilder::#{configured_builder}".constantize if configured_builder.is_a?(String)
891
+ configured_builder
892
+ end
893
+
894
+ ##
895
+ # Returns an initialized builder instance for the given object and settings.
896
+ #
897
+ # @example
898
+ # builder_instance(@account, :nested => { ... }) => <FormBuilder>
899
+ #
900
+ def builder_instance(object, settings={})
901
+ builder_class = configured_form_builder_class(settings.delete(:builder))
902
+ builder_class.new(self, object, settings)
903
+ end
910
904
 
911
- ##
912
- # Returns whether the application is being protected from csrf
913
- #
914
- def is_protected_from_csrf?
915
- return true unless defined? app
916
- return true unless app.respond_to?(:protect_from_csrf)
917
- return true if app.protect_from_csrf == nil
918
- app.protect_from_csrf
905
+ ##
906
+ # Returns whether the option should be selected or not.
907
+ #
908
+ # @example
909
+ # option_is_selected?("red", "Red", ["red", "blue"]) => true
910
+ # option_is_selected?("red", "Red", ["green", "blue"]) => false
911
+ #
912
+ def option_is_selected?(value, caption, selected_values)
913
+ Array(selected_values).any? do |selected|
914
+ [value.to_s, caption.to_s].include?(selected.to_s)
919
915
  end
920
- end # FormHelpers
921
- end # Helpers
922
- end # Padrino
916
+ end
917
+ end
918
+ end
919
+ end