Finish component stack refactoring.
This commit is contained in:
parent
7329eb4c72
commit
000156e2e2
|
@ -16,7 +16,8 @@ module SimpleForm
|
|||
mattr_accessor :components
|
||||
@@components = [
|
||||
SimpleForm::Components::Wrapper, SimpleForm::Components::Label,
|
||||
SimpleForm::Components::Input, SimpleForm::Components::Hint, SimpleForm::Components::Error
|
||||
SimpleForm::Components::Input, SimpleForm::Components::Hint,
|
||||
SimpleForm::Components::Error
|
||||
]
|
||||
|
||||
# The terminator sent to the last component
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
module SimpleForm
|
||||
module Components
|
||||
# The component is the core of SimpleForm. SimpleForm can be customized simply
|
||||
# with the addition of new components to the component stack. A component just
|
||||
# need to be initialized with two values, the builder and the next component to
|
||||
# be invoked and respond to call.
|
||||
#
|
||||
# The Base component is a raw component with some helpers and a default behavior
|
||||
# of prepending the content available in the method content.
|
||||
class Base
|
||||
attr_reader :builder, :attribute, :input_type, :options
|
||||
delegate :template, :object, :object_name, :attribute, :input_type, :options, :to => :@builder
|
||||
|
||||
def self.basename
|
||||
@basename ||= name.split("::").last.underscore.to_sym
|
||||
|
@ -10,34 +17,19 @@ module SimpleForm
|
|||
def initialize(builder, component)
|
||||
@builder = builder
|
||||
@component = component
|
||||
@attribute = @builder.attribute
|
||||
@input_type = @builder.input_type
|
||||
@options = @builder.options
|
||||
end
|
||||
|
||||
def call
|
||||
generate + @component.call
|
||||
end
|
||||
|
||||
def generate
|
||||
return "" unless valid?
|
||||
component_tag(content).to_s
|
||||
return @component.call unless valid?
|
||||
content + @component.call
|
||||
end
|
||||
|
||||
def valid?
|
||||
true
|
||||
end
|
||||
|
||||
def template
|
||||
@builder.template
|
||||
end
|
||||
|
||||
def object
|
||||
@builder.object
|
||||
end
|
||||
|
||||
def hidden_input?
|
||||
@input_type == :hidden
|
||||
input_type == :hidden
|
||||
end
|
||||
|
||||
def basename
|
||||
|
@ -49,7 +41,7 @@ module SimpleForm
|
|||
end
|
||||
|
||||
def translate(default='')
|
||||
lookups = [ :"#{@builder.object_name}.#{@attribute}", :"#{@attribute}", default ]
|
||||
lookups = [ :"#{object_name}.#{attribute}", :"#{attribute}", default ]
|
||||
I18n.t(lookups.shift, :scope => :"simple_form.#{basename.to_s.pluralize}", :default => lookups)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,11 +6,11 @@ module SimpleForm
|
|||
end
|
||||
|
||||
def errors
|
||||
@errors ||= object.errors[@attribute]
|
||||
@errors ||= object.errors[attribute]
|
||||
end
|
||||
|
||||
def content
|
||||
Array(errors).to_sentence
|
||||
component_tag Array(errors).to_sentence
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,11 +2,15 @@ module SimpleForm
|
|||
module Components
|
||||
class Hint < Base
|
||||
def valid?
|
||||
!hidden_input? && !content.blank?
|
||||
!hidden_input? && !hint.blank?
|
||||
end
|
||||
|
||||
def hint
|
||||
@hint ||= options[:hint] || translate
|
||||
end
|
||||
|
||||
def content
|
||||
@content ||= @options[:hint] || translate
|
||||
component_tag hint
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,15 +26,15 @@ module SimpleForm
|
|||
end
|
||||
end
|
||||
|
||||
def generate
|
||||
html_options = @options[:html] || {}
|
||||
def content
|
||||
html_options = options[:html] || {}
|
||||
html_options[:class] = default_css_classes(html_options[:class])
|
||||
@options[:options] ||= {}
|
||||
options[:options] ||= {}
|
||||
|
||||
mapping = self.class.mappings[@input_type]
|
||||
raise "Invalid input type #{@input_type.inspect}" unless mapping
|
||||
mapping = self.class.mappings[input_type]
|
||||
raise "Invalid input type #{input_type.inspect}" unless mapping
|
||||
|
||||
args = [ @attribute ]
|
||||
args = [ attribute ]
|
||||
apply_collection_behavior(args) if mapping.collection
|
||||
apply_options_behavior(args) if mapping.options
|
||||
args << html_options
|
||||
|
@ -45,15 +45,15 @@ module SimpleForm
|
|||
protected
|
||||
|
||||
def apply_collection_behavior(args)
|
||||
collection = (@options[:collection] || self.class.boolean_collection).to_a
|
||||
detect_collection_methods(collection, @options)
|
||||
collection = (options[:collection] || self.class.boolean_collection).to_a
|
||||
detect_collection_methods(collection, options)
|
||||
|
||||
@options[:options][:include_blank] = true unless @options[:options].key?(:include_blank)
|
||||
args.push(collection, @options[:value_method], @options[:label_method])
|
||||
options[:options][:include_blank] = true unless options[:options].key?(:include_blank)
|
||||
args.push(collection, options[:value_method], options[:label_method])
|
||||
end
|
||||
|
||||
def apply_options_behavior(args)
|
||||
args << @options[:options]
|
||||
args << options[:options]
|
||||
end
|
||||
|
||||
def detect_collection_methods(collection, options)
|
||||
|
|
|
@ -28,15 +28,14 @@ module SimpleForm
|
|||
!hidden_input?
|
||||
end
|
||||
|
||||
def generate
|
||||
return '' unless valid?
|
||||
def content
|
||||
html_options = { :class => default_css_classes }
|
||||
html_options[:for] = @options[:html][:id] if @options.key?(:html)
|
||||
@builder.label(@attribute, label_text, html_options)
|
||||
html_options[:for] = options[:html][:id] if options.key?(:html)
|
||||
@builder.label(attribute, label_text, html_options)
|
||||
end
|
||||
|
||||
def label_text
|
||||
required_text << (@options[:label] || translate_label)
|
||||
required_text << (options[:label] || translate_label)
|
||||
end
|
||||
|
||||
def required_text
|
||||
|
@ -44,7 +43,7 @@ module SimpleForm
|
|||
end
|
||||
|
||||
def translate_label
|
||||
default = object.try(:human_attribute_name, @attribute.to_s) || @attribute.to_s.humanize
|
||||
default = object.try(:human_attribute_name, attribute.to_s) || attribute.to_s.humanize
|
||||
translate(default)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
module SimpleForm
|
||||
class FormBuilder < ActionView::Helpers::FormBuilder
|
||||
# Make the template accessible for components
|
||||
attr_reader :template, :object_name, :object, :attribute, :input_type, :options
|
||||
|
||||
def input(attribute, options={})
|
||||
|
@ -23,7 +22,7 @@ module SimpleForm
|
|||
return :select if @options[:collection]
|
||||
|
||||
input_type = if @object.respond_to?(:column_for_attribute)
|
||||
column = @object.column_for_attribute(attribute)
|
||||
column = @object.column_for_attribute(@attribute)
|
||||
column.type if column
|
||||
end
|
||||
|
||||
|
@ -31,7 +30,7 @@ module SimpleForm
|
|||
when :timestamp
|
||||
:datetime
|
||||
when :string, nil
|
||||
attribute.to_s =~ /password/ ? :password : :string
|
||||
@attribute.to_s =~ /password/ ? :password : :string
|
||||
else
|
||||
input_type
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module SimpleForm
|
||||
module RequiredHelpers
|
||||
def attribute_required?
|
||||
@options[:required] != false
|
||||
options[:required] != false
|
||||
end
|
||||
|
||||
def required_class
|
||||
|
@ -9,11 +9,11 @@ module SimpleForm
|
|||
end
|
||||
|
||||
def attribute_required?
|
||||
@options[:required] != false
|
||||
options[:required] != false
|
||||
end
|
||||
|
||||
def default_css_classes(merge_class=nil)
|
||||
"#{@input_type} #{required_class} #{merge_class}".strip
|
||||
"#{input_type} #{required_class} #{merge_class}".strip
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,26 +9,26 @@ class ErrorTest < ActionView::TestCase
|
|||
f.options = options
|
||||
|
||||
error = SimpleForm::Components::Error.new(f, SimpleForm.terminator)
|
||||
concat(error.generate)
|
||||
concat(error.call)
|
||||
yield error if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
test 'error should not generate content for hidden fields' do
|
||||
with_error_for @user, :name, :hidden do |error|
|
||||
assert error.generate.blank?
|
||||
assert error.call.blank?
|
||||
end
|
||||
end
|
||||
|
||||
test 'error should not generate content for attribute without errors' do
|
||||
with_error_for @user, :active, :boolean do |error|
|
||||
assert error.generate.blank?
|
||||
assert error.call.blank?
|
||||
end
|
||||
end
|
||||
|
||||
test 'error should not generate messages when object is not present' do
|
||||
with_error_for :project, :name, :string do |error|
|
||||
assert error.generate.blank?
|
||||
assert error.call.blank?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,20 +9,20 @@ class ErrorTest < ActionView::TestCase
|
|||
f.options = options
|
||||
|
||||
hint = SimpleForm::Components::Hint.new(f, SimpleForm.terminator)
|
||||
concat(hint.generate)
|
||||
concat(hint.call)
|
||||
yield hint if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
test 'hint should not be generated by default' do
|
||||
with_hint_for @user, :name, :string do |hint|
|
||||
assert hint.generate.blank?
|
||||
assert hint.call.blank?
|
||||
end
|
||||
end
|
||||
|
||||
test 'hint should not be generated for hidden fields' do
|
||||
with_hint_for @user, :name, :hidden, :hint => 'Use with care...' do |hint|
|
||||
assert hint.generate.blank?
|
||||
assert hint.call.blank?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class InputTest < ActionView::TestCase
|
|||
f.options = options
|
||||
|
||||
input = SimpleForm::Components::Input.new(f, SimpleForm.terminator)
|
||||
concat(input.generate)
|
||||
concat(input.call)
|
||||
yield input if block_given?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,14 +15,14 @@ class LabelTest < ActionView::TestCase
|
|||
f.options = options
|
||||
|
||||
label = SimpleForm::Components::Label.new(f, SimpleForm.terminator)
|
||||
concat(label.generate)
|
||||
concat(label.call)
|
||||
yield label if block_given?
|
||||
end
|
||||
end
|
||||
|
||||
test 'label should not be generated for hidden inputs' do
|
||||
with_label_for @user, :name, :hidden do |label|
|
||||
assert label.generate.blank?
|
||||
with_label_for @user, :name, :hidden do |label|
|
||||
assert label.call.blank?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue