    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.corelib.components;
    014
    015import org.apache.tapestry5.*;
    016import org.apache.tapestry5.annotations.Environmental;
    017import org.apache.tapestry5.annotations.Mixin;
    018import org.apache.tapestry5.annotations.Parameter;
    019import org.apache.tapestry5.corelib.mixins.DiscardBody;
    020import org.apache.tapestry5.corelib.mixins.RenderDisabled;
    021import org.apache.tapestry5.corelib.mixins.RenderInformals;
    022import org.apache.tapestry5.ioc.annotations.Inject;
    023import org.apache.tapestry5.services.ComponentDefaultProvider;
    024import org.apache.tapestry5.services.javascript.JavaScriptSupport;
    025
    026/**
    027 * A radio button (i.e., &lt;input type="radio"&gt;). Radio buttons <strong>must</strong> operate within a
    028 * {@link RadioContainer} (normally, the {@link RadioGroup} component).
    029 *
    030 * If the value parameter is not bound, then the default value is a property of the container component whose name
    031 * matches the Radio component's id.
    032 *
    033 * @tapestrydoc
    034 * @see RadioGroup
    035 * @see Form
    036 * @see Select
    037 */
    038public class Radio implements Field
    039{
    040    @Environmental
    041    private RadioContainer container;
    042
    043    /**
    044     * The user presentable label for the field. If not provided, a reasonable label is generated from the component's
    045     * id, first by looking for a message key named "id-label" (substituting the component's actual id), then by
    046     * converting the actual id to a presentable string (for example, "userId" to "User Id").
    047     */
    048    @Parameter(defaultPrefix = BindingConstants.LITERAL)
    049    private String label;
    050
    051    /**
    052     * The value associated with this radio button. This is used to determine which radio button will be selected when
    053     * the page is rendered, and also becomes the value assigned when the form is submitted.
    054     */
    055    @Parameter(required = true, principal = true, autoconnect = true)
    056    private Object value;
    057
    058    @Inject
    059    private ComponentDefaultProvider defaultProvider;
    060
    061    @Inject
    062    private ComponentResources resources;
    063
    064    @SuppressWarnings("unused")
    065    @Mixin
    066    private RenderInformals renderInformals;
    067
    068    @SuppressWarnings("unused")
    069    @Mixin
    070    private RenderDisabled renderDisabled;
    071
    072    @SuppressWarnings("unused")
    073    @Mixin
    074    private DiscardBody discardBody;
    075
    076    @Inject
    077    private JavaScriptSupport jsSupport;
    078
    079    private String clientId;
    080
    081    private String controlName;
    082
    083    /**
    084     * If true, then the field will render out with a disabled attribute (to turn off client-side behavior). Further, a
    085     * disabled field ignores any value in the request when the form is submitted.
    086     */
    087    @Parameter("false")
    088    private boolean disabled;
    089
    090    String defaultLabel()
    091    {
    092        return defaultProvider.defaultLabel(resources);
    093    }
    094
    095    /**
    096     * Returns the control name provided by the containing {@link org.apache.tapestry5.RadioContainer}.
    097     */
    098    public String getControlName()
    099    {
    100        return controlName;
    101    }
    102
    103    public String getLabel()
    104    {
    105        return label;
    106    }
    107
    108    /**
    109     * Returns true if this component has been expressly disabled (via its disabled parameter), or if the
    110     * {@link RadioContainer container} has been disabled.
    111     */
    112    public boolean isDisabled()
    113    {
    114        return disabled || container.isDisabled();
    115    }
    116
    117    public String getClientId()
    118    {
    119        return clientId;
    120    }
    121
    122    void beginRender(MarkupWriter writer)
    123    {
    124        String value = container.toClient(this.value);
    125
    126        clientId = jsSupport.allocateClientId(resources);
    127        controlName = container.getControlName();
    128
    129        writer.element("input",
    130                "type", "radio",
    131                "id", clientId,
    132                "name", controlName,
    133                "value", value);
    134
    135        if (container.isSelected(this.value))
    136            writer.attributes("checked", "checked");
    137    }
    138
    139    void afterRender(MarkupWriter writer)
    140    {
    141        writer.end();
    142    }
    143
    144    /**
    145     * Returns false; the RadioComponent component does not support declarative field validation.
    146     */
    147    public boolean isRequired()
    148    {
    149        return false;
    150    }
    151}