diff options
Diffstat (limited to 'actionpack/lib')
9 files changed, 201 insertions, 174 deletions
diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb index 45a5aff8bd..090ca33cef 100644 --- a/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -15,7 +15,7 @@ module ActionView module ActiveRecordHelper # Returns a default input tag for the type of object returned by the method. Example # (title is a VARCHAR column and holds "Hello World"): - # input("post", "title") => + # input("post", "title") => # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /> def input(record_name, method) InstanceTag.new(record_name, method, self).to_tag @@ -41,7 +41,7 @@ module ActionView # It's possible to specialize the form builder by using a different action name and by supplying another # block renderer. Example (entry is a new record that has a message attribute using VARCHAR): # - # form("entry", :action => "sign", :input_block => + # form("entry", :action => "sign", :input_block => # Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}<br />" }) => # # <form action='/post/sign' method='post'> @@ -56,16 +56,17 @@ module ActionView # form << content_tag("b", "Department") # form << collection_select("department", "id", @departments, "id", "name") # end - def form(record_name, options = {}) - record = instance_eval("@#{record_name}") + def form(record_name, options = nil) + options = (options || {}).symbolize_keys + record = instance_eval("@#{record_name}") options[:action] ||= record.new_record? ? "create" : "update" - action = url_for(:action => options[:action]) + action = url_for(:action => options[:action]) submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize - + id_field = record.new_record? ? "" : InstanceTag.new(record_name, "id", self).to_input_field_tag("hidden") - + formtag = %(<form action="#{action}" method="post">#{id_field}) + all_input_tags(record, record_name, options) yield formtag if block_given? formtag + %(<input type="submit" value="#{submit_value}" /></form>) @@ -73,7 +74,7 @@ module ActionView # Returns a string containing the error message attached to the +method+ on the +object+, if one exists. # This error message is wrapped in a DIV tag, which can be specialized to include both a +prepend_text+ and +append_text+ - # to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message + # to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message # "can't be empty" on the title attribute): # # <%= error_message_on "post", "title" %> => @@ -86,19 +87,20 @@ module ActionView "<div class=\"#{css_class}\">#{prepend_text + (errors.is_a?(Array) ? errors.first : errors) + append_text}</div>" end end - + # Returns a string with a div containing all the error messages for the object located as an instance variable by the name # of <tt>object_name</tt>. This div can be tailored by the following options: # # * <tt>header_tag</tt> - Used for the header of the error div (default: h2) # * <tt>id</tt> - The id of the error div (default: errorExplanation) # * <tt>class</tt> - The class of the error div (default: errorExplanation) - def error_messages_for(object_name, options={}) + def error_messages_for(object_name, options = {}) + options = options.symbolize_keys object = instance_eval "@#{object_name}" unless object.errors.empty? content_tag("div", content_tag( - options[:header_tag] || "h2", + options[:header_tag] || "h2", "#{pluralize(object.errors.count, "error")} prohibited this #{object_name.gsub("_", " ")} from being saved" ) + content_tag("p", "There were problems with the following fields:") + @@ -107,7 +109,7 @@ module ActionView ) end end - + private def all_input_tags(record, record_name, options) input_block = options[:input_block] || default_input_block @@ -116,7 +118,7 @@ module ActionView def default_input_block Proc.new { |record, column| "<p><label for=\"#{record}_#{column.name}\">#{column.human_name}</label><br />#{input(record, column.name)}</p>" } - end + end end class InstanceTag #:nodoc: diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 33914b2144..2f3bd71d5a 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -10,15 +10,15 @@ module ActionView # either be <tt>:rss</tt> (default) or <tt>:atom</tt> and the +options+ follow the url_for style of declaring a link target. # # Examples: - # auto_discovery_link_tag # => + # auto_discovery_link_tag # => # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/action" /> - # auto_discovery_link_tag(:atom) # => + # auto_discovery_link_tag(:atom) # => # <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/action" /> - # auto_discovery_link_tag(:rss, :action => "feed") # => + # auto_discovery_link_tag(:rss, :action => "feed") # => # <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/feed" /> def auto_discovery_link_tag(type = :rss, options = {}) tag( - "link", "rel" => "alternate", "type" => "application/#{type}+xml", "title" => type.to_s.upcase, + "link", "rel" => "alternate", "type" => "application/#{type}+xml", "title" => type.to_s.upcase, "href" => url_for(options.merge(:only_path => false)) ) end @@ -38,7 +38,7 @@ module ActionView content_tag("script", "", "language" => "JavaScript", "type" => "text/javascript", "src" => source) }.join("\n") end - + # Returns a css link tag per source given as argument. Examples: # # stylesheet_link_tag "style" # => @@ -48,7 +48,7 @@ module ActionView # <link href="/stylesheets/random.styles" media="screen" rel="Stylesheet" type="text/css" /> # <link href="/css/stylish.css" media="screen" rel="Stylesheet" type="text/css" /> def stylesheet_link_tag(*sources) - sources.collect { |source| + sources.collect { |source| source = "/stylesheets/#{source}" unless source.include?("/") source = "#{source}.css" unless source.include?(".") tag("link", "rel" => "Stylesheet", "type" => "text/css", "media" => "screen", "href" => source) diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 03a34c93f1..7ec24f2428 100755 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -5,7 +5,7 @@ module ActionView # The Date Helper primarily creates select/option tags for different kinds of dates and date elements. All of the select-type methods # share a number of common options that are as follows: # - # * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" would give + # * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" would give # birthday[month] instead of date[month] if passed to the select_month method. # * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date. # * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true, the select_month @@ -13,11 +13,11 @@ module ActionView module DateHelper DEFAULT_PREFIX = "date" unless const_defined?("DEFAULT_PREFIX") - # Reports the approximate distance in time between to Time objects. For example, if the distance is 47 minutes, it'll return + # Reports the approximate distance in time between to Time objects. For example, if the distance is 47 minutes, it'll return # "about 1 hour". See the source for the complete wording list. def distance_of_time_in_words(from_time, to_time) distance_in_minutes = ((to_time - from_time) / 60).round - + case distance_in_minutes when 0 then "less than a minute" when 1 then "1 minute" @@ -28,7 +28,7 @@ module ActionView else "#{(distance_in_minutes / 1440).round} days" end end - + # Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>. def distance_of_time_in_words_to_now(from_time) distance_of_time_in_words(from_time, Time.now) @@ -48,7 +48,7 @@ module ActionView # # date_select("post", "written_on") # date_select("post", "written_on", :start_year => 1995) - # date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true, + # date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true, # :discard_day => true, :include_blank => true) # date_select("post", "written_on", :order => [:day, :month, :year]) # date_select("user", "birthday", :order => [:month, :day]) @@ -107,7 +107,7 @@ module ActionView 0.upto(59) do |minute| minute_options << ((datetime.kind_of?(Fixnum) ? datetime : datetime.min) == minute ? - "<option selected=\"selected\">#{leading_zero_on_single_digits(minute)}</option>\n" : + "<option selected=\"selected\">#{leading_zero_on_single_digits(minute)}</option>\n" : "<option>#{leading_zero_on_single_digits(minute)}</option>\n" ) end @@ -122,7 +122,7 @@ module ActionView 0.upto(23) do |hour| hour_options << ((datetime.kind_of?(Fixnum) ? datetime : datetime.hour) == hour ? - "<option selected=\"selected\">#{leading_zero_on_single_digits(hour)}</option>\n" : + "<option selected=\"selected\">#{leading_zero_on_single_digits(hour)}</option>\n" : "<option>#{leading_zero_on_single_digits(hour)}</option>\n" ) end @@ -137,18 +137,18 @@ module ActionView 1.upto(31) do |day| day_options << ((date.kind_of?(Fixnum) ? date : date.day) == day ? - "<option selected=\"selected\">#{day}</option>\n" : + "<option selected=\"selected\">#{day}</option>\n" : "<option>#{day}</option>\n" ) end select_html("day", day_options, options[:prefix], options[:include_blank], options[:discard_type]) end - + # Returns a select tag with options for each of the months January through December with the current month selected. # The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are used as values # (what's submitted to the server). It's also possible to use month numbers for the presentation instead of names -- - # set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names, + # set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names, # set the <tt>:add_month_numbers</tt> key in +options+ to true. Examples: # # select_month(Date.today) # Will use keys like "January", "March" @@ -158,7 +158,7 @@ module ActionView month_options = [] 1.upto(12) do |month_number| - month_name = if options[:use_month_numbers] + month_name = if options[:use_month_numbers] month_number elsif options[:add_month_numbers] month_number.to_s + " - " + Date::MONTHNAMES[month_number] @@ -167,16 +167,16 @@ module ActionView end month_options << ((date.kind_of?(Fixnum) ? date : date.month) == month_number ? - %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) : + %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) : %(<option value="#{month_number}">#{month_name}</option>\n) ) end select_html("month", month_options, options[:prefix], options[:include_blank], options[:discard_type]) end - + # Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius - # can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. The <tt>date</tt> can also be substituted + # can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. The <tt>date</tt> can also be substituted # for a year given as a number. Example: # # select_year(Date.today, :start_year => 1992, :end_year => 2007) @@ -187,14 +187,14 @@ module ActionView (options[:start_year] || default_start_year).upto(options[:end_year] || default_end_year) do |year| year_options << ((date.kind_of?(Fixnum) ? date : date.year) == year ? - "<option selected=\"selected\">#{year}</option>\n" : + "<option selected=\"selected\">#{year}</option>\n" : "<option>#{year}</option>\n" ) end select_html("year", year_options, options[:prefix], options[:include_blank], options[:discard_type]) end - + private def select_html(type, options, prefix = nil, include_blank = false, discard_type = false) select_html = %(<select name="#{prefix || DEFAULT_PREFIX}) @@ -206,7 +206,7 @@ module ActionView return select_html end - + def leading_zero_on_single_digits(number) number > 9 ? number : "0#{number}" end @@ -217,32 +217,32 @@ module ActionView def to_date_select_tag(options = {}) defaults = { :discard_type => true } - options = defaults.merge(options) - options_with_prefix = Proc.new { |position| options.update({ :prefix => "#{@object_name}[#{@method_name}(#{position}i)]" }) } + options = defaults.merge(options) + options_with_prefix = Proc.new { |position| options.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") } date = options[:include_blank] ? (value || 0) : (value || Date.today) - date_select = "" + date_select = "" options[:order] = [:month, :year, :day] if options[:month_before_year] # For backwards compatibility options[:order] ||= [:year, :month, :day] position = {:year => 1, :month => 2, :day => 3} - + discard = {} discard[:year] = true if options[:discard_year] discard[:month] = true if options[:discard_month] discard[:day] = true if options[:discard_day] or options[:discard_month] - + options[:order].each do |param| date_select << self.send("select_#{param}", date, options_with_prefix.call(position[param])) unless discard[param] end return date_select end - + def to_datetime_select_tag(options = {}) defaults = { :discard_type => true } - options = defaults.merge(options) - options_with_prefix = Proc.new { |position| options.update({ :prefix => "#{@object_name}[#{@method_name}(#{position}i)]" }) } + options = defaults.merge(options) + options_with_prefix = Proc.new { |position| options.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") } datetime = options[:include_blank] ? (value || 0) : (value || Time.now) datetime_select = select_year(datetime, options_with_prefix.call(1)) @@ -250,7 +250,7 @@ module ActionView datetime_select << select_day(datetime, options_with_prefix.call(3)) unless options[:discard_day] || options[:discard_month] datetime_select << " — " + select_hour(datetime, options_with_prefix.call(4)) unless options[:discard_hour] datetime_select << " : " + select_minute(datetime, options_with_prefix.call(5)) unless options[:discard_minute] || options[:discard_hour] - + return datetime_select end end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 2c9589194c..e4b90e42f2 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -8,10 +8,10 @@ module ActionView # The following is an example of a complete form for a person object that works for both creates and updates built # with all the form helpers. The <tt>@person</tt> object was assigned by an action on the controller: # <form action="save_person" method="post"> - # Name: + # Name: # <%= text_field "person", "name", "size" => 20 %> # - # Password: + # Password: # <%= password_field "person", "password", "maxsize" => 20 %> # # Single?: @@ -26,12 +26,12 @@ module ActionView # ...is compiled to: # # <form action="save_person" method="post"> - # Name: - # <input type="text" id="person_name" name="person[name]" + # Name: + # <input type="text" id="person_name" name="person[name]" # size="20" value="<%= @person.name %>" /> # - # Password: - # <input type="password" id="person_password" name="person[password]" + # Password: + # <input type="password" id="person_password" name="person[password]" # size="20" maxsize="20" value="<%= @person.password %>" /> # # Single?: @@ -43,7 +43,7 @@ module ActionView # </textarea> # # <input type="submit" value="Save"> - # </form> + # </form> # # If the helper is being used to generate a repetitive sequence of similar form elements, for example in a partial # used by render_collection_of_partials, the "index" option may come in handy. Example: @@ -51,10 +51,10 @@ module ActionView # <%= text_field "person", "name", "index" => 1 %> # # becomes - # + # # <input type="text" id="person_1_name" name="person[1][name]" value="<%= @person.name %>" /> # - # There's also methods for helping to build form tags in link:classes/ActionView/Helpers/FormOptionsHelper.html, + # There's also methods for helping to build form tags in link:classes/ActionView/Helpers/FormOptionsHelper.html, # link:classes/ActionView/Helpers/DateHelper.html, and link:classes/ActionView/Helpers/ActiveRecordHelper.html module FormHelper # Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object @@ -64,7 +64,7 @@ module ActionView # Examples (call, result): # text_field("post", "title", "size" => 20) # <input type="text" id="post_title" name="post[title]" size="20" value="#{@post.title}" /> - def text_field(object, method, options = {}) + def text_field(object, method, options = {}) InstanceTag.new(object, method, self).to_input_field_tag("text", options) end @@ -95,12 +95,12 @@ module ActionView def text_area(object, method, options = {}) InstanceTag.new(object, method, self).to_text_area_tag(options) end - + # Returns a checkbox tag tailored for accessing a specified attribute (identified by +method+) on an object # assigned to the template (identified by +object+). It's intended that +method+ returns an integer and if that # integer is above zero, then the checkbox is checked. Additional options on the input tag can be passed as a # hash with +options+. The +checked_value+ defaults to 1 while the default +unchecked_value+ - # is set to 0 which is convenient for boolean values. Usually unchecked checkboxes don't post anything. + # is set to 0 which is convenient for boolean values. Usually unchecked checkboxes don't post anything. # We work around this problem by adding a hidden value with the same name as the checkbox. # # Example (call, result). Imagine that @post.validated? returns 1: @@ -119,13 +119,13 @@ module ActionView # Returns a radio button tag for accessing a specified attribute (identified by +method+) on an object # assigned to the template (identified by +object+). If the current value of +method+ is +tag_value+ the # radio button will be checked. Additional options on the input tag can be passed as a - # hash with +options+. + # hash with +options+. # Example (call, result). Imagine that @post.category returns "rails": # radio_button("post", "category", "rails") # radio_button("post", "category", "java") # <input type="radio" id="post_category" name="post[category] value="rails" checked="checked" /> # <input type="radio" id="post_category" name="post[category] value="java" /> - # + # def radio_button(object, method, tag_value, options = {}) InstanceTag.new(object, method, self).to_radio_button_tag(tag_value, options) end @@ -135,9 +135,10 @@ module ActionView include Helpers::TagHelper attr_reader :method_name, :object_name - - DEFAULT_FIELD_OPTIONS = { "size" => 30 } unless const_defined?("DEFAULT_FIELD_OPTIONS") - DEFAULT_TEXT_AREA_OPTIONS = { "wrap" => "virtual", "cols" => 40, "rows" => 20 } unless const_defined?("DEFAULT_TEXT_AREA_OPTIONS") + + DEFAULT_FIELD_OPTIONS = { "size" => 30 }.freeze unless const_defined?(:DEFAULT_FIELD_OPTIONS) + DEFAULT_TEXT_AREA_OPTIONS = { "wrap" => "virtual", "cols" => 40, "rows" => 20 }.freeze unless const_defined?(:DEFAULT_TEXT_AREA_OPTIONS) + DEFAULT_DATE_OPTIONS = { :discard_type => true }.freeze unless const_defined?(:DEFAULT_DATE_OPTIONS) def initialize(object_name, method_name, template_object, local_binding = nil) @object_name, @method_name = object_name, method_name @@ -146,50 +147,69 @@ module ActionView @auto_index = @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}").id end end - + def to_input_field_tag(field_type, options = {}) - html_options = DEFAULT_FIELD_OPTIONS.merge(options) - html_options.merge!({ "size" => options["maxlength"]}) if options["maxlength"] && !options["size"] - html_options.delete("size") if field_type == "hidden" - html_options.merge!({ "type" => field_type}) - html_options.merge!({ "value" => value_before_type_cast }) if options["value"].nil? && field_type != "file" - add_default_name_and_id(html_options) - tag("input", html_options) - end - - def to_radio_button_tag(tag_value, options={}) - html_options = DEFAULT_FIELD_OPTIONS.merge(options) - html_options.merge!({ "checked" => "checked" }) if value == tag_value - html_options.merge!({ "type" => "radio", "value"=> tag_value.to_s }) - - add_default_name_and_id(html_options) - tag("input", html_options) - end - + options = options.stringify_keys + if field_type == "hidden" + options.delete("size") + else + options["size"] ||= options["maxlength"] || DEFAULT_FIELD_OPTIONS["size"] + end + options["type"] = field_type + options["value"] ||= value_before_type_cast unless field_type == "file" + add_default_name_and_id(options) + tag("input", options) + end + + def to_radio_button_tag(tag_value, options = {}) + options = DEFAULT_FIELD_OPTIONS.merge(options.stringify_keys) + options["type"] = "radio" + options["value"] = tag_value + options["checked"] = "checked" if value == tag_value + add_default_name_and_id(options) + tag("input", options) + end + def to_text_area_tag(options = {}) - options = DEFAULT_TEXT_AREA_OPTIONS.merge(options) + options = DEFAULT_TEXT_AREA_OPTIONS.merge(options.stringify_keys) add_default_name_and_id(options) content_tag("textarea", html_escape(value_before_type_cast), options) end def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0") - options.merge!({ "checked" => "checked" }) if !value.nil? && ((value.is_a?(TrueClass) || value.is_a?(FalseClass)) ? value : value.to_i > 0) - options.merge!({ "type" => "checkbox", "value" => checked_value }) + options = options.stringify_keys + options["type"] = "checkbox" + options["value"] = checked_value + checked = case value + when TrueClass, FalseClass + value + when NilClass + false + when Integer + value != 0 + else + value.to_i != 0 + end + if checked + options["checked"] = "checked" + else + options.delete("checked") + end add_default_name_and_id(options) - tag("input", options) << tag("input", ({ "name" => options['name'], "type" => "hidden", "value" => unchecked_value })) + tag("input", options) << tag("input", "name" => options["name"], "type" => "hidden", "value" => unchecked_value) end def to_date_tag() - defaults = { "discard_type" => true } + defaults = DEFAULT_DATE_OPTIONS.dup date = value || Date.today - options = Proc.new { |position| defaults.update({ :prefix => "#{@object_name}[#{@method_name}(#{position}i)]" }) } - + options = Proc.new { |position| defaults.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") } html_day_select(date, options.call(3)) + - html_month_select(date, options.call(2)) + + html_month_select(date, options.call(2)) + html_year_select(date, options.call(1)) end def to_boolean_select_tag(options = {}) + options = options.stringify_keys add_default_name_and_id(options) tag_text = "<select" tag_text << tag_options(options) @@ -210,7 +230,7 @@ module ActionView def value_before_type_cast unless object.nil? - object.respond_to?(@method_name + "_before_type_cast") ? + object.respond_to?(@method_name + "_before_type_cast") ? object.send(@method_name + "_before_type_cast") : object.send(@method_name) end @@ -218,23 +238,23 @@ module ActionView private def add_default_name_and_id(options) - if options.has_key? "index" - options['name'] = tag_name_with_index(options["index"]) unless options.has_key? "name" - options['id'] = tag_id_with_index(options["index"]) unless options.has_key? "id" + if options.has_key?("index") + options["name"] ||= tag_name_with_index(options["index"]) + options["id"] ||= tag_id_with_index(options["index"]) options.delete("index") elsif @auto_index - options['name'] = tag_name_with_index(@auto_index) unless options.has_key? "name" - options['id'] = tag_id_with_index(@auto_index) unless options.has_key? "id" + options["name"] ||= tag_name_with_index(@auto_index) + options["id"] ||= tag_id_with_index(@auto_index) else - options['name'] = tag_name unless options.has_key? "name" - options['id'] = tag_id unless options.has_key? "id" + options["name"] ||= tag_name + options["id"] ||= tag_id end end - + def tag_name "#{@object_name}[#{@method_name}]" end - + def tag_name_with_index(index) "#{@object_name}[#{index}][#{@method_name}]" end diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index aeef3bba74..99114b8694 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -25,7 +25,7 @@ module ActionView # Create a select tag and a series of contained option tags for the provided object and method. # The option currently held by the object will be selected, provided that the object is available. - # + # # This can be used to provide a default set of options in the standard way: before rendering the create form, a # new model instance is assigned the default options and bound to @model_name. Usually this model is not saved # to the database. Instead, a second model object is created when the create request is received. @@ -34,17 +34,17 @@ module ActionView def select(object, method, choices, options = {}, html_options = {}) InstanceTag.new(object, method, self).to_select_tag(choices, options, html_options) end - + # Return select and option tags for the given object and method using options_from_collection_for_select to generate the list of option tags. 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 - + # Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags. 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 - + # Return select and option tags for the given object and method, using # #time_zone_options_for_select to generate the list of option tags. # @@ -57,11 +57,11 @@ module ActionView InstanceTag.new(object, method, self).to_time_zone_select_tag(priority_zones, options, html_options) end - # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container + # 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. + # may also be an array of values to be selected when using a multiple select. # # Examples (call, result): # options_for_select([["Dollar", "$"], ["Kroner", "DKK"]]) @@ -79,8 +79,8 @@ module ActionView # 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 - - options_for_select = container.inject([]) do |options, element| + + 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 @@ -93,11 +93,11 @@ module ActionView 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 + # 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. # @@ -108,7 +108,7 @@ module ActionView # 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_value = nil) options_for_select( - collection.inject([]) { |options, object| options << [ object.send(text_method), object.send(value_method) ] }, + collection.inject([]) { |options, object| options << [ object.send(text_method), object.send(value_method) ] }, selected_value ) end @@ -135,18 +135,18 @@ module ActionView # # 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 + # 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 + # def initialize(id, name) @id = id; @name = name end + # def country_id() @id; end + # def country_name() @name; end # end # # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. - def option_groups_from_collection_for_select(collection, group_method, group_label_method, + 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}") @@ -154,16 +154,16 @@ module ActionView 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 + 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. # # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. 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" @@ -264,23 +264,27 @@ module ActionView include FormOptionsHelper def to_select_tag(choices, options, html_options) + html_options = html_options.stringify_keys 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) + html_options = html_options.stringify_keys 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) + html_options = html_options.stringify_keys 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 def to_time_zone_select_tag(priority_zones, options, html_options) + html_options = html_options.stringify_keys add_default_name_and_id(html_options) content_tag("select", add_blank_option( diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index a5b18fe7f0..60e3bbb67b 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -6,21 +6,20 @@ module ActionView # Provides a number of methods for creating form tags that doesn't rely on conventions with an object assigned to the template like # FormHelper does. With the FormTagHelper, you provide the names and values yourself. module FormTagHelper - # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like + # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like # ActionController::Base#url_for. The method for the form defaults to POST. # # Options: # * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data". def form_tag(url_for_options = {}, options = {}, *parameters_for_url) - html_options = { "method" => "post" }.merge(options) - + html_options = { "method" => "post" }.merge(options.stringify_keys) + if html_options[:multipart] html_options["enctype"] = "multipart/form-data" html_options.delete(:multipart) end - + html_options["action"] = url_for(url_for_options, *parameters_for_url) - tag("form", html_options, true) end @@ -32,48 +31,49 @@ module ActionView end def select_tag(name, option_tags = nil, options = {}) - content_tag("select", option_tags, { "name" => name, "id" => name }.update(options)) + content_tag("select", option_tags, { "name" => name, "id" => name }.update(options.stringify_keys)) end def text_field_tag(name, value = nil, options = {}) - tag("input", {"type" => "text", "name" => name, "id" => name, "value" => value}.update(options)) + tag("input", { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)) end def hidden_field_tag(name, value = nil, options = {}) - text_field_tag(name, value, options.update("type" => "hidden")) + text_field_tag(name, value, options.stringify_keys.update("type" => "hidden")) end def file_field_tag(name, options = {}) - text_field_tag(name, nil, options.update("type" => "file")) + text_field_tag(name, nil, options.stringify_keys.update("type" => "file")) end def password_field_tag(name = "password", value = nil, options = {}) - text_field_tag(name, value, options.update("type" => "password")) + text_field_tag(name, value, options.stringify_keys.update("type" => "password")) end def text_area_tag(name, content = nil, options = {}) - if options[:size] - options["cols"], options["rows"] = options[:size].split("x") - options.delete(:size) + options = options.stringify_keys + if options["size"] + options["cols"], options["rows"] = options["size"].split("x") + options.delete("size") end - - content_tag("textarea", content, { "name" => name, "id" => name }.update(options)) + + content_tag("textarea", content, { "name" => name, "id" => name }.update(options.stringify_keys)) end def check_box_tag(name, value = "1", checked = false, options = {}) - html_options = {"type" => "checkbox", "name" => name, "id" => name, "value" => value}.update(options) + html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys) html_options["checked"] = "checked" if checked tag("input", html_options) end def radio_button_tag(name, value, checked = false, options = {}) - html_options = {"type" => "radio", "name" => name, "id" => name, "value" => value}.update(options) + html_options = { "type" => "radio", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys) html_options["checked"] = "checked" if checked tag("input", html_options) end def submit_tag(value = "Save changes", options = {}) - tag("input", {"type" => "submit", "name" => "submit", "value" => value}.update(options)) + tag("input", { "type" => "submit", "name" => "submit", "value" => value }.update(options.stringify_keys)) end end end diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 5ebfecb8bd..fa74e3f4ee 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -7,14 +7,14 @@ module ActionView module TagHelper include ERB::Util - # Examples: + # Examples: # * <tt>tag("br") => <br /></tt> # * <tt>tag("input", { "type" => "text"}) => <input type="text" /></tt> def tag(name, options = {}, open = false) "<#{name}#{tag_options(options)}" + (open ? ">" : " />") end - - # Examples: + + # Examples: # * <tt>content_tag("p", "Hello world!") => <p>Hello world!</p></tt> # * <tt>content_tag("div", content_tag("p", "Hello world!"), "class" => "strong") => </tt> # <tt><div class="strong"><p>Hello world!</p></div></tt> @@ -26,7 +26,7 @@ module ActionView def tag_options(options) unless options.empty? " " + options.map { |key, value| - %(#{key}="#{html_escape(value)}") + %(#{key}="#{html_escape(value.to_s)}") }.sort.join(" ") end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 26a8b74faa..1c67e3efb4 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -1,7 +1,7 @@ module ActionView module Helpers #:nodoc: # Provides a set of methods for working with text strings that can help unburden the level of inline Ruby code in the - # templates. In the example below we iterate over a collection of posts provided to the template and prints each title + # templates. In the example below we iterate over a collection of posts provided to the template and prints each title # after making sure it doesn't run longer than 20 characters: # <% for post in @posts %> # Title: <%= truncate(post.title, 20) %> @@ -29,14 +29,14 @@ module ActionView if text.nil? || phrase.nil? then return end text.gsub(/(#{escape_regexp(phrase)})/i, highlighter) unless text.nil? end - + # Extracts an excerpt from the +text+ surrounding the +phrase+ with a number of characters on each side determined - # by +radius+. If the phrase isn't found, nil is returned. Ex: + # by +radius+. If the phrase isn't found, nil is returned. Ex: # excerpt("hello my world", "my", 3) => "...lo my wo..." def excerpt(text, phrase, radius = 100, excerpt_string = "...") if text.nil? || phrase.nil? then return end phrase = escape_regexp(phrase) - + if found_pos = text =~ /(#{phrase})/i start_pos = [ found_pos - radius, 0 ].max end_pos = [ found_pos + phrase.length + radius, text.length ].min @@ -58,7 +58,7 @@ module ActionView plural elsif Object.const_defined?("Inflector") Inflector.pluralize(singular) - else + else singular + "s" end end @@ -66,13 +66,13 @@ module ActionView begin require "redcloth" - # Returns the text with all the Textile codes turned into HTML-tags. + # Returns the text with all the Textile codes turned into HTML-tags. # <i>This method is only available if RedCloth can be required</i>. def textilize(text) text.empty? ? "" : RedCloth.new(text, [ :hard_breaks ]).to_html end - # Returns the text with all the Textile codes turned into HTML-tags, but without the regular bounding <p> tag. + # Returns the text with all the Textile codes turned into HTML-tags, but without the regular bounding <p> tag. # <i>This method is only available if RedCloth can be required</i>. def textilize_without_paragraph(text) textiled = textilize(text) @@ -87,7 +87,7 @@ module ActionView begin require "bluecloth" - # Returns the text with all the Markdown codes turned into HTML-tags. + # Returns the text with all the Markdown codes turned into HTML-tags. # <i>This method is only available if BlueCloth can be required</i>. def markdown(text) text.empty? ? "" : BlueCloth.new(text).to_html @@ -101,7 +101,7 @@ module ActionView # # Example: # auto_link("Go to http://www.rubyonrails.com and say hello to david@loudthinking.com") => - # Go to <a href="http://www.rubyonrails.com">http://www.rubyonrails.com</a> and + # Go to <a href="http://www.rubyonrails.com">http://www.rubyonrails.com</a> and # say hello to <a href="mailto:david@loudthinking.com">david@loudthinking.com</a> def auto_link(text, link = :all) case link @@ -115,7 +115,7 @@ module ActionView def strip_links(text) text.gsub(/<a.*>(.*)<\/a>/m, '\1') end - + private # Returns a version of the text that's safe to use in a regular expression without triggering engine features. def escape_regexp(text) @@ -133,4 +133,4 @@ module ActionView end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 951760b3ba..901374d877 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -7,26 +7,27 @@ module ActionView module UrlHelper # Returns the URL for the set of +options+ provided. See the valid options in link:classes/ActionController/Base.html#M000021 def url_for(options = {}, *parameters_for_method_reference) - if Hash === options then options = { :only_path => true }.merge(options) end + if Hash === options then options = { :only_path => true }.update(options.stringify_keys) end @controller.send(:url_for, options, *parameters_for_method_reference) end # Creates a link tag of the given +name+ using an URL created by the set of +options+. See the valid options in # link:classes/ActionController/Base.html#M000021. It's also possible to pass a string instead of an options hash to - # get a link tag that just points without consideration. If nil is passed as a name, the link itself will become the name. - # The html_options have a special feature for creating javascript confirm alerts where if you pass :confirm => 'Are you sure?', + # get a link tag that just points without consideration. If nil is passed as a name, the link itself will become the name. + # The html_options have a special feature for creating javascript confirm alerts where if you pass :confirm => 'Are you sure?', # the link will be guarded with a JS popup asking that question. If the user accepts, the link is processed, otherwise not. # # Example: # link_to "Delete this page", { :action => "destroy", :id => @page.id }, :confirm => "Are you sure?" - def link_to(name, options = {}, html_options = {}, *parameters_for_method_reference) - convert_confirm_option_to_javascript!(html_options) unless html_options.nil? + def link_to(name, options = {}, html_options = nil, *parameters_for_method_reference) + html_options = (html_options || {}).stringify_keys + convert_confirm_option_to_javascript!(html_options) if options.is_a?(String) - content_tag "a", name || options, (html_options || {}).merge({ "href" => options }) + content_tag "a", name || options, (html_options || {}).merge("href" => options) else content_tag( - "a", name || url_for(options, *parameters_for_method_reference), - (html_options || {}).merge({ "href" => url_for(options, *parameters_for_method_reference) }) + "a", name || url_for(options, *parameters_for_method_reference), + (html_options || {}).merge("href" => url_for(options, *parameters_for_method_reference)) ) end end @@ -41,7 +42,7 @@ module ActionView # * <tt>:border</tt> - Is set to 0 by default # * <tt>:align</tt> - Sets the alignment, no special features # - # The +src+ can be supplied as a... + # The +src+ can be supplied as a... # * full path, like "/my_images/image.gif" # * file name, like "rss.gif", that gets expanded to "/images/rss.gif" # * file name without extension, like "logo", that gets expanded to "/images/logo.png" @@ -51,8 +52,9 @@ module ActionView # link_image_to "delete", { :action => "destroy" }, :size => "10x10", :confirm => "Are you sure?", "class" => "admin" def link_image_to(src, options = {}, html_options = {}, *parameters_for_method_reference) image_options = { "src" => src.include?("/") ? src : "/images/#{src}" } - image_options["src"] = image_options["src"] + ".png" unless image_options["src"].include?(".") - + image_options["src"] += ".png" unless image_options["src"].include?(".") + + html_options = html_options.stringify_keys if html_options["alt"] image_options["alt"] = html_options["alt"] html_options.delete "alt" @@ -71,7 +73,7 @@ module ActionView else image_options["border"] = "0" end - + if html_options["align"] image_options["align"] = html_options["align"] html_options.delete "align" @@ -82,9 +84,9 @@ module ActionView alias_method :link_to_image, :link_image_to # deprecated name - # Creates a link tag of the given +name+ using an URL created by the set of +options+, unless the current + # Creates a link tag of the given +name+ using an URL created by the set of +options+, unless the current # request uri is the same as the link's, in which case only the name is returned (or the - # given block is yielded, if one exists). This is useful for creating link bars where you don't want to link + # given block is yielded, if one exists). This is useful for creating link bars where you don't want to link # to the page currently being viewed. def link_to_unless_current(name, options = {}, html_options = {}, *parameters_for_method_reference) if current_page?(options) @@ -107,8 +109,8 @@ module ActionView # mail_to "me@domain.com", "My email", :encode => "hex" # => # <a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a> def mail_to(email_address, name = nil, html_options = {}) - encode = html_options[:encode] - html_options.delete(:encode) + html_options = html_options.stringify_keys + encode = html_options.delete("encode") string = '' if encode == 'javascript' tmp = "document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address.to_s }))}');" @@ -137,9 +139,8 @@ module ActionView private def convert_confirm_option_to_javascript!(html_options) - if html_options.include?(:confirm) - html_options["onclick"] = "return confirm('#{html_options[:confirm]}');" - html_options.delete(:confirm) + if confirm = html_options.delete("confirm") + html_options["onclick"] = "return confirm('#{confirm}');" end end end |