12 junho 2007

Wicket: Highlight current Menu with Generics!

Yeah! The title sounds weird, but it's something really cool. The idea is to do less if/else as possible to select the current menu.

This is what my Template.html looks like:
        <!-- menu -->   
<div id="menu">
<ul>
<li wicket:id="system">
<a wicket:id="link" href="System.html">System</a>
</li>
<li wicket:id="about">
<a wicket:id="link" href="About.html">About</a>
</li>
</ul>
</div>

So, yes there is some CSS behind to show a cool layout, but that is not the point. Just note that if a <li> has an id of "current" like this:
    <li id="current">...</li>

Imagine that the CSS setup will do the rest, throwing out some cool stuff to highlight the current/selected menu.

So, how any pages under System's menu tells Template that they belong to it? As simple as this:
class UsersCRUD extends Template<System> {
}

Done! How this works? Let's check what's happening inside Template's default constructor:
public abstract class Template<M> extends WebPage {
public Template() {
Class<M> clazz = (Class<M>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];

add(new MenuItem("system", System.class, clazz));
add(new MenuItem("about", About.class, clazz));
}
}

And here goes the code for MenuItem:
public class MenuItem extends WebMarkupContainer {
/* Here the magic happens with CSS... */
public String getMarkupId() { return "current"; }

public MenuItem(String id, Class<? extends Template> linkTo,
Class<? extends Template> currentGeneric) {
super(id);

boolean isCurrentPage = currentGeneric.equals(linkTo);
setOutputMarkupId(isCurrentPage);
add(new BookmarkablePageLink("link", linkTo));
}
}

How about that? One simple equals and the conditional menu is done!

Oh, don't forget that Template is an abstract page and so, it has somewhere a <wicket:child/> so UserCRUD can be a subclass and do a composite page through inheritance.

Have fun Wicketers!!

2 comentários:

Eelco Hillenius disse...

Hey Bruno. Thanks for the post. Can't have enough of those :)

Why did you decide to use generics for this rather than e.g. annotations? Wouldn't that be more flexible?

Bruno Borges disse...

You're correct Eelco. Annotations are more flexible in this case. I just didn't remember to use them. But with Generics the code looks like more objective and clean, imho.

Anyway, the concept is quite the same and the idea is really cool in my opinion. :)

Generics or annotations, the result will be the same: less logical statements, more configuration in Java code.

Moving from this:

class Template<M extends Template> extends WebPage {
public Template() {
Class clazz = readGenericType();
...
}
}

To something like this:

class Template extends WebPage {
public Template() {
Class clazz = readAnnotation();
...
}
}

@Menu(About.class)
public UserCRUD extends Template {}

public @interface Menu {
Class<M extends Template> value();
}

Is trivial... :) Yes, Annotations are better! :)

Contato

Email:bruno.borges(at)gmail.com

LinkedIn: www.linkedin.com/in/brunocborges
Twitter: www.twitter.com/brunoborges
Comprei e Não Vou
Rio de Janeiro, RJ Brasil
Oracle
São Paulo, SP Brasil