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