Note: there is an updated post on this topic.
We wanted to add Suckerfish dropdowns to our Wicket site. Suckerfish dropdowns were first mentioned on A List Apart and have since become very popular as super-simple, lightweight, easy-to-use Javascript menus. The licensing is liberal too, see the "Free source" section on the Copyright page. Since then they have been refined as "Son of Suckerfish".
As is common with Wicket, this turned out to be easy to do. All we need was single-level menus (i.e. no sub-submenus), but it should be straightforward to extend this to support that. I also wanted to keep it as simple as possible for illustration purposes. The solution consists of just one class.
Note: this has only been tested with Wicket 1.3.0.
First an example of how to use it.
MyWebPage.java
...
// Create the menubar
final SuckerfishMenuPanel mb = new SuckerfishMenuPanel("menuBar");
add(mb);
// Create a menu
SuckerfishMenuPanel.MenuItem mi =
new SuckerfishMenuPanel.MenuItem(new
BookmarkablePageLink(SuckerfishMenuPanel.LINK_ID, MyFirstPage.class),
"myFirstLabel");
mb.addMenu(mi);
// Create a submenu
SuckerfishMenuPanel.MenuItem submi =
new SuckerfishMenuPanel.MenuItem(new
BookmarkablePageLink(SuckerfishMenuPanel.LINK_ID, MySecondPage.class),
"mySecondLabel");
mi.addMenu(submi);
...
MyWebPage.html
...
<div wicket:id="menuBar" class="menubar">[MenuBar Here]</div>
...
Now the implementation. Note that these menus consist of Links. This gives you the freedom to pass in whatever type of Link you need, except for ExternalLink, which unfortunately does not inherit from Link.
SuckerfishMenuPanel.java
/**
* See http://www.alistapart.com/articles/dropdowns/
* License is at
* http://www.alistapart.com/copyright/, see "Free source"
* Currently only supports one level of dropdowns
*/
public class SuckerfishMenuPanel extends Panel
{
private static final long serialVersionUID = -21832859336423477L;
public static final String LINK_ID = "linkid";
public static final String LINK_TEXT_ID = "linktext";
private final Listnew ListView("menuitemlinks", menuItem.getChildren())
{
private static final long serialVersionUID = -2997784619579088676L;
@Override
protected void populateItem(ListItem item)
{
final MenuItem menuItem = (MenuItem) item
.getModelObject();
item.add(menuItem.getLink());
}
};
menuitemul.add(menuitemlinks);
}
});
}
/** Add one menu item */
public void addMenu(MenuItem menu)
{
if (!menu.link.getId().equals(LINK_ID))
{
throw new IllegalArgumentException(
"The id must be SuckerfishMenuPanel.LINK_ID");
}
topMenuItems.add(menu);
}
/** Add all menus at once */
public void setMenuItems(ListmenuItems)
{
this.topMenuItems.clear();
this.topMenuItems.addAll(menuItems);
}
/** Lightweight menu object that stores a menu Link and its label */
public static class MenuItem
{
private final Link link;
private final ListsubMenuItems = new ArrayList ();
public MenuItem(Link link, String label)
{
this.link = link;
this.link.add(new Label(LINK_TEXT_ID, label));
}
/** Add one menu item */
public void addMenu(MenuItem menu)
{
if (!menu.link.getId().equals(LINK_ID))
{
throw new IllegalArgumentException(
"The id must be SuckerfishMenuPanel.LINK_ID");
}
subMenuItems.add(menu);
}
/** Add all menus at once */
public void setMenuItems(ListmenuItems)
{
this.subMenuItems.clear();
for (MenuItem child : menuItems)
{
addMenu(child);
}
}
public Link getLink()
{
return link;
}
public ListgetChildren()
{
return subMenuItems;
}
}
}
SuckerfishMenuPanel.html
<!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"
xmlns:wicket="http://wicket.sourceforge.net/" xml:lang="en" lang="en">
<wicket:head>
<script language="JavaScript" type="text/javascript">
myHover = function() {
var sfEls = document.getElementById("nav").getElementsByTagName("LI");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=" myhover";
}
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp(" myhover\\b"), "");
}
}
}
if (window.attachEvent) window.attachEvent("onload", myHover);
</script>
</wicket:head>
<body>
<wicket:panel>
<ul id="nav">
<li wicket:id="menubarlinks">
<a href="#" wicket:id="linkid"
class="topmenu"><span wicket:id="linktext">Link Text</span></a>
<ul wicket:id="menuitemul">
<li wicket:id="menuitemlinks">
<a href="#" wicket:id="linkid"
class="childmenu"><span wicket:id="linktext">Link Text</span></a>
</li>
</ul>
</li>
</ul>
</wicket:panel>
</body>
</html>
The CSS below is for horizontal menus. It can be changed to accommodate vertical menus. I'm using a background image (gradient.gif). You will either need to supply your own or just use a plain background.
SuckerfishMenuPanel.css
#nav, #nav ul {
float: left;
width: 99.9%;
list-style: none;
line-height: 1;
font-weight: bold;
padding: 0;
margin: 0;
border: 1px solid #3e6581;
background:#BCCDDB
url(/images/gradient.gif)
repeat-x 0% 0%;
}
#nav a {
display: block;
width: 10em;
w\idth: 6em;
color: #7C6240;
text-decoration: none;
padding: 0.25em;
}
#nav a.topmenu {
width: 10em;
text-align: center;
width: auto;
}
#nav a.topmenu span {
color: white;
}
#nav a.childmenu {
width: 13em;
}
#nav a.childmenu span {
color: white;
}
#nav li {
float: left;
padding-left: 0.5em;
padding-right: 0.5em;
padding-top: 0.5em;
padding-bottom: 0.5em;
width: auto;
background:#BCCDDB
url(/images/gradient.gif)
repeat-x 0% 0%;
}
#nav li ul {
position: absolute;
left: -999em;
height: auto;
width: 14.4em;
w\idth: 13.9em;
font-weight: normal;
margin: 0;
}
#nav li li {
padding-right: 1em;
width: 13em
padding-left: 0;
padding-top: 0.25em;
padding-bottom: 0.25em;
}
#nav li ul a {
width: 13em;
w\idth: 9em;
}
#nav li ul ul {
margin: -1.75em 0 0 14em;
}
#nav li:hover ul ul, #nav li:hover ul ul ul, #nav li.myhover ul ul, #nav li.myhover ul ul ul {
left: -999em;
}
#nav li:hover ul, #nav li li:hover ul, #nav li li li:hover ul, #nav li.myhover ul, #nav li li.myhover ul, #nav li li li.myhover ul {
left: auto;
}
#nav li:hover, #nav li.myhover {
background:#C8D7E3
url(/images/gradient-highlighted.gif)
repeat-x;
}
5 comments:
no get method defined for topMenuItems
this would be a great contribution to the wicket stuff project so others could use it!
Suresh, I believe the problem was that you were using Wicket 1.2.6, and I didn't test my code with that version. Sorry about that. But I'm sure it's pretty easy to modify.
Ryan, thanks for the suggestion. It's done!
This is exactly what I need. Where can I download this module?
Nili, see the updated post. The code is available from Wicket Stuff.
Post a Comment