lucasefe-multi_helper 0.0.1

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.
Files changed (60) hide show
  1. data/README.rdoc +11 -0
  2. data/Rakefile +14 -0
  3. data/generators/full_layout/full_layout_generator.rb +47 -0
  4. data/generators/full_layout/templates/_flash_messages.html.haml +6 -0
  5. data/generators/full_layout/templates/_main_navigation.html.haml +6 -0
  6. data/generators/full_layout/templates/_secondary_navigation.html.haml +2 -0
  7. data/generators/full_layout/templates/_sidebar.html.haml +15 -0
  8. data/generators/full_layout/templates/_theme_switch.html.erb +29 -0
  9. data/generators/full_layout/templates/_user_navigation.html.erb +10 -0
  10. data/generators/full_layout/templates/javascripts/jquery-ui.js +273 -0
  11. data/generators/full_layout/templates/javascripts/jquery.corner.js +178 -0
  12. data/generators/full_layout/templates/javascripts/jquery.form.js +601 -0
  13. data/generators/full_layout/templates/javascripts/jquery.js +19 -0
  14. data/generators/full_layout/templates/javascripts/jquery.livequery.js +250 -0
  15. data/generators/full_layout/templates/javascripts/jquery.localscroll.js +104 -0
  16. data/generators/full_layout/templates/javascripts/jquery.scrollTo.js +150 -0
  17. data/generators/full_layout/templates/javascripts/layout.js +26 -0
  18. data/generators/full_layout/templates/layout.html.haml +36 -0
  19. data/generators/full_layout/templates/stylesheets/base.css +282 -0
  20. data/generators/full_layout/templates/stylesheets/overrides.css +11 -0
  21. data/generators/full_layout/templates/stylesheets/themes/bec/style.css +279 -0
  22. data/generators/full_layout/templates/stylesheets/themes/black-grey/style.css +171 -0
  23. data/generators/full_layout/templates/stylesheets/themes/default/style.css +233 -0
  24. data/generators/full_scaffold/README +11 -0
  25. data/generators/full_scaffold/full_scaffold_generator.rb +149 -0
  26. data/generators/full_scaffold/templates/controller.rb +13 -0
  27. data/generators/full_scaffold/templates/helper.rb +2 -0
  28. data/generators/full_scaffold/templates/migration.rb +15 -0
  29. data/generators/full_scaffold/templates/model.rb +2 -0
  30. data/generators/full_scaffold/templates/rspec/unit_spec.rb +11 -0
  31. data/generators/full_scaffold/templates/view__collection.haml +23 -0
  32. data/generators/full_scaffold/templates/view__form.haml +3 -0
  33. data/generators/full_scaffold/templates/view__search.haml +11 -0
  34. data/generators/full_scaffold/templates/view_edit.haml +9 -0
  35. data/generators/full_scaffold/templates/view_index.haml +8 -0
  36. data/generators/full_scaffold/templates/view_index.js.haml +1 -0
  37. data/generators/full_scaffold/templates/view_new.haml +7 -0
  38. data/generators/full_scaffold/templates/view_show.haml +10 -0
  39. data/icons/add.png +0 -0
  40. data/icons/arrow_undo.png +0 -0
  41. data/icons/cross.png +0 -0
  42. data/icons/error.png +0 -0
  43. data/icons/exclamation.png +0 -0
  44. data/icons/pencil.png +0 -0
  45. data/icons/tick.png +0 -0
  46. data/lib/multi_helper.rb +6 -0
  47. data/lib/multi_helper/form.rb +11 -0
  48. data/lib/multi_helper/form/README.markdown +119 -0
  49. data/lib/multi_helper/form/builder.rb +346 -0
  50. data/lib/multi_helper/form/helper.rb +41 -0
  51. data/lib/multi_helper/navigation.rb +6 -0
  52. data/lib/multi_helper/navigation/group.rb +36 -0
  53. data/lib/multi_helper/navigation/helper.rb +11 -0
  54. data/lib/multi_helper/navigation/item.rb +27 -0
  55. data/lib/multi_helper/navigation/renderer.rb +35 -0
  56. data/lib/multi_helper/vendor/validation_reflection.rb +73 -0
  57. data/lib/multi_helper/view.rb +49 -0
  58. data/multi_helper.gemspec +31 -0
  59. data/rails/init.rb +2 -0
  60. metadata +129 -0
@@ -0,0 +1,13 @@
1
+ class <%= controller_class_name %>Controller < ResourceController::Base
2
+ index.wants.js {render :layout => false}
3
+ private
4
+ def default_options_for(search)
5
+ { :per_page => 10, :order_as => "ASC" }.merge(search ||{})
6
+ end
7
+ def collection
8
+ @search = <%= model_name %>.new_search(default_options_for(params[:search]))
9
+ @search.per_page = 10
10
+ @<%= plural_name %>, @<%= plural_name %>_count = @search.all, @search.count
11
+ @<%= plural_name %>
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ module <%= controller_class_name %>Helper
2
+ end
@@ -0,0 +1,15 @@
1
+ class <%= migration_name %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= table_name %>, :force => true do |t|
4
+ <% for attribute in attributes -%>
5
+ t.<%= attribute.type %> :<%= attribute.name %>
6
+ <% end -%>
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :<%= table_name %>
14
+ end
15
+ end
@@ -0,0 +1,2 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '<%= '/..' * controller_class_nesting_depth %>/../spec_helper')
2
+
3
+ describe <%= class_name %> do
4
+ before(:each) do
5
+ @<%= file_name %> = <%= class_name %>.new
6
+ end
7
+
8
+ it "should be valid" do
9
+ @<%= file_name %>.should be_valid
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ #resultados
2
+ %table.table
3
+ %tr
4
+ <% for attribute in attributes -%>
5
+ %th<%= (attribute == attributes.first) ? ".first" : "" %>= order_by_link :<%= attribute.column.name %>
6
+ <% end -%>
7
+ %th
8
+ %th
9
+ %th.last
10
+ - <%= plural_name %>.each do |<%= singular_name %>|
11
+ %tr
12
+ <%- for attribute in attributes %>
13
+ %td= h <%= singular_name %>.<%= attribute.name %>
14
+ <%- end -%>
15
+ %td= link_to 'Show', object_url(<%= singular_name %>)
16
+ %td= link_to 'Edit', edit_object_url(<%= singular_name %>)
17
+ %td= link_to 'Destroy', object_url(<%= singular_name %>), :confirm => 'Are you sure?', :method => :delete
18
+ .actions-bar
19
+ .pagination
20
+ = page_links
21
+ = per_page_select
22
+ .clear
23
+
@@ -0,0 +1,3 @@
1
+ <%- for attribute in attributes -%>
2
+ = f.<%= attribute.field_type %> :<%= attribute.name %>
3
+ <% end -%>
@@ -0,0 +1,11 @@
1
+ - next_form_for @search, :html=>{:id => 'search', :class => 'form'} do |fs|
2
+
3
+ - fs.fields_for @search.conditions do |s|
4
+ <%- for attribute in attributes -%>
5
+ .group
6
+ %label.title <%= attribute.name.humanize %>
7
+ = s.<%= attribute.field_type %> :<%= attribute.name %>
8
+ <%- end -%>
9
+
10
+ = fs.submit "Buscar"
11
+
@@ -0,0 +1,9 @@
1
+ - text_block :title => "Editing <%= singular_name %>" do
2
+ - next_form_for(:<%= singular_name %>, :url => object_url, :html => { :method => :put, :class => 'form' }) do |f|
3
+ = render :partial => "form", :locals => { :f => f }
4
+ - f.buttons do |b|
5
+ = b.save
6
+ = b.cancel :url => collection_path
7
+
8
+ - content_for :sidebar do
9
+ = sidebar_link 'Show', object_url
@@ -0,0 +1,8 @@
1
+ - table_block :title => '<%= plural_name.humanize %>' do
2
+ = render :partial => '<%= plural_name %>', :object => @<%= plural_name %>
3
+
4
+ - content_for :search do
5
+ = render :partial => 'search'
6
+
7
+ - content_for :sidebar do
8
+ = sidebar_link 'New <%= singular_name %>', new_object_url
@@ -0,0 +1 @@
1
+ = render :partial => '<%= plural_name %>', :object => @<%= plural_name %>
@@ -0,0 +1,7 @@
1
+ - text_block :title => "New <%= singular_name %>" do
2
+ - next_form_for(@<%= singular_name %>, :url => collection_path, :html => {:class => 'form'}) do |f|
3
+ = render :partial => "form", :locals => { :f => f }
4
+ - f.buttons do |b|
5
+ = b.save
6
+ = b.cancel :url => collection_path
7
+
@@ -0,0 +1,10 @@
1
+ - text_block :title => "<%= singular_name.humanize %>" do
2
+ <% for attribute in attributes %>
3
+ %p
4
+ %strong <%= attribute.column.human_name %>:
5
+ =h @<%= singular_name %>.<%= attribute.name %>
6
+ <% end -%>
7
+
8
+ - content_for :sidebar do
9
+ = sidebar_link 'Edit', edit_object_url
10
+ = sidebar_link 'Back', collection_url
data/icons/add.png ADDED
Binary file
Binary file
data/icons/cross.png ADDED
Binary file
data/icons/error.png ADDED
Binary file
Binary file
data/icons/pencil.png ADDED
Binary file
data/icons/tick.png ADDED
Binary file
@@ -0,0 +1,6 @@
1
+ module MultiHelper
2
+ end
3
+
4
+ require "multi_helper/navigation"
5
+ require "multi_helper/form"
6
+ require "multi_helper/view"
@@ -0,0 +1,11 @@
1
+ require 'multi_helper/vendor/validation_reflection'
2
+ require 'multi_helper/form/helper'
3
+ require 'multi_helper/form/builder'
4
+
5
+ ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| html_tag }
6
+ ActionView::Base.send :include, MultiHelper::Form::Helper
7
+
8
+ MultiHelper::Form::Builder.default_options.merge!({
9
+ :required_signifier => '*',
10
+ :label_suffix => '',
11
+ })
@@ -0,0 +1,119 @@
1
+ AirBuddFormBuilder
2
+ ==================
3
+
4
+ A form builder that generates semantic HTML as advocated by Andy Budd in [CSS Mastery][1].
5
+
6
+ It generates [Wufoo-style][2] buttons and links for submitting the form, cancelling it, etc. These buttons and links use several icons from the [FAMFAMFAM set][3]. You can choose not to use them if you don't want to.
7
+
8
+ [1]: http://www.cssmastery.com
9
+ [2]: http://particletree.com/features/rediscovering-the-button-element/
10
+ [3]: http://famfamfam.com/lab/icons/silk/
11
+
12
+ Please send feedback to boss@airbladesoftware.com.
13
+
14
+
15
+ HAML
16
+ ====
17
+ Thanks to [David Baldwin][4], this form builder can be used with HAML.
18
+
19
+ [4]: http://www.baldwindigital.net
20
+
21
+
22
+ ERB Example
23
+ ===========
24
+
25
+ app/views/projects/new.html.erb:
26
+
27
+ <% next_form_for @project do |f| %>
28
+ <%= f.text_field :title, :required => true, :name => "Article's Title" %>
29
+ <% f.buttons do |b| %>
30
+ <%= b.save %>
31
+ <%= b.cancel :url => projects_path %>
32
+ <% end %>
33
+ <% end %>
34
+
35
+ This renders:
36
+
37
+ <form ...> <!-- standard Rails form element -->
38
+ <p class="text">
39
+ <label for="article_title">Article's Title:
40
+ <em class="required">(required)</em>
41
+ </label>
42
+ <input id="article_title" name="article[title]" type="text" value=""/>
43
+ </p>
44
+ <div class="buttons">
45
+ <button type="submit" class="positive"><img src="/images/icons/tick.png" alt=""/> Save</button>
46
+ <a href="/projects"><img src="/images/icons.pencil.png" alt=""/> Cancel</a>
47
+ </div>
48
+ </form>
49
+
50
+ And if the field's value is invalid:
51
+
52
+ <p class="error text">
53
+ <label for="article_title">Article's Title:
54
+ <em class="required">(required)</em>
55
+ <span class="feedback">can't be blank</span>
56
+ </label>
57
+ <input id="article_title" name="article[title]" type="text" value=""/>
58
+ </p>
59
+
60
+ See Mr Budd's good book for discussion of the HTML and the CSS to go with it.
61
+
62
+
63
+ Required fields
64
+ ===============
65
+
66
+ Thanks to Bill, the form builder automatically detects required fields (by looking for :validates_presence_of in the model) and marks them up appropriately.
67
+
68
+
69
+ Configuration
70
+ =============
71
+
72
+ Thanks to Dan Webb, whose [Enhanced Form Builder](http://svn.danwebb.net/external/rails/plugins/enhanced_form_builder/lib/enhanced_form_builder/form_builder.rb) configuration I borrowed.
73
+
74
+ You can configure the form builder at three levels: app-wide, per-form, and per-field. The per-field configuration differs slightly from the other two.
75
+
76
+ * App-wide:
77
+
78
+ config/initializers/form_builder.rb:
79
+
80
+ AirBlade::AirBudd::FormBuilder.default_options.merge!({
81
+ :required_signifier => '*',
82
+ :label_suffix => '',
83
+ })
84
+
85
+ * Per form:
86
+
87
+ In your form:
88
+
89
+ - next_form_for @member do |f|
90
+ - f.required_signifier = '*'
91
+ = f.text_field :name
92
+
93
+ * Per field:
94
+
95
+ On a form field:
96
+
97
+ = f.text_field :name, :required => true, :suffix => ''
98
+
99
+ See the comments in the form builder's code for the exact configuration options available.
100
+
101
+
102
+ To Do
103
+ =====
104
+
105
+ * Fix `country_select` so it handles priority countries and options. It's currently broken.
106
+ * Wrapper for `options_group_from_collection_for_select`.
107
+ * DRY way to show consistent form links, e.g. edit, outside a form.
108
+ - include `link_to_function`, `link_to_remote`, etc.
109
+ - Cf `AirBlade::AirBudd::FormHelper#link_to_form`.
110
+ - Do we need to wrap buttons/links in a div? (Probably semantically good to do so?)
111
+ * Two read-only field helpers: one for within a form, containing the value so it can be submitted, and one for the 'show' page, so we can use the same markup and CSS (c.f. http://tomayko.com/writings/administrative-debris)..
112
+ * Example CSS:
113
+ - for Wufoo-style buttons and links.
114
+ - for CSS Mastery XHTML.
115
+ * Summary error messages.
116
+ * Consider how to handle multiple actions, e.g. 'save & create another', 'save & keep editing'. See Brandon Keepers's [with_action plugin](http://opensoul.org/2007/7/16/handling-forms-with-multiple-buttons).
117
+
118
+
119
+ Copyright (c) 2007 Andrew Stewart, released under the MIT license.
@@ -0,0 +1,346 @@
1
+ module MultiHelper
2
+ module Form
3
+
4
+ class Builder < ActionView::Helpers::FormBuilder
5
+ include Haml::Helpers if defined? Haml # for compatibility
6
+ include ActionView::Helpers::TextHelper # so we can use concat
7
+ include ActionView::Helpers::CaptureHelper # so we can use capture
8
+ include ActionView::Helpers::TagHelper # so we can use concat
9
+
10
+ # App-wide form configuration.
11
+ # E.g. in config/initializers/form_builder.rb:
12
+ #
13
+ # AirBlade::AirBudd::FormBuilder.default_options[:required_signifier] = '*'
14
+ #
15
+ @@default_options = {
16
+ :required_signifier => '(required)',
17
+ :label_suffix => ':',
18
+ :capitalize_errors => true,
19
+ }
20
+ cattr_accessor :default_options
21
+
22
+ # Per-form configuration (overrides app-wide form configuration).
23
+ # E.g. in a form itself:
24
+ #
25
+ # - airbudd_form_for @member do |f|
26
+ # - f.required_signifier = '*'
27
+ # = f.text_field :name
28
+ # ...etc...
29
+ #
30
+ attr_writer *default_options.keys
31
+ default_options.keys.each do |field|
32
+ src = <<-END_SRC
33
+ def #{field}
34
+ @#{field} || default_options[:#{field}]
35
+ end
36
+ END_SRC
37
+ class_eval src, __FILE__, __LINE__
38
+ end
39
+
40
+ @@field_keys = [:hint, :required, :label, :addendum, :suffix]
41
+
42
+ alias_method :vanilla_hidden_field, :hidden_field
43
+
44
+ # Creates a glorified form field helper. It takes a form helper's usual
45
+ # arguments with an optional options hash:
46
+ #
47
+ # <%= form.text_field 'title',
48
+ # :required => true,
49
+ # :label => "Article's Title",
50
+ # :hint => "Try not to use the letter 'e'." %>
51
+ #
52
+ # The code above generates the following HTML. The :required entry in the hash
53
+ # triggers the <em/> element and the :label overwrites the default field label,
54
+ # 'title' in this case, with its value. The stanza is wrapped in a <p/> element.
55
+ #
56
+ # <p class="text">
57
+ # <label for="article_title">Article's Title:
58
+ # <em class="required">(required)</em>
59
+ # </label>
60
+ # <input id="article_title" name="article[title]" type="text" value=""/>
61
+ # <span class="hint">Try not to use the letter 'e'.</span>
62
+ # </p>
63
+ #
64
+ # If the field's value is invalid, the <p/> is marked so and a <span/> is added
65
+ # with the (in)validation message:
66
+ #
67
+ # <p class="error text">
68
+ # <label for="article_title">Article's Title:
69
+ # <em class="required">(required)</em>
70
+ # <span class="feedback">can't be blank</span>
71
+ # </label>
72
+ # <input id="article_title" name="article[title]" type="text" value=""/>
73
+ # <span class="hint">Try not to use the letter 'e'.</span>
74
+ # </p>
75
+ #
76
+ # You can also pass an :addendum option. This generates a <span/> between the
77
+ # <input/> and the hint. Typically you would use this to show a small icon
78
+ # for deleting the field.
79
+ def self.create_field_helper(field_helper)
80
+ src = <<-END
81
+ def #{field_helper}(method, options = {}, html_options = {})
82
+ attribs = attributes_for(method, '#{field_helper}')
83
+ attribs[:class] << " group"
84
+ @template.content_tag('div',
85
+ label_element(method, options, html_options) +
86
+ super(method, options.except(*@@field_keys)) +
87
+ addendum_element(options) +
88
+ hint_element(options),
89
+ attribs
90
+ )
91
+ end
92
+ END
93
+ class_eval src, __FILE__, __LINE__
94
+ end
95
+
96
+ def self.create_short_field_helper(field_helper)
97
+ src = <<-END
98
+ def #{field_helper}(method, options = {}, html_options = {})
99
+ attribs = attributes_for(method, '#{field_helper}')
100
+ attribs[:class] << " group"
101
+ @template.content_tag('p',
102
+ super(method, options.except(*@@field_keys)) +
103
+ label_element(method, options, html_options) +
104
+ hint_element(options), attribs
105
+ )
106
+ end
107
+ END
108
+ class_eval src, __FILE__, __LINE__
109
+ end
110
+
111
+ # Creates a hidden input field and a simple <span/> using the same
112
+ # pattern as other form fields.
113
+ def read_only_text_field(method_for_text_field, method_for_hidden_field = nil, options = {}, html_options = {})
114
+ method_for_hidden_field ||= method_for_text_field
115
+ @template.content_tag('p',
116
+ label_element(method_for_text_field, options, html_options) +
117
+ vanilla_hidden_field(method_for_hidden_field, options) +
118
+ @template.content_tag('span', object.send(method_for_text_field)) +
119
+ addendum_element(options) +
120
+ hint_element(options),
121
+ attributes_for(method_for_text_field, 'text_field')
122
+ )
123
+ end
124
+
125
+ # TODO: DRY this with self.create_field_helper above.
126
+ def self.create_collection_field_helper(field_helper)
127
+ src = <<-END
128
+ def #{field_helper}(method, choices, options = {}, html_options = {})
129
+ @template.content_tag('p',
130
+ label_element(method, options, html_options) +
131
+ super(method, choices, options.except(*@@field_keys)) +
132
+ addendum_element(options) +
133
+ hint_element(options),
134
+ attributes_for(method, '#{field_helper}')
135
+ )
136
+ end
137
+ END
138
+ class_eval src, __FILE__, __LINE__
139
+ end
140
+
141
+ def attributes_for(method, field_helper)
142
+ # FIXME: there must be a neater way than below. This is Ruby, after all.
143
+ ary = []
144
+ ary << 'error' if errors_for?(method)
145
+ ary << input_type_for(field_helper) unless input_type_for(field_helper).blank?
146
+ attrs = {}
147
+ attrs[:class] = ary.reject{ |x| x.blank? }.join(' ') unless ary.empty?
148
+ attrs
149
+ end
150
+
151
+ def input_type_for(field_helper)
152
+ case field_helper
153
+ when 'text_field'; 'text'
154
+ when 'text_area'; 'text'
155
+ when 'password_field'; 'password'
156
+ when 'file_field'; 'file'
157
+ when 'hidden_field'; 'hidden'
158
+ when 'check_box'; 'checkbox'
159
+ when 'radio_button'; 'radio'
160
+ when 'select'; 'select'
161
+ when 'date_select'; 'select'
162
+ when 'time_select'; 'select'
163
+ when 'country_select'; 'select'
164
+ else ''
165
+ end
166
+ end
167
+
168
+
169
+ # Beefs up the appropriate field helpers.
170
+ %w( text_field text_area password_field file_field
171
+ date_select time_select country_select ).each do |name|
172
+ create_field_helper name
173
+ end
174
+
175
+ # Beefs up the appropriate field helpers.
176
+ %w( check_box radio_button ).each do |name|
177
+ create_short_field_helper name
178
+ end
179
+
180
+ # Beefs up the appropriate field helpers.
181
+ %w( select ).each do |name|
182
+ create_collection_field_helper name
183
+ end
184
+
185
+
186
+ # Within the form's block you can get good buttons with:
187
+ #
188
+ # <% f.buttons do |b| %>
189
+ # <%= b.save %>
190
+ # <%= b.cancel %>
191
+ # <% end %>
192
+ #
193
+ # You can have save, cancel, edit and delete buttons.
194
+ # Each one takes an optional label. For example:
195
+ #
196
+ # <%= b.save :label => 'Update' %>
197
+ #
198
+ # See the documentation for the +button+ method for the
199
+ # options you can use.
200
+ #
201
+ # You could call the button method directly, e.g. <%= f.button %>,
202
+ # but then your button would not be wrapped with a div of class
203
+ # 'buttons'. The div is needed for the CSS.
204
+ def buttons(&block)
205
+ concat '<div class="buttons">'
206
+ yield self
207
+ concat '</div>'
208
+ end
209
+
210
+ # Buttons and links for REST actions. Actions that change
211
+ # state, i.e. save and delete, have buttons. Other actions
212
+ # have links.
213
+ #
214
+ # For visual feedback with colours and icons, save is seen
215
+ # as a positive action; delete is negative.
216
+ #
217
+ # type = :new|:save|:cancel|:edit|:delete
218
+ # TODO :all ?
219
+ #
220
+ # Options you can use are:
221
+ # :label - The label for the button or text for the link.
222
+ # Optional; defaults to capitalised purpose.
223
+ # :icon - Whether or not to show an icon to the left of the label.
224
+ # Optional; icon will be shown unless :icon set to false.
225
+ # :url - The URL to link to (only used in links).
226
+ # Optional; defaults to ''.
227
+ def button(purpose = :save, options = {}, html_options = {})
228
+ # TODO: DRY the :a and :button.
229
+ element, icon, nature = case purpose
230
+ when :new then [:a, 'add', 'positive']
231
+ when :save then [:button, 'tick', 'positive']
232
+ when :cancel then [:a, 'arrow_undo', nil ]
233
+ when :edit then [:a, 'pencil', nil ]
234
+ when :delete then [:button, 'cross', 'negative']
235
+ end
236
+ legend = ( (options[:icon] == false || options[:icon] == 'false') ?
237
+ '' :
238
+ "<img src='/images/icons/#{icon}.png' alt=''/> " ) +
239
+ (options[:label] || purpose.to_s.capitalize)
240
+
241
+ html_options.merge!(:class => nature)
242
+ if element == :button
243
+ html_options.merge!(:type => 'submit')
244
+ else
245
+ html_options.merge!(:href => (options[:url] || ''))
246
+ end
247
+
248
+ # TODO: separate button and link construction and use
249
+ # link_to to gain its functionality, e.g. :back?
250
+ @template.content_tag(element.to_s,
251
+ legend,
252
+ html_options)
253
+ end
254
+
255
+ def method_missing(*args, &block)
256
+ # Button method
257
+ if args.first.to_s =~ /^(new|save|cancel|edit|delete)$/
258
+ button args.shift, *args, &block
259
+ else
260
+ super
261
+ end
262
+ end
263
+
264
+ private
265
+
266
+ # Writes out a <label/> element for the given field.
267
+ # Options:
268
+ # - :required: text to indicate that field is required. Optional: if not given,
269
+ # field is not required. If set to true instead of a string, default indicator
270
+ # text is '(required)'.
271
+ # - :label: text wrapped by the <label/>. Optional (default is field's name).
272
+ # - :suffix: appended to the label. Optional (default is ':').
273
+ # - :capitalize: false if any error message should not be capitalised,
274
+ # true otherwise. Optional (default is true).
275
+ def label_element(field, options = {}, html_options = {})
276
+ return '' if options.has_key?(:label) && options[:label].nil?
277
+ text = options.delete(:label) || (@object.nil? ? field.to_s.humanize : @object.class.human_attribute_name(field.to_s))
278
+ suffix = options.delete(:suffix) || label_suffix
279
+ value = text + suffix
280
+ html_options[:class] ||= []
281
+ html_options[:class] << " title"
282
+ if (required = mandatory?(field, options.delete(:required)))
283
+ required = required_signifier if required == true
284
+ value += " <em class='required'>#{required}</em>"
285
+ end
286
+
287
+ html_options.stringify_keys!
288
+ html_options['for'] ||= "#{@object_name}_#{field}"
289
+
290
+ if errors_for? field
291
+ error_msg = @object.errors[field].to_a.to_sentence
292
+ option_capitalize = options.delete(:capitalize) || capitalize_errors
293
+ error_msg = error_msg.capitalize unless option_capitalize == 'false' or option_capitalize == false
294
+ value += %Q( <span class="feedback">#{error_msg}.</span>)
295
+ end
296
+
297
+ @template.content_tag :label, value, html_options
298
+ end
299
+
300
+ def mandatory?(method, override = nil)
301
+ return override unless override.nil?
302
+ # Leverage vendor/validation_reflection.rb
303
+ if @object.class.respond_to? :reflect_on_validations_for
304
+ @object.class.reflect_on_validations_for(method).any? { |v| v.macro == :validates_presence_of }
305
+ end
306
+ end
307
+
308
+ # Writes out a <span/> element with a hint for how to fill in a field.
309
+ # Options:
310
+ # - :hint: text for the hint. Optional.
311
+ def hint_element(options = {})
312
+ hint = options.delete :hint
313
+ if hint
314
+ @template.content_tag :span, hint, :class => 'hint'
315
+ else
316
+ ''
317
+ end
318
+ end
319
+
320
+ # Writes out a <span/> element with something that follows a field.
321
+ # Options:
322
+ # - :hint: text for the hint. Optional.
323
+ def addendum_element(options = {})
324
+ addendum = options.delete :addendum
325
+ if addendum
326
+ @template.content_tag :span, addendum, :class => 'addendum'
327
+ else
328
+ ''
329
+ end
330
+ end
331
+
332
+ def errors_for?(method)
333
+ @object && @object.respond_to?(:errors) && @object.errors[method]
334
+ end
335
+
336
+ def output_buffer
337
+ @template.output_buffer
338
+ end
339
+
340
+ def output_buffer=(buffer)
341
+ @template.output_buffer = buffer
342
+ end
343
+
344
+ end
345
+ end
346
+ end