1 /*
2 * Copyright (c) 2002-2026 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.dom;
16
17 import org.htmlunit.corejs.javascript.Scriptable;
18 import org.htmlunit.html.DomNode;
19 import org.htmlunit.html.HtmlRadioButtonInput;
20 import org.htmlunit.javascript.JavaScriptEngine;
21 import org.htmlunit.javascript.configuration.JsxClass;
22 import org.htmlunit.javascript.configuration.JsxConstructor;
23 import org.htmlunit.javascript.configuration.JsxGetter;
24 import org.htmlunit.javascript.configuration.JsxSetter;
25 import org.htmlunit.javascript.configuration.JsxSymbol;
26
27 import java.util.List;
28
29 import static org.htmlunit.html.DomElement.ATTRIBUTE_NOT_DEFINED;
30
31 /**
32 * A JavaScript object for {@code RadioNodeList}.
33 *
34 * @author Ahmed Ashour
35 * @author Ronald Brill
36 * @author Lai Quang Duong
37 *
38 * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/RadioNodeList">MDN Documentation</a>
39 */
40 @JsxClass
41 public class RadioNodeList extends NodeList {
42
43 /**
44 * Creates an instance.
45 */
46 public RadioNodeList() {
47 super();
48 }
49
50 /**
51 * Creates an instance.
52 *
53 * @param domNode the {@link DomNode}
54 */
55 public RadioNodeList(final DomNode domNode) {
56 super(domNode, true);
57 }
58
59 /**
60 * Creates an instance.
61 *
62 * @param domNode the {@link DomNode}
63 * @param attributeChangeSensitive indicates if the content of the collection may change when an attribute
64 * of a descendant node of domNode changes (attribute added, modified or removed)
65 */
66 public RadioNodeList(final DomNode domNode, final boolean attributeChangeSensitive) {
67 super(domNode, attributeChangeSensitive);
68 }
69
70 /**
71 * Constructs an instance with an initial cache value.
72 * @param domNode the parent scope, on which we listen for changes
73 * @param initialElements the initial content for the cache
74 */
75 public RadioNodeList(final DomNode domNode, final List<DomNode> initialElements) {
76 super(domNode, initialElements);
77 }
78
79 /**
80 * JavaScript constructor.
81 */
82 @Override
83 @JsxConstructor
84 public void jsConstructor() {
85 super.jsConstructor();
86 }
87
88 /**
89 * Returns the value of the first checked radio button represented by radioNodeList.
90 * @return the value of the first checked radio button represented by radioNodeList ("on" if value attribute
91 * is not defined) or an empty string if no radio button is checked.
92 * @see <a href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#the-htmlformcontrolscollection-interface">HTML Standard</a>
93 */
94 @JsxGetter
95 public String getValue() {
96 for (final DomNode node : getElements()) {
97 if (node instanceof HtmlRadioButtonInput input && input.isChecked()) {
98 final String value = input.getValueAttribute();
99 return value == ATTRIBUTE_NOT_DEFINED ? "on" : value;
100 }
101 }
102
103 return "";
104 }
105
106 /**
107 * Checks the first radio button represented by radioNodeList that has value equal the specified value.
108 * @param newValue the value of the radio button to be checked.
109 * @see <a href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#the-htmlformcontrolscollection-interface">HTML Standard</a>
110 */
111 @JsxSetter
112 public void setValue(final String newValue) {
113 for (final DomNode node : getElements()) {
114 if (node instanceof HtmlRadioButtonInput input) {
115 String value = input.getValueAttribute();
116 if (value == ATTRIBUTE_NOT_DEFINED) {
117 value = "on";
118 }
119 if (newValue.equals(value)) {
120 input.setChecked(true);
121 break;
122 }
123 }
124 }
125 }
126
127 /**
128 * Returns the {@code Symbol.iterator} function that allows iterating over this collection.
129 * @return the Iterator symbol
130 */
131 @JsxSymbol
132 public Scriptable iterator() {
133 return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
134 }
135 }