~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/actionpack/lib/action_view/helpers/scriptaculous_helper.rb

  • Committer: Richard Lee (Canonical)
  • Date: 2010-10-15 15:17:58 UTC
  • mfrom: (190.1.3 use-case-mapper)
  • Revision ID: richard.lee@canonical.com-20101015151758-wcvmfxrexsongf9d
Merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
require 'action_view/helpers/javascript_helper'
2
 
require 'active_support/json'
3
 
 
4
 
module ActionView
5
 
  module Helpers
6
 
    # Provides a set of helpers for calling Scriptaculous JavaScript 
7
 
    # functions, including those which create Ajax controls and visual effects.
8
 
    #
9
 
    # To be able to use these helpers, you must include the Prototype 
10
 
    # JavaScript framework and the Scriptaculous JavaScript library in your 
11
 
    # pages. See the documentation for ActionView::Helpers::JavaScriptHelper
12
 
    # for more information on including the necessary JavaScript.
13
 
    #
14
 
    # The Scriptaculous helpers' behavior can be tweaked with various options.
15
 
    # See the documentation at http://script.aculo.us for more information on
16
 
    # using these helpers in your application.
17
 
    module ScriptaculousHelper
18
 
      unless const_defined? :TOGGLE_EFFECTS
19
 
        TOGGLE_EFFECTS = [:toggle_appear, :toggle_slide, :toggle_blind]
20
 
      end
21
 
      
22
 
      # Returns a JavaScript snippet to be used on the Ajax callbacks for
23
 
      # starting visual effects.
24
 
      #
25
 
      # Example:
26
 
      #   <%= link_to_remote "Reload", :update => "posts", 
27
 
      #         :url => { :action => "reload" }, 
28
 
      #         :complete => visual_effect(:highlight, "posts", :duration => 0.5)
29
 
      #
30
 
      # If no +element_id+ is given, it assumes "element" which should be a local
31
 
      # variable in the generated JavaScript execution context. This can be 
32
 
      # used for example with +drop_receiving_element+:
33
 
      #
34
 
      #   <%= drop_receiving_element (...), :loading => visual_effect(:fade) %>
35
 
      #
36
 
      # This would fade the element that was dropped on the drop receiving 
37
 
      # element.
38
 
      #
39
 
      # For toggling visual effects, you can use <tt>:toggle_appear</tt>, <tt>:toggle_slide</tt>, and
40
 
      # <tt>:toggle_blind</tt> which will alternate between appear/fade, slidedown/slideup, and
41
 
      # blinddown/blindup respectively.
42
 
      #
43
 
      # You can change the behaviour with various options, see
44
 
      # http://script.aculo.us for more documentation.
45
 
      def visual_effect(name, element_id = false, js_options = {})
46
 
        element = element_id ? ActiveSupport::JSON.encode(element_id) : "element"
47
 
        
48
 
        js_options[:queue] = if js_options[:queue].is_a?(Hash)
49
 
          '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}'
50
 
        elsif js_options[:queue]
51
 
          "'#{js_options[:queue]}'"
52
 
        end if js_options[:queue]
53
 
        
54
 
        [:endcolor, :direction, :startcolor, :scaleMode, :restorecolor].each do |option|
55
 
          js_options[option] = "'#{js_options[option]}'" if js_options[option]
56
 
        end
57
 
 
58
 
        if TOGGLE_EFFECTS.include? name.to_sym
59
 
          "Effect.toggle(#{element},'#{name.to_s.gsub(/^toggle_/,'')}',#{options_for_javascript(js_options)});"
60
 
        else
61
 
          "new Effect.#{name.to_s.camelize}(#{element},#{options_for_javascript(js_options)});"
62
 
        end
63
 
      end
64
 
      
65
 
      # Makes the element with the DOM ID specified by +element_id+ sortable
66
 
      # by drag-and-drop and make an Ajax call whenever the sort order has
67
 
      # changed. By default, the action called gets the serialized sortable
68
 
      # element as parameters.
69
 
      #
70
 
      # Example:
71
 
      #
72
 
      #   <%= sortable_element("my_list", :url => { :action => "order" }) %>
73
 
      #
74
 
      # In the example, the action gets a "my_list" array parameter 
75
 
      # containing the values of the ids of elements the sortable consists 
76
 
      # of, in the current order.
77
 
      #
78
 
      # Important: For this to work, the sortable elements must have id
79
 
      # attributes in the form "string_identifier". For example, "item_1". Only
80
 
      # the identifier part of the id attribute will be serialized.
81
 
      # 
82
 
      # Additional +options+ are:
83
 
      #
84
 
      # * <tt>:format</tt> - A regular expression to determine what to send as the
85
 
      #   serialized id to the server (the default is <tt>/^[^_]*_(.*)$/</tt>).
86
 
      #                           
87
 
      # * <tt>:constraint</tt> - Whether to constrain the dragging to either
88
 
      #   <tt>:horizontal</tt> or <tt>:vertical</tt> (or false to make it unconstrained).
89
 
      #                            
90
 
      # * <tt>:overlap</tt> - Calculate the item overlap in the <tt>:horizontal</tt>
91
 
      #   or <tt>:vertical</tt> direction.
92
 
      #                            
93
 
      # * <tt>:tag</tt> - Which children of the container element to treat as
94
 
      #   sortable (default is <tt>li</tt>).
95
 
      #                          
96
 
      # * <tt>:containment</tt> - Takes an element or array of elements to treat as
97
 
      #   potential drop targets (defaults to the original target element).
98
 
      #                          
99
 
      # * <tt>:only</tt> - A CSS class name or array of class names used to filter
100
 
      #   out child elements as candidates.
101
 
      #                          
102
 
      # * <tt>:scroll</tt> - Determines whether to scroll the list during drag
103
 
      #   operations if the list runs past the visual border.
104
 
      #                          
105
 
      # * <tt>:tree</tt> - Determines whether to treat nested lists as part of the
106
 
      #   main sortable list. This means that you can create multi-layer lists,
107
 
      #   and not only sort items at the same level, but drag and sort items
108
 
      #   between levels.
109
 
      #                          
110
 
      # * <tt>:hoverclass</tt> - If set, the Droppable will have this additional CSS class
111
 
      #   when an accepted Draggable is hovered over it.                         
112
 
      #                          
113
 
      # * <tt>:handle</tt> - Sets whether the element should only be draggable by an
114
 
      #   embedded handle. The value may be a string referencing a CSS class value
115
 
      #   (as of script.aculo.us V1.5). The first child/grandchild/etc. element
116
 
      #   found within the element that has this CSS class value will be used as
117
 
      #   the handle.
118
 
      #                          
119
 
      # * <tt>:ghosting</tt> - Clones the element and drags the clone, leaving
120
 
      #   the original in place until the clone is dropped (default is <tt>false</tt>).
121
 
      #                          
122
 
      # * <tt>:dropOnEmpty</tt> - If true the Sortable container will be made into
123
 
      #   a Droppable, that can receive a Draggable (as according to the containment
124
 
      #   rules) as a child element when there are no more elements inside (default
125
 
      #   is <tt>false</tt>).
126
 
      #                          
127
 
      # * <tt>:onChange</tt> - Called whenever the sort order changes while dragging. When
128
 
      #   dragging from one Sortable to another, the callback is called once on each
129
 
      #   Sortable. Gets the affected element as its parameter.
130
 
      #                          
131
 
      # * <tt>:onUpdate</tt> - Called when the drag ends and the Sortable's order is
132
 
      #   changed in any way. When dragging from one Sortable to another, the callback
133
 
      #   is called once on each Sortable. Gets the container as its parameter.
134
 
      #                                                                                         
135
 
      # See http://script.aculo.us for more documentation.
136
 
      def sortable_element(element_id, options = {})
137
 
        javascript_tag(sortable_element_js(element_id, options).chop!)
138
 
      end
139
 
      
140
 
      def sortable_element_js(element_id, options = {}) #:nodoc:
141
 
        options[:with]     ||= "Sortable.serialize(#{ActiveSupport::JSON.encode(element_id)})"
142
 
        options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
143
 
        options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
144
 
  
145
 
        [:tag, :overlap, :constraint, :handle].each do |option|
146
 
          options[option] = "'#{options[option]}'" if options[option]
147
 
        end
148
 
  
149
 
        options[:containment] = array_or_string_for_javascript(options[:containment]) if options[:containment]
150
 
        options[:only] = array_or_string_for_javascript(options[:only]) if options[:only]
151
 
  
152
 
        %(Sortable.create(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});)
153
 
      end
154
 
 
155
 
      # Makes the element with the DOM ID specified by +element_id+ draggable.
156
 
      #
157
 
      # Example:
158
 
      #   <%= draggable_element("my_image", :revert => true)
159
 
      # 
160
 
      # You can change the behaviour with various options, see
161
 
      # http://script.aculo.us for more documentation.
162
 
      def draggable_element(element_id, options = {})
163
 
        javascript_tag(draggable_element_js(element_id, options).chop!)
164
 
      end
165
 
      
166
 
      def draggable_element_js(element_id, options = {}) #:nodoc:
167
 
        %(new Draggable(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});)
168
 
      end
169
 
 
170
 
      # Makes the element with the DOM ID specified by +element_id+ receive
171
 
      # dropped draggable elements (created by +draggable_element+).
172
 
      # and make an AJAX call. By default, the action called gets the DOM ID 
173
 
      # of the element as parameter.
174
 
      #
175
 
      # Example:
176
 
      #   <%= drop_receiving_element("my_cart", :url => 
177
 
      #     { :controller => "cart", :action => "add" }) %>
178
 
      #
179
 
      # You can change the behaviour with various options, see
180
 
      # http://script.aculo.us for more documentation.
181
 
      #
182
 
      # Some of these +options+ include:
183
 
      # * <tt>:accept</tt> - Set this to a string or an array of strings describing the
184
 
      #   allowable CSS classes that the +draggable_element+ must have in order 
185
 
      #   to be accepted by this +drop_receiving_element+.
186
 
      #                          
187
 
      # * <tt>:confirm</tt> - Adds a confirmation dialog. Example:
188
 
      #                     
189
 
      #     :confirm => "Are you sure you want to do this?"
190
 
      #                          
191
 
      # * <tt>:hoverclass</tt> - If set, the +drop_receiving_element+ will have
192
 
      #   this additional CSS class when an accepted +draggable_element+ is
193
 
      #   hovered over it.                         
194
 
      #                          
195
 
      # * <tt>:onDrop</tt> - Called when a +draggable_element+ is dropped onto
196
 
      #   this element. Override this callback with a JavaScript expression to 
197
 
      #   change the default drop behaviour. Example:
198
 
      #                          
199
 
      #     :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }"
200
 
      #                          
201
 
      #   This callback gets three parameters: The Draggable element, the Droppable
202
 
      #   element and the Event object. You can extract additional information about
203
 
      #   the drop - like if the Ctrl or Shift keys were pressed - from the Event object.
204
 
      #                          
205
 
      # * <tt>:with</tt> - A JavaScript expression specifying the parameters for
206
 
      #   the XMLHttpRequest. Any expressions should return a valid URL query string.
207
 
      def drop_receiving_element(element_id, options = {})
208
 
        javascript_tag(drop_receiving_element_js(element_id, options).chop!)
209
 
      end
210
 
      
211
 
      def drop_receiving_element_js(element_id, options = {}) #:nodoc:
212
 
        options[:with]     ||= "'id=' + encodeURIComponent(element.id)"
213
 
        options[:onDrop]   ||= "function(element){" + remote_function(options) + "}"
214
 
        options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
215
 
 
216
 
        options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]    
217
 
        options[:hoverclass] = "'#{options[:hoverclass]}'" if options[:hoverclass]
218
 
        
219
 
        # Confirmation happens during the onDrop callback, so it can be removed from the options
220
 
        options.delete(:confirm) if options[:confirm]
221
 
 
222
 
        %(Droppables.add(#{ActiveSupport::JSON.encode(element_id)}, #{options_for_javascript(options)});)
223
 
      end
224
 
    end
225
 
  end
226
 
end