1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html;
16
17 import static org.htmlunit.BrowserVersionFeatures.FORM_IGNORE_REL_NOREFERRER;
18 import static org.htmlunit.BrowserVersionFeatures.FORM_SUBMISSION_HEADER_CACHE_CONTROL_MAX_AGE;
19
20 import java.net.MalformedURLException;
21 import java.net.URL;
22 import java.nio.charset.Charset;
23 import java.nio.charset.StandardCharsets;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.Objects;
32 import java.util.function.Predicate;
33 import java.util.regex.Pattern;
34
35 import org.apache.commons.lang3.ArrayUtils;
36 import org.apache.commons.lang3.StringUtils;
37 import org.apache.commons.lang3.Strings;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.htmlunit.BrowserVersion;
41 import org.htmlunit.ElementNotFoundException;
42 import org.htmlunit.FormEncodingType;
43 import org.htmlunit.HttpHeader;
44 import org.htmlunit.HttpMethod;
45 import org.htmlunit.Page;
46 import org.htmlunit.ScriptResult;
47 import org.htmlunit.SgmlPage;
48 import org.htmlunit.WebAssert;
49 import org.htmlunit.WebClient;
50 import org.htmlunit.WebRequest;
51 import org.htmlunit.WebWindow;
52 import org.htmlunit.http.HttpUtils;
53 import org.htmlunit.javascript.host.event.Event;
54 import org.htmlunit.javascript.host.event.SubmitEvent;
55 import org.htmlunit.protocol.javascript.JavaScriptURLConnection;
56 import org.htmlunit.util.EncodingSniffer;
57 import org.htmlunit.util.NameValuePair;
58 import org.htmlunit.util.UrlUtils;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public class HtmlForm extends HtmlElement {
78 private static final Log LOG = LogFactory.getLog(HtmlForm.class);
79
80
81 public static final String TAG_NAME = "form";
82
83
84 private static final String ATTRIBUTE_NOVALIDATE = "novalidate";
85
86
87 public static final String ATTRIBUTE_FORMNOVALIDATE = "formnovalidate";
88
89 private static final HashSet<String> SUBMITTABLE_TAG_NAMES = new HashSet<>(Arrays.asList(HtmlInput.TAG_NAME,
90 HtmlButton.TAG_NAME, HtmlSelect.TAG_NAME, HtmlTextArea.TAG_NAME));
91
92 private static final Pattern SUBMIT_CHARSET_PATTERN = Pattern.compile("[ ,].*");
93
94 private boolean isPreventDefault_;
95
96
97
98
99
100
101
102
103 HtmlForm(final String qualifiedName, final SgmlPage htmlPage,
104 final Map<String, DomAttr> attributes) {
105 super(qualifiedName, htmlPage, attributes);
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 public void submit(final SubmittableElement submitElement) {
122 final HtmlPage htmlPage = (HtmlPage) getPage();
123 final WebClient webClient = htmlPage.getWebClient();
124
125 if (webClient.isJavaScriptEnabled()) {
126 if (submitElement != null) {
127 isPreventDefault_ = false;
128
129 boolean validate = true;
130 if (submitElement instanceof HtmlSubmitInput
131 && ((HtmlSubmitInput) submitElement).isFormNoValidate()) {
132 validate = false;
133 }
134 else if (submitElement instanceof HtmlButton) {
135 final HtmlButton htmlButton = (HtmlButton) submitElement;
136 if ("submit".equalsIgnoreCase(htmlButton.getType())
137 && htmlButton.isFormNoValidate()) {
138 validate = false;
139 }
140 }
141
142 if (validate
143 && getAttributeDirect(ATTRIBUTE_NOVALIDATE) != ATTRIBUTE_NOT_DEFINED) {
144 validate = false;
145 }
146
147 if (validate && !areChildrenValid()) {
148 return;
149 }
150 final ScriptResult scriptResult = fireEvent(new SubmitEvent(this,
151 ((HtmlElement) submitElement).getScriptableObject()));
152 if (isPreventDefault_) {
153
154 if (scriptResult == null) {
155 return;
156 }
157 return;
158 }
159 }
160
161 final String action = getActionAttribute().trim();
162 if (Strings.CI.startsWith(action, JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
163 htmlPage.executeJavaScript(action, "Form action", getStartLineNumber());
164 return;
165 }
166 }
167 else {
168 if (Strings.CI.startsWith(getActionAttribute(), JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
169
170 return;
171 }
172 }
173
174
175 if (submitElement != null) {
176 updateHtml5Attributes(submitElement);
177 }
178
179
180 final String methodAttribute = getMethodAttribute();
181 if ("dialog".equalsIgnoreCase(methodAttribute)) {
182
183 final HtmlElement dialog = getEnclosingElement("dialog");
184 if (dialog != null) {
185 ((HtmlDialog) dialog).close("");
186 }
187 return;
188 }
189
190 final WebRequest request = getWebRequest(submitElement);
191 final String target = htmlPage.getResolvedTarget(getTargetAttribute());
192
193 final WebWindow webWindow = htmlPage.getEnclosingWindow();
194
195 webClient.download(webWindow, target, request, false, null, "JS form.submit()");
196 }
197
198
199
200
201
202
203
204 private void updateHtml5Attributes(final SubmittableElement submitElement) {
205 if (submitElement instanceof HtmlElement) {
206 final HtmlElement element = (HtmlElement) submitElement;
207
208 final String type = element.getAttributeDirect(TYPE_ATTRIBUTE);
209 boolean typeImage = false;
210 final boolean isInput = HtmlInput.TAG_NAME.equals(element.getTagName());
211 if (isInput) {
212 typeImage = "image".equalsIgnoreCase(type);
213 }
214
215
216
217
218
219 final boolean typeSubmit = "submit".equalsIgnoreCase(type);
220 if (isInput && !typeSubmit && !typeImage) {
221 return;
222 }
223 else if (HtmlButton.TAG_NAME.equals(element.getTagName())
224 && !"submit".equals(((HtmlButton) element).getType())) {
225 return;
226 }
227
228 final String formaction = element.getAttributeDirect("formaction");
229 if (ATTRIBUTE_NOT_DEFINED != formaction) {
230 setActionAttribute(formaction);
231 }
232 final String formmethod = element.getAttributeDirect("formmethod");
233 if (ATTRIBUTE_NOT_DEFINED != formmethod) {
234 setMethodAttribute(formmethod);
235 }
236 final String formtarget = element.getAttributeDirect("formtarget");
237 if (ATTRIBUTE_NOT_DEFINED != formtarget) {
238 setTargetAttribute(formtarget);
239 }
240 final String formenctype = element.getAttributeDirect("formenctype");
241 if (ATTRIBUTE_NOT_DEFINED != formenctype) {
242 setEnctypeAttribute(formenctype);
243 }
244 }
245 }
246
247 private boolean areChildrenValid() {
248 boolean valid = true;
249 for (final HtmlElement element : getElements(htmlElement -> htmlElement instanceof HtmlInput)) {
250 if (!element.isValid()) {
251 if (LOG.isInfoEnabled()) {
252 LOG.info("Form validation failed; element '" + element + "' was not valid. Submit cancelled.");
253 }
254 valid = false;
255 break;
256 }
257 }
258 return valid;
259 }
260
261
262
263
264
265
266
267
268 public WebRequest getWebRequest(final SubmittableElement submitElement) {
269 final HttpMethod method;
270 final String methodAttribute = getMethodAttribute();
271 if ("post".equalsIgnoreCase(methodAttribute)) {
272 method = HttpMethod.POST;
273 }
274 else {
275 if (!"get".equalsIgnoreCase(methodAttribute) && StringUtils.isNotBlank(methodAttribute)) {
276 notifyIncorrectness("Incorrect submit method >" + getMethodAttribute() + "<. Using >GET<.");
277 }
278 method = HttpMethod.GET;
279 }
280
281 String actionUrl = getActionAttribute();
282 String anchor = null;
283 String queryFormFields = "";
284 Charset enc = getSubmitCharset();
285 if (StandardCharsets.UTF_16 == enc
286 || StandardCharsets.UTF_16BE == enc
287 || StandardCharsets.UTF_16LE == enc) {
288 enc = StandardCharsets.UTF_8;
289 }
290
291 final List<NameValuePair> parameters = getParameterListForSubmit(submitElement);
292 if (HttpMethod.GET == method) {
293 if (actionUrl.contains("#")) {
294 anchor = StringUtils.substringAfter(actionUrl, "#");
295 }
296 queryFormFields = HttpUtils.toQueryFormFields(parameters, enc);
297
298
299 actionUrl = StringUtils.substringBefore(actionUrl, "#");
300 actionUrl = StringUtils.substringBefore(actionUrl, "?");
301 parameters.clear();
302 }
303
304 final HtmlPage htmlPage = (HtmlPage) getPage();
305 URL url;
306 try {
307 if (actionUrl.isEmpty()) {
308 url = WebClient.expandUrl(htmlPage.getUrl(), actionUrl);
309 }
310 else {
311 url = htmlPage.getFullyQualifiedUrl(actionUrl);
312 }
313
314 if (!queryFormFields.isEmpty()) {
315 url = UrlUtils.getUrlWithNewQuery(url, queryFormFields);
316 }
317
318 if (anchor != null && UrlUtils.URL_ABOUT_BLANK != url) {
319 url = UrlUtils.getUrlWithNewRef(url, anchor);
320 }
321 }
322 catch (final MalformedURLException e) {
323 throw new IllegalArgumentException("Not a valid url: " + actionUrl, e);
324 }
325
326 final BrowserVersion browser = htmlPage.getWebClient().getBrowserVersion();
327 final WebRequest request = new WebRequest(url, browser.getHtmlAcceptHeader(),
328 browser.getAcceptEncodingHeader());
329 request.setHttpMethod(method);
330 request.setRequestParameters(parameters);
331 if (HttpMethod.POST == method) {
332 request.setEncodingType(FormEncodingType.getInstance(getEnctypeAttribute()));
333 }
334 request.setCharset(enc);
335
336
337 if (browser.hasFeature(FORM_IGNORE_REL_NOREFERRER)
338 || !relContainsNoreferrer()) {
339 request.setRefererHeader(htmlPage.getUrl());
340 }
341
342 if (HttpMethod.POST == method) {
343 try {
344 request.setAdditionalHeader(HttpHeader.ORIGIN,
345 UrlUtils.getUrlWithProtocolAndAuthority(htmlPage.getUrl()).toExternalForm());
346 }
347 catch (final MalformedURLException e) {
348 if (LOG.isInfoEnabled()) {
349 LOG.info("Invalid origin url '" + htmlPage.getUrl() + "'");
350 }
351 }
352 }
353 if (HttpMethod.POST == method) {
354 if (browser.hasFeature(FORM_SUBMISSION_HEADER_CACHE_CONTROL_MAX_AGE)) {
355 request.setAdditionalHeader(HttpHeader.CACHE_CONTROL, "max-age=0");
356 }
357 }
358
359 return request;
360 }
361
362 private boolean relContainsNoreferrer() {
363 String rel = getRelAttribute();
364 if (rel != null) {
365 rel = rel.toLowerCase(Locale.ROOT);
366 return ArrayUtils.contains(org.htmlunit.util.StringUtils.splitAtBlank(rel), "noreferrer");
367 }
368 return false;
369 }
370
371
372
373
374
375
376
377 private Charset getSubmitCharset() {
378 String charset = getAcceptCharsetAttribute();
379 if (!charset.isEmpty()) {
380 charset = charset.trim();
381 return EncodingSniffer.toCharset(
382 SUBMIT_CHARSET_PATTERN.matcher(charset).replaceAll("").toUpperCase(Locale.ROOT));
383 }
384 return getPage().getCharset();
385 }
386
387
388
389
390
391
392
393
394
395
396
397
398
399 public List<NameValuePair> getParameterListForSubmit(final SubmittableElement submitElement) {
400 final Collection<SubmittableElement> submittableElements = getSubmittableElements(submitElement);
401
402 final List<NameValuePair> parameterList = new ArrayList<>(submittableElements.size());
403 for (final SubmittableElement element : submittableElements) {
404 parameterList.addAll(Arrays.asList(element.getSubmitNameValuePairs()));
405 }
406
407 return parameterList;
408 }
409
410
411
412
413
414
415
416
417 public Page reset() {
418 final SgmlPage htmlPage = getPage();
419 final ScriptResult scriptResult = fireEvent(Event.TYPE_RESET);
420 if (ScriptResult.isFalse(scriptResult)) {
421 return htmlPage.getWebClient().getCurrentWindow().getEnclosedPage();
422 }
423
424 for (final HtmlElement next : getHtmlElementDescendants()) {
425 if (next instanceof SubmittableElement) {
426 ((SubmittableElement) next).reset();
427 }
428 }
429
430 return htmlPage;
431 }
432
433
434
435
436 @Override
437 public boolean isValid() {
438 for (final HtmlElement element : getFormElements()) {
439 if (!element.isValid()) {
440 return false;
441 }
442 }
443 return super.isValid();
444 }
445
446
447
448
449
450
451
452
453
454 Collection<SubmittableElement> getSubmittableElements(final SubmittableElement submitElement) {
455 final List<SubmittableElement> submittableElements = new ArrayList<>();
456
457 for (final HtmlElement element : getElements(htmlElement -> isSubmittable(htmlElement, submitElement))) {
458 submittableElements.add((SubmittableElement) element);
459 }
460
461 return submittableElements;
462 }
463
464 private static boolean isValidForSubmission(final HtmlElement element, final SubmittableElement submitElement) {
465 final String tagName = element.getTagName();
466 if (!SUBMITTABLE_TAG_NAMES.contains(tagName)) {
467 return false;
468 }
469 if (element.isDisabledElementAndDisabled()) {
470 return false;
471 }
472
473 if (element == submitElement && element instanceof HtmlImageInput) {
474 return true;
475 }
476
477 if (!element.hasAttribute(NAME_ATTRIBUTE)) {
478 return false;
479 }
480
481 if (org.htmlunit.util.StringUtils.isEmptyString(element.getAttributeDirect(NAME_ATTRIBUTE))) {
482 return false;
483 }
484
485 if (element instanceof HtmlInput) {
486 final HtmlInput input = (HtmlInput) element;
487 if (input.isCheckable()) {
488 return ((HtmlInput) element).isChecked();
489 }
490 }
491 if (HtmlSelect.TAG_NAME.equals(tagName)) {
492 return ((HtmlSelect) element).isValidForSubmission();
493 }
494 return true;
495 }
496
497
498
499
500
501
502
503
504
505
506 private static boolean isSubmittable(final HtmlElement element, final SubmittableElement submitElement) {
507 if (!isValidForSubmission(element, submitElement)) {
508 return false;
509 }
510
511
512 if (element == submitElement) {
513 return true;
514 }
515 if (element instanceof HtmlInput) {
516 final HtmlInput input = (HtmlInput) element;
517 if (!input.isSubmitable()) {
518 return false;
519 }
520 }
521
522 return !HtmlButton.TAG_NAME.equals(element.getTagName());
523 }
524
525
526
527
528
529
530
531 public List<HtmlInput> getInputsByName(final String name) {
532 return getFormElementsByAttribute(HtmlInput.TAG_NAME, NAME_ATTRIBUTE, name);
533 }
534
535
536
537
538
539 @SuppressWarnings("unchecked")
540 private <E extends HtmlElement> List<E> getFormElementsByAttribute(
541 final String elementName,
542 final String attributeName,
543 final String attributeValue) {
544
545 return (List<E>) getElements(htmlElement ->
546 htmlElement.getTagName().equals(elementName)
547 && htmlElement.getAttribute(attributeName).equals(attributeValue));
548 }
549
550
551
552
553
554
555
556
557
558 public List<HtmlElement> getFormElements() {
559 return getElements(htmlElement -> {
560 final String tagName = htmlElement.getTagName();
561 return HtmlButton.TAG_NAME.equals(tagName)
562 || HtmlFieldSet.TAG_NAME.equals(tagName)
563 || HtmlInput.TAG_NAME.equals(tagName)
564 || HtmlObject.TAG_NAME.equals(tagName)
565 || HtmlOutput.TAG_NAME.equals(tagName)
566 || HtmlSelect.TAG_NAME.equals(tagName)
567 || HtmlTextArea.TAG_NAME.equals(tagName);
568 });
569 }
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584 public List<HtmlElement> getElementsJS() {
585 return getElements(htmlElement -> {
586 final String tagName = htmlElement.getTagName();
587 if (HtmlInput.TAG_NAME.equals(tagName)) {
588 return !(htmlElement instanceof HtmlImageInput);
589 }
590
591 return HtmlButton.TAG_NAME.equals(tagName)
592 || HtmlFieldSet.TAG_NAME.equals(tagName)
593 || HtmlObject.TAG_NAME.equals(tagName)
594 || HtmlOutput.TAG_NAME.equals(tagName)
595 || HtmlSelect.TAG_NAME.equals(tagName)
596 || HtmlTextArea.TAG_NAME.equals(tagName);
597 });
598 }
599
600
601
602
603
604 public List<HtmlElement> getElements(final Predicate<HtmlElement> filter) {
605 final List<HtmlElement> elements = new ArrayList<>();
606
607 if (isAttachedToPage()) {
608 for (final HtmlElement element : getPage().getDocumentElement().getHtmlElementDescendants()) {
609 if (filter.test(element)
610 && element.getEnclosingForm() == this) {
611 elements.add(element);
612 }
613 }
614 }
615 else {
616 for (final HtmlElement element : getHtmlElementDescendants()) {
617 if (filter.test(element)) {
618 elements.add(element);
619 }
620 }
621 }
622
623 return elements;
624 }
625
626
627
628
629
630
631
632
633
634 @SuppressWarnings("unchecked")
635 public final <I extends HtmlInput> I getInputByName(final String name) throws ElementNotFoundException {
636 final List<HtmlInput> inputs = getInputsByName(name);
637
638 if (inputs.isEmpty()) {
639 throw new ElementNotFoundException(HtmlInput.TAG_NAME, NAME_ATTRIBUTE, name);
640 }
641 return (I) inputs.get(0);
642 }
643
644
645
646
647
648
649
650 public List<HtmlSelect> getSelectsByName(final String name) {
651 return getFormElementsByAttribute(HtmlSelect.TAG_NAME, NAME_ATTRIBUTE, name);
652 }
653
654
655
656
657
658
659
660
661
662 public HtmlSelect getSelectByName(final String name) throws ElementNotFoundException {
663 final List<HtmlSelect> list = getSelectsByName(name);
664 if (list.isEmpty()) {
665 throw new ElementNotFoundException(HtmlSelect.TAG_NAME, NAME_ATTRIBUTE, name);
666 }
667 return list.get(0);
668 }
669
670
671
672
673
674
675
676 public List<HtmlButton> getButtonsByName(final String name) {
677 return getFormElementsByAttribute(HtmlButton.TAG_NAME, NAME_ATTRIBUTE, name);
678 }
679
680
681
682
683
684
685
686
687
688 public HtmlButton getButtonByName(final String name) throws ElementNotFoundException {
689 final List<HtmlButton> list = getButtonsByName(name);
690 if (list.isEmpty()) {
691 throw new ElementNotFoundException(HtmlButton.TAG_NAME, NAME_ATTRIBUTE, name);
692 }
693 return list.get(0);
694 }
695
696
697
698
699
700
701
702 public List<HtmlTextArea> getTextAreasByName(final String name) {
703 return getFormElementsByAttribute(HtmlTextArea.TAG_NAME, NAME_ATTRIBUTE, name);
704 }
705
706
707
708
709
710
711
712
713
714 public HtmlTextArea getTextAreaByName(final String name) throws ElementNotFoundException {
715 final List<HtmlTextArea> list = getTextAreasByName(name);
716 if (list.isEmpty()) {
717 throw new ElementNotFoundException(HtmlTextArea.TAG_NAME, NAME_ATTRIBUTE, name);
718 }
719 return list.get(0);
720 }
721
722
723
724
725
726
727
728 public List<HtmlRadioButtonInput> getRadioButtonsByName(final String name) {
729 WebAssert.notNull("name", name);
730
731 final List<HtmlRadioButtonInput> results = new ArrayList<>();
732
733 for (final HtmlElement element : getInputsByName(name)) {
734 if (element instanceof HtmlRadioButtonInput) {
735 results.add((HtmlRadioButtonInput) element);
736 }
737 }
738
739 return results;
740 }
741
742
743
744
745
746
747
748 void setCheckedRadioButton(final HtmlRadioButtonInput radioButtonInput) {
749 if (radioButtonInput.getEnclosingForm() == null) {
750 throw new IllegalArgumentException("HtmlRadioButtonInput is not child of this HtmlForm");
751 }
752 final List<HtmlRadioButtonInput> radios = getRadioButtonsByName(radioButtonInput.getNameAttribute());
753
754 for (final HtmlRadioButtonInput input : radios) {
755 input.setCheckedInternal(input == radioButtonInput);
756 }
757 }
758
759
760
761
762
763
764
765
766 public HtmlRadioButtonInput getCheckedRadioButton(final String name) {
767 WebAssert.notNull("name", name);
768
769 for (final HtmlRadioButtonInput input : getRadioButtonsByName(name)) {
770 if (input.isChecked()) {
771 return input;
772 }
773 }
774 return null;
775 }
776
777
778
779
780
781
782
783
784 public final String getActionAttribute() {
785 return getAttributeDirect("action");
786 }
787
788
789
790
791
792
793
794
795 public final void setActionAttribute(final String action) {
796 setAttribute("action", action);
797 }
798
799
800
801
802
803
804
805
806 public final String getMethodAttribute() {
807 return getAttributeDirect("method");
808 }
809
810
811
812
813
814
815
816
817 public final void setMethodAttribute(final String method) {
818 setAttribute("method", method);
819 }
820
821
822
823
824
825
826
827
828 public final String getNameAttribute() {
829 return getAttributeDirect(NAME_ATTRIBUTE);
830 }
831
832
833
834
835
836
837
838
839 public final void setNameAttribute(final String name) {
840 setAttribute(NAME_ATTRIBUTE, name);
841 }
842
843
844
845
846
847
848
849
850
851 public final String getEnctypeAttribute() {
852 return getAttributeDirect("enctype");
853 }
854
855
856
857
858
859
860
861
862
863 public final void setEnctypeAttribute(final String encoding) {
864 setAttribute("enctype", encoding);
865 }
866
867
868
869
870
871
872
873
874 public final String getOnSubmitAttribute() {
875 return getAttributeDirect("onsubmit");
876 }
877
878
879
880
881
882
883
884
885 public final String getOnResetAttribute() {
886 return getAttributeDirect("onreset");
887 }
888
889
890
891
892
893
894
895
896 public final String getAcceptAttribute() {
897 return getAttribute(HttpHeader.ACCEPT_LC);
898 }
899
900
901
902
903
904
905
906
907 public final String getAcceptCharsetAttribute() {
908 return getAttribute("accept-charset");
909 }
910
911
912
913
914
915
916
917
918 public final String getTargetAttribute() {
919 return getAttributeDirect("target");
920 }
921
922
923
924
925
926
927
928
929 public final void setTargetAttribute(final String target) {
930 setAttribute("target", target);
931 }
932
933
934
935
936
937
938
939
940 public final String getRelAttribute() {
941 return getAttributeDirect("rel");
942 }
943
944
945
946
947
948
949
950
951 @SuppressWarnings("unchecked")
952 public <I extends HtmlInput> I getInputByValue(final String value) throws ElementNotFoundException {
953 final List<HtmlInput> list = getInputsByValue(value);
954 if (list.isEmpty()) {
955 throw new ElementNotFoundException(HtmlInput.TAG_NAME, VALUE_ATTRIBUTE, value);
956 }
957 return (I) list.get(0);
958 }
959
960
961
962
963
964
965 public List<HtmlInput> getInputsByValue(final String value) {
966 final List<HtmlInput> results = new ArrayList<>();
967
968 for (final HtmlElement element : getElements(htmlElement -> htmlElement instanceof HtmlInput)) {
969 if (Objects.equals(((HtmlInput) element).getValue(), value)) {
970 results.add((HtmlInput) element);
971 }
972 }
973
974 return results;
975 }
976
977
978
979
980 @Override
981 protected void preventDefault() {
982 isPreventDefault_ = true;
983 }
984
985
986
987
988 @Override
989 protected boolean isEmptyXmlTagExpanded() {
990 return true;
991 }
992
993
994
995
996 public final boolean isNoValidate() {
997 return hasAttribute(ATTRIBUTE_NOVALIDATE);
998 }
999
1000
1001
1002
1003
1004
1005 public final void setNoValidate(final boolean noValidate) {
1006 if (noValidate) {
1007 setAttribute(ATTRIBUTE_NOVALIDATE, ATTRIBUTE_NOVALIDATE);
1008 }
1009 else {
1010 removeAttribute(ATTRIBUTE_NOVALIDATE);
1011 }
1012 }
1013 }