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