Thursday, June 21, 2007

Adding an Ajax hide/show button to a Wicket border

This build on my previous post
A Wicket rounded box border. I am reusing this border component in several places, and I wanted the ability to hide it and all of its contents. Due to licensing restrictions placed on me by my client, I cannot use Dojo or Scriptaculous, which have built-in wiper panels. These weren't quite what I wanted anyway. The Normal example shown below is just a Label, but in reality it would be a complex Panel in its own right. Sample images are below.

Sample usage: Tester.java


package com.my;

import wicket.AttributeModifier;
import wicket.Component;
import wicket.ajax.AjaxRequestTarget;
import wicket.markup.html.WebPage;
import wicket.markup.html.basic.Label;
import wicket.model.AbstractReadOnlyModel;

public class Tester extends WebPage
{
/** Used to toggle visibility */
private static final String STYLE = "style";
private static final String DISPLAYNONE = "display:none";
private boolean display = true;

public Tester()
{
final Label normal = new Label("normal", "Displayed in Normal view");
normal.add(new AttributeModifier(STYLE, true,
new AbstractReadOnlyModel()
{
public Object getObject(Component component)
{
return display ? "" : DISPLAYNONE;
}
}));
normal.setOutputMarkupId(true);

final Label minimized = new Label("minimized",
"Displayed in Minimized view");
minimized.add(new AttributeModifier(STYLE, true,
new AbstractReadOnlyModel()
{
public Object getObject(Component component)
{
// Opposite to normal
return display ? DISPLAYNONE : "";
}
}));
minimized.setOutputMarkupId(true);

RoundedBoxBorder border = new RoundedBoxBorder("border", true)
{
@Override
protected void minimize(AjaxRequestTarget target)
{
target.addComponent(normal);
target.addComponent(minimized);
display = !display;
}
};
border.add(normal);
border.add(minimized);
add(border);
}
}

Sample usage: Tester.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">
<body>
<div wicket:id="border">
<span wicket:id="normal">normal</span>
<span wicket:id="minimized">minimized</span>
</div>
</body>
</html>

RoundedBoxBorder.java


package com.my;

import wicket.ResourceReference;
import wicket.ajax.AjaxRequestTarget;
import wicket.ajax.markup.html.AjaxFallbackLink;
import wicket.behavior.HeaderContributor;
import wicket.markup.html.border.Border;
import wicket.markup.html.image.Image;
import wicket.markup.html.link.Link;

public class RoundedBoxBorder extends Border
{
public RoundedBoxBorder(String id)
{
this(id, false);
}
public RoundedBoxBorder(String id, boolean minimizable)
{
super(id);
add(HeaderContributor.forCss(RoundedBoxBorder.class, "RoundedBoxBorder.css"));

Link l = new AjaxFallbackLink("minimize"){
@Override
public void onClick(AjaxRequestTarget target)
{
minimize(target);
}
};
l.add(new Image("minimizeimg", new ResourceReference(RoundedBoxBorder.class, "minimize.GIF")));
add(l);
l.setVisible(minimizable);
}

/** Subclasses can override to toggle minimization of their contents */
protected void minimize(AjaxRequestTarget arg0)
{
// Default does nothing
}
}

RoundedBoxBorder.html


<html xmlns:wicket="xmlns:wicket">
<body>
<wicket:border>
<div class="roundedBox">
<div class="boxTopLeft">
<div class="boxTopRight">
<a wicket:id="minimize" class="minimize">
<img wicket:id="minimizeimg" class="minimizeimg"/>
</a>
</div>
</div>

<wicket:body/>

<div class="boxBottomLeft">
<div class="boxBottomRight"> </div>
</div>
</div>
</wicket:border>
</body>
</html>

RoundedBoxBorder.css


.roundedBox {
width:98%;
margin-bottom:10px;
background-color: #d6ddee;
}

.boxTopLeft {
background-image:url(/mycontext/images/blue_round_corner_tl.gif);
background-repeat:no-repeat;
height:10px;
overflow:hidden; # IE hack
}

.boxTopRight {
background-image:url(/mycontext/images/blue_round_corner_tr.gif);
background-position:right top;
background-repeat:no-repeat;
height:10px;
}

.boxBottomLeft {
background-image:url(/mycontext/images/blue_round_corner_bl.gif);
background-repeat:no-repeat;
height:10px;
}

.boxBottomRight {
background-image:url(/mycontext/images/blue_round_corner_br.gif);
background-position:right top;
background-repeat:no-repeat;
height:10px;
}

.minimizeimg {
float:right;
margin-right: 10px;
border: none;
}









2 comments:

Nosugref said...

I've been trying to do something similar, but implemented by toggling the isVisible() for the components inside the border. I'll have to try your approach though, because mine is yielding weird behavior. The panel can be minimized, but when maximized, wicket is complaining about the HTML tags being mismatched.

Nosugref said...

Works great. Thanks for the code.
(BTW, getObject(Component c) is now final, so you have to remove the Component param).