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 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 }