diff options
Diffstat (limited to 'actionpack/lib/action_view/helpers/form_options_helper.rb')
-rw-r--r-- | actionpack/lib/action_view/helpers/form_options_helper.rb | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb new file mode 100644 index 0000000000..ca3798ede6 --- /dev/null +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -0,0 +1,212 @@ +require 'cgi' +require 'erb' +require File.dirname(__FILE__) + '/form_helper' + +module ActionView + module Helpers + # Provides a number of methods for turning different kinds of containers into a set of option tags. Neither of the methods provide + # the actual select tag, so you'll need to construct that in HTML manually. + module FormOptionsHelper + include ERB::Util + + def select(object, method, choices, options = {}, html_options = {}) + InstanceTag.new(object, method, self).to_select_tag(choices, options, html_options) + end + + def collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {}) + InstanceTag.new(object, method, self).to_collection_select_tag(collection, value_method, text_method, options, html_options) + end + + def country_select(object, method, priority_countries = nil, options = {}, html_options = {}) + InstanceTag.new(object, method, self).to_country_select_tag(priority_countries, options, html_options) + end + + # 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. + # + # Examples (call, result): + # options_for_select([["Dollar", "$"], ["Kroner", "DKK"]]) + # <option value="$">Dollar</option>\n<option value="DKK">Kroner</option> + # + # options_for_select([ "VISA", "Mastercard" ], "Mastercard") + # <option>VISA</option>\n<option selected="selected">Mastercard</option> + # + # options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40") + # <option value="$20">Basic</option>\n<option value="$40" selected="selected">Plus</option> + # + # options_for_select([ "VISA", "Mastercard", "Discover" ], ["VISA", "Discover"]) + # <option selected="selected">VISA</option>\n<option>Mastercard</option>\n<option selected="selected">Discover</option> + def options_for_select(container, selected = nil) + container = container.to_a if Hash === container + + options_for_select = container.inject([]) do |options, element| + if element.respond_to?(:first) && element.respond_to?(:last) + is_selected = ( (selected.respond_to?(:include?) ? selected.include?(element.last) : element.last == selected) ) + if is_selected + options << "<option value=\"#{html_escape(element.last.to_s)}\" selected=\"selected\">#{html_escape(element.first.to_s)}</option>" + else + options << "<option value=\"#{html_escape(element.last.to_s)}\">#{html_escape(element.first.to_s)}</option>" + end + else + is_selected = ( (selected.respond_to?(:include?) ? selected.include?(element) : element == selected) ) + options << ((is_selected) ? "<option selected=\"selected\">#{html_escape(element.to_s)}</option>" : "<option>#{html_escape(element.to_s)}</option>") + end + end + + options_for_select.join("\n") + end + + # Returns a string of option tags that has 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_value+ is specified, the element returning a match on +value_method+ will get the selected option tag. + # + # Example (call, result). Imagine a loop iterating over each +person+ in <tt>@project.people</tt> to generate a input tag: + # options_from_collection_for_select(@project.people, "id", "name") + # <option value="#{person.id}">#{person.name}</option> + def options_from_collection_for_select(collection, value_method, text_method, selected_value = nil) + options_for_select( + collection.inject([]) { |options, object| options << [ object.send(text_method), object.send(value_method) ] }, + selected_value + ) + end + + # Returns a string of option tags, like options_from_collection_for_select, but surrounds them by <optgroup> tags. + # + # An array of group objects are passed. Each group should return an array of options when calling group_method + # Each group should should return its name when calling group_label_method. + # + # html_option_groups_from_collection(@continents, "countries", "contient_name", "country_id", "country_name", @selected_country.id) + # + # Could become: + # <optgroup label="Africa"> + # <select>Egypt</select> + # <select>Rwanda</select> + # ... + # </optgroup> + # <optgroup label="Asia"> + # <select>China</select> + # <select>India</select> + # <select>Japan</select> + # ... + # </optgroup> + # + # with objects of the following classes: + # class Continent + # def initialize(p_name, p_countries) @continent_name = p_name; @countries = p_countries; end + # def continent_name() @continent_name; end + # def countries() @countries; end + # end + # class Country + # def initialize(id, name) @id = id; @name = name end + # def country_id() @id; end + # def country_name() @name; end + # end + def option_groups_from_collection_for_select(collection, group_method, group_label_method, + option_key_method, option_value_method, selected_key = nil) + collection.inject("") do |options_for_select, group| + group_label_string = eval("group.#{group_label_method}") + options_for_select += "<optgroup label=\"#{html_escape(group_label_string)}\">" + options_for_select += options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key) + options_for_select += '</optgroup>' + end + end + + # Returns a string of option tags for pretty much any country in the world. Supply a country name as +selected+ to + # have it marked as the selected option tag. You can also supply an array of countries as +priority_countries+, so + # that they will be listed above the rest of the (long) list. + def country_options_for_select(selected = nil, priority_countries = nil) + country_options = "" + + if priority_countries + country_options += options_for_select(priority_countries, selected) + country_options += "<option>-------------</option>\n" + end + + if priority_countries && priority_countries.include?(selected) + country_options += options_for_select(COUNTRIES - priority_countries, selected) + else + country_options += options_for_select(COUNTRIES, selected) + end + + return country_options + end + + + private + # All the countries included in the country_options output. + COUNTRIES = [ "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", + "Antarctica", "Antigua And Barbuda", "Argentina", "Armenia", "Aruba", "Australia", + "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", + "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", + "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory", + "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burma", "Burundi", "Cambodia", + "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", + "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", + "Comoros", "Congo", "Congo, the Democratic Republic of the", "Cook Islands", + "Costa Rica", "Cote d'Ivoire", "Croatia", "Cyprus", "Czech Republic", "Denmark", + "Djibouti", "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", + "El Salvador", "England", "Equatorial Guinea", "Eritrea", "Espana", "Estonia", + "Ethiopia", "Falkland Islands", "Faroe Islands", "Fiji", "Finland", "France", + "French Guiana", "French Polynesia", "French Southern Territories", "Gabon", "Gambia", + "Georgia", "Germany", "Ghana", "Gibraltar", "Great Britain", "Greece", "Greenland", + "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", + "Haiti", "Heard and Mc Donald Islands", "Honduras", "Hong Kong", "Hungary", "Iceland", + "India", "Indonesia", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan", + "Kazakhstan", "Kenya", "Kiribati", "Korea, Republic of", "Korea (South)", "Kuwait", + "Kyrgyzstan", "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", + "Liberia", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia", + "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", + "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", + "Micronesia, Federated States of", "Moldova, Republic of", "Monaco", "Mongolia", + "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", + "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", + "Niger", "Nigeria", "Niue", "Norfolk Island", "Northern Ireland", + "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Panama", + "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Pitcairn", "Poland", + "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russia", "Rwanda", + "Saint Kitts and Nevis", "Saint Lucia", "Saint Vincent and the Grenadines", + "Samoa (Independent)", "San Marino", "Sao Tome and Principe", "Saudi Arabia", + "Scotland", "Senegal", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", + "Slovenia", "Solomon Islands", "Somalia", "South Africa", + "South Georgia and the South Sandwich Islands", "South Korea", "Spain", "Sri Lanka", + "St. Helena", "St. Pierre and Miquelon", "Suriname", "Svalbard and Jan Mayen Islands", + "Swaziland", "Sweden", "Switzerland", "Taiwan", "Tajikistan", "Tanzania", "Thailand", + "Togo", "Tokelau", "Tonga", "Trinidad", "Trinidad and Tobago", "Tunisia", "Turkey", + "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", + "United Arab Emirates", "United Kingdom", "United States", + "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", + "Vatican City State (Holy See)", "Venezuela", "Viet Nam", "Virgin Islands (British)", + "Virgin Islands (U.S.)", "Wales", "Wallis and Futuna Islands", "Western Sahara", + "Yemen", "Zambia", "Zimbabwe" ] unless const_defined?("COUNTRIES") + end + + class InstanceTag #:nodoc: + include FormOptionsHelper + + def to_select_tag(choices, options, html_options) + add_default_name_and_id(html_options) + content_tag("select", add_blank_option(options_for_select(choices, value), options[:include_blank]), html_options) + end + + def to_collection_select_tag(collection, value_method, text_method, options, html_options) + add_default_name_and_id(html_options) + content_tag( + "select", add_blank_option(options_from_collection_for_select(collection, value_method, text_method, value), options[:include_blank]), html_options + ) + end + + def to_country_select_tag(priority_countries, options, html_options) + add_default_name_and_id(html_options) + content_tag("select", add_blank_option(country_options_for_select(value, priority_countries), options[:include_blank]), html_options) + end + + private + def add_blank_option(option_tags, add_blank) + add_blank ? "<option></option>\n" + option_tags : option_tags + end + end + end +end |