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.util.Map;
042:
043: import com.gargoylesoftware.htmlunit.Page;
044:
045: /**
046: * Wrapper for the html element "option"
047: *
048: * @version $Revision: 2132 $
049: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
050: * @author David K. Taylor
051: * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
052: * @author David D. Kilzer
053: * @author Marc Guillemot
054: * @author Ahmed Ashour
055: */
056: public class HtmlOption extends ClickableElement implements
057: DisabledElement {
058:
059: private static final long serialVersionUID = 8995198439134305753L;
060:
061: /** the HTML tag represented by this element */
062: public static final String TAG_NAME = "option";
063:
064: private final boolean initialSelectedState_;
065:
066: /**
067: * Create an instance
068: *
069: * @param page The page that contains this element
070: * @param attributes the initial attributes
071: * @deprecated You should not directly construct HtmlOption.
072: */
073: //TODO: to be removed, deprecated after 1.11
074: public HtmlOption(final HtmlPage page, final Map attributes) {
075: this (null, TAG_NAME, page, attributes);
076: }
077:
078: /**
079: * Create an instance
080: *
081: * @param namespaceURI the URI that identifies an XML namespace.
082: * @param qualifiedName The qualified name of the element type to instantiate
083: * @param page The page that contains this element
084: * @param attributes the initial attributes
085: */
086: HtmlOption(final String namespaceURI, final String qualifiedName,
087: final HtmlPage page, final Map attributes) {
088: super (namespaceURI, qualifiedName, page, attributes);
089: initialSelectedState_ = isAttributeDefined("selected");
090: }
091:
092: /**
093: * Return true if this option is currently selected
094: *
095: * @return See above
096: */
097: public boolean isSelected() {
098: return isAttributeDefined("selected");
099: }
100:
101: /**
102: * Set the selected state of this option. This will possibly also change the
103: * selected properties of sibling option elements
104: *
105: * @param selected true if this option should be selected.
106: * @return The page that occupies this window after this change is made. It
107: * may be the same window or it may be a freshly loaded one.
108: */
109: public Page setSelected(boolean selected) {
110: if (selected == isSelected()) {
111: return getPage();
112: } else {
113: final HtmlSelect select = getEnclosingSelect();
114: if (select != null) {
115: if (!select.isMultipleSelectEnabled()
116: && select.getOptionSize() == 1) {
117: selected = true;
118: }
119: return select.setSelectedAttribute(this , selected);
120: } else {
121: // for instance from JS for an option created by document.createElement('option')
122: // and not yet added to a select
123: setSelectedInternal(selected);
124: return getPage();
125: }
126: }
127: }
128:
129: /**
130: * {@inheritDoc}
131: * @see DomNode#insertBefore(DomNode)
132: */
133: public void insertBefore(final DomNode newNode)
134: throws IllegalStateException {
135: super .insertBefore(newNode);
136: if (newNode instanceof HtmlOption) {
137: final HtmlOption option = (HtmlOption) newNode;
138: if (option.isSelected()) {
139: getEnclosingSelect().setSelectedAttribute(option, true);
140: }
141: }
142: }
143:
144: /**
145: * Gets the enclosing select of this option
146: * @return <code>null</code> if no select is found (for instance malformed html)
147: */
148: public HtmlSelect getEnclosingSelect() {
149: return (HtmlSelect) getEnclosingElement("select");
150: }
151:
152: /**
153: * Reset the option to its original selected state.
154: */
155: public void reset() {
156: setSelectedInternal(initialSelectedState_);
157: }
158:
159: /**
160: * Return the value of the attribute "selected". Refer to the
161: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
162: * documentation for details on the use of this attribute.
163: *
164: * @return The value of the attribute "selected"
165: * or an empty string if that attribute isn't defined.
166: */
167: public final String getSelectedAttribute() {
168: return getAttributeValue("selected");
169: }
170:
171: /**
172: * Return whether this Option is selected by default.
173: * That is whether the "selected"
174: * attribute exists when the Option is constructed. This also determines
175: * the value of getSelectedAttribute() after a reset() on the form.
176: * @return whether the option is selected by default.
177: */
178: public final boolean isDefaultSelected() {
179: return initialSelectedState_;
180: }
181:
182: /**
183: * Return true if the disabled attribute is set for this element.
184: *
185: * @return Return true if this element is disabled.
186: */
187: public final boolean isDisabled() {
188: return isAttributeDefined("disabled");
189: }
190:
191: /**
192: * Return the value of the attribute "disabled". 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 "disabled"
197: * or an empty string if that attribute isn't defined.
198: */
199: public final String getDisabledAttribute() {
200: return getAttributeValue("disabled");
201: }
202:
203: /**
204: * Return the value of the attribute "label". Refer to the
205: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
206: * documentation for details on the use of this attribute.
207: *
208: * @return The value of the attribute "label"
209: * or an empty string if that attribute isn't defined.
210: */
211: public final String getLabelAttribute() {
212: return getAttributeValue("label");
213: }
214:
215: /**
216: * Set the value of the attribute "label". Refer to the
217: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
218: * documentation for details on the use of this attribute.
219: *
220: * @param newLabel The value of the attribute "label".
221: */
222: public final void setLabelAttribute(final String newLabel) {
223: setAttributeValue("label", newLabel);
224: }
225:
226: /**
227: * Return the value of the attribute "value". Refer to the
228: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
229: * documentation for details on the use of this attribute.
230: * @see <a href="http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#adef-value-OPTION">
231: * initial value if value attribute is not set</a>
232: * @return The value of the attribute "value"
233: */
234: public final String getValueAttribute() {
235: return getAttributeValue("value");
236: }
237:
238: /**
239: * Set the value of the attribute "value". Refer to the
240: * <a href='http://www.w3.org/TR/html401/'>HTML 4.01</a>
241: * documentation for details on the use of this attribute.
242: *
243: * @param newValue The value of the attribute "value".
244: */
245: public final void setValueAttribute(final String newValue) {
246: setAttributeValue("value", newValue);
247: }
248:
249: /**
250: * Selects the option if it's not already selected.
251: * {@inheritDoc}
252: */
253: protected Page doClickAction(final Page defaultPage)
254: throws IOException {
255: if (!isSelected()) {
256: return setSelected(true);
257: }
258: return defaultPage;
259: }
260:
261: /**
262: * {@inheritDoc}
263: */
264: public DomNode appendDomChild(final DomNode node) {
265: final DomNode addedNode = super .appendDomChild(node);
266:
267: // default value is the text of the option
268: // see http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#adef-value-OPTION
269: if (getAttributeValue("value") == ATTRIBUTE_NOT_DEFINED) {
270: setAttributeValue("value", asText());
271: }
272:
273: return addedNode;
274: }
275:
276: /**
277: * For internal use only.
278: * Sets/remove the selected attribute to reflect the select state
279: * @param selected the selected status
280: */
281: void setSelectedInternal(final boolean selected) {
282: if (selected) {
283: setAttributeValue("selected", "selected");
284: } else {
285: removeAttribute("selected");
286: }
287: }
288:
289: /**
290: * {@inheritDoc}
291: * This implementation will show the label attribute before the
292: * content of the tag if the attribute exists.
293: */
294: public String asText() {
295: if (getLabelAttribute() != ATTRIBUTE_NOT_DEFINED) {
296: return getLabelAttribute();
297: }
298: return super.asText();
299: }
300: }
|