Permalink
Browse files

added support for html attributes in options_for_select [#2165]

Signed-off-by: José Valim <jose.valim@gmail.com>
  • Loading branch information...
1 parent fc2480a commit 2dc1402417242784a738321e7edd521f8ec7ac83 @pleax pleax committed with josevalim May 15, 2010
@@ -270,6 +270,15 @@ def time_zone_select(object, method, priority_zones = nil, options = {}, html_op
# options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
# <option selected="selected">VISA</option>\n<option>MasterCard</option>\n<option selected="selected">Discover</option>
#
+ # You can optionally provide html attributes as the last element of the array.
+ #
+ # Examples:
+ # options_for_select([ "Denmark", ["USA", {:class=>'bold'}], "Sweden" ], ["USA", "Sweden"])
+ # <option value="Denmark">Denmark</option>\n<option value="USA" class="bold" selected="selected">USA</option>\n<option value="Sweden" selected="selected">Sweden</option>
+ #
+ # options_for_select([["Dollar", "$", {:class=>"bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]])
+ # <option value="$" class="bold">Dollar</option>\n<option value="DKK" onclick="alert('HI');">Kroner</option>
+ #
# If you wish to specify disabled option tags, set +selected+ to be a hash, with <tt>:disabled</tt> being either a value
# or array of values to be disabled. In this case, you can use <tt>:selected</tt> to specify selected option tags.
#
@@ -291,10 +300,11 @@ def options_for_select(container, selected = nil)
selected, disabled = extract_selected_and_disabled(selected)
options_for_select = container.inject([]) do |options, element|
+ html_attributes = option_html_attributes(element)
text, value = option_text_and_value(element)
selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
- options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
+ options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{html_escape(text.to_s)}</option>)
end
options_for_select.join("\n").html_safe
@@ -486,9 +496,22 @@ def time_zone_options_for_select(selected = nil, priority_zones = nil, model = :
end
private
+ def option_html_attributes(element)
+ return "" unless Array === element
+ html_attributes = []
+ element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v|
+ html_attributes << " #{k}=\"#{html_escape(v.to_s)}\""
+ end
+ html_attributes.join
+ end
+
def option_text_and_value(option)
# Options are [text, value] pairs or strings used for both.
- if !option.is_a?(String) and option.respond_to?(:first) and option.respond_to?(:last)
+ case
+ when Array === option
+ option = option.reject { |e| Hash === e }
+ [option.first, option.last]
+ when !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last)
[option.first, option.last]
else
[option, option]
@@ -767,6 +767,62 @@ def test_time_zone_select_with_default_time_zone_and_value
html
end
+ def test_options_for_select_with_element_attributes
+ assert_dom_equal(
+ "<option value=\"&lt;Denmark&gt;\" class=\"bold\">&lt;Denmark&gt;</option>\n<option value=\"USA\" onclick=\"alert('Hello World');\">USA</option>\n<option value=\"Sweden\">Sweden</option>\n<option value=\"Germany\">Germany</option>",
+ options_for_select([ [ "<Denmark>", { :class => 'bold' } ], [ "USA", { :onclick => "alert('Hello World');" } ], [ "Sweden" ], "Germany" ])
+ )
+ end
+
+ def test_options_for_select_with_element_attributes_and_selection
+ assert_dom_equal(
+ "<option value=\"&lt;Denmark&gt;\">&lt;Denmark&gt;</option>\n<option value=\"USA\" class=\"bold\" selected=\"selected\">USA</option>\n<option value=\"Sweden\">Sweden</option>",
+ options_for_select([ "<Denmark>", [ "USA", { :class => 'bold' } ], "Sweden" ], "USA")
+ )
+ end
+
+ def test_options_for_select_with_element_attributes_and_selection_array
+ assert_dom_equal(
+ "<option value=\"&lt;Denmark&gt;\">&lt;Denmark&gt;</option>\n<option value=\"USA\" class=\"bold\" selected=\"selected\">USA</option>\n<option value=\"Sweden\" selected=\"selected\">Sweden</option>",
+ options_for_select([ "<Denmark>", [ "USA", { :class => 'bold' } ], "Sweden" ], [ "USA", "Sweden" ])
+ )
+ end
+
+ def test_option_html_attributes_from_without_hash
+ assert_dom_equal(
+ "",
+ option_html_attributes([ 'foo', 'bar' ])
+ )
+ end
+
+ def test_option_html_attributes_with_single_element_hash
+ assert_dom_equal(
+ " class=\"fancy\"",
+ option_html_attributes([ 'foo', 'bar', { :class => 'fancy' } ])
+ )
+ end
+
+ def test_option_html_attributes_with_multiple_element_hash
+ assert_dom_equal(
+ " class=\"fancy\" onclick=\"alert('Hello World');\"",
+ option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ])
+ )
+ end
+
+ def test_option_html_attributes_with_multiple_hashes
+ assert_dom_equal(
+ " class=\"fancy\" onclick=\"alert('Hello World');\"",
+ option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ])
+ )
+ end
+
+ def test_option_html_attributes_with_special_characters
+ assert_dom_equal(
+ " onclick=\"alert(&quot;&lt;code&gt;&quot;)\"",
+ option_html_attributes([ 'foo', 'bar', { :onclick => %(alert("<code>")) } ])
+ )
+ end
+
def test_grouped_collection_select
@continents = [
Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")] ),

0 comments on commit 2dc1402

Please sign in to comment.