aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/helpers/tags
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view/helpers/tags')
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb43
-rw-r--r--actionpack/lib/action_view/helpers/tags/check_box.rb14
-rw-r--r--actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb37
-rw-r--r--actionpack/lib/action_view/helpers/tags/collection_helpers.rb82
-rw-r--r--actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb30
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_field.rb15
-rw-r--r--actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb7
-rw-r--r--actionpack/lib/action_view/helpers/tags/label.rb6
-rw-r--r--actionpack/lib/action_view/helpers/tags/text_area.rb6
-rw-r--r--actionpack/lib/action_view/helpers/tags/text_field.rb3
10 files changed, 215 insertions, 28 deletions
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index 449f94d347..7c2f12d8e7 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -5,8 +5,6 @@ module ActionView
include Helpers::ActiveModelInstanceTag, Helpers::TagHelper, Helpers::FormTagHelper
include FormOptionsHelper
- DEFAULT_FIELD_OPTIONS = { "size" => 30 }
-
attr_reader :object
def initialize(object_name, method_name, template_object, options = {})
@@ -32,9 +30,11 @@ module ActionView
def value_before_type_cast(object)
unless object.nil?
- object.respond_to?(@method_name + "_before_type_cast") ?
- object.send(@method_name + "_before_type_cast") :
- object.send(@method_name)
+ method_before_type_cast = @method_name + "_before_type_cast"
+
+ object.respond_to?(method_before_type_cast) ?
+ object.send(method_before_type_cast) :
+ value(object)
end
end
@@ -59,26 +59,28 @@ module ActionView
end
def add_default_name_and_id_for_value(tag_value, options)
- unless tag_value.nil?
- pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase
- specified_id = options["id"]
+ if tag_value.nil?
add_default_name_and_id(options)
- options["id"] += "_#{pretty_tag_value}" if specified_id.blank? && options["id"].present?
else
+ specified_id = options["id"]
add_default_name_and_id(options)
+
+ if specified_id.blank? && options["id"].present?
+ options["id"] += "_#{sanitized_value(tag_value)}"
+ end
end
end
def add_default_name_and_id(options)
if options.has_key?("index")
- options["name"] ||= tag_name_with_index(options["index"])
+ options["name"] ||= options.fetch("name"){ tag_name_with_index(options["index"]) }
options["id"] = options.fetch("id"){ tag_id_with_index(options["index"]) }
options.delete("index")
elsif defined?(@auto_index)
- options["name"] ||= tag_name_with_index(@auto_index)
+ options["name"] ||= options.fetch("name"){ tag_name_with_index(@auto_index) }
options["id"] = options.fetch("id"){ tag_id_with_index(@auto_index) }
else
- options["name"] ||= tag_name + (options['multiple'] ? '[]' : '')
+ options["name"] ||= options.fetch("name"){ options['multiple'] ? tag_name_multiple : tag_name }
options["id"] = options.fetch("id"){ tag_id }
end
options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence
@@ -88,6 +90,10 @@ module ActionView
"#{@object_name}[#{sanitized_method_name}]"
end
+ def tag_name_multiple
+ "#{tag_name}[]"
+ end
+
def tag_name_with_index(index)
"#{@object_name}[#{index}][#{sanitized_method_name}]"
end
@@ -108,11 +114,16 @@ module ActionView
@sanitized_method_name ||= @method_name.sub(/\?$/,"")
end
+ def sanitized_value(value)
+ value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase
+ end
+
def select_content_tag(option_tags, options, html_options)
html_options = html_options.stringify_keys
add_default_name_and_id(html_options)
select = content_tag("select", add_options(option_tags, options, value(object)), html_options)
- if html_options["multiple"]
+
+ if html_options["multiple"] && options.fetch(:include_hidden) { true }
tag("input", :disabled => html_options["disabled"], :name => html_options["name"], :type => "hidden", :value => "") + select
else
select
@@ -121,13 +132,13 @@ module ActionView
def add_options(option_tags, options, value = nil)
if options[:include_blank]
- option_tags = "<option value=\"\">#{ERB::Util.html_escape(options[:include_blank]) if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
+ option_tags = content_tag('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags
end
if value.blank? && options[:prompt]
prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
- option_tags = "<option value=\"\">#{ERB::Util.html_escape(prompt)}</option>\n" + option_tags
+ option_tags = content_tag('option', prompt, :value => '') + "\n" + option_tags
end
- option_tags.html_safe
+ option_tags
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/check_box.rb b/actionpack/lib/action_view/helpers/tags/check_box.rb
index 7ad5de0596..1a4aebb936 100644
--- a/actionpack/lib/action_view/helpers/tags/check_box.rb
+++ b/actionpack/lib/action_view/helpers/tags/check_box.rb
@@ -25,9 +25,15 @@ module ActionView
add_default_name_and_id(options)
end
- hidden = @unchecked_value ? tag("input", "name" => options["name"], "type" => "hidden", "value" => @unchecked_value, "disabled" => options["disabled"]) : "".html_safe
+ include_hidden = options.delete("include_hidden") { true }
checkbox = tag("input", options)
- hidden + checkbox
+
+ if include_hidden
+ hidden = hidden_field_for_checkbox(options)
+ hidden + checkbox
+ else
+ checkbox
+ end
end
private
@@ -48,6 +54,10 @@ module ActionView
value.to_i != 0
end
end
+
+ def hidden_field_for_checkbox(options)
+ @unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb
new file mode 100644
index 0000000000..e23f5113fb
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb
@@ -0,0 +1,37 @@
+require 'action_view/helpers/tags/collection_helpers'
+
+module ActionView
+ module Helpers
+ module Tags
+ class CollectionCheckBoxes < Base
+ include CollectionHelpers
+
+ class CheckBoxBuilder < Builder
+ def check_box(extra_html_options={})
+ html_options = extra_html_options.merge(@input_html_options)
+ @template_object.check_box(@object_name, @method_name, html_options, @value, nil)
+ end
+ end
+
+ def render
+ rendered_collection = render_collection do |item, value, text, default_html_options|
+ default_html_options[:multiple] = true
+ builder = instantiate_builder(CheckBoxBuilder, item, value, text, default_html_options)
+
+ if block_given?
+ yield builder
+ else
+ builder.check_box + builder.label
+ end
+ end
+
+ # Append a hidden field to make sure something will be sent back to the
+ # server if all check boxes are unchecked.
+ hidden = @template_object.hidden_field_tag(tag_name_multiple, "", :id => nil)
+
+ rendered_collection + hidden
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb
new file mode 100644
index 0000000000..6a1479069f
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb
@@ -0,0 +1,82 @@
+module ActionView
+ module Helpers
+ module Tags
+ module CollectionHelpers
+ class Builder
+ attr_reader :object, :text, :value
+
+ def initialize(template_object, object_name, method_name, object,
+ sanitized_attribute_name, text, value, input_html_options)
+ @template_object = template_object
+ @object_name = object_name
+ @method_name = method_name
+ @object = object
+ @sanitized_attribute_name = sanitized_attribute_name
+ @text = text
+ @value = value
+ @input_html_options = input_html_options
+ end
+
+ def label(label_html_options={}, &block)
+ @template_object.label(@object_name, @sanitized_attribute_name, @text, label_html_options, &block)
+ end
+ end
+
+ def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options)
+ @collection = collection
+ @value_method = value_method
+ @text_method = text_method
+ @html_options = html_options
+
+ super(object_name, method_name, template_object, options)
+ end
+
+ private
+
+ def instantiate_builder(builder_class, item, value, text, html_options)
+ builder_class.new(@template_object, @object_name, @method_name, item,
+ sanitize_attribute_name(value), text, value, html_options)
+ end
+
+ # Generate default options for collection helpers, such as :checked and
+ # :disabled.
+ def default_html_options_for_collection(item, value) #:nodoc:
+ html_options = @html_options.dup
+
+ [:checked, :selected, :disabled].each do |option|
+ next unless current_value = @options[option]
+
+ accept = if current_value.respond_to?(:call)
+ current_value.call(item)
+ else
+ Array(current_value).include?(value)
+ end
+
+ if accept
+ html_options[option] = true
+ elsif option == :checked
+ html_options[option] = false
+ end
+ end
+
+ html_options[:object] = @object
+ html_options
+ end
+
+ def sanitize_attribute_name(value) #:nodoc:
+ "#{sanitized_method_name}_#{sanitized_value(value)}"
+ end
+
+ def render_collection #:nodoc:
+ @collection.map do |item|
+ value = value_for_collection(item, @value_method)
+ text = value_for_collection(item, @text_method)
+ default_html_options = default_html_options_for_collection(item, value)
+
+ yield item, value, text, default_html_options
+ end.join.html_safe
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb b/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb
new file mode 100644
index 0000000000..ba2035f074
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/collection_radio_buttons.rb
@@ -0,0 +1,30 @@
+require 'action_view/helpers/tags/collection_helpers'
+
+module ActionView
+ module Helpers
+ module Tags
+ class CollectionRadioButtons < Base
+ include CollectionHelpers
+
+ class RadioButtonBuilder < Builder
+ def radio_button(extra_html_options={})
+ html_options = extra_html_options.merge(@input_html_options)
+ @template_object.radio_button(@object_name, @method_name, @value, html_options)
+ end
+ end
+
+ def render
+ render_collection do |item, value, text, default_html_options|
+ builder = instantiate_builder(RadioButtonBuilder, item, value, text, default_html_options)
+
+ if block_given?
+ yield builder
+ else
+ builder.radio_button + builder.label
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb
new file mode 100644
index 0000000000..bb968e9f39
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/date_field.rb
@@ -0,0 +1,15 @@
+module ActionView
+ module Helpers
+ module Tags
+ class DateField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { value(object).try(:to_date) }
+ options["size"] = nil
+ @options = options
+ super
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb b/actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb
index 507466a57a..507ba8835f 100644
--- a/actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb
+++ b/actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb
@@ -14,8 +14,13 @@ module ActionView
end
def render
+ option_tags_options = {
+ :selected => @options.fetch(:selected) { value(@object) },
+ :disabled => @options[:disabled]
+ }
+
select_content_tag(
- option_groups_from_collection_for_select(@collection, @group_method, @group_label_method, @option_key_method, @option_value_method, value(@object)), @options, @html_options
+ option_groups_from_collection_for_select(@collection, @group_method, @group_label_method, @option_key_method, @option_value_method, option_tags_options), @options, @html_options
)
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/label.rb b/actionpack/lib/action_view/helpers/tags/label.rb
index 1bd71c2778..1c8bf063ea 100644
--- a/actionpack/lib/action_view/helpers/tags/label.rb
+++ b/actionpack/lib/action_view/helpers/tags/label.rb
@@ -3,16 +3,16 @@ module ActionView
module Tags
class Label < Base #:nodoc:
def initialize(object_name, method_name, template_object, content_or_options = nil, options = nil)
+ options ||= {}
+
content_is_options = content_or_options.is_a?(Hash)
if content_is_options
- options = content_or_options
+ options.merge! content_or_options
@content = nil
else
@content = content_or_options
end
- options ||= {}
-
super(object_name, method_name, template_object, options)
end
diff --git a/actionpack/lib/action_view/helpers/tags/text_area.rb b/actionpack/lib/action_view/helpers/tags/text_area.rb
index a7db8eb437..f74652c5e7 100644
--- a/actionpack/lib/action_view/helpers/tags/text_area.rb
+++ b/actionpack/lib/action_view/helpers/tags/text_area.rb
@@ -2,17 +2,15 @@ module ActionView
module Helpers
module Tags
class TextArea < Base #:nodoc:
- DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }
-
def render
- options = DEFAULT_TEXT_AREA_OPTIONS.merge(@options.stringify_keys)
+ options = @options.stringify_keys
add_default_name_and_id(options)
if size = options.delete("size")
options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
end
- content_tag("textarea", ERB::Util.html_escape(options.delete('value') || value_before_type_cast(object)), options)
+ content_tag("textarea", options.delete('value') || value_before_type_cast(object), options)
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/text_field.rb b/actionpack/lib/action_view/helpers/tags/text_field.rb
index ce5182d20f..024a1a8af2 100644
--- a/actionpack/lib/action_view/helpers/tags/text_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/text_field.rb
@@ -4,8 +4,7 @@ module ActionView
class TextField < Base #:nodoc:
def render
options = @options.stringify_keys
- options["size"] = options["maxlength"] || DEFAULT_FIELD_OPTIONS["size"] unless options.key?("size")
- options = DEFAULT_FIELD_OPTIONS.merge(options)
+ options["size"] = options["maxlength"] unless options.key?("size")
options["type"] ||= field_type
options["value"] = options.fetch("value"){ value_before_type_cast(object) } unless field_type == "file"
options["value"] &&= ERB::Util.html_escape(options["value"])