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