url_helper.rb 9.1 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1 2 3 4 5 6 7
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
8 9
      # 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.
D
Initial  
David Heinemeier Hansson 已提交
10
      def url_for(options = {}, *parameters_for_method_reference)
11
        options = { :only_path => true }.update(options.symbolize_keys) if options.kind_of? Hash
D
Initial  
David Heinemeier Hansson 已提交
12 13 14 15 16
        @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
17 18
      # 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?',
19
      # the link will be guarded with a JS popup asking that question. If the user accepts, the link is processed, otherwise not.
20 21 22
      #
      # Example:
      #   link_to "Delete this page", { :action => "destroy", :id => @page.id }, :confirm => "Are you sure?"
23
      def link_to(name, options = {}, html_options = nil, *parameters_for_method_reference)
24
        html_options = (html_options || {}).stringify_keys
25
        convert_confirm_option_to_javascript!(html_options)
D
Initial  
David Heinemeier Hansson 已提交
26
        if options.is_a?(String)
27
          content_tag "a", name || options, (html_options || {}).merge("href" => options)
D
Initial  
David Heinemeier Hansson 已提交
28
        else
29
          content_tag(
30 31
            "a", name || url_for(options, *parameters_for_method_reference),
            (html_options || {}).merge("href" => url_for(options, *parameters_for_method_reference))
32
          )
D
Initial  
David Heinemeier Hansson 已提交
33 34 35
        end
      end

36
      # This tag is deprecated. Combine the link_to and AssetTagHelper::image_tag yourself instead, like:
37
      #   link_to(image_tag("rss", :size => "30x45", :border => 0), "http://www.example.com")
38
      def link_image_to(src, options = {}, html_options = {}, *parameters_for_method_reference)
39
        image_options = { "src" => src.include?("/") ? src : "/images/#{src}" }
40 41 42
        image_options["src"] += ".png" unless image_options["src"].include?(".")

        html_options = html_options.stringify_keys
43 44 45 46 47 48 49 50 51 52 53
        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
54 55 56 57 58

        if html_options["border"]
          image_options["border"] = html_options["border"]
          html_options.delete "border"
        end
59

60 61 62 63 64 65 66 67
        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

68 69
      alias_method :link_to_image, :link_image_to # deprecated name

70
      # Creates a link tag of the given +name+ using an URL created by the set of +options+, unless the current
71
      # request uri is the same as the link's, in which case only the name is returned (or the
72
      # given block is yielded, if one exists). This is useful for creating link bars where you don't want to link
D
Initial  
David Heinemeier Hansson 已提交
73
      # to the page currently being viewed.
74 75 76 77 78 79 80 81 82 83 84
      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
D
Initial  
David Heinemeier Hansson 已提交
85
            html_escape(name)
86
          end
D
Initial  
David Heinemeier Hansson 已提交
87
        else
88
          link_to(name, options, html_options, *parameters_for_method_reference)
89 90 91 92 93 94 95
        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
D
Initial  
David Heinemeier Hansson 已提交
96 97 98 99
      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.
100 101
      #
      # You can also make it difficult for spiders to harvest email address by obfuscating them.
102
      # Examples:
103 104 105 106 107
      #   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>
108 109 110 111 112 113 114 115
      #
      # 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>
D
Initial  
David Heinemeier Hansson 已提交
116
      def mail_to(email_address, name = nil, html_options = {})
117 118
        html_options = html_options.stringify_keys
        encode = html_options.delete("encode")
119 120
        cc, bcc, subject, body = html_options.delete("cc"), html_options.delete("bcc"), html_options.delete("subject"), html_options.delete("body")

121
        string = ''
122 123 124 125 126 127 128
        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?

129
        if encode == 'javascript'
130
          tmp = "document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address.to_s+extras }))}');"
131 132 133 134 135 136 137 138 139 140 141 142
          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
143
          content_tag "a", name || email_address, html_options.merge({ "href" => "mailto:#{string}#{extras}" })
144
        else
145
          content_tag "a", name || email_address, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
146
        end
D
Initial  
David Heinemeier Hansson 已提交
147 148
      end

149 150 151 152 153
      # 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

D
Initial  
David Heinemeier Hansson 已提交
154 155
      private
        def convert_confirm_option_to_javascript!(html_options)
156
          if confirm = html_options.delete("confirm")
157
            html_options["onclick"] = "return confirm('#{confirm.gsub(/'/, '\\\\\'')}');"
D
Initial  
David Heinemeier Hansson 已提交
158 159 160 161
          end
        end
    end
  end
162
end