/* Copyright 2005-2006 Tim Fennell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.stripes.tag;
import net.sourceforge.stripes.exception.StripesJspException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTag;
import java.io.IOException;
import net.sourceforge.stripes.localization.LocalizationUtility;
/**
* <p>Tag handler for a tag that produces an HTML label tag which is capable of looking up
* localized field names and formatting the label when validation errors exist. The field being
* labeled is identified using either the {@code name} attribute (preferred) or the
* {@code for} attribute. If the {@code name} attribute is supplied this will always be used as
* the lookup key (optionally pre-pended with the form's action path). If the {@code name} field
* is not supplied, the tag will fall back to using the value supplied for the {@code for}
* attribute. This is done because the {@code for} attribute is used by HTML as a reference to the
* {@code id} of the input being labeled. In the case where the id is equal to the field name
* it is unnecessary to specify a {@code name} attribute for the label tag. In cases where the
* field name (or other localized resource name) does not match an HTML ID, the {@code name}
* attribute must be used.</p>
*
* <p>The value used for the label is the localized field name if one exists. Localized field
* names are looked up in the field name resource bundle first using {@code formActionPath.fieldName},
* and then (if no value is found) using just {@code fieldName}. If no localized String can be found
* then the body of the label tag is used. If no body is supplied then a warning String will be used
* instead!</p>
*
* @author Tim Fennell
* @since Stripes 1.1
*/
public class InputLabelTag extends InputTagSupport implements BodyTag {
private boolean nameSet;
/** Sets the HTML ID of the field for which this is a label. */
public void setFor(String forId) {
set("for", forId);
// If the name field isn't set yet, set it with the forId.
if (!nameSet) {
super.setName(forId);
}
}
/** Gets the HTML ID of the field for which this is a label. */
public String getFor() { return get("for"); }
/**
* Sets the name of the form element/label to be rendered. Should only be invoked by
* the JSP container as it also tracks whether or not the container has set the name, in
* order to correctly handle pooling.
*/
@Override
public void setName(String name) {
super.setName(name);
this.nameSet = true;
}
/**
* Does nothing.
* @return EVAL_BODY_BUFFERED in all cases.
*/
@Override
public int doStartInputTag() throws JspException {
return EVAL_BODY_BUFFERED;
}
/** Does nothing. */
public void doInitBody() throws JspException { /** Do Nothing */ }
/**
* Does nothing.
* @return SKIP_BODY in all cases.
*/
public int doAfterBody() throws JspException {
return SKIP_BODY;
}
/**
* Performs the main work of the tag as described in the class level javadoc.
* @return EVAL_PAGE in all cases.
* @throws JspException if an IOException is encountered writing to the output stream.
*/
@Override
public int doEndInputTag() throws JspException {
try {
String label = getLocalizedFieldName();
String fieldName = getAttributes().remove("name");
if (label == null) {
label = getBodyContentAsString();
}
if (label == null) {
if (fieldName != null) {
label = LocalizationUtility.makePseudoFriendlyName(fieldName);
}
else {
label = "Label could not find localized field name and had no body nor name attribute.";
}
}
// Write out the tag
writeOpenTag(getPageContext().getOut(), "label");
getPageContext().getOut().write(label);
writeCloseTag(getPageContext().getOut(), "label");
// Reset the field name so as to not screw up tag pooling
if (this.nameSet) {
super.setName(fieldName);
}
return EVAL_PAGE;
}
catch (IOException ioe) {
throw new StripesJspException("Encountered an exception while trying to write to " +
"the output from the stripes:label tag handler class, InputLabelTag.", ioe);
}
}
/** Overridden to do nothing, since a label isn't really a form field. */
@Override
protected void registerWithParentForm() throws StripesJspException { }
/**
* Wraps the parent loadErrors() to suppress exceptions when the label is outside of a
* stripes form tag.
*/
@Override
protected void loadErrors() {
try {
super.loadErrors();
}
catch (StripesJspException sje) {
// Do nothing, we're suppressing this error
}
}
}