aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view/helpers')
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb59
-rw-r--r--actionpack/lib/action_view/helpers/csrf_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb54
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb11
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb131
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/tags.rb48
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb5
-rw-r--r--actionpack/lib/action_view/helpers/tags/check_box.rb2
-rw-r--r--actionpack/lib/action_view/helpers/tags/collection_select.rb9
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_select.rb8
-rw-r--r--actionpack/lib/action_view/helpers/tags/label.rb2
-rw-r--r--actionpack/lib/action_view/helpers/tags/select.rb28
-rw-r--r--actionpack/lib/action_view/helpers/tags/text_field.rb8
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb56
17 files changed, 235 insertions, 200 deletions
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 973135e2ea..1187956081 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -16,7 +16,9 @@ module ActionView
end
end
- module_eval "def content_tag(*) error_wrapping(super) end", __FILE__, __LINE__
+ def content_tag(*)
+ error_wrapping(super)
+ end
def tag(type, options, *)
tag_generate_errors?(options) ? error_wrapping(super) : super
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 5dbba3c4a7..40a950c644 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/hash/keys'
require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers'
require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers'
require 'action_view/helpers/asset_tag_helpers/asset_paths'
@@ -232,7 +234,7 @@ module ActionView
#
# generates
#
- # <link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
+ # <link href="/assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
#
# You may specify a different file in the first argument:
#
@@ -250,7 +252,7 @@ module ActionView
#
# <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %>
#
- def favicon_link_tag(source='/favicon.ico', options={})
+ def favicon_link_tag(source='favicon.ico', options={})
tag('link', {
:rel => 'shortcut icon',
:type => 'image/vnd.microsoft.icon',
@@ -353,8 +355,8 @@ module ActionView
# <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
# image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # =>
# <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
- def image_tag(source, options = {})
- options.symbolize_keys!
+ def image_tag(source, options={})
+ options = options.dup.symbolize_keys!
src = options[:src] = path_to_image(source)
@@ -407,26 +409,19 @@ module ActionView
# <video src="/trailers/hd.avi" width="16" height="16" />
# video_tag("/trailers/hd.avi", :height => '32', :width => '32') # =>
# <video height="32" src="/trailers/hd.avi" width="32" />
+ # video_tag("trailer.ogg", "trailer.flv") # =>
+ # <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
# video_tag(["trailer.ogg", "trailer.flv"]) # =>
- # <video><source src="trailer.ogg" /><source src="trailer.ogg" /><source src="trailer.flv" /></video>
+ # <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
# video_tag(["trailer.ogg", "trailer.flv"] :size => "160x120") # =>
- # <video height="120" width="160"><source src="trailer.ogg" /><source src="trailer.flv" /></video>
- def video_tag(sources, options = {})
- options.symbolize_keys!
+ # <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
+ def video_tag(*sources)
+ multiple_sources_tag('video', sources) do |options|
+ options[:poster] = path_to_image(options[:poster]) if options[:poster]
- options[:poster] = path_to_image(options[:poster]) if options[:poster]
-
- if size = options.delete(:size)
- options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
- end
-
- if sources.is_a?(Array)
- content_tag("video", options) do
- sources.map { |source| tag("source", :src => source) }.join.html_safe
+ if size = options.delete(:size)
+ options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
end
- else
- options[:src] = path_to_video(sources)
- tag("video", options)
end
end
@@ -441,10 +436,10 @@ module ActionView
# <audio src="/audios/sound.wav" />
# audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
# <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
- def audio_tag(source, options = {})
- options.symbolize_keys!
- options[:src] = path_to_audio(source)
- tag("audio", options)
+ # audio_tag("sound.wav", "sound.mid") # =>
+ # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
+ def audio_tag(*sources)
+ multiple_sources_tag('audio', sources)
end
private
@@ -452,6 +447,22 @@ module ActionView
def asset_paths
@asset_paths ||= AssetTagHelper::AssetPaths.new(config, controller)
end
+
+ def multiple_sources_tag(type, sources)
+ options = sources.extract_options!.dup.symbolize_keys!
+ sources.flatten!
+
+ yield options if block_given?
+
+ if sources.size > 1
+ content_tag(type, options) do
+ safe_join sources.map { |source| tag("source", :src => send("path_to_#{type}", source)) }
+ end
+ else
+ options[:src] = send("path_to_#{type}", sources.first)
+ tag(type, options)
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/csrf_helper.rb b/actionpack/lib/action_view/helpers/csrf_helper.rb
index 1f2bc28cac..eeb0ed94b9 100644
--- a/actionpack/lib/action_view/helpers/csrf_helper.rb
+++ b/actionpack/lib/action_view/helpers/csrf_helper.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/string/strip'
-
module ActionView
# = Action View CSRF Helper
module Helpers
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index f5077b034a..2d37923825 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -142,6 +142,8 @@ module ActionView
# ==== Options
# * <tt>:use_month_numbers</tt> - Set to true if you want to use month numbers rather than month names (e.g.
# "2" instead of "February").
+ # * <tt>:use_two_digit_numbers</tt> - Set to true if you want to display two digit month and day numbers (e.g.
+ # "02" instead of "February" and "08" instead of "8").
# * <tt>:use_short_month</tt> - Set to true if you want to use abbreviated month names instead of full
# month names (e.g. "Feb" instead of "February").
# * <tt>:add_month_numbers</tt> - Set to true if you want to use both month numbers and month names (e.g.
@@ -189,6 +191,10 @@ module ActionView
# date_select("article", "written_on", :start_year => 1995, :use_month_numbers => true,
# :discard_day => true, :include_blank => true)
#
+ # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute,
+ # # with two digit numbers used for months and days.
+ # date_select("article", "written_on", :use_two_digit_numbers => true)
+ #
# # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute
# # with the fields ordered as day, month, year rather than month, day, year.
# date_select("article", "written_on", :order => [:day, :month, :year])
@@ -502,6 +508,7 @@ module ActionView
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
# The <tt>date</tt> can also be substituted for a day number.
+ # If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'day' by default.
#
# ==== Examples
@@ -513,6 +520,9 @@ module ActionView
# # Generates a select field for days that defaults to the number given.
# select_day(5)
#
+ # # Generates a select field for days that defaults to the number given, but displays it with two digits.
+ # select_day(5, :use_two_digit_numbers => true)
+ #
# # Generates a select field for days that defaults to the day for the date in my_date
# # that is named 'due' rather than 'day'.
# select_day(my_time, :field_name => 'due')
@@ -532,6 +542,7 @@ module ActionView
# want both numbers and names, set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer
# to show month names as abbreviations, set the <tt>:use_short_month</tt> key in +options+ to true. If you want
# to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
+ # If you want to display months with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
#
# ==== Examples
@@ -559,6 +570,10 @@ module ActionView
# # will use keys like "Januar", "Marts."
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
#
+ # # Generates a select field for months that defaults to the current month that
+ # # will use keys with two digit numbers like "01", "03".
+ # select_month(Date.today, :use_two_digit_numbers => true)
+ #
# # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_month(14, :prompt => 'Choose month')
@@ -734,7 +749,7 @@ module ActionView
def select_day
if @options[:use_hidden] || @options[:discard_day]
- build_hidden(:day, day)
+ build_hidden(:day, day || 1)
else
build_options_and_select(:day, day, :start => 1, :end => 31, :leading_zeros => false, :use_two_digit_numbers => @options[:use_two_digit_numbers])
end
@@ -742,7 +757,7 @@ module ActionView
def select_month
if @options[:use_hidden] || @options[:discard_month]
- build_hidden(:month, month)
+ build_hidden(:month, month || 1)
else
month_options = []
1.upto(12) do |month_number|
@@ -756,7 +771,7 @@ module ActionView
def select_year
if !@datetime || @datetime == 0
- val = ''
+ val = '1'
middle_year = Date.today.year
else
val = middle_year = year
@@ -817,6 +832,9 @@ module ActionView
# If <tt>:use_month_numbers</tt> option is passed
# month_name(1) => 1
#
+ # If <tt>:use_two_month_numbers</tt> option is passed
+ # month_name(1) => '01'
+ #
# If <tt>:add_month_numbers</tt> option is passed
# month_name(1) => "1 - January"
def month_name(number)
@@ -836,7 +854,15 @@ module ActionView
end
def translated_date_order
- I18n.translate(:'date.order', :locale => @options[:locale]) || []
+ date_order = I18n.translate(:'date.order', :locale => @options[:locale], :default => [])
+
+ forbidden_elements = date_order - [:year, :month, :day]
+ if forbidden_elements.any?
+ raise StandardError,
+ "#{@options[:locale]}.date.order only accepts :year, :month and :day"
+ end
+
+ date_order
end
# Build full select tag from date type and options.
@@ -850,6 +876,12 @@ module ActionView
# <option value="2">2</option>
# <option value="3">3</option>..."
#
+ # If <tt>:use_two_digit_numbers => true</tt> option is passed
+ # build_options(15, :start => 1, :end => 31, :use_two_digit_numbers => true)
+ # => "<option value="1">01</option>
+ # <option value="2">02</option>
+ # <option value="3">03</option>..."
+ #
# If <tt>:step</tt> options is passed
# build_options(15, :start => 1, :end => 31, :step => 2)
# => "<option value="1">1</option>
@@ -958,18 +990,12 @@ module ActionView
# Returns the separator for a given datetime component.
def separator(type)
case type
- when :year
- @options[:discard_year] ? "" : @options[:date_separator]
- when :month
- @options[:discard_month] ? "" : @options[:date_separator]
- when :day
- @options[:discard_day] ? "" : @options[:date_separator]
+ when :year, :month, :day
+ @options[:"discard_#{type}"] ? "" : @options[:date_separator]
when :hour
(@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
- when :minute
- @options[:discard_minute] ? "" : @options[:time_separator]
- when :second
- @options[:include_seconds] ? @options[:time_separator] : ""
+ when :minute, :second
+ @options[:"discard_#{type}"] ? "" : @options[:time_separator]
end
end
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index e323350608..c4cdfef4a2 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -334,7 +334,7 @@ module ActionView
end.join("\n").html_safe
end
- # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
+ # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning
# the result of a call to the +value_method+ as the option value and the +text_method+ as the option text.
# Example:
# options_from_collection_for_select(@people, 'id', 'name')
@@ -418,9 +418,9 @@ module ActionView
# wrap the output in an appropriate <tt><select></tt> tag.
def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
collection.map do |group|
- group_label_string = eval("group.#{group_label_method}")
+ group_label_string = group.send(group_label_method)
"<optgroup label=\"#{ERB::Util.html_escape(group_label_string)}\">" +
- options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key) +
+ options_from_collection_for_select(group.send(group_method), option_key_method, option_value_method, selected_key) +
'</optgroup>'
end.join.html_safe
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 57b90a9c42..e97f602728 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -627,7 +627,7 @@ module ActionView
token_tag(authenticity_token)
else
html_options["method"] = "post"
- tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag(authenticity_token)
+ method_tag(method) + token_tag(authenticity_token)
end
tags = utf8_enforcer_tag << method_tag
@@ -646,15 +646,6 @@ module ActionView
output.safe_concat("</form>")
end
- def token_tag(token)
- if token == false || !protect_against_forgery?
- ''
- else
- token ||= form_authenticity_token
- tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
- end
- end
-
# see http://www.w3.org/TR/html4/types.html#type-name
def sanitize_to_id(name)
name.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "_")
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 43122ef2ba..b0860f87c4 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -57,15 +57,11 @@ module ActionView
# # => +1.123.555.1234 x 1343
def number_to_phone(number, options = {})
return unless number
+ options = options.symbolize_keys
- begin
- Float(number)
- rescue ArgumentError, TypeError
- raise InvalidNumberError, number
- end if options[:raise]
+ parse_float(number, true) if options[:raise]
number = number.to_s.strip
- options = options.symbolize_keys
area_code = options[:area_code]
delimiter = options[:delimiter] || "-"
extension = options[:extension]
@@ -75,7 +71,7 @@ module ActionView
number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
else
number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
- number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
+ number.slice!(0, 1) if number.start_with?(delimiter) && !delimiter.blank?
end
str = []
@@ -122,14 +118,12 @@ module ActionView
# # => 1234567890,50 &pound;
def number_to_currency(number, options = {})
return unless number
+ options = options.symbolize_keys
- options.symbolize_keys!
-
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
+ currency = translations_for('currency', options[:locale])
currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
- defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
+ defaults = DEFAULT_CURRENCY_VALUES.merge(defaults_translations(options[:locale])).merge!(currency)
defaults[:negative_format] = "-" + options[:format] if options[:format]
options = defaults.merge!(options)
@@ -152,7 +146,6 @@ module ActionView
e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
end
end
-
end
# Formats a +number+ as a percentage string (e.g., 65%). You can customize the format in the +options+ hash.
@@ -169,6 +162,8 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator
# (defaults to +false+).
+ # * <tt>:format</tt> - Specifies the format of the percentage string
+ # The number field is <tt>%n</tt> (defaults to "%n%").
# * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# ==== Examples
@@ -180,26 +175,27 @@ module ActionView
# number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
# number_to_percentage(1000, :locale => :fr) # => 1 000,000%
# number_to_percentage("98a") # => 98a%
+ # number_to_percentage(100, :format => "%n %") # => 100 %
#
# number_to_percentage("98a", :raise => true) # => InvalidNumberError
def number_to_percentage(number, options = {})
return unless number
+ options = options.symbolize_keys
- options.symbolize_keys!
+ defaults = format_translations('percentage', options[:locale])
+ options = defaults.merge!(options)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(percentage)
-
- options = options.reverse_merge(defaults)
+ format = options[:format] || "%n%"
begin
- "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe
+ value = number_with_precision(number, options.merge(:raise => true))
+ format.gsub(/%n/, value).html_safe
rescue InvalidNumberError => e
if options[:raise]
raise
else
- e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%"
+ formatted_number = format.gsub(/%n/, e.number)
+ e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
end
end
end
@@ -229,25 +225,15 @@ module ActionView
#
# number_with_delimiter("112a", :raise => true) # => raise InvalidNumberError
def number_with_delimiter(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ parse_float(number, options[:raise]) or return number
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- options = options.reverse_merge(defaults)
+ options = defaults_translations(options[:locale]).merge(options)
parts = number.to_s.to_str.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
parts.join(options[:separator]).html_safe
-
end
# Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision
@@ -264,6 +250,7 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator
# (defaults to +false+).
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# ==== Examples
# number_with_precision(111.2345) # => 111.235
@@ -282,23 +269,13 @@ module ActionView
# number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
# # => 1.111,23
def number_with_precision(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(precision_defaults)
+ defaults = format_translations('precision', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults) # Allow the user to unset default values: Eg.: :significant => false
precision = options.delete :precision
significant = options.delete :significant
strip_insignificant_zeros = options.delete :strip_insignificant_zeros
@@ -323,7 +300,6 @@ module ActionView
else
formatted_number
end
-
end
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
@@ -343,6 +319,7 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+)
# * <tt>:prefix</tt> - If +:si+ formats the number using the SI prefix (defaults to :binary)
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
# ==== Examples
# number_to_human_size(123) # => 123 Bytes
# number_to_human_size(1234) # => 1.21 KB
@@ -359,23 +336,13 @@ module ActionView
# number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB"
# number_to_human_size(524288000, :precision => 5) # => "500 MB"
def number_to_human_size(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(human)
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults)
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
@@ -424,6 +391,7 @@ module ActionView
# * *integers*: <tt>:unit</tt>, <tt>:ten</tt>, <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>, <tt>:billion</tt>, <tt>:trillion</tt>, <tt>:quadrillion</tt>
# * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>, <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>, <tt>:pico</tt>, <tt>:femto</tt>
# * <tt>:format</tt> - Sets the format of the output string (defaults to "%n %u"). The field types are:
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# %u The quantifier (ex.: 'thousand')
# %n The number
@@ -478,23 +446,13 @@ module ActionView
# number_to_human(0.34, :units => :distance) # => "34 centimeters"
#
def number_to_human(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(human)
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults)
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
@@ -530,6 +488,25 @@ module ActionView
decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe
end
+ private
+
+ def format_translations(namespace, locale)
+ defaults_translations(locale).merge(translations_for(namespace, locale))
+ end
+
+ def defaults_translations(locale)
+ I18n.translate(:'number.format', :locale => locale, :default => {})
+ end
+
+ def translations_for(namespace, locale)
+ I18n.translate(:"number.#{namespace}.format", :locale => locale, :default => {})
+ end
+
+ def parse_float(number, raise_error)
+ Float(number)
+ rescue ArgumentError, TypeError
+ raise InvalidNumberError, number if raise_error
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index d7a2651bad..ecd26891d6 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -118,7 +118,7 @@ module ActionView
# escape_once("&lt;&lt; Accept & Checkout")
# # => "&lt;&lt; Accept &amp; Checkout"
def escape_once(html)
- html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
+ ERB::Util.html_escape_once(html)
end
private
diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb
index 89b3efda5f..e874d4ca42 100644
--- a/actionpack/lib/action_view/helpers/tags.rb
+++ b/actionpack/lib/action_view/helpers/tags.rb
@@ -1,28 +1,30 @@
module ActionView
module Helpers
- module Tags
- autoload :Base, 'action_view/helpers/tags/base'
- autoload :Label, 'action_view/helpers/tags/label'
- autoload :TextField, 'action_view/helpers/tags/text_field'
- autoload :PasswordField, 'action_view/helpers/tags/password_field'
- autoload :HiddenField, 'action_view/helpers/tags/hidden_field'
- autoload :FileField, 'action_view/helpers/tags/file_field'
- autoload :SearchField, 'action_view/helpers/tags/search_field'
- autoload :TelField, 'action_view/helpers/tags/tel_field'
- autoload :UrlField, 'action_view/helpers/tags/url_field'
- autoload :EmailField, 'action_view/helpers/tags/email_field'
- autoload :NumberField, 'action_view/helpers/tags/number_field'
- autoload :RangeField, 'action_view/helpers/tags/range_field'
- autoload :TextArea, 'action_view/helpers/tags/text_area'
- autoload :CheckBox, 'action_view/helpers/tags/check_box'
- autoload :RadioButton, 'action_view/helpers/tags/radio_button'
- autoload :Select, 'action_view/helpers/tags/select'
- autoload :CollectionSelect, 'action_view/helpers/tags/collection_select'
- autoload :GroupedCollectionSelect, 'action_view/helpers/tags/grouped_collection_select'
- autoload :TimeZoneSelect, 'action_view/helpers/tags/time_zone_select'
- autoload :DateSelect, 'action_view/helpers/tags/date_select'
- autoload :TimeSelect, 'action_view/helpers/tags/time_select'
- autoload :DatetimeSelect, 'action_view/helpers/tags/datetime_select'
+ module Tags #:nodoc:
+ extend ActiveSupport::Autoload
+
+ autoload :Base
+ autoload :Label
+ autoload :TextField
+ autoload :PasswordField
+ autoload :HiddenField
+ autoload :FileField
+ autoload :SearchField
+ autoload :TelField
+ autoload :UrlField
+ autoload :EmailField
+ autoload :NumberField
+ autoload :RangeField
+ autoload :TextArea
+ autoload :CheckBox
+ autoload :RadioButton
+ autoload :Select
+ autoload :CollectionSelect
+ autoload :GroupedCollectionSelect
+ autoload :TimeZoneSelect
+ autoload :DateSelect
+ autoload :TimeSelect
+ autoload :DatetimeSelect
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index 24956beb9c..449f94d347 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -19,8 +19,9 @@ module ActionView
@auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match
end
- def render(&block)
- raise "Abstract Method called"
+ # This is what child classes implement.
+ def render
+ raise NotImplementedError, "Subclasses must implement a render method"
end
private
diff --git a/actionpack/lib/action_view/helpers/tags/check_box.rb b/actionpack/lib/action_view/helpers/tags/check_box.rb
index b3bd6eb2ad..7ad5de0596 100644
--- a/actionpack/lib/action_view/helpers/tags/check_box.rb
+++ b/actionpack/lib/action_view/helpers/tags/check_box.rb
@@ -25,7 +25,7 @@ module ActionView
add_default_name_and_id(options)
end
- hidden = @unchecked_value ? tag("input", "name" => options["name"], "type" => "hidden", "value" => @unchecked_value, "disabled" => options["disabled"]) : ""
+ hidden = @unchecked_value ? tag("input", "name" => options["name"], "type" => "hidden", "value" => @unchecked_value, "disabled" => options["disabled"]) : "".html_safe
checkbox = tag("input", options)
hidden + checkbox
end
diff --git a/actionpack/lib/action_view/helpers/tags/collection_select.rb b/actionpack/lib/action_view/helpers/tags/collection_select.rb
index f84140d8d0..ec78e6e5f9 100644
--- a/actionpack/lib/action_view/helpers/tags/collection_select.rb
+++ b/actionpack/lib/action_view/helpers/tags/collection_select.rb
@@ -12,9 +12,14 @@ module ActionView
end
def render
- selected_value = @options.has_key?(:selected) ? @options[:selected] : value(@object)
+ option_tags_options = {
+ :selected => @options.fetch(:selected) { value(@object) },
+ :disabled => @options[:disabled]
+ }
+
select_content_tag(
- options_from_collection_for_select(@collection, @value_method, @text_method, :selected => selected_value, :disabled => @options[:disabled]), @options, @html_options
+ options_from_collection_for_select(@collection, @value_method, @text_method, option_tags_options),
+ @options, @html_options
)
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/date_select.rb b/actionpack/lib/action_view/helpers/tags/date_select.rb
index 5912598ca1..5d706087b0 100644
--- a/actionpack/lib/action_view/helpers/tags/date_select.rb
+++ b/actionpack/lib/action_view/helpers/tags/date_select.rb
@@ -12,10 +12,16 @@ module ActionView
error_wrapping(datetime_selector(@options, @html_options).send("select_#{select_type}").html_safe)
end
+ class << self
+ def select_type
+ @select_type ||= self.name.split("::").last.sub("Select", "").downcase
+ end
+ end
+
private
def select_type
- self.class.name.split("::").last.sub("Select", "").downcase
+ self.class.select_type
end
def datetime_selector(options, html_options)
diff --git a/actionpack/lib/action_view/helpers/tags/label.rb b/actionpack/lib/action_view/helpers/tags/label.rb
index 74ac92ee18..1bd71c2778 100644
--- a/actionpack/lib/action_view/helpers/tags/label.rb
+++ b/actionpack/lib/action_view/helpers/tags/label.rb
@@ -30,7 +30,7 @@ module ActionView
add_default_name_and_id_for_value(tag_value, name_and_id)
options.delete("index")
options.delete("namespace")
- options["for"] ||= name_and_id["id"]
+ options["for"] = name_and_id["id"] unless options.key?("for")
if block_given?
@template_object.label_tag(name_and_id["id"], options, &block)
diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionpack/lib/action_view/helpers/tags/select.rb
index 71fd4d04b7..53a108b7e6 100644
--- a/actionpack/lib/action_view/helpers/tags/select.rb
+++ b/actionpack/lib/action_view/helpers/tags/select.rb
@@ -4,27 +4,37 @@ module ActionView
class Select < Base #:nodoc:
def initialize(object_name, method_name, template_object, choices, options, html_options)
@choices = choices
+ @choices = @choices.to_a if @choices.is_a?(Range)
@html_options = html_options
super(object_name, method_name, template_object, options)
end
def render
- selected_value = @options.has_key?(:selected) ? @options[:selected] : value(@object)
+ option_tags_options = {
+ :selected => @options.fetch(:selected) { value(@object) },
+ :disabled => @options[:disabled]
+ }
- # Grouped choices look like this:
- #
- # [nil, []]
- # { nil => [] }
- #
- if !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last
- option_tags = grouped_options_for_select(@choices, :selected => selected_value, :disabled => @options[:disabled])
+ option_tags = if grouped_choices?
+ grouped_options_for_select(@choices, option_tags_options)
else
- option_tags = options_for_select(@choices, :selected => selected_value, :disabled => @options[:disabled])
+ options_for_select(@choices, option_tags_options)
end
select_content_tag(option_tags, @options, @html_options)
end
+
+ private
+
+ # Grouped choices look like this:
+ #
+ # [nil, []]
+ # { nil => [] }
+ #
+ def grouped_choices?
+ !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/text_field.rb b/actionpack/lib/action_view/helpers/tags/text_field.rb
index 0f81726eb4..ce5182d20f 100644
--- a/actionpack/lib/action_view/helpers/tags/text_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/text_field.rb
@@ -13,10 +13,16 @@ module ActionView
tag("input", options)
end
+ class << self
+ def field_type
+ @field_type ||= self.name.split("::").last.sub("Field", "").downcase
+ end
+ end
+
private
def field_type
- @field_type ||= self.class.name.split("::").last.sub("Field", "").downcase
+ self.class.field_type
end
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index ebd1f280a8..b5fc882e31 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -323,33 +323,24 @@ module ActionView
# #
def button_to(name, options = {}, html_options = {})
html_options = html_options.stringify_keys
- convert_boolean_attributes!(html_options, %w( disabled ))
+ convert_boolean_attributes!(html_options, %w(disabled))
- method_tag = ''
- if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
- method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
- end
+ url = options.is_a?(String) ? options : url_for(options)
+ remote = html_options.delete('remote')
+
+ method = html_options.delete('method').to_s
+ method_tag = %w{put delete}.include?(method) ? method_tag(method) : ""
- form_method = method.to_s == 'get' ? 'get' : 'post'
+ form_method = method == 'get' ? 'get' : 'post'
form_options = html_options.delete('form') || {}
form_options[:class] ||= html_options.delete('form_class') || 'button_to'
+ form_options.merge!(:method => form_method, :action => url)
+ form_options.merge!("data-remote" => "true") if remote
- remote = html_options.delete('remote')
-
- request_token_tag = ''
- if form_method == 'post' && protect_against_forgery?
- request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
- end
-
- url = options.is_a?(String) ? options : self.url_for(options)
- name ||= url
+ request_token_tag = form_method == 'post' ? token_tag : ''
html_options = convert_options_to_data_attributes(options, html_options)
-
- html_options.merge!("type" => "submit", "value" => name)
-
- form_options.merge!(:method => form_method, :action => url)
- form_options.merge!("data-remote" => "true") if remote
+ html_options.merge!("type" => "submit", "value" => name || url)
"#{tag(:form, form_options, true)}<div>#{method_tag}#{tag("input", html_options)}#{request_token_tag}</div></form>".html_safe
end
@@ -476,7 +467,7 @@ module ActionView
# string given as the value.
# * <tt>:subject</tt> - Preset the subject line of the email.
# * <tt>:body</tt> - Preset the body of the email.
- # * <tt>:cc</tt> - Carbon Copy addition recipients on the email.
+ # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
# * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
#
# ==== Examples
@@ -599,11 +590,7 @@ module ActionView
# We ignore any extra parameters in the request_uri if the
# submitted url doesn't have any either. This lets the function
# work with things like ?order=asc
- if url_string.index("?")
- request_uri = request.fullpath
- else
- request_uri = request.path
- end
+ request_uri = url_string.index("?") ? request.fullpath : request.path
if url_string =~ /^\w+:\/\//
url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
@@ -633,12 +620,12 @@ module ActionView
end
def link_to_remote_options?(options)
- options.is_a?(Hash) && options.key?('remote') && options.delete('remote')
+ options.is_a?(Hash) && options.delete('remote')
end
def add_method_to_attributes!(html_options, method)
if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
- html_options["rel"] = "#{html_options["rel"]} nofollow".strip
+ html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip
end
html_options["data-method"] = method
end
@@ -670,6 +657,19 @@ module ActionView
bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
html_options
end
+
+ def token_tag(token=nil)
+ if token == false || !protect_against_forgery?
+ ''
+ else
+ token ||= form_authenticity_token
+ tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
+ end
+ end
+
+ def method_tag(method)
+ tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
+ end
end
end
end