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.
@@ -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