1
0
Fork 0
mirror of https://github.com/heartcombo/simple_form.git synced 2022-11-09 12:19:26 -05:00

Merge origin/master

This commit is contained in:
Carlos Antonio da Silva 2009-12-09 19:01:10 -02:00
commit d64d55b7f9
21 changed files with 258 additions and 252 deletions

View file

@ -1,5 +1,10 @@
require 'simple_form/builder_extensions'
require 'simple_form/form_helper'
require 'simple_form/form_builder'
require 'simple_form/action_view_extensions/form_helper'
require 'simple_form/action_view_extensions/builder'
ActionView::Helpers::FormBuilder.send :include, SimpleForm::BuilderExtensions
module SimpleForm
autoload :Components, 'simple_form/components'
autoload :FormBuilder, 'simple_form/form_builder'
autoload :I18nCache, 'simple_form/i18n_cache'
autoload :MapType, 'simple_form/map_type'
autoload :RequiredHelpers, 'simple_form/required_helpers'
end

View file

@ -1,50 +0,0 @@
module SimpleForm
class AbstractComponent
attr_reader :builder, :attribute, :input_type, :options
def self.basename
@basename ||= name.split("::").last.underscore.to_sym
end
def initialize(builder, attribute, input_type, options)
@builder = builder
@attribute = attribute
@input_type = input_type
@options = options
end
def generate
return "" unless valid?
component_tag(content).to_s
end
def valid?
true
end
def template
@builder.template
end
def object
@builder.object
end
def hidden_input?
@input_type == :hidden
end
def basename
self.class.basename
end
def component_tag(content)
template.content_tag(:span, content, :class => basename)
end
def translate(default='')
lookups = [ :"#{@builder.object_name}.#{@attribute}", :"#{@attribute}", default ]
I18n.t(lookups.shift, :scope => :"simple_form.#{basename.to_s.pluralize}", :default => lookups)
end
end
end

View file

@ -0,0 +1,19 @@
module SimpleForm
module ActionViewExtensions
# A collection of methods required by simple_form but added to rails default form.
# This means that you can use such methods outside simple_form context.
module Builder
def collection_radio(attribute, collection, value_method, text_method, html_options={})
collection.inject('') do |result, item|
value = item.send value_method
text = item.send text_method
result << radio_button(attribute, value, html_options) <<
label("#{attribute}_#{value}", text, :class => "radio")
end
end
end
end
end
ActionView::Helpers::FormBuilder.send :include, SimpleForm::ActionViewExtensions::Builder

View file

@ -0,0 +1,13 @@
module SimpleForm
module ActionViewExtensions
module FormHelper
def simple_form_for(*args, &block)
options = args.extract_options!
options[:builder] = SimpleForm::FormBuilder
form_for(*(args << options), &block)
end
end
end
end
ActionView::Base.send :include, SimpleForm::ActionViewExtensions::FormHelper

View file

@ -1,15 +0,0 @@
module SimpleForm
# A collection of methods required by simple_form but added to rails default form.
# This means that you can use such methods outside simple_form context.
module BuilderExtensions
def collection_radio(attribute, collection, value_method, text_method, html_options={})
collection.inject('') do |result, item|
value = item.send value_method
text = item.send text_method
result << radio_button(attribute, value, html_options) <<
label("#{attribute}_#{value}", text, :class => "radio")
end
end
end
end

View file

@ -0,0 +1,9 @@
module SimpleForm
module Components
autoload :Base, 'simple_form/components/base'
autoload :Error, 'simple_form/components/error'
autoload :Hint, 'simple_form/components/hint'
autoload :Input, 'simple_form/components/input'
autoload :Label, 'simple_form/components/label'
end
end

View file

@ -0,0 +1,52 @@
module SimpleForm
module Components
class Base
attr_reader :builder, :attribute, :input_type, :options
def self.basename
@basename ||= name.split("::").last.underscore.to_sym
end
def initialize(builder, attribute, input_type, options)
@builder = builder
@attribute = attribute
@input_type = input_type
@options = options
end
def generate
return "" unless valid?
component_tag(content).to_s
end
def valid?
true
end
def template
@builder.template
end
def object
@builder.object
end
def hidden_input?
@input_type == :hidden
end
def basename
self.class.basename
end
def component_tag(content)
template.content_tag(:span, content, :class => basename)
end
def translate(default='')
lookups = [ :"#{@builder.object_name}.#{@attribute}", :"#{@attribute}", default ]
I18n.t(lookups.shift, :scope => :"simple_form.#{basename.to_s.pluralize}", :default => lookups)
end
end
end
end

View file

@ -0,0 +1,17 @@
module SimpleForm
module Components
class Error < Base
def valid?
!hidden_input? && !errors.blank?
end
def errors
@errors ||= object.errors[@attribute]
end
def content
Array(errors).to_sentence
end
end
end
end

View file

@ -0,0 +1,13 @@
module SimpleForm
module Components
class Hint < Base
def valid?
!hidden_input? && !content.blank?
end
def content
@content ||= @options[:hint] || translate
end
end
end
end

View file

@ -0,0 +1,68 @@
module SimpleForm
module Components
class Input < Base
include RequiredHelpers
extend I18nCache
extend MapType
map_type :boolean, :to => :check_box
map_type :text, :to => :text_area
map_type :datetime, :to => :datetime_select, :options => true
map_type :date, :to => :date_select, :options => true
map_type :time, :to => :time_select, :options => true
map_type :password, :to => :password_field
map_type :hidden, :to => :hidden_field
map_type :select, :to => :collection_select, :options => true, :collection => true
map_type :radio, :to => :collection_radio, :collection => true
map_type :numeric, :to => :text_field
map_type :string, :to => :text_field
def self.boolean_collection
i18n_cache :boolean_collection do
[ [I18n.t(:"simple_form.true", :default => 'Yes'), true],
[I18n.t(:"simple_form.false", :default => 'No'), false] ]
end
end
def generate
html_options = @options[:html] || {}
html_options[:class] = default_css_classes(html_options[:class])
@options[:options] ||= {}
mapping = self.class.mappings[@input_type]
raise "Invalid input type #{@input_type.inspect}" unless mapping
args = [ @attribute ]
if mapping.collection
collection = @options[:collection] || self.class.boolean_collection
detect_collection_methods(collection, @options)
args.push(collection, @options[:value_method], @options[:label_method])
end
args << @options[:options] if mapping.options
args << html_options
@builder.send(mapping.method, *args)
end
def detect_collection_methods(collection, options)
sample = collection.first
if sample.is_a?(Array) # TODO Test me
options[:label_method] ||= :first
options[:value_method] ||= :last
elsif sample.is_a?(String) # TODO Test me
options[:label_method] ||= :to_s
options[:value_method] ||= :to_s
elsif sample.is_a?(Numeric) # TODO Test me (including selected)
options[:label_method] ||= :to_s
options[:value_method] ||= :to_i
else # TODO Implement collection label methods or something similar
options[:label_method] ||= :to_s
options[:value_method] ||= :to_s
end
end
end
end
end

View file

@ -0,0 +1,48 @@
module SimpleForm
module Components
class Label < Base
include RequiredHelpers
extend I18nCache
def self.translate_required_string
i18n_cache :translate_required_string do
I18n.t(:"simple_form.required.string", :default =>
%[<abbr title="#{translate_required_text}">#{translate_required_mark}</abbr> ]
)
end
end
def self.translate_required_text
I18n.t(:"simple_form.required.text", :default => 'required')
end
def self.translate_required_mark
I18n.t(:"simple_form.required.mark", :default => '*')
end
def valid?
!hidden_input?
end
def generate
return '' unless valid?
html_options = { :class => default_css_classes }
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)
end
def required_text
attribute_required? ? self.class.translate_required_string.dup : ''
end
def translate_label
default = object.try(:human_attribute_name, @attribute.to_s) || @attribute.to_s.humanize
translate(default)
end
end
end
end

View file

@ -1,15 +0,0 @@
module SimpleForm
class Error < AbstractComponent
def valid?
!hidden_input? && !errors.blank?
end
def errors
@errors ||= object.errors[@attribute]
end
def content
Array(errors).to_sentence
end
end
end

View file

@ -1,24 +1,17 @@
require 'simple_form/abstract_component'
require 'simple_form/label'
require 'simple_form/input'
require 'simple_form/hint'
require 'simple_form/error'
module SimpleForm
class FormBuilder < ActionView::Helpers::FormBuilder
# Components used by the folder builder. By default is:
# [SimpleForm::Label, SimpleForm::Input, SimpleForm::Hint, SimpleForm::Error]
# Components used by the folder builder.
# By default is [:label, :input, :hint, :error].
cattr_accessor :components, :instance_writer => false
@@components = [SimpleForm::Label, SimpleForm::Input, SimpleForm::Hint, SimpleForm::Error]
@@components = [
SimpleForm::Components::Label, SimpleForm::Components::Input,
SimpleForm::Components::Hint, SimpleForm::Components::Error
]
# Make the template accessible for components
attr_reader :template
def input(attribute, options={})
# TODO Do this makes sense since we are delegating to components?
options.assert_valid_keys(:as, :label, :required, :hint, :options, :html,
:collection, :label_method, :value_method)
input_type = (options[:as] || default_input_type(attribute, options)).to_sym
pieces = self.components.collect do |klass|

View file

@ -1,12 +0,0 @@
module SimpleForm
module FormHelper
def simple_form_for(*args, &block)
options = args.extract_options!
options[:builder] = SimpleForm::FormBuilder
form_for(*(args << options), &block)
end
end
end
ActionView::Base.send :include, SimpleForm::FormHelper

View file

@ -1,11 +0,0 @@
module SimpleForm
class Hint < AbstractComponent
def valid?
!hidden_input? && !content.blank?
end
def content
@content ||= @options[:hint] || translate
end
end
end

View file

@ -1,71 +0,0 @@
require 'simple_form/required_component'
require 'simple_form/i18n_cache'
require 'simple_form/map_type'
module SimpleForm
class Input < AbstractComponent
extend I18nCache
extend MapType
include RequiredComponent
map_type :boolean, :to => :check_box
map_type :text, :to => :text_area
map_type :datetime, :to => :datetime_select, :options => true
map_type :date, :to => :date_select, :options => true
map_type :time, :to => :time_select, :options => true
map_type :password, :to => :password_field
map_type :hidden, :to => :hidden_field
map_type :select, :to => :collection_select, :options => true, :collection => true
map_type :radio, :to => :collection_radio, :collection => true
map_type :numeric, :to => :text_field
map_type :string, :to => :text_field
def self.boolean_collection
i18n_cache :boolean_collection do
[ [I18n.t(:"simple_form.true", :default => 'Yes'), true],
[I18n.t(:"simple_form.false", :default => 'No'), false] ]
end
end
def generate
html_options = @options[:html] || {}
html_options[:class] = default_css_classes(html_options[:class])
@options[:options] ||= {}
mapping = self.class.mappings[@input_type]
raise "Invalid input type #{@input_type.inspect}" unless mapping
args = [ @attribute ]
if mapping.collection
collection = @options[:collection] || self.class.boolean_collection
detect_collection_methods(collection, @options)
args.push(collection, @options[:value_method], @options[:label_method])
end
args << @options[:options] if mapping.options
args << html_options
@builder.send(mapping.method, *args)
end
def detect_collection_methods(collection, options)
sample = collection.first
if sample.is_a?(Array) # TODO Test me
options[:label_method] ||= :first
options[:value_method] ||= :last
elsif sample.is_a?(String) # TODO Test me
options[:label_method] ||= :to_s
options[:value_method] ||= :to_s
elsif sample.is_a?(Numeric) # TODO Test me (including selected)
options[:label_method] ||= :to_s
options[:value_method] ||= :to_i
else # TODO Implement collection label methods or something similar
options[:label_method] ||= :to_s
options[:value_method] ||= :to_s
end
end
end
end

View file

@ -1,49 +0,0 @@
require 'simple_form/required_component'
require 'simple_form/i18n_cache'
module SimpleForm
class Label < AbstractComponent
extend SimpleForm::I18nCache
include RequiredComponent
def self.translate_required_string
i18n_cache :translate_required_string do
I18n.t(:"simple_form.required.string", :default =>
%[<abbr title="#{translate_required_text}">#{translate_required_mark}</abbr> ]
)
end
end
def self.translate_required_text
I18n.t(:"simple_form.required.text", :default => 'required')
end
def self.translate_required_mark
I18n.t(:"simple_form.required.mark", :default => '*')
end
def valid?
!hidden_input?
end
def generate
return '' unless valid?
html_options = { :class => default_css_classes }
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)
end
def required_text
attribute_required? ? self.class.translate_required_string.dup : ''
end
def translate_label
default = object.try(:human_attribute_name, @attribute.to_s) || @attribute.to_s.humanize
translate(default)
end
end
end

View file

@ -1,5 +1,5 @@
module SimpleForm
module RequiredComponent
module RequiredHelpers
def attribute_required?
@options[:required] != false
end

View file

@ -3,15 +3,7 @@ require 'test_helper'
class InputTest < ActionView::TestCase
setup do
SimpleForm::Input.reset_i18n_cache :boolean_collection
end
test 'input should verify options hash' do
assert_raise ArgumentError do
simple_form_for @user do |f|
concat f.input :name, :invalid_param => true
end
end
SimpleForm::Components::Input.reset_i18n_cache :boolean_collection
end
test 'input should generate a default text field' do

View file

@ -3,7 +3,7 @@ require 'test_helper'
class LabelTest < ActionView::TestCase
setup do
SimpleForm::Label.reset_i18n_cache :translate_required_string
SimpleForm::Components::Label.reset_i18n_cache :translate_required_string
end
test 'input should generate a label with the text field' do

View file

@ -13,7 +13,7 @@ I18n.default_locale = :en
class ActionView::TestCase
include I18nHelper
tests SimpleForm::FormHelper
tests SimpleForm::ActionViewExtensions::FormHelper
setup :set_controller
setup :set_response