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