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 org.htmlunit.corejs.javascript.Scriptable;
18 import org.htmlunit.html.DomElement;
19 import org.htmlunit.html.DomNode;
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.JsxFunction;
24 import org.htmlunit.javascript.configuration.JsxSymbol;
25 import org.htmlunit.javascript.host.dom.RadioNodeList;
26
27 import java.util.ArrayList;
28 import java.util.List;
29
30 /**
31 * A JavaScript object for {@code HTMLFormControlsCollection}.
32 *
33 * @author Ahmed Ashour
34 * @author Ronald Brill
35 * @author Lai Quang Duong
36 */
37 @JsxClass
38 public class HTMLFormControlsCollection extends HTMLCollection {
39
40 /**
41 * Creates an instance.
42 */
43 public HTMLFormControlsCollection() {
44 super();
45 }
46
47 /**
48 * Creates an instance.
49 * @param domNode parent scope
50 * @param attributeChangeSensitive indicates if the content of the collection may change when an attribute
51 * of a descendant node of parentScope changes (attribute added, modified or removed)
52 */
53 public HTMLFormControlsCollection(final DomNode domNode, final boolean attributeChangeSensitive) {
54 super(domNode, attributeChangeSensitive);
55 }
56
57 /**
58 * Constructs an instance with an initial cache value.
59 * @param domNode the parent scope, on which we listen for changes
60 * @param initialElements the initial content for the cache
61 */
62 HTMLFormControlsCollection(final DomNode domNode, final List<DomNode> initialElements) {
63 super(domNode, initialElements);
64 }
65
66 /**
67 * JavaScript constructor.
68 */
69 @Override
70 @JsxConstructor
71 public void jsConstructor() {
72 super.jsConstructor();
73 }
74
75 /**
76 * Returns the element with ID or name match the specified value from the collection.
77 * If there are multiple matching elements, then a RadioNodeList object containing all those elements is returned.
78 * @param name the name or id the element or elements to return
79 * @return the element or elements corresponding to the specified name or id
80 * @see <a href="https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#the-htmlformcontrolscollection-interface">HTML Standard</a>
81 */
82 @Override
83 @JsxFunction
84 public Scriptable namedItem(final String name) {
85 if (name.isEmpty()) {
86 return null;
87 }
88
89 final List<DomNode> elements = new ArrayList<>();
90 for (final Object next : getElements()) {
91 if (next instanceof DomElement) {
92 final DomElement elem = (DomElement) next;
93 final String nodeName = elem.getAttributeDirect(DomElement.NAME_ATTRIBUTE);
94 if (name.equals(nodeName)) {
95 elements.add(elem);
96 continue;
97 }
98
99 final String id = elem.getId();
100 if (name.equals(id)) {
101 elements.add(elem);
102 }
103 }
104 }
105
106 if (elements.isEmpty()) {
107 return null;
108 }
109 if (elements.size() == 1) {
110 return getScriptableForElement(elements.get(0));
111 }
112
113 final RadioNodeList nodeList = new RadioNodeList(getDomNodeOrDie(), elements);
114 nodeList.setElementsSupplier(getElementSupplier());
115 return nodeList;
116 }
117
118 @JsxSymbol
119 @Override
120 public Scriptable iterator() {
121 return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
122 }
123 }