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.
- data/README.rdoc +11 -0
- data/Rakefile +14 -0
- data/generators/full_layout/full_layout_generator.rb +47 -0
- data/generators/full_layout/templates/_flash_messages.html.haml +6 -0
- data/generators/full_layout/templates/_main_navigation.html.haml +6 -0
- data/generators/full_layout/templates/_secondary_navigation.html.haml +2 -0
- data/generators/full_layout/templates/_sidebar.html.haml +15 -0
- data/generators/full_layout/templates/_theme_switch.html.erb +29 -0
- data/generators/full_layout/templates/_user_navigation.html.erb +10 -0
- data/generators/full_layout/templates/javascripts/jquery-ui.js +273 -0
- data/generators/full_layout/templates/javascripts/jquery.corner.js +178 -0
- data/generators/full_layout/templates/javascripts/jquery.form.js +601 -0
- data/generators/full_layout/templates/javascripts/jquery.js +19 -0
- data/generators/full_layout/templates/javascripts/jquery.livequery.js +250 -0
- data/generators/full_layout/templates/javascripts/jquery.localscroll.js +104 -0
- data/generators/full_layout/templates/javascripts/jquery.scrollTo.js +150 -0
- data/generators/full_layout/templates/javascripts/layout.js +26 -0
- data/generators/full_layout/templates/layout.html.haml +36 -0
- data/generators/full_layout/templates/stylesheets/base.css +282 -0
- data/generators/full_layout/templates/stylesheets/overrides.css +11 -0
- data/generators/full_layout/templates/stylesheets/themes/bec/style.css +279 -0
- data/generators/full_layout/templates/stylesheets/themes/black-grey/style.css +171 -0
- data/generators/full_layout/templates/stylesheets/themes/default/style.css +233 -0
- data/generators/full_scaffold/README +11 -0
- data/generators/full_scaffold/full_scaffold_generator.rb +149 -0
- data/generators/full_scaffold/templates/controller.rb +13 -0
- data/generators/full_scaffold/templates/helper.rb +2 -0
- data/generators/full_scaffold/templates/migration.rb +15 -0
- data/generators/full_scaffold/templates/model.rb +2 -0
- data/generators/full_scaffold/templates/rspec/unit_spec.rb +11 -0
- data/generators/full_scaffold/templates/view__collection.haml +23 -0
- data/generators/full_scaffold/templates/view__form.haml +3 -0
- data/generators/full_scaffold/templates/view__search.haml +11 -0
- data/generators/full_scaffold/templates/view_edit.haml +9 -0
- data/generators/full_scaffold/templates/view_index.haml +8 -0
- data/generators/full_scaffold/templates/view_index.js.haml +1 -0
- data/generators/full_scaffold/templates/view_new.haml +7 -0
- data/generators/full_scaffold/templates/view_show.haml +10 -0
- data/icons/add.png +0 -0
- data/icons/arrow_undo.png +0 -0
- data/icons/cross.png +0 -0
- data/icons/error.png +0 -0
- data/icons/exclamation.png +0 -0
- data/icons/pencil.png +0 -0
- data/icons/tick.png +0 -0
- data/lib/multi_helper.rb +6 -0
- data/lib/multi_helper/form.rb +11 -0
- data/lib/multi_helper/form/README.markdown +119 -0
- data/lib/multi_helper/form/builder.rb +346 -0
- data/lib/multi_helper/form/helper.rb +41 -0
- data/lib/multi_helper/navigation.rb +6 -0
- data/lib/multi_helper/navigation/group.rb +36 -0
- data/lib/multi_helper/navigation/helper.rb +11 -0
- data/lib/multi_helper/navigation/item.rb +27 -0
- data/lib/multi_helper/navigation/renderer.rb +35 -0
- data/lib/multi_helper/vendor/validation_reflection.rb +73 -0
- data/lib/multi_helper/view.rb +49 -0
- data/multi_helper.gemspec +31 -0
- data/rails/init.rb +2 -0
- 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,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,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,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
|
data/lib/multi_helper.rb
ADDED
@@ -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
|