Skip to content

Commit dd72d4e

Browse files
committed
HTMLFormControlsCollection getOwnPropertyDescriptor() has to support fields by name and id
1 parent b37cab4 commit dd72d4e

3 files changed

Lines changed: 114 additions & 4 deletions

File tree

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
<body>
1010
<release version="4.19.0" date="November xx, 2025" description="Chrome/Edge 142, Bugfixes">
11+
<action type="update" dev="rbri">
12+
HTMLFormControlsCollection getOwnPropertyDescriptor() has to support fields by name and id.
13+
</action>
1114
<action type="update" dev="RhinoTeam">
1215
core-js: Refactor internal property descriptors to not be 'ScriptableObjects'
1316
</action>

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

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
*/
1515
package org.htmlunit.javascript.host.html;
1616

17+
import java.util.ArrayList;
18+
import java.util.List;
19+
20+
import org.htmlunit.corejs.javascript.Context;
1721
import org.htmlunit.corejs.javascript.Scriptable;
22+
import org.htmlunit.corejs.javascript.ScriptableObject;
1823
import org.htmlunit.html.DomElement;
1924
import org.htmlunit.html.DomNode;
2025
import org.htmlunit.javascript.JavaScriptEngine;
@@ -24,9 +29,6 @@
2429
import org.htmlunit.javascript.configuration.JsxSymbol;
2530
import org.htmlunit.javascript.host.dom.RadioNodeList;
2631

27-
import java.util.ArrayList;
28-
import java.util.List;
29-
3032
/**
3133
* A JavaScript object for {@code HTMLFormControlsCollection}.
3234
*
@@ -115,6 +117,30 @@ public Scriptable namedItem(final String name) {
115117
return nodeList;
116118
}
117119

120+
/**
121+
* Overridden to allow the retrieval of certain form elements by ID or name.
122+
*
123+
* @param cx {@inheritDoc}
124+
* @param id {@inheritDoc}
125+
* @return {@inheritDoc}
126+
*/
127+
@Override
128+
protected DescriptorInfo getOwnPropertyDescriptor(final Context cx, final Object id) {
129+
final DescriptorInfo descInfo = super.getOwnPropertyDescriptor(cx, id);
130+
if (descInfo != null) {
131+
return descInfo;
132+
}
133+
134+
if (id instanceof CharSequence) {
135+
final Scriptable element = namedItem(id.toString());
136+
if (element != null) {
137+
return ScriptableObject.buildDataDescriptor(element, ScriptableObject.READONLY);
138+
}
139+
}
140+
141+
return null;
142+
}
143+
118144
@JsxSymbol
119145
@Override
120146
public Scriptable iterator() {

src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public void elementsAccessor() throws Exception {
6767
+ " for (var i = 0; i < document.form1.length; i++) {\n"
6868
+ " var element = document.form1.elements[i];\n"
6969
+ " if (element.type != 'radio' && element != document.form1[element.name]) {\n"
70-
+ " log('name index not working for '+element.name);\n"
70+
+ " log('name index not working for ' + element.name);\n"
7171
+ " }\n"
7272
+ " log(element.name);\n"
7373
+ " }\n"
@@ -157,6 +157,87 @@ public void elementsAccessorFormAttribute() throws Exception {
157157
loadPageVerifyTitle2(html);
158158
}
159159

160+
/**
161+
* @throws Exception if the test fails
162+
*/
163+
@Test
164+
@Alerts({"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false",
165+
"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false"})
166+
public void formAccessorOwnPropertyDescriptor() throws Exception {
167+
final String html = DOCTYPE_HTML
168+
+ "<html><head><script>\n"
169+
+ LOG_TITLE_FUNCTION
170+
+ "function doTest() {\n"
171+
+ " let desc = Object.getOwnPropertyDescriptor(document.form1, 'buttonId');\n"
172+
+ " log(desc.get + '/' + desc.set);\n"
173+
+ " log(typeof desc.value + '/' + desc.value);\n"
174+
+ " log('W-' + desc.writable);\n"
175+
+ " log('C-' + desc.configurable);\n"
176+
+ " log('E-' + desc.enumerable);\n"
177+
178+
+ " desc = Object.getOwnPropertyDescriptor(document.form1, 'buttonName');\n"
179+
+ " log(desc.get + '/' + desc.set);\n"
180+
+ " log(typeof desc.value + '/' + desc.value);\n"
181+
+ " log('W-' + desc.writable);\n"
182+
+ " log('C-' + desc.configurable);\n"
183+
+ " log('E-' + desc.enumerable);\n"
184+
+ "}\n"
185+
+ "</script></head>\n"
186+
+ "<body onload='doTest()'>\n"
187+
188+
+ "<form id='myForm' name='form1'>\n"
189+
+ " <input type='button' name='buttonName' id='buttonId' />\n"
190+
+ "</form>\n"
191+
+ "</body></html>";
192+
193+
loadPageVerifyTitle2(html);
194+
}
195+
196+
/**
197+
* @throws Exception if the test fails
198+
*/
199+
@Test
200+
@Alerts(DEFAULT = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true",
201+
"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true"},
202+
FF = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false",
203+
"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false"},
204+
FF_ESR = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false",
205+
"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false"})
206+
@HtmlUnitNYI(
207+
FF = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true",
208+
"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true"},
209+
FF_ESR = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true",
210+
"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true"})
211+
public void elementsAccessorOwnPropertyDescriptor() throws Exception {
212+
final String html = DOCTYPE_HTML
213+
+ "<html><head><script>\n"
214+
+ LOG_TITLE_FUNCTION
215+
+ "function doTest() {\n"
216+
+ " let desc = Object.getOwnPropertyDescriptor(document.form1.elements, 'buttonId');\n"
217+
+ " log(desc.get + '/' + desc.set);\n"
218+
+ " log(typeof desc.value + '/' + desc.value);\n"
219+
+ " log('W-' + desc.writable);\n"
220+
+ " log('C-' + desc.configurable);\n"
221+
+ " log('E-' + desc.enumerable);\n"
222+
223+
+ " desc = Object.getOwnPropertyDescriptor(document.form1.elements, 'buttonName');\n"
224+
+ " log(desc.get + '/' + desc.set);\n"
225+
+ " log(typeof desc.value + '/' + desc.value);\n"
226+
+ " log('W-' + desc.writable);\n"
227+
+ " log('C-' + desc.configurable);\n"
228+
+ " log('E-' + desc.enumerable);\n"
229+
+ "}\n"
230+
+ "</script></head>\n"
231+
+ "<body onload='doTest()'>\n"
232+
233+
+ "<form id='myForm' name='form1'>\n"
234+
+ " <input type='button' name='buttonName' id='buttonId' />\n"
235+
+ "</form>\n"
236+
+ "</body></html>";
237+
238+
loadPageVerifyTitle2(html);
239+
}
240+
160241
/**
161242
* @throws Exception if the test fails
162243
*/

0 commit comments

Comments
 (0)