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