Skip to content

Commit 2dc1402

Browse files
pleaxjosevalim
authored andcommitted
added support for html attributes in options_for_select [rails#2165]
Signed-off-by: José Valim <[email protected]>
1 parent fc2480a commit 2dc1402

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

actionpack/lib/action_view/helpers/form_options_helper.rb

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,15 @@ def time_zone_select(object, method, priority_zones = nil, options = {}, html_op
270270
# options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
271271
# <option selected="selected">VISA</option>\n<option>MasterCard</option>\n<option selected="selected">Discover</option>
272272
#
273+
# You can optionally provide html attributes as the last element of the array.
274+
#
275+
# Examples:
276+
# options_for_select([ "Denmark", ["USA", {:class=>'bold'}], "Sweden" ], ["USA", "Sweden"])
277+
# <option value="Denmark">Denmark</option>\n<option value="USA" class="bold" selected="selected">USA</option>\n<option value="Sweden" selected="selected">Sweden</option>
278+
#
279+
# options_for_select([["Dollar", "$", {:class=>"bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]])
280+
# <option value="$" class="bold">Dollar</option>\n<option value="DKK" onclick="alert('HI');">Kroner</option>
281+
#
273282
# If you wish to specify disabled option tags, set +selected+ to be a hash, with <tt>:disabled</tt> being either a value
274283
# or array of values to be disabled. In this case, you can use <tt>:selected</tt> to specify selected option tags.
275284
#
@@ -291,10 +300,11 @@ def options_for_select(container, selected = nil)
291300
selected, disabled = extract_selected_and_disabled(selected)
292301

293302
options_for_select = container.inject([]) do |options, element|
303+
html_attributes = option_html_attributes(element)
294304
text, value = option_text_and_value(element)
295305
selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
296306
disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
297-
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
307+
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{html_escape(text.to_s)}</option>)
298308
end
299309

300310
options_for_select.join("\n").html_safe
@@ -486,9 +496,22 @@ def time_zone_options_for_select(selected = nil, priority_zones = nil, model = :
486496
end
487497

488498
private
499+
def option_html_attributes(element)
500+
return "" unless Array === element
501+
html_attributes = []
502+
element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v|
503+
html_attributes << " #{k}=\"#{html_escape(v.to_s)}\""
504+
end
505+
html_attributes.join
506+
end
507+
489508
def option_text_and_value(option)
490509
# Options are [text, value] pairs or strings used for both.
491-
if !option.is_a?(String) and option.respond_to?(:first) and option.respond_to?(:last)
510+
case
511+
when Array === option
512+
option = option.reject { |e| Hash === e }
513+
[option.first, option.last]
514+
when !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last)
492515
[option.first, option.last]
493516
else
494517
[option, option]

actionpack/test/template/form_options_helper_test.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,62 @@ def test_time_zone_select_with_default_time_zone_and_value
767767
html
768768
end
769769

770+
def test_options_for_select_with_element_attributes
771+
assert_dom_equal(
772+
"<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>",
773+
options_for_select([ [ "<Denmark>", { :class => 'bold' } ], [ "USA", { :onclick => "alert('Hello World');" } ], [ "Sweden" ], "Germany" ])
774+
)
775+
end
776+
777+
def test_options_for_select_with_element_attributes_and_selection
778+
assert_dom_equal(
779+
"<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>",
780+
options_for_select([ "<Denmark>", [ "USA", { :class => 'bold' } ], "Sweden" ], "USA")
781+
)
782+
end
783+
784+
def test_options_for_select_with_element_attributes_and_selection_array
785+
assert_dom_equal(
786+
"<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>",
787+
options_for_select([ "<Denmark>", [ "USA", { :class => 'bold' } ], "Sweden" ], [ "USA", "Sweden" ])
788+
)
789+
end
790+
791+
def test_option_html_attributes_from_without_hash
792+
assert_dom_equal(
793+
"",
794+
option_html_attributes([ 'foo', 'bar' ])
795+
)
796+
end
797+
798+
def test_option_html_attributes_with_single_element_hash
799+
assert_dom_equal(
800+
" class=\"fancy\"",
801+
option_html_attributes([ 'foo', 'bar', { :class => 'fancy' } ])
802+
)
803+
end
804+
805+
def test_option_html_attributes_with_multiple_element_hash
806+
assert_dom_equal(
807+
" class=\"fancy\" onclick=\"alert('Hello World');\"",
808+
option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ])
809+
)
810+
end
811+
812+
def test_option_html_attributes_with_multiple_hashes
813+
assert_dom_equal(
814+
" class=\"fancy\" onclick=\"alert('Hello World');\"",
815+
option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ])
816+
)
817+
end
818+
819+
def test_option_html_attributes_with_special_characters
820+
assert_dom_equal(
821+
" onclick=\"alert(&quot;&lt;code&gt;&quot;)\"",
822+
option_html_attributes([ 'foo', 'bar', { :onclick => %(alert("<code>")) } ])
823+
)
824+
end
825+
770826
def test_grouped_collection_select
771827
@continents = [
772828
Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")] ),

0 commit comments

Comments
 (0)