1 | """ |
---|
2 | Scriptaculous Helpers |
---|
3 | |
---|
4 | Provides a set of helpers for calling Scriptaculous JavaScript |
---|
5 | functions, including those which create Ajax controls and visual effects. |
---|
6 | |
---|
7 | To be able to use these helpers, you must include the Prototype |
---|
8 | JavaScript framework and the Scriptaculous JavaScript library in your |
---|
9 | pages. |
---|
10 | |
---|
11 | The Scriptaculous helpers' behavior can be tweaked with various options. |
---|
12 | See the documentation at http://script.aculo.us for more information on |
---|
13 | using these helpers in your application. |
---|
14 | """ |
---|
15 | # Last synced with Rails copy at Revision 3772 on Aug 19th, 2006. |
---|
16 | import simplejson as json |
---|
17 | from prototype import * |
---|
18 | from javascript import options_for_javascript, array_or_string_for_javascript |
---|
19 | from prototype import AJAX_OPTIONS, javascript_tag |
---|
20 | from tags import camelize |
---|
21 | |
---|
22 | def visual_effect(name, element_id=False, **js_options): |
---|
23 | """ |
---|
24 | Returns a JavaScript snippet to be used on the Ajax callbacks for |
---|
25 | starting visual effects. |
---|
26 | |
---|
27 | Example:: |
---|
28 | |
---|
29 | <% link_to_remote("Reload", |
---|
30 | dict(url=url(action="reload"), |
---|
31 | update="posts", |
---|
32 | complete=visual_effect('highlight', "posts", duration=0.5))) %> |
---|
33 | |
---|
34 | If no element_id is given, it assumes "element" which should be a local |
---|
35 | variable in the generated JavaScript execution context. This can be |
---|
36 | used for example with drop_receiving_element:: |
---|
37 | |
---|
38 | <% drop_receving_element('some_element', loading=visual_effect('fade')) %> |
---|
39 | |
---|
40 | This would fade the element that was dropped on the drop receiving |
---|
41 | element. |
---|
42 | |
---|
43 | For toggling visual effects, you can use ``toggle_appear``, ``toggle_slide``, and |
---|
44 | ``toggle_blind`` which will alternate between appear/fade, slidedown/slideup, and |
---|
45 | blinddown/blindup respectively. |
---|
46 | |
---|
47 | You can change the behaviour with various options, see |
---|
48 | http://script.aculo.us for more documentation. |
---|
49 | """ |
---|
50 | element = (element_id and json.dumps(element_id)) or "element" |
---|
51 | if isinstance(js_options.get('queue'), dict): |
---|
52 | js_options['queue'] = '{%s}' % ','.join(["%s:%s" % (k,(k == 'limit' and v) or "'%s'" % v) for k,v in js_options['queue'].iteritems()]) |
---|
53 | elif js_options.has_key('queue'): |
---|
54 | js_options['queue'] = "'%s'" % js_options['queue'] |
---|
55 | |
---|
56 | |
---|
57 | if 'toggle' in name: |
---|
58 | return "Effect.toggle(%s,'%s',%s);" % (element, name.replace('toggle_',''), options_for_javascript(js_options)) |
---|
59 | return "new Effect.%s(%s,%s);" % (camelize(name), element, options_for_javascript(js_options)) |
---|
60 | |
---|
61 | def parallel_effects(*effects, **js_options): |
---|
62 | """ |
---|
63 | Wraps visual effects so they occur in parallel |
---|
64 | |
---|
65 | Example:: |
---|
66 | |
---|
67 | parallel_effects( |
---|
68 | visual_effect('highlight, 'dom_id'), |
---|
69 | visual_effect('fade', 'dom_id'), |
---|
70 | ) |
---|
71 | """ |
---|
72 | str_effects = [e[:e.rindex(';')] for e in effects] # Remove trailing ';' |
---|
73 | return "new Effect.Parallel([%s], %s)" % (','.join(str_effects), options_for_javascript(js_options)) |
---|
74 | |
---|
75 | def sortable_element(element_id, **options): |
---|
76 | """ |
---|
77 | Makes the element with the DOM ID specified by ``element_id`` sortable. |
---|
78 | |
---|
79 | Uses drag-and-drop and makes an Ajax call whenever the sort order has |
---|
80 | changed. By default, the action called gets the serialized sortable |
---|
81 | element as parameters. |
---|
82 | |
---|
83 | Example:: |
---|
84 | |
---|
85 | <% sortable_element("my_list", url=url(action="order")) %> |
---|
86 | |
---|
87 | In the example, the action gets a "my_list" array parameter |
---|
88 | containing the values of the ids of elements the sortable consists |
---|
89 | of, in the current order. |
---|
90 | |
---|
91 | You can change the behaviour with various options, see |
---|
92 | http://script.aculo.us for more documentation. |
---|
93 | """ |
---|
94 | return javascript_tag(sortable_element_js(element_id, **options)) |
---|
95 | |
---|
96 | def sortable_element_js(element_id, **options): |
---|
97 | options.setdefault('with', "Sortable.serialize('%s')" % element_id) |
---|
98 | options.setdefault('onUpdate', "function(){%s}" % remote_function(**options)) |
---|
99 | for k in options.keys(): |
---|
100 | if k in AJAX_OPTIONS: del options[k] |
---|
101 | |
---|
102 | for option in ['tag', 'overlap', 'constraint', 'handle']: |
---|
103 | if options.has_key(option) and options[option]: |
---|
104 | options[option] = "'%s'" % options[option] |
---|
105 | |
---|
106 | if options.has_key('containment'): |
---|
107 | options['containment'] = array_or_string_for_javascript(options['containment']) |
---|
108 | if options.has_key('only'): |
---|
109 | options['only'] = array_or_string_for_javascript(options['only']) |
---|
110 | |
---|
111 | return "Sortable.create(%s, %s)" % (json.dumps(element_id), options_for_javascript(options)) |
---|
112 | |
---|
113 | def draggable_element(element_id, **options): |
---|
114 | """ |
---|
115 | Makes the element with the DOM ID specified by ``element_id`` draggable. |
---|
116 | |
---|
117 | Example:: |
---|
118 | |
---|
119 | <% draggable_element("my_image", revert=True) |
---|
120 | |
---|
121 | You can change the behaviour with various options, see |
---|
122 | http://script.aculo.us for more documentation. |
---|
123 | """ |
---|
124 | return javascript_tag(draggable_element_js(element_id, **options)) |
---|
125 | |
---|
126 | def draggable_element_js(element_id, **options): |
---|
127 | return "new Draggable(%s, %s)" % (json.dumps(element_id), options_for_javascript(options)) |
---|
128 | |
---|
129 | def drop_receiving_element(element_id, **options): |
---|
130 | """ |
---|
131 | Makes an element able to recieve dropped draggable elements |
---|
132 | |
---|
133 | Makes the element with the DOM ID specified by ``element_id`` receive |
---|
134 | dropped draggable elements (created by draggable_element) and make an |
---|
135 | AJAX call By default, the action called gets the DOM ID of the element |
---|
136 | as parameter. |
---|
137 | |
---|
138 | Example:: |
---|
139 | |
---|
140 | <% drop_receiving_element("my_cart", url=(controller="cart", action="add" )) %> |
---|
141 | |
---|
142 | You can change the behaviour with various options, see |
---|
143 | http://script.aculo.us for more documentation. |
---|
144 | """ |
---|
145 | return javascript_tag(drop_receiving_element_js(element_id, **options)) |
---|
146 | |
---|
147 | def drop_receiving_element_js(element_id, **options): |
---|
148 | options.setdefault('with', "'id=' + encodeURIComponent(element.id)") |
---|
149 | options.setdefault('onDrop', "function(element){%s}" % remote_function(**options)) |
---|
150 | for k in options.keys(): |
---|
151 | if k in AJAX_OPTIONS: del options[k] |
---|
152 | |
---|
153 | if options.has_key('accept'): |
---|
154 | options['accept'] = array_or_string_for_javascript(options['accept']) |
---|
155 | if options.has_key('hoverclass'): |
---|
156 | options['hoverclass'] = "'%s'" % options['hoverclass'] |
---|
157 | |
---|
158 | return "Droppables.add(%s, %s)" % (json.dumps(element_id), options_for_javascript(options)) |
---|
159 | |
---|
160 | __all__ = ['visual_effect', 'parallel_effects', 'sortable_element', 'draggable_element', 'drop_receiving_element'] |
---|