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.rb7
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb49
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb23
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb32
-rw-r--r--actionpack/lib/action_view/helpers/deprecated_block_helpers.rb52
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb88
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb402
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb49
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb7
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb12
12 files changed, 479 insertions, 252 deletions
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index e3db2923f7..80b3d3a664 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -3,6 +3,7 @@ require 'action_view/helpers/form_helper'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/object/blank'
module ActionView
ActionView.base_hook do
@@ -127,7 +128,7 @@ module ActionView
object = convert_to_model(object)
if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
- (errors = obj.errors[method])
+ (errors = obj.errors[method]).presence
content_tag("div",
"#{options[:prepend_text]}#{ERB::Util.h(errors.first)}#{options[:append_text]}".html_safe,
:class => options[:css_class]
@@ -295,6 +296,10 @@ module ActionView
end
end
+ def error_message
+ object.errors[@method_name]
+ end
+
def column_type
object.send(:column_for_attribute, @method_name).type
end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index b594002629..02ad41719b 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -3,6 +3,7 @@ require 'cgi'
require 'action_view/helpers/url_helper'
require 'action_view/helpers/tag_helper'
require 'active_support/core_ext/file'
+require 'active_support/core_ext/object/blank'
module ActionView
module Helpers #:nodoc:
@@ -623,41 +624,37 @@ module ActionView
@@cache_asset_timestamps = true
private
+ def rewrite_extension?(source, dir, ext)
+ source_ext = File.extname(source)[1..-1]
+ ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}"))))
+ end
+
+ def rewrite_host_and_protocol(source, has_request)
+ host = compute_asset_host(source)
+ if has_request && host.present? && !is_uri?(host)
+ host = "#{controller.request.protocol}#{host}"
+ end
+ "#{host}#{source}"
+ end
+
# Add the the extension +ext+ if not present. Return full URLs otherwise untouched.
# Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
# roots. Rewrite the asset path for cache-busting asset ids. Include
# asset host, if configured, with the correct request protocol.
def compute_public_path(source, dir, ext = nil, include_host = true)
- has_request = controller.respond_to?(:request)
-
- source_ext = File.extname(source)[1..-1]
- if ext && !is_uri?(source) && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}"))))
- source += ".#{ext}"
- end
+ return source if is_uri?(source)
- unless is_uri?(source)
- source = "/#{dir}/#{source}" unless source[0] == ?/
+ source += ".#{ext}" if rewrite_extension?(source, dir, ext)
+ source = "/#{dir}/#{source}" unless source[0] == ?/
+ source = rewrite_asset_path(source)
- source = rewrite_asset_path(source)
-
- if has_request && include_host
- unless source =~ %r{^#{controller.config.relative_url_root}/}
- source = "#{controller.config.relative_url_root}#{source}"
- end
- end
+ has_request = controller.respond_to?(:request)
+ if has_request && include_host && source !~ %r{^#{controller.config.relative_url_root}/}
+ source = "#{controller.config.relative_url_root}#{source}"
end
+ source = rewrite_host_and_protocol(source, has_request) if include_host
- if include_host && !is_uri?(source)
- host = compute_asset_host(source)
-
- if has_request && !host.blank? && !is_uri?(host)
- host = "#{controller.request.protocol}#{host}"
- end
-
- "#{host}#{source}"
- else
- source
- end
+ source
end
def is_uri?(path)
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index d5cc14b29a..a904af56bb 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -32,7 +32,28 @@ module ActionView
# <i>Topics listed alphabetically</i>
# <% end %>
def cache(name = {}, options = nil, &block)
- controller.fragment_for(output_buffer, name, options, &block)
+ safe_concat fragment_for(name, options, &block)
+ nil
+ end
+
+ private
+ # TODO: Create an object that has caching read/write on it
+ def fragment_for(name = {}, options = nil, &block) #:nodoc:
+ if controller.perform_caching
+ if controller.fragment_exist?(name, options)
+ controller.read_fragment(name, options)
+ else
+ # VIEW TODO: Make #capture usable outside of ERB
+ # This dance is needed because Builder can't use capture
+ pos = output_buffer.length
+ yield
+ fragment = output_buffer.slice!(pos..-1)
+ controller.write_fragment(name, fragment, options)
+ end
+ else
+ ret = yield
+ ActiveSupport::SafeBuffer.new(ret) if ret.is_a?(String)
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 03c7ba5a87..f0be814700 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -2,22 +2,22 @@ module ActionView
module Helpers
# CaptureHelper exposes methods to let you extract generated markup which
# can be used in other parts of a template or layout file.
- # It provides a method to capture blocks into variables through capture and
+ # It provides a method to capture blocks into variables through capture and
# a way to capture a block of markup for use in a layout through content_for.
module CaptureHelper
- # The capture method allows you to extract part of a template into a
- # variable. You can then use this variable anywhere in your templates or layout.
- #
+ # The capture method allows you to extract part of a template into a
+ # variable. You can then use this variable anywhere in your templates or layout.
+ #
# ==== Examples
# The capture method can be used in ERb templates...
- #
+ #
# <% @greeting = capture do %>
# Welcome to my shiny new web page! The date and time is
# <%= Time.now %>
# <% end %>
#
# ...and Builder (RXML) templates.
- #
+ #
# @timestamp = capture do
# "The current timestamp is #{Time.now}."
# end
@@ -32,16 +32,18 @@ module ActionView
#
def capture(*args)
value = nil
- buffer = with_output_buffer { value = yield *args }
- buffer.presence || value
+ buffer = with_output_buffer { value = yield(*args) }
+ if string = buffer.presence || value and string.is_a?(String)
+ NonConcattingString.new(string)
+ end
end
# Calling content_for stores a block of markup in an identifier for later use.
# You can make subsequent calls to the stored content in other templates or the layout
# by passing the identifier as an argument to <tt>yield</tt>.
- #
+ #
# ==== Examples
- #
+ #
# <% content_for :not_authorized do %>
# alert('You are not authorized to do that!')
# <% end %>
@@ -75,7 +77,7 @@ module ActionView
#
# Then, in another view, you could to do something like this:
#
- # <%= link_to_remote 'Logout', :action => 'logout' %>
+ # <%= link_to 'Logout', :action => 'logout', :remote => true %>
#
# <% content_for :script do %>
# <%= javascript_include_tag :defaults %>
@@ -92,7 +94,7 @@ module ActionView
# <% end %>
#
# <%# Add some other content, or use a different template: %>
- #
+ #
# <% content_for :navigation do %>
# <li><%= link_to 'Login', :action => 'login' %></li>
# <% end %>
@@ -109,13 +111,13 @@ module ActionView
# for elements that will be fragment cached.
def content_for(name, content = nil, &block)
content = capture(&block) if block_given?
- return @_content_for[name] << content if content
- @_content_for[name]
+ @_content_for[name] << content if content
+ @_content_for[name] unless content
end
# content_for? simply checks whether any content has been captured yet using content_for
# Useful to render parts of your layout differently based on what is in your views.
- #
+ #
# ==== Examples
#
# Perhaps you will use different css in you layout if no content_for :right_column
diff --git a/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb b/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb
deleted file mode 100644
index 3d0657e873..0000000000
--- a/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-module ActionView
- module Helpers
- module DeprecatedBlockHelpers
- extend ActiveSupport::Concern
-
- include ActionView::Helpers::TagHelper
- include ActionView::Helpers::TextHelper
- include ActionView::Helpers::JavaScriptHelper
- include ActionView::Helpers::FormHelper
-
- def content_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def javascript_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def form_for(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def form_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def fields_for(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def field_set_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
-
- if RUBY_VERSION < '1.9.0'
- # Check whether we're called from an erb template.
- # We'd return a string in any other case, but erb <%= ... %>
- # can't take an <% end %> later on, so we have to use <% ... %>
- # and implicitly concat.
- def block_called_from_erb?(block)
- block && eval(BLOCK_CALLED_FROM_ERB, block)
- end
- else
- def block_called_from_erb?(block)
- block && eval(BLOCK_CALLED_FROM_ERB, block.binding)
- end
- end
- end
- end
-end \ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 6176f1fb06..2ba5339b7d 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -1014,7 +1014,7 @@ module ActionView
class FormBuilder #:nodoc:
# The methods which wrap a form helper call.
class_inheritable_accessor :field_helpers
- self.field_helpers = (FormHelper.instance_methods - ['form_for'])
+ self.field_helpers = (FormHelper.instance_method_names - ['form_for'])
attr_accessor :object_name, :object, :options
@@ -1040,7 +1040,7 @@ module ActionView
end
(field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector|
- src = <<-end_src
+ src, file, line = <<-end_src, __FILE__, __LINE__ + 1
def #{selector}(method, options = {}) # def text_field(method, options = {})
@template.send( # @template.send(
#{selector.inspect}, # "text_field",
@@ -1049,7 +1049,7 @@ module ActionView
objectify_options(options)) # objectify_options(options))
end # end
end_src
- class_eval src, __FILE__, __LINE__
+ class_eval src, file, line
end
def fields_for(record_or_name_or_array, *args, &block)
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index 07eee3b399..b0a7718f22 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -1,5 +1,4 @@
require 'action_view/helpers/tag_helper'
-require 'action_view/helpers/prototype_helper'
module ActionView
module Helpers
@@ -89,6 +88,93 @@ module ActionView
def javascript_cdata_section(content) #:nodoc:
"\n//#{cdata_section("\n#{content}\n//")}\n".html_safe
end
+
+ # Returns a button with the given +name+ text that'll trigger a JavaScript +function+ using the
+ # onclick handler.
+ #
+ # The first argument +name+ is used as the button's value or display text.
+ #
+ # The next arguments are optional and may include the javascript function definition and a hash of html_options.
+ #
+ # The +function+ argument can be omitted in favor of an +update_page+
+ # block, which evaluates to a string when the template is rendered
+ # (instead of making an Ajax request first).
+ #
+ # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button"
+ #
+ # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil
+ #
+ # Examples:
+ # button_to_function "Greeting", "alert('Hello world!')"
+ # button_to_function "Delete", "if (confirm('Really?')) do_delete()"
+ # button_to_function "Details" do |page|
+ # page[:details].visual_effect :toggle_slide
+ # end
+ # button_to_function "Details", :class => "details_button" do |page|
+ # page[:details].visual_effect :toggle_slide
+ # end
+ def button_to_function(name, *args, &block)
+ html_options = args.extract_options!.symbolize_keys
+
+ function = block_given? ? update_page(&block) : args[0] || ''
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
+
+ tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
+ end
+
+ # Returns a link of the given +name+ that will trigger a JavaScript +function+ using the
+ # onclick handler and return false after the fact.
+ #
+ # The first argument +name+ is used as the link text.
+ #
+ # The next arguments are optional and may include the javascript function definition and a hash of html_options.
+ #
+ # The +function+ argument can be omitted in favor of an +update_page+
+ # block, which evaluates to a string when the template is rendered
+ # (instead of making an Ajax request first).
+ #
+ # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button"
+ #
+ # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil
+ #
+ #
+ # Examples:
+ # link_to_function "Greeting", "alert('Hello world!')"
+ # Produces:
+ # <a onclick="alert('Hello world!'); return false;" href="#">Greeting</a>
+ #
+ # link_to_function(image_tag("delete"), "if (confirm('Really?')) do_delete()")
+ # Produces:
+ # <a onclick="if (confirm('Really?')) do_delete(); return false;" href="#">
+ # <img src="/images/delete.png?" alt="Delete"/>
+ # </a>
+ #
+ # link_to_function("Show me more", nil, :id => "more_link") do |page|
+ # page[:details].visual_effect :toggle_blind
+ # page[:more_link].replace_html "Show me less"
+ # end
+ # Produces:
+ # <a href="#" id="more_link" onclick="try {
+ # $(&quot;details&quot;).visualEffect(&quot;toggle_blind&quot;);
+ # $(&quot;more_link&quot;).update(&quot;Show me less&quot;);
+ # }
+ # catch (e) {
+ # alert('RJS error:\n\n' + e.toString());
+ # alert('$(\&quot;details\&quot;).visualEffect(\&quot;toggle_blind\&quot;);
+ # \n$(\&quot;more_link\&quot;).update(\&quot;Show me less\&quot;);');
+ # throw e
+ # };
+ # return false;">Show me more</a>
+ #
+ def link_to_function(name, *args, &block)
+ html_options = args.extract_options!.symbolize_keys
+
+ function = block_given? ? update_page(&block) : args[0] || ''
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
+ href = html_options[:href] || '#'
+
+ content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 46e41bc406..719b64b940 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -3,10 +3,24 @@ require 'active_support/core_ext/float/rounding'
module ActionView
module Helpers #:nodoc:
+
# Provides methods for converting numbers into formatted strings.
# Methods are provided for phone numbers, currency, percentage,
- # precision, positional notation, and file size.
+ # precision, positional notation, file size and pretty printing.
+ #
+ # Most methods expect a +number+ argument, and will return it
+ # unchanged if can't be converted into a valid number.
module NumberHelper
+
+ # Raised when argument +number+ param given to the helpers is invalid and
+ # the option :raise is set to +true+.
+ class InvalidNumberError < StandardError
+ attr_accessor :number
+ def initialize(number)
+ @number = number
+ end
+ end
+
# Formats a +number+ into a US phone number (e.g., (555) 123-9876). You can customize the format
# in the +options+ hash.
#
@@ -30,6 +44,17 @@ module ActionView
def number_to_phone(number, options = {})
return nil if number.nil?
+ begin
+ Float(number)
+ is_number_html_safe = true
+ rescue ArgumentError, TypeError
+ if options[:raise]
+ raise InvalidNumberError, number
+ else
+ is_number_html_safe = number.to_s.html_safe?
+ end
+ end
+
number = number.to_s.strip
options = options.symbolize_keys
area_code = options[:area_code] || nil
@@ -46,7 +71,7 @@ module ActionView
number.starts_with?('-') ? number.slice!(1..-1) : number
end
str << " x #{extension}" unless extension.blank?
- str
+ is_number_html_safe ? str.html_safe : str
end
# Formats a +number+ into a currency string (e.g., $13.65). You can customize the format
@@ -72,38 +97,42 @@ module ActionView
# number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
# # => 1234567890,50 &pound;
def number_to_currency(number, options = {})
+ return nil if number.nil?
+
options.symbolize_keys!
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
- currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :raise => true) rescue {}
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
+ currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
defaults = defaults.merge(currency)
- precision = options[:precision] || defaults[:precision]
- unit = options[:unit] || defaults[:unit]
- separator = options[:separator] || defaults[:separator]
- delimiter = options[:delimiter] || defaults[:delimiter]
- format = options[:format] || defaults[:format]
- separator = '' if precision == 0
+ options = options.reverse_merge(defaults)
- value = number_with_precision(number,
- :precision => precision,
- :delimiter => delimiter,
- :separator => separator)
+ unit = options.delete(:unit)
+ format = options.delete(:format)
- if value
+ begin
+ value = number_with_precision(number, options.merge(:raise => true))
format.gsub(/%n/, value).gsub(/%u/, unit).html_safe
- else
- number
+ rescue InvalidNumberError => e
+ if options[:raise]
+ raise
+ else
+ formatted_number = format.gsub(/%n/, e.number).gsub(/%u/, unit)
+ 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.
#
# ==== Options
- # * <tt>:precision</tt> - Sets the level of precision (defaults to 3).
- # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +false+)
+ # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
# * <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+)
#
# ==== Examples
# number_to_percentage(100) # => 100.000%
@@ -111,21 +140,25 @@ module ActionView
# number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000%
# number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
def number_to_percentage(number, options = {})
+ return nil if number.nil?
+
options.symbolize_keys!
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
- percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :raise => true) rescue {}
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
+ percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {})
defaults = defaults.merge(percentage)
- precision = options[:precision] || defaults[:precision]
- separator = options[:separator] || defaults[:separator]
- delimiter = options[:delimiter] || defaults[:delimiter]
+ options = options.reverse_merge(defaults)
- value = number_with_precision(number,
- :precision => precision,
- :separator => separator,
- :delimiter => delimiter)
- value ? value + "%" : number
+ begin
+ "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe
+ rescue InvalidNumberError => e
+ if options[:raise]
+ raise
+ else
+ e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%"
+ end
+ end
end
# Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You can
@@ -133,7 +166,7 @@ module ActionView
#
# ==== Options
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
- # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
#
# ==== Examples
# number_with_delimiter(12345678) # => 12,345,678
@@ -146,148 +179,186 @@ module ActionView
# You can still use <tt>number_with_delimiter</tt> with the old API that accepts the
# +delimiter+ as its optional second and the +separator+ as its
# optional third parameter:
- # number_with_delimiter(12345678, " ") # => 12 345.678
+ # number_with_delimiter(12345678, " ") # => 12 345 678
# number_with_delimiter(12345678.05, ".", ",") # => 12.345.678,05
def number_with_delimiter(number, *args)
options = args.extract_options!
options.symbolize_keys!
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
+ begin
+ Float(number)
+ rescue ArgumentError, TypeError
+ if options[:raise]
+ raise InvalidNumberError, number
+ else
+ return number
+ end
+ end
+
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
unless args.empty?
ActiveSupport::Deprecation.warn('number_with_delimiter takes an option hash ' +
'instead of separate delimiter and precision arguments.', caller)
- delimiter = args[0] || defaults[:delimiter]
- separator = args[1] || defaults[:separator]
+ options[:delimiter] ||= args[0] if args[0]
+ options[:separator] ||= args[1] if args[1]
end
- delimiter ||= (options[:delimiter] || defaults[:delimiter])
- separator ||= (options[:separator] || defaults[:separator])
+ options = options.reverse_merge(defaults)
parts = number.to_s.split('.')
- if parts[0]
- parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
- parts.join(separator)
- else
- number
- end
+ 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 of 2).
+ # Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision
+ # of 2 if +:significant+ is +false+, and 5 if +:significant+ is +true+).
# You can customize the format in the +options+ hash.
#
# ==== Options
- # * <tt>:precision</tt> - Sets the level of precision (defaults to 3).
- # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +false+)
+ # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
# * <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+)
#
# ==== Examples
- # number_with_precision(111.2345) # => 111.235
- # number_with_precision(111.2345, :precision => 2) # => 111.23
- # number_with_precision(13, :precision => 5) # => 13.00000
- # number_with_precision(389.32314, :precision => 0) # => 389
+ # number_with_precision(111.2345) # => 111.235
+ # number_with_precision(111.2345, :precision => 2) # => 111.23
+ # number_with_precision(13, :precision => 5) # => 13.00000
+ # number_with_precision(389.32314, :precision => 0) # => 389
+ # number_with_precision(111.2345, :significant => true) # => 111
+ # number_with_precision(111.2345, :precision => 1, :significant => true) # => 100
+ # number_with_precision(13, :precision => 5, :significant => true) # => 13.000
+ # number_with_precision(13, :precision => 5, :significant => true, strip_insignificant_zeros => true)
+ # # => 13
+ # number_with_precision(389.32314, :precision => 4, :significant => true) # => 389.3
# number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
# # => 1.111,23
#
# You can still use <tt>number_with_precision</tt> with the old API that accepts the
# +precision+ as its optional second parameter:
- # number_with_precision(number_with_precision(111.2345, 2) # => 111.23
+ # number_with_precision(111.2345, 2) # => 111.23
def number_with_precision(number, *args)
+
options = args.extract_options!
options.symbolize_keys!
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
- precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale],
- :raise => true) rescue {}
+ number = begin
+ Float(number)
+ rescue ArgumentError, TypeError
+ if options[:raise]
+ raise InvalidNumberError, number
+ else
+ return number
+ end
+ end
+
+ 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)
+ #Backwards compatibility
unless args.empty?
ActiveSupport::Deprecation.warn('number_with_precision takes an option hash ' +
'instead of a separate precision argument.', caller)
- precision = args[0] || defaults[:precision]
+ options[:precision] ||= args[0] if args[0]
end
- precision ||= (options[:precision] || defaults[:precision])
- separator ||= (options[:separator] || defaults[:separator])
- delimiter ||= (options[:delimiter] || defaults[:delimiter])
+ 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
- begin
- value = Float(number)
- rescue ArgumentError, TypeError
- value = nil
+ if significant and precision > 0
+ digits = (Math.log10(number) + 1).floor
+ rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision)
+ precision = precision - digits
+ precision = precision > 0 ? precision : 0 #don't let it be negative
+ else
+ rounded_number = BigDecimal.new((number * (10 ** precision)).to_s).round.to_f / 10 ** precision
end
-
- if value
- rounded_number = BigDecimal.new((Float(number) * (10 ** precision)).to_s).round.to_f / 10 ** precision
- number_with_delimiter("%01.#{precision}f" % rounded_number,
- :separator => separator,
- :delimiter => delimiter)
+ formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
+ if strip_insignificant_zeros
+ escaped_separator = Regexp.escape(options[:separator])
+ formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '').html_safe
else
- number
+ formatted_number
end
+
end
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
- # Formats the bytes in +size+ into a more understandable representation
+ # Formats the bytes in +number+ into a more understandable representation
# (e.g., giving it 1500 yields 1.5 KB). This method is useful for
- # reporting file sizes to users. This method returns nil if
- # +size+ cannot be converted into a number. You can customize the
+ # reporting file sizes to users. You can customize the
# format in the +options+ hash.
#
+ # See <tt>number_to_human</tt> if you want to pretty-print a generic number.
+ #
# ==== Options
- # * <tt>:precision</tt> - Sets the level of precision (defaults to 1).
- # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +true+)
+ # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
# * <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+)
# ==== Examples
# number_to_human_size(123) # => 123 Bytes
- # number_to_human_size(1234) # => 1.2 KB
+ # number_to_human_size(1234) # => 1.21 KB
# number_to_human_size(12345) # => 12.1 KB
- # number_to_human_size(1234567) # => 1.2 MB
- # number_to_human_size(1234567890) # => 1.1 GB
- # number_to_human_size(1234567890123) # => 1.1 TB
- # number_to_human_size(1234567, :precision => 2) # => 1.18 MB
- # number_to_human_size(483989, :precision => 0) # => 473 KB
- # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
+ # number_to_human_size(1234567) # => 1.18 MB
+ # number_to_human_size(1234567890) # => 1.15 GB
+ # number_to_human_size(1234567890123) # => 1.12 TB
+ # number_to_human_size(1234567, :precision => 2) # => 1.2 MB
+ # number_to_human_size(483989, :precision => 2) # => 470 KB
+ # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,2 MB
#
- # Zeros after the decimal point are always stripped out, regardless of the
- # specified precision:
- # helper.number_to_human_size(1234567890123, :precision => 5) # => "1.12283 TB"
- # helper.number_to_human_size(524288000, :precision=>5) # => "500 MB"
+ # Unsignificant zeros after the fractional separator are stripped out by default (set
+ # <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
+ # number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB"
+ # number_to_human_size(524288000, :precision=>5) # => "500 MB"
#
# You can still use <tt>number_to_human_size</tt> with the old API that accepts the
# +precision+ as its optional second parameter:
- # number_to_human_size(1234567, 2) # => 1.18 MB
- # number_to_human_size(483989, 0) # => 473 KB
+ # number_to_human_size(1234567, 1) # => 1 MB
+ # number_to_human_size(483989, 2) # => 470 KB
def number_to_human_size(number, *args)
- return nil if number.nil?
-
options = args.extract_options!
options.symbolize_keys!
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :raise => true) rescue {}
+ number = begin
+ Float(number)
+ rescue ArgumentError, TypeError
+ if options[:raise]
+ raise InvalidNumberError, number
+ else
+ return number
+ end
+ end
+
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
+ human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
defaults = defaults.merge(human)
unless args.empty?
ActiveSupport::Deprecation.warn('number_to_human_size takes an option hash ' +
'instead of a separate precision argument.', caller)
- precision = args[0] || defaults[:precision]
+ options[:precision] ||= args[0] if args[0]
end
- precision ||= (options[:precision] || defaults[:precision])
- separator ||= (options[:separator] || defaults[:separator])
- delimiter ||= (options[:delimiter] || defaults[:delimiter])
+ 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)
storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
if number.to_i < 1024
unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
- storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
+ storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit).html_safe
else
max_exp = STORAGE_UNITS.size - 1
- number = Float(number)
exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
number /= 1024 ** exponent
@@ -295,15 +366,138 @@ module ActionView
unit_key = STORAGE_UNITS[exponent]
unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
- escaped_separator = Regexp.escape(separator)
- formatted_number = number_with_precision(number,
- :precision => precision,
- :separator => separator,
- :delimiter => delimiter
- ).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
- storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
+ formatted_number = number_with_precision(number, options)
+ storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).html_safe
+ end
+ end
+
+ DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
+ -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}.freeze
+
+ # Pretty prints (formats and approximates) a number in a way it is more readable by humans
+ # (eg.: 1200000000 becomes "1.2 Billion"). This is useful for numbers that
+ # can get very large (and too hard to read).
+ #
+ # See <tt>number_to_human_size</tt> if you want to print a file size.
+ #
+ # You can also define you own unit-quantifier names if you want to use other decimal units
+ # (eg.: 1500 becomes "1.5 kilometers", 0.150 becomes "150 mililiters", etc). You may define
+ # a wide range of unit quantifiers, even fractional ones (centi, deci, mili, etc).
+ #
+ # ==== Options
+ # * <tt>:precision</tt> - Sets the precision of the number (defaults to 3).
+ # * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +true+)
+ # * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
+ # * <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>:units</tt> - A Hash of unit quantifier names. Or a string containing an i18n scope where to find this hash. It might have the following keys:
+ # * *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:
+ #
+ # %u The quantifier (ex.: 'thousand')
+ # %n The number
+ #
+ # ==== Examples
+ # number_to_human(123) # => "123"
+ # number_to_human(1234) # => "1.23 Thousand"
+ # number_to_human(12345) # => "12.3 Thousand"
+ # number_to_human(1234567) # => "1.23 Million"
+ # number_to_human(1234567890) # => "1.23 Billion"
+ # number_to_human(1234567890123) # => "1.23 Trillion"
+ # number_to_human(1234567890123456) # => "1.23 Quadrillion"
+ # number_to_human(1234567890123456789) # => "1230 Quadrillion"
+ # number_to_human(489939, :precision => 2) # => "490 Thousand"
+ # number_to_human(489939, :precision => 4) # => "489.9 Thousand"
+ # number_to_human(1234567, :precision => 4,
+ # :significant => false) # => "1.2346 Million"
+ # number_to_human(1234567, :precision => 1,
+ # :separator => ',',
+ # :significant => false) # => "1,2 Million"
+ #
+ # Unsignificant zeros after the decimal separator are stripped out by default (set
+ # <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
+ # number_to_human(12345012345, :significant_digits => 6) # => "12.345 Billion"
+ # number_to_human(500000000, :precision=>5) # => "500 Million"
+ #
+ # ==== Custom Unit Quantifiers
+ #
+ # You can also use your own custom unit quantifiers:
+ # number_to_human(500000, :units => {:unit => "ml", :thousand => "lt"}) # => "500 lt"
+ #
+ # If in your I18n locale you have:
+ # distance:
+ # centi:
+ # one: "centimeter"
+ # other: "centimeters"
+ # unit:
+ # one: "meter"
+ # other: "meters"
+ # thousand:
+ # one: "kilometer"
+ # other: "kilometers"
+ # billion: "gazilion-distance"
+ #
+ # Then you could do:
+ #
+ # number_to_human(543934, :units => :distance) # => "544 kilometers"
+ # number_to_human(54393498, :units => :distance) # => "54400 kilometers"
+ # number_to_human(54393498000, :units => :distance) # => "54.4 gazilion-distance"
+ # number_to_human(343, :units => :distance, :precision => 1) # => "300 meters"
+ # number_to_human(1, :units => :distance) # => "1 meter"
+ # number_to_human(0.34, :units => :distance) # => "34 centimeters"
+ #
+ def number_to_human(number, options = {})
+ options.symbolize_keys!
+
+ number = begin
+ Float(number)
+ rescue ArgumentError, TypeError
+ if options[:raise]
+ raise InvalidNumberError, number
+ else
+ return number
+ end
end
+
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
+ human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
+ defaults = defaults.merge(human)
+
+ 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)
+
+ units = options.delete :units
+ unit_exponents = case units
+ when Hash
+ units
+ when String, Symbol
+ I18n.translate(:"#{units}", :locale => options[:locale], :raise => true)
+ when nil
+ I18n.translate(:"number.human.decimal_units.units", :locale => options[:locale], :raise => true)
+ else
+ raise ArgumentError, ":units must be a Hash or String translation scope."
+ end.keys.map{|e_name| DECIMAL_UNITS.invert[e_name] }.sort_by{|e| -e}
+
+ number_exponent = Math.log10(number).floor
+ display_exponent = unit_exponents.find{|e| number_exponent >= e }
+ number /= 10 ** display_exponent
+
+ unit = case units
+ when Hash
+ units[DECIMAL_UNITS[display_exponent]]
+ when String, Symbol
+ I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
+ else
+ I18n.translate(:"number.human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
+ end
+
+ decimal_format = options[:format] || I18n.translate(:'number.human.decimal_units.format', :locale => options[:locale], :default => "%n %u")
+ formatted_number = number_with_precision(number, options)
+ decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe
end
+
end
end
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index dc3c6d88f5..ccdc8181db 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -102,39 +102,6 @@ module ActionView
:form, :with, :update, :script, :type ]).merge(CALLBACKS)
end
- # Returns a button with the given +name+ text that'll trigger a JavaScript +function+ using the
- # onclick handler.
- #
- # The first argument +name+ is used as the button's value or display text.
- #
- # The next arguments are optional and may include the javascript function definition and a hash of html_options.
- #
- # The +function+ argument can be omitted in favor of an +update_page+
- # block, which evaluates to a string when the template is rendered
- # (instead of making an Ajax request first).
- #
- # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button"
- #
- # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil
- #
- # Examples:
- # button_to_function "Greeting", "alert('Hello world!')"
- # button_to_function "Delete", "if (confirm('Really?')) do_delete()"
- # button_to_function "Details" do |page|
- # page[:details].visual_effect :toggle_slide
- # end
- # button_to_function "Details", :class => "details_button" do |page|
- # page[:details].visual_effect :toggle_slide
- # end
- def button_to_function(name, *args, &block)
- html_options = args.extract_options!.symbolize_keys
-
- function = block_given? ? update_page(&block) : args[0] || ''
- onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
-
- tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
- end
-
# Returns the JavaScript needed for a remote function.
# Takes the same arguments as link_to_remote.
#
@@ -181,11 +148,9 @@ module ActionView
class JavaScriptGenerator #:nodoc:
def initialize(context, &block) #:nodoc:
@context, @lines = context, []
- @context.update_details(:formats => [:js, :html]) do
- include_helpers_from_context
- @context.with_output_buffer(@lines) do
- @context.instance_exec(self, &block)
- end
+ include_helpers_from_context
+ @context.with_output_buffer(@lines) do
+ @context.instance_exec(self, &block)
end
end
@@ -615,7 +580,7 @@ module ActionView
# page.hide 'spinner'
# end
def update_page(&block)
- JavaScriptGenerator.new(@template, &block).to_s.html_safe
+ JavaScriptGenerator.new(view_context, &block).to_s.html_safe
end
# Works like update_page but wraps the generated JavaScript in a <script>
@@ -689,6 +654,10 @@ module ActionView
@generator << root if root
end
+ def is_a?(klass)
+ klass == JavaScriptProxy
+ end
+
private
def method_missing(method, *arguments, &block)
if method.to_s =~ /(.*)=$/
@@ -882,5 +851,3 @@ module ActionView
end
end
end
-
-require 'action_view/helpers/javascript_helper'
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index e1ce65f90a..27be1690dd 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -29,7 +29,7 @@ module ActionView
end
def safe_concat(string)
- output_buffer.safe_concat(string)
+ output_buffer.respond_to?(:safe_concat) ? output_buffer.safe_concat(string) : concat(string)
end
# Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
@@ -576,7 +576,7 @@ module ActionView
# each email is yielded and the result is used as the link text.
def auto_link_email_addresses(text, html_options = {})
body = text.dup
- text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
+ text.gsub(/([\w\.!#\$%\-+]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
text = $1
if body.match(/<a\b[^>]*>(.*)(#{Regexp.escape(text)})(.*)<\/a>/)
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index 8a89ee58a0..457944dbb6 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -13,7 +13,7 @@ module ActionView
def translate(key, options = {})
options[:raise] = true
translation = I18n.translate(scope_key_by_partial(key), options)
- translation.is_a?(Array) ? translation.map { |entry| entry.html_safe } : translation.html_safe
+ (translation.respond_to?(:join) ? translation.join : translation).html_safe
rescue I18n::MissingTranslationData => e
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
content_tag('span', keys.join(', '), :class => 'translation_missing')
@@ -29,9 +29,10 @@ module ActionView
private
def scope_key_by_partial(key)
- if (key.respond_to?(:join) ? key.join : key.to_s).first == "."
+ strkey = key.respond_to?(:join) ? key.join : key.to_s
+ if strkey.first == "."
if @_virtual_path
- @_virtual_path.gsub(%r{/_?}, ".") + key.to_s
+ @_virtual_path.gsub(%r{/_?}, ".") + strkey
else
raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 131e950b18..b23d5fcb68 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -1,6 +1,7 @@
require 'action_view/helpers/javascript_helper'
require 'active_support/core_ext/array/access'
require 'active_support/core_ext/hash/keys'
+require 'action_dispatch'
module ActionView
module Helpers #:nodoc:
@@ -9,6 +10,9 @@ module ActionView
# This allows you to use the same format for links in views
# and controllers.
module UrlHelper
+ extend ActiveSupport::Concern
+
+ include ActionDispatch::Routing::UrlFor
include JavaScriptHelper
# Need to map default url options to controller one.
@@ -16,6 +20,10 @@ module ActionView
controller.send(:default_url_options, *args)
end
+ def url_options
+ controller.url_options
+ end
+
# Returns the URL for the set of +options+ provided. This takes the
# same options as +url_for+ in Action Controller (see the
# documentation for <tt>ActionController::Base#url_for</tt>). Note that by default
@@ -206,7 +214,7 @@ module ActionView
if block_given?
options = args.first || {}
html_options = args.second
- safe_concat(link_to(capture(&block), options, html_options))
+ link_to(capture(&block), options, html_options)
else
name = args[0]
options = args[1] || {}
@@ -578,8 +586,6 @@ module ActionView
add_confirm_to_attributes!(html_options, confirm) if confirm
add_method_to_attributes!(html_options, method) if method
- html_options["data-url"] = options[:url] if options.is_a?(Hash) && options[:url]
-
html_options
end