padrino-helpers-cj 0.12.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +21 -0
- data/.yardopts +1 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +239 -0
- data/Rakefile +5 -0
- data/lib/padrino-helpers.rb +62 -0
- data/lib/padrino-helpers/asset_tag_helpers.rb +390 -0
- data/lib/padrino-helpers/form_builder/abstract_form_builder.rb +283 -0
- data/lib/padrino-helpers/form_builder/deprecated_builder_methods.rb +92 -0
- data/lib/padrino-helpers/form_builder/standard_form_builder.rb +40 -0
- data/lib/padrino-helpers/form_helpers.rb +633 -0
- data/lib/padrino-helpers/form_helpers/errors.rb +138 -0
- data/lib/padrino-helpers/form_helpers/options.rb +97 -0
- data/lib/padrino-helpers/form_helpers/security.rb +70 -0
- data/lib/padrino-helpers/format_helpers.rb +372 -0
- data/lib/padrino-helpers/locale/cs.yml +103 -0
- data/lib/padrino-helpers/locale/da.yml +91 -0
- data/lib/padrino-helpers/locale/de.yml +81 -0
- data/lib/padrino-helpers/locale/en.yml +103 -0
- data/lib/padrino-helpers/locale/es.yml +103 -0
- data/lib/padrino-helpers/locale/fr.yml +79 -0
- data/lib/padrino-helpers/locale/hu.yml +103 -0
- data/lib/padrino-helpers/locale/it.yml +89 -0
- data/lib/padrino-helpers/locale/ja.yml +103 -0
- data/lib/padrino-helpers/locale/lv.yml +103 -0
- data/lib/padrino-helpers/locale/nl.yml +82 -0
- data/lib/padrino-helpers/locale/no.yml +91 -0
- data/lib/padrino-helpers/locale/pl.yml +95 -0
- data/lib/padrino-helpers/locale/pt_br.yml +103 -0
- data/lib/padrino-helpers/locale/ro.yml +103 -0
- data/lib/padrino-helpers/locale/ru.yml +103 -0
- data/lib/padrino-helpers/locale/sv.yml +103 -0
- data/lib/padrino-helpers/locale/tr.yml +103 -0
- data/lib/padrino-helpers/locale/uk.yml +103 -0
- data/lib/padrino-helpers/locale/zh_cn.yml +103 -0
- data/lib/padrino-helpers/locale/zh_tw.yml +103 -0
- data/lib/padrino-helpers/number_helpers.rb +283 -0
- data/lib/padrino-helpers/output_helpers.rb +226 -0
- data/lib/padrino-helpers/output_helpers/abstract_handler.rb +61 -0
- data/lib/padrino-helpers/output_helpers/erb_handler.rb +27 -0
- data/lib/padrino-helpers/output_helpers/haml_handler.rb +25 -0
- data/lib/padrino-helpers/output_helpers/slim_handler.rb +18 -0
- data/lib/padrino-helpers/render_helpers.rb +63 -0
- data/lib/padrino-helpers/tag_helpers.rb +294 -0
- data/lib/padrino-helpers/translation_helpers.rb +36 -0
- data/lib/padrino/rendering.rb +397 -0
- data/lib/padrino/rendering/erubis_template.rb +66 -0
- data/lib/padrino/rendering/haml_template.rb +26 -0
- data/lib/padrino/rendering/slim_template.rb +20 -0
- data/padrino-helpers.gemspec +29 -0
- data/test/fixtures/apps/.components +6 -0
- data/test/fixtures/apps/.gitignore +7 -0
- data/test/fixtures/apps/render.rb +25 -0
- data/test/fixtures/apps/views/article/comment/show.slim +1 -0
- data/test/fixtures/apps/views/blog/post.erb +1 -0
- data/test/fixtures/apps/views/layouts/specific.erb +1 -0
- data/test/fixtures/apps/views/test/post.erb +1 -0
- data/test/fixtures/layouts/layout.erb +1 -0
- data/test/fixtures/markup_app/app.rb +87 -0
- data/test/fixtures/markup_app/views/button_to.erb +8 -0
- data/test/fixtures/markup_app/views/button_to.haml +5 -0
- data/test/fixtures/markup_app/views/button_to.slim +6 -0
- data/test/fixtures/markup_app/views/capture_concat.erb +14 -0
- data/test/fixtures/markup_app/views/capture_concat.haml +12 -0
- data/test/fixtures/markup_app/views/capture_concat.slim +12 -0
- data/test/fixtures/markup_app/views/content_for.erb +23 -0
- data/test/fixtures/markup_app/views/content_for.haml +19 -0
- data/test/fixtures/markup_app/views/content_for.slim +19 -0
- data/test/fixtures/markup_app/views/content_tag.erb +13 -0
- data/test/fixtures/markup_app/views/content_tag.haml +11 -0
- data/test/fixtures/markup_app/views/content_tag.slim +11 -0
- data/test/fixtures/markup_app/views/current_engine.erb +5 -0
- data/test/fixtures/markup_app/views/current_engine.haml +5 -0
- data/test/fixtures/markup_app/views/current_engine.slim +5 -0
- data/test/fixtures/markup_app/views/fields_for.erb +20 -0
- data/test/fixtures/markup_app/views/fields_for.haml +15 -0
- data/test/fixtures/markup_app/views/fields_for.slim +15 -0
- data/test/fixtures/markup_app/views/form_for.erb +72 -0
- data/test/fixtures/markup_app/views/form_for.haml +59 -0
- data/test/fixtures/markup_app/views/form_for.slim +59 -0
- data/test/fixtures/markup_app/views/form_tag.erb +95 -0
- data/test/fixtures/markup_app/views/form_tag.haml +78 -0
- data/test/fixtures/markup_app/views/form_tag.slim +79 -0
- data/test/fixtures/markup_app/views/link_to.erb +5 -0
- data/test/fixtures/markup_app/views/link_to.haml +4 -0
- data/test/fixtures/markup_app/views/link_to.slim +4 -0
- data/test/fixtures/markup_app/views/mail_to.erb +3 -0
- data/test/fixtures/markup_app/views/mail_to.haml +3 -0
- data/test/fixtures/markup_app/views/mail_to.slim +3 -0
- data/test/fixtures/markup_app/views/meta_tag.erb +3 -0
- data/test/fixtures/markup_app/views/meta_tag.haml +3 -0
- data/test/fixtures/markup_app/views/meta_tag.slim +3 -0
- data/test/fixtures/markup_app/views/partials/_erb.erb +1 -0
- data/test/fixtures/markup_app/views/partials/_haml.haml +1 -0
- data/test/fixtures/markup_app/views/partials/_slim.slim +1 -0
- data/test/fixtures/markup_app/views/simple_partial.erb +1 -0
- data/test/fixtures/markup_app/views/simple_partial.haml +1 -0
- data/test/fixtures/markup_app/views/simple_partial.slim +1 -0
- data/test/fixtures/render_app/app.rb +94 -0
- data/test/fixtures/render_app/views/_deep.erb +3 -0
- data/test/fixtures/render_app/views/_deep.haml +2 -0
- data/test/fixtures/render_app/views/_deep.slim +2 -0
- data/test/fixtures/render_app/views/_partial_block_erb.erb +10 -0
- data/test/fixtures/render_app/views/_partial_block_haml.haml +7 -0
- data/test/fixtures/render_app/views/_partial_block_slim.slim +7 -0
- data/test/fixtures/render_app/views/_unsafe.html.builder +2 -0
- data/test/fixtures/render_app/views/_unsafe_object.html.builder +2 -0
- data/test/fixtures/render_app/views/current_engine.haml +5 -0
- data/test/fixtures/render_app/views/current_engines/_erb.erb +1 -0
- data/test/fixtures/render_app/views/current_engines/_haml.haml +1 -0
- data/test/fixtures/render_app/views/current_engines/_slim.slim +1 -0
- data/test/fixtures/render_app/views/double_capture_erb.erb +3 -0
- data/test/fixtures/render_app/views/double_capture_haml.haml +2 -0
- data/test/fixtures/render_app/views/double_capture_slim.slim +2 -0
- data/test/fixtures/render_app/views/erb/test.erb +1 -0
- data/test/fixtures/render_app/views/explicit_engine.haml +5 -0
- data/test/fixtures/render_app/views/haml/test.haml +1 -0
- data/test/fixtures/render_app/views/render_block_erb.erb +5 -0
- data/test/fixtures/render_app/views/render_block_haml.haml +4 -0
- data/test/fixtures/render_app/views/render_block_slim.slim +4 -0
- data/test/fixtures/render_app/views/ruby_block_capture_erb.erb +1 -0
- data/test/fixtures/render_app/views/ruby_block_capture_haml.haml +1 -0
- data/test/fixtures/render_app/views/ruby_block_capture_slim.slim +1 -0
- data/test/fixtures/render_app/views/template/_user.haml +7 -0
- data/test/fixtures/render_app/views/template/haml_template.haml +1 -0
- data/test/fixtures/render_app/views/template/some_template.haml +2 -0
- data/test/fixtures/render_app/views/wrong_capture_erb.erb +3 -0
- data/test/fixtures/render_app/views/wrong_capture_haml.haml +2 -0
- data/test/fixtures/render_app/views/wrong_capture_slim.slim +2 -0
- data/test/helper.rb +131 -0
- data/test/test_asset_tag_helpers.rb +406 -0
- data/test/test_form_builder.rb +1216 -0
- data/test/test_form_helpers.rb +1056 -0
- data/test/test_format_helpers.rb +251 -0
- data/test/test_helpers.rb +10 -0
- data/test/test_locale.rb +20 -0
- data/test/test_number_helpers.rb +142 -0
- data/test/test_output_helpers.rb +157 -0
- data/test/test_render_helpers.rb +215 -0
- data/test/test_rendering.rb +694 -0
- data/test/test_rendering_extensions.rb +14 -0
- data/test/test_tag_helpers.rb +131 -0
- metadata +241 -0
@@ -0,0 +1,283 @@
|
|
1
|
+
require 'padrino-helpers/form_builder/deprecated_builder_methods'
|
2
|
+
|
3
|
+
module Padrino
|
4
|
+
module Helpers
|
5
|
+
module FormBuilder
|
6
|
+
# Base class for Padrino Form Builder
|
7
|
+
class AbstractFormBuilder
|
8
|
+
attr_accessor :template, :object, :multipart
|
9
|
+
attr_reader :namespace, :is_nested, :parent_form, :nested_index, :attributes_name, :model_name
|
10
|
+
|
11
|
+
include DeprecatedBuilderMethods
|
12
|
+
|
13
|
+
def initialize(template, object, options={})
|
14
|
+
@template = template
|
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
|
27
|
+
end
|
28
|
+
|
29
|
+
def error_messages(*params)
|
30
|
+
@template.error_messages_for object, *params
|
31
|
+
end
|
32
|
+
|
33
|
+
def error_message_on(field, options={})
|
34
|
+
@template.error_message_on object, field, options
|
35
|
+
end
|
36
|
+
|
37
|
+
def label(field, options={}, &block)
|
38
|
+
options[:id] ||= nil
|
39
|
+
options[:caption] ||= I18n.t("#{model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models) + ': '
|
40
|
+
@template.label_tag(field_id(field), default_options(field, options), &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def hidden_field(field, options={})
|
44
|
+
@template.hidden_field_tag field_name(field), default_options(field, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def text_field(field, options={})
|
48
|
+
@template.text_field_tag field_name(field), default_options(field, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
def number_field(field, options={})
|
52
|
+
@template.number_field_tag field_name(field), default_options(field, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def telephone_field(field, options={})
|
56
|
+
@template.telephone_field_tag field_name(field), default_options(field, options)
|
57
|
+
end
|
58
|
+
alias_method :phone_field, :telephone_field
|
59
|
+
|
60
|
+
def email_field(field, options={})
|
61
|
+
@template.email_field_tag field_name(field), default_options(field, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def search_field(field, options={})
|
65
|
+
@template.search_field_tag field_name(field), default_options(field, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def url_field(field, options={})
|
69
|
+
@template.url_field_tag field_name(field), default_options(field, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def text_area(field, options={})
|
73
|
+
@template.text_area_tag field_name(field), default_options(field, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
def password_field(field, options={})
|
77
|
+
@template.password_field_tag field_name(field), default_options(field, options)
|
78
|
+
end
|
79
|
+
|
80
|
+
def select(field, options={})
|
81
|
+
@template.select_tag field_name(field), default_options(field, options)
|
82
|
+
end
|
83
|
+
|
84
|
+
def check_box_group(field, options={})
|
85
|
+
labeled_group(field, options) do |attributes|
|
86
|
+
@template.check_box_tag(field_name(field)+'[]', attributes)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def radio_button_group(field, options={})
|
91
|
+
labeled_group(field, options) do |attributes|
|
92
|
+
@template.radio_button_tag(field_name(field), attributes)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def check_box(field, options={})
|
97
|
+
options = default_options(field, options, :value => '1')
|
98
|
+
options[:checked] = true if is_checked?(field, options)
|
99
|
+
name = field_name(field)
|
100
|
+
html = @template.hidden_field_tag(name, :value => options.delete(:uncheck_value) || '0')
|
101
|
+
html << @template.check_box_tag(name, options)
|
102
|
+
end
|
103
|
+
|
104
|
+
def radio_button(field, options={})
|
105
|
+
options = default_options(field, options)
|
106
|
+
options[:checked] = true if is_checked?(field, options)
|
107
|
+
options[:id] = field_id(field, options[:value])
|
108
|
+
@template.radio_button_tag field_name(field), options
|
109
|
+
end
|
110
|
+
|
111
|
+
def file_field(field, options={})
|
112
|
+
self.multipart = true
|
113
|
+
@template.file_field_tag field_name(field), default_options(field, options).except(:value)
|
114
|
+
end
|
115
|
+
|
116
|
+
def submit(*args)
|
117
|
+
@template.submit_tag *args
|
118
|
+
end
|
119
|
+
|
120
|
+
def image_submit(source, options={})
|
121
|
+
@template.image_submit_tag source, options
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Supports nested fields for a child model within a form.
|
126
|
+
# f.fields_for :addresses
|
127
|
+
# f.fields_for :addresses, address
|
128
|
+
# f.fields_for :addresses, @addresses
|
129
|
+
# f.fields_for :addresses, address, index: i
|
130
|
+
def fields_for(child_association, collection=nil, options={}, &block)
|
131
|
+
default_collection = self.object.send(child_association)
|
132
|
+
collection ||= default_collection
|
133
|
+
include_index = default_collection.respond_to?(:each)
|
134
|
+
|
135
|
+
nested_options = { :parent => self, :association => child_association }
|
136
|
+
Array(collection).each_with_index.inject(ActiveSupport::SafeBuffer.new) do |all,(child_instance,index)|
|
137
|
+
nested_options[:index] = options[:index] || (include_index ? index : nil)
|
138
|
+
all << @template.fields_for(child_instance, { :nested => nested_options, :builder => self.class }, &block) << "\n"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def csrf_token_field
|
143
|
+
@template.csrf_token_field
|
144
|
+
end
|
145
|
+
|
146
|
+
protected
|
147
|
+
|
148
|
+
# Returns the known field types for a Formbuilder.
|
149
|
+
def self.field_types
|
150
|
+
[:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Returns the name for the given field.
|
155
|
+
# field_name(:username) => "user[username]"
|
156
|
+
# field_name(:number) => "user[telephone_attributes][number]"
|
157
|
+
# field_name(:street) => "user[addresses_attributes][0][street]"
|
158
|
+
def field_name(field=nil)
|
159
|
+
result = field_name_fragment
|
160
|
+
result << "[#{field}]" unless field.blank?
|
161
|
+
result
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Returns the id for the given field.
|
166
|
+
# field_id(:username) => "user_username"
|
167
|
+
# field_id(:gender, :male) => "user_gender_male"
|
168
|
+
# field_name(:number) => "user_telephone_attributes_number"
|
169
|
+
# field_name(:street) => "user_addresses_attributes_0_street"
|
170
|
+
def field_id(field=nil, value=nil)
|
171
|
+
result = (namespace && !is_nested) ? "#{namespace}_" : ''
|
172
|
+
result << field_id_fragment
|
173
|
+
result << "_#{field}" unless field.blank?
|
174
|
+
result << "_#{value}" unless value.blank?
|
175
|
+
result
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Returns the child object if it exists.
|
180
|
+
#
|
181
|
+
def nested_object_id
|
182
|
+
is_nested && object.respond_to?(:new_record?) && !object.new_record? && object.id
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Returns the value for the object's field.
|
187
|
+
#
|
188
|
+
def field_value(field)
|
189
|
+
@object.respond_to?(field) ? @object.send(field) : ''
|
190
|
+
end
|
191
|
+
|
192
|
+
##
|
193
|
+
# Returns a record from template instance or create a record of specified class.
|
194
|
+
#
|
195
|
+
def build_object(symbol)
|
196
|
+
@template.instance_variable_get("@#{symbol}") || symbol.to_s.camelize.constantize.new
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# Builds a group of labels for radios or checkboxes.
|
201
|
+
#
|
202
|
+
def labeled_group(field, options={})
|
203
|
+
options = { :id => field_id(field), :selected => field_value(field) }.update(options)
|
204
|
+
options.update(error_class(field)){ |_,*values| values.compact.join(' ') }
|
205
|
+
selected_values = resolve_checked_values(field, options)
|
206
|
+
variants_for_group(options).inject(ActiveSupport::SafeBuffer.new) do |html, (caption,value)|
|
207
|
+
variant_id = "#{options[:id]}_#{value}"
|
208
|
+
attributes = { :value => value, :id => variant_id, :checked => selected_values.include?(value) }
|
209
|
+
caption = yield(attributes) << ' ' << caption
|
210
|
+
html << @template.label_tag("#{field_name(field)}[]", :for => variant_id, :caption => caption)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
def is_checked?(field, options)
|
217
|
+
!options.has_key?(:checked) && [options[:value].to_s, 'true'].include?(field_value(field).to_s)
|
218
|
+
end
|
219
|
+
|
220
|
+
def variants_for_group(options)
|
221
|
+
if variants = options[:options]
|
222
|
+
variants.map{ |caption, value| [caption.to_s, (value||caption).to_s] }
|
223
|
+
elsif collection = options[:collection]
|
224
|
+
collection.map{ |variant| field_values(variant, options) }
|
225
|
+
else
|
226
|
+
[]
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def resolve_checked_values(field, options)
|
231
|
+
selected_values = Array(options[:selected] || field_value(field))
|
232
|
+
if options[:collection]
|
233
|
+
_, id_method = *field_methods(options)
|
234
|
+
selected_values.map do |value|
|
235
|
+
(value.respond_to?(id_method) ? value.send(id_method) : value).to_s
|
236
|
+
end
|
237
|
+
else
|
238
|
+
selected_values
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def field_methods(options)
|
243
|
+
options[:fields] || [:name, :id]
|
244
|
+
end
|
245
|
+
|
246
|
+
def field_values(object, options)
|
247
|
+
field_methods(options).map{ |field| object.send(field).to_s }
|
248
|
+
end
|
249
|
+
|
250
|
+
def field_name_fragment
|
251
|
+
if is_nested
|
252
|
+
fragment = parent_form.field_name.dup << "[#{attributes_name}"
|
253
|
+
fragment << "][#{nested_index}" if nested_index
|
254
|
+
fragment << "]"
|
255
|
+
else
|
256
|
+
"#{model_name}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def field_id_fragment
|
261
|
+
if is_nested
|
262
|
+
fragment = parent_form.field_id.dup << "_#{attributes_name}"
|
263
|
+
fragment << "_#{nested_index}" if nested_index
|
264
|
+
fragment
|
265
|
+
else
|
266
|
+
"#{model_name}"
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def error_class(field)
|
271
|
+
error = @object.errors[field] if @object.respond_to?(:errors)
|
272
|
+
error.blank? ? {} : { :class => 'invalid' }
|
273
|
+
end
|
274
|
+
|
275
|
+
def default_options(field, options, defaults={})
|
276
|
+
{ :value => field_value(field),
|
277
|
+
:id => field_id(field)
|
278
|
+
}.update(defaults).update(options).update(error_class(field)){ |_,*values| values.compact.join(' ') }
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Padrino
|
2
|
+
module Helpers
|
3
|
+
module FormBuilder
|
4
|
+
module DeprecatedBuilderMethods
|
5
|
+
##
|
6
|
+
# Returns true if the value matches the value in the field.
|
7
|
+
# field_has_value?(:gender, 'male')
|
8
|
+
def values_matches_field?(field, value)
|
9
|
+
logger.warn "##{__method__} is deprecated"
|
10
|
+
value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Add a :invalid css class to the field if it contain an error.
|
15
|
+
#
|
16
|
+
def field_error(field, options)
|
17
|
+
logger.warn "##{__method__} is deprecated"
|
18
|
+
error = @object.errors[field] rescue nil
|
19
|
+
error.blank? ? options[:class] : [options[:class], :invalid].flatten.compact.join(" ")
|
20
|
+
end
|
21
|
+
|
22
|
+
def nested_form?
|
23
|
+
logger.warn "##{__method__} is deprecated"
|
24
|
+
@options[:nested] && @options[:nested][:parent] && @options[:nested][:parent].respond_to?(:object)
|
25
|
+
is_nested && object.respond_to?(:new_record?) && !object.new_record? && object.id
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Returns a new record of the type specified in the object
|
30
|
+
#
|
31
|
+
def build_object(object_or_symbol)
|
32
|
+
logger.warn "##{__method__} is deprecated"
|
33
|
+
object_or_symbol.is_a?(Symbol) ? @template.instance_variable_get("@#{object_or_symbol}") || object_class(object_or_symbol).new : object_or
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Returns the object's models name.
|
38
|
+
#
|
39
|
+
def object_model_name(explicit_object=object)
|
40
|
+
logger.warn "##{__method__} is deprecated"
|
41
|
+
return @options[:as] if root_form? && @options[:as].is_a?(Symbol)
|
42
|
+
explicit_object.is_a?(Symbol) ? explicit_object : explicit_object.class.to_s.underscore.gsub(/\//, '_')
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Returns the class type for the given object.
|
47
|
+
#
|
48
|
+
def object_class(explicit_object)
|
49
|
+
logger.warn "##{__method__} is deprecated"
|
50
|
+
explicit_object.is_a?(Symbol) ? explicit_object.to_s.camelize.constantize : explicit_object.class
|
51
|
+
@object.respond_to?(field) ? @object.send(field) : ''
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Returns true if this form is the top-level (not nested).
|
56
|
+
# Returns a record from template instance or create a record of specified class.
|
57
|
+
#
|
58
|
+
def root_form?
|
59
|
+
logger.warn "##{__method__} is deprecated"
|
60
|
+
!nested_form?
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_object(symbol)
|
64
|
+
logger.warn "##{__method__} is deprecated"
|
65
|
+
@template.instance_variable_get("@#{symbol}") || symbol.to_s.camelize.constantize.new
|
66
|
+
end
|
67
|
+
|
68
|
+
def field_result
|
69
|
+
logger.warn "##{__method__} is deprecated"
|
70
|
+
result = []
|
71
|
+
result << object_model_name if root_form?
|
72
|
+
result
|
73
|
+
end
|
74
|
+
|
75
|
+
def merge_default_options!(field, options)
|
76
|
+
logger.warn "##{__method__} is deprecated"
|
77
|
+
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
78
|
+
options.merge!(:class => field_error(field, options))
|
79
|
+
end
|
80
|
+
|
81
|
+
def result_options
|
82
|
+
logger.warn "##{__method__} is deprecated"
|
83
|
+
{
|
84
|
+
:parent_form => @options[:nested][:parent],
|
85
|
+
:nested_index => @options[:nested][:index],
|
86
|
+
:attributes_name => "#{@options[:nested][:association]}_attributes"
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/abstract_form_builder') unless defined?(AbstractFormBuilder)
|
2
|
+
|
3
|
+
module Padrino
|
4
|
+
module Helpers
|
5
|
+
module FormBuilder
|
6
|
+
class StandardFormBuilder < AbstractFormBuilder
|
7
|
+
##
|
8
|
+
# StandardFormBuilder
|
9
|
+
#
|
10
|
+
# text_field_block(:username, { :class => 'long' }, { :class => 'wide-label' })
|
11
|
+
# text_area_block(:summary, { :class => 'long' }, { :class => 'wide-label' })
|
12
|
+
# password_field_block(:password, { :class => 'long' }, { :class => 'wide-label' })
|
13
|
+
# file_field_block(:photo, { :class => 'long' }, { :class => 'wide-label' })
|
14
|
+
# check_box_block(:remember_me, { :class => 'long' }, { :class => 'wide-label' })
|
15
|
+
# select_block(:color, :options => ['green', 'black'])
|
16
|
+
#
|
17
|
+
(self.field_types - [ :hidden_field, :radio_button ]).each do |field_type|
|
18
|
+
class_eval <<-EOF
|
19
|
+
def #{field_type}_block(field, options={}, label_options={})
|
20
|
+
label_options.reverse_merge!(:caption => options.delete(:caption)) if options[:caption]
|
21
|
+
field_html = label(field, label_options)
|
22
|
+
field_html << #{field_type}(field, options)
|
23
|
+
@template.content_tag(:p, field_html)
|
24
|
+
end
|
25
|
+
EOF
|
26
|
+
end
|
27
|
+
|
28
|
+
def submit_block(caption, options={})
|
29
|
+
submit_html = self.submit(caption, options)
|
30
|
+
@template.content_tag(:p, submit_html)
|
31
|
+
end
|
32
|
+
|
33
|
+
def image_submit_block(source, options={})
|
34
|
+
submit_html = self.image_submit(source, options)
|
35
|
+
@template.content_tag(:p, submit_html)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,633 @@
|
|
1
|
+
require 'padrino-helpers/form_helpers/errors'
|
2
|
+
require 'padrino-helpers/form_helpers/options'
|
3
|
+
require 'padrino-helpers/form_helpers/security'
|
4
|
+
|
5
|
+
module Padrino
|
6
|
+
module Helpers
|
7
|
+
##
|
8
|
+
# Helpers related to producing form related tags and inputs into templates.
|
9
|
+
#
|
10
|
+
module FormHelpers
|
11
|
+
def self.included(base)
|
12
|
+
base.send(:include, FormHelpers::Errors)
|
13
|
+
base.send(:include, FormHelpers::Options)
|
14
|
+
base.send(:include, FormHelpers::Security)
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Constructs a form for object using given or default form_builder.
|
19
|
+
#
|
20
|
+
# @param [Object] object
|
21
|
+
# The object for which the form is being built.
|
22
|
+
# @param [String] URL
|
23
|
+
# The url this form will submit to.
|
24
|
+
# @param [Hash] options
|
25
|
+
# The settings associated with this form.
|
26
|
+
# Accepts a :namespace option that will be prepended to the id attributes of the form's elements.
|
27
|
+
# Also accepts HTML options.
|
28
|
+
# @option settings [String] :builder ("StandardFormBuilder")
|
29
|
+
# The FormBuilder class to use such as StandardFormBuilder.
|
30
|
+
# @option settings [Symbol] :as
|
31
|
+
# Sets custom form object name.
|
32
|
+
# @param [Proc] block
|
33
|
+
# The fields and content inside this form.
|
34
|
+
#
|
35
|
+
# @yield [AbstractFormBuilder] The form builder used to compose fields.
|
36
|
+
#
|
37
|
+
# @return [String] The html object-backed form with the specified options and input fields.
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# form_for :user, '/register' do |f| ... end
|
41
|
+
# form_for @user, '/register', :id => 'register' do |f| ... end
|
42
|
+
# form_for @user, '/register', :as => :customer do |f| ... end
|
43
|
+
#
|
44
|
+
def form_for(object, url, options={}, &block)
|
45
|
+
instance = builder_instance(object, options)
|
46
|
+
# this can erect instance.multipart flag if the block calls instance.file_field
|
47
|
+
html = capture_html(instance, &block)
|
48
|
+
options = { :multipart => instance.multipart }.update(options.except(:namespace, :as))
|
49
|
+
form_tag(url, options) { html }
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Constructs form fields for an object using given or default form_builder.
|
54
|
+
# Used within an existing form to allow alternate objects within one form.
|
55
|
+
#
|
56
|
+
# @param [Object] object
|
57
|
+
# The object for which the fields are being built.
|
58
|
+
# @param [Hash] options
|
59
|
+
# The settings associated with these fields. Accepts HTML options.
|
60
|
+
# @param [Proc] block
|
61
|
+
# The content inside this set of fields.
|
62
|
+
#
|
63
|
+
# @return [String] The html fields with the specified options.
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# fields_for @user.assignment do |assignment| ... end
|
67
|
+
# fields_for :assignment do |assigment| ... end
|
68
|
+
#
|
69
|
+
def fields_for(object, options={}, &block)
|
70
|
+
instance = builder_instance(object, options)
|
71
|
+
fields_html = capture_html(instance, &block)
|
72
|
+
fields_html << instance.hidden_field(:id) if instance.send(:nested_object_id)
|
73
|
+
concat_content fields_html
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Constructs a form without object based on options.
|
78
|
+
#
|
79
|
+
# @param [String] url
|
80
|
+
# The URL this form will submit to.
|
81
|
+
# @param [Hash] options
|
82
|
+
# The html options associated with this form.
|
83
|
+
# @param [Proc] block
|
84
|
+
# The fields and content inside this form.
|
85
|
+
#
|
86
|
+
# @return [String] The HTML form with the specified options and input fields.
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# form_tag '/register', :class => "registration_form" do ... end
|
90
|
+
#
|
91
|
+
def form_tag(url, options={}, &block)
|
92
|
+
options = {
|
93
|
+
:action => url,
|
94
|
+
:protect_from_csrf => is_protected_from_csrf?,
|
95
|
+
'accept-charset' => 'UTF-8'
|
96
|
+
}.update(options)
|
97
|
+
options[:enctype] = 'multipart/form-data' if options.delete(:multipart)
|
98
|
+
|
99
|
+
if (desired_method = options[:method]) =~ /get/i
|
100
|
+
options.delete(:protect_from_csrf)
|
101
|
+
else
|
102
|
+
options[:method] = 'post'
|
103
|
+
end
|
104
|
+
inner_form_html = hidden_form_method_field(desired_method)
|
105
|
+
inner_form_html << csrf_token_field if options.delete(:protect_from_csrf)
|
106
|
+
concat_content content_tag(:form, inner_form_html << capture_html(&block), options)
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Returns the hidden method field for 'put' and 'delete' forms.
|
111
|
+
# Only 'get' and 'post' are allowed within browsers;
|
112
|
+
# 'put' and 'delete' are just specified using hidden fields with form action still 'put'.
|
113
|
+
#
|
114
|
+
# @param [String] desired_method
|
115
|
+
# The method this hidden field represents (i.e put or delete).
|
116
|
+
#
|
117
|
+
# @return [String] The hidden field representing the +desired_method+ for the form.
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# # Generate: <input name="_method" value="delete" />
|
121
|
+
# hidden_form_method_field('delete')
|
122
|
+
#
|
123
|
+
def hidden_form_method_field(desired_method)
|
124
|
+
return ActiveSupport::SafeBuffer.new if desired_method.blank? || desired_method.to_s =~ /get|post/i
|
125
|
+
hidden_field_tag(:_method, :value => desired_method)
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Constructs a field_set to group fields with given options.
|
130
|
+
#
|
131
|
+
# @overload field_set_tag(legend=nil, options={}, &block)
|
132
|
+
# @param [String] legend The legend caption for the fieldset
|
133
|
+
# @param [Hash] options The html options for the fieldset.
|
134
|
+
# @param [Proc] block The content inside the fieldset.
|
135
|
+
# @overload field_set_tag(options={}, &block)
|
136
|
+
# @param [Hash] options The html options for the fieldset.
|
137
|
+
# @param [Proc] block The content inside the fieldset.
|
138
|
+
#
|
139
|
+
# @return [String] The html for the fieldset tag based on given +options+.
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# field_set_tag(:class => "office-set") { }
|
143
|
+
# field_set_tag("Office", :class => 'office-set') { }
|
144
|
+
#
|
145
|
+
def field_set_tag(*args, &block)
|
146
|
+
options = args.extract_options!
|
147
|
+
legend_text = args.first
|
148
|
+
legend_html = legend_text.blank? ? ActiveSupport::SafeBuffer.new : content_tag(:legend, legend_text)
|
149
|
+
concat_content content_tag(:fieldset, legend_html << capture_html(&block), options)
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Constructs a label tag from the given options.
|
154
|
+
#
|
155
|
+
# @param [String] name
|
156
|
+
# The name of the field to label.
|
157
|
+
# @param [Hash] options
|
158
|
+
# The html options for this label.
|
159
|
+
# @option options :caption
|
160
|
+
# The caption for this label.
|
161
|
+
# @param [Proc] block
|
162
|
+
# The content to be inserted into the label.
|
163
|
+
#
|
164
|
+
# @return [String] The html for this label with the given +options+.
|
165
|
+
#
|
166
|
+
# @example
|
167
|
+
# label_tag :username, :class => 'long-label'
|
168
|
+
# label_tag :username, :class => 'long-label' do ... end
|
169
|
+
#
|
170
|
+
def label_tag(name, options={}, &block)
|
171
|
+
options = { :caption => "#{name.to_s.humanize}: ", :for => name }.update(options)
|
172
|
+
caption_text = ActiveSupport::SafeBuffer.new << options.delete(:caption)
|
173
|
+
caption_text << "<span class='required'>*</span> ".html_safe if options.delete(:required)
|
174
|
+
|
175
|
+
if block_given?
|
176
|
+
concat_content content_tag(:label, caption_text << capture_html(&block), options)
|
177
|
+
else
|
178
|
+
content_tag(:label, caption_text, options)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Creates a text field input with the given name and options.
|
184
|
+
#
|
185
|
+
# @macro [new] text_field
|
186
|
+
# @param [Symbol] name
|
187
|
+
# The name of the input to create.
|
188
|
+
# @param [Hash] options
|
189
|
+
# The HTML options to include in this field.
|
190
|
+
#
|
191
|
+
# @option options [String] :id
|
192
|
+
# Specifies a unique identifier for the field.
|
193
|
+
# @option options [String] :class
|
194
|
+
# Specifies the stylesheet class of the field.
|
195
|
+
# @option options [String] :name
|
196
|
+
# Specifies the name of the field.
|
197
|
+
# @option options [String] :accesskey
|
198
|
+
# Specifies a shortcut key to access the field.
|
199
|
+
# @option options [Integer] :tabindex
|
200
|
+
# Specifies the tab order of the field.
|
201
|
+
# @option options [Integer] :maxlength
|
202
|
+
# Specifies the maximum length, in characters, of the field.
|
203
|
+
# @option options [Integer] :size
|
204
|
+
# Specifies the width, in characters, of the field.
|
205
|
+
# @option options [String] :placeholder
|
206
|
+
# Specifies a short hint that describes the expected value of the field.
|
207
|
+
# @option options [Boolean] :hidden
|
208
|
+
# Specifies whether or not the field is hidden from view.
|
209
|
+
# @option options [Boolean] :spellcheck
|
210
|
+
# Specifies whether or not the field should have it's spelling and grammar checked for errors.
|
211
|
+
# @option options [Boolean] :draggable
|
212
|
+
# Specifies whether or not the field is draggable. (true, false, :auto).
|
213
|
+
# @option options [String] :pattern
|
214
|
+
# Specifies the regular expression pattern that the field's value is checked against.
|
215
|
+
# @option options [Symbol] :autocomplete
|
216
|
+
# Specifies whether or not the field should have autocomplete enabled. (:on, :off).
|
217
|
+
# @option options [Boolean] :autofocus
|
218
|
+
# Specifies whether or not the field should automatically get focus when the page loads.
|
219
|
+
# @option options [Boolean] :required
|
220
|
+
# Specifies whether or not the field is required to be completed before the form is submitted.
|
221
|
+
# @option options [Boolean] :readonly
|
222
|
+
# Specifies whether or not the field is read only.
|
223
|
+
# @option options [Boolean] :disabled
|
224
|
+
# Specifies whether or not the field is disabled.
|
225
|
+
#
|
226
|
+
# @return [String]
|
227
|
+
# Generated HTML with specified +options+.
|
228
|
+
#
|
229
|
+
# @example
|
230
|
+
# text_field_tag :first_name, :maxlength => 40, :required => true
|
231
|
+
# # => <input name="first_name" maxlength="40" required type="text" />
|
232
|
+
#
|
233
|
+
# text_field_tag :last_name, :class => 'string', :size => 40
|
234
|
+
# # => <input name="last_name" class="string" size="40" type="text" />
|
235
|
+
#
|
236
|
+
# text_field_tag :username, :placeholder => 'Your Username'
|
237
|
+
# # => <input name="username" placeholder="Your Username" type="text" />
|
238
|
+
#
|
239
|
+
def text_field_tag(name, options={})
|
240
|
+
input_tag(:text, { :name => name }.update(options))
|
241
|
+
end
|
242
|
+
|
243
|
+
##
|
244
|
+
# Creates a number field input with the given name and options.
|
245
|
+
#
|
246
|
+
# @macro [new] number_field
|
247
|
+
# @param [Symbol] name
|
248
|
+
# The name of the input to create.
|
249
|
+
# @param [Hash] options
|
250
|
+
# The HTML options to include in this field.
|
251
|
+
#
|
252
|
+
# @option options [String] :id
|
253
|
+
# Specifies a unique identifier for the field.
|
254
|
+
# @option options [String] :class
|
255
|
+
# Specifies the stylesheet class of the field.
|
256
|
+
# @option options [String] :name
|
257
|
+
# Specifies the name of the field.
|
258
|
+
# @option options [String] :accesskey
|
259
|
+
# Specifies a shortcut key to access the field.
|
260
|
+
# @option options [Integer] :tabindex
|
261
|
+
# Specifies the tab order of the field.
|
262
|
+
# @option options [Integer] :min
|
263
|
+
# Specifies the minimum value of the field.
|
264
|
+
# @option options [Integer] :max
|
265
|
+
# Specifies the maximum value of the field.
|
266
|
+
# @option options [Integer] :step
|
267
|
+
# Specifies the legal number intervals of the field.
|
268
|
+
# @option options [Boolean] :hidden
|
269
|
+
# Specifies whether or not the field is hidden from view.
|
270
|
+
# @option options [Boolean] :spellcheck
|
271
|
+
# Specifies whether or not the field should have it's spelling and grammar checked for errors.
|
272
|
+
# @option options [Boolean] :draggable
|
273
|
+
# Specifies whether or not the field is draggable. (true, false, :auto).
|
274
|
+
# @option options [String] :pattern
|
275
|
+
# Specifies the regular expression pattern that the field's value is checked against.
|
276
|
+
# @option options [Symbol] :autocomplete
|
277
|
+
# Specifies whether or not the field should have autocomplete enabled. (:on, :off).
|
278
|
+
# @option options [Boolean] :autofocus
|
279
|
+
# Specifies whether or not the field should automatically get focus when the page loads.
|
280
|
+
# @option options [Boolean] :required
|
281
|
+
# Specifies whether or not the field is required to be completeled before the form is submitted.
|
282
|
+
# @option options [Boolean] :readonly
|
283
|
+
# Specifies whether or not the field is read only.
|
284
|
+
# @option options [Boolean] :disabled
|
285
|
+
# Specifies whether or not the field is disabled.
|
286
|
+
#
|
287
|
+
# @return [String]
|
288
|
+
# Generated HTML with specified +options+.
|
289
|
+
#
|
290
|
+
# @example
|
291
|
+
# number_field_tag :quantity, :class => 'numeric'
|
292
|
+
# # => <input name="quantity" class="numeric" type="number" />
|
293
|
+
#
|
294
|
+
# number_field_tag :zip_code, :pattern => /[0-9]{5}/
|
295
|
+
# # => <input name="zip_code" pattern="[0-9]{5}" type="number" />
|
296
|
+
#
|
297
|
+
# number_field_tag :credit_card, :autocomplete => :off
|
298
|
+
# # => <input name="credit_card" autocomplete="off" type="number" />
|
299
|
+
#
|
300
|
+
# number_field_tag :age, :min => 18, :max => 120, :step => 1
|
301
|
+
# # => <input name="age" min="18" max="120" step="1" type="number" />
|
302
|
+
#
|
303
|
+
def number_field_tag(name, options={})
|
304
|
+
input_tag(:number, { :name => name }.update(options))
|
305
|
+
end
|
306
|
+
|
307
|
+
##
|
308
|
+
# Creates a telephone field input with the given name and options.
|
309
|
+
#
|
310
|
+
# @macro text_field
|
311
|
+
#
|
312
|
+
# @example
|
313
|
+
# telephone_field_tag :phone_number, :class => 'string'
|
314
|
+
# # => <input name="phone_number" class="string" type="tel" />
|
315
|
+
#
|
316
|
+
# telephone_field_tag :cell_phone, :tabindex => 1
|
317
|
+
# telephone_field_tag :work_phone, :tabindex => 2
|
318
|
+
# telephone_field_tag :home_phone, :tabindex => 3
|
319
|
+
#
|
320
|
+
# # => <input name="cell_phone" tabindex="1" type="tel" />
|
321
|
+
# # => <input name="work_phone" tabindex="2" type="tel" />
|
322
|
+
# # => <input name="home_phone" tabindex="3" type="tel" />
|
323
|
+
#
|
324
|
+
def telephone_field_tag(name, options={})
|
325
|
+
input_tag(:tel, { :name => name }.update(options))
|
326
|
+
end
|
327
|
+
alias_method :phone_field_tag, :telephone_field_tag
|
328
|
+
|
329
|
+
##
|
330
|
+
# Creates an email field input with the given name and options.
|
331
|
+
#
|
332
|
+
# @macro text_field
|
333
|
+
#
|
334
|
+
# @example
|
335
|
+
# email_field_tag :email, :placeholder => 'you@example.com'
|
336
|
+
# # => <input name="email" placeholder="you@example.com" type="email" />
|
337
|
+
#
|
338
|
+
# email_field_tag :email, :value => 'padrinorb@gmail.com', :readonly => true
|
339
|
+
# # => <input name="email" value="padrinorb@gmail.com" readonly type="email" />
|
340
|
+
#
|
341
|
+
def email_field_tag(name, options={})
|
342
|
+
input_tag(:email, { :name => name }.update(options))
|
343
|
+
end
|
344
|
+
|
345
|
+
##
|
346
|
+
# Creates a search field input with the given name and options.
|
347
|
+
#
|
348
|
+
# @macro text_field
|
349
|
+
#
|
350
|
+
# @example
|
351
|
+
# search_field_tag :search, :placeholder => 'Search this website...'
|
352
|
+
# # => <input name="search" placeholder="Search this website..." type="search" />
|
353
|
+
#
|
354
|
+
# search_field_tag :search, :maxlength => 15, :class => ['search', 'string']
|
355
|
+
# # => <input name="search" maxlength="15" class="search string" />
|
356
|
+
#
|
357
|
+
# search_field_tag :search, :id => 'search'
|
358
|
+
# # => <input name="search" id="search" type="search" />
|
359
|
+
#
|
360
|
+
# search_field_tag :search, :autofocus => true
|
361
|
+
# # => <input name="search" autofocus type="search" />
|
362
|
+
#
|
363
|
+
def search_field_tag(name, options={})
|
364
|
+
input_tag(:search, { :name => name }.update(options))
|
365
|
+
end
|
366
|
+
|
367
|
+
##
|
368
|
+
# Creates a URL field input with the given name and options.
|
369
|
+
#
|
370
|
+
# @macro text_field
|
371
|
+
#
|
372
|
+
# @example
|
373
|
+
# url_field_tag :favorite_website, :placeholder => 'http://padrinorb.com'
|
374
|
+
# <input name="favorite_website" placeholder="http://padrinorb.com." type="url" />
|
375
|
+
#
|
376
|
+
# url_field_tag :home_page, :class => 'string url'
|
377
|
+
# <input name="home_page" class="string url", type="url" />
|
378
|
+
#
|
379
|
+
def url_field_tag(name, options={})
|
380
|
+
input_tag(:url, { :name => name }.update(options))
|
381
|
+
end
|
382
|
+
|
383
|
+
##
|
384
|
+
# Constructs a hidden field input from the given options.
|
385
|
+
#
|
386
|
+
# @example
|
387
|
+
# hidden_field_tag :session_key, :value => "__secret__"
|
388
|
+
#
|
389
|
+
def hidden_field_tag(name, options={})
|
390
|
+
input_tag(:hidden, { :name => name }.update(options))
|
391
|
+
end
|
392
|
+
|
393
|
+
##
|
394
|
+
# Constructs a text area input from the given options.
|
395
|
+
#
|
396
|
+
# @example
|
397
|
+
# text_area_tag :username, :class => 'long', :value => "Demo?"
|
398
|
+
#
|
399
|
+
def text_area_tag(name, options={})
|
400
|
+
inner_html = "\n#{options.delete(:value)}"
|
401
|
+
options = { :name => name, :rows => "", :cols => "" }.update(options)
|
402
|
+
content_tag(:textarea, inner_html, options)
|
403
|
+
end
|
404
|
+
|
405
|
+
##
|
406
|
+
# Constructs a password field input from the given options.
|
407
|
+
#
|
408
|
+
# @example
|
409
|
+
# password_field_tag :password, :class => 'long'
|
410
|
+
#
|
411
|
+
# @api public
|
412
|
+
def password_field_tag(name, options={})
|
413
|
+
input_tag(:password, { :name => name }.update(options))
|
414
|
+
end
|
415
|
+
|
416
|
+
##
|
417
|
+
# Constructs a check_box from the given options.
|
418
|
+
#
|
419
|
+
# @example
|
420
|
+
# check_box_tag :remember_me, :value => 'Yes'
|
421
|
+
#
|
422
|
+
def check_box_tag(name, options={})
|
423
|
+
input_tag(:checkbox, { :name => name, :value => '1' }.update(options))
|
424
|
+
end
|
425
|
+
|
426
|
+
##
|
427
|
+
# Constructs a radio_button from the given options.
|
428
|
+
#
|
429
|
+
# @example
|
430
|
+
# radio_button_tag :remember_me, :value => 'true'
|
431
|
+
#
|
432
|
+
def radio_button_tag(name, options={})
|
433
|
+
input_tag(:radio, { :name => name }.update(options))
|
434
|
+
end
|
435
|
+
|
436
|
+
##
|
437
|
+
# Constructs a file field input from the given options.
|
438
|
+
#
|
439
|
+
# @example
|
440
|
+
# file_field_tag :photo, :class => 'long'
|
441
|
+
#
|
442
|
+
# @api public
|
443
|
+
def file_field_tag(name, options={})
|
444
|
+
name = "#{name}[]" if options[:multiple]
|
445
|
+
input_tag(:file, { :name => name }.update(options))
|
446
|
+
end
|
447
|
+
|
448
|
+
##
|
449
|
+
# Constructs a select from the given options.
|
450
|
+
#
|
451
|
+
# @example
|
452
|
+
# options = [['caption', 'value'], ['Green', 'green1'], ['Blue', 'blue1'], ['Black', "black1"]]
|
453
|
+
# options = ['option', 'red', 'yellow' ]
|
454
|
+
# select_tag(:favorite_color, :options => ['red', 'yellow'], :selected => 'green1')
|
455
|
+
# select_tag(:country, :collection => @countries, :fields => [:name, :code], :include_blank => 'None')
|
456
|
+
#
|
457
|
+
# # Optgroups can be generated using :grouped_options => (Hash or nested Array)
|
458
|
+
# grouped_options = [['Friends',['Yoda',['Obiwan',1]]],['Enemies',['Palpatine',['Darth Vader',3]]]]
|
459
|
+
# grouped_options = {'Friends' => ['Yoda',['Obiwan',1]],'Enemies' => ['Palpatine',['Darth Vader',3]]}
|
460
|
+
# select_tag(:color, :grouped_options => [['warm',['red','yellow']],['cool',['blue', 'purple']]])
|
461
|
+
#
|
462
|
+
# # Optgroups can be generated using the rails-style attribute hash.
|
463
|
+
# grouped_options = {
|
464
|
+
# "Friends" => ["Yoda", ["Obiwan", 2, {:magister => 'no'}], {:lame => 'yes'}],
|
465
|
+
# "Enemies" => [["Palpatine", "Palpatine", {:scary => 'yes', :old => 'yes'}], ["Darth Vader", 3, {:disabled => true}]]
|
466
|
+
# }
|
467
|
+
# select_tag(:name, :grouped_options => grouped_options)
|
468
|
+
#
|
469
|
+
# @param [String] name
|
470
|
+
# The name of the input field.
|
471
|
+
# @param [Hash] options
|
472
|
+
# The html options for the input field.
|
473
|
+
# @option options [Array<String, Array>] :options
|
474
|
+
# Explicit options to display in the select. Can be strings or string tuples.
|
475
|
+
# @option options [Array<Array>] :grouped_options
|
476
|
+
# List of options for each group in the select. See examples for details.
|
477
|
+
# @option options [Array<Object>] :collection
|
478
|
+
# Collection of objects used as options in the select.
|
479
|
+
# @option options [Array<Symbol>] :fields
|
480
|
+
# The attributes used as "label" and "value" for each +collection+ object.
|
481
|
+
# @option options [String] :selected (nil)
|
482
|
+
# The option value initially selected.
|
483
|
+
# @option options [Boolean] :include_blank (false)
|
484
|
+
# Include a blank option in the select.
|
485
|
+
# @option options [Boolean] :multiple (false)
|
486
|
+
# Allow multiple options to be selected at once.
|
487
|
+
#
|
488
|
+
# @return [String] The HTML input field based on the +options+ specified.
|
489
|
+
#
|
490
|
+
def select_tag(name, options={})
|
491
|
+
options = { :name => name }.merge(options)
|
492
|
+
options[:name] = "#{options[:name]}[]" if options[:multiple]
|
493
|
+
content_tag(:select, extract_option_tags!(options), options)
|
494
|
+
end
|
495
|
+
|
496
|
+
##
|
497
|
+
# Constructs a button input from the given options.
|
498
|
+
#
|
499
|
+
# @param [String] caption
|
500
|
+
# The caption for the button.
|
501
|
+
# @param [Hash] options
|
502
|
+
# The html options for the input field.
|
503
|
+
#
|
504
|
+
# @return [String] The html button based on the +options+ specified.
|
505
|
+
#
|
506
|
+
# @example
|
507
|
+
# button_tag "Cancel", :class => 'clear'
|
508
|
+
#
|
509
|
+
def button_tag(caption, options = {})
|
510
|
+
input_tag(:button, { :value => caption }.update(options))
|
511
|
+
end
|
512
|
+
|
513
|
+
##
|
514
|
+
# Constructs a submit button from the given options.
|
515
|
+
#
|
516
|
+
# @param [String] caption (defaults to: +Submit+)
|
517
|
+
# The caption for the submit button.
|
518
|
+
# @param [Hash] options
|
519
|
+
# The html options for the input field.
|
520
|
+
#
|
521
|
+
# @return [String] The html submit button based on the +options+ specified.
|
522
|
+
#
|
523
|
+
# @example
|
524
|
+
# submit_tag "Create", :class => 'success'
|
525
|
+
# submit_tag :class => 'btn'
|
526
|
+
#
|
527
|
+
def submit_tag(*args)
|
528
|
+
options = args.extract_options!
|
529
|
+
caption = args.length >= 1 ? args.first : "Submit"
|
530
|
+
input_tag(:submit, { :value => caption }.merge(options))
|
531
|
+
end
|
532
|
+
|
533
|
+
##
|
534
|
+
# Constructs a submit button from the given options.
|
535
|
+
#
|
536
|
+
# @param [String] source
|
537
|
+
# The source image path for the button.
|
538
|
+
# @param [Hash] options
|
539
|
+
# The html options for the input field.
|
540
|
+
#
|
541
|
+
# @return [String] The html image button based on the +options+ specified.
|
542
|
+
#
|
543
|
+
# @example
|
544
|
+
# image_submit_tag 'form/submit.png'
|
545
|
+
#
|
546
|
+
def image_submit_tag(source, options={})
|
547
|
+
input_tag(:image, { :src => image_path(source) }.update(options))
|
548
|
+
end
|
549
|
+
|
550
|
+
##
|
551
|
+
# Creates a form containing a single button that submits to the URL.
|
552
|
+
#
|
553
|
+
# @overload button_to(name, url, options={})
|
554
|
+
# @param [String] caption The text caption.
|
555
|
+
# @param [String] url The url href.
|
556
|
+
# @param [Hash] options The html options.
|
557
|
+
# @overload button_to(name, options={}, &block)
|
558
|
+
# @param [String] url The url href.
|
559
|
+
# @param [Hash] options The html options.
|
560
|
+
# @param [Proc] block The button content.
|
561
|
+
#
|
562
|
+
# @option options [Boolean] :multipart
|
563
|
+
# If true, this form will support multipart encoding.
|
564
|
+
# @option options [String] :remote
|
565
|
+
# Instructs ujs handler to handle the submit as ajax.
|
566
|
+
# @option options [Symbol] :method
|
567
|
+
# Instructs ujs handler to use different http method (i.e :post, :delete).
|
568
|
+
# @option options [Hash] :submit_options
|
569
|
+
# Hash of any options, that you want to pass to submit_tag (i.e :id, :class)
|
570
|
+
#
|
571
|
+
# @return [String] Form and button html with specified +options+.
|
572
|
+
#
|
573
|
+
# @example
|
574
|
+
# button_to 'Delete', url(:accounts_destroy, :id => account), :method => :delete, :class => :form
|
575
|
+
# # Generates:
|
576
|
+
# # <form class="form" action="/admin/accounts/destroy/2" method="post">
|
577
|
+
# # <input type="hidden" value="delete" name="_method" />
|
578
|
+
# # <input type="submit" value="Delete" />
|
579
|
+
# # </form>
|
580
|
+
#
|
581
|
+
def button_to(*args, &block)
|
582
|
+
options = args.extract_options!.dup
|
583
|
+
name, url = *args
|
584
|
+
options['data-remote'] = 'true' if options.delete(:remote)
|
585
|
+
submit_options = options.delete(:submit_options) || {}
|
586
|
+
block ||= proc { submit_tag(name, submit_options) }
|
587
|
+
form_tag(url || name, options, &block)
|
588
|
+
end
|
589
|
+
|
590
|
+
##
|
591
|
+
# Constructs a range tag from the given options.
|
592
|
+
#
|
593
|
+
# @example
|
594
|
+
# range_field_tag('ranger_with_min_max', :min => 1, :max => 50)
|
595
|
+
# range_field_tag('ranger_with_range', :range => 1..5)
|
596
|
+
#
|
597
|
+
# @param [String] name
|
598
|
+
# The name of the range field.
|
599
|
+
# @param [Hash] options
|
600
|
+
# The html options for the range field.
|
601
|
+
# @option options [Integer] :min
|
602
|
+
# The min range of the range field.
|
603
|
+
# @option options [Integer] :max
|
604
|
+
# The max range of the range field.
|
605
|
+
# @option options [range] :range
|
606
|
+
# The range, in lieu of :min and :max. See examples for details.
|
607
|
+
# @return [String] The html range field
|
608
|
+
#
|
609
|
+
def range_field_tag(name, options = {})
|
610
|
+
options = { :name => name }.update(options)
|
611
|
+
if range = options.delete(:range)
|
612
|
+
options[:min], options[:max] = range.min, range.max
|
613
|
+
end
|
614
|
+
input_tag(:range, options)
|
615
|
+
end
|
616
|
+
|
617
|
+
private
|
618
|
+
|
619
|
+
##
|
620
|
+
# Returns an initialized builder instance for the given object and settings.
|
621
|
+
#
|
622
|
+
# @example
|
623
|
+
# builder_instance(@account, :nested => { ... }) => <FormBuilder>
|
624
|
+
#
|
625
|
+
def builder_instance(object, options={})
|
626
|
+
default_builder = respond_to?(:settings) && settings.default_builder || 'StandardFormBuilder'
|
627
|
+
builder_class = options.delete(:builder) || default_builder
|
628
|
+
builder_class = "Padrino::Helpers::FormBuilder::#{builder_class}".constantize if builder_class.is_a?(String)
|
629
|
+
builder_class.new(self, object, options)
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
633
|
+
end
|