001 // Copyright 2007, 2008, 2010, 2011 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
015 package org.apache.tapestry5.corelib.components;
016
017 import org.apache.tapestry5.BindingConstants;
018 import org.apache.tapestry5.ComponentResources;
019 import org.apache.tapestry5.Field;
020 import org.apache.tapestry5.MarkupWriter;
021 import org.apache.tapestry5.RadioContainer;
022 import org.apache.tapestry5.annotations.Environmental;
023 import org.apache.tapestry5.annotations.Mixin;
024 import org.apache.tapestry5.annotations.Parameter;
025 import org.apache.tapestry5.corelib.mixins.DiscardBody;
026 import org.apache.tapestry5.corelib.mixins.RenderDisabled;
027 import org.apache.tapestry5.corelib.mixins.RenderInformals;
028 import org.apache.tapestry5.ioc.annotations.Inject;
029 import org.apache.tapestry5.services.ComponentDefaultProvider;
030 import org.apache.tapestry5.services.javascript.JavaScriptSupport;
031
032 /**
033 * A radio button (i.e., <input type="radio">). Radio buttons <strong>must</strong> operate within a
034 * {@link RadioContainer} (normally, the {@link RadioGroup} component).
035 * <p/>
036 * If the value parameter is not bound, then the default value is a property of the container component whose name
037 * matches the Radio component's id.
038 *
039 * @tapestrydoc
040 * @see RadioGroup
041 * @see Form
042 * @see Select
043 */
044 public class Radio implements Field
045 {
046 @Environmental
047 private RadioContainer container;
048
049 /**
050 * The user presentable label for the field. If not provided, a reasonable label is generated from the component's
051 * id, first by looking for a message key named "id-label" (substituting the component's actual id), then by
052 * converting the actual id to a presentable string (for example, "userId" to "User Id").
053 */
054 @Parameter(defaultPrefix = BindingConstants.LITERAL)
055 private String label;
056
057 /**
058 * The value associated with this radio button. This is used to determine which radio button will be selected when
059 * the page is rendered, and also becomes the value assigned when the form is submitted.
060 */
061 @Parameter(required = true, principal = true, autoconnect = true)
062 private Object value;
063
064 @Inject
065 private ComponentDefaultProvider defaultProvider;
066
067 @Inject
068 private ComponentResources resources;
069
070 @SuppressWarnings("unused")
071 @Mixin
072 private RenderInformals renderInformals;
073
074 @SuppressWarnings("unused")
075 @Mixin
076 private RenderDisabled renderDisabled;
077
078 @SuppressWarnings("unused")
079 @Mixin
080 private DiscardBody discardBody;
081
082 @Inject
083 private JavaScriptSupport jsSupport;
084
085 private String clientId;
086
087 private String controlName;
088
089 /**
090 * If true, then the field will render out with a disabled attribute (to turn off client-side behavior). Further, a
091 * disabled field ignores any value in the request when the form is submitted.
092 */
093 @Parameter("false")
094 private boolean disabled;
095
096 String defaultLabel()
097 {
098 return defaultProvider.defaultLabel(resources);
099 }
100
101 /**
102 * Returns the control name provided by the containing {@link org.apache.tapestry5.RadioContainer}.
103 */
104 public String getControlName()
105 {
106 return controlName;
107 }
108
109 public String getLabel()
110 {
111 return label;
112 }
113
114 /**
115 * Returns true if this component has been expressly disabled (via its disabled parameter), or if the
116 * {@link RadioContainer container} has been disabled.
117 */
118 public boolean isDisabled()
119 {
120 return disabled || container.isDisabled();
121 }
122
123 public String getClientId()
124 {
125 return clientId;
126 }
127
128 void beginRender(MarkupWriter writer)
129 {
130 String value = container.toClient(this.value);
131
132 clientId = jsSupport.allocateClientId(resources);
133 controlName = container.getControlName();
134
135 writer.element("input", "type", "radio", "id", clientId, "name", controlName, "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 }