use Rose::Object::MakeMethods::Generic
 (
-  'scalar --get_set_init' => [ qw(_actions) ],
+  'scalar --get_set_init' => [ qw(_actions _flash _error) ],
 );
 
 my %supported_methods = (
+  # ## Non-jQuery methods ##
+  flash        => 2,            # display_flash(<TARGET>, <ARGS>)
+
   # ## jQuery basics ##
 
   # Basic effects
   data         => 3,
   removeData   => 2,
 
+  # Form Events
+  focus        => 1,
+
   # ## jstree plugin ## pattern: $.jstree._reference($(<TARGET>)).<FUNCTION>(<ARGS>)
 
   # Operations on the whole tree
   'jstree:reopen'        => 1,
 
   # Modifying nodes
+  'jstree:create_node'   => 4,
   'jstree:rename_node'   => 3,
   'jstree:delete_node'   => 2,
   'jstree:move_node'     => 5,
   my $method        =  $AUTOLOAD;
   $method           =~ s/.*:://;
   return if $method eq 'DESTROY';
+  return $self->action($method, @args);
+}
+
+sub action {
+  my ($self, $method, @args) = @_;
 
   $method      =  (delete($self->{_prefix}) || '') . $method;
   my $num_args =  $supported_methods{$method};
   return [];
 }
 
+sub init__flash {
+  return {};
+}
+
+sub init__error {
+  return '';
+}
+
 sub to_json {
   my ($self) = @_;
+
+  return SL::JSON::to_json({ error        => $self->_error   }) if $self->_error;
   return SL::JSON::to_json({ eval_actions => $self->_actions });
 }
 
   return $self;
 }
 
+sub flash {
+  my ($self, $type, @messages) = @_;
+
+  my $message = join ' ', grep { $_ } @messages;
+
+  if (!$self->_flash->{$type}) {
+    $self->_flash->{$type} = [ 'flash', $type, $message ];
+    push @{ $self->_actions }, $self->_flash->{$type};
+  } else {
+    $self->_flash->{$type}->[-1] .= ' ' . $message;
+  }
+
+  return $self;
+}
+
+sub error {
+  my ($self, @messages) = @_;
+
+  $self->_error(join ' ', grep { $_ } ($self->_error, @messages));
+
+  return $self;
+}
+
 1;
 __END__
 
 
 =head1 FUNCTIONS EVALUATED ON THE CLIENT SIDE
 
+=head2 GENERIC FUNCTION
+
+All of the following functions can be invoked in two ways: either by
+calling the function name directly on C<$self> or by calling
+L</action> with the function name as the first parameter. Therefore
+the following two calls are identical:
+
+  $js->insertAfter($html, '#some-id');
+  $js->action('insertAfter', $html, '#some-id');
+
+The second form, calling L</action>, is more to type but can be useful
+in situations in which you have to call one of two functions depending
+on context. For example, when you want to insert new code in a
+list. If the list is empty you might have to use C<appendTo>, if it
+isn't you might have to use C<insertAfter>. Example:
+
+  my $html = $self->render(...);
+  $js->action($list_is_empty ? 'appendTo' : 'insertAfter', $html, '#text-block-' . ($list_is_empty ? 'list' : $self->text_block->id));
+
+Instead of:
+
+  my $html = $self->render(...);
+  if ($list_is_empty) {
+    $js->appendTo($html, '#text-block-list');
+  } else {
+    $js->insertAfter($html, '#text-block-' . $self->text_block->id);
+  }
+
+The first variation is obviously better suited for chaining.
+
+Additional functions:
+
+=over 4
+
+=item C<flash $type, $message>
+
+Display a C<$message> in the flash of type C<$type>. Multiple calls of
+C<flash> on the same C<$self> will be merged by type.
+
+On the client side the flash of this type will be cleared before the
+message is shown.
+
+=item C<error $message>
+
+Causes L<to_json> (and therefore L<render>) to output a JSON object
+that only contains an C<error> field set to this C<$message>. The
+client will then show the message in the 'error' flash.
+
+The messages of multiple calls of C<error> on the same C<$self> will
+be merged.
+
+=back
+
 =head2 JQUERY FUNCTIONS
 
 The following jQuery functions are supported:
 
 C<data>, C<removeData>
 
+=item Form Events
+
+C<focus>
+
 =back
 
 =head2 JSTREE JQUERY PLUGIN