merb_helpers 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,655 +1,14 @@
1
- require "#{File.dirname(__FILE__)}/tag_helpers"
2
-
3
- module Merb
4
-
5
- # Merb helpers include several helpers used for simplifying view creation.
6
- # The available helpers currently include form tag helpers for both resource based and generic HTML form tag creation
7
- module Helpers
8
- # Provides a number of methods for creating form tags which may be used either with or without the presence of ORM specific models.
9
- # There are two types of form helpers: those that specifically work with model attributes and those that don't.
10
- # This helper deals with both model attributes and generic form tags. Model attributes generally end in "_control" such as +text_control+,
11
- # and generic tags end with "_field", such as +text_field+
12
- #
13
- # The core method of this helper, +form_for+, gives you the ability to create a form for a resource.
14
- # For example, let's say that you have a model <tt>Person</tt> and want to create a new instance of it:
15
- #
16
- # <% form_for :person, :action => url(:people) do %>
17
- # <%= text_control :first_name, :label => 'First Name' %>
18
- # <%= text_control :last_name, :label => 'Last Name' %>
19
- # <%= submit_button 'Create' %>
20
- # <% end %>
21
- #
22
- # The HTML generated for this would be:
23
- #
24
- # <form action="/people/create" method="post">
25
- # <label for="person_first_name">First Name</label>
26
- # <input id="person_first_name" name="person[first_name]" size="30" type="text" />
27
- # <label for="person_last_name">Last Name</label>
28
- # <input id="person_last_name" name="person[last_name]" size="30" type="text" />
29
- # <button type="submit">Create</button>
30
- # </form>
31
- #
32
- # You may also create a normal form using form_tag
33
- # <% form_tag(:action => url(:controller => "foo", :action => "bar", :id => 1)) do %>
34
- # <%= text_field :name => 'first_name', :label => 'First Name' %>
35
- # <%= submit_button 'Create' %>
36
- # <% end %>
37
- #
38
- # The HTML generated for this would be:
39
- #
40
- # <form action="/foo/bar/1" method="post">
41
- # <label for="first_name">First Name</label><input id="first_name" name="first_name" size="30" type="text" />
42
- # <button type="submit">Create</button>
43
- # </form>
44
- module Form
45
-
46
- # Provides a HTML formatted display of resource errors in an unordered list with a h2 form submission error
47
- # ==== Options
48
- # +build_li+:: Block for generating a list item for an error. It receives an instance of the error.
49
- # +html_class+:: Set for custom error div class default is <tt>submission_failed<tt>
50
- #
51
- # ==== Examples
52
- # <%= error_messages_for :person %>
53
- # <%= error_messages_for :person {|errors| "You can has probs nao: #{errors.size} of em!"}
54
- # <%= error_messages_for :person, lambda{|error| "<li class='aieeee'>#{error.join(' ')}"} %>
55
- # <%= error_messages_for :person, nil, 'bad_mojo' %>
56
- def error_messages_for(obj, build_li = nil, html_class='error')
57
- obj = self.instance_variable_get("@#{obj}") if obj.kind_of?(Symbol)
58
-
59
- return "" unless obj.respond_to?(:errors) && ! obj.errors.empty?
60
-
61
- if obj.errors.respond_to?(:each) # AR & DM
62
- build_li ||= lambda{|err| "<li>#{err.join(' ')}</li>"}
63
- error_collection = obj.errors
64
- else # Sequel
65
- build_li ||= lambda{|msg| "<li>#{msg}</li>"}
66
- error_collection = obj.errors.full_messages
67
- end
68
- error_count = error_collection.size
69
-
70
- header_message = if block_given?
71
- yield(obj.errors)
72
- else
73
- error_plurality = (error_count == 1 ? 'problem' : 'problems')
74
- "<h2>Form submission failed because of #{error_count} #{error_plurality}</h2>"
75
- end
76
-
77
- markup = %Q{
78
- <div class='#{html_class}'>
79
- #{header_message}
80
- <ul>
81
- }
82
-
83
- error_collection.each {|error, message| markup << build_li.call([error, message])}
84
-
85
- markup << %Q{
86
- </ul>
87
- </div>
88
- }
89
- end
90
-
91
- def obj_from_ivar_or_sym(obj)
92
- obj.is_a?(Symbol) ? instance_variable_get("@#{obj}") : obj
93
- end
94
-
95
- # Generates a form tag, which accepts a block that is not directly based on resource attributes
96
- #
97
- # <% form_tag(:action => url(:controller => "foo", :action => "bar", :id => 1)) do %>
98
- # <%= text_field :name => 'first_name', :label => 'First Name' %>
99
- # <%= submit_button 'Create' %>
100
- # <% end %>
101
- #
102
- # The HTML generated for this would be:
103
- #
104
- # <form action="/foo/bar/1" method="post">
105
- # <label for="first_name">First Name</label><input id="first_name" name="first_name" size="30" type="text" />
106
- # <input name="commit" type="submit" value="Create" />
107
- # </form>
108
- def form_tag(attrs = {}, &block)
109
- set_multipart_attribute!(attrs)
110
- fake_form_method = set_form_method(attrs)
111
- concat(open_tag("form", attrs), block.binding)
112
- concat(generate_fake_form_method(fake_form_method), block.binding) if fake_form_method
113
- concat(capture(&block), block.binding)
114
- concat("</form>", block.binding)
115
- end
116
-
117
- # Generates a resource specific form tag which accepts a block, this also provides automatic resource routing.
118
- # <% form_for :person, :action => url(:people) do %>
119
- # <%= text_control :first_name, :label => 'First Name' %>
120
- # <%= text_control :last_name, :label => 'Last Name' %>
121
- # <%= submit_button 'Create' %>
122
- # <% end %>
123
- #
124
- # The HTML generated for this would be:
125
- #
126
- # <form action="/people/create" method="post">
127
- # <label for="person[first_name]">First Name</label><input id="person_first_name" name="person[first_name]" size="30" type="text" />
128
- # <label for="person[last_name]">Last Name</label><input id="person_last_name" name="person[last_name]" size="30" type="text" />
129
- # <input name="commit" type="submit" value="Create" />
130
- # </form>
131
- def form_for(obj, attrs={}, &block)
132
- set_multipart_attribute!(attrs)
133
- obj = obj_from_ivar_or_sym(obj)
134
- fake_form_method = set_form_method(attrs, obj)
135
- concat(open_tag("form", attrs), block.binding)
136
- concat(generate_fake_form_method(fake_form_method), block.binding) if fake_form_method
137
- fields_for(obj, attrs, &block)
138
- concat("</form>", block.binding)
139
- end
140
-
141
- # Creates a scope around a specific resource object like form_for, but doesnt create the form tags themselves.
142
- # This makes fields_for suitable for specifying additional resource objects in the same form.
143
- #
144
- # ==== Examples
145
- # <% form_for :person, :action => url(:people) do %>
146
- # <%= text_control :first_name, :label => 'First Name' %>
147
- # <%= text_control :last_name, :label => 'Last Name' %>
148
- # <% fields_for :permission do %>
149
- # <%= checkbox_control :is_admin, :label => 'Administrator' %>
150
- # <% end %>
151
- # <%= submit_button 'Create' %>
152
- # <% end %>
153
- def fields_for(obj, attrs=nil, &block)
154
- @_obj ||= nil
155
- @_block ||= nil
156
- @_object_name ||= nil
157
- obj = obj_from_ivar_or_sym(obj)
158
- old_obj, @_obj = @_obj, obj
159
- old_block, @_block = @_block, block
160
- old_object_name, @_object_name = @_object_name, "#{@_obj.class}".snake_case
161
-
162
- concat(capture(&block), block.binding)
163
-
164
- @_obj, @_block, @_object_name = old_obj, old_block, old_object_name
165
- end
166
-
167
- def control_name(col)
168
- "#{@_object_name}[#{col}]"
169
- end
170
-
171
- def control_id(col)
172
- "#{@_object_name}_#{col}"
173
- end
174
-
175
- def control_value(col)
176
- escape_xml(@_obj.send(col))
177
- end
178
-
179
- def control_name_value(col, attrs)
180
- {:name => control_name(col), :value => control_value(col)}.merge(attrs)
181
- end
182
-
183
- # Provides a HTML text input tag based on a resource attribute.
184
- #
185
- # ==== Example
186
- # <% form_for :person, :action => url(:people) do %>
187
- # <%= text_control :first_name, :label => 'First Name' %>
188
- # <% end %>
189
- def text_control(col, attrs = {})
190
- errorify_field(attrs, col)
191
- attrs.merge!(:id => control_id(col))
192
- text_field(control_name_value(col, attrs))
193
- end
194
-
195
- # Provides a generic HTML text input tag.
196
- # Provides a HTML text input tag based on a resource attribute.
197
- #
198
- # ==== Example
199
- # <%= text_field :name => :fav_color, :label => 'Your Favorite Color' %>
200
- # # => <label for="fav_color">Your Favorite Color</label><input type="text" name="fav_color" id="fav_color"/>
201
- def text_field(attrs = {})
202
- attrs.merge!(:type => "text")
203
- attrs.add_html_class!("text")
204
- optional_label(attrs) { self_closing_tag("input", attrs) }
205
- end
206
-
207
- # Provides a HTML password input based on a resource attribute.
208
- # This is generally used within a resource block such as +form_for+.
209
- #
210
- # ==== Example
211
- # <%= password_control :password, :label => 'New Password' %>
212
- def password_control(col, attrs = {})
213
- attrs.merge!(:name => control_name(col), :id => control_id(col))
214
- errorify_field(attrs, col)
215
- password_field({:name => control_name(col)}.merge(attrs))
216
- end
217
-
218
- # Provides a generic HTML password input tag.
219
- #
220
- # ==== Example
221
- # <%= password_field :name => :password, :label => "Password" %>
222
- # # => <label for="password">Password</label><input type="password" name="password" id="password"/>
223
- def password_field(attrs = {})
224
- attrs.merge!(:type => 'password')
225
- attrs.add_html_class!("password")
226
- optional_label(attrs) { self_closing_tag("input", attrs) }
227
- end
228
-
229
- # translate column values from the db to boolean
230
- # nil, false, 0 and '0' are false. All others are true
231
- def col_val_to_bool(val)
232
- !(val == "0" || val == 0 || !val)
233
- end
234
- private :col_val_to_bool
235
-
236
- # Provides a HTML checkbox input based on a resource attribute.
237
- # This is generally used within a resource block such as +form_for+.
238
- #
239
- # ==== Example
240
- # <%= checkbox_control :is_activated, :label => "Activated?" %>
241
- def checkbox_control(col, attrs = {}, hidden_attrs={})
242
- errorify_field(attrs, col)
243
- method_name = @_obj.respond_to?(col) ? col : :"#{col}?"
244
- attrs.merge!(:checked => "checked") if col_val_to_bool(@_obj.send(method_name))
245
- attrs.merge!(:id => control_id(col))
246
- attrs = {:name => control_name(col), :value => control_value(method_name)}.merge(attrs)
247
- checkbox_field(attrs, hidden_attrs)
248
- end
249
-
250
- # Provides a generic HTML checkbox input tag.
251
- # There are two ways this tag can be generated, based on the
252
- # option :boolean. If not set to true, a "magic" input is generated.
253
- # Otherwise, an input is created that can be easily used for passing
254
- # an array of values to the application.
255
- #
256
- # ==== Example
257
- # <% checkbox_field :name => "is_activated", :value => "1" %>
258
- #
259
- # <% checkbox_field :name => "choices[]", :boolean => false, :value => "dog" %>
260
- # <% checkbox_field :name => "choices[]", :boolean => false, :value => "cat" %>
261
- # <% checkbox_field :name => "choices[]", :boolean => false, :value => "weasle" %>
262
- def checkbox_field(attrs = {}, hidden_attrs={})
263
- boolbox = true
264
- boolbox = false if ( attrs.has_key?(:boolean) and !attrs[:boolean] )
265
- attrs.delete(:boolean)
266
-
267
- if( boolbox )
268
- on = attrs.delete(:on) || 1
269
- off = attrs.delete(:off) || 0
270
- attrs[:value] = on if ( (v = attrs[:value]).nil? || v != "" )
271
- else
272
- # HTML-escape the value attribute
273
- attrs[:value] = escape_xml( attrs[:value] )
274
- end
275
-
276
- attrs.merge!(:type => :checkbox)
277
- attrs.add_html_class!("checkbox")
278
- (boolbox ? hidden_field({:name => attrs[:name], :value => off}.merge(hidden_attrs)) : '') + optional_label(attrs){self_closing_tag("input", attrs)}
279
- end
280
-
281
- # Returns a hidden input tag tailored for accessing a specified attribute (identified by +col+) on an object
282
- # resource within a +form_for+ resource block. Additional options on the input tag can be passed as a
283
- # hash with +attrs+. These options will be tagged onto the HTML as an HTML element attribute as in the example
284
- # shown.
285
- #
286
- # ==== Example
287
- # <%= hidden_control :identifier %>
288
- # # => <input id="person_identifier" name="person[identifier]" type="hidden" value="#{@person.identifier}" />
289
- def hidden_control(col, attrs = {})
290
- attrs.delete(:label)
291
- errorify_field(attrs, col)
292
- attrs[:class] ||= "hidden"
293
- hidden_field(control_name_value(col, attrs))
294
- end
295
-
296
- # Provides a generic HTML hidden input field.
297
- #
298
- # ==== Example
299
- # <%= hidden_field :name => "secret", :value => "some secret value" %>
300
- def hidden_field(attrs = {})
301
- attrs.delete(:label)
302
- attrs.merge!(:type => :hidden)
303
- attrs.add_html_class!("hidden")
304
- self_closing_tag("input", attrs)
305
- end
306
-
307
- # Provides a HTML radio input tag based on a resource attribute.
308
- #
309
- # ==== Example
310
- # <% form_for :person, :action => url(:people) do %>
311
- # <%= radio_control :first_name %>
312
- # <% end %>
313
- def radio_control(col, attrs = {})
314
- errorify_field(attrs, col)
315
- attrs.merge!(:id => control_id(col))
316
- val = @_obj.send(col)
317
- attrs.merge!(:checked => "checked") if val.to_s == attrs[:value]
318
- optional_label(attrs) { radio_field(control_name_value(col, attrs)) }
319
- end
320
-
321
- # Provides a radio group based on a resource attribute.
322
- # This is generally used within a resource block such as +form_for+.
323
- #
324
- # ==== Examples
325
- # <%# the labels are the options %>
326
- # <%= radio_group_control :my_choice, [5,6,7] %>
327
- #
328
- # <%# custom labels %>
329
- # <%= radio_group_control :my_choice, [{:value => 5, :label => "five"}] %>
330
- def radio_group_control(col, options = [], attrs = {})
331
- errorify_field(attrs, col)
332
- val = @_obj.send(col)
333
- ret = ""
334
- options.each do |opt|
335
- value, label = opt.is_a?(Hash) ? [opt.delete(:value), opt.delete(:label)] : [opt, opt]
336
- hash = {:name => "#{@_object_name}[#{col}]", :value => value, :label => label, :id => "#{control_id(col)}_#{value}" }
337
- hash.merge!(opt) if opt.is_a?(Hash)
338
- hash.merge!(:checked => "checked") if val.to_s == value.to_s
339
- ret << radio_field(hash)
340
- end
341
- ret
342
- end
343
-
344
- # Provides a generic HTML radio input tag.
345
- # Normally, you would use multipe +radio_field+.
346
- #
347
- # ==== Example
348
- # <%= radio_field :name => "radio_options", :value => "1", :label => "One" %>
349
- # <%= radio_field :name => "radio_options", :value => "2", :label => "Two" %>
350
- # <%= radio_field :name => "radio_options", :value => "3", :label => "Three", :checked => true %>
351
- def radio_field(attrs = {})
352
- attrs.merge!(:type => "radio")
353
- attrs.delete(:checked) unless attrs[:checked]
354
- attrs.add_html_class!("radio")
355
- optional_label(attrs){self_closing_tag("input", attrs)}
356
- end
357
-
358
- # Provides a HTML textarea based on a resource attribute
359
- # This is generally used within a resource block such as +form_for+
360
- #
361
- # ==== Example
362
- # <% text_area_control :comments, :label => "Comments"
363
- def text_area_control(col, attrs = {})
364
- attrs ||= {}
365
- errorify_field(attrs, col)
366
- attrs.merge!(:id => control_id(col))
367
- text_area_field(control_value(col), attrs.merge(:name => control_name(col)))
368
- end
369
-
370
- # Provides a generic HTML textarea tag.
371
- #
372
- # ==== Example
373
- # <% text_area_field "my comments", :name => "comments", :label => "Comments" %>
374
- def text_area_field(val, attrs = {})
375
- val ||=""
376
- optional_label(attrs) do
377
- open_tag("textarea", attrs) +
378
- val +
379
- "</textarea>"
380
- end
381
- end
382
-
383
- # Provides a generic HTML submit button.
384
- #
385
- # ==== Example
386
- # <% submit_button "Process" %>
387
- def submit_button(contents, attrs = {})
388
- contents ||= "Submit"
389
- attrs.merge!(:type => "submit")
390
- tag("button", contents, attrs)
391
- end
392
-
393
- # Provides a generic HTML label.
394
- #
395
- # ==== Example
396
- # <% label "Name", "", :for => "name" %>
397
- # # => <label for="name">Name</label>
398
- def label(name, contents = "", attrs = {})
399
- tag("label", name.to_s + contents, attrs)
400
- end
401
-
402
- # Provides a generic HTML select.
403
- #
404
- # ==== Options
405
- # +prompt+:: Adds an additional option tag with the provided string with no value.
406
- # +selected+:: The value of a selected object, which may be either a string or an array.
407
- # +include_blank+:: Adds an additional blank option tag with no value.
408
- # +collection+:: The collection for the select options
409
- # +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.
410
- # +value_method+:: Method to determine value of an option (as a symbol).
411
- def select_field(attrs = {})
412
- collection = attrs.delete(:collection)
413
- option_attrs = {
414
- :prompt => attrs.delete(:prompt),
415
- :selected => attrs.delete(:selected),
416
- :include_blank => attrs.delete(:include_blank),
417
- :text_method => attrs.delete(:text_method),
418
- :value_method => attrs.delete(:value_method)
419
- }
420
- optional_label(attrs) { open_tag('select', attrs) + options_from_collection_for_select(collection, option_attrs) + "</select>"}
421
- end
422
-
423
- # Provides a HTML select based on a resource attribute.
424
- # This is generally used within a resource block such as +form_for+.
425
- #
426
- # ==== Example
427
- # <% select_control :name, :collection => %w(one two three four) %>
428
- def select_control(col, attrs = {})
429
- attrs.merge!(:name => attrs[:name] || control_name(col))
430
- attrs.merge!(:id => attrs[:id] || control_id(col))
431
- attrs.merge!(:selected => attrs[:selected] || control_value(col))
432
- errorify_field(attrs, col)
433
- optional_label(attrs) { select_field(attrs) }
434
- end
435
-
436
- # Accepts a collection (hash, array, enumerable, your type) and returns a string of option tags.
437
- # Given a collection where the elements respond to first and last (such as a two-element array),
438
- # the "lasts" serve as option values and the "firsts" as option text. Hashes are turned into
439
- # this form automatically, so the keys become "firsts" and values become lasts. If selected is
440
- # specified, the matching "last" or element will get the selected option-tag. Selected may also
441
- # be an array of values to be selected when using a multiple select.
442
- #
443
- # ==== Examples
444
- # <%= options_for_select( [['apple','Apple Pie'],['orange','Orange Juice']], :selected => 'orange' )
445
- # => <option value="apple">Apple Pie</option><option value="orange" selected="selected">Orange Juice</option>
446
- #
447
- # <%= options_for_select( [['apple','Apple Pie'],['orange','Orange Juice']], :selected => ['orange','apple'], :prompt => 'Select One' )
448
- # => <option value="">Select One</option><option value="apple" selected="selected">Apple Pie</option><option value="orange" selected="selected">Orange Juice</option>
449
- #
450
- # ==== Options
451
- # +selected+:: The value of a selected object, which may be either a string or an array.
452
- # +prompt+:: Adds an addtional option tag with the provided string with no value.
453
- # +include_blank+:: Adds an additional blank option tag with no value.
454
- def options_for_select(collection, attrs = {})
455
- prompt = attrs.delete(:prompt)
456
- blank = attrs.delete(:include_blank)
457
- selected = attrs.delete(:selected)
458
- ret = String.new
459
- ret << tag('option', prompt, :value => '') if prompt
460
- ret << tag("option", '', :value => '') if blank
461
- unless collection.blank?
462
- if collection.is_a?(Hash)
463
- collection.each do |label,group|
464
- ret << open_tag("optgroup", :label => label.to_s.gsub(/\b[a-z]/) {|x| x.upcase}) +
465
- options_for_select(group, :selected => selected) + "</optgroup>"
466
- end
467
- else
468
- collection.each do |value,text|
469
- options = Array(selected).include?(value) ? {:selected => 'selected'} : {}
470
- ret << tag( 'option', text, {:value => value}.merge(options) )
471
- end
472
- end
473
- end
474
-
475
- return ret
476
- end
477
-
478
- # Returns a string of option tags that have been compiled by iterating over the collection and
479
- # assigning the the result of a call to the value_method as the option value and the text_method
480
- # as the option text. If selected_value is specified, the element returning a match on
481
- # the value_method option will get the selected option tag.
482
- #
483
- # This method also also supports the automatic generation of optgroup tags by using a hash.
484
- # ==== Examples
485
- # If we had a collection of people within a @project object, and want to use 'id' as the value, and 'name'
486
- # as the option content we could do something similar to this;
487
- #
488
- # <%= options_from_collection_for_select(@project.people, :value_method => "id", :text_method => "name") %>
489
- # The iteration of the collection would create options in this manner;
490
- # => <option value="#{person.id}">#{person.name}</option>
491
- #
492
- # <% @people = Person.find(:all).group_by( &:state )
493
- # <%= options_for_select(@people, :text_method => 'full_name', :value_method => 'id', :selected => 3) %>
494
- # => <optgroup label="Washington"><option value="1">Josh Martin</option><option value="2">John Doe</option></optgroup>
495
- # => <optgroup label="Idaho"><option value="3" selected="selected">Jane Doe</option>
496
- #
497
- # ==== Options
498
- # +text_method+:: Defines the method which will be used to provide the text of the option tags (required)
499
- # +value_method+:: Defines the method which will be used to provide the value of the option tags (required)
500
- # +selected+:: The value of a selected object, may be either a string or an array.
501
- def options_from_collection_for_select(collection, attrs = {})
502
- prompt = attrs.delete(:prompt)
503
- blank = attrs.delete(:include_blank)
504
- ret = String.new
505
- if collection.is_a?(Hash)
506
- ret << tag("option", prompt, :value => '') if prompt
507
- ret << tag("option", '', :value => '') if blank
508
- collection.each do |label, group|
509
- # .gsub(/_/, " ").gsub(/\b[a-z]/) {|x| x.upcase}) == .humanize.titleize, which is no longer in -core
510
- ret << open_tag("optgroup", :label => label.to_s.gsub(/_/, " ").gsub(/\b[a-z]/) {|x| x.upcase}) +
511
- options_from_collection_for_select(group, attrs) + "</optgroup>"
512
- end
513
- return ret
514
- else
515
- text_method = attrs[:text_method]
516
- value_method = attrs[:value_method]
517
- selected_value = attrs[:selected]
518
-
519
- text_method ||= :to_s
520
- value_method ||= text_method
521
-
522
- options_for_select((collection || []).inject([]) { |options, object|
523
- options << [ object.send(value_method), object.send(text_method) ] },
524
- :selected => selected_value, :include_blank => blank, :prompt => prompt
525
- )
526
- end
527
- end
528
-
529
- # Provides the ability to create quick fieldsets as blocks for your forms.
530
- #
531
- # ==== Example
532
- # <% fieldset :legend => 'Customer Options' do -%>
533
- # ...your form elements
534
- # <% end -%>
535
- #
536
- # => <fieldset><legend>Customer Options</legend>...your form elements</fieldset>
537
- #
538
- # ==== Options
539
- # +legend+:: The name of this fieldset which will be provided in a HTML legend tag.
540
- def fieldset(attrs={}, &block)
541
- legend = attrs.delete(:legend)
542
- concat( open_tag('fieldset', attrs), block.binding )
543
- concat( tag('legend', legend), block.binding ) if legend
544
- concat(capture(&block), block.binding)
545
- concat( "</fieldset>", block.binding)
546
- end
547
-
548
- # Provides a HTML file input for a resource attribute.
549
- # This is generally used within a resource block such as +form_for+.
550
- #
551
- # ==== Example
552
- # <% file_control :file, :label => "File" %>
553
- def file_control(col, attrs = {})
554
- errorify_field(attrs, col)
555
- file_field(control_name_value(col, attrs))
556
- end
557
-
558
- # Provides a HTML file input
559
- #
560
- # ==== Example
561
- # <% file_field :name => "file", :label => "File" %>
562
- def file_field(attrs = {})
563
- attrs.merge!(:type => "file")
564
- attrs.add_html_class!("file")
565
- optional_label(attrs) { self_closing_tag("input", attrs) }
566
- end
567
-
568
- def submit_field(attrs = {})
569
- attrs.merge!(:type => :submit)
570
- attrs[:name] ||= "submit"
571
- self_closing_tag("input", attrs)
572
- end
573
-
574
- # Generates a delete button inside of a form.
575
- #
576
- # <%= delete_button :news_post, @news_post, 'Remove' %>
577
- # <%= delete_button('/posts/24/comments/10') %>
578
- #
579
- # The HTML generated for this would be:
580
- #
581
- # <form method="post" action="/news_posts/4">
582
- # <input type="hidden" value="delete" name="_method"/>
583
- # <button type="submit">Remove</button>
584
- # </form>
585
- #
586
- # <form method="post" action="/posts/24/comments/10">
587
- # <input type="hidden" value="delete" name="_method"/>
588
- # <button type="submit">Remove</button>
589
- # </form>
590
- def delete_button(symbol_or_string, obj = nil, contents = 'Delete', form_attrs = {}, button_attrs = {})
591
- obj ||= instance_variable_get("@#{symbol_or_string}") if symbol_or_string.kind_of?(Symbol)
592
-
593
- button_attrs[:type] = :submit
594
-
595
- form_attrs.merge! :action => symbol_or_string.kind_of?(Symbol) ? url(symbol_or_string, obj) : symbol_or_string, :method => :delete
596
-
597
- fake_form_method = set_form_method(form_attrs, obj)
598
-
599
- button = ''
600
- button << open_tag(:form, form_attrs)
601
- button << generate_fake_form_method(fake_form_method)
602
- button << tag(:button, contents, button_attrs)
603
- button << '</form>'
604
- button
605
- end
606
-
607
- private
608
- # Fake out the browser to send back the method for RESTful stuff.
609
- # Fall silently back to post if a method is given that is not supported here
610
- def set_form_method(options = {}, obj = nil)
611
- options[:method] ||= ((obj && obj.respond_to?(:new_record?) && !obj.new_record?) ? :put : :post)
612
- if ![:get,:post].include?(options[:method])
613
- fake_form_method = options[:method] if [:put, :delete].include?(options[:method])
614
- options[:method] = :post
615
- end
616
- fake_form_method
617
- end
618
-
619
- def generate_fake_form_method(fake_form_method)
620
- fake_form_method ? hidden_field(:name => "_method", :value => "#{fake_form_method}") : ""
621
- end
622
-
623
- def optional_label(attrs = {})
624
- label = attrs.delete(:label) if attrs
625
- if label
626
- title = label.is_a?(Hash) ? label.delete(:title) : label
627
- named = attrs[:id].blank? ? {} : {:for => attrs[:id]}
628
- align = label.delete(:align) if label.is_a?(Hash)
629
- align ||= ['radio', 'checkbox'].include?(attrs[:type].to_s) ? :right : :left
630
- label_tag = label(title, '', label.is_a?(Hash) ? label.merge(named) : named)
631
- if align && align.to_sym == :right
632
- yield + label_tag
633
- else
634
- label_tag + yield
635
- end
636
- else
637
- yield
638
- end
639
- end
640
-
641
- def errorify_field(attrs, col)
642
- attrs.add_html_class!("error") if @_obj.respond_to?(:errors) && @_obj.errors.on(col)
643
- end
644
-
645
- def set_multipart_attribute!(attrs = {})
646
- attrs.merge!( :enctype => "multipart/form-data" ) if attrs.delete(:multipart)
647
- end
648
-
649
- end
650
- end
651
- end
1
+ load File.dirname(__FILE__) / "form" / "helpers.rb"
2
+ load File.dirname(__FILE__) / "form" / "builder.rb"
652
3
 
653
4
  class Merb::Controller
5
+ class_inheritable_accessor :_form_class
654
6
  include Merb::Helpers::Form
655
7
  end
8
+
9
+ Merb::BootLoader.after_app_loads do
10
+ class Merb::Controller
11
+ self._form_class =
12
+ Object.full_const_get(Merb::Plugins.config[:helpers][:form_class]) rescue Merb::Helpers::Form::Builder::ResourcefulFormWithErrors
13
+ end
14
+ end