001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.tags.form; 018 019import javax.servlet.jsp.JspException; 020 021import org.springframework.lang.Nullable; 022import org.springframework.util.Assert; 023import org.springframework.util.StringUtils; 024 025/** 026 * The {@code <label>} tag renders a form field label in an HTML 'label' tag. 027 * 028 * <p>See the "formTags" showcase application that ships with the 029 * full Spring distribution for an example of this class in action. 030 * 031 * <p> 032 * <table> 033 * <caption>Attribute Summary</caption> 034 * <thead> 035 * <tr> 036 * <th class="colFirst">Attribute</th> 037 * <th class="colOne">Required?</th> 038 * <th class="colOne">Runtime Expression?</th> 039 * <th class="colLast">Description</th> 040 * </tr> 041 * </thead> 042 * <tbody> 043 * <tr class="altColor"> 044 * <td><p>cssClass</p></td> 045 * <td><p>false</p></td> 046 * <td><p>true</p></td> 047 * <td><p>HTML Optional Attribute.</p></td> 048 * </tr> 049 * <tr class="rowColor"> 050 * <td><p>cssErrorClass</p></td> 051 * <td><p>false</p></td> 052 * <td><p>true</p></td> 053 * <td><p>HTML Optional Attribute. Used only when errors are present.</p></td> 054 * </tr> 055 * <tr class="altColor"> 056 * <td><p>cssStyle</p></td> 057 * <td><p>false</p></td> 058 * <td><p>true</p></td> 059 * <td><p>HTML Optional Attribute</p></td> 060 * </tr> 061 * <tr class="rowColor"> 062 * <td><p>dir</p></td> 063 * <td><p>false</p></td> 064 * <td><p>true</p></td> 065 * <td><p>HTML Standard Attribute</p></td> 066 * </tr> 067 * <tr class="altColor"> 068 * <td><p>for</p></td> 069 * <td><p>false</p></td> 070 * <td><p>true</p></td> 071 * <td><p>HTML Standard Attribute</p></td> 072 * </tr> 073 * <tr class="rowColor"> 074 * <td><p>htmlEscape</p></td> 075 * <td><p>false</p></td> 076 * <td><p>true</p></td> 077 * <td><p>Enable/disable HTML escaping of rendered values.</p></td> 078 * </tr> 079 * <tr class="altColor"> 080 * <td><p>id</p></td> 081 * <td><p>false</p></td> 082 * <td><p>true</p></td> 083 * <td><p>HTML Standard Attribute</p></td> 084 * </tr> 085 * <tr class="rowColor"> 086 * <td><p>lang</p></td> 087 * <td><p>false</p></td> 088 * <td><p>true</p></td> 089 * <td><p>HTML Standard Attribute</p></td> 090 * </tr> 091 * <tr class="altColor"> 092 * <td><p>onclick</p></td> 093 * <td><p>false</p></td> 094 * <td><p>true</p></td> 095 * <td><p>HTML Event Attribute</p></td> 096 * </tr> 097 * <tr class="rowColor"> 098 * <td><p>ondblclick</p></td> 099 * <td><p>false</p></td> 100 * <td><p>true</p></td> 101 * <td><p>HTML Event Attribute</p></td> 102 * </tr> 103 * <tr class="altColor"> 104 * <td><p>onkeydown</p></td> 105 * <td><p>false</p></td> 106 * <td><p>true</p></td> 107 * <td><p>HTML Event Attribute</p></td> 108 * </tr> 109 * <tr class="rowColor"> 110 * <td><p>onkeypress</p></td> 111 * <td><p>false</p></td> 112 * <td><p>true</p></td> 113 * <td><p>HTML Event Attribute</p></td> 114 * </tr> 115 * <tr class="altColor"> 116 * <td><p>onkeyup</p></td> 117 * <td><p>false</p></td> 118 * <td><p>true</p></td> 119 * <td><p>HTML Event Attribute</p></td> 120 * </tr> 121 * <tr class="rowColor"> 122 * <td><p>onmousedown</p></td> 123 * <td><p>false</p></td> 124 * <td><p>true</p></td> 125 * <td><p>HTML Event Attribute</p></td> 126 * </tr> 127 * <tr class="altColor"> 128 * <td><p>onmousemove</p></td> 129 * <td><p>false</p></td> 130 * <td><p>true</p></td> 131 * <td><p>HTML Event Attribute</p></td> 132 * </tr> 133 * <tr class="rowColor"> 134 * <td><p>onmouseout</p></td> 135 * <td><p>false</p></td> 136 * <td><p>true</p></td> 137 * <td><p>HTML Event Attribute</p></td> 138 * </tr> 139 * <tr class="altColor"> 140 * <td><p>onmouseover</p></td> 141 * <td><p>false</p></td> 142 * <td><p>true</p></td> 143 * <td><p>HTML Event Attribute</p></td> 144 * </tr> 145 * <tr class="rowColor"> 146 * <td><p>onmouseup</p></td> 147 * <td><p>false</p></td> 148 * <td><p>true</p></td> 149 * <td><p>HTML Event Attribute</p></td> 150 * </tr> 151 * <tr class="altColor"> 152 * <td><p>path</p></td> 153 * <td><p>true</p></td> 154 * <td><p>true</p></td> 155 * <td><p>Path to errors object for data binding</p></td> 156 * </tr> 157 * <tr class="rowColor"> 158 * <td><p>tabindex</p></td> 159 * <td><p>false</p></td> 160 * <td><p>true</p></td> 161 * <td><p>HTML Standard Attribute</p></td> 162 * </tr> 163 * <tr class="altColor"> 164 * <td><p>title</p></td> 165 * <td><p>false</p></td> 166 * <td><p>true</p></td> 167 * <td><p>HTML Standard Attribute</p></td> 168 * </tr> 169 * </tbody> 170 * </table> 171 * 172 * @author Rob Harrop 173 * @author Juergen Hoeller 174 * @since 2.0 175 */ 176@SuppressWarnings("serial") 177public class LabelTag extends AbstractHtmlElementTag { 178 179 /** 180 * The HTML '{@code label}' tag. 181 */ 182 private static final String LABEL_TAG = "label"; 183 184 /** 185 * The name of the '{@code for}' attribute. 186 */ 187 private static final String FOR_ATTRIBUTE = "for"; 188 189 190 /** 191 * The {@link TagWriter} instance being used. 192 * <p>Stored so we can close the tag on {@link #doEndTag()}. 193 */ 194 @Nullable 195 private TagWriter tagWriter; 196 197 /** 198 * The value of the '{@code for}' attribute. 199 */ 200 @Nullable 201 private String forId; 202 203 204 /** 205 * Set the value of the '{@code for}' attribute. 206 * <p>Defaults to the value of {@link #getPath}; may be a runtime expression. 207 */ 208 public void setFor(String forId) { 209 this.forId = forId; 210 } 211 212 /** 213 * Get the value of the '{@code id}' attribute. 214 * <p>May be a runtime expression. 215 */ 216 @Nullable 217 protected String getFor() { 218 return this.forId; 219 } 220 221 222 /** 223 * Writes the opening '{@code label}' tag and forces a block tag so 224 * that body content is written correctly. 225 * @return {@link javax.servlet.jsp.tagext.Tag#EVAL_BODY_INCLUDE} 226 */ 227 @Override 228 protected int writeTagContent(TagWriter tagWriter) throws JspException { 229 tagWriter.startTag(LABEL_TAG); 230 tagWriter.writeAttribute(FOR_ATTRIBUTE, resolveFor()); 231 writeDefaultAttributes(tagWriter); 232 tagWriter.forceBlock(); 233 this.tagWriter = tagWriter; 234 return EVAL_BODY_INCLUDE; 235 } 236 237 /** 238 * Overrides {@code #getName()} to always return {@code null}, 239 * because the '{@code name}' attribute is not supported by the 240 * '{@code label}' tag. 241 * @return the value for the HTML '{@code name}' attribute 242 */ 243 @Override 244 @Nullable 245 protected String getName() throws JspException { 246 // This also suppresses the 'id' attribute (which is okay for a <label/>) 247 return null; 248 } 249 250 /** 251 * Determine the '{@code for}' attribute value for this tag, 252 * autogenerating one if none specified. 253 * @see #getFor() 254 * @see #autogenerateFor() 255 */ 256 protected String resolveFor() throws JspException { 257 if (StringUtils.hasText(this.forId)) { 258 return getDisplayString(evaluate(FOR_ATTRIBUTE, this.forId)); 259 } 260 else { 261 return autogenerateFor(); 262 } 263 } 264 265 /** 266 * Autogenerate the '{@code for}' attribute value for this tag. 267 * <p>The default implementation delegates to {@link #getPropertyPath()}, 268 * deleting invalid characters (such as "[" or "]"). 269 */ 270 protected String autogenerateFor() throws JspException { 271 return StringUtils.deleteAny(getPropertyPath(), "[]"); 272 } 273 274 /** 275 * Close the '{@code label}' tag. 276 */ 277 @Override 278 public int doEndTag() throws JspException { 279 Assert.state(this.tagWriter != null, "No TagWriter set"); 280 this.tagWriter.endTag(); 281 return EVAL_PAGE; 282 } 283 284 /** 285 * Disposes of the {@link TagWriter} instance. 286 */ 287 @Override 288 public void doFinally() { 289 super.doFinally(); 290 this.tagWriter = null; 291 } 292 293}