1 require 'action_view/helpers/javascript_helper'
5 # Provides a set of helpers for calling Scriptaculous JavaScript
6 # functions, including those which create Ajax controls and visual effects.
8 # To be able to use these helpers, you must include the Prototype
9 # JavaScript framework and the Scriptaculous JavaScript library in your
10 # pages. See the documentation for ActionView::Helpers::JavaScriptHelper
11 # for more information on including the necessary JavaScript.
13 # The Scriptaculous helpers' behavior can be tweaked with various options.
14 # See the documentation at http://script.aculo.us for more information on
15 # using these helpers in your application.
16 module ScriptaculousHelper
17 unless const_defined? :TOGGLE_EFFECTS
18 TOGGLE_EFFECTS = [:toggle_appear, :toggle_slide, :toggle_blind]
21 # Returns a JavaScript snippet to be used on the Ajax callbacks for
22 # starting visual effects.
25 # <%= link_to_remote "Reload", :update => "posts",
26 # :url => { :action => "reload" },
27 # :complete => visual_effect(:highlight, "posts", :duration => 0.5)
29 # If no element_id is given, it assumes "element" which should be a local
30 # variable in the generated JavaScript execution context. This can be
31 # used for example with drop_receiving_element:
33 # <%= drop_receiving_element (...), :loading => visual_effect(:fade) %>
35 # This would fade the element that was dropped on the drop receiving
38 # For toggling visual effects, you can use :toggle_appear, :toggle_slide, and
39 # :toggle_blind which will alternate between appear/fade, slidedown/slideup, and
40 # blinddown/blindup respectively.
42 # You can change the behaviour with various options, see
43 # http://script.aculo.us for more documentation.
44 def visual_effect(name, element_id = false, js_options = {})
45 element = element_id ? element_id.to_json : "element"
47 js_options[:queue] = if js_options[:queue].is_a?(Hash)
48 '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}'
49 elsif js_options[:queue]
50 "'#{js_options[:queue]}'"
51 end if js_options[:queue]
53 [:endcolor, :direction, :startcolor, :scaleMode, :restorecolor].each do |option|
54 js_options[option] = "'#{js_options[option]}'" if js_options[option]
57 if TOGGLE_EFFECTS.include? name.to_sym
58 "Effect.toggle(#{element},'#{name.to_s.gsub(/^toggle_/,'')}',#{options_for_javascript(js_options)});"
60 "new Effect.#{name.to_s.camelize}(#{element},#{options_for_javascript(js_options)});"
64 # Makes the element with the DOM ID specified by +element_id+ sortable
65 # by drag-and-drop and make an Ajax call whenever the sort order has
66 # changed. By default, the action called gets the serialized sortable
67 # element as parameters.
70 # <%= sortable_element("my_list", :url => { :action => "order" }) %>
72 # In the example, the action gets a "my_list" array parameter
73 # containing the values of the ids of elements the sortable consists
74 # of, in the current order.
76 # Important: For this to work, the sortable elements must have id
77 # attributes in the form "string_identifier". For example, "item_1". Only
78 # the identifier part of the id attribute will be serialized.
81 # You can change the behaviour with various options, see
82 # http://script.aculo.us for more documentation.
83 def sortable_element(element_id, options = {})
84 javascript_tag(sortable_element_js(element_id, options).chop!)
87 def sortable_element_js(element_id, options = {}) #:nodoc:
88 options[:with] ||= "Sortable.serialize(#{element_id.to_json})"
89 options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
90 options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
92 [:tag, :overlap, :constraint, :handle].each do |option|
93 options[option] = "'#{options[option]}'" if options[option]
96 options[:containment] = array_or_string_for_javascript(options[:containment]) if options[:containment]
97 options[:only] = array_or_string_for_javascript(options[:only]) if options[:only]
99 %(Sortable.create(#{element_id.to_json}, #{options_for_javascript(options)});)
102 # Makes the element with the DOM ID specified by +element_id+ draggable.
105 # <%= draggable_element("my_image", :revert => true)
107 # You can change the behaviour with various options, see
108 # http://script.aculo.us for more documentation.
109 def draggable_element(element_id, options = {})
110 javascript_tag(draggable_element_js(element_id, options).chop!)
113 def draggable_element_js(element_id, options = {}) #:nodoc:
114 %(new Draggable(#{element_id.to_json}, #{options_for_javascript(options)});)
117 # Makes the element with the DOM ID specified by +element_id+ receive
118 # dropped draggable elements (created by draggable_element).
119 # and make an AJAX call By default, the action called gets the DOM ID
120 # of the element as parameter.
123 # <%= drop_receiving_element("my_cart", :url =>
124 # { :controller => "cart", :action => "add" }) %>
126 # You can change the behaviour with various options, see
127 # http://script.aculo.us for more documentation.
128 def drop_receiving_element(element_id, options = {})
129 javascript_tag(drop_receiving_element_js(element_id, options).chop!)
132 def drop_receiving_element_js(element_id, options = {}) #:nodoc:
133 options[:with] ||= "'id=' + encodeURIComponent(element.id)"
134 options[:onDrop] ||= "function(element){" + remote_function(options) + "}"
135 options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
137 options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
138 options[:hoverclass] = "'#{options[:hoverclass]}'" if options[:hoverclass]
140 %(Droppables.add(#{element_id.to_json}, #{options_for_javascript(options)});)