com.redijedi.tapestry.components.RatingField Maven / Gradle / Ivy
Show all versions of redijedi-t5-components
package com.redijedi.tapestry.components;
import java.util.List;
import org.apache.tapestry.Asset;
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.PageRenderSupport;
import org.apache.tapestry.ValueEncoder;
import org.apache.tapestry.annotations.Component;
import org.apache.tapestry.annotations.Inject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.annotations.Path;
import org.apache.tapestry.annotations.SetupRender;
import org.apache.tapestry.corelib.base.AbstractField;
import org.apache.tapestry.corelib.components.Label;
import org.apache.tapestry.corelib.components.Loop;
import org.apache.tapestry.corelib.components.Radio;
import org.apache.tapestry.corelib.components.RadioGroup;
import org.apache.tapestry.dom.Element;
import org.apache.tapestry.services.Environment;
import org.apache.tapestry.services.FormSupport;
import org.apache.tapestry.util.EnumValueEncoder;
import com.redijedi.tapestry.internal.EnvironmentData;
import com.redijedi.tapestry.internal.GenericValueEncoder;
import com.redijedi.tapestry.internal.InternalUtils;
import com.redijedi.tapestry.internal.LongValueEncoder;
import com.redijedi.tapestry.internal.StringValueEncoder;
/**
* This component provides the ability to associate a RadioGroup and its
* subordinate Radio fields with a set of values displayed as a rating scale.
* This is typified by the "star field" where grayed stars represent the choices
* and highlighted stars represent the chosen value and all values up to the
* chosen value from left to right.
*
* This is in fact that default visual appearance. However, the images can be
* overridden via parameters and the entire component can, of course, be styled
* via CSS.
*
* As an added benefit, since the underlying representation is simply a
* RadioGroup with Radio fields it should degrade well when JS and/or CSS is
* disabled. This should keep the component rather accessible.
*
* By default the first value display image will be hidden as this typically
* will indicate no value.
*
* @author torr
*
*/
public class RatingField extends AbstractField {
@Parameter(value = "prop:componentResources.id", defaultPrefix = "literal")
private String _id;
@Parameter(required = true)
private T _value;
@Parameter(required = true)
private Object _source;
private List extends Object> _listSource;
@Parameter
private ValueEncoder> _encoder;
@Parameter(required = false)
private Asset _selectedImage;
@Parameter(required = false)
private Asset _unselectedImage;
@Inject
private Environment _environment;
@Inject
private PageRenderSupport _pageRenderSupport;
@Inject
@Path("rating.css")
private Asset _styleSheet;
@Inject
@Path("rating_default_selected.gif")
private Asset _defaultSelectedImage;
@Inject
@Path("rating_default_unselected.gif")
private Asset _defaultUnselectedImage;
@SuppressWarnings("unused")
@Component(parameters = { "value=prop:value", "encoder=encoder" })
private RadioGroup _radioGroup;
@SuppressWarnings("unused")
@Component(parameters = { "source=prop:source", "value=loopValue" })
private Loop _loop;
private T _loopValue;
@SuppressWarnings("unused")
@Component(parameters = { "value=loopValue", "label=prop:radioLabel" })
private Radio _radio;
@SuppressWarnings("unused")
@Component(parameters = { "for=radio" })
private Label _label;
@Inject
@Path("rating.js")
private Asset _ratingScript;
/**
* Returns the component's ID.
*
* @return
*/
public String getId() {
return _id;
}
public T getValue() {
return _value;
}
public void setValue(T value) {
_value = value;
}
/**
* Returns the image representing an unselected value.
*
* @return
*/
public Asset getUnselectedImage() {
if (_unselectedImage == null) {
return _defaultUnselectedImage;
} else {
return _unselectedImage;
}
}
/**
* Returns the image representing a selected value.
*
* @return
*/
public Asset getSelectedImage() {
if (_selectedImage == null) {
return _defaultSelectedImage;
} else {
return _selectedImage;
}
}
/**
* Returns an appropriate ValueEncoder implementation based on the value
* type.
*
* @return
*/
@SuppressWarnings("unchecked")
public ValueEncoder> getEncoder() {
if (_encoder != null) {
return _encoder;
}
if (getValue() instanceof Long) {
return new LongValueEncoder();
} else if (getValue() instanceof Enum) {
return new EnumValueEncoder(getValue().getClass());
} else if (getValue() instanceof String) {
return new StringValueEncoder();
} else {
return new GenericValueEncoder(getSource());
}
}
/**
* Returns a reasonable label for the radio value. If the value is primitive
* it will be returned as is. Otherwise the toString() method will be called
* on the value object.
*
* @return
*/
public String getRadioLabel() {
return _loopValue.toString();
}
/**
* Getter for the loop iteration's value.
*
* @return
*/
public Object getLoopValue() {
return _loopValue;
}
/**
* Setter for the loop iteration's value.
*/
public void setLoopValue(T loopValue) {
_loopValue = loopValue;
}
/**
* Returns an Iterable implementation of the source provided.
*
* @return
*/
public List extends Object> getSource() {
return _listSource;
}
/*
* Event listeners
*/
/**
* Manages adding the correct JS includes into the page head section as well
* as initializing the source, etc.
*/
@SetupRender
void setupComponent(MarkupWriter writer) {
if (!getIsHeadWritten()) {
Element head = writer.getDocument().find("html/head");
// NOTE rating.js has to be included after prototype so it has to
// use PageRenderSupport
// head.element("script", "type", "text/javascript", "src",
// _ratingScript.toClientURL());
_pageRenderSupport.addScriptLink(_ratingScript);
head.element("link", "type", "text/css", "href", _styleSheet
.toClientURL(), "rel", "stylesheet");
setIsHeadWritten(true);
}
initSource();
}
/*
* (non-Javadoc)
*
* @see org.apache.tapestry.corelib.base.AbstractField#processSubmission(org.apache.tapestry.services.FormSupport,
* java.lang.String)
*/
@Override
protected void processSubmission(FormSupport arg0, String arg1) {
initSource();
}
@SuppressWarnings("unchecked")
private boolean getIsHeadWritten() {
// see if the head content has been set yet
EnvironmentData data = _environment.peek(EnvironmentData.class);
if (data == null) {
return false;
}
if (data.containsKey("isRatingHeadSet")) {
return (Boolean) data.get("isRatingHeadSet");
} else {
return false;
}
}
@SuppressWarnings("unchecked")
private void setIsHeadWritten(Boolean written) {
// see if the head content has been set yet
EnvironmentData data = _environment.peek(EnvironmentData.class);
if (data == null) {
data = new EnvironmentData();
}
data.put("isRatingHeadSet", written);
_environment.push(EnvironmentData.class, data);
}
private void initSource() {
if (_source instanceof String) {
String stringSource = (String) _source;
_listSource = InternalUtils
.convertStringToListOfStrings(stringSource);
} else if (_source != null && _source.getClass().isArray()) {
_listSource = InternalUtils
.convertArrayToListOfObjects((Object[]) _source);
}
}
}