001: /*
002: * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: * 2. Redistributions in binary form must reproduce the above copyright notice,
010: * this list of conditions and the following disclaimer in the documentation
011: * and/or other materials provided with the distribution.
012: * 3. The end-user documentation included with the redistribution, if any, must
013: * include the following acknowledgment:
014: *
015: * "This product includes software developed by Gargoyle Software Inc.
016: * (http://www.GargoyleSoftware.com/)."
017: *
018: * Alternately, this acknowledgment may appear in the software itself, if
019: * and wherever such third-party acknowledgments normally appear.
020: * 4. The name "Gargoyle Software" must not be used to endorse or promote
021: * products derived from this software without prior written permission.
022: * For written permission, please contact info@GargoyleSoftware.com.
023: * 5. Products derived from this software may not be called "HtmlUnit", nor may
024: * "HtmlUnit" appear in their name, without prior written permission of
025: * Gargoyle Software Inc.
026: *
027: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030: * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: */
038: package com.gargoylesoftware.htmlunit.html;
039:
040: import java.io.IOException;
041: import java.net.MalformedURLException;
042: import java.net.URL;
043: import java.util.ArrayList;
044: import java.util.Arrays;
045: import java.util.Collection;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.Map;
049:
050: import org.apache.commons.httpclient.NameValuePair;
051: import org.apache.commons.httpclient.util.EncodingUtil;
052: import org.apache.commons.lang.StringUtils;
053: import org.jaxen.JaxenException;
054:
055: import com.gargoylesoftware.htmlunit.Assert;
056: import com.gargoylesoftware.htmlunit.BrowserVersion;
057: import com.gargoylesoftware.htmlunit.ElementNotFoundException;
058: import com.gargoylesoftware.htmlunit.FormEncodingType;
059: import com.gargoylesoftware.htmlunit.KeyValuePair;
060: import com.gargoylesoftware.htmlunit.Page;
061: import com.gargoylesoftware.htmlunit.ScriptResult;
062: import com.gargoylesoftware.htmlunit.SubmitMethod;
063: import com.gargoylesoftware.htmlunit.TextUtil;
064: import com.gargoylesoftware.htmlunit.WebRequestSettings;
065: import com.gargoylesoftware.htmlunit.WebWindow;
066: import com.gargoylesoftware.htmlunit.javascript.host.Event;
067:
068: /**
069: * Wrapper for the html element "form"
070: *
071: * @version $Revision: 2141 $
072: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
073: * @author David K. Taylor
074: * @author Brad Clarke
075: * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
076: * @author Marc Guillemot
077: * @author George Murnock
078: * @author Kent Tong
079: * @author Ahmed Ashour
080: * @author Philip Graf
081: */
082: public class HtmlForm extends ClickableElement {
083:
084: private static final long serialVersionUID = 5338964478788825866L;
085:
086: /** the HTML tag represented by this element */
087: public static final String TAG_NAME = "form";
088:
089: private static final Collection SUBMITTABLE_ELEMENT_NAMES = Arrays
090: .asList(new String[] { "input", "button", "select",
091: "textarea", "isindex" });
092:
093: /**
094: * @deprecated
095: */
096: private KeyValuePair fakeSelectedRadioButton_;
097:
098: /**
099: * Create an instance
100: *
101: * @param htmlPage The page that contains this element
102: * @param attributes the initial attributes
103: * @deprecated You should not directly construct HtmlForm.
104: */
105: //TODO: to be removed, deprecated after 1.11
106: public HtmlForm(final HtmlPage htmlPage, final Map attributes) {
107: this (null, TAG_NAME, htmlPage, attributes);
108: }
109:
110: /**
111: * Create an instance
112: *
113: * @param namespaceURI the URI that identifies an XML namespace.
114: * @param qualifiedName The qualified name of the element type to instantiate
115: * @param htmlPage The page that contains this element
116: * @param attributes the initial attributes
117: */
118: HtmlForm(final String namespaceURI, final String qualifiedName,
119: final HtmlPage htmlPage, final Map attributes) {
120: super (namespaceURI, qualifiedName, htmlPage, attributes);
121: }
122:
123: /**
124: * Submit this form to the appropriate server as if a submit button had been pressed
125: *
126: * @param buttonName The name of a submit input element or a button element
127: * which will be sent back up with the response
128: * @return A new Page that reflects the results of this submission
129: * @throws IOException If an IO error occurs
130: * @throws ElementNotFoundException If a button with the specified name cannot be found.
131: * @deprecated after 1.11, click on the specific {@link SubmittableElement} instead.
132: */
133: public Page submit(final String buttonName) throws IOException,
134: ElementNotFoundException {
135: final List inputList = getHtmlElementsByAttribute("input",
136: "name", buttonName);
137: final Iterator iterator = inputList.iterator();
138: while (iterator.hasNext()) {
139: final HtmlInput input = (HtmlInput) iterator.next();
140: if (input.getTypeAttribute().equals("submit")) {
141: return submit(input);
142: }
143: }
144:
145: final HtmlButton button = (HtmlButton) getOneHtmlElementByAttribute(
146: "button", "name", buttonName);
147: return submit(button);
148: }
149:
150: /**
151: * Submit this form to the appropriate server as if it had been submitted
152: * by javascript - i.e. no submit buttons were pressed. Note that because we
153: * are simulating a javascript submit, the onsubmit handler will not get executed.
154: *
155: * @return A new Page that reflects the results of this submission
156: * @exception IOException If an IO error occurs
157: * @deprecated after 1.11, click on a specific {@link SubmittableElement} instead.
158: */
159: public Page submit() throws IOException {
160: return submit((SubmittableElement) null);
161: }
162:
163: /**
164: * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br/>
165: *
166: * Submit this form to the appropriate server. If submitElement is null then
167: * treat this as if it was called by javascript. In this case, the onsubmit
168: * handler will not get executed.
169: *
170: * @param submitElement The element that caused the submit to occur
171: * @return A new Page that reflects the results of this submission
172: * @exception IOException If an IO error occurs
173: */
174: public Page submit(final SubmittableElement submitElement)
175: throws IOException {
176: final HtmlPage htmlPage = getPage();
177: if (htmlPage.getWebClient().isJavaScriptEnabled()) {
178: if (submitElement != null) {
179: final ScriptResult scriptResult = fireEvent(Event.TYPE_SUBMIT);
180: if (scriptResult != null
181: && Boolean.FALSE.equals(scriptResult
182: .getJavaScriptResult())) {
183: return scriptResult.getNewPage();
184: }
185: }
186:
187: final String action = getActionAttribute();
188: if (TextUtil.startsWithIgnoreCase(action, "javascript:")) {
189: return htmlPage.executeJavaScriptIfPossible(action,
190: "Form action", getStartLineNumber())
191: .getNewPage();
192: }
193: } else {
194: if (TextUtil.startsWithIgnoreCase(getActionAttribute(),
195: "javascript:")) {
196: // The action is javascript but javascript isn't enabled. Return
197: // the current page.
198: return htmlPage;
199: }
200: }
201:
202: final List parameters = getParameterListForSubmit(submitElement);
203: final SubmitMethod method;
204: final String methodAttribute = getMethodAttribute();
205: if ("post".equalsIgnoreCase(methodAttribute)) {
206: method = SubmitMethod.POST;
207: } else {
208: if (!"get".equalsIgnoreCase(methodAttribute)
209: && methodAttribute.trim().length() > 0) {
210: notifyIncorrectness("Incorrect submit method >"
211: + getMethodAttribute() + "<. Using >GET<.");
212: }
213: method = SubmitMethod.GET;
214: }
215:
216: String actionUrl = getActionAttribute();
217: if (SubmitMethod.GET.equals(method)) {
218: final String anchor = StringUtils.substringAfter(actionUrl,
219: "#");
220: actionUrl = StringUtils.substringBefore(actionUrl, "#");
221:
222: final NameValuePair[] pairs = new NameValuePair[parameters
223: .size()];
224: parameters.toArray(pairs);
225: final String queryFromFields = EncodingUtil.formUrlEncode(
226: pairs, getPage().getPageEncoding());
227:
228: // action may already contain some query parameters: they have to be removed
229: actionUrl = StringUtils.substringBefore(actionUrl, "?");
230: final BrowserVersion browserVersion = getPage()
231: .getWebClient().getBrowserVersion();
232: if (!(browserVersion.isIE() && browserVersion
233: .getBrowserVersionNumeric() >= 7)
234: || queryFromFields.length() > 0) {
235: actionUrl += "?" + queryFromFields;
236: }
237: if (anchor.length() > 0) {
238: actionUrl += "#" + anchor;
239: }
240: parameters.clear(); // parameters have been added to query
241: }
242: final URL url;
243: try {
244: url = htmlPage.getFullyQualifiedUrl(actionUrl);
245: } catch (final MalformedURLException e) {
246: throw new IllegalArgumentException("Not a valid url: "
247: + actionUrl);
248: }
249:
250: final WebRequestSettings settings = new WebRequestSettings(url,
251: method);
252: settings.setRequestParameters(parameters);
253: settings.setEncodingType(FormEncodingType
254: .getInstance(getEnctypeAttribute()));
255: settings.setCharset(getSubmitCharset());
256: settings.addAdditionalHeader("Referer", htmlPage
257: .getWebResponse().getUrl().toExternalForm());
258:
259: final WebWindow webWindow = htmlPage.getEnclosingWindow();
260: return htmlPage.getWebClient().getPage(webWindow,
261: htmlPage.getResolvedTarget(getTargetAttribute()),
262: settings);
263: }
264:
265: /**
266: * Gets the charset to use for the form submission. This is the first one
267: * from the list provided in {@link #getAcceptCharsetAttribute()} if any
268: * or the page's charset else
269: * @return see above
270: */
271: private String getSubmitCharset() {
272: if (getAcceptCharsetAttribute().length() > 0) {
273: return getAcceptCharsetAttribute().trim().replaceAll(
274: "[ ,].*", "");
275: } else {
276: return getPage().getPageEncoding();
277: }
278: }
279:
280: /**
281: * Return a list of {@link KeyValuePair}s that represent the data that will be
282: * sent to the server on a form submit. This is primarily intended to aid
283: * debugging.
284: *
285: * @param submitElement The element that would have been pressed to submit the
286: * form or null if the form was submitted by javascript.
287: * @return The list of {@link KeyValuePair}s.
288: */
289: public final List getParameterListForSubmit(
290: final SubmittableElement submitElement) {
291: final Collection submittableElements = getSubmittableElements(submitElement);
292:
293: final List parameterList = new ArrayList(submittableElements
294: .size());
295: final Iterator iterator = submittableElements.iterator();
296: while (iterator.hasNext()) {
297: final SubmittableElement element = (SubmittableElement) iterator
298: .next();
299: final KeyValuePair[] pairs = element
300: .getSubmitKeyValuePairs();
301:
302: for (int i = 0; i < pairs.length; i++) {
303: parameterList.add(pairs[i]);
304: }
305: }
306:
307: if (fakeSelectedRadioButton_ != null) {
308: adjustParameterListToAccountForFakeSelectedRadioButton(parameterList);
309: }
310: return parameterList;
311: }
312:
313: /**
314: * Reset this form to its initial values.
315: * @return The page that is loaded at the end of calling this method. Typically this
316: * will be the same page that had been loaded previously but since javascript might
317: * have run, this isn't guaranteed.
318: */
319: public Page reset() {
320: final HtmlPage htmlPage = getPage();
321: final ScriptResult scriptResult = fireEvent(Event.TYPE_RESET);
322: if (scriptResult != null
323: && Boolean.FALSE.equals(scriptResult
324: .getJavaScriptResult())) {
325: return scriptResult.getNewPage();
326: }
327:
328: final Iterator elementIterator = getAllHtmlChildElements();
329: while (elementIterator.hasNext()) {
330: final Object next = elementIterator.next();
331: if (next instanceof SubmittableElement) {
332: ((SubmittableElement) next).reset();
333: }
334: }
335:
336: return htmlPage;
337: }
338:
339: /**
340: * Return a collection of elements that represent all the "submittable" elements in this form
341: *
342: * @param submitElement The element that would have been pressed to submit the
343: * form or null if the form was submitted by javascript.
344: * @return See above
345: */
346: public Collection getSubmittableElements(
347: final SubmittableElement submitElement) {
348: final List submittableElements = new ArrayList();
349:
350: final Iterator iterator = getAllHtmlChildElements();
351: while (iterator.hasNext()) {
352: final HtmlElement element = (HtmlElement) iterator.next();
353: if (isSubmittable(element, submitElement)) {
354: submittableElements.add(element);
355: }
356: }
357:
358: return submittableElements;
359: }
360:
361: private boolean isValidForSubmission(final HtmlElement element,
362: final SubmittableElement submitElement) {
363: final String tagName = element.getTagName();
364: if (!SUBMITTABLE_ELEMENT_NAMES.contains(tagName.toLowerCase())) {
365: return false;
366: }
367: if (element.isAttributeDefined("disabled")) {
368: return false;
369: }
370: // clicked input type="image" is submitted even if it hasn't a name
371: if (element == submitElement
372: && element instanceof HtmlImageInput) {
373: return true;
374: }
375:
376: if (!tagName.equals("isindex")
377: && !element.isAttributeDefined("name")) {
378: return false;
379: }
380:
381: if (!tagName.equals("isindex")
382: && element.getAttributeValue("name").equals("")) {
383: return false;
384: }
385:
386: if (tagName.equals("input")) {
387: final String type = element.getAttributeValue("type")
388: .toLowerCase();
389: if (type.equals("radio") || type.equals("checkbox")) {
390: return element.isAttributeDefined("checked");
391: }
392: }
393: if (tagName.equals("select")) {
394: return ((HtmlSelect) element).isValidForSubmission();
395: }
396: return true;
397: }
398:
399: /**
400: * @param element The element that we are checking for isSubmittable
401: * @param submitElement The element that would have been pressed to submit the
402: * form or null if the form was submitted by javascript.
403: * @return true if element is submittable
404: */
405: private boolean isSubmittable(final HtmlElement element,
406: final SubmittableElement submitElement) {
407: final String tagName = element.getTagName();
408: if (!isValidForSubmission(element, submitElement)) {
409: return false;
410: }
411:
412: // The one submit button that was clicked can be submitted but no other ones
413: if (element == submitElement) {
414: return true;
415: }
416: if (tagName.equals("input")) {
417: final HtmlInput input = (HtmlInput) element;
418: final String type = input.getTypeAttribute().toLowerCase();
419: if (type.equals("submit") || type.equals("image")
420: || type.equals("reset") || type.equals("button")) {
421: return false;
422: }
423: }
424: if (tagName.equals("button")) {
425: return false;
426: }
427:
428: return true;
429: }
430:
431: /**
432: * Return the input tags that have the specified name
433: *
434: * @param name The name of the input
435: * @return A list of HtmlInputs
436: */
437: public List getInputsByName(final String name) {
438: return getHtmlElementsByAttribute("input", "name", name);
439: }
440:
441: /**
442: * Return the first input with the specified name
443: *
444: * @param name The name of the input
445: * @return The input
446: * @throws ElementNotFoundException If no inputs could be found with the specified name.
447: */
448: public final HtmlInput getInputByName(final String name)
449: throws ElementNotFoundException {
450: final List inputs = getHtmlElementsByAttribute("input", "name",
451: name);
452: if (inputs.size() == 0) {
453: throw new ElementNotFoundException("input", "name", name);
454: } else {
455: return (HtmlInput) inputs.get(0);
456: }
457: }
458:
459: /**
460: * Return the "radio" type input field that matches the specified name and value
461: *
462: * @param name The name of the HtmlInput
463: * @param value The value of the HtmlInput
464: * @return See above
465: * @exception ElementNotFoundException If the field could not be found
466: *
467: * @deprecated Deprecated because 'name' and 'value' are sometimes not unique to select a single
468: * HtmlRadioButtonInput, it should not be called,
469: * you can use {@link #getByXPath(String)} instead.
470: */
471: //TODO: to be removed, deprecated after 1.11
472: public HtmlRadioButtonInput getRadioButtonInput(final String name,
473: final String value) throws ElementNotFoundException {
474:
475: final Iterator iterator = getAllHtmlChildElements();
476: while (iterator.hasNext()) {
477: final HtmlElement element = (HtmlElement) iterator.next();
478:
479: if (element instanceof HtmlRadioButtonInput
480: && element.getAttributeValue("name").equals(name)) {
481:
482: final HtmlRadioButtonInput input = (HtmlRadioButtonInput) element;
483: if (input.getValueAttribute().equals(value)) {
484: return input;
485: }
486: }
487: }
488: throw new ElementNotFoundException("input", "value", value);
489: }
490:
491: /**
492: * Return all the HtmlSelect that match the specified name
493: *
494: * @param name The name
495: * @return See above
496: */
497: public List getSelectsByName(final String name) {
498: return getHtmlElementsByAttribute("select", "name", name);
499: }
500:
501: /**
502: * Find the first select element with the specified name
503: * @param name The name of the select element
504: * @return The first select.
505: * @throws ElementNotFoundException If the select cannot be found.
506: */
507: public HtmlSelect getSelectByName(final String name)
508: throws ElementNotFoundException {
509: final List list = getSelectsByName(name);
510: if (list.isEmpty()) {
511: throw new ElementNotFoundException("select", "name", name);
512: } else {
513: return (HtmlSelect) list.get(0);
514: }
515: }
516:
517: /**
518: * Return all the HtmlButtons that match the specified name
519: *
520: * @param name The name
521: * @return See above
522: * @exception ElementNotFoundException If no matching buttons were found
523: */
524: public List getButtonsByName(final String name)
525: throws ElementNotFoundException {
526: return getHtmlElementsByAttribute("button", "name", name);
527: }
528:
529: /**
530: * Find the first button element with the specified name.
531: * @param name The name of the button element.
532: * @return The first button.
533: * @throws ElementNotFoundException If the button cannot be found.
534: */
535: public HtmlButton getButtonByName(final String name)
536: throws ElementNotFoundException {
537: final List list = getButtonsByName(name);
538: if (list.isEmpty()) {
539: throw new ElementNotFoundException("button", "name", name);
540: } else {
541: return (HtmlButton) list.get(0);
542: }
543: }
544:
545: /**
546: * Return all the HtmlTextAreas that match the specified name
547: *
548: * @param name The name
549: * @return See above
550: */
551: public List getTextAreasByName(final String name) {
552: return getHtmlElementsByAttribute("textarea", "name", name);
553: }
554:
555: /**
556: * Find the first textarea element with the specified name.
557: * @param name The name of the textarea element.
558: * @return The first textarea.
559: * @throws ElementNotFoundException If the textarea cannot be found.
560: */
561: public HtmlTextArea getTextAreaByName(final String name)
562: throws ElementNotFoundException {
563: final List list = getTextAreasByName(name);
564: if (list.isEmpty()) {
565: throw new ElementNotFoundException("textarea", "name", name);
566: } else {
567: return (HtmlTextArea) list.get(0);
568: }
569: }
570:
571: /**
572: * Return a list of HtmlInputs that are of type radio and match the specified name
573: *
574: * @param name The name
575: * @return See above
576: */
577: public List getRadioButtonsByName(final String name) {
578: Assert.notNull("name", name);
579:
580: final List results = new ArrayList();
581:
582: final Iterator iterator = getAllHtmlChildElements();
583: while (iterator.hasNext()) {
584: final HtmlElement element = (HtmlElement) iterator.next();
585: if (element instanceof HtmlRadioButtonInput
586: && element.getAttributeValue("name").equals(name)) {
587: results.add(element);
588: }
589: }
590:
591: return results;
592: }
593:
594: /**
595: * Select the specified radio button in the form. <p/>
596: *
597: * Only a radio button that is actually contained in the form can be
598: * selected. If you need to be able to select a button that really isn't
599: * there (ie during testing of error cases) then use {@link #fakeCheckedRadioButton(String,String)} instead
600: *
601: * @param name The name of the radio buttons
602: * @param value The value to match
603: * @exception ElementNotFoundException If the specified element could not be found
604: *
605: * @deprecated Deprecated because 'name' and 'value' are sometimes not unique to select a single
606: * HtmlRadioButtonInput, it should not be called,
607: * you can use {@link #getByXPath(String)} instead.
608: */
609: //TODO: to be removed, deprecated after 1.11
610: public void setCheckedRadioButton(final String name,
611: final String value) throws ElementNotFoundException {
612:
613: //we could do this with one iterator, but that would set the state of the other
614: //radios also in the case where the specified one is not found
615: final HtmlInput inputToSelect = getRadioButtonInput(name, value);
616:
617: final Iterator iterator = getAllHtmlChildElements();
618: while (iterator.hasNext()) {
619: final HtmlElement element = (HtmlElement) iterator.next();
620: if (element instanceof HtmlRadioButtonInput
621: && element.getAttributeValue("name").equals(name)) {
622:
623: final HtmlRadioButtonInput input = (HtmlRadioButtonInput) element;
624: if (input == inputToSelect) {
625: input.setAttributeValue("checked", "checked");
626: } else {
627: input.removeAttribute("checked");
628: }
629: }
630: }
631: }
632:
633: /**
634: * Select the specified radio button in the form.
635: *
636: * Only a radio button that is actually contained in the form can be selected.
637: *
638: * @param radioButtonInput The radio Button
639: */
640: void setCheckedRadioButton(
641: final HtmlRadioButtonInput radioButtonInput) {
642: try {
643: if (!isAncestorOf(radioButtonInput)) {
644: throw new IllegalArgumentException(
645: "HtmlRadioButtonInput is not child of this HtmlForm");
646: }
647: final Iterator iterator = getByXPath(
648: "//input[lower-case(@type)='radio' and @name='"
649: + radioButtonInput.getNameAttribute()
650: + "']").iterator();
651:
652: while (iterator.hasNext()) {
653: final HtmlRadioButtonInput input = (HtmlRadioButtonInput) iterator
654: .next();
655: if (input == radioButtonInput) {
656: input.setAttributeValue("checked", "checked");
657: } else {
658: input.removeAttribute("checked");
659: }
660: }
661: } catch (final JaxenException e) {
662: getLog().error(e);
663: }
664: }
665:
666: /**
667: * Set the "selected radio button" to a value that doesn't actually exist
668: * in the page. This is useful primarily for testing error cases.
669: *
670: * @param name The name of the radio buttons
671: * @param value The value to match
672: * @exception ElementNotFoundException If a particular xml element could not be found in the dom model
673: * @deprecated after 1.11
674: */
675: // it can be made package private if needed for testing.
676: public final void fakeCheckedRadioButton(final String name,
677: final String value) throws ElementNotFoundException {
678:
679: fakeSelectedRadioButton_ = new KeyValuePair(name, value);
680: }
681:
682: /**
683: * @deprecated
684: */
685: private void adjustParameterListToAccountForFakeSelectedRadioButton(
686: final List list) {
687: final String fakeRadioButtonName = fakeSelectedRadioButton_
688: .getKey();
689:
690: // Remove any pairs that match the name of the radio button
691: final Iterator iterator = list.iterator();
692: while (iterator.hasNext()) {
693: final KeyValuePair pair = (KeyValuePair) iterator.next();
694: if (pair.getKey().equals(fakeRadioButtonName)) {
695: iterator.remove();
696: }
697: }
698:
699: // Now add this one back in
700: list.add(fakeSelectedRadioButton_);
701: }
702:
703: /**
704: * Return the first checked radio button with the specified name. If none of
705: * the radio buttons by that name are checked then return null.
706: *
707: * @param name The name of the radio button
708: * @return The first checked radio button.
709: */
710: public HtmlRadioButtonInput getCheckedRadioButton(final String name) {
711: Assert.notNull("name", name);
712:
713: final Iterator iterator = getAllHtmlChildElements();
714: while (iterator.hasNext()) {
715: final HtmlElement element = (HtmlElement) iterator.next();
716: if (element instanceof HtmlRadioButtonInput
717: && element.getAttributeValue("name").equals(name)) {
718:
719: final HtmlRadioButtonInput input = (HtmlRadioButtonInput) element;
720: if (input.isChecked()) {
721: return input;
722: }
723: }
724: }
725: return null;
726: }
727:
728: /**
729: * Return the value of the attribute "action". Refer to the <a
730: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for
731: * details on the use of this attribute.
732: *
733: * @return The value of the attribute "action" or an empty string if that attribute isn't defined.
734: */
735: public final String getActionAttribute() {
736: return getAttributeValue("action");
737: }
738:
739: /**
740: * Set the value of the attribute "action". Refer to the <a
741: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for
742: * details on the use of this attribute.
743: *
744: * @param action The value of the attribute "action"
745: */
746: public final void setActionAttribute(final String action) {
747: setAttributeValue("action", action);
748: }
749:
750: /**
751: * Return the value of the attribute "method". Refer to the <a
752: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for
753: * details on the use of this attribute.
754: *
755: * @return The value of the attribute "method" or an empty string if that
756: * attribute isn't defined.
757: */
758: public final String getMethodAttribute() {
759: return getAttributeValue("method");
760: }
761:
762: /**
763: * Set the value of the attribute "method". Refer to the <a
764: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for
765: * details on the use of this attribute.
766: *
767: * @param method The value of the attribute "method" or an empty string if that attribute isn't defined.
768: */
769: public final void setMethodAttribute(final String method) {
770: setAttributeValue("method", method);
771: }
772:
773: /**
774: * Return the value of the attribute "name". Refer to the <a
775: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for
776: * details on the use of this attribute.
777: *
778: * @return The value of the attribute "name" or an empty string if that attribute isn't defined.
779: */
780: public final String getNameAttribute() {
781: return getAttributeValue("name");
782: }
783:
784: /**
785: * Set the value of the attribute "name". Refer to the <a
786: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for details on the use of this attribute.<p>
787: *
788: * @param name the new value
789: */
790: public final void setNameAttribute(final String name) {
791: setAttributeValue("name", name);
792: }
793:
794: /**
795: * Return the value of the attribute "enctype". Refer to the <a
796: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for details on the use of this attribute.<p>
797: *
798: * Enctype is the encoding type used when submitting a form back to the server
799: *
800: * @return The value of the attribute "enctype" or an empty string if that attribute isn't defined.
801: */
802: public final String getEnctypeAttribute() {
803: return getAttributeValue("enctype");
804: }
805:
806: /**
807: * Set the value of the attribute "enctype". Refer to the <a
808: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for
809: * details on the use of this attribute.<p>
810: *
811: * Enctype is the encoding type used when submitting a form back to the server
812: *
813: * @param encoding The value of the attribute "enctype" or an empty string if that attribute isn't defined.
814: */
815: public final void setEnctypeAttribute(final String encoding) {
816: setAttributeValue("enctype", encoding);
817: }
818:
819: /**
820: * Return the value of the attribute "onsubmit". Refer to the <a
821: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for
822: * details on the use of this attribute.
823: *
824: * @return The value of the attribute "onsubmit" or an empty string if that attribute isn't defined.
825: */
826: public final String getOnSubmitAttribute() {
827: return getAttributeValue("onsubmit");
828: }
829:
830: /**
831: * Return the value of the attribute "onreset". Refer to the <a
832: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for details on the use of this attribute.
833: *
834: * @return The value of the attribute "onreset" or an empty string if that attribute isn't defined.
835: */
836: public final String getOnResetAttribute() {
837: return getAttributeValue("onreset");
838: }
839:
840: /**
841: * Return the value of the attribute "accept". Refer to the <a
842: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for details on the use of this attribute.
843: *
844: * @return The value of the attribute "accept" or an empty string if that attribute isn't defined.
845: */
846: public final String getAcceptAttribute() {
847: return getAttributeValue("accept");
848: }
849:
850: /**
851: * Return the value of the attribute "accept-charset". Refer to the <a
852: * href='http://www.w3.org/TR/html401/interact/forms.html#adef-accept-charset'>
853: * HTML 4.01</a> documentation for details on the use of this attribute.
854: *
855: * @return The value of the attribute "accept-charset" or an empty string if that attribute isn't defined.
856: */
857: public final String getAcceptCharsetAttribute() {
858: return getAttributeValue("accept-charset");
859: }
860:
861: /**
862: * Return the value of the attribute "target". Refer to the <a
863: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for details on the use of this attribute.
864: *
865: * @return The value of the attribute "target" or an empty string if that attribute isn't defined.
866: */
867: public final String getTargetAttribute() {
868: return getAttributeValue("target");
869: }
870:
871: /**
872: * Set the value of the attribute "target". Refer to the <a
873: * href='http://www.w3.org/TR/html401/'>HTML 4.01</a> documentation for details on the use of this attribute.
874: *
875: * @param target The value of the attribute "target" or an empty string if that attribute isn't defined.
876: */
877: public final void setTargetAttribute(final String target) {
878: setAttributeValue("target", target);
879: }
880:
881: /**
882: * Return the first input with the specified value.
883: * @param value The value
884: * @return The first input with the specified value.
885: * @throws ElementNotFoundException If no elements can be found with the specified value.
886: */
887: public HtmlInput getInputByValue(final String value)
888: throws ElementNotFoundException {
889: return (HtmlInput) getOneHtmlElementByAttribute("input",
890: "value", value);
891: }
892:
893: /**
894: * Return all the inputs with the specified value.
895: * @param value The value
896: * @return all the inputs with the specified value.
897: */
898: public List getInputsByValue(final String value) {
899: return getHtmlElementsByAttribute("input", "value", value);
900: }
901: }
|