2005-08-14 04:43:07 -04:00
require File . dirname ( __FILE__ ) + '/javascript_helper'
2004-11-23 20:04:44 -05:00
module ActionView
module Helpers
# Provides a set of methods for making easy links and getting urls that depend on the controller and action. This means that
# you can use the same format for links in the views that you do in the controller. The different methods are even named
# synchronously, so link_to uses that same url as is generated by url_for, which again is the same url used for
# redirection in redirect_to.
module UrlHelper
2005-08-14 04:43:07 -04:00
include JavaScriptHelper
2005-03-06 12:35:52 -05:00
# Returns the URL for the set of +options+ provided. This takes the same options
# as url_for. For a list, see the url_for documentation in link:classes/ActionController/Base.html#M000079.
2005-09-11 05:12:22 -04:00
# Note that it'll set :only_path => true so you'll get /controller/action instead of the
# http://example.com/controller/action part (makes it harder to parse httpd log files)
2004-11-23 20:04:44 -05:00
def url_for ( options = { } , * parameters_for_method_reference )
2005-03-14 18:24:47 -05:00
options = { :only_path = > true } . update ( options . symbolize_keys ) if options . kind_of? Hash
2004-11-23 20:04:44 -05:00
@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
2005-09-11 05:12:22 -04:00
# link:classes/ActionView/Helpers/UrlHelper.html#M000304. It's also possible to pass a string instead of an options hash to
2005-03-06 06:50:41 -05:00
# get a link tag that just points without consideration. If nil is passed as a name, the link itself will become the name.
2005-09-03 20:33:45 -04:00
#
2005-09-07 08:56:33 -04:00
# The html_options has three special features. One for creating javascript confirm alerts where if you pass :confirm => 'Are you sure?',
2005-01-04 19:38:09 -05:00
# the link will be guarded with a JS popup asking that question. If the user accepts, the link is processed, otherwise not.
2005-02-19 06:33:32 -05:00
#
2005-09-07 08:56:33 -04:00
# Another for creating a popup window, which is done by either passing :popup with true or the options of the window in
2005-09-03 20:33:45 -04:00
# Javascript form.
#
2005-09-07 08:56:33 -04:00
# And a third for making the link do a POST request (instead of the regular GET) through a dynamically added form element that
# is instantly submitted. Note that if the user has turned off Javascript, the request will fall back on the GET. So its
# your responsibility to determine what the action should be once it arrives at the controller. The POST form is turned on by
# passing :post as true. Note, it's not possible to use POST requests and popup targets at the same time (an exception will be thrown).
#
2005-09-03 20:33:45 -04:00
# Examples:
2005-02-19 06:33:32 -05:00
# link_to "Delete this page", { :action => "destroy", :id => @page.id }, :confirm => "Are you sure?"
2005-09-03 20:33:45 -04:00
# link_to "Help", { :action => "help" }, :popup => true
# link_to "Busy loop", { :action => "busy" }, :popup => ['new_window', 'height=300,width=600']
2005-09-07 08:56:33 -04:00
# link_to "Destroy account", { :action => "destroy" }, :confirm => "Are you sure?", :post => true
2005-03-06 06:50:41 -05:00
def link_to ( name , options = { } , html_options = nil , * parameters_for_method_reference )
2005-09-20 03:54:55 -04:00
if html_options
html_options = html_options . stringify_keys
convert_options_to_javascript! ( html_options )
tag_options = tag_options ( html_options )
2004-11-23 20:04:44 -05:00
else
2005-09-20 03:54:55 -04:00
tag_options = nil
2004-11-23 20:04:44 -05:00
end
2005-10-13 18:44:45 -04:00
url = html_escape ( options . is_a? ( String ) ? options : url_for ( options , * parameters_for_method_reference ) )
2005-09-20 03:54:55 -04:00
" <a href= \" #{ url } \" #{ tag_options } > #{ name || url } </a> "
2004-11-23 20:04:44 -05:00
end
2005-06-16 02:17:51 -04:00
# Generates a form containing a sole button that submits to the
# URL given by _options_. Use this method instead of +link_to+
# for actions that do not have the safe HTTP GET semantics
# implied by using a hypertext link.
#
# The parameters are the same as for +link_to+. Any _html_options_
# that you pass will be applied to the inner +input+ element.
# In particular, pass
#
# :disabled => true/false
#
# as part of _html_options_ to control whether the button is
# disabled. The generated form element is given the class
# 'button-to', to which you can attach CSS styles for display
# purposes.
#
# Example 1:
#
# # inside of controller for "feeds"
# button_to "Edit", :action => 'edit', :id => 3
#
# Generates the following HTML (sans formatting):
#
# <form method="post" action="/feeds/edit/3" class="button-to">
# <div><input value="Edit" type="submit" /></div>
# </form>
#
# Example 2:
#
# button_to "Destroy", { :action => 'destroy', :id => 3 },
# :confirm => "Are you sure?"
#
# Generates the following HTML (sans formatting):
#
# <form method="post" action="/feeds/destroy/3" class="button-to">
# <div><input onclick="return confirm('Are you sure?');"
# value="Destroy" type="submit" />
# </div>
# </form>
#
# *NOTE*: This method generates HTML code that represents a form.
# Forms are "block" content, which means that you should not try to
# insert them into your HTML where only inline content is expected.
# For example, you can legally insert a form inside of a +div+ or
# +td+ element or in between +p+ elements, but not in the middle of
# a run of text, nor can you place a form within another form.
# (Bottom line: Always validate your HTML before going public.)
def button_to ( name , options = { } , html_options = nil )
html_options = ( html_options || { } ) . stringify_keys
convert_boolean_attributes! ( html_options , %w( disabled ) )
2005-09-07 08:56:33 -04:00
if confirm = html_options . delete ( " confirm " )
html_options [ " onclick " ] = " return #{ confirm_javascript_function ( confirm ) } ; "
end
url , name = options . is_a? ( String ) ?
2005-06-16 02:17:51 -04:00
[ options , name || options ] :
2005-10-13 18:44:45 -04:00
[ url_for ( options ) , name || html_escape ( url_for ( options ) ) ]
2005-09-07 08:56:33 -04:00
2005-06-16 02:17:51 -04:00
html_options . merge! ( " type " = > " submit " , " value " = > name )
2005-09-07 08:56:33 -04:00
2005-06-16 02:17:51 -04:00
" <form method= \" post \" action= \" #{ h url } \" class= \" button-to \" ><div> " +
tag ( " input " , html_options ) + " </div></form> "
end
2005-03-22 08:09:44 -05:00
# This tag is deprecated. Combine the link_to and AssetTagHelper::image_tag yourself instead, like:
2005-03-09 08:53:47 -05:00
# link_to(image_tag("rss", :size => "30x45", :border => 0), "http://www.example.com")
2005-02-19 06:33:32 -05:00
def link_image_to ( src , options = { } , html_options = { } , * parameters_for_method_reference )
2004-12-09 18:18:25 -05:00
image_options = { " src " = > src . include? ( " / " ) ? src : " /images/ #{ src } " }
2005-03-06 06:50:41 -05:00
image_options [ " src " ] += " .png " unless image_options [ " src " ] . include? ( " . " )
html_options = html_options . stringify_keys
2004-12-09 18:18:25 -05:00
if html_options [ " alt " ]
image_options [ " alt " ] = html_options [ " alt " ]
html_options . delete " alt "
else
image_options [ " alt " ] = src . split ( " / " ) . last . split ( " . " ) . first . capitalize
end
if html_options [ " size " ]
image_options [ " width " ] , image_options [ " height " ] = html_options [ " size " ] . split ( " x " )
html_options . delete " size "
end
2004-12-09 19:02:14 -05:00
if html_options [ " border " ]
image_options [ " border " ] = html_options [ " border " ]
html_options . delete " border "
end
2005-03-06 06:50:41 -05:00
2004-12-09 18:18:25 -05:00
if html_options [ " align " ]
image_options [ " align " ] = html_options [ " align " ]
html_options . delete " align "
end
link_to ( tag ( " img " , image_options ) , options , html_options , * parameters_for_method_reference )
end
2005-02-19 06:33:32 -05:00
alias_method :link_to_image , :link_image_to # deprecated name
2005-03-06 06:50:41 -05:00
# Creates a link tag of the given +name+ using an URL created by the set of +options+, unless the current
2005-02-17 07:25:52 -05:00
# request uri is the same as the link's, in which case only the name is returned (or the
2005-03-06 06:50:41 -05:00
# given block is yielded, if one exists). This is useful for creating link bars where you don't want to link
2004-11-23 20:04:44 -05:00
# to the page currently being viewed.
2005-03-06 09:06:33 -05:00
def link_to_unless_current ( name , options = { } , html_options = { } , * parameters_for_method_reference , & block )
link_to_unless current_page? ( options ) , name , options , html_options , * parameters_for_method_reference , & block
end
# Create a link tag of the given +name+ using an URL created by the set of +options+, unless +condition+
# is true, in which case only the name is returned (or the given block is yielded, if one exists).
def link_to_unless ( condition , name , options = { } , html_options = { } , * parameters_for_method_reference , & block )
if condition
if block_given?
block . arity < = 1 ? yield ( name ) : yield ( name , options , html_options , * parameters_for_method_reference )
else
2005-07-09 13:08:23 -04:00
name
2005-03-06 09:06:33 -05:00
end
2004-11-23 20:04:44 -05:00
else
2005-02-17 07:25:52 -05:00
link_to ( name , options , html_options , * parameters_for_method_reference )
2005-03-06 09:06:33 -05:00
end
end
# Create a link tag of the given +name+ using an URL created by the set of +options+, if +condition+
# is true, in which case only the name is returned (or the given block is yielded, if one exists).
def link_to_if ( condition , name , options = { } , html_options = { } , * parameters_for_method_reference , & block )
link_to_unless ! condition , name , options , html_options , * parameters_for_method_reference , & block
2004-11-23 20:04:44 -05:00
end
# Creates a link tag for starting an email to the specified <tt>email_address</tt>, which is also used as the name of the
# link unless +name+ is specified. Additional HTML options, such as class or id, can be passed in the <tt>html_options</tt> hash.
2005-01-24 08:48:24 -05:00
#
# You can also make it difficult for spiders to harvest email address by obfuscating them.
2005-04-02 03:16:57 -05:00
# Examples:
2005-02-23 07:31:05 -05:00
# mail_to "me@domain.com", "My email", :encode => "javascript" # =>
# <script type="text/javascript" language="javascript">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>
#
# 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>
2005-04-02 03:16:57 -05:00
#
# You can also specify the cc address, bcc address, subject, and body parts of the message header to create a complex e-mail using the
# corresponding +cc+, +bcc+, +subject+, and +body+ <tt>html_options</tt> keys. Each of these options are URI escaped and then appended to
# the <tt>email_address</tt> before being output. <b>Be aware that javascript keywords will not be escaped and may break this feature
# when encoding with javascript.</b>
# Examples:
# mail_to "me@domain.com", "My email", :cc => "ccaddress@domain.com", :bcc => "bccaddress@domain.com", :subject => "This is an example email", :body => "This is the body of the message." # =>
# <a href="mailto:me@domain.com?cc="ccaddress@domain.com"&bcc="bccaddress@domain.com"&body="This%20is%20the%20body%20of%20the%20message."&subject="This%20is%20an%20example%20email">My email</a>
2004-11-23 20:04:44 -05:00
def mail_to ( email_address , name = nil , html_options = { } )
2005-03-06 06:50:41 -05:00
html_options = html_options . stringify_keys
encode = html_options . delete ( " encode " )
2005-04-02 03:16:57 -05:00
cc , bcc , subject , body = html_options . delete ( " cc " ) , html_options . delete ( " bcc " ) , html_options . delete ( " subject " ) , html_options . delete ( " body " )
2005-01-24 08:48:24 -05:00
string = ''
2005-04-02 03:16:57 -05:00
extras = ''
extras << " cc= #{ CGI . escape ( cc ) . gsub ( " + " , " %20 " ) } & " unless cc . nil?
extras << " bcc= #{ CGI . escape ( bcc ) . gsub ( " + " , " %20 " ) } & " unless bcc . nil?
extras << " body= #{ CGI . escape ( body ) . gsub ( " + " , " %20 " ) } & " unless body . nil?
extras << " subject= #{ CGI . escape ( subject ) . gsub ( " + " , " %20 " ) } & " unless subject . nil?
extras = " ? " << extras . gsub! ( / &?$ / , " " ) unless extras . empty?
2005-07-02 02:46:41 -04:00
email_address_obfuscated = email_address . dup
email_address_obfuscated . gsub! ( / @ / , html_options . delete ( " replace_at " ) ) if html_options . has_key? ( " replace_at " )
email_address_obfuscated . gsub! ( / \ . / , html_options . delete ( " replace_dot " ) ) if html_options . has_key? ( " replace_dot " )
2005-01-24 08:48:24 -05:00
if encode == 'javascript'
2005-04-02 03:16:57 -05:00
tmp = " document.write(' #{ content_tag ( " a " , name || email_address , html_options . merge ( { " href " = > " mailto: " + email_address . to_s + extras } ) ) } '); "
2005-01-24 08:48:24 -05:00
for i in 0 ... tmp . length
string << sprintf ( " %%%x " , tmp [ i ] )
end
" <script type= \" text/javascript \" language= \" javascript \" >eval(unescape(' #{ string } '))</script> "
elsif encode == 'hex'
for i in 0 ... email_address . length
if email_address [ i , 1 ] =~ / \ w /
string << sprintf ( " %%%x " , email_address [ i ] )
else
string << email_address [ i , 1 ]
end
end
2005-07-02 02:46:41 -04:00
content_tag " a " , name || email_address_obfuscated , html_options . merge ( { " href " = > " mailto: #{ string } #{ extras } " } )
2005-01-24 08:48:24 -05:00
else
2005-07-02 02:46:41 -04:00
content_tag " a " , name || email_address_obfuscated , html_options . merge ( { " href " = > " mailto: #{ email_address } #{ extras } " } )
2005-01-24 08:48:24 -05:00
end
2004-11-23 20:04:44 -05:00
end
2005-02-17 10:34:32 -05:00
# Returns true if the current page uri is generated by the options passed (in url_for format).
def current_page? ( options )
2005-09-20 03:54:55 -04:00
url_for ( options ) == @controller . request . request_uri
2005-02-17 10:34:32 -05:00
end
2004-11-23 20:04:44 -05:00
private
2005-09-07 08:56:33 -04:00
def convert_options_to_javascript! ( html_options )
confirm , popup , post = html_options . delete ( " confirm " ) , html_options . delete ( " popup " ) , html_options . delete ( " post " )
html_options [ " onclick " ] = case
when popup && post
raise ActionView :: ActionViewError , " You can't use :popup and :post in the same link "
when confirm && popup
" if ( #{ confirm_javascript_function ( confirm ) } ) { #{ popup_javascript_function ( popup ) } };return false; "
when confirm && post
" if ( #{ confirm_javascript_function ( confirm ) } ) { #{ post_javascript_function } };return false; "
when confirm
" return #{ confirm_javascript_function ( confirm ) } ; "
when post
" #{ post_javascript_function } return false; "
when popup
popup_javascript_function ( popup ) + 'return false;'
2005-09-08 13:54:16 -04:00
else
html_options [ " onclick " ]
2004-11-23 20:04:44 -05:00
end
end
2005-09-03 20:33:45 -04:00
2005-09-07 08:56:33 -04:00
def confirm_javascript_function ( confirm )
" confirm(' #{ escape_javascript ( confirm ) } ') "
2005-09-03 20:33:45 -04:00
end
2005-09-07 08:56:33 -04:00
def popup_javascript_function ( popup )
popup . is_a? ( Array ) ? " window.open(this.href,' #{ popup . first } ',' #{ popup . last } '); " : " window.open(this.href); "
2005-09-03 20:33:45 -04:00
end
2005-09-07 08:56:33 -04:00
def post_javascript_function
2005-09-07 09:04:09 -04:00
" f = document.createElement('form'); document.body.appendChild(f); f.method = 'POST'; f.action = this.href; f.submit(); "
2005-09-07 08:56:33 -04:00
end
2005-06-16 02:17:51 -04:00
# Processes the _html_options_ hash, converting the boolean
# attributes from true/false form into the form required by
# HTML/XHTML. (An attribute is considered to be boolean if
# its name is listed in the given _bool_attrs_ array.)
#
# More specifically, for each boolean attribute in _html_options_
# given as:
#
# "attr" => bool_value
#
# if the the associated _bool_value_ evaluates to true, it is
# replaced with the attribute's name; otherwise the attribute is
# removed from the _html_options_ hash. (See the XHTML 1.0 spec,
# section 4.5 "Attribute Minimization" for more:
# http://www.w3.org/TR/xhtml1/#h-4.5)
#
# Returns the updated _html_options_ hash, which is also modified
# in place.
#
# Example:
#
# convert_boolean_attributes!( html_options,
# %w( checked disabled readonly ) )
def convert_boolean_attributes! ( html_options , bool_attrs )
bool_attrs . each { | x | html_options [ x ] = x if html_options . delete ( x ) }
html_options
end
2004-11-23 20:04:44 -05:00
end
end
2005-06-16 02:17:51 -04:00
end