Skip to content

Commit be92531

Browse files
committed
form elements are available as property descriptors also (issue #578)
1 parent 7dba261 commit be92531

2 files changed

Lines changed: 167 additions & 0 deletions

File tree

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,47 @@ protected Object getWithPreemption(final String name) {
432432
return coll;
433433
}
434434

435+
/**
436+
* Overridden to allow the retrieval of certain form elements by ID or name.
437+
*
438+
* @param name {@inheritDoc}
439+
* @param start {@inheritDoc}
440+
* @return {@inheritDoc}
441+
*/
442+
@Override
443+
public boolean has(final String name, final Scriptable start) {
444+
if (super.has(name, start)) {
445+
return true;
446+
}
447+
448+
return findFirstElement(name) != null;
449+
}
450+
451+
/**
452+
* Overridden to allow the retrieval of certain form elements by ID or name.
453+
*
454+
* @param cx {@inheritDoc}
455+
* @param id {@inheritDoc}
456+
* @return {@inheritDoc}
457+
*/
458+
@Override
459+
protected ScriptableObject getOwnPropertyDescriptor(final Context cx, final Object id) {
460+
final ScriptableObject desc = super.getOwnPropertyDescriptor(cx, id);
461+
if (desc != null) {
462+
return desc;
463+
}
464+
465+
if (id instanceof CharSequence) {
466+
final HtmlElement element = findFirstElement(id.toString());
467+
if (element != null) {
468+
return ScriptableObject.buildDataDescriptor(this, element.getScriptableObject(),
469+
ScriptableObject.READONLY | ScriptableObject.DONTENUM);
470+
}
471+
}
472+
473+
return null;
474+
}
475+
435476
List<HtmlElement> findElements(final String name) {
436477
final List<HtmlElement> elements = new ArrayList<>();
437478
addElements(name, getHtmlForm().getHtmlElementDescendants(), elements);
@@ -461,6 +502,32 @@ private void addElements(final String name, final Iterable<HtmlElement> nodes,
461502
}
462503
}
463504

505+
private HtmlElement findFirstElement(final String name) {
506+
for (final HtmlElement node : getHtmlForm().getHtmlElementDescendants()) {
507+
if (isAccessibleByIdOrName(node, name)) {
508+
return node;
509+
}
510+
}
511+
512+
for (final HtmlElement node : getHtmlForm().getLostChildren()) {
513+
if (isAccessibleByIdOrName(node, name)) {
514+
return node;
515+
}
516+
}
517+
518+
// If no form fields are found, browsers are able to find img elements by ID or name.
519+
for (final DomNode node : getHtmlForm().getHtmlElementDescendants()) {
520+
if (node instanceof HtmlImage) {
521+
final HtmlImage img = (HtmlImage) node;
522+
if (name.equals(img.getId()) || name.equals(img.getNameAttribute())) {
523+
return img;
524+
}
525+
}
526+
}
527+
528+
return null;
529+
}
530+
464531
/**
465532
* Indicates if the element can be reached by id or name in expressions like "myForm.myField".
466533
* @param element the element to test

src/test/java/org/htmlunit/html/HtmlForm2Test.java

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,4 +1609,104 @@ public void relAttribute() throws Exception {
16091609

16101610
loadPageVerifyTitle2(html);
16111611
}
1612+
1613+
/**
1614+
* @throws Exception on test failure
1615+
*/
1616+
@Test
1617+
@Alerts({"[object HTMLFormElement]", "[object HTMLInputElement]", "true",
1618+
"[object HTMLInputElement]", "true"})
1619+
public void inputNameProperty() throws Exception {
1620+
final String html
1621+
= "<html>\n"
1622+
+ "<head></head>\n"
1623+
+ "<body>\n"
1624+
+ " <form id='testForm' name='testForm' action='/dosomething\' method='POST'>\n"
1625+
+ " <input type='submit' name='button' value='PushMe' id='button'/>\n"
1626+
+ " <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1627+
+ " </form>\n"
1628+
+ "<script>\n"
1629+
+ LOG_TITLE_FUNCTION
1630+
+ " log(testForm);\n"
1631+
+ " log(testForm.button);\n"
1632+
+ " log(testForm.button !== undefined);\n"
1633+
+ " log(testForm.hiddenParam);\n"
1634+
+ " log(testForm.hiddenParam !== undefined);\n"
1635+
+ "</script>\n"
1636+
+ "</body></html>";
1637+
1638+
loadPageVerifyTitle2(html);
1639+
}
1640+
1641+
/**
1642+
* @throws Exception on test failure
1643+
*/
1644+
@Test
1645+
@Alerts({"[object HTMLFormElement]", "[object HTMLInputElement]", "true",
1646+
"[object HTMLInputElement]", "true"})
1647+
public void inputHasOwnProperty() throws Exception {
1648+
final String html
1649+
= "<html>\n"
1650+
+ "<head></head>\n"
1651+
+ "<body>\n"
1652+
+ " <form id='testForm' name='testForm' action='/dosomething\' method='POST'>\n"
1653+
+ " <input type='submit' name='button' value='PushMe' id='button'/>\n"
1654+
+ " <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1655+
+ " </form>\n"
1656+
+ "<script>\n"
1657+
+ LOG_TITLE_FUNCTION
1658+
+ " log(testForm);\n"
1659+
+ " log(testForm.button);\n"
1660+
+ " log(testForm.hasOwnProperty('button'));\n"
1661+
+ " log(testForm.hiddenParam);\n"
1662+
+ " log(testForm.hasOwnProperty('hiddenParam'));\n"
1663+
+ "</script>\n"
1664+
+ "</body></html>";
1665+
1666+
loadPageVerifyTitle2(html);
1667+
}
1668+
1669+
1670+
/**
1671+
* @throws Exception on test failure
1672+
*/
1673+
@Test
1674+
@Alerts({"[object HTMLFormElement]", "[object HTMLInputElement]",
1675+
"undefined", "undefined", "[object HTMLInputElement]", "true", "false", "false",
1676+
"undefined", "undefined", "[object HTMLInputElement]", "true", "false", "false"})
1677+
public void inputGetOwnPropertyDescriptor() throws Exception {
1678+
final String html
1679+
= "<html>\n"
1680+
+ "<head></head>\n"
1681+
+ "<body>\n"
1682+
+ " <form id='testForm' name='testForm' action='/dosomething\' method='POST'>\n"
1683+
+ " <input type='submit' name='button' value='PushMe' id='button'/>\n"
1684+
+ " <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1685+
+ " </form>\n"
1686+
+ "<script>\n"
1687+
+ LOG_TITLE_FUNCTION
1688+
+ " log(testForm);\n"
1689+
+ " log(testForm.button);\n"
1690+
1691+
+ " var prop = Object.getOwnPropertyDescriptor(testForm, 'button');\n"
1692+
+ " log(prop.get);\n"
1693+
+ " log(prop.set);\n"
1694+
+ " log(prop.value);\n"
1695+
+ " log(prop.configurable);\n"
1696+
+ " log(prop.enumerable);\n"
1697+
+ " log(prop.writable);\n"
1698+
1699+
+ " prop = Object.getOwnPropertyDescriptor(testForm, 'hiddenParam');\n"
1700+
+ " log(prop.get);\n"
1701+
+ " log(prop.set);\n"
1702+
+ " log(prop.value);\n"
1703+
+ " log(prop.configurable);\n"
1704+
+ " log(prop.enumerable);\n"
1705+
+ " log(prop.writable);\n"
1706+
1707+
+ "</script>\n"
1708+
+ "</body></html>";
1709+
1710+
loadPageVerifyTitle2(html);
1711+
}
16121712
}

0 commit comments

Comments
 (0)