1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.dom;
16
17 import java.util.ArrayList;
18 import java.util.List;
19
20 import org.htmlunit.WebClient;
21 import org.htmlunit.corejs.javascript.Callable;
22 import org.htmlunit.corejs.javascript.Context;
23 import org.htmlunit.corejs.javascript.ContextAction;
24 import org.htmlunit.corejs.javascript.Function;
25 import org.htmlunit.corejs.javascript.Scriptable;
26 import org.htmlunit.corejs.javascript.VarScope;
27 import org.htmlunit.html.DomNode;
28 import org.htmlunit.javascript.HtmlUnitContextFactory;
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 @JsxClass
51 public class NodeList extends AbstractList implements Callable {
52
53
54
55
56 public NodeList() {
57 super();
58 }
59
60
61
62
63 @JsxConstructor
64 public void jsConstructor() {
65
66 }
67
68
69
70
71
72
73
74
75 public NodeList(final DomNode domNode, final boolean attributeChangeSensitive) {
76 super(domNode, attributeChangeSensitive, null);
77 }
78
79
80
81
82
83
84 public NodeList(final DomNode domNode, final List<DomNode> initialElements) {
85 super(domNode, true, new ArrayList<>(initialElements));
86 }
87
88
89
90
91
92 NodeList(final VarScope parentScope) {
93 super();
94 setParentScope(parentScope);
95 setPrototype(getPrototype(getClass()));
96 setExternalArrayData(parentScope, this);
97 }
98
99
100
101
102
103
104
105
106 public static NodeList staticNodeList(final VarScope parentScope, final List<DomNode> elements) {
107 return new NodeList(parentScope) {
108 @Override
109 public List<DomNode> getElements() {
110 return elements;
111 }
112 };
113 }
114
115
116
117
118
119 @JsxFunction
120 public Scriptable keys() {
121 return JavaScriptEngine.newArrayIteratorTypeKeys(getParentScope(), this);
122 }
123
124
125
126
127
128 @JsxFunction
129 @JsxSymbol(symbolName = "iterator")
130 public Scriptable values() {
131 return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
132 }
133
134
135
136
137
138 @JsxFunction
139 public Scriptable entries() {
140 return JavaScriptEngine.newArrayIteratorTypeEntries(getParentScope(), this);
141 }
142
143
144
145
146
147 @JsxFunction
148 public void forEach(final Object callback) {
149 if (!(callback instanceof Function function)) {
150 throw JavaScriptEngine.typeError(
151 "Foreach callback '" + JavaScriptEngine.toString(callback) + "' is not a function");
152 }
153
154 if (getElements().isEmpty()) {
155 return;
156 }
157
158 final WebClient client = getWindow().getWebWindow().getWebClient();
159 final HtmlUnitContextFactory cf = client.getJavaScriptEngine().getContextFactory();
160
161 final ContextAction<Object> contextAction = cx -> {
162 final VarScope scope = getParentScope();
163
164 List<DomNode> nodes = getElements();
165 final int size = nodes.size();
166 int i = 0;
167 while (i < size && i < nodes.size()) {
168 function.call(cx, scope, this, new Object[] {nodes.get(i).getScriptableObject(), i, this});
169
170
171 nodes = getElements();
172 i++;
173 }
174
175 return null;
176 };
177 cf.call(contextAction);
178 }
179
180
181
182
183
184 @JsxGetter
185 @Override
186 public final int getLength() {
187 return super.getLength();
188 }
189
190
191
192
193
194
195
196 @JsxFunction
197 public Object item(final Object index) {
198 final Object object = getIt(index);
199 if (object == NOT_FOUND) {
200 return null;
201 }
202 return object;
203 }
204
205
206
207
208 @Override
209 public Object call(final Context cx, final VarScope scope, final Scriptable thisObj, final Object[] args) {
210 if (args.length == 0) {
211 throw JavaScriptEngine.reportRuntimeError("Zero arguments; need an index or a key.");
212 }
213 final Object object = getIt(args[0]);
214 if (object == NOT_FOUND) {
215 return null;
216 }
217 return object;
218 }
219
220
221
222
223 @Override
224 protected AbstractList create(final DomNode parentScope, final List<DomNode> initialElements) {
225 return new NodeList(parentScope, new ArrayList<>(initialElements));
226 }
227 }