nuatt-formtastic 0.2.2 → 0.2.3
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/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
|