5 use parent qw(Rose::Object);
10 use Rose::Object::MakeMethods::Generic
12 'scalar --get_set_init' => [ qw(_actions) ],
15 my %supported_methods = (
21 # DOM insertion, around
27 # DOM insertion, inside
35 # DOM insertion, outside
64 my ($self, @args) = @_;
66 my $method = $AUTOLOAD;
68 return if $method eq 'DESTROY';
70 my $num_args = $supported_methods{$method};
71 $::lxdebug->message(0, "autoload method $method");
73 croak "Unsupported jQuery action: $method" unless defined $num_args;
74 croak "Parameter count mismatch for $method(actual: " . scalar(@args) . " wanted: $num_args)" if scalar(@args) != $num_args;
77 # Force flattening from SL::Presenter::EscapedText: "" . $...
78 $args[0] = "" . $args[0];
82 push @{ $self->_actions }, [ $method, @args ];
93 return SL::JSON::to_json({ eval_actions => $self->_actions });
98 return $self->_actions;
102 my ($self, $controller) = @_;
103 return $controller->render(\$self->to_json, { type => 'json' });
115 SL::ClientJS - Easy programmatic client-side JavaScript generation
120 First some JavaScript code:
122 // In the client generate an AJAX request whose 'success' handler
123 // calls "eval_json_response(data)":
125 action: "SomeController/the_action",
126 id: $('#some_input_field').val()
128 $.post("controller.pl", data, eval_json_response);
132 # In the controller itself. First, make sure that the "client_js.js"
133 # is loaded. This must be done when the whole side is loaded, so
134 # it's not in the action called by the AJAX request shown above.
135 $::request->layout->use_javascript('client_js.js');
137 # Now in that action called via AJAX:
138 sub action_the_action {
141 # Create a new client-side JS object and do stuff with it!
142 my $js = SL::ClientJS->new;
144 # Show some element on the page:
145 $js->show('#usually_hidden');
147 # Set to hidden inputs. Yes, calls can be chained!
148 $js->val('#hidden_id', $self->new_id)
149 ->val('#other_type', 'Unicorn');
151 # Replace some HTML code:
152 my $html = $self->render('SomeController/the_action', { output => 0 });
153 $js->html('#id_with_new_content', $html);
155 # Finally render the JSON response:
161 This module enables the generation of jQuery-using JavaScript code on
162 the server side. That code is then evaluated in a safe way on the
165 The workflow is usally that the client creates an AJAX request, the
166 server creates some actions and sends them back, and the client then
167 implements each of these actions.
169 There are three things that need to be done for this to work:
173 =item 1. The "client_js.js" has to be loaded before the AJAX request is started.
175 =item 2. The client code needs to call C<eval_json_response()> with the result returned from the server.
177 =item 3. The server must use this module.
181 The functions called on the client side are mostly jQuery
182 functions. Other functionality may be added later.
184 Note that L<SL::Controller/render> is aware of this module which saves
185 you some boilerplate. The following two calls are equivalent:
187 $controller->render($client_js);
188 $controller->render(\$client_js->to_json, { type => 'json' });
190 =head1 FUNCTIONS NOT PASSED TO THE CLIENT SIDE
196 Returns the actions gathered so far as an array reference. Each
197 element is an array reference containing at least two items: the
198 function's name and what it is called on. Additional array elements
199 are the function parameters.
203 Returns the actions gathered so far as a JSON string ready to be sent
206 =item C<render $controller>
208 Renders C<$self> via the controller. Useful for chaining. Equivalent
211 $controller->render(\$self->to_json, { type => 'json' });
215 =head1 FUNCTIONS EVALUATED ON THE CLIENT SIDE
217 =head2 JQUERY FUNCTIONS
219 The following jQuery functions are supported:
225 C<hide>, C<show>, C<toggle>
227 =item DOM insertion, around
229 C<unwrap>, C<wrap>, C<wrapAll>, C<wrapInner>
231 =item DOM insertion, inside
233 C<append>, C<appendTo>, C<html>, C<prepend>, C<prependTo>, C<text>
235 =item DOM insertion, outside
237 C<after>, C<before>, C<insertAfter>, C<insertBefore>
243 =item DOM replacement
245 C<replaceAll>, C<replaceWith>
247 =item General attributes
249 C<attr>, C<prop>, C<removeAttr>, C<removeProp>, C<val>
253 C<data>, C<removeData>
257 =head1 ADDING SUPPORT FOR ADDITIONAL FUNCTIONS
259 In order not having to maintain two files (this one and
260 C<js/client_js.js>) there's a script that can parse this file's
261 C<%supported_methods> definition and convert it into the appropriate
262 code ready for manual insertion into C<js/client_js.js>. The steps
267 =item 1. Add lines in this file to the C<%supported_methods> hash. The
268 key is the function name and the value is the number of expected
271 =item 2. Run C<scripts/generate_client_js_actions.pl>
273 =item 3. Edit C<js/client_js.js> and replace the type casing code with
274 the output generated in step 2.
284 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>