my %supported_methods = (
# ## Non-jQuery methods ##
- flash => 2, # display_flash(<TARGET>, <ARGS>)
+ flash => 2, # kivi.display_flash(<TARGET>, <ARGS>)
# ## jQuery basics ##
removeProp => 2,
val => 2,
+ # Class attribute
+ addClass => 2,
+ removeClass => 2,
+ toggleClass => 2,
+
# Data storage
data => 3,
removeData => 2,
# Form Events
focus => 1,
+ # Generic Event Handling ## pattern: $(<TARGET>).<FUNCTION>(<ARG1>, kivi.get_function_by_name(<ARG2>))
+ on => 3,
+ off => 3,
+ one => 3,
+
+ # ## jQuery UI dialog plugin ## pattern: $(<TARGET>).dialog('<FUNCTION>')
+
+ # Closing and removing the popup
+ 'dialog:close' => 1,
+
+ # ## jQuery Form plugin ##
+ 'ajaxForm' => 1, # pattern: $(<TARGET>).ajaxForm({ success: eval_json_result })
+
# ## jstree plugin ## pattern: $.jstree._reference($(<TARGET>)).<FUNCTION>(<ARGS>)
# Operations on the whole tree
'jstree:select_node' => 2, # $.jstree._reference($(<TARGET>)).<FUNCTION>(<ARGS>, true)
'jstree:deselect_node' => 2,
'jstree:deselect_all' => 1,
+
+ # ## other stuff ##
+ redirect_to => 1, # window.location.href = <TARGET>
+
+ reinit_widgets => 0, # kivi.reinit_widgets()
);
sub AUTOLOAD {
croak "Unsupported jQuery action: $method" unless defined $num_args;
croak "Parameter count mismatch for $method(actual: " . scalar(@args) . " wanted: $num_args)" if scalar(@args) != $num_args;
- if ($num_args) {
- # Force flattening from SL::Presenter::EscapedText: "" . $...
- $args[0] = "" . $args[0];
- $args[0] =~ s/^\s+//;
+ foreach my $idx (0..$num_args - 1) {
+ # Force flattening from SL::Presenter::EscapedText and trim leading whitespace for scalars
+ $args[$idx] = "" . $args[$idx] if ref($args[$idx]) eq 'SL::Presenter::EscapedText';
+ $args[$idx] =~ s/^\s+// if !ref($args[$idx]);
}
push @{ $self->_actions }, [ $method, @args ];
return $self;
}
+sub action_if {
+ my ($self, $condition, @args) = @_;
+
+ return $condition ? $self->action(@args) : $self;
+}
+
sub init__actions {
return [];
}
sub render {
my ($self, $controller) = @_;
+ $self->reinit_widgets if $::request->presenter->need_reinit_widgets;
return $controller->render(\$self->to_json, { type => 'json' });
}
return $self;
}
+sub dialog {
+ my ($self) = @_;
+ $self->{_prefix} = 'dialog:';
+ return $self;
+}
+
sub flash {
my ($self, $type, @messages) = @_;
First some JavaScript code:
// In the client generate an AJAX request whose 'success' handler
- // calls "eval_json_response(data)":
+ // calls "eval_json_result(data)":
var data = {
action: "SomeController/the_action",
id: $('#some_input_field').val()
};
- $.post("controller.pl", data, eval_json_response);
+ $.post("controller.pl", data, eval_json_result);
Now some Perl code:
$js->jstree->rename_node('#tb-' . $text_block->id, $text_block->title)
->jstree->select_node('#tb-' . $text_block->id);
+ # Close a popup opened by kivi.popup_dialog():
+ $js->dialog->close('#jqueryui_popup_dialog');
+
# Finally render the JSON response:
$self->render($js);
=item 1. The "client_js.js" has to be loaded before the AJAX request is started.
-=item 2. The client code needs to call C<eval_json_response()> with the result returned from the server.
+=item 2. The client code needs to call C<kivi.eval_json_result()> with the result returned from the server.
=item 3. The server must use this module.
$controller->render(\$self->to_json, { type => 'json' });
+=item C<dialog>
+
+Tells C<$self> that the next action is to be called on a jQuery UI
+dialog instance, e.g. one opened by C<kivi.popup_dialog()>. For
+example:
+
+ $js->dialog->close('#jqueryui_popup_dialog');
+
=item C<jstree>
Tells C<$self> that the next action is to be called on a jstree
The first variation is obviously better suited for chaining.
-Additional functions:
+=over 4
+
+=item C<action $method, @args>
+
+Call the function with the name C<$method> on C<$self> with arguments
+C<@args>. Returns the return value of the actual function
+called. Useful for chaining (see above).
+
+=item C<action_if $condition, $method, @args>
+
+Call the function with the name C<$method> on C<$self> with arguments
+C<@args> if C<$condition> is trueish. Does nothing otherwise.
+
+Returns the return value of the actual function called if
+C<$condition> is trueish and C<$self> otherwise. Useful for chaining
+(see above).
+
+This function is equivalent to the following:
+
+ if ($condition) {
+ $obj->$method(@args);
+ }
+
+But it is easier to integrate into a method call chain, e.g.:
+
+ $js->html('#content', $html)
+ ->action_if($item->is_flagged, 'toggleClass', '#marker', 'flagged')
+ ->render($self);
+
+=back
+
+=head2 ADDITIONAL FUNCTIONS
=over 4
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.
+On the client side the flashes of all types will be cleared after each
+successful ClientJS call that did not end with C<$js-E<gt>error(...)>.
=item C<error $message>
The messages of multiple calls of C<error> on the same C<$self> will
be merged.
+=item C<redirect_to $url>
+
+Redirects the browser window to the new URL by setting the JavaScript
+property C<window.location.href>. Note that
+L<SL::Controller::Base/redirect_to> is AJAX aware and uses this
+function if the current request is an AJAX request as determined by
+L<SL::Request/is_ajax>.
+
=back
=head2 JQUERY FUNCTIONS
C<focus>
+=item Generic Event Handlers
+
+C<on>, C<off>, C<one>
+
+These attach/detach event listeners to specific selectors. The first
+argument is the selector, the second the name of the events and the
+third argument is the name of the handler function. That function must
+already exist when the handler is added.
+
=back
=head2 JSTREE JQUERY PLUGIN