1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.html;
16
17 import static org.htmlunit.BrowserVersionFeatures.HTMLCOLLECTION_NAMED_ITEM_ID_FIRST;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.htmlunit.BrowserVersion;
24 import org.htmlunit.corejs.javascript.Scriptable;
25 import org.htmlunit.html.DomElement;
26 import org.htmlunit.html.DomNode;
27 import org.htmlunit.html.HtmlForm;
28 import org.htmlunit.html.HtmlInput;
29 import org.htmlunit.javascript.JavaScriptEngine;
30 import org.htmlunit.javascript.configuration.JsxClass;
31 import org.htmlunit.javascript.configuration.JsxConstructor;
32 import org.htmlunit.javascript.configuration.JsxFunction;
33 import org.htmlunit.javascript.configuration.JsxGetter;
34 import org.htmlunit.javascript.configuration.JsxSymbol;
35 import org.htmlunit.javascript.host.dom.AbstractList;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 @JsxClass
56 public class HTMLCollection extends AbstractList {
57
58
59
60
61 public HTMLCollection() {
62 super();
63 }
64
65
66
67
68 @JsxConstructor
69 public void jsConstructor() {
70
71 }
72
73
74
75
76
77
78
79 public HTMLCollection(final DomNode domNode, final boolean attributeChangeSensitive) {
80 super(domNode, attributeChangeSensitive, null);
81 }
82
83
84
85
86
87
88 HTMLCollection(final DomNode domNode, final List<DomNode> initialElements) {
89 super(domNode, true, new ArrayList<>(initialElements));
90 }
91
92 private HTMLCollection(final DomNode domNode, final boolean attributeChangeSensitive,
93 final List<DomNode> initialElements) {
94 super(domNode, attributeChangeSensitive, new ArrayList<>(initialElements));
95 }
96
97
98
99
100
101
102 public static HTMLCollection emptyCollection(final DomNode domNode) {
103 return new HTMLCollection(domNode, false, Collections.emptyList());
104 }
105
106
107
108
109 @Override
110 protected HTMLCollection create(final DomNode parentScope, final List<DomNode> initialElements) {
111 return new HTMLCollection(parentScope, initialElements);
112 }
113
114
115
116
117
118 @JsxSymbol
119 public Scriptable iterator() {
120 return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
121 }
122
123
124
125
126
127 @JsxGetter
128 @Override
129 public final int getLength() {
130 return super.getLength();
131 }
132
133
134
135
136 @Override
137 protected Object getWithPreemptionByName(final String name, final List<DomNode> elements) {
138 final List<DomNode> matchingElements = new ArrayList<>();
139 final boolean searchName = isGetWithPreemptionSearchName();
140 for (final DomNode next : elements) {
141 if (next instanceof DomElement element
142 && (searchName || next instanceof HtmlInput || next instanceof HtmlForm)) {
143 final String nodeName = element.getAttributeDirect(DomElement.NAME_ATTRIBUTE);
144 if (name.equals(nodeName)) {
145 matchingElements.add(next);
146 }
147 }
148 }
149
150 if (matchingElements.isEmpty()) {
151 return NOT_FOUND;
152 }
153
154 if (matchingElements.size() == 1) {
155 return getScriptableForElement(matchingElements.get(0));
156 }
157
158
159 final DomNode domNode = getDomNodeOrNull();
160 final HTMLCollection collection = new HTMLCollection(domNode, matchingElements);
161 collection.setAvoidObjectDetection(true);
162 return collection;
163 }
164
165
166
167
168
169 protected boolean isGetWithPreemptionSearchName() {
170 return true;
171 }
172
173
174
175
176
177
178
179 @JsxFunction
180 public Object item(final Object index) {
181 int idx = 0;
182 final double doubleValue = JavaScriptEngine.toNumber(index);
183 if (!Double.isNaN(doubleValue)) {
184 idx = (int) doubleValue;
185 }
186
187 final Object object = get(idx, this);
188 if (object == NOT_FOUND) {
189 return null;
190 }
191 return object;
192 }
193
194
195
196
197
198
199
200
201 @JsxFunction
202 public Scriptable namedItem(final String name) {
203 final List<DomNode> elements = getElements();
204 final BrowserVersion browserVersion = getBrowserVersion();
205 if (browserVersion.hasFeature(HTMLCOLLECTION_NAMED_ITEM_ID_FIRST)) {
206 for (final Object next : elements) {
207 if (next instanceof DomElement elem) {
208 final String id = elem.getId();
209 if (name.equals(id)) {
210 return getScriptableForElement(elem);
211 }
212 }
213 }
214 }
215 for (final Object next : elements) {
216 if (next instanceof DomElement elem) {
217 final String nodeName = elem.getAttributeDirect(DomElement.NAME_ATTRIBUTE);
218 if (name.equals(nodeName)) {
219 return getScriptableForElement(elem);
220 }
221
222 final String id = elem.getId();
223 if (name.equals(id)) {
224 return getScriptableForElement(elem);
225 }
226 }
227 }
228 return null;
229 }
230 }