aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/helpers/url_helper.rb
blob: 951760b3ba510dd0194e25fce76c62532c66e858 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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
      # Returns the URL for the set of +options+ provided. See the valid options in link:classes/ActionController/Base.html#M000021
      def url_for(options = {}, *parameters_for_method_reference)
        if Hash === options then options = { :only_path => true }.merge(options) end
        @controller.send(:url_for, options, *parameters_for_method_reference)
      end

      # Creates a link tag of the given +name+ using an URL created by the set of +options+. See the valid options in
      # link:classes/ActionController/Base.html#M000021. It's also possible to pass a string instead of an options hash to
      # get a link tag that just points without consideration. If nil is passed as a name, the link itself will become the name. 
      # The html_options have a special feature for creating javascript confirm alerts where if you pass :confirm => 'Are you sure?', 
      # the link will be guarded with a JS popup asking that question. If the user accepts, the link is processed, otherwise not.
      #
      # Example:
      #   link_to "Delete this page", { :action => "destroy", :id => @page.id }, :confirm => "Are you sure?"
      def link_to(name, options = {}, html_options = {}, *parameters_for_method_reference)
        convert_confirm_option_to_javascript!(html_options) unless html_options.nil?
        if options.is_a?(String)
          content_tag "a", name || options, (html_options || {}).merge({ "href" => options })
        else
          content_tag(
            "a", name || url_for(options, *parameters_for_method_reference), 
            (html_options || {}).merge({ "href" => url_for(options, *parameters_for_method_reference) })
          )
        end
      end

      # Creates a link tag on the image residing at the +src+ using an URL created by the set of +options+. See the valid options in
      # link:classes/ActionController/Base.html#M000021. It's also possible to pass a string instead of an options hash to
      # get a link tag that just points without consideration. The <tt>html_options</tt> works jointly for the image and ahref tag by
      # letting the following special values enter the options on the image and the rest goes to the ahref:
      #
      # * <tt>:alt</tt> - If no alt text is given, the file name part of the +src+ is used (capitalized and without the extension)
      # * <tt>:size</tt> - Supplied as "XxY", so "30x45" becomes width="30" and height="45"
      # * <tt>:border</tt> - Is set to 0 by default
      # * <tt>:align</tt> - Sets the alignment, no special features
      #
      # The +src+ can be supplied as a... 
      # * full path, like "/my_images/image.gif"
      # * file name, like "rss.gif", that gets expanded to "/images/rss.gif"
      # * file name without extension, like "logo", that gets expanded to "/images/logo.png"
      #
      # Examples:
      #   link_image_to "logo", { :controller => "home" }, :alt => "Homepage", :size => "45x80"
      #   link_image_to "delete", { :action => "destroy" }, :size => "10x10", :confirm => "Are you sure?", "class" => "admin"
      def link_image_to(src, options = {}, html_options = {}, *parameters_for_method_reference)
        image_options = { "src" => src.include?("/") ? src : "/images/#{src}" }
        image_options["src"] = image_options["src"] + ".png" unless image_options["src"].include?(".")
        
        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

        if html_options["border"]
          image_options["border"] = html_options["border"]
          html_options.delete "border"
        else
          image_options["border"] = "0"
        end
        
        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

      alias_method :link_to_image, :link_image_to # deprecated name

      # Creates a link tag of the given +name+ using an URL created by the set of +options+, unless the current 
      # request uri is the same as the link's, in which case only the name is returned (or the
      # given block is yielded, if one exists). This is useful for creating link bars where you don't want to link 
      # to the page currently being viewed.
      def link_to_unless_current(name, options = {}, html_options = {}, *parameters_for_method_reference)
        if current_page?(options)
          block_given? ?
            yield(name, options, html_options, *parameters_for_method_reference) :
            html_escape(name)
        else
          link_to(name, options, html_options, *parameters_for_method_reference)
        end
      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.
      #
      # You can also make it difficult for spiders to harvest email address by obfuscating them.
       # Examples:
      #   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>
      def mail_to(email_address, name = nil, html_options = {})
        encode = html_options[:encode]
        html_options.delete(:encode)
        string = ''
        if encode == 'javascript'
          tmp = "document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address.to_s }))}');"
          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
          content_tag "a", name || email_address, html_options.merge({ "href" => "mailto:#{string}" })
        else
          content_tag "a", name || email_address, html_options.merge({ "href" => "mailto:#{email_address}" })
        end
      end

      # Returns true if the current page uri is generated by the options passed (in url_for format).
      def current_page?(options)
        url_for(options) == @request.request_uri
      end

      private
        def convert_confirm_option_to_javascript!(html_options)
          if html_options.include?(:confirm)
            html_options["onclick"] = "return confirm('#{html_options[:confirm]}');"
            html_options.delete(:confirm)
          end
        end
    end
  end
end