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 final List<DomNode> nodes = getElements();
156
157 final WebClient client = getWindow().getWebWindow().getWebClient();
158 final HtmlUnitContextFactory cf = client.getJavaScriptEngine().getContextFactory();
159
160 final ContextAction<Object> contextAction = cx -> {
161 final Function function = (Function) callback;
162 final Scriptable scope = getParentScope();
163 for (int i = 0; i < nodes.size(); i++) {
164 function.call(cx, scope, this, new Object[] {nodes.get(i).getScriptableObject(), i, this});
165 }
166 return null;
167 };
168 cf.call(contextAction);
169 }
170
171
172
173
174
175 @JsxGetter
176 @Override
177 public final int getLength() {
178 return super.getLength();
179 }
180
181
182
183
184
185
186
187 @JsxFunction
188 public Object item(final Object index) {
189 final Object object = getIt(index);
190 if (object == NOT_FOUND) {
191 return null;
192 }
193 return object;
194 }
195
196
197
198
199 @Override
200 public Object call(final Context cx, final Scriptable scope, final Scriptable thisObj, final Object[] args) {
201 if (args.length == 0) {
202 throw JavaScriptEngine.reportRuntimeError("Zero arguments; need an index or a key.");
203 }
204 final Object object = getIt(args[0]);
205 if (object == NOT_FOUND) {
206 return null;
207 }
208 return object;
209 }
210
211
212
213
214 @Override
215 protected AbstractList create(final DomNode parentScope, final List<DomNode> initialElements) {
216 return new NodeList(parentScope, new ArrayList<>(initialElements));
217 }
218 }