Tuesday, June 23, 2009

Replacing Wicket's FeedbackPanel with jGrowl

I wanted to replace the standard Wicket FeedbackPanel with a more modern growl-like presentation based on jGrowl. There are several ways to do this, but I chose Alex Objelean's JGrowlBehavior as my starting point. Our needs were simple. We have two types of feedback messages: component-level errors on form fields, which we display under the form field using Al Maw's ShinyFormVisitor, and session-level messages for everything else. We only want to display the session-level messages using JGrowlBehavior, so my version of JGrowlBehavior is quite simple. This works for both full server round trips (the button labeled "Normal OK" in the demo below), and Ajax (the button labeled "Ajax OK").

Demo



JGrowlBehavior.java


/**
* Attach to any component to display jGrowl messages.
*
* Displays only session-level messages. If you need component-level
* messages, see http://pastebin.com/f6db2ec0e for an example. Basically,
* instead of Session.get().getFeedbackMessages(), you would call
* getComponent().getFeedbackMessage().
*
* Requires the following be included: "jquery.js", "jquery.ui.all.js",
* "jquery.jgrowl.js", "jquery.jgrowl.css". These can be downloaded
* from http://plugins.jquery.com/files/jGrowl-1.2.0.tgz.
*
* @author jsinai
* Based on an example by Alex Objelean, see the above link.
*/
public class JGrowlBehavior extends AbstractDefaultAjaxBehavior
{
private static final long serialVersionUID = 1L;

/**
* Displays an info message that is sticky. The default is non-sticky.
* Sample usage: session.getFeedbackMessages().add(new FeedbackMessage(null,
* "my message", JGrowlBehavior.INFO_STICKY));
*/
public static final int INFO_STICKY = 250;

@Override
protected void respond(AjaxRequestTarget target)
{
final String feedbackMsg = renderFeedback();
if (!StringUtils.isEmpty(feedbackMsg))
{
target.appendJavascript(feedbackMsg);
}
}

@Override
public void renderHead(final IHeaderResponse response)
{
super.renderHead(response);
final String feedbackMsg = renderFeedback();
if (!StringUtils.isEmpty(feedbackMsg))
{
response.renderOnDomReadyJavascript(feedbackMsg);
}
}

private String renderFeedback()
{
this.getComponent().getFeedbackMessage();
final FeedbackMessages fm = Session.get().getFeedbackMessages();

final Iterator<FeedbackMessage> iter = fm.iterator();
final StringBuilder sb = new StringBuilder();
while (iter.hasNext())
{
final FeedbackMessage message = iter.next();
if ((message.getReporter() != null) || message.isRendered())
{
// If a component-level message, don't show it
continue;
}
final String cssClassSuffix = (message.getLevel() == INFO_STICKY) ? "INFO" : message
.getLevelAsString();
final Serializable serializable = message.getMessage();
final String msg = (serializable == null) ? StringUtils.EMPTY : serializable.toString();
sb.append("$.jGrowl(\"").append(msg).append('\"');
sb.append(", {");
sb.append("theme: \'jgrowl-").append(cssClassSuffix).append("\'");
if (message.getLevel() > FeedbackMessage.INFO)
{
sb.append(", sticky: true");
}
sb.append("}");
sb.append(");");
message.markRendered();
}
return sb.toString();
}
}

JGrowlPage.java


/**
* @author jsinai
*/
public class JGrowlPage extends WebPage {

public JGrowlPage() {
super();
add(CSSPackageResource.getHeaderContribution(JGrowlPage.class,
"JGrowlPage.css"));

Form<?> form = new Form("form") {

@Override
protected void onSubmit() {
Session.get().error("Test error");
Session.get().warn("Test warning");
Session.get().info("Test info");
Session.get().getFeedbackMessages().add(
new FeedbackMessage(null, "Test sticky info",
JGrowlBehavior.INFO_STICKY));
}
};
add(form);

AjaxButton b = new AjaxButton("ajaxbutton", form) {

@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
target.addComponent(form);
}
};
form.add(b);
form.add(new JGrowlBehavior());
}
}

JGrowlPage.html


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<wicket:head>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.ui.all.js"></script>
<script type="text/javascript" src="js/jquery.jgrowl.js"></script>
<link rel="stylesheet" href="css/jquery.jgrowl.css" />
<title>Wicket/jGrowl Demo</title>
</wicket:head>

<body>
<h1>Wicket/jGrowl Demo</h1>
<form wicket:id="form">
<input type="submit" value="Normal OK"/>
<input type="submit" value="Ajax OK" wicket:id="ajaxbutton"/>
</form>
</body>
</html>

JGrowlPage.css


@CHARSET "UTF-8";

div.jGrowl div.jgrowl-ERROR {
background-color: #BF0B0B;
}
div.jGrowl div.jgrowl-WARNING {
background-color: orange;
color: black;
}
div.jGrowl div.jgrowl-INFO {
background-color: #0C5F0C;
}

2 comments:

ink said...

That is very slick!

Arryandra Luis said...

Great !!!!