nuatt-formtastic 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.textile +635 -0
- data/lib/formtastic.rb +24 -0
- data/lib/formtastic/form_builder.rb +75 -0
- data/lib/formtastic/helpers.rb +15 -0
- data/lib/formtastic/helpers/buttons_helper.rb +277 -0
- data/lib/formtastic/helpers/errors_helper.rb +124 -0
- data/lib/formtastic/helpers/fieldset_wrapper.rb +62 -0
- data/lib/formtastic/helpers/file_column_detection.rb +16 -0
- data/lib/formtastic/helpers/form_helper.rb +221 -0
- data/lib/formtastic/helpers/input_helper.rb +357 -0
- data/lib/formtastic/helpers/inputs_helper.rb +381 -0
- data/lib/formtastic/helpers/reflection.rb +12 -0
- data/lib/formtastic/helpers/semantic_form_helper.rb +11 -0
- data/lib/formtastic/html_attributes.rb +21 -0
- data/lib/formtastic/i18n.rb +32 -0
- data/lib/formtastic/inputs.rb +29 -0
- data/lib/formtastic/inputs/base.rb +50 -0
- data/lib/formtastic/inputs/base/associations.rb +33 -0
- data/lib/formtastic/inputs/base/choices.rb +88 -0
- data/lib/formtastic/inputs/base/collections.rb +94 -0
- data/lib/formtastic/inputs/base/database.rb +17 -0
- data/lib/formtastic/inputs/base/errors.rb +58 -0
- data/lib/formtastic/inputs/base/fileish.rb +23 -0
- data/lib/formtastic/inputs/base/grouped_collections.rb +77 -0
- data/lib/formtastic/inputs/base/hints.rb +31 -0
- data/lib/formtastic/inputs/base/html.rb +51 -0
- data/lib/formtastic/inputs/base/labelling.rb +53 -0
- data/lib/formtastic/inputs/base/naming.rb +54 -0
- data/lib/formtastic/inputs/base/options.rb +18 -0
- data/lib/formtastic/inputs/base/stringish.rb +30 -0
- data/lib/formtastic/inputs/base/timeish.rb +125 -0
- data/lib/formtastic/inputs/base/validations.rb +125 -0
- data/lib/formtastic/inputs/base/wrapping.rb +38 -0
- data/lib/formtastic/inputs/boolean_input.rb +87 -0
- data/lib/formtastic/inputs/check_boxes_input.rb +169 -0
- data/lib/formtastic/inputs/country_input.rb +66 -0
- data/lib/formtastic/inputs/date_input.rb +14 -0
- data/lib/formtastic/inputs/datetime_input.rb +9 -0
- data/lib/formtastic/inputs/email_input.rb +40 -0
- data/lib/formtastic/inputs/file_input.rb +42 -0
- data/lib/formtastic/inputs/hidden_input.rb +66 -0
- data/lib/formtastic/inputs/number_input.rb +72 -0
- data/lib/formtastic/inputs/numeric_input.rb +20 -0
- data/lib/formtastic/inputs/password_input.rb +40 -0
- data/lib/formtastic/inputs/phone_input.rb +41 -0
- data/lib/formtastic/inputs/radio_input.rb +146 -0
- data/lib/formtastic/inputs/search_input.rb +40 -0
- data/lib/formtastic/inputs/select_input.rb +208 -0
- data/lib/formtastic/inputs/string_input.rb +34 -0
- data/lib/formtastic/inputs/text_input.rb +47 -0
- data/lib/formtastic/inputs/time_input.rb +14 -0
- data/lib/formtastic/inputs/time_zone_input.rb +48 -0
- data/lib/formtastic/inputs/url_input.rb +40 -0
- data/lib/formtastic/localized_string.rb +96 -0
- data/lib/formtastic/railtie.rb +12 -0
- data/lib/formtastic/semantic_form_builder.rb +11 -0
- data/lib/formtastic/util.rb +25 -0
- data/lib/generators/formtastic/form/form_generator.rb +95 -0
- data/lib/generators/formtastic/install/install_generator.rb +23 -0
- data/lib/generators/templates/_form.html.erb +7 -0
- data/lib/generators/templates/_form.html.haml +5 -0
- data/lib/generators/templates/formtastic.css +145 -0
- data/lib/generators/templates/formtastic.rb +74 -0
- data/lib/generators/templates/formtastic_changes.css +14 -0
- data/lib/locale/en.yml +7 -0
- data/lib/tasks/verify_rcov.rb +44 -0
- metadata +206 -19
data/lib/formtastic.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'formtastic/railtie.rb' if defined?(Rails)
|
3
|
+
|
4
|
+
module Formtastic
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
autoload :FormBuilder
|
8
|
+
autoload :SemanticFormBuilder
|
9
|
+
autoload :Helpers
|
10
|
+
autoload :HtmlAttributes
|
11
|
+
autoload :I18n
|
12
|
+
autoload :Inputs
|
13
|
+
autoload :LocalizedString
|
14
|
+
autoload :Util
|
15
|
+
|
16
|
+
# @private
|
17
|
+
class UnknownInputError < NameError
|
18
|
+
end
|
19
|
+
|
20
|
+
# @private
|
21
|
+
class PolymorphicInputWithoutCollectionError < ArgumentError
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Formtastic
|
2
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
3
|
+
|
4
|
+
def self.configure(name, value = nil)
|
5
|
+
class_attribute(name)
|
6
|
+
self.send(:"#{name}=", value)
|
7
|
+
end
|
8
|
+
|
9
|
+
configure :custom_namespace
|
10
|
+
configure :default_text_field_size
|
11
|
+
configure :default_text_area_height, 20
|
12
|
+
configure :default_text_area_width
|
13
|
+
configure :all_fields_required_by_default, true
|
14
|
+
configure :include_blank_for_select_by_default, true
|
15
|
+
configure :required_string, proc { Formtastic::Util.html_safe(%{<abbr title="#{Formtastic::I18n.t(:required)}">*</abbr>}) }
|
16
|
+
configure :optional_string, ''
|
17
|
+
configure :inline_errors, :sentence
|
18
|
+
configure :label_str_method, :humanize
|
19
|
+
configure :collection_label_methods, %w[to_label display_name full_name name title username login value to_s]
|
20
|
+
configure :collection_value_methods, %w[id to_s]
|
21
|
+
configure :custom_inline_order, {}
|
22
|
+
configure :file_methods, [ :file?, :public_filename, :filename ]
|
23
|
+
configure :file_metadata_suffixes, ['content_type', 'file_name', 'file_size']
|
24
|
+
configure :priority_countries, ["Australia", "Canada", "United Kingdom", "United States"]
|
25
|
+
configure :i18n_lookups_by_default, true
|
26
|
+
configure :escape_html_entities_in_hints_and_labels, true
|
27
|
+
configure :default_commit_button_accesskey
|
28
|
+
configure :default_inline_error_class, 'inline-errors'
|
29
|
+
configure :default_error_list_class, 'errors'
|
30
|
+
configure :default_hint_class, 'inline-hints'
|
31
|
+
|
32
|
+
attr_reader :template
|
33
|
+
|
34
|
+
attr_reader :auto_index
|
35
|
+
|
36
|
+
include Formtastic::HtmlAttributes
|
37
|
+
|
38
|
+
include Formtastic::Helpers::InputHelper
|
39
|
+
include Formtastic::Helpers::InputsHelper
|
40
|
+
include Formtastic::Helpers::ButtonsHelper
|
41
|
+
include Formtastic::Helpers::ErrorsHelper
|
42
|
+
|
43
|
+
# A thin wrapper around `ActionView::Helpers::FormBuilder#fields_for` helper to set
|
44
|
+
# `:builder => Formtastic::FormBuilder` for nesting forms inside the builder. Can be used in
|
45
|
+
# the same way, but you'll also have access to the helpers in `Formtastic::FormBuilder`
|
46
|
+
# (such as {#input}, etc) inside the block.
|
47
|
+
#
|
48
|
+
# @see http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-fields_for ActionView::Helpers::FormBuilder#fields_for
|
49
|
+
# @see http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for ActionView::Helpers::FormHelper#fields_for
|
50
|
+
# @see Formtastic::Helpers::FormHelper#semantic_fields_for
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# <% semantic_form_for @post do |post| %>
|
54
|
+
# <% post.semantic_fields_for :author do |author| %>
|
55
|
+
# <% author.inputs :name %>
|
56
|
+
# <% end %>
|
57
|
+
# <% end %>
|
58
|
+
#
|
59
|
+
# <form ...>
|
60
|
+
# <fieldset class="inputs">
|
61
|
+
# <ol>
|
62
|
+
# <li class="string"><input type='text' name='post[author][name]' id='post_author_name' /></li>
|
63
|
+
# </ol>
|
64
|
+
# </fieldset>
|
65
|
+
# </form>
|
66
|
+
def semantic_fields_for(record_or_name_or_array, *args, &block)
|
67
|
+
opts = args.extract_options!
|
68
|
+
opts[:builder] ||= self.class
|
69
|
+
args.push(opts)
|
70
|
+
fields_for(record_or_name_or_array, *args, &block)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Formtastic
|
2
|
+
# @private
|
3
|
+
module Helpers
|
4
|
+
autoload :ButtonsHelper, 'formtastic/helpers/buttons_helper'
|
5
|
+
autoload :ErrorsHelper, 'formtastic/helpers/errors_helper'
|
6
|
+
autoload :FieldsetWrapper, 'formtastic/helpers/fieldset_wrapper'
|
7
|
+
autoload :FileColumnDetection, 'formtastic/helpers/file_column_detection'
|
8
|
+
autoload :FormHelper, 'formtastic/helpers/form_helper'
|
9
|
+
autoload :InputHelper, 'formtastic/helpers/input_helper'
|
10
|
+
autoload :InputsHelper, 'formtastic/helpers/inputs_helper'
|
11
|
+
autoload :LabelHelper, 'formtastic/helpers/label_helper'
|
12
|
+
autoload :SemanticFormHelper, 'formtastic/helpers/semantic_form_helper'
|
13
|
+
autoload :Reflection, 'formtastic/helpers/reflection'
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,277 @@
|
|
1
|
+
module Formtastic
|
2
|
+
module Helpers
|
3
|
+
|
4
|
+
# ButtonsHelper encapsulates the responsibilties of the {#buttons} and {#commit_button} helpers
|
5
|
+
# for submitting forms.
|
6
|
+
#
|
7
|
+
# {#buttons} is used to wrap the form's button(s) and actions in a `<fieldset>` and `<ol>`,
|
8
|
+
# with each item in the list containing the markup representing a single button.
|
9
|
+
#
|
10
|
+
# {#buttons} is usually called with a block containing a single {#commit_button} call:
|
11
|
+
#
|
12
|
+
# <%= semantic_form_for @post do |f| %>
|
13
|
+
# ...
|
14
|
+
# <%= f.buttons do %>
|
15
|
+
# <%= f.commit_button
|
16
|
+
# <% end %>
|
17
|
+
# <% end %>
|
18
|
+
#
|
19
|
+
# The HTML output will be something like:
|
20
|
+
#
|
21
|
+
# <form class="formtastic" method="post" action="...">
|
22
|
+
# ...
|
23
|
+
# <fieldset class="buttons">
|
24
|
+
# <ol>
|
25
|
+
# <li class="commit">
|
26
|
+
# <input type="submit" name="commit" value="Create Post" class="create">
|
27
|
+
# </li>
|
28
|
+
# </ol>
|
29
|
+
# </fieldset>
|
30
|
+
# </form>
|
31
|
+
#
|
32
|
+
# While this may seem slightly over-engineered, it is consistent with the way form inputs are
|
33
|
+
# handled, and makes room for other types of buttons and actions in future versions (such as
|
34
|
+
# cancel buttons or links, reset buttons and even alternate actions like 'save and continue
|
35
|
+
# editing').
|
36
|
+
#
|
37
|
+
# It's important to note that the `semantic_form_for` and {#buttons} blocks wrap the
|
38
|
+
# standard Rails `form_for` helper and form builder, so you have full access to every standard
|
39
|
+
# Rails form helper, with any HTML markup and ERB syntax, allowing you to "break free" from
|
40
|
+
# Formtastic when it doesn't suit to create your own buttons, links and actions:
|
41
|
+
#
|
42
|
+
# <%= semantic_form_for @post do |f| %>
|
43
|
+
# ...
|
44
|
+
# <%= f.buttons do %>
|
45
|
+
# <li class="save">
|
46
|
+
# <%= f.submit "Save" %>
|
47
|
+
# <li>
|
48
|
+
# <li class="cancel-link">
|
49
|
+
# Or <%= link_to "Cancel", posts_url %>
|
50
|
+
# <li>
|
51
|
+
# <% end %>
|
52
|
+
# <% end %>
|
53
|
+
#
|
54
|
+
# There are many other syntax variations and arguments to customize your form. See the
|
55
|
+
# full documentation of {#buttons} and {#commit_button} for details.
|
56
|
+
module ButtonsHelper
|
57
|
+
include Formtastic::Helpers::FieldsetWrapper
|
58
|
+
include Formtastic::LocalizedString
|
59
|
+
|
60
|
+
# Creates a fieldset and ol tag wrapping for use around a set of buttons. It can be
|
61
|
+
# called either with a block (in which you can do the usual Rails form stuff, HTML, ERB, etc),
|
62
|
+
# or with a list of named buttons. These two examples are functionally equivalent:
|
63
|
+
#
|
64
|
+
# # With a block:
|
65
|
+
# <% semantic_form_for @post do |f| %>
|
66
|
+
# ...
|
67
|
+
# <% f.buttons do %>
|
68
|
+
# <%= f.commit_button %>
|
69
|
+
# <% end %>
|
70
|
+
# <% end %>
|
71
|
+
#
|
72
|
+
# # With a list of fields:
|
73
|
+
# <% semantic_form_for @post do |f| %>
|
74
|
+
# <%= f.buttons :commit %>
|
75
|
+
# <% end %>
|
76
|
+
#
|
77
|
+
# # Output:
|
78
|
+
# <form ...>
|
79
|
+
# <fieldset class="inputs">
|
80
|
+
# <ol>
|
81
|
+
# <li class="commit">
|
82
|
+
# <input type="submit" ...>
|
83
|
+
# </li>
|
84
|
+
# </ol>
|
85
|
+
# </fieldset>
|
86
|
+
# </form>
|
87
|
+
#
|
88
|
+
# Only one type of named button is supported at this time (:commit), and it's assumed to be
|
89
|
+
# the default choice, so this is also functionally equivalent, but may change in the future:
|
90
|
+
#
|
91
|
+
# # With no args:
|
92
|
+
# <% semantic_form_for @post do |f| %>
|
93
|
+
# ...
|
94
|
+
# <%= f.buttons %>
|
95
|
+
# <% end %>
|
96
|
+
#
|
97
|
+
# While this may seem slightly over-engineered, it is consistent with the way form inputs are
|
98
|
+
# handled, and makes room for other types of buttons and actions in future versions (such as
|
99
|
+
# cancel buttons or links, reset buttons and even alternate actions like 'save and continue
|
100
|
+
# editing').
|
101
|
+
#
|
102
|
+
# All options except `:name` and `:title` are passed down to the fieldset as HTML
|
103
|
+
# attributes (`id`, `class`, `style`...). If provided, the `:name` or `:title` option is
|
104
|
+
# passed into a `<legend>` inside the `<fieldset>` to name the set of buttons.
|
105
|
+
#
|
106
|
+
# @example Quickly add button(s) to the form, accepting all default values, options and behaviors
|
107
|
+
# <% semantic_form_for @post do |f| %>
|
108
|
+
# ...
|
109
|
+
# <%= f.buttons %>
|
110
|
+
# <% end %>
|
111
|
+
#
|
112
|
+
# @example Specify which named buttons you want, accepting all default values, options and behaviors
|
113
|
+
# <% semantic_form_for @post do |f| %>
|
114
|
+
# ...
|
115
|
+
# <%= f.buttons :commit %>
|
116
|
+
# <% end %>
|
117
|
+
#
|
118
|
+
# @example Specify which named buttons you want, and name the fieldset
|
119
|
+
# <% semantic_form_for @post do |f| %>
|
120
|
+
# ...
|
121
|
+
# <%= f.buttons :commit, :name => "Actions" %>
|
122
|
+
# or
|
123
|
+
# <%= f.buttons :commit, :label => "Actions" %>
|
124
|
+
# <% end %>
|
125
|
+
#
|
126
|
+
# @example Get full control over the commit_button options
|
127
|
+
# <% semantic_form_for @post do |f| %>
|
128
|
+
# ...
|
129
|
+
# <%= f.buttons do %>
|
130
|
+
# <%= f.commit_button :label => "Go", :input_html => { ... }, :wrapper_html => { ... }
|
131
|
+
# <% end %>
|
132
|
+
# <% end %>
|
133
|
+
#
|
134
|
+
# @example Make your own custom buttons, links or actions with standard Rails helpers or HTML
|
135
|
+
# <% semantic_form_for @post do |f| %>
|
136
|
+
# ...
|
137
|
+
# <%= f.buttons do %>
|
138
|
+
# <li class="submit">
|
139
|
+
# <%= f.submit "Submit" %>
|
140
|
+
# </li>
|
141
|
+
# <li class="reset">
|
142
|
+
# <input type="reset" value="Reset">
|
143
|
+
# </li>
|
144
|
+
# <li class="cancel">
|
145
|
+
# <%= link_to "Cancel", posts_url %>
|
146
|
+
# </li>
|
147
|
+
# <% end %>
|
148
|
+
# <% end %>
|
149
|
+
#
|
150
|
+
# @example Add HTML attributes to the fieldset
|
151
|
+
# <% semantic_form_for @post do |f| %>
|
152
|
+
# ...
|
153
|
+
# <%= f.buttons :commit, :style => "border:1px;" %>
|
154
|
+
# or
|
155
|
+
# <%= f.buttons :style => "border:1px;" do %>
|
156
|
+
# ...
|
157
|
+
# <% end %>
|
158
|
+
# <% end %>
|
159
|
+
#
|
160
|
+
# @option *args :label [String, Symbol]
|
161
|
+
# Optionally specify text for the legend of the fieldset
|
162
|
+
#
|
163
|
+
# @option *args :name [String, Symbol]
|
164
|
+
# Optionally specify text for the legend of the fieldset (alias for `:label`)
|
165
|
+
#
|
166
|
+
# @todo document i18n keys
|
167
|
+
def buttons(*args, &block)
|
168
|
+
html_options = args.extract_options!
|
169
|
+
html_options[:class] ||= "buttons"
|
170
|
+
|
171
|
+
if block_given?
|
172
|
+
field_set_and_list_wrapping(html_options, &block)
|
173
|
+
else
|
174
|
+
args = [:commit] if args.empty?
|
175
|
+
contents = args.map { |button_name| send(:"#{button_name}_button") }
|
176
|
+
field_set_and_list_wrapping(html_options, contents)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Creates a submit input tag with the value "Save [model name]" (for existing records) or
|
181
|
+
# "Create [model name]" (for new records) by default. The output is an `<input>` tag with the
|
182
|
+
# `type` of `submit` and a class of either `create` or `update` (if Formtastic can determin if)
|
183
|
+
# the record is new or not) with `submit` as a fallback class. The submit button is wrapped in
|
184
|
+
# an `<li>` tag with a class of `commit`, and is intended to be rendered inside a {#buttons}
|
185
|
+
# block which wraps the button in a `fieldset` and `ol`.
|
186
|
+
#
|
187
|
+
# The textual value of the label can be changed from this default through the `:label`
|
188
|
+
# argument or through i18n.
|
189
|
+
#
|
190
|
+
# You can pass HTML attributes down to the `<input>` tag with the `:button_html` option, and
|
191
|
+
# pass HTML attributes to the wrapping `<li>` tag with the `:wrapper_html` option.
|
192
|
+
#
|
193
|
+
# @example Basic usage
|
194
|
+
# # form
|
195
|
+
# <%= semantic_form_for @post do |f| %>
|
196
|
+
# ...
|
197
|
+
# <%= f.buttons do %>
|
198
|
+
# <%= f.commit_button %>
|
199
|
+
# <% end %>
|
200
|
+
# <% end %>
|
201
|
+
#
|
202
|
+
# # output
|
203
|
+
# <form ...>
|
204
|
+
# ...
|
205
|
+
# <fieldset class="buttons">
|
206
|
+
# <input name="commit" type="submit" value="Create Post" class="create">
|
207
|
+
# </fieldset>
|
208
|
+
# </form>
|
209
|
+
#
|
210
|
+
# @example Set the value through the `:label` option
|
211
|
+
# <%= f.commit_button :label => "Go" %>
|
212
|
+
#
|
213
|
+
# @example Set the value through the optional first argument (like Rails' `f.submit`)
|
214
|
+
# <%= f.commit_button "Go" %>
|
215
|
+
#
|
216
|
+
# @example Pass HTML attributes down to the `<input>`
|
217
|
+
# <%= f.commit_button :button_html => { :class => 'pretty', :accesskey => 'g' } %>
|
218
|
+
# <%= f.commit_button :label => "Go", :button_html => { :class => 'pretty', :accesskey => 'g' } %>
|
219
|
+
# <%= f.commit_button "Go", :button_html => { :class => 'pretty', :accesskey => 'g' } %>
|
220
|
+
#
|
221
|
+
# @example Pass HTML attributes down to the `<li>` wrapper
|
222
|
+
# <%= f.commit_button :button_html => { :class => 'special', :id => 'whatever' } %>
|
223
|
+
# <%= f.commit_button :label => "Go", :button_html => { :class => 'special', :id => 'whatever' } %>
|
224
|
+
# <%= f.commit_button "Go", :button_html => { :class => 'special', :id => 'whatever' } %>
|
225
|
+
#
|
226
|
+
# @option *args :label [String, Symbol]
|
227
|
+
# Override the label text with a String or a symbold for an i18n translation key
|
228
|
+
#
|
229
|
+
# @option *args :button_html [Hash]
|
230
|
+
# Override or add to the HTML attributes to be passed down to the `<input>` tag
|
231
|
+
#
|
232
|
+
# @option *args :wrapper_html [Hash]
|
233
|
+
# Override or add to the HTML attributes to be passed down to the wrapping `<li>` tag
|
234
|
+
#
|
235
|
+
# @todo document i18n keys
|
236
|
+
# @todo strange that `:accesskey` seems to be supported in the top level args as well as `:button_html`
|
237
|
+
def commit_button(*args)
|
238
|
+
options = args.extract_options!
|
239
|
+
text = options.delete(:label) || args.shift
|
240
|
+
|
241
|
+
if @object && (@object.respond_to?(:persisted?) || @object.respond_to?(:new_record?))
|
242
|
+
key = @object.persisted? ? :update : :create
|
243
|
+
|
244
|
+
# Deal with some complications with ActiveRecord::Base.human_name and two name models (eg UserPost)
|
245
|
+
# ActiveRecord::Base.human_name falls back to ActiveRecord::Base.name.humanize ("Userpost")
|
246
|
+
# if there's no i18n, which is pretty crappy. In this circumstance we want to detect this
|
247
|
+
# fall back (human_name == name.humanize) and do our own thing name.underscore.humanize ("User Post")
|
248
|
+
if @object.class.model_name.respond_to?(:human)
|
249
|
+
object_name = @object.class.model_name.human
|
250
|
+
else
|
251
|
+
object_human_name = @object.class.human_name # default is UserPost => "Userpost", but i18n may do better ("User post")
|
252
|
+
crappy_human_name = @object.class.name.humanize # UserPost => "Userpost"
|
253
|
+
decent_human_name = @object.class.name.underscore.humanize # UserPost => "User post"
|
254
|
+
object_name = (object_human_name == crappy_human_name) ? decent_human_name : object_human_name
|
255
|
+
end
|
256
|
+
else
|
257
|
+
key = :submit
|
258
|
+
object_name = @object_name.to_s.send(label_str_method)
|
259
|
+
end
|
260
|
+
|
261
|
+
text = (localized_string(key, text, :action, :model => object_name) ||
|
262
|
+
Formtastic::I18n.t(key, :model => object_name)) unless text.is_a?(::String)
|
263
|
+
|
264
|
+
button_html = options.delete(:button_html) || {}
|
265
|
+
button_html.merge!(:class => [button_html[:class], key].compact.join(' '))
|
266
|
+
|
267
|
+
wrapper_html_class = ['commit'] # TODO: Add class reflecting on form action.
|
268
|
+
wrapper_html = options.delete(:wrapper_html) || {}
|
269
|
+
wrapper_html[:class] = (wrapper_html_class << wrapper_html[:class]).flatten.compact.join(' ')
|
270
|
+
|
271
|
+
accesskey = (options.delete(:accesskey) || default_commit_button_accesskey) unless button_html.has_key?(:accesskey)
|
272
|
+
button_html = button_html.merge(:accesskey => accesskey) if accesskey
|
273
|
+
template.content_tag(:li, Formtastic::Util.html_safe(submit(text, button_html)), wrapper_html)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Formtastic
|
2
|
+
module Helpers
|
3
|
+
module ErrorsHelper
|
4
|
+
include Formtastic::Helpers::FileColumnDetection
|
5
|
+
include Formtastic::Helpers::Reflection
|
6
|
+
include Formtastic::LocalizedString
|
7
|
+
|
8
|
+
INLINE_ERROR_TYPES = [:sentence, :list, :first]
|
9
|
+
|
10
|
+
# Generates an unordered list of error messages on the base object and optionally for a given
|
11
|
+
# set of named attribute. This is idea for rendering a block of error messages at the top of
|
12
|
+
# the form for hidden/special/virtual attributes (the Paperclip Rails plugin does this), or
|
13
|
+
# errors on the base model.
|
14
|
+
#
|
15
|
+
# A hash can be used as the last set of arguments to pass HTML attributes to the `<ul>`
|
16
|
+
# wrapper.
|
17
|
+
#
|
18
|
+
# @example A list of errors on the base model
|
19
|
+
# <%= semantic_form_for ... %>
|
20
|
+
# <%= f.semantic_errors %>
|
21
|
+
# ...
|
22
|
+
# <% end %>
|
23
|
+
#
|
24
|
+
# @example A list of errors on the base and named attributes
|
25
|
+
# <%= semantic_form_for ... %>
|
26
|
+
# <%= f.semantic_errors :something_special %>
|
27
|
+
# ...
|
28
|
+
# <% end %>
|
29
|
+
#
|
30
|
+
# @example A list of errors on the base model, with custom HTML attributes
|
31
|
+
# <%= semantic_form_for ... %>
|
32
|
+
# <%= f.semantic_errors :class => "awesome" %>
|
33
|
+
# ...
|
34
|
+
# <% end %>
|
35
|
+
#
|
36
|
+
# @example A list of errors on the base model and named attributes, with custom HTML attributes
|
37
|
+
# <%= semantic_form_for ... %>
|
38
|
+
# <%= f.semantic_errors :something_special, :something_else, :class => "awesome", :onclick => "Awesome();" %>
|
39
|
+
# ...
|
40
|
+
# <% end %>
|
41
|
+
def semantic_errors(*args)
|
42
|
+
html_options = args.extract_options!
|
43
|
+
full_errors = args.inject([]) do |array, method|
|
44
|
+
attribute = localized_string(method, method.to_sym, :label) || humanized_attribute_name(method)
|
45
|
+
errors = Array(@object.errors[method.to_sym]).to_sentence
|
46
|
+
errors.present? ? array << [attribute, errors].join(" ") : array ||= []
|
47
|
+
end
|
48
|
+
full_errors << @object.errors[:base]
|
49
|
+
full_errors.flatten!
|
50
|
+
full_errors.compact!
|
51
|
+
return nil if full_errors.blank?
|
52
|
+
html_options[:class] ||= "errors"
|
53
|
+
template.content_tag(:ul, html_options) do
|
54
|
+
Formtastic::Util.html_safe(full_errors.map { |error| template.content_tag(:li, Formtastic::Util.html_safe(error)) }.join)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Generates error messages for the given method, used for displaying errors right near the
|
59
|
+
# field for data entry. Uses the `:inline_errors` config to determin the right presentation,
|
60
|
+
# which may be an ordered list, a paragraph sentence containing all errors, or a paragraph
|
61
|
+
# containing just the first error. If configred to `:none`, no error is shown.
|
62
|
+
#
|
63
|
+
# See the `:inline_errors` config documentation for more details.
|
64
|
+
#
|
65
|
+
# This method is mostly used internally, but can be used in your forms when creating your own
|
66
|
+
# custom inputs, so it's been made public and aliased to `errors_on`.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# <%= semantic_form_for @post do |f| %>
|
70
|
+
# <li class='my-custom-text-input'>
|
71
|
+
# <%= f.label(:body) %>
|
72
|
+
# <%= f.text_field(:body) %>
|
73
|
+
# <%= f.errors_on(:body) %>
|
74
|
+
# </li>
|
75
|
+
# <% end %>
|
76
|
+
#
|
77
|
+
# @deprecated See the README for the currently supported approach to custom inputs.
|
78
|
+
def inline_errors_for(method, options = {})
|
79
|
+
ActiveSupport::Deprecation.warn('inline_errors_for and errors_on are deprecated and will be removed on or after version 2.1', caller)
|
80
|
+
if render_inline_errors?
|
81
|
+
errors = error_keys(method, options).map{|x| @object.errors[x] }.flatten.compact.uniq
|
82
|
+
send(:"error_#{inline_errors}", [*errors], options) if errors.any?
|
83
|
+
else
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
alias :errors_on :inline_errors_for
|
88
|
+
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
def error_keys(method, options)
|
93
|
+
@methods_for_error ||= {}
|
94
|
+
@methods_for_error[method] ||= begin
|
95
|
+
methods_for_error = [method.to_sym]
|
96
|
+
methods_for_error << file_metadata_suffixes.map{|suffix| "#{method}_#{suffix}".to_sym} if is_file?(method, options)
|
97
|
+
methods_for_error << [association_primary_key(method)] if association_macro_for_method(method) == :belongs_to
|
98
|
+
methods_for_error.flatten.compact.uniq
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def has_errors?(method, options)
|
103
|
+
methods_for_error = error_keys(method,options)
|
104
|
+
@object && @object.respond_to?(:errors) && methods_for_error.any?{|error| !@object.errors[error].blank?}
|
105
|
+
end
|
106
|
+
|
107
|
+
def render_inline_errors?
|
108
|
+
@object && @object.respond_to?(:errors) && Formtastic::FormBuilder::INLINE_ERROR_TYPES.include?(inline_errors)
|
109
|
+
end
|
110
|
+
|
111
|
+
def association_macro_for_method(method) #:nodoc:
|
112
|
+
reflection = reflection_for(method)
|
113
|
+
reflection.macro if reflection
|
114
|
+
end
|
115
|
+
|
116
|
+
def association_primary_key(method)
|
117
|
+
reflection = reflection_for(method)
|
118
|
+
reflection.options[:foreign_key] if reflection && !reflection.options[:foreign_key].blank?
|
119
|
+
:"#{method}_id"
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|