Skip to content

Commit ff6b7b8

Browse files
committed
fix HTMLAllCollection prototype
1 parent 61d97d8 commit ff6b7b8

File tree

4 files changed

+89
-79
lines changed

4 files changed

+89
-79
lines changed

src/main/java/org/htmlunit/javascript/configuration/JavaScriptConfiguration.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,8 +592,8 @@ public final class JavaScriptConfiguration extends AbstractJavaScriptConfigurati
592592
CloseEvent.class, ComputedCSSStyleDeclaration.class, CustomEvent.class, DOMMatrix.class, DOMPoint.class,
593593
DeviceMotionEvent.class, DeviceOrientationEvent.class, ErrorEvent.class, EventSource.class,
594594
FederatedCredential.class, File.class, FileReader.class, FileSystemDirectoryEntry.class,
595-
FileSystemFileEntry.class, FontFaceSet.class, GamepadEvent.class, HTMLCollection.class, HashChangeEvent.class,
596-
IDBCursorWithValue.class, IDBDatabase.class, IDBRequest.class, IDBTransaction.class,
595+
FileSystemFileEntry.class, FontFaceSet.class, GamepadEvent.class, HTMLAllCollection.class, HTMLCollection.class,
596+
HashChangeEvent.class, IDBCursorWithValue.class, IDBDatabase.class, IDBRequest.class, IDBTransaction.class,
597597
IDBVersionChangeEvent.class, MIDIAccess.class, MIDIConnectionEvent.class, MIDIMessageEvent.class,
598598
MIDIPort.class, MediaDevices.class, MediaEncryptedEvent.class, MediaKeyError.class, MediaKeyMessageEvent.class,
599599
MediaKeySession.class, MediaQueryList.class, MediaQueryListEvent.class, MediaRecorder.class, MediaSource.class,
@@ -619,8 +619,8 @@ public final class JavaScriptConfiguration extends AbstractJavaScriptConfigurati
619619
CanvasCaptureMediaStreamTrack.class, ChannelMergerNode.class, ChannelSplitterNode.class, CharacterData.class,
620620
CompositionEvent.class, ConvolverNode.class, DelayNode.class, Document.class, DocumentFragment.class,
621621
DocumentType.class, DynamicsCompressorNode.class, Element.class, FocusEvent.class, GainNode.class,
622-
HTMLAllCollection.class, HTMLFormControlsCollection.class, IDBOpenDBRequest.class, IIRFilterNode.class,
623-
InputEvent.class, KeyboardEvent.class, MIDIInput.class, MIDIOutput.class, MediaElementAudioSourceNode.class,
622+
HTMLFormControlsCollection.class, IDBOpenDBRequest.class, IIRFilterNode.class, InputEvent.class,
623+
KeyboardEvent.class, MIDIInput.class, MIDIOutput.class, MediaElementAudioSourceNode.class,
624624
MediaStreamAudioDestinationNode.class, MediaStreamAudioSourceNode.class, MouseEvent.class,
625625
OfflineAudioContext.class, PannerNode.class, PerformanceNavigationTiming.class, RadioNodeList.class,
626626
ScriptProcessorNode.class, SpeechSynthesisErrorEvent.class, StereoPannerNode.class, TextEvent.class,

src/main/java/org/htmlunit/javascript/host/dom/Document.java

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,13 +1705,7 @@ public HtmlUnitScriptable elementFromPoint(final int x, final int y) {
17051705
*/
17061706
@JsxGetter
17071707
public HTMLCollection getForms() {
1708-
final HTMLCollection forms = new HTMLCollection(getDomNodeOrDie(), false) {
1709-
@Override
1710-
public Object call(final Context cx, final Scriptable scope,
1711-
final Scriptable thisObj, final Object[] args) {
1712-
throw JavaScriptEngine.typeError("document.forms is not a function");
1713-
}
1714-
};
1708+
final HTMLCollection forms = new HTMLCollection(getDomNodeOrDie(), false);
17151709

17161710
forms.setIsMatchingPredicate(
17171711
(Predicate<DomNode> & Serializable)
@@ -1725,13 +1719,7 @@ public Object call(final Context cx, final Scriptable scope,
17251719
*/
17261720
@JsxGetter
17271721
public HTMLCollection getEmbeds() {
1728-
final HTMLCollection embeds = new HTMLCollection(getDomNodeOrDie(), false) {
1729-
@Override
1730-
public Object call(final Context cx, final Scriptable scope,
1731-
final Scriptable thisObj, final Object[] args) {
1732-
throw JavaScriptEngine.typeError("document.embeds is not a function");
1733-
}
1734-
};
1722+
final HTMLCollection embeds = new HTMLCollection(getDomNodeOrDie(), false);
17351723

17361724
embeds.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> node instanceof HtmlEmbed);
17371725
return embeds;
@@ -1743,13 +1731,7 @@ public Object call(final Context cx, final Scriptable scope,
17431731
*/
17441732
@JsxGetter
17451733
public HTMLCollection getImages() {
1746-
final HTMLCollection images = new HTMLCollection(getDomNodeOrDie(), false) {
1747-
@Override
1748-
public Object call(final Context cx, final Scriptable scope,
1749-
final Scriptable thisObj, final Object[] args) {
1750-
throw JavaScriptEngine.typeError("document.images is not a function");
1751-
}
1752-
};
1734+
final HTMLCollection images = new HTMLCollection(getDomNodeOrDie(), false);
17531735

17541736
images.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> node instanceof HtmlImage);
17551737
return images;
@@ -1761,13 +1743,7 @@ public Object call(final Context cx, final Scriptable scope,
17611743
*/
17621744
@JsxGetter
17631745
public HTMLCollection getScripts() {
1764-
final HTMLCollection scripts = new HTMLCollection(getDomNodeOrDie(), false) {
1765-
@Override
1766-
public Object call(final Context cx, final Scriptable scope,
1767-
final Scriptable thisObj, final Object[] args) {
1768-
throw JavaScriptEngine.typeError("document.scripts is not a function");
1769-
}
1770-
};
1746+
final HTMLCollection scripts = new HTMLCollection(getDomNodeOrDie(), false);
17711747

17721748
scripts.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> node instanceof HtmlScript);
17731749
return scripts;
@@ -3505,8 +3481,8 @@ public ScriptableObject getFonts() {
35053481
* @return the value of the {@code all} property
35063482
*/
35073483
@JsxGetter
3508-
public HTMLCollection getAll() {
3509-
final HTMLCollection all = new HTMLAllCollection(getDomNodeOrDie());
3484+
public HTMLAllCollection getAll() {
3485+
final HTMLAllCollection all = new HTMLAllCollection(getDomNodeOrDie());
35103486
all.setAvoidObjectDetection(true);
35113487
all.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> true);
35123488
return all;

src/main/java/org/htmlunit/javascript/host/html/HTMLAllCollection.java

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,20 @@
1717
import java.util.ArrayList;
1818
import java.util.List;
1919

20+
import org.htmlunit.corejs.javascript.Callable;
2021
import org.htmlunit.corejs.javascript.Context;
2122
import org.htmlunit.corejs.javascript.Scriptable;
2223
import org.htmlunit.html.DomElement;
2324
import org.htmlunit.html.DomNode;
25+
import org.htmlunit.html.HtmlForm;
26+
import org.htmlunit.html.HtmlInput;
2427
import org.htmlunit.javascript.JavaScriptEngine;
2528
import org.htmlunit.javascript.configuration.JsxClass;
2629
import org.htmlunit.javascript.configuration.JsxConstructor;
30+
import org.htmlunit.javascript.configuration.JsxFunction;
31+
import org.htmlunit.javascript.configuration.JsxGetter;
32+
import org.htmlunit.javascript.configuration.JsxSymbol;
33+
import org.htmlunit.javascript.host.dom.AbstractList;
2734

2835
/**
2936
* A special {@link HTMLCollection} for <code>document.all</code>.
@@ -32,7 +39,7 @@
3239
* @author Ahmed Ashour
3340
*/
3441
@JsxClass
35-
public class HTMLAllCollection extends HTMLCollection {
42+
public class HTMLAllCollection extends AbstractList implements Callable {
3643

3744
/**
3845
* Creates an instance.
@@ -44,18 +51,16 @@ public HTMLAllCollection() {
4451
/**
4552
* JavaScript constructor.
4653
*/
47-
@Override
4854
@JsxConstructor
4955
public void jsConstructor() {
50-
super.jsConstructor();
5156
}
5257

5358
/**
5459
* Creates an instance.
5560
* @param parentScope parent scope
5661
*/
5762
public HTMLAllCollection(final DomNode parentScope) {
58-
super(parentScope, false);
63+
super(parentScope, false, null);
5964
}
6065

6166
/**
@@ -64,7 +69,7 @@ public HTMLAllCollection(final DomNode parentScope) {
6469
* @return the element or elements corresponding to the specified index or key
6570
* @see <a href="http://msdn.microsoft.com/en-us/library/ms536460.aspx">MSDN doc</a>
6671
*/
67-
@Override
72+
@JsxFunction
6873
public Object item(final Object index) {
6974
final double numb;
7075

@@ -99,9 +104,13 @@ public Object item(final Object index) {
99104
}
100105

101106
/**
102-
* {@inheritDoc}
107+
* Retrieves the item or items corresponding to the specified name (checks ids, and if
108+
* that does not work, then names).
109+
* @param name the name or id the element or elements to return
110+
* @return the element or elements corresponding to the specified name or id
111+
* @see <a href="http://msdn.microsoft.com/en-us/library/ms536634.aspx">MSDN doc</a>
103112
*/
104-
@Override
113+
@JsxFunction
105114
public final Scriptable namedItem(final String name) {
106115
final List<DomNode> elements = getElements();
107116

@@ -158,7 +167,13 @@ public Object call(final Context cx, final Scriptable scope, final Scriptable th
158167
}
159168
}
160169

161-
final Object value = super.call(cx, scope, thisObj, args);
170+
if (args.length == 0) {
171+
throw JavaScriptEngine.reportRuntimeError("Zero arguments; need an index or a key.");
172+
}
173+
Object value = getIt(args[0]);
174+
if (value == NOT_FOUND) {
175+
value = null;
176+
}
162177
if (nullIfNotFound && JavaScriptEngine.isUndefined(value)) {
163178
return null;
164179
}
@@ -169,19 +184,68 @@ public Object call(final Context cx, final Scriptable scope, final Scriptable th
169184
* {@inheritDoc}
170185
*/
171186
@Override
172-
protected boolean supportsParentheses() {
173-
return true;
187+
protected Object equivalentValues(final Object value) {
188+
if (value == null || JavaScriptEngine.isUndefined(value)) {
189+
return Boolean.TRUE;
190+
}
191+
192+
return super.equivalentValues(value);
193+
}
194+
/**
195+
* @return the Iterator symbol
196+
*/
197+
@JsxSymbol
198+
public Scriptable iterator() {
199+
return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
200+
}
201+
202+
/**
203+
* Returns the length.
204+
* @return the length
205+
*/
206+
@JsxGetter
207+
@Override
208+
public final int getLength() {
209+
return super.getLength();
174210
}
175211

176212
/**
177213
* {@inheritDoc}
178214
*/
179215
@Override
180-
protected Object equivalentValues(final Object value) {
181-
if (value == null || JavaScriptEngine.isUndefined(value)) {
182-
return Boolean.TRUE;
216+
protected Object getWithPreemptionByName(final String name, final List<DomNode> elements) {
217+
final List<DomNode> matchingElements = new ArrayList<>();
218+
final boolean searchName = isGetWithPreemptionSearchName();
219+
for (final DomNode next : elements) {
220+
if (next instanceof DomElement
221+
&& (searchName || next instanceof HtmlInput || next instanceof HtmlForm)) {
222+
final String nodeName = ((DomElement) next).getAttributeDirect(DomElement.NAME_ATTRIBUTE);
223+
if (name.equals(nodeName)) {
224+
matchingElements.add(next);
225+
}
226+
}
183227
}
184228

185-
return super.equivalentValues(value);
229+
if (matchingElements.isEmpty()) {
230+
return NOT_FOUND;
231+
}
232+
233+
if (matchingElements.size() == 1) {
234+
return getScriptableForElement(matchingElements.get(0));
235+
}
236+
237+
// many elements => build a sub collection
238+
final DomNode domNode = getDomNodeOrNull();
239+
final HTMLCollection collection = new HTMLCollection(domNode, matchingElements);
240+
collection.setAvoidObjectDetection(true);
241+
return collection;
242+
}
243+
244+
/**
245+
* Returns whether {@link #getWithPreemption(String)} should search by name or not.
246+
* @return whether {@link #getWithPreemption(String)} should search by name or not
247+
*/
248+
protected boolean isGetWithPreemptionSearchName() {
249+
return true;
186250
}
187251
}

src/main/java/org/htmlunit/javascript/host/html/HTMLCollection.java

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
import java.util.List;
2222

2323
import org.htmlunit.BrowserVersion;
24-
import org.htmlunit.corejs.javascript.Callable;
25-
import org.htmlunit.corejs.javascript.Context;
2624
import org.htmlunit.corejs.javascript.Scriptable;
2725
import org.htmlunit.html.DomElement;
2826
import org.htmlunit.html.DomNode;
@@ -53,7 +51,7 @@
5351
* @author Ronald Brill
5452
*/
5553
@JsxClass
56-
public class HTMLCollection extends AbstractList implements Callable {
54+
public class HTMLCollection extends AbstractList {
5755

5856
/**
5957
* Creates an instance.
@@ -129,34 +127,6 @@ public final int getLength() {
129127
return super.getLength();
130128
}
131129

132-
/**
133-
* {@inheritDoc}
134-
*/
135-
@Override
136-
public Object call(final Context cx, final Scriptable scope, final Scriptable thisObj, final Object[] args) {
137-
if (supportsParentheses()) {
138-
if (args.length == 0) {
139-
throw JavaScriptEngine.reportRuntimeError("Zero arguments; need an index or a key.");
140-
}
141-
final Object object = getIt(args[0]);
142-
if (object == NOT_FOUND) {
143-
return null;
144-
}
145-
return object;
146-
}
147-
148-
throw JavaScriptEngine.typeError("HTMLCollection does nont support function like access");
149-
}
150-
151-
/**
152-
* Is parentheses supported.
153-
*
154-
* @return true or false
155-
*/
156-
protected boolean supportsParentheses() {
157-
return false;
158-
}
159-
160130
/**
161131
* {@inheritDoc}
162132
*/

0 commit comments

Comments
 (0)