/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. * * $Header:$ */ package org.apache.beehive.netui.tags.html; import org.apache.beehive.netui.pageflow.ProcessPopulate; import org.apache.beehive.netui.pageflow.RequestParameterHandler; import org.apache.beehive.netui.tags.ByRef; import org.apache.beehive.netui.tags.IHtmlAccessable; import org.apache.beehive.netui.tags.naming.FormDataNameInterceptor; import org.apache.beehive.netui.tags.naming.IndexedNameInterceptor; import org.apache.beehive.netui.tags.naming.PrefixNameInterceptor; import org.apache.beehive.netui.tags.rendering.*; import org.apache.beehive.netui.util.Bundle; import org.apache.beehive.netui.util.logging.Logger; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Generates a checkbox which binds to a form bean property or databound expression. * CheckBox should be used on its own and not within a CheckBoxGroup. CheckBox ignores its * body content. * * CheckBoxes can bind to boolean, Boolean, and Strings. * @jsptagref.tagdescription
Generates a single HTML checkbox. The <netui:checkBox> tag should be used on its own, not within a * {@link CheckBoxGroup}. * *
The <netui:checkBox> tag can be data bound to a boolean or Boolean type. For instance, * the following <netui:checkBox> tag... * *
<netui:checkBox dataSource="actionForm.checkBoxValue"/>* * ...must be bound to a boolean or Boolean field in the Form Bean... * *
public static class ProcessDataForm extends FormData * { * private boolean checkBoxValue; * * public void setCheckBoxValue(boolean checkBoxValue) * { * this.checkBoxValue = checkBoxValue; * } * * public boolean isCheckBoxValue() * { * return this.checkBoxValue; * } * }* @example In this sample, the <netui:checkBox reads it initial value from the * Form Bean field
wantSpecialOffers
. Upon submission, the user specified value is
* loaded into the same Form Bean field. The data is submitted to the
* action method processData
.
* <netui:form action="processData"> * Do you want to be notified of special offers? * <netui:checkBox dataSource="actionForm.wantsSpecialOffers"/><br> * <netui:button value="Submit" type="submit"/> * </netui:form>* @netui:tag name="checkBox" description="Generates a checkbox that binds to a form bean property or databound expression." */ public class CheckBox extends HtmlDefaultableDataSourceTag implements IHtmlAccessable { private static final Logger logger = Logger.getInstance(CheckBox.class); private InputBooleanTag.State _state = new InputBooleanTag.State(); private InputHiddenTag.State _hiddenState = new InputHiddenTag.State(); private static final String CHECKBOX_KEY = "checkbox_key"; private static final String OLDVALUE_SUFFIX = "OldValue"; private static final List _internalNamingChain; static { List l = new ArrayList(3); l.add(new FormDataNameInterceptor()); l.add(new IndexedNameInterceptor()); l.add(new PrefixNameInterceptor(CHECKBOX_KEY)); _internalNamingChain = Collections.unmodifiableList(l); } static { org.apache.beehive.netui.pageflow.ProcessPopulate.registerPrefixHandler(CHECKBOX_KEY, new CheckBoxPrefixHandler()); } /** * The handler for naming and indexing the CheckBox. */ public static class CheckBoxPrefixHandler implements RequestParameterHandler { /** * Determines the current state of the CheckBox (true or false) based on the Request. */ public void process(HttpServletRequest request, String key, String expr, ProcessPopulate.ExpressionUpdateNode node) { String returnVal = null; if (!key.endsWith(OLDVALUE_SUFFIX)) { //This checkbox is true and should stay that way returnVal = "true"; } else { //Check the request to see if checkBox also exists String newKey = key.substring(0, key.indexOf(OLDVALUE_SUFFIX)); String checkBox = request.getParameter(newKey); if (checkBox != null) { returnVal = "true"; } else { returnVal = "false"; } } if (node.expression.endsWith(OLDVALUE_SUFFIX)) { node.expression = node.expression.substring(0, node.expression.indexOf(OLDVALUE_SUFFIX)); } node.values = new String[]{returnVal}; if (logger.isDebugEnabled()) { logger.debug("*********************************************\n" + "process with key \"" + key + "\" and expression \"" + node.expression + "\"" + "and result: " + returnVal + "\n" + "*********************************************\n"); } } } public CheckBox() { super(); } /** * Return the name of the Tag. */ public String getTagName() { return "CheckBox"; } /** * Base support for the attribute tag. This is overridden to prevent setting the
type
,
* checked
and value
attributes.
* @param name The name of the attribute. This value may not be null or the empty string.
* @param value The value of the attribute. This may contain an expression.
* @param facet The name of a facet to which the attribute will be applied. This is optional.
* @throws JspException A JspException may be thrown if there is an error setting the attribute.
*/
public void setAttribute(String name, String value, String facet)
throws JspException
{
if (name != null) {
if (name.equals(TYPE) || name.equals(VALUE) || name.equals(CHECKED)) {
String s = Bundle.getString("Tags_AttributeMayNotBeSet", new Object[]{name});
registerTagError(s, null);
}
else {
if (name.equals(DISABLED)) {
setDisabled(Boolean.parseBoolean(value));
return;
}
}
}
super.setAttribute(name, value, facet);
}
/**
* This method will return the state associated with the tag. This is used by this
* base class to access the individual state objects created by the tags.
* @return a subclass of the AbstractHtmlState
class.
*/
protected AbstractHtmlState getState()
{
return _state;
}
/**
* Return an ArrayList
which represents a chain of INameInterceptor
* objects. This method by default returns null
and should be overridden
* by objects that support naming.
* @return an ArrayList
that will contain INameInterceptor
objects.
*/
protected List getNamingChain()
{
return _internalNamingChain;
}
/**
* @return A boolean value.
*/
private boolean evaluateDefaultValue()
{
if (_defaultValue instanceof String)
return Boolean.valueOf((String) _defaultValue).booleanValue();
if (_defaultValue instanceof Boolean)
return ((Boolean) _defaultValue).booleanValue();
return false;
}
/**
* Render the checkbox.
* @throws JspException if a JSP exception has occurred
*/
public int doStartTag() throws JspException
{
// evaluate the body so that we can set the attributes
return EVAL_BODY_BUFFERED;
}
/**
* Save the body content of the checkbox.
* @throws JspException if a JSP exception has occurred
*/
public int doAfterBody() throws JspException
{
return SKIP_BODY;
}
/**
* Render the checkbox.
* @throws JspException if a JSP exception has occurred
*/
public int doEndTag() throws JspException
{
Tag parent = getParent();
if (parent instanceof CheckBoxGroup)
registerTagError(Bundle.getString("Tags_CheckBoxGroupChildError"), null);
Object val = evaluateDataSource();
if (hasErrors())
return reportAndExit(EVAL_PAGE);
ByRef ref = new ByRef();
nameHtmlControl(_state, ref);
String hiddenParamName = _state.name + OLDVALUE_SUFFIX;
ServletRequest req = pageContext.getRequest();
if (val instanceof String) {
if (val != null && Boolean.valueOf(val.toString()).booleanValue())
_state.checked = true;
else
_state.checked = false;
}
else if (val instanceof Boolean) {
_state.checked = ((Boolean) val).booleanValue();
}
else {
String oldCheckBoxValue = req.getParameter(hiddenParamName);
if (oldCheckBoxValue != null) {
_state.checked = new Boolean(oldCheckBoxValue).booleanValue();
}
else {
_state.checked = evaluateDefaultValue();
}
}
_state.disabled = isDisabled();
//Create a hidden field to store the CheckBox oldValue
String oldValue = req.getParameter(_state.name);
WriteRenderAppender writer = new WriteRenderAppender(pageContext);
// if the checkbox is disabled we need to not write out the hidden
// field because it can cause the default state to change from
// true to false. Disabled check boxes do not postback.
if (!_state.disabled) {
_hiddenState.name = hiddenParamName;
if (oldValue == null) {
_hiddenState.value = "false";
}
else {
_hiddenState.value = oldValue;
}
TagRenderingBase hiddenTag = TagRenderingBase.Factory.getRendering(TagRenderingBase.INPUT_HIDDEN_TAG, req);
hiddenTag.doStartTag(writer, _hiddenState);
hiddenTag.doEndTag(writer);
}
_state.type = INPUT_CHECKBOX;
TagRenderingBase br = TagRenderingBase.Factory.getRendering(TagRenderingBase.INPUT_BOOLEAN_TAG, req);
br.doStartTag(writer, _state);
if (!ref.isNull())
write((String) ref.getRef());
// Continue processing this page
localRelease();
return EVAL_PAGE;
}
/**
* Release any acquired resources.
*/
protected void localRelease()
{
super.localRelease();
_state.clear();
_hiddenState.clear();
}
/* ==================================================================
*
* This tag's publically exposed HTML, CSS, and JavaScript attributes
*
* ==================================================================
*/
/**
* Sets the accessKey attribute value. This should key value of the
* keyboard navigation key. It is recommended not to use the following
* values because there are often used by browsers A, C, E, F, G,
* H, V, left arrow, and right arrow
.
* @param accessKey the accessKey value.
* @jsptagref.attributedescription The keyboard navigation key for the element.
* The following values are not recommended because they
* are often used by browsers: A, C, E, F, G,
* H, V, left arrow, and right arrow
* @jsptagref.databindable false
* @jsptagref.attributesyntaxvalue string_accessKey
* @netui:attribute required="false" rtexprvalue="true" type="char"
* description="The keyboard navigation key for the element.
* The following values are not recommended because they
* are often used by browsers: A, C, E, F, G,
* H, V, left arrow, and right arrow"
*/
public void setAccessKey(char accessKey)
{
if (accessKey == 0x00)
return;
_state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ACCESSKEY, Character.toString(accessKey));
}
/**
* Sets the alt attribute value.
* @param alt the alt value.
* @jsptagref.attributedescription The alt attribute of the element.
* @jsptagref.databindable Read Only
* @jsptagref.attributesyntaxvalue string_alt
* @netui:attribute required="false" rtexprvalue="true"
* description="The alt attribute of the element."
*/
public void setAlt(String alt)
{
_state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, alt);
}
/**
* Sets the tabIndex of the rendered html tag.
* @param tabindex the tab index.
* @jsptagref.attributedescription The tabIndex of the rendered HTML tag. This attribute determines the position of the
* tag in the sequence of page elements that the user may advance through by pressing the TAB key.
* @jsptagref.databindable false
* @jsptagref.attributesyntaxvalue string_tabIndex
* @netui:attribute required="false" rtexprvalue="true" type="int"
* description="The tabIndex of the rendered HTML tag. This attribute determines the position of the
* tag in the sequence of page elements that the user may advance through by pressing the TAB key."
*/
public void setTabindex(int tabindex)
{
_state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TABINDEX, Integer.toString(tabindex));
}
}