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