View Javadoc
1   /*
2    * Copyright (c) 2002-2017 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    * http://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 com.gargoylesoftware.htmlunit.javascript.host.html;
16  
17  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.HTMLOPTION_REMOVE_SELECTED_ATTRIB_DESELECTS;
18  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
19  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
20  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF;
21  
22  import org.xml.sax.helpers.AttributesImpl;
23  
24  import com.gargoylesoftware.htmlunit.html.DomElement;
25  import com.gargoylesoftware.htmlunit.html.DomNode;
26  import com.gargoylesoftware.htmlunit.html.DomText;
27  import com.gargoylesoftware.htmlunit.html.HTMLParser;
28  import com.gargoylesoftware.htmlunit.html.HtmlForm;
29  import com.gargoylesoftware.htmlunit.html.HtmlOption;
30  import com.gargoylesoftware.htmlunit.html.HtmlOptionGroup;
31  import com.gargoylesoftware.htmlunit.html.HtmlPage;
32  import com.gargoylesoftware.htmlunit.html.HtmlSelect;
33  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
34  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
35  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
36  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
37  
38  /**
39   * The JavaScript object that represents an option.
40   *
41   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
42   * @author David K. Taylor
43   * @author Chris Erskine
44   * @author Marc Guillemot
45   * @author Ahmed Ashour
46   * @author Ronald Brill
47   * @author Frank Danek
48   */
49  @JsxClass(domClass = HtmlOption.class)
50  public class HTMLOptionElement extends HTMLElement {
51  
52      /**
53       * JavaScript constructor.
54       * @param newText the text
55       * @param newValue the value
56       * @param defaultSelected Whether the option is initially selected
57       * @param selected the current selection state of the option
58       */
59      @JsxConstructor({CHROME, FF, EDGE})
60      public void jsConstructor(final String newText, final String newValue,
61              final boolean defaultSelected, final boolean selected) {
62          final HtmlPage page = (HtmlPage) getWindow().getWebWindow().getEnclosedPage();
63          AttributesImpl attributes = null;
64          if (defaultSelected) {
65              attributes = new AttributesImpl();
66              attributes.addAttribute(null, "selected", "selected", null, "selected");
67          }
68  
69          final HtmlOption htmlOption = (HtmlOption) HTMLParser.getFactory(HtmlOption.TAG_NAME).createElement(
70                  page, HtmlOption.TAG_NAME, attributes);
71          htmlOption.setSelected(selected);
72          setDomNode(htmlOption);
73  
74          if (!"undefined".equals(newText)) {
75              htmlOption.appendChild(new DomText(page, newText));
76              htmlOption.setLabelAttribute(newText);
77          }
78          if (!"undefined".equals(newValue)) {
79              htmlOption.setValueAttribute(newValue);
80          }
81      }
82  
83      /**
84       * Returns the value of the {@code value} property.
85       * @return the value property
86       */
87      @JsxGetter
88      public String getValue() {
89          String value = getDomNodeOrNull().getAttribute("value");
90          if (value == DomElement.ATTRIBUTE_NOT_DEFINED) {
91              value = ((HtmlOption) getDomNodeOrNull()).getText();
92          }
93          return value;
94      }
95  
96      /**
97       * Sets the value of the {@code value} property.
98       * @param newValue the value property
99       */
100     @JsxSetter
101     public void setValue(final String newValue) {
102         final DomNode dom = getDomNodeOrNull();
103         if (dom instanceof HtmlOption) {
104             ((HtmlOption) dom).setValueAttribute(newValue);
105         }
106     }
107 
108     /**
109      * Returns the value of the {@code text} property.
110      * @return the text property
111      */
112     @JsxGetter
113     public String getText() {
114         final DomNode dom = getDomNodeOrNull();
115         if (dom instanceof HtmlOption) {
116             return ((HtmlOption) dom).getText();
117         }
118         return null;
119     }
120 
121     /**
122      * Sets the value of the {@code text} property.
123      * @param newText the text property
124      */
125     @JsxSetter
126     public void setText(final String newText) {
127         final DomNode dom = getDomNodeOrNull();
128         if (dom instanceof HtmlOption) {
129             ((HtmlOption) dom).setText(newText);
130 
131             if (!hasAttribute("label")) {
132                 setLabel(newText);
133             }
134         }
135     }
136 
137     /**
138      * Returns the value of the {@code selected} property.
139      * @return the text property
140      */
141     @JsxGetter
142     public boolean isSelected() {
143         final DomNode dom = getDomNodeOrNull();
144         if (dom instanceof HtmlOption) {
145             return ((HtmlOption) dom).isSelected();
146         }
147         return false;
148     }
149 
150     /**
151      * Sets the value of the {@code selected} property.
152      * @param selected the new selected property
153      */
154     @JsxSetter
155     public void setSelected(final boolean selected) {
156         final HtmlOption optionNode = (HtmlOption) getDomNodeOrNull();
157         final HtmlSelect enclosingSelect = optionNode.getEnclosingSelect();
158         if (!selected && optionNode.isSelected()
159                 && enclosingSelect != null && !enclosingSelect.isMultipleSelectEnabled()) {
160             enclosingSelect.getOption(0).setSelectedFromJavaScript(true);
161         }
162         else {
163             optionNode.setSelectedFromJavaScript(selected);
164         }
165     }
166 
167     /**
168      * Returns the value of the {@code defaultSelected} property.
169      * @return the text property
170      */
171     @JsxGetter
172     public boolean isDefaultSelected() {
173         final DomNode dom = getDomNodeOrNull();
174         if (dom instanceof HtmlOption) {
175             return ((HtmlOption) dom).isDefaultSelected();
176         }
177         return false;
178     }
179 
180     /**
181      * Returns the value of the {@code label} property.
182      * @return the label property
183      */
184     @JsxGetter
185     public String getLabel() {
186         final DomNode domNode = getDomNodeOrNull();
187         if (domNode instanceof HtmlOption) {
188             return ((HtmlOption) domNode).getLabelAttribute();
189         }
190         return ((HtmlOptionGroup) domNode).getLabelAttribute();
191     }
192 
193     /**
194      * Sets the value of the {@code label} property.
195      * @param label the new label property
196      */
197     @JsxSetter
198     public void setLabel(final String label) {
199         final DomNode domNode = getDomNodeOrNull();
200         if (domNode instanceof HtmlOption) {
201             ((HtmlOption) domNode).setLabelAttribute(label);
202         }
203         else {
204             ((HtmlOptionGroup) domNode).setLabelAttribute(label);
205         }
206     }
207 
208     /**
209      * {@inheritDoc} Overridden to modify browser configurations.
210      */
211     @Override
212     @JsxGetter
213     public boolean isDisabled() {
214         return super.isDisabled();
215     }
216 
217     /**
218      * {@inheritDoc} Overridden to modify browser configurations.
219      */
220     @Override
221     @JsxSetter
222     public void setDisabled(final boolean disabled) {
223         super.setDisabled(disabled);
224     }
225 
226     /**
227      * Returns the {@code index} property.
228      * @return the {@code index} property
229      */
230     @JsxGetter
231     public int getIndex() {
232         final HtmlOption optionNode = (HtmlOption) getDomNodeOrNull();
233         if (optionNode != null) {
234             final HtmlSelect enclosingSelect = optionNode.getEnclosingSelect();
235             if (enclosingSelect != null) {
236                 return enclosingSelect.indexOf(optionNode);
237             }
238         }
239         return 0;
240     }
241 
242     /**
243      * {@inheritDoc}
244      */
245     @Override
246     public void setAttribute(final String name, final String value) {
247         super.setAttribute(name, value);
248         if ("selected".equals(name)) {
249             setSelected(true);
250         }
251     }
252 
253     /**
254      * {@inheritDoc}
255      */
256     @Override
257     public void removeAttribute(final String name) {
258         super.removeAttribute(name);
259         if (getBrowserVersion().hasFeature(HTMLOPTION_REMOVE_SELECTED_ATTRIB_DESELECTS)) {
260             if ("selected".equals(name)) {
261                 setSelected(false);
262             }
263         }
264     }
265 
266     /**
267      * Returns the value of the JavaScript {@code form} attribute.
268      *
269      * @return the value of the JavaScript {@code form} attribute
270      */
271     @JsxGetter
272     public HTMLFormElement getForm() {
273         final HtmlForm form = getDomNodeOrDie().getEnclosingForm();
274         if (form == null) {
275             return null;
276         }
277         return (HTMLFormElement) getScriptableFor(form);
278     }
279 }