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 java.util.Map;
020
021import javax.servlet.jsp.JspException;
022
023import org.springframework.lang.Nullable;
024
025/**
026 * The {@code <input>} tag renders an HTML 'input' tag with type 'text' using
027 * the bound value.
028 *
029 * <p>
030 * <table>
031 * <caption>Attribute Summary</caption>
032 * <thead>
033 * <tr>
034 * <th class="colFirst">Attribute</th>
035 * <th class="colOne">Required?</th>
036 * <th class="colOne">Runtime Expression?</th>
037 * <th class="colLast">Description</th>
038 * </tr>
039 * </thead>
040 * <tbody>
041 * <tr class="altColor">
042 * <td><p>accesskey</p></td>
043 * <td><p>false</p></td>
044 * <td><p>true</p></td>
045 * <td><p>HTML Standard Attribute</p></td>
046 * </tr>
047 * <tr class="rowColor">
048 * <td><p>alt</p></td>
049 * <td><p>false</p></td>
050 * <td><p>true</p></td>
051 * <td><p>HTML Optional Attribute</p></td>
052 * </tr>
053 * <tr class="altColor">
054 * <td><p>autocomplete</p></td>
055 * <td><p>false</p></td>
056 * <td><p>true</p></td>
057 * <td><p>Common Optional Attribute</p></td>
058 * </tr>
059 * <tr class="rowColor">
060 * <td><p>cssClass</p></td>
061 * <td><p>false</p></td>
062 * <td><p>true</p></td>
063 * <td><p>HTML Optional Attribute</p></td>
064 * </tr>
065 * <tr class="altColor">
066 * <td><p>cssErrorClass</p></td>
067 * <td><p>false</p></td>
068 * <td><p>true</p></td>
069 * <td><p>HTML Optional Attribute. Used when the bound field has errors.</p></td>
070 * </tr>
071 * <tr class="rowColor">
072 * <td><p>cssStyle</p></td>
073 * <td><p>false</p></td>
074 * <td><p>true</p></td>
075 * <td><p>HTML Optional Attribute</p></td>
076 * </tr>
077 * <tr class="altColor">
078 * <td><p>dir</p></td>
079 * <td><p>false</p></td>
080 * <td><p>true</p></td>
081 * <td><p>HTML Standard Attribute</p></td>
082 * </tr>
083 * <tr class="rowColor">
084 * <td><p>disabled</p></td>
085 * <td><p>false</p></td>
086 * <td><p>true</p></td>
087 * <td><p>HTML Optional Attribute. Setting the value of this attribute to
088 * 'true' will disable the HTML element.</p></td>
089 * </tr>
090 * <tr class="altColor">
091 * <td><p>htmlEscape</p></td>
092 * <td><p>false</p></td>
093 * <td><p>true</p></td>
094 * <td><p>Enable/disable HTML escaping of rendered values.</p></td>
095 * </tr>
096 * <tr class="rowColor">
097 * <td><p>id</p></td>
098 * <td><p>false</p></td>
099 * <td><p>true</p></td>
100 * <td><p>HTML Standard Attribute</p></td>
101 * </tr>
102 * <tr class="altColor">
103 * <td><p>lang</p></td>
104 * <td><p>false</p></td>
105 * <td><p>true</p></td>
106 * <td><p>HTML Standard Attribute</p></td>
107 * </tr>
108 * <tr class="rowColor">
109 * <td><p>maxlength</p></td>
110 * <td><p>false</p></td>
111 * <td><p>true</p></td>
112 * <td><p>HTML Optional Attribute</p></td>
113 * </tr>
114 * <tr class="altColor">
115 * <td><p>onblur</p></td>
116 * <td><p>false</p></td>
117 * <td><p>true</p></td>
118 * <td><p>HTML Event Attribute</p></td>
119 * </tr>
120 * <tr class="rowColor">
121 * <td><p>onchange</p></td>
122 * <td><p>false</p></td>
123 * <td><p>true</p></td>
124 * <td><p>HTML Event Attribute</p></td>
125 * </tr>
126 * <tr class="altColor">
127 * <td><p>onclick</p></td>
128 * <td><p>false</p></td>
129 * <td><p>true</p></td>
130 * <td><p>HTML Event Attribute</p></td>
131 * </tr>
132 * <tr class="rowColor">
133 * <td><p>ondblclick</p></td>
134 * <td><p>false</p></td>
135 * <td><p>true</p></td>
136 * <td><p>HTML Event Attribute</p></td>
137 * </tr>
138 * <tr class="altColor">
139 * <td><p>onfocus</p></td>
140 * <td><p>false</p></td>
141 * <td><p>true</p></td>
142 * <td><p>HTML Event Attribute</p></td>
143 * </tr>
144 * <tr class="rowColor">
145 * <td><p>onkeydown</p></td>
146 * <td><p>false</p></td>
147 * <td><p>true</p></td>
148 * <td><p>HTML Event Attribute</p></td>
149 * </tr>
150 * <tr class="altColor">
151 * <td><p>onkeypress</p></td>
152 * <td><p>false</p></td>
153 * <td><p>true</p></td>
154 * <td><p>HTML Event Attribute</p></td>
155 * </tr>
156 * <tr class="rowColor">
157 * <td><p>onkeyup</p></td>
158 * <td><p>false</p></td>
159 * <td><p>true</p></td>
160 * <td><p>HTML Event Attribute</p></td>
161 * </tr>
162 * <tr class="altColor">
163 * <td><p>onmousedown</p></td>
164 * <td><p>false</p></td>
165 * <td><p>true</p></td>
166 * <td><p>HTML Event Attribute</p></td>
167 * </tr>
168 * <tr class="rowColor">
169 * <td><p>onmousemove</p></td>
170 * <td><p>false</p></td>
171 * <td><p>true</p></td>
172 * <td><p>HTML Event Attribute</p></td>
173 * </tr>
174 * <tr class="altColor">
175 * <td><p>onmouseout</p></td>
176 * <td><p>false</p></td>
177 * <td><p>true</p></td>
178 * <td><p>HTML Event Attribute</p></td>
179 * </tr>
180 * <tr class="rowColor">
181 * <td><p>onmouseover</p></td>
182 * <td><p>false</p></td>
183 * <td><p>true</p></td>
184 * <td><p>HTML Event Attribute</p></td>
185 * </tr>
186 * <tr class="altColor">
187 * <td><p>onmouseup</p></td>
188 * <td><p>false</p></td>
189 * <td><p>true</p></td>
190 * <td><p>HTML Event Attribute</p></td>
191 * </tr>
192 * <tr class="rowColor">
193 * <td><p>onselect</p></td>
194 * <td><p>false</p></td>
195 * <td><p>true</p></td>
196 * <td><p>HTML Event Attribute</p></td>
197 * </tr>
198 * <tr class="altColor">
199 * <td><p>path</p></td>
200 * <td><p>true</p></td>
201 * <td><p>true</p></td>
202 * <td><p>Path to property for data binding</p></td>
203 * </tr>
204 * <tr class="rowColor">
205 * <td><p>readonly</p></td>
206 * <td><p>false</p></td>
207 * <td><p>true</p></td>
208 * <td><p>HTML Optional Attribute. Setting the value of this attribute to
209 * 'true' will make the HTML element readonly.</p></td>
210 * </tr>
211 * <tr class="altColor">
212 * <td><p>size</p></td>
213 * <td><p>false</p></td>
214 * <td><p>true</p></td>
215 * <td><p>HTML Optional Attribute</p></td>
216 * </tr>
217 * <tr class="rowColor">
218 * <td><p>tabindex</p></td>
219 * <td><p>false</p></td>
220 * <td><p>true</p></td>
221 * <td><p>HTML Standard Attribute</p></td>
222 * </tr>
223 * <tr class="altColor">
224 * <td><p>title</p></td>
225 * <td><p>false</p></td>
226 * <td><p>true</p></td>
227 * <td><p>HTML Standard Attribute</p></td>
228 * </tr>
229 * </tbody>
230 * </table>
231 *
232 * @author Rob Harrop
233 * @author Juergen Hoeller
234 * @author Rossen Stoyanchev
235 * @since 2.0
236 */
237@SuppressWarnings("serial")
238public class InputTag extends AbstractHtmlInputElementTag {
239
240        public static final String SIZE_ATTRIBUTE = "size";
241
242        public static final String MAXLENGTH_ATTRIBUTE = "maxlength";
243
244        public static final String ALT_ATTRIBUTE = "alt";
245
246        public static final String ONSELECT_ATTRIBUTE = "onselect";
247
248        public static final String AUTOCOMPLETE_ATTRIBUTE = "autocomplete";
249
250
251        @Nullable
252        private String size;
253
254        @Nullable
255        private String maxlength;
256
257        @Nullable
258        private String alt;
259
260        @Nullable
261        private String onselect;
262
263        @Nullable
264        private String autocomplete;
265
266
267        /**
268         * Set the value of the '{@code size}' attribute.
269         * May be a runtime expression.
270         */
271        public void setSize(String size) {
272                this.size = size;
273        }
274
275        /**
276         * Get the value of the '{@code size}' attribute.
277         */
278        @Nullable
279        protected String getSize() {
280                return this.size;
281        }
282
283        /**
284         * Set the value of the '{@code maxlength}' attribute.
285         * May be a runtime expression.
286         */
287        public void setMaxlength(String maxlength) {
288                this.maxlength = maxlength;
289        }
290
291        /**
292         * Get the value of the '{@code maxlength}' attribute.
293         */
294        @Nullable
295        protected String getMaxlength() {
296                return this.maxlength;
297        }
298
299        /**
300         * Set the value of the '{@code alt}' attribute.
301         * May be a runtime expression.
302         */
303        public void setAlt(String alt) {
304                this.alt = alt;
305        }
306
307        /**
308         * Get the value of the '{@code alt}' attribute.
309         */
310        @Nullable
311        protected String getAlt() {
312                return this.alt;
313        }
314
315        /**
316         * Set the value of the '{@code onselect}' attribute.
317         * May be a runtime expression.
318         */
319        public void setOnselect(String onselect) {
320                this.onselect = onselect;
321        }
322
323        /**
324         * Get the value of the '{@code onselect}' attribute.
325         */
326        @Nullable
327        protected String getOnselect() {
328                return this.onselect;
329        }
330
331        /**
332         * Set the value of the '{@code autocomplete}' attribute.
333         * May be a runtime expression.
334         */
335        public void setAutocomplete(String autocomplete) {
336                this.autocomplete = autocomplete;
337        }
338
339        /**
340         * Get the value of the '{@code autocomplete}' attribute.
341         */
342        @Nullable
343        protected String getAutocomplete() {
344                return this.autocomplete;
345        }
346
347
348        /**
349         * Writes the '{@code input}' tag to the supplied {@link TagWriter}.
350         * Uses the value returned by {@link #getType()} to determine which
351         * type of '{@code input}' element to render.
352         */
353        @Override
354        protected int writeTagContent(TagWriter tagWriter) throws JspException {
355                tagWriter.startTag("input");
356
357                writeDefaultAttributes(tagWriter);
358                Map<String, Object> attributes = getDynamicAttributes();
359                if (attributes == null || !attributes.containsKey("type")) {
360                        tagWriter.writeAttribute("type", getType());
361                }
362                writeValue(tagWriter);
363
364                // custom optional attributes
365                writeOptionalAttribute(tagWriter, SIZE_ATTRIBUTE, getSize());
366                writeOptionalAttribute(tagWriter, MAXLENGTH_ATTRIBUTE, getMaxlength());
367                writeOptionalAttribute(tagWriter, ALT_ATTRIBUTE, getAlt());
368                writeOptionalAttribute(tagWriter, ONSELECT_ATTRIBUTE, getOnselect());
369                writeOptionalAttribute(tagWriter, AUTOCOMPLETE_ATTRIBUTE, getAutocomplete());
370
371                tagWriter.endTag();
372                return SKIP_BODY;
373        }
374
375        /**
376         * Writes the '{@code value}' attribute to the supplied {@link TagWriter}.
377         * Subclasses may choose to override this implementation to control exactly
378         * when the value is written.
379         */
380        protected void writeValue(TagWriter tagWriter) throws JspException {
381                String value = getDisplayString(getBoundValue(), getPropertyEditor());
382                String type = null;
383                Map<String, Object> attributes = getDynamicAttributes();
384                if (attributes != null) {
385                        type = (String) attributes.get("type");
386                }
387                if (type == null) {
388                        type = getType();
389                }
390                tagWriter.writeAttribute("value", processFieldValue(getName(), value, type));
391        }
392
393        /**
394         * Flags {@code type="checkbox"} and {@code type="radio"} as illegal
395         * dynamic attributes.
396         */
397        @Override
398        protected boolean isValidDynamicAttribute(String localName, Object value) {
399                return !("type".equals(localName) && ("checkbox".equals(value) || "radio".equals(value)));
400        }
401
402        /**
403         * Get the value of the '{@code type}' attribute. Subclasses
404         * can override this to change the type of '{@code input}' element
405         * rendered. Default value is '{@code text}'.
406         */
407        protected String getType() {
408                return "text";
409        }
410
411}