From ae70e9520ea3e8b58b8644da04e5cb6fa2804c5e Mon Sep 17 00:00:00 2001 From: Arthur Carlsson Date: Sat, 19 Jul 2008 12:49:34 +0200 Subject: [PATCH] options_for_select with html_options --- .../lib/action_view/helpers/form_options_helper.rb | 76 ++++++++++----- .../test/template/form_options_helper_test.rb | 100 ++++++++++++++++++- 2 files changed, 147 insertions(+), 29 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 9aae945..1f32132 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -170,8 +170,11 @@ module ActionView # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values - # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +selected+ - # may also be an array of values to be selected when using a multiple select. + # become lasts sorted by the hash's keys. If +selected+ is specified, the matching "last" or element will get the + # selected option-tag. +selected+ may also be an array of values to be selected when using a multiple select. + # +html_options+ may be either a hash or a proc. If it is a hash, the same HTML options will be applied for + # all generated option elements. If the +html_options+ parameter is a proc, the HTML options is calculated for each + # generated option element. # # Examples (call, result): # options_for_select([["Dollar", "$"], ["Kroner", "DKK"]]) @@ -186,14 +189,25 @@ module ActionView # options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"]) # \n\n # + # options_for_select({"Dollar" => "$", "Kroner" => "DKK", "Kronor" => "SEK"}, "Kronor", :style => 'color: blue;') + # \n\n + # + # options_for_select({"Dollar" => "$", "Kroner" => "DKK", "Kronor" => "SEK"}, "Kronor", lambda { |text, value, selected| {:class => cycle("odd", "even")} }) + # \n\n + # # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. - def options_for_select(container, selected = nil) - container = container.to_a if Hash === container + def options_for_select(container, selected = nil, html_options = {}) + container = container.to_a.sort if Hash === container options_for_select = container.inject([]) do |options, element| text, value = option_text_and_value(element) - selected_attribute = ' selected="selected"' if option_value_selected?(value, selected) - options << %() + option_selected = option_value_selected?(value, selected) + + option_html_options = to_html_options(html_options, text, value, option_selected) + option_html_options[:value] = html_escape(value.to_s) + option_html_options[:selected] = 'selected' if option_selected + + options << content_tag('option', html_escape(text.to_s), option_html_options) end options_for_select.join("\n") @@ -202,17 +216,18 @@ module ActionView # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the # the result of a call to the +value_method+ as the option value and the +text_method+ as the option text. # If +selected+ is specified, the element returning a match on +value_method+ will get the selected option tag. + # See options_for_select for the usage of the +html_options+ parameter. # # Example (call, result). Imagine a loop iterating over each +person+ in @project.people to generate an input tag: # options_from_collection_for_select(@project.people, "id", "name") # # # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. - def options_from_collection_for_select(collection, value_method, text_method, selected = nil) + def options_from_collection_for_select(collection, value_method, text_method, selected = nil, html_options = {}) options = collection.map do |element| [element.send(text_method), element.send(value_method)] end - options_for_select(options, selected) + options_for_select(options, selected, html_options) end # Returns a string of tags, like options_from_collection_for_select, but @@ -231,6 +246,10 @@ module ActionView # * +selected_key+ - A value equal to the +value+ attribute for one of the tags, # which will have the +selected+ attribute set. Corresponds to the return value of one of the calls # to +option_key_method+. If +nil+, no selection is made. + # * +group_html_options+ - Options passed as attributes to the optgroup element in the same way as + # the +html_options+ parameter for options_for_select. + # * +option_html_options+ - Options passed as attributes to the option element in the same way as + # the +html_options+ parameter for options_for_select. # # Example object structure for use with this method: # class Continent < ActiveRecord::Base @@ -243,29 +262,28 @@ module ActionView # end # # Sample usage: - # option_groups_from_collection_for_select(@continents, :countries, :name, :id, :name, 3) + # option_groups_from_collection_for_select(@continents, :countries, :name, :id, :name, 3, {:class => "continent"}, {:class => "country"}) # # Possible output: - # - # - # + # + # + # # ... # - # - # - # - # + # + # + # + # # ... # # # Note: Only the and tags are returned, so you still have to # wrap the output in an appropriate