DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
this is another example like : Tapestry5HowToAddBindingPrefix
This binding prefix will return different value for each call, and we will use it for zebra effect on grid or any other loop.
First let's see usage example:
<t:grid .... rowClass="cycle:line1,line2">
...
</t:grid>
or any loop
<t:loop ...>
<div class="${cycle:line1,line2}">aaaa</div>
</tloop>
but not separately:
<div class="${cycle:line1,line2}">aaaa</div>
<div class="${cycle:line1,line2}">aaaa</div>
<div class="${cycle:line1,line2}">aaaa</div>
that is it, no need for counter, and counter % 2 and stuff..
To make it work you have to tell tapestry about the "cycle:" binding prefix. So, add following to your module:
public static void contributeBindingSource(
MappedConfiguration<String, BindingFactory> configuration,
BindingSource bindingSource
)
{
configuration.add("cycle",new CycleBindingFactory(bindingSource));
}
And you'll need the implementation:
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry5.Binding;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.ioc.Location;
import org.apache.tapestry5.services.BindingFactory;
import org.apache.tapestry5.services.BindingSource;
/**
* Implementation of the cycle: binding prefix -- we parse list of bindings
* and generate delegate bindings for each element<br>
* default binding is literal, other bindings can be used by specifying prefix.<br>
* example: "cycle:prop:name,prop:lastName,sth,sth else"
*/
public class CycleBindingFactory implements BindingFactory {
private final BindingSource _bindingSource;
public CycleBindingFactory(BindingSource source){
this._bindingSource = source;
}
public Binding newBinding(String description, ComponentResources container, ComponentResources component,
String expression, Location location)
{
List<Binding> delegates = new ArrayList<Binding>();
String[] bindingNames = expression.split(",");
for (String bindingName : bindingNames){
String defaultBinding = BindingConstants.LITERAL;
Binding binding = _bindingSource.newBinding(description, container, component, defaultBinding, bindingName, location);
delegates.add(binding);
}
CycleBinding cycleBinding = new CycleBinding(delegates);
container.addPageLifecycleListener(cycleBinding);
return cycleBinding;
}
}
And the binding itself:
Note: that starting with Tapestry 5.2 PageBindings do not appear to be thread safe when running without page pools. So now we store the index in a ThreadLocal which works around this upgrade issue. (The previous version simply used an int for the index instead of a ThreadLocal).
import java.util.List;
import org.apache.tapestry5.Binding;
import org.apache.tapestry5.internal.bindings.AbstractBinding;
import org.apache.tapestry5.runtime.PageLifecycleListener;
public class CycleBinding extends AbstractBinding implements PageLifecycleListener{
private final List<Binding> delegates;
private ThreadLocal<Integer> index;
public CycleBinding(List<Binding> delegates) {
this.delegates = delegates;
}
public Object get() {
Object ret = delegates.get(getIndex()).get();
incrIndex();
return ret;
}
@Override
public boolean isInvariant() {
return false;
}
@Override
public Class<Object> getBindingType() {
return Object.class;
}
public void containingPageDidDetach() {
index.remove();
}
public void containingPageDidAttach() {
index = createThreadLocal();
}
public void containingPageDidLoad() {}
public void restoreStateBeforePageAttach() {}
private ThreadLocal<Integer> createThreadLocal() {
return new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return Integer.valueOf(0);
};
};
}
private int getIndex() {
return index.get().intValue();
}
private void incrIndex() {
int i = index.get().intValue() + 1;
if (i >= delegates.size()) {
i = 0;
}
index.set(Integer.valueOf(i));
}
}