merb_helpers 0.9.4 → 0.9.5
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.
- data/Rakefile +2 -2
- data/lib/merb_helpers/core_ext.rb +2 -0
- data/lib/merb_helpers/form/builder.rb +394 -0
- data/lib/merb_helpers/form/helpers.rb +410 -0
- data/lib/merb_helpers/form_helpers.rb +10 -651
- metadata +6 -3
@@ -0,0 +1,410 @@
|
|
1
|
+
# Form helpers provide a number of methods to simplify the creation of HTML forms.
|
2
|
+
# They can work directly with models (bound) or standalone (unbound).
|
3
|
+
#
|
4
|
+
# The core method of this helper, +form_for+, gives you the ability to create a form for a resource.
|
5
|
+
# For example, let's say that you have a model <tt>Person</tt> and want to create a new instance of it:
|
6
|
+
module Merb::Helpers::Form
|
7
|
+
|
8
|
+
def _singleton_form_context
|
9
|
+
@_singleton_form_context ||=
|
10
|
+
self._form_class.new(nil, nil, self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def form_contexts
|
14
|
+
@_form_contexts ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_form_context
|
18
|
+
form_contexts.last || _singleton_form_context
|
19
|
+
end
|
20
|
+
|
21
|
+
def _new_form_context(name, builder)
|
22
|
+
if name.is_a?(String) || name.is_a?(Symbol)
|
23
|
+
ivar = instance_variable_get("@#{name}")
|
24
|
+
else
|
25
|
+
ivar, name = name, name.class.to_s.snake_case
|
26
|
+
end
|
27
|
+
builder ||= current_form_context.class if current_form_context
|
28
|
+
(builder || self._form_class).new(ivar, name, self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_form_context(name, builder)
|
32
|
+
form_contexts.push(_new_form_context(name, builder))
|
33
|
+
ret = yield
|
34
|
+
form_contexts.pop
|
35
|
+
ret
|
36
|
+
end
|
37
|
+
|
38
|
+
# Generates a form tag, which accepts a block that is not directly based on resource attributes
|
39
|
+
#
|
40
|
+
# ==== Parameters
|
41
|
+
# attrs<Hash>:: HTML attributes
|
42
|
+
#
|
43
|
+
# ==== Returns
|
44
|
+
# String:: HTML
|
45
|
+
#
|
46
|
+
# ==== Notes
|
47
|
+
# * Block helpers use the <%= =%> syntax
|
48
|
+
# * a multipart enctype is automatically set if the form contains a file upload field
|
49
|
+
#
|
50
|
+
# ==== Example
|
51
|
+
# <%= form :action => url(:controller => "foo", :action => "bar", :id => 1) do %>
|
52
|
+
# <%= text_field :name => "first_name", :label => "First Name" %>
|
53
|
+
# <%= submit "Create" %>
|
54
|
+
# <% end =%>
|
55
|
+
#
|
56
|
+
# Generates the HTML:
|
57
|
+
#
|
58
|
+
# <form action="/foo/bar/1" method="post">
|
59
|
+
# <label for="first_name">First Name</label>
|
60
|
+
# <input type="text" id="first_name" name="first_name" />
|
61
|
+
# <input type="submit" value="Create" />
|
62
|
+
# </form>
|
63
|
+
def form(*args, &blk)
|
64
|
+
_singleton_form_context.form(*args, &blk)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Generates a resource specific form tag which accepts a block, this also provides automatic resource routing.
|
68
|
+
#
|
69
|
+
# ==== Parameters
|
70
|
+
# name<Symbol>:: Model or Resource
|
71
|
+
# attrs<Hash>:: HTML attributes
|
72
|
+
#
|
73
|
+
# ==== Returns
|
74
|
+
# String:: HTML
|
75
|
+
#
|
76
|
+
# ==== Notes
|
77
|
+
# * Block helpers use the <%= =%> syntax
|
78
|
+
#
|
79
|
+
# ==== Example
|
80
|
+
# <%= form_for @person do %>
|
81
|
+
# <%= text_field :first_name, :label => "First Name" %>
|
82
|
+
# <%= text_field :last_name, :label => "Last Name" %>
|
83
|
+
# <%= submit "Create" %>
|
84
|
+
# <% end =%>
|
85
|
+
#
|
86
|
+
# The HTML generated for this would be:
|
87
|
+
#
|
88
|
+
# <form action="/people" method="post">
|
89
|
+
# <label for="person_first_name">First Name</label>
|
90
|
+
# <input type="text" id="person_first_name" name="person[first_name]" />
|
91
|
+
# <label for="person_last_name">Last Name</label>
|
92
|
+
# <input type="text" id="person_last_name" name="person[last_name]" />
|
93
|
+
# <input type="submit" value="Create" />
|
94
|
+
# </form>
|
95
|
+
def form_for(name, attrs = {}, &blk)
|
96
|
+
with_form_context(name, attrs.delete(:builder)) do
|
97
|
+
current_form_context.form(attrs, &blk)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Creates a scope around a specific resource object like form_for, but doesnt create the form tags themselves.
|
102
|
+
# This makes fields_for suitable for specifying additional resource objects in the same form.
|
103
|
+
#
|
104
|
+
# ==== Examples
|
105
|
+
# <%= form_for @person do %>
|
106
|
+
# <%= text_field :first_name, :label => "First Name" %>
|
107
|
+
# <%= text_field :last_name, :label => "Last Name" %>
|
108
|
+
# <% fields_for :permission do %>
|
109
|
+
# <%= check_box :is_admin, :label => "Administrator" %>
|
110
|
+
# <% end %>
|
111
|
+
# <%= submit "Create" %>
|
112
|
+
# <% end =%>
|
113
|
+
def fields_for(name, attrs = {}, &blk)
|
114
|
+
attrs ||= {}
|
115
|
+
with_form_context(name, attrs.delete(:builder)) do
|
116
|
+
current_form_context.concat(attrs, &blk)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Provides the ability to create quick fieldsets as blocks for your forms.
|
121
|
+
#
|
122
|
+
# ==== Parameters
|
123
|
+
# attrs<Hash>:: HTML attributes and options
|
124
|
+
#
|
125
|
+
# ==== Options
|
126
|
+
# +legend+:: Adds a legend tag within the fieldset
|
127
|
+
#
|
128
|
+
# ==== Returns
|
129
|
+
# String:: HTML
|
130
|
+
#
|
131
|
+
# ==== Notes
|
132
|
+
# Block helpers use the <%= =%> syntax
|
133
|
+
#
|
134
|
+
# ==== Example
|
135
|
+
# <%= fieldset :legend => "Customer Options" do %>
|
136
|
+
# ...your form elements
|
137
|
+
# <% end =%>
|
138
|
+
#
|
139
|
+
# Generates the HTML:
|
140
|
+
#
|
141
|
+
# <fieldset>
|
142
|
+
# <legend>Customer Options</legend>
|
143
|
+
# ...your form elements
|
144
|
+
# </fieldset>
|
145
|
+
def fieldset(attrs = {}, &blk)
|
146
|
+
_singleton_form_context.fieldset(attrs, &blk)
|
147
|
+
end
|
148
|
+
|
149
|
+
def fieldset_for(name, attrs = {}, &blk)
|
150
|
+
with_form_context(name, attrs.delete(:builder)) do
|
151
|
+
current_form_context.fieldset(attrs, &blk)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Provides a HTML text input tag
|
156
|
+
#
|
157
|
+
# ==== Parameters
|
158
|
+
# name<Symbol>:: Model or Resource
|
159
|
+
# attrs<Hash>:: HTML attributes
|
160
|
+
#
|
161
|
+
# ==== Returns
|
162
|
+
# String:: HTML
|
163
|
+
#
|
164
|
+
# ==== Example
|
165
|
+
# <%= text_field :name => :fav_color, :label => "Your Favorite Color" %>
|
166
|
+
# # => <label for="fav_color">Your Favorite Color</label><input type="text" id="fav_color" name="fav_color" />
|
167
|
+
#
|
168
|
+
# Used with a model:
|
169
|
+
#
|
170
|
+
# <%= form_for @person do %>
|
171
|
+
# <%= text_field :first_name, :label => "First Name" %>
|
172
|
+
# <% end =%>
|
173
|
+
def text_field; end
|
174
|
+
|
175
|
+
# Provides a HTML password input.
|
176
|
+
#
|
177
|
+
# ==== Parameters
|
178
|
+
# name<Symbol>:: Model or Resource
|
179
|
+
# attrs<Hash>:: HTML attributes
|
180
|
+
#
|
181
|
+
# ==== Returns
|
182
|
+
# String:: HTML
|
183
|
+
#
|
184
|
+
# ==== Example
|
185
|
+
# <%= password_field :name => :password, :label => "Password" %>
|
186
|
+
# # => <label for="password">Password</label><input type="password" id="password" name="password" />
|
187
|
+
#
|
188
|
+
# Used with a model:
|
189
|
+
#
|
190
|
+
# <%= password_field :password, :label => 'New Password' %>
|
191
|
+
def password_field; end
|
192
|
+
|
193
|
+
# Provides a HTML hidden input field
|
194
|
+
#
|
195
|
+
# ==== Parameters
|
196
|
+
# name<Symbol>:: Model or Resource
|
197
|
+
# attrs<Hash>:: HTML attributes
|
198
|
+
#
|
199
|
+
# ==== Returns
|
200
|
+
# String:: HTML
|
201
|
+
#
|
202
|
+
# ==== Example
|
203
|
+
# <%= hidden_field :name => "secret", :value => "some secret value" %>
|
204
|
+
#
|
205
|
+
# Used with a model:
|
206
|
+
#
|
207
|
+
# <%= hidden_field :identifier %>
|
208
|
+
# # => <input type="hidden" id="person_identifier" name="person[identifier]" value="#{@person.identifier}" />
|
209
|
+
def hidden_field; end
|
210
|
+
|
211
|
+
# Provides a HTML file input
|
212
|
+
#
|
213
|
+
# ==== Parameters
|
214
|
+
# name<Symbol>:: Model or Resource
|
215
|
+
# attrs<Hash>:: HTML attributes
|
216
|
+
#
|
217
|
+
# ==== Returns
|
218
|
+
# String:: HTML
|
219
|
+
#
|
220
|
+
# ==== Example
|
221
|
+
# <%= file_field :name => "file", :label => "File" %>
|
222
|
+
#
|
223
|
+
# Used with a model:
|
224
|
+
#
|
225
|
+
# <%= file_field :file, :label => "Choose a file" %>
|
226
|
+
def file_field; end
|
227
|
+
|
228
|
+
# Provides a HTML textarea tag
|
229
|
+
#
|
230
|
+
# ==== Parameters
|
231
|
+
# contents<String>:: Contents of the text area
|
232
|
+
# attrs<Hash>:: HTML attributes
|
233
|
+
#
|
234
|
+
# ==== Returns
|
235
|
+
# String:: HTML
|
236
|
+
#
|
237
|
+
# ==== Example
|
238
|
+
# <%= text_area "my comments", :name => "comments" %>
|
239
|
+
#
|
240
|
+
# Used with a model:
|
241
|
+
#
|
242
|
+
# <%= text_area :comments %>
|
243
|
+
def text_area; end
|
244
|
+
|
245
|
+
# Provides a HTML select
|
246
|
+
#
|
247
|
+
# ==== Parameters
|
248
|
+
# method<Symbol>:: Resource attribute
|
249
|
+
# attrs<Hash>:: HTML attributes and options
|
250
|
+
#
|
251
|
+
# ==== Options
|
252
|
+
# +prompt+:: Adds an additional option tag with the provided string with no value.
|
253
|
+
# +selected+:: The value of a selected object, which may be either a string or an array.
|
254
|
+
# +include_blank+:: Adds an additional blank option tag with no value.
|
255
|
+
# +collection+:: The collection for the select options
|
256
|
+
# +text_method+:: Method to determine text of an option (as a symbol). Ex: :text_method => :name will call .name on your record object for what text to display.
|
257
|
+
# +value_method+:: Method to determine value of an option (as a symbol).
|
258
|
+
#
|
259
|
+
# ==== Returns
|
260
|
+
# String:: HTML
|
261
|
+
#
|
262
|
+
# ==== Example
|
263
|
+
# <%= select :name, :collection => %w(one two three) %>
|
264
|
+
def select; end
|
265
|
+
|
266
|
+
# Provides a generic HTML checkbox input tag.
|
267
|
+
# There are two ways this tag can be generated, based on the
|
268
|
+
# option :boolean. If not set to true, a "magic" input is generated.
|
269
|
+
# Otherwise, an input is created that can be easily used for passing
|
270
|
+
# an array of values to the application.
|
271
|
+
#
|
272
|
+
# ==== Parameters
|
273
|
+
# method<Symbol>:: Resource attribute
|
274
|
+
# attrs<Hash>:: HTML attributes and options
|
275
|
+
#
|
276
|
+
# ==== Returns
|
277
|
+
# String:: HTML
|
278
|
+
#
|
279
|
+
# ==== Example
|
280
|
+
# <%= check_box :name => "is_activated", :value => "1" %>
|
281
|
+
# <%= check_box :name => "choices[]", :boolean => false, :value => "dog" %>
|
282
|
+
# <%= check_box :name => "choices[]", :boolean => false, :value => "cat" %>
|
283
|
+
# <%= check_box :name => "choices[]", :boolean => false, :value => "weasle" %>
|
284
|
+
#
|
285
|
+
# Used with a model:
|
286
|
+
#
|
287
|
+
# <%= check_box :is_activated, :label => "Activated?" %>
|
288
|
+
def check_box; end
|
289
|
+
|
290
|
+
# Provides a HTML radio input tag
|
291
|
+
#
|
292
|
+
# ==== Parameters
|
293
|
+
# method<Symbol>:: Resource attribute
|
294
|
+
# attrs<Hash>:: HTML attributes and options
|
295
|
+
#
|
296
|
+
# ==== Returns
|
297
|
+
# String:: HTML
|
298
|
+
#
|
299
|
+
# ==== Example
|
300
|
+
# <%= radio_button :name => "radio_options", :value => "1", :label => "One" %>
|
301
|
+
# <%= radio_button :name => "radio_options", :value => "2", :label => "Two" %>
|
302
|
+
# <%= radio_button :name => "radio_options", :value => "3", :label => "Three", :checked => true %>
|
303
|
+
#
|
304
|
+
# Used with a model:
|
305
|
+
#
|
306
|
+
# <%= form_for @person do %>
|
307
|
+
# <%= radio_button :first_name %>
|
308
|
+
# <% end =%>
|
309
|
+
def radio_button; end
|
310
|
+
|
311
|
+
# Provides a radio group based on a resource attribute.
|
312
|
+
# This is generally used within a resource block such as +form_for+.
|
313
|
+
#
|
314
|
+
# ==== Parameters
|
315
|
+
# method<Symbol>:: Resource attribute
|
316
|
+
# arr<Array>:: Choices
|
317
|
+
#
|
318
|
+
# ==== Returns
|
319
|
+
# String:: HTML
|
320
|
+
#
|
321
|
+
# ==== Examples
|
322
|
+
# <%# the labels are the options %>
|
323
|
+
# <%= radio_group :my_choice, [5,6,7] %>
|
324
|
+
#
|
325
|
+
# <%# custom labels %>
|
326
|
+
# <%= radio_group :my_choice, [{:value => 5, :label => "five"}] %>
|
327
|
+
def radio_group; end
|
328
|
+
|
329
|
+
# @todo radio_group helper still needs to be implemented
|
330
|
+
%w(text_field password_field hidden_field file_field
|
331
|
+
text_area select check_box radio_button radio_group).each do |kind|
|
332
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
333
|
+
def #{kind}(*args)
|
334
|
+
if bound?(*args)
|
335
|
+
current_form_context.bound_#{kind}(*args)
|
336
|
+
else
|
337
|
+
current_form_context.unbound_#{kind}(*args)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
RUBY
|
341
|
+
end
|
342
|
+
|
343
|
+
# Generates a HTML button.
|
344
|
+
#
|
345
|
+
# ==== Parameters
|
346
|
+
# contents<String>:: HTML contained within the button tag
|
347
|
+
# attrs<Hash>:: HTML attributes
|
348
|
+
#
|
349
|
+
# ==== Returns
|
350
|
+
# String:: HTML
|
351
|
+
#
|
352
|
+
# ==== Notes
|
353
|
+
# * Buttons do not always work as planned in IE
|
354
|
+
# http://www.peterbe.com/plog/button-tag-in-IE
|
355
|
+
# * Not all mobile browsers support buttons
|
356
|
+
# http://nickcowie.com/2007/time-to-stop-using-the-button-element/
|
357
|
+
#
|
358
|
+
# ==== Example
|
359
|
+
# <%= button "Initiate Launch Sequence" %>
|
360
|
+
def button(contents, attrs = {})
|
361
|
+
current_form_context.button(contents, attrs)
|
362
|
+
end
|
363
|
+
|
364
|
+
# Generates a HTML submit button.
|
365
|
+
#
|
366
|
+
# ==== Parameters
|
367
|
+
# value<String>:: Sets the value="" attribute
|
368
|
+
# attrs<Hash>:: HTML attributes
|
369
|
+
#
|
370
|
+
# ==== Returns
|
371
|
+
# String:: HTML
|
372
|
+
#
|
373
|
+
# ==== Example
|
374
|
+
# <%= submit "Process" %>
|
375
|
+
def submit(contents, attrs = {})
|
376
|
+
current_form_context.submit(contents, attrs)
|
377
|
+
end
|
378
|
+
|
379
|
+
# Provides a HTML formatted display of resource errors in an unordered list with a h2 form submission error
|
380
|
+
#
|
381
|
+
# ==== Parameters
|
382
|
+
# obj<Symbol>:: Model or Resource
|
383
|
+
# error_class<String>:: CSS class to use for error container
|
384
|
+
# build_li<String>:: Custom li tag to wrap each error in
|
385
|
+
# header<String>:: Custom header text for the error container
|
386
|
+
# before<Boolean>:: Display the errors before or inside of the form
|
387
|
+
#
|
388
|
+
# ==== Returns
|
389
|
+
# String:: HTML
|
390
|
+
#
|
391
|
+
# ==== Examples
|
392
|
+
# <%= error_messages_for :person %>
|
393
|
+
# <%= error_messages_for :person {|errors| "You can has probs nao: #{errors.size} of em!"}
|
394
|
+
# <%= error_messages_for :person, lambda{|error| "<li class='aieeee'>#{error.join(' ')}"} %>
|
395
|
+
# <%= error_messages_for :person, nil, 'bad_mojo' %>
|
396
|
+
def error_messages_for(obj = nil, opts = {})
|
397
|
+
current_form_context.error_messages_for(obj, opts[:error_class] || "error",
|
398
|
+
opts[:build_li] || "<li>%s</li>",
|
399
|
+
opts[:header] || "<h2>Form submission failed because of %s problem%s</h2>",
|
400
|
+
opts.key?(:before) ? opts[:before] : true)
|
401
|
+
end
|
402
|
+
alias error_messages error_messages_for
|
403
|
+
|
404
|
+
private
|
405
|
+
|
406
|
+
def bound?(*args)
|
407
|
+
args.first.is_a?(Symbol)
|
408
|
+
end
|
409
|
+
|
410
|
+
end
|