2010-01-09 15:05:02 +00:00
|
|
|
module SimpleForm
|
|
|
|
module Inputs
|
|
|
|
class Base
|
|
|
|
extend I18nCache
|
|
|
|
|
|
|
|
# When action is create or update, we still should use new and edit
|
|
|
|
ACTIONS = {
|
|
|
|
:create => :new,
|
|
|
|
:update => :edit
|
|
|
|
}
|
|
|
|
|
|
|
|
include SimpleForm::Components::Errors
|
|
|
|
include SimpleForm::Components::Hints
|
2010-07-06 09:24:12 +00:00
|
|
|
include SimpleForm::Components::LabelInput
|
2010-11-07 09:41:33 +00:00
|
|
|
include SimpleForm::Components::Placeholders
|
2010-01-09 15:05:02 +00:00
|
|
|
include SimpleForm::Components::Wrapper
|
2011-08-30 23:51:53 +00:00
|
|
|
include SimpleForm::Components::Maxlength
|
2010-01-09 15:05:02 +00:00
|
|
|
|
2010-12-08 02:25:14 +00:00
|
|
|
attr_reader :attribute_name, :column, :input_type, :reflection,
|
|
|
|
:options, :input_html_options
|
2010-01-09 15:05:02 +00:00
|
|
|
|
2010-12-08 02:25:14 +00:00
|
|
|
delegate :template, :object, :object_name, :to => :@builder
|
2010-10-18 21:14:07 +00:00
|
|
|
|
|
|
|
def initialize(builder, attribute_name, column, input_type, options = {})
|
2010-11-07 09:41:33 +00:00
|
|
|
@builder = builder
|
|
|
|
@attribute_name = attribute_name
|
|
|
|
@column = column
|
|
|
|
@input_type = input_type
|
2010-12-08 02:25:14 +00:00
|
|
|
@reflection = options.delete(:reflection)
|
2010-11-07 09:41:33 +00:00
|
|
|
@options = options
|
|
|
|
@input_html_options = html_options_for(:input, input_html_classes).tap do |o|
|
Add configuration option to explicitly turn off HTML5 extensions.
This includes the new field types such as email, number, search, url,
tel, and the new attributes such as required, autofocus, maxlength, min, max, step.
None of these are technically allowed in the HTML4 or XHTML1.0 doc types.
Test coverage and updated README.
Update config file generator with new HTML5 option.
2011-04-01 23:31:48 +00:00
|
|
|
o[:required] = true if has_required? # Don't make this conditional on HTML5 here, because we want the CSS class to be set
|
2010-12-17 11:28:47 +00:00
|
|
|
o[:disabled] = true if disabled?
|
2011-05-16 09:42:58 +00:00
|
|
|
o[:autofocus] = true if has_autofocus? && SimpleForm.html5
|
2010-11-07 09:41:33 +00:00
|
|
|
end
|
2010-01-09 15:05:02 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def input
|
|
|
|
raise NotImplementedError
|
|
|
|
end
|
|
|
|
|
|
|
|
def input_options
|
|
|
|
options
|
|
|
|
end
|
|
|
|
|
2010-06-01 21:37:53 +00:00
|
|
|
def input_html_classes
|
|
|
|
[input_type, required_class]
|
2010-01-09 15:05:02 +00:00
|
|
|
end
|
|
|
|
|
2011-09-02 15:48:20 +00:00
|
|
|
def limit
|
|
|
|
column && column.limit
|
|
|
|
end
|
|
|
|
|
2010-01-09 15:05:02 +00:00
|
|
|
def render
|
2010-07-06 09:24:12 +00:00
|
|
|
content = "".html_safe
|
|
|
|
components_list.each do |component|
|
2010-01-09 15:05:02 +00:00
|
|
|
next if options[component] == false
|
2010-11-07 09:41:33 +00:00
|
|
|
rendered = send(component)
|
|
|
|
content.safe_concat rendered.to_s if rendered
|
2010-01-09 15:05:02 +00:00
|
|
|
end
|
2010-07-06 09:24:12 +00:00
|
|
|
wrap(content)
|
2010-01-09 15:05:02 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
|
2010-04-22 12:33:23 +00:00
|
|
|
def components_list
|
2010-09-27 09:56:37 +00:00
|
|
|
options[:components] || SimpleForm.components
|
2010-04-22 12:33:23 +00:00
|
|
|
end
|
|
|
|
|
2010-01-09 15:05:02 +00:00
|
|
|
def attribute_required?
|
2010-10-27 20:47:36 +00:00
|
|
|
if !options[:required].nil?
|
2010-05-17 09:08:47 +00:00
|
|
|
options[:required]
|
2010-12-09 21:36:09 +00:00
|
|
|
elsif has_validators?
|
2011-06-12 01:56:41 +00:00
|
|
|
(attribute_validators + reflection_validators).any? do |v|
|
2011-08-10 22:50:17 +00:00
|
|
|
v.kind == :presence && !conditional_validators?(v) && action_validators?(v)
|
2011-06-12 01:56:41 +00:00
|
|
|
end
|
2010-05-17 09:08:47 +00:00
|
|
|
else
|
2010-07-06 09:24:12 +00:00
|
|
|
attribute_required_by_default?
|
2010-05-14 21:58:36 +00:00
|
|
|
end
|
2010-01-09 15:05:02 +00:00
|
|
|
end
|
|
|
|
|
2010-12-10 22:57:22 +00:00
|
|
|
# Whether this input is valid for HTML 5 required attribute.
|
|
|
|
def has_required?
|
2011-05-26 17:40:17 +00:00
|
|
|
attribute_required? && SimpleForm.html5 && SimpleForm.browser_validations
|
2010-12-10 22:57:22 +00:00
|
|
|
end
|
|
|
|
|
2010-12-17 11:28:47 +00:00
|
|
|
def has_autofocus?
|
|
|
|
options[:autofocus]
|
|
|
|
end
|
|
|
|
|
2010-09-14 03:40:03 +00:00
|
|
|
def has_validators?
|
2010-12-09 21:36:09 +00:00
|
|
|
attribute_name && object.class.respond_to?(:validators_on)
|
2010-09-14 03:40:03 +00:00
|
|
|
end
|
|
|
|
|
2010-08-06 17:52:19 +00:00
|
|
|
def attribute_validators
|
|
|
|
object.class.validators_on(attribute_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def reflection_validators
|
|
|
|
reflection ? object.class.validators_on(reflection.name) : []
|
|
|
|
end
|
|
|
|
|
2011-06-12 01:56:41 +00:00
|
|
|
def conditional_validators?(validator)
|
2011-08-10 22:50:17 +00:00
|
|
|
validator.options.include?(:if) || validator.options.include?(:unless)
|
2011-06-12 01:56:41 +00:00
|
|
|
end
|
|
|
|
|
2011-08-10 14:00:12 +00:00
|
|
|
def action_validators?(validator)
|
2011-08-10 22:50:17 +00:00
|
|
|
!validator.options.include?(:on) || ACTIONS[validator.options[:on].to_sym] == lookup_action
|
|
|
|
end
|
2011-08-10 14:00:12 +00:00
|
|
|
|
2010-07-06 09:24:12 +00:00
|
|
|
def attribute_required_by_default?
|
2010-07-06 09:28:23 +00:00
|
|
|
SimpleForm.required_by_default
|
2010-07-06 09:24:12 +00:00
|
|
|
end
|
|
|
|
|
2010-01-09 15:05:02 +00:00
|
|
|
def required_class
|
|
|
|
attribute_required? ? :required : :optional
|
|
|
|
end
|
|
|
|
|
|
|
|
# Find reflection name when available, otherwise use attribute
|
|
|
|
def reflection_or_attribute_name
|
|
|
|
reflection ? reflection.name : attribute_name
|
|
|
|
end
|
|
|
|
|
|
|
|
# Retrieve options for the given namespace from the options hash
|
2010-06-01 21:37:53 +00:00
|
|
|
def html_options_for(namespace, extra)
|
2010-01-09 15:05:02 +00:00
|
|
|
html_options = options[:"#{namespace}_html"] || {}
|
|
|
|
html_options[:class] = (extra << html_options[:class]).join(' ').strip if extra.present?
|
|
|
|
html_options
|
|
|
|
end
|
|
|
|
|
2010-11-22 00:07:22 +00:00
|
|
|
def disabled?
|
2011-08-31 02:59:08 +00:00
|
|
|
options[:disabled] == true
|
2010-11-22 00:07:22 +00:00
|
|
|
end
|
|
|
|
|
2010-01-09 15:05:02 +00:00
|
|
|
# Lookup translations for the given namespace using I18n, based on object name,
|
|
|
|
# actual action and attribute name. Lookup priority as follows:
|
|
|
|
#
|
|
|
|
# simple_form.{namespace}.{model}.{action}.{attribute}
|
|
|
|
# simple_form.{namespace}.{model}.{attribute}
|
|
|
|
# simple_form.{namespace}.{attribute}
|
|
|
|
#
|
|
|
|
# Namespace is used for :labels and :hints.
|
|
|
|
#
|
|
|
|
# Model is the actual object name, for a @user object you'll have :user.
|
|
|
|
# Action is the action being rendered, usually :new or :edit.
|
|
|
|
# And attribute is the attribute itself, :name for example.
|
|
|
|
#
|
2011-02-12 15:42:35 +00:00
|
|
|
# The lookup for nested attributes is also done in a nested format using
|
|
|
|
# both model and nested object names, such as follow:
|
|
|
|
#
|
|
|
|
# simple_form.{namespace}.{model}.{nested}.{action}.{attribute}
|
|
|
|
# simple_form.{namespace}.{model}.{nested}.{attribute}
|
|
|
|
# simple_form.{namespace}.{nested}.{action}.{attribute}
|
|
|
|
# simple_form.{namespace}.{nested}.{attribute}
|
|
|
|
# simple_form.{namespace}.{attribute}
|
|
|
|
#
|
2010-01-09 15:05:02 +00:00
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# simple_form:
|
|
|
|
# labels:
|
|
|
|
# user:
|
|
|
|
# new:
|
|
|
|
# email: 'E-mail para efetuar o sign in.'
|
|
|
|
# edit:
|
|
|
|
# email: 'E-mail.'
|
|
|
|
#
|
|
|
|
# Take a look at our locale example file.
|
|
|
|
def translate(namespace, default='')
|
2010-09-30 06:12:45 +00:00
|
|
|
return nil unless SimpleForm.translate
|
2011-02-12 15:42:35 +00:00
|
|
|
|
|
|
|
model_names = lookup_model_names
|
|
|
|
lookups = []
|
|
|
|
|
|
|
|
while !model_names.empty?
|
|
|
|
joined_model_names = model_names.join(".")
|
|
|
|
model_names.shift
|
|
|
|
|
|
|
|
lookups << :"#{joined_model_names}.#{lookup_action}.#{reflection_or_attribute_name}"
|
|
|
|
lookups << :"#{joined_model_names}.#{reflection_or_attribute_name}"
|
|
|
|
end
|
2010-01-09 15:05:02 +00:00
|
|
|
lookups << :"#{reflection_or_attribute_name}"
|
|
|
|
lookups << default
|
2011-02-12 15:42:35 +00:00
|
|
|
|
2010-09-30 06:12:45 +00:00
|
|
|
I18n.t(lookups.shift, :scope => :"simple_form.#{namespace}", :default => lookups).presence
|
2010-01-09 15:05:02 +00:00
|
|
|
end
|
|
|
|
|
2011-05-22 16:19:44 +00:00
|
|
|
# Extract the model names from the object_name mess, ignoring numeric and
|
|
|
|
# explicit child indexes.
|
2011-02-12 15:42:35 +00:00
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# route[blocks_attributes][0][blocks_learning_object_attributes][1][foo_attributes]
|
|
|
|
# ["route", "blocks", "blocks_learning_object", "foo"]
|
|
|
|
#
|
|
|
|
def lookup_model_names
|
2011-05-22 16:19:44 +00:00
|
|
|
child_index = @builder.options[:child_index]
|
|
|
|
names = object_name.to_s.scan(/([a-zA-Z_]+)/).flatten
|
|
|
|
names.delete(child_index) if child_index
|
|
|
|
names.each { |name| name.gsub!('_attributes', '') }
|
2011-02-12 15:42:35 +00:00
|
|
|
end
|
|
|
|
|
2010-01-09 15:05:02 +00:00
|
|
|
# The action to be used in lookup.
|
|
|
|
def lookup_action
|
2010-09-30 06:12:45 +00:00
|
|
|
action = template.controller.action_name
|
|
|
|
return unless action
|
|
|
|
action = action.to_sym
|
2010-01-09 15:05:02 +00:00
|
|
|
ACTIONS[action] || action
|
|
|
|
end
|
2011-03-02 09:32:10 +00:00
|
|
|
|
|
|
|
def input_method
|
|
|
|
self.class.mappings[input_type] or
|
|
|
|
raise("Could not find method for #{input_type.inspect}")
|
|
|
|
end
|
2010-01-09 15:05:02 +00:00
|
|
|
end
|
|
|
|
end
|
2010-09-14 03:40:03 +00:00
|
|
|
end
|