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., <input type="radio">). 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}