2009-11-18 18:50:43 -05:00
|
|
|
module SimpleForm
|
|
|
|
class FormBuilder < ActionView::Helpers::FormBuilder
|
2009-12-10 16:52:23 -05:00
|
|
|
attr_reader :template, :object_name, :object, :attribute, :column, :input_type, :options
|
2009-12-09 13:55:39 -05:00
|
|
|
|
2009-12-10 16:52:23 -05:00
|
|
|
# Basic input helper, combines all components in the stack to generate input
|
|
|
|
# html based on options the user define and some guesses through
|
2009-12-10 12:57:24 -05:00
|
|
|
# database column information. By default a call to input will generate
|
|
|
|
# label + input + hint (when defined) + errors (when exists), and all can be
|
|
|
|
# configured inside a wrapper html.
|
2009-12-10 16:52:23 -05:00
|
|
|
#
|
2009-12-10 12:57:24 -05:00
|
|
|
# Examples:
|
2009-12-10 16:52:23 -05:00
|
|
|
#
|
2009-12-10 12:57:24 -05:00
|
|
|
# # Imagine @user has error "can't be blank" on name
|
|
|
|
# simple_form_for @user do |f|
|
|
|
|
# f.input :name, :hint => 'My hint'
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# This is the output html (only the input portion, not the form):
|
|
|
|
# <label class="string required" for="user_name"><abbr title="required">*</abbr> Super User Name!</label>
|
2009-12-10 16:52:23 -05:00
|
|
|
# <input class="string required" id="user_name" maxlength="100" name="user[name]" size="100" type="text" value="Carlos" />
|
2009-12-10 12:57:24 -05:00
|
|
|
# <span class="hint">My hint</span>
|
|
|
|
# <span class="error">can't be blank</span>
|
|
|
|
#
|
|
|
|
# Each database type will render a default input, based on some mappings and
|
|
|
|
# heuristic to determine which is the best option.
|
2009-12-10 16:52:23 -05:00
|
|
|
#
|
2009-12-10 12:57:24 -05:00
|
|
|
# You have some options for the input to enable/disable some functions:
|
|
|
|
#
|
2009-12-10 16:52:23 -05:00
|
|
|
# :as => allows you to define the input type you want, for instance you
|
|
|
|
# can use it to generate a text field for a date column.
|
|
|
|
#
|
|
|
|
# :required => defines whether this attribute is required or not. True
|
|
|
|
# by default.
|
|
|
|
#
|
|
|
|
# The fact SimpleForm is built in components allow the interface to be unified.
|
|
|
|
# So, for instance, if you need to disable :hint for a given input, you can pass
|
|
|
|
# :hint => false. The same works for :error, :label and :wrapper.
|
|
|
|
#
|
|
|
|
# Besides the html for any component can be changed. So, if you want to change
|
|
|
|
# the label html you just need to give a hash to :label_html. To configure the
|
|
|
|
# input html, supply :input_html instead and so on.
|
|
|
|
#
|
|
|
|
# == Options
|
|
|
|
#
|
|
|
|
# Some inputs, as datetime, time and select allow you to give extra options, like
|
|
|
|
# prompt and/or include blank. Such options are given in the :options key.
|
|
|
|
#
|
|
|
|
# f.input :created_at, :options => { :include_blank => true }
|
|
|
|
#
|
|
|
|
# == Collection
|
|
|
|
#
|
|
|
|
# When playing with collections (:radio and :select inputs), you have three extra
|
|
|
|
# options:
|
|
|
|
#
|
|
|
|
# :collection => use to determine the collection to generate the radio or select
|
|
|
|
#
|
|
|
|
# :label_method => the method to apply on the array collection to get the label
|
|
|
|
#
|
|
|
|
# :value_method => the method to apply on the array collection to get the value
|
|
|
|
#
|
2009-11-19 16:26:16 -05:00
|
|
|
def input(attribute, options={})
|
2009-12-10 16:52:23 -05:00
|
|
|
define_simple_form_attributes(attribute, options)
|
2009-12-08 08:48:31 -05:00
|
|
|
|
2009-12-10 08:01:44 -05:00
|
|
|
component = SimpleForm.terminator
|
|
|
|
SimpleForm.components.reverse.each do |klass|
|
|
|
|
next if @options[klass.basename] == false
|
|
|
|
component = klass.new(self, component)
|
2009-12-09 14:41:20 -05:00
|
|
|
end
|
2009-12-10 08:01:44 -05:00
|
|
|
component.call
|
2009-11-19 16:26:16 -05:00
|
|
|
end
|
|
|
|
|
2009-12-10 15:03:27 -05:00
|
|
|
# Creates a button:
|
|
|
|
#
|
|
|
|
# form_for @user do |f|
|
|
|
|
# f.button :submit
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# If the record is a new_record?, it will create a button with label "Create User",
|
|
|
|
# otherwise it will create with label "Update User". You can overwrite the label
|
|
|
|
# giving a second parameter or giving :label.
|
|
|
|
#
|
|
|
|
# f.button :submit, "Create a new user"
|
|
|
|
# f.button :submit, :label => "Create a new user"
|
|
|
|
#
|
|
|
|
# button is actually just a wrapper that adds a default text, that said, f.button
|
|
|
|
# above is just calling:
|
|
|
|
#
|
|
|
|
# submit_tag "Create a new user"
|
|
|
|
#
|
|
|
|
# All options given to button are given straight to submit_tag. That said, you can
|
|
|
|
# use :confirm normally:
|
|
|
|
#
|
|
|
|
# f.button :submit, :confirm => "Are you sure?"
|
|
|
|
#
|
|
|
|
# And if you want to use image_submit_tag, just give it as an option:
|
|
|
|
#
|
|
|
|
# f.button :image_submit, "/images/foo/bar.png"
|
|
|
|
#
|
|
|
|
# This comes with a bonus that any method added to your ApplicationController can
|
|
|
|
# be used by SimpleForm, as long as it ends with _tag. So is quite easy to customize
|
|
|
|
# your buttons.
|
|
|
|
#
|
|
|
|
def button(type, *args)
|
|
|
|
options = args.extract_options!
|
|
|
|
value = args.first || options.delete(:label)
|
|
|
|
|
|
|
|
value ||= begin
|
|
|
|
if @object
|
|
|
|
key = @object.new_record? ? :create : :update
|
|
|
|
model = @object.class.human_name if @object.class.respond_to?(:human_name)
|
|
|
|
end
|
|
|
|
key ||= :submit
|
|
|
|
model ||= @object_name.to_s.humanize
|
|
|
|
|
|
|
|
I18n.t(:"simple_form.#{key}", :model => model, :default => "#{key.to_s.humanize} #{model}")
|
|
|
|
end
|
|
|
|
|
|
|
|
@template.send(:"#{type}_tag", value, options)
|
|
|
|
end
|
|
|
|
|
2009-12-10 12:57:24 -05:00
|
|
|
# Creates an error tag based on the given attribute, only when the attribute
|
2009-12-10 16:52:23 -05:00
|
|
|
# contains errors. All the given options are sent as :error_html.
|
|
|
|
#
|
|
|
|
# == Examples
|
|
|
|
#
|
|
|
|
# f.error :name
|
|
|
|
# f.error :name, :id => "cool_error"
|
2009-12-10 17:11:15 -05:00
|
|
|
#
|
2009-12-10 16:52:23 -05:00
|
|
|
def error(attribute, options={})
|
|
|
|
define_simple_form_attributes(attribute, :error_html => options)
|
2009-12-10 10:49:17 -05:00
|
|
|
SimpleForm::Components::Error.new(self, SimpleForm.terminator).call
|
|
|
|
end
|
|
|
|
|
2009-12-10 16:52:23 -05:00
|
|
|
# Creates a hint tag for the given attribute. Accepts a symbol indicating
|
|
|
|
# an attribute for I18n lookup or a string. All the given options are sent
|
|
|
|
# as :hint_html.
|
|
|
|
#
|
|
|
|
# == Examples
|
|
|
|
#
|
|
|
|
# f.hint :name # Do I18n lookup
|
|
|
|
# f.hint :name, :id => "cool_hint"
|
|
|
|
# f.hint "Don't forget to accept this"
|
|
|
|
#
|
|
|
|
def hint(attribute, options={})
|
|
|
|
attribute, options[:hint] = nil, attribute if attribute.is_a?(String)
|
|
|
|
define_simple_form_attributes(attribute, :hint => options.delete(:hint), :hint_html => options)
|
2009-12-10 10:49:17 -05:00
|
|
|
SimpleForm::Components::Hint.new(self, SimpleForm.terminator).call
|
|
|
|
end
|
|
|
|
|
2009-12-10 12:57:24 -05:00
|
|
|
# Creates a default label tag for the given attribute. You can give a label
|
2009-12-10 16:52:23 -05:00
|
|
|
# through the :label option or using i18n. All the given options are sent
|
|
|
|
# as :label_html.
|
|
|
|
#
|
|
|
|
# == Examples
|
|
|
|
#
|
|
|
|
# f.label :name # Do I18n lookup
|
|
|
|
# f.label :name, "Name" # Same behavior as Rails, do not add required tag
|
|
|
|
# f.label :name, :label => "Name" # Same as above, but adds required tag
|
|
|
|
#
|
|
|
|
# f.label :name, :required => false
|
|
|
|
# f.label :name, :id => "cool_label"
|
|
|
|
#
|
|
|
|
def label(attribute, *args)
|
|
|
|
return super if args.first.is_a?(String)
|
|
|
|
options = args.extract_options!
|
|
|
|
define_simple_form_attributes(attribute, :label => options.delete(:label),
|
|
|
|
:label_html => options, :required => options.delete(:required))
|
2009-12-10 10:49:17 -05:00
|
|
|
SimpleForm::Components::Label.new(self, SimpleForm.terminator).call
|
|
|
|
end
|
|
|
|
|
2009-12-09 20:57:05 -05:00
|
|
|
private
|
2009-12-08 11:49:14 -05:00
|
|
|
|
2009-12-10 12:57:24 -05:00
|
|
|
# Setup default simple form attributes.
|
2009-12-10 16:52:23 -05:00
|
|
|
def define_simple_form_attributes(attribute, options)
|
|
|
|
@options = options
|
2009-12-10 10:49:17 -05:00
|
|
|
|
2009-12-10 16:52:23 -05:00
|
|
|
if @attribute = attribute
|
|
|
|
@column = find_attribute_column
|
|
|
|
@input_type = default_input_type
|
|
|
|
end
|
2009-12-10 10:49:17 -05:00
|
|
|
end
|
|
|
|
|
2009-12-10 12:57:24 -05:00
|
|
|
# Attempt to guess the better input type given the defined options. By
|
|
|
|
# default alwayls fallback to the user :as option, or to a :select when a
|
|
|
|
# collection is given.
|
2009-12-10 08:01:44 -05:00
|
|
|
def default_input_type
|
|
|
|
return @options[:as].to_sym if @options[:as]
|
|
|
|
return :select if @options[:collection]
|
2009-12-09 20:11:57 -05:00
|
|
|
|
2009-12-10 16:52:23 -05:00
|
|
|
input_type = @column.try(:type)
|
2009-12-09 19:55:42 -05:00
|
|
|
|
2009-12-09 20:57:05 -05:00
|
|
|
case input_type
|
|
|
|
when :timestamp
|
|
|
|
:datetime
|
|
|
|
when :string, nil
|
2009-12-10 08:23:48 -05:00
|
|
|
@attribute.to_s =~ /password/ ? :password : :string
|
2009-12-09 20:57:05 -05:00
|
|
|
else
|
|
|
|
input_type
|
2009-12-08 11:49:14 -05:00
|
|
|
end
|
2009-12-09 20:57:05 -05:00
|
|
|
end
|
2009-12-08 14:08:36 -05:00
|
|
|
|
2009-12-10 12:57:24 -05:00
|
|
|
# Finds the database column for the given attribute
|
2009-12-10 08:57:05 -05:00
|
|
|
def find_attribute_column
|
|
|
|
@object.column_for_attribute(@attribute) if @object.respond_to?(:column_for_attribute)
|
|
|
|
end
|
|
|
|
|
2009-11-18 18:50:43 -05:00
|
|
|
end
|
|
|
|
end
|