aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/helpers/javascript_helper.rb
blob: 136d006ad18eef20cc1d0cfb713309be9cb828e7 (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
require 'action_view/helpers/tag_helper'

module ActionView
  # = Action View JavaScript Helpers
  module Helpers
    # Provides functionality for working with JavaScript in your views.
    #
    # == Ajax, controls and visual effects
    #
    # * For information on using Ajax, see
    #   ActionView::Helpers::PrototypeHelper.
    # * For information on using controls and visual effects, see
    #   ActionView::Helpers::ScriptaculousHelper.
    #
    # == Including the JavaScript libraries into your pages
    #
    # Rails includes the Prototype JavaScript framework and the Scriptaculous
    # JavaScript controls and visual effects library.  If you wish to use
    # these libraries and their helpers (ActionView::Helpers::PrototypeHelper
    # and ActionView::Helpers::ScriptaculousHelper), you must do one of the
    # following:
    #
    # * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
    #   section of your page (recommended): This function will return
    #   references to the JavaScript files created by the +rails+ command in
    #   your <tt>public/javascripts</tt> directory. Using it is recommended as
    #   the browser can then cache the libraries instead of fetching all the
    #   functions anew on every request.
    # * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
    #   will only include the Prototype core library, which means you are able
    #   to use all basic AJAX functionality. For the Scriptaculous-based
    #   JavaScript helpers, like visual effects, autocompletion, drag and drop
    #   and so on, you should use the method described above.
    #
    # For documentation on +javascript_include_tag+ see
    # ActionView::Helpers::AssetTagHelper.
    module JavaScriptHelper
      include PrototypeHelper

      JS_ESCAPE_MAP = {
        '\\'    => '\\\\',
        '</'    => '<\/',
        "\r\n"  => '\n',
        "\n"    => '\n',
        "\r"    => '\n',
        '"'     => '\\"',
        "'"     => "\\'" }

      # Escape carrier returns and single and double quotes for JavaScript segments.
      # Also available through the alias j(). This is particularly helpful in JavaScript responses, like:
      #
      #   $('some_element').replaceWith('<%=j render 'some/element_template' %>');
      def escape_javascript(javascript)
        if javascript
          javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
        else
          ''
        end
      end

      alias_method :j, :escape_javascript

      # Returns a JavaScript tag with the +content+ inside. Example:
      #   javascript_tag "alert('All is good')"
      #
      # Returns:
      #   <script type="text/javascript">
      #   //<![CDATA[
      #   alert('All is good')
      #   //]]>
      #   </script>
      #
      # +html_options+ may be a hash of attributes for the <tt>\<script></tt>
      # tag. Example:
      #   javascript_tag "alert('All is good')", :defer => 'defer'
      #   # => <script defer="defer" type="text/javascript">alert('All is good')</script>
      #
      # Instead of passing the content as an argument, you can also use a block
      # in which case, you pass your +html_options+ as the first parameter.
      #   <%= javascript_tag :defer => 'defer' do -%>
      #     alert('All is good')
      #   <% end -%>
      def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
        content =
          if block_given?
            html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
            capture(&block)
          else
            content_or_options_with_block
          end

        content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
      end

      def javascript_cdata_section(content) #:nodoc:
        "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe
      end

      # Returns a button whose +onclick+ handler triggers the passed JavaScript.
      #
      # The helper receives a name, JavaScript code, and an optional hash of HTML options. The
      # name is used as button label and the JavaScript code goes into its +onclick+ attribute.
      # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+.
      #
      #   button_to_function "Greeting", "alert('Hello world!')", :class => "ok"
      #   # => <input class="ok" onclick="alert('Hello world!');" type="button" value="Greeting" />
      #
      def button_to_function(name, function='', html_options={})
        onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"

        tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
      end

      # Returns a link whose +onclick+ handler triggers the passed JavaScript.
      #
      # The helper receives a name, JavaScript code, and an optional hash of HTML options. The
      # name is used as the link text and the JavaScript code goes into the +onclick+ attribute.
      # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+. Once all
      # the JavaScript is set, the helper appends "; return false;".
      #
      # The +href+ attribute of the tag is set to "#" unles +html_options+ has one.
      #
      #   link_to_function "Greeting", "alert('Hello world!')", :class => "nav_link"
      #     Produces:
      #       <a onclick="alert('Hello world!'); return false;" href="#" class="nav_link">Greeting</a>
      def link_to_function(name, function, html_options={})
        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