/* 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 net.sourceforge.stripes.util.HtmlUtil; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTag; import java.io.IOException; /** * <p>Generates an {@literal <option value="foo">Fooey</option>} HTML tag. Coordinates with an * enclosing select tag to determine its state (i.e. whether or not it is selected.) As a result * some of the logic regarding state repopulation is a bit complex.</p> * * <p>Since options can have only a single value per option the value attribute of the tag * must be a scalar, which will be converted into a String using a Formatter if an * appropriate one can be found, otherwise the toString() method will be invoked. The presence of * a "selected" attribute is used as an indication that this option believes it should be selected * by default - the value (as opposed to the presence) of the selected attribute is never used....</p> * * <p>The option tag delegates to its enclosing select tag to determine whether or not it should * be selected. See the {@link InputSelectTag "select tag"} for documentation on how it * determines selection status. If the select tag <em>has no opinion</em> on selection state * (note that this is not the same as select tag deeming the option should not be selected) then * the presence of the selected attribute (or lack thereof) is used to turn selection on or off.</p> * * <p>If the option has a body then the String value of that body will be used to generate the * body of the generated HTML option. If the body is empty or not present then the label attribute * will be written into the body of the tag.</p> * * @author Tim Fennell */ public class InputOptionTag extends InputTagSupport implements BodyTag { private String selected; private String label; private Object value; /** Sets the value of this option. */ public void setValue(Object value) { this.value = value; } /** Returns the value of the option as set with setValue(). */ public Object getValue() { return this.value; } /** Sets the label that will be used as the option body if no body is supplied. */ public void setLabel(String label) { this.label = label; } /** Returns the value set with setLabel(). */ public String getLabel() { return this.label; } /** Sets whether or not this option believes it should be selected by default. */ public void setSelected(String selected) { this.selected = selected; } /** Returns the value set with setSelected(). */ public String getSelected() { return this.selected; } /** * 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 { } /** * Does nothing. * @return SKIP_BODY in all cases. */ public int doAfterBody() throws JspException { return SKIP_BODY; } /** * Locates the option's parent select tag, determines selection state and then writes out * an option tag with an appropriate body. * * @return EVAL_PAGE in all cases. * @throws JspException if the option is not contained inside an InputSelectTag or output * cannot be written. */ @Override public int doEndInputTag() throws JspException { // Find our mandatory enclosing select tag InputSelectTag selectTag = getParentTag(InputSelectTag.class); if (selectTag == null) { throw new StripesJspException ("Option tags must always be contained inside a select tag."); } // Decide if the label will come from the body of the option, of the label attr String actualLabel = getBodyContentAsString(); if (actualLabel == null) { actualLabel = HtmlUtil.encode(this.label); } // If no explicit value attribute set, use the tag label as the value Object actualValue; if (this.value == null) { actualValue = actualLabel; } else { actualValue = this.value; } getAttributes().put("value", format(actualValue)); // Determine if the option should be selected if (selectTag.isOptionSelected(actualValue, (this.selected != null))) { getAttributes().put("selected", "selected"); } // And finally write the tag out to the page try { writeOpenTag(getPageContext().getOut(), "option"); if (actualLabel != null) { getPageContext().getOut().write(actualLabel); } writeCloseTag(getPageContext().getOut(), "option"); // Clean out the attributes we modified getAttributes().remove("selected"); getAttributes().remove("value"); } catch (IOException ioe) { throw new JspException("IOException in InputOptionTag.doEndTag().", ioe); } return EVAL_PAGE; } /** * Overridden to make sure that options do not try and register themselves with * the form tag. This is done because options are not standalone input tags, but * always part of a select tag (which gets registered). */ @Override protected void registerWithParentForm() throws StripesJspException { // Do nothing, options are not standalone fields and should not register } }