View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import static org.htmlunit.html.HtmlForm.ATTRIBUTE_FORMNOVALIDATE;
18  
19  import java.io.IOException;
20  import java.util.Map;
21  
22  import org.htmlunit.SgmlPage;
23  import org.htmlunit.javascript.host.event.Event;
24  import org.htmlunit.javascript.host.event.MouseEvent;
25  import org.htmlunit.util.NameValuePair;
26  import org.htmlunit.util.StringUtils;
27  
28  /**
29   * Wrapper for the HTML element "button".
30   *
31   * @author Mike Bowler
32   * @author David K. Taylor
33   * @author Christian Sell
34   * @author David D. Kilzer
35   * @author Daniel Gredler
36   * @author Ahmed Ashour
37   * @author Dmitri Zoubkov
38   * @author Ronald Brill
39   * @author Frank Danek
40   * @author Sven Strickroth
41   * @author Lai Quang Duong
42   */
43  public class HtmlButton extends HtmlElement implements DisabledElement, SubmittableElement,
44                  LabelableElement, ValidatableHtmlElement {
45  
46      // private static final Log LOG = LogFactory.getLog(HtmlButton.class);
47  
48      /** The HTML tag represented by this element. */
49      public static final String TAG_NAME = "button";
50  
51      private static final String TYPE_SUBMIT = "submit";
52      private static final String TYPE_RESET = "reset";
53      private static final String TYPE_BUTTON = "button";
54  
55      private String customValidity_;
56  
57      /**
58       * Creates a new instance.
59       *
60       * @param qualifiedName the qualified name of the element type to instantiate
61       * @param page the page that contains this element
62       * @param attributes the initial attributes
63       */
64      HtmlButton(final String qualifiedName, final SgmlPage page,
65              final Map<String, DomAttr> attributes) {
66          super(qualifiedName, page, attributes);
67      }
68  
69      /**
70       * Sets the content of the {@code value} attribute.
71       *
72       * @param newValue the new content
73       */
74      public void setValueAttribute(final String newValue) {
75          setAttribute(VALUE_ATTRIBUTE, newValue);
76      }
77  
78      /**
79       * {@inheritDoc}
80       */
81      @Override
82      protected boolean doClickStateUpdate(final boolean shiftKey, final boolean ctrlKey) throws IOException {
83          if (!isDisabled()) {
84              final HtmlForm form = getEnclosingForm();
85              if (form != null) {
86                  final String type = getType();
87                  if (TYPE_BUTTON.equals(type)) {
88                      return false;
89                  }
90  
91                  if (TYPE_RESET.equals(type)) {
92                      form.reset();
93                      return false;
94                  }
95  
96                  form.submit(this);
97                  return false;
98              }
99          }
100 
101         super.doClickStateUpdate(shiftKey, ctrlKey);
102         return false;
103     }
104 
105     /**
106      * {@inheritDoc}
107      */
108     @Override
109     public NameValuePair[] getSubmitNameValuePairs() {
110         return new NameValuePair[]{new NameValuePair(getNameAttribute(), getValueAttribute())};
111     }
112 
113     /**
114      * {@inheritDoc}
115      *
116      * This implementation is empty; buttons have no reset-specific behavior.
117      *
118      * @see SubmittableElement#reset()
119      */
120     @Override
121     public void reset() {
122         // Empty.
123     }
124 
125     /**
126      * {@inheritDoc}
127      *
128      * This implementation is empty; buttons do not maintain a default value.
129      *
130      * @see SubmittableElement#setDefaultValue(String)
131      */
132     @Override
133     public void setDefaultValue(final String defaultValue) {
134         // Empty.
135     }
136 
137     /**
138      * {@inheritDoc}
139      *
140      * This implementation returns an empty string; buttons do not maintain a default value.
141      *
142      * @see SubmittableElement#getDefaultValue()
143      */
144     @Override
145     public String getDefaultValue() {
146         return "";
147     }
148 
149     /**
150      * {@inheritDoc}
151      *
152      * This implementation is empty; only checkboxes and radio buttons really care what the
153      * default checked value is.
154      *
155      * @see SubmittableElement#setDefaultChecked(boolean)
156      * @see HtmlRadioButtonInput#setDefaultChecked(boolean)
157      * @see HtmlCheckBoxInput#setDefaultChecked(boolean)
158      */
159     @Override
160     public void setDefaultChecked(final boolean defaultChecked) {
161         // Empty.
162     }
163 
164     /**
165      * {@inheritDoc}
166      *
167      * This implementation returns {@code false}; only checkboxes and radio buttons really care what
168      * the default checked value is.
169      *
170      * @see SubmittableElement#isDefaultChecked()
171      * @see HtmlRadioButtonInput#isDefaultChecked()
172      * @see HtmlCheckBoxInput#isDefaultChecked()
173      */
174     @Override
175     public boolean isDefaultChecked() {
176         return false;
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     @Override
183     public boolean handles(final Event event) {
184         if (event instanceof MouseEvent) {
185             return true;
186         }
187 
188         return super.handles(event);
189     }
190 
191     /**
192      * Returns the value of the attribute {@code name}. Refer to the
193      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
194      * documentation for details on the use of this attribute.
195      *
196      * @return the value of the attribute {@code name} or an empty string if that attribute isn't defined
197      */
198     public final String getNameAttribute() {
199         return getAttributeDirect(NAME_ATTRIBUTE);
200     }
201 
202     /**
203      * Returns the value of the attribute {@code value}. Refer to the
204      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
205      * documentation for details on the use of this attribute.
206      *
207      * @return the value of the attribute {@code value} or an empty string if that attribute isn't defined
208      */
209     public final String getValueAttribute() {
210         return getAttributeDirect(VALUE_ATTRIBUTE);
211     }
212 
213     /**
214      * Returns the value of the attribute {@code type}. Refer to the
215      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
216      * documentation for details on the use of this attribute.
217      *
218      * @return the value of the attribute {@code type} or the default value if that attribute isn't defined
219      */
220     public final String getTypeAttribute() {
221         return getAttributeDirect(TYPE_ATTRIBUTE);
222     }
223 
224     /**
225      * Returns the normalized button type.
226      *
227      * @return the normalized type value ({@code submit}, {@code reset}, or {@code button})
228      */
229     public String getType() {
230         final String type = getTypeAttribute();
231         if (TYPE_RESET.equalsIgnoreCase(type)) {
232             return TYPE_RESET;
233         }
234         if (TYPE_BUTTON.equalsIgnoreCase(type)) {
235             return TYPE_BUTTON;
236         }
237         return TYPE_SUBMIT;
238     }
239 
240     /**
241      * Returns the value of the attribute {@code disabled}. Refer to the
242      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
243      * documentation for details on the use of this attribute.
244      *
245      * @return the value of the attribute {@code disabled} or an empty string if that attribute isn't defined
246      */
247     @Override
248     public final String getDisabledAttribute() {
249         return getAttributeDirect(ATTRIBUTE_DISABLED);
250     }
251 
252     /**
253      * Returns the value of the attribute {@code tabindex}. Refer to the
254      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
255      * documentation for details on the use of this attribute.
256      *
257      * @return the value of the attribute {@code tabindex} or an empty string if that attribute isn't defined
258      */
259     public final String getTabIndexAttribute() {
260         return getAttributeDirect("tabindex");
261     }
262 
263     /**
264      * Returns the value of the attribute {@code accesskey}. Refer to the
265      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
266      * documentation for details on the use of this attribute.
267      *
268      * @return the value of the attribute {@code accesskey} or an empty string if that attribute isn't defined
269      */
270     public final String getAccessKeyAttribute() {
271         return getAttributeDirect("accesskey");
272     }
273 
274     /**
275      * Returns the value of the attribute {@code onfocus}. Refer to the
276      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
277      * documentation for details on the use of this attribute.
278      *
279      * @return the value of the attribute {@code onfocus} or an empty string if that attribute isn't defined
280      */
281     public final String getOnFocusAttribute() {
282         return getAttributeDirect("onfocus");
283     }
284 
285     /**
286      * Returns the value of the attribute {@code onblur}. Refer to the
287      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
288      * documentation for details on the use of this attribute.
289      *
290      * @return the value of the attribute {@code onblur} or an empty string if that attribute isn't defined
291      */
292     public final String getOnBlurAttribute() {
293         return getAttributeDirect("onblur");
294     }
295 
296     /**
297      * {@inheritDoc}
298      */
299     @Override
300     public DisplayStyle getDefaultStyleDisplay() {
301         return DisplayStyle.INLINE_BLOCK;
302     }
303 
304     /**
305      * {@inheritDoc}
306      *
307      * @return {@code true} to make generated XML readable as HTML.
308      */
309     @Override
310     protected boolean isEmptyXmlTagExpanded() {
311         return true;
312     }
313 
314     /**
315      * {@inheritDoc}
316      */
317     @Override
318     public boolean isValid() {
319         return super.isValid() && !isCustomErrorValidityState();
320     }
321 
322     /**
323      * {@inheritDoc}
324      */
325     @Override
326     public boolean willValidate() {
327         if (TYPE_RESET.equals(getType()) || TYPE_BUTTON.equals(getType())) {
328             return false;
329         }
330 
331         return !isDisabled();
332     }
333 
334     /**
335      * {@inheritDoc}
336      */
337     @Override
338     public String getCustomValidity() {
339         return customValidity_;
340     }
341 
342     /**
343      * {@inheritDoc}
344      */
345     @Override
346     public void setCustomValidity(final String message) {
347         customValidity_ = message;
348     }
349 
350     /**
351      * {@inheritDoc}
352      */
353     @Override
354     public boolean isCustomErrorValidityState() {
355         return !StringUtils.isEmptyOrNull(customValidity_);
356     }
357 
358     @Override
359     public boolean isValidValidityState() {
360         return !isCustomErrorValidityState();
361     }
362 
363     /**
364      * Returns whether the {@code formnovalidate} attribute is present.
365      *
366      * @return {@code true} if the {@code formnovalidate} attribute is present
367      */
368     public final boolean isFormNoValidate() {
369         return hasAttribute(ATTRIBUTE_FORMNOVALIDATE);
370     }
371 
372     /**
373      * Sets the value of the attribute {@code formnovalidate}.
374      *
375      * @param noValidate the value of the attribute {@code formnovalidate}
376      */
377     public final void setFormNoValidate(final boolean noValidate) {
378         if (noValidate) {
379             setAttribute(ATTRIBUTE_FORMNOVALIDATE, ATTRIBUTE_FORMNOVALIDATE);
380         }
381         else {
382             removeAttribute(ATTRIBUTE_FORMNOVALIDATE);
383         }
384     }
385 }