This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/struts.git
commit aee029a6c7b560bd04139bf46c010dcfe7e9ce33 Author: Emil Huseynov <[email protected]> AuthorDate: Sun Nov 1 11:04:43 2026 +0400 WW-5774 Address review: html5 fixture, RadioNodeList, guard the script - combobox.js: when form.elements[target] is a RadioNodeList (two controls share the name) resolve the first text input rather than assigning value to the list, which would not reach the field. - Add testHtml5ThemeRendersDataAttributes with a ComboBox-5 html5-theme fixture pinning data-struts-combobox-target / -header-key / -empty-option, which the xhtml->simple fixtures never exercised. - Move the combobox.js include inside the list?? guard, right before the select, so a listless combobox emits no stray script; fixtures 1-4 updated for the new position. - Rename testJsCallNamingUsesEscapedId(_clearTagStateSet) to testDataAttributeUsesEscapedId; the escaped id now lands in the data-struts-combobox attribute, not a JS call name. --- .../org/apache/struts2/static/combobox.js | 12 ++++++++ .../src/main/resources/template/html5/combobox.ftl | 2 +- .../main/resources/template/simple/combobox.ftl | 2 +- .../apache/struts2/views/jsp/ui/ComboBoxTest.java | 33 ++++++++++++++++++++-- .../org/apache/struts2/views/jsp/ui/ComboBox-1.txt | 2 +- .../org/apache/struts2/views/jsp/ui/ComboBox-2.txt | 2 +- .../org/apache/struts2/views/jsp/ui/ComboBox-3.txt | 2 +- .../org/apache/struts2/views/jsp/ui/ComboBox-4.txt | 2 +- .../jsp/ui/{ComboBox-2.txt => ComboBox-5.txt} | 13 ++------- 9 files changed, 52 insertions(+), 18 deletions(-) diff --git a/core/src/main/resources/org/apache/struts2/static/combobox.js b/core/src/main/resources/org/apache/struts2/static/combobox.js index 94a570fda..e32a53797 100644 --- a/core/src/main/resources/org/apache/struts2/static/combobox.js +++ b/core/src/main/resources/org/apache/struts2/static/combobox.js @@ -49,6 +49,18 @@ return; } var field = select.form.elements[target]; + if (field && typeof field.length === 'number' && field.tagName === undefined) { + // Two controls in the form share the name, so elements[target] is a RadioNodeList rather than the + // text field; assigning value to it would not reach the input. Resolve the first text input in it. + var resolved = null; + for (var i = 0; i < field.length; i++) { + if (field[i].tagName === 'INPUT') { + resolved = field[i]; + break; + } + } + field = resolved; + } if (field) { field.value = value; } diff --git a/core/src/main/resources/template/html5/combobox.ftl b/core/src/main/resources/template/html5/combobox.ftl index 9f5c1b617..8c3972142 100644 --- a/core/src/main/resources/template/html5/combobox.ftl +++ b/core/src/main/resources/template/html5/combobox.ftl @@ -18,11 +18,11 @@ * under the License. */ --> -<@s.script src="${base}${attributes.staticContentPath}/combobox.js" /> <#include "/${attributes.templateDir}/html5/text.ftl" /><#rt/> <#include "/${attributes.templateDir}/${attributes.expandTheme}/controlheader.ftl" /> <#if attributes.list??> +<@s.script src="${base}${attributes.staticContentPath}/combobox.js" /> <select data-struts-combobox="${attributes.escapedId}" data-struts-combobox-target="${attributes.name}"<#rt/> <#if attributes.headerKey?? && attributes.headerValue??> data-struts-header-key="${attributes.headerKey}"</#if><#t/> <#if attributes.emptyOption!false> data-struts-empty-option="true"</#if><#t/> diff --git a/core/src/main/resources/template/simple/combobox.ftl b/core/src/main/resources/template/simple/combobox.ftl index 13dd95851..01a2fa6ae 100644 --- a/core/src/main/resources/template/simple/combobox.ftl +++ b/core/src/main/resources/template/simple/combobox.ftl @@ -18,10 +18,10 @@ * under the License. */ --> -<@s.script src="${base}${attributes.staticContentPath}/combobox.js" /> <#include "/${attributes.templateDir}/simple/text.ftl" /> <br /> <#if attributes.list??> +<@s.script src="${base}${attributes.staticContentPath}/combobox.js" /> <select data-struts-combobox="${attributes.escapedId}" data-struts-combobox-target="${attributes.name}"<#rt/> <#if attributes.headerKey?? && attributes.headerValue??> data-struts-header-key="${attributes.headerKey}"</#if><#t/> <#if attributes.emptyOption!false> data-struts-empty-option="true"</#if><#t/> diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/ComboBoxTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/ComboBoxTest.java index 03721c9d0..5562d9714 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/ui/ComboBoxTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/ComboBoxTest.java @@ -278,7 +278,7 @@ public class ComboBoxTest extends AbstractUITagTest { strutsBodyTagsAreReflectionEqual(tag, freshTag)); } - public void testJsCallNamingUsesEscapedId() throws Exception { + public void testDataAttributeUsesEscapedId() throws Exception { TestAction testAction = (TestAction) action; testAction.setFoo("hello"); @@ -306,7 +306,7 @@ public class ComboBoxTest extends AbstractUITagTest { strutsBodyTagsAreReflectionEqual(tag, freshTag)); } - public void testJsCallNamingUsesEscapedId_clearTagStateSet() throws Exception { + public void testDataAttributeUsesEscapedId_clearTagStateSet() throws Exception { TestAction testAction = (TestAction) action; testAction.setFoo("hello"); @@ -337,4 +337,33 @@ public class ComboBoxTest extends AbstractUITagTest { strutsBodyTagsAreReflectionEqual(tag, freshTag)); } + public void testHtml5ThemeRendersDataAttributes() throws Exception { + // The ComboBox-1..4 fixtures all render the xhtml -> simple path, so a typo in the html5 template's + // data-struts-combobox-target / data-struts-header-key / data-struts-empty-option lines would go + // unnoticed. Render the html5 theme explicitly and pin all three attributes. + TestAction testAction = (TestAction) action; + testAction.setFoo("banana"); + + List l = new ArrayList(); + l.add("apple"); + l.add("banana"); + testAction.setCollection(l); + + ComboBoxTag tag = new ComboBoxTag(); + tag.setPageContext(pageContext); + tag.setTheme("html5"); + tag.setLabel("My Favourite Fruit"); + tag.setName("myFavouriteFruit"); + tag.setEmptyOption("true"); + tag.setHeaderKey("-1"); + tag.setHeaderValue("--- Please Select ---"); + tag.setList("collection"); + tag.setValue("%{foo}"); + + tag.doStartTag(); + tag.doEndTag(); + + verify(ComboBoxTag.class.getResource("ComboBox-5.txt")); + } + } diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-1.txt index 8c91cbd7f..ecdc52238 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-1.txt @@ -1,8 +1,8 @@ <tr> <td class="tdLabel"><label for="cb" class="label">mylabel:</label></td> <td class="tdInput"> -<script src="/static/combobox.js" nonce="r4nd0m"></script> <input type="text" name="foo" value="hello" id="cb"/><br/> +<script src="/static/combobox.js" nonce="r4nd0m"></script> <select data-struts-combobox="cb" data-struts-combobox-target="foo"> <option value="foo">foo</option> <option value="bar">bar</option> diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-2.txt index 2f39ed24d..6f98ce713 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-2.txt @@ -1,8 +1,8 @@ <tr> <td class="tdLabel"><label for="myFavouriteFruit" class="label">My Favourite Fruit:</label></td> <td class="tdInput"> -<script src="/static/combobox.js"></script> <input type="text" name="myFavouriteFruit" value="banana" id="myFavouriteFruit"/><br/> +<script src="/static/combobox.js"></script> <select data-struts-combobox="myFavouriteFruit" data-struts-combobox-target="myFavouriteFruit" data-struts-header-key="-1" data-struts-empty-option="true"> <option value="-1">--- Please Select ---</option> <option value=""></option> diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-3.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-3.txt index 2f39ed24d..6f98ce713 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-3.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-3.txt @@ -1,8 +1,8 @@ <tr> <td class="tdLabel"><label for="myFavouriteFruit" class="label">My Favourite Fruit:</label></td> <td class="tdInput"> -<script src="/static/combobox.js"></script> <input type="text" name="myFavouriteFruit" value="banana" id="myFavouriteFruit"/><br/> +<script src="/static/combobox.js"></script> <select data-struts-combobox="myFavouriteFruit" data-struts-combobox-target="myFavouriteFruit" data-struts-header-key="-1" data-struts-empty-option="true"> <option value="-1">--- Please Select ---</option> <option value=""></option> diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-4.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-4.txt index 1e6830100..23f0e0caa 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-4.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-4.txt @@ -1,8 +1,8 @@ <tr> <td class="tdLabel"><label for="cb['"."']=bc(){};//" class="label">mylabel:</label></td> <td class="tdInput"> - <script src="/static/combobox.js"></script> <input type="text" name="foo" value="hello" id="cb['"."']=bc(){};//"/><br/> + <script src="/static/combobox.js"></script> <select data-struts-combobox="cb__________bc_______" data-struts-combobox-target="foo"> <option value="foo">foo</option> </select> diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-5.txt similarity index 52% copy from core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-2.txt copy to core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-5.txt index 2f39ed24d..ab9b56fba 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/ComboBox-5.txt @@ -1,15 +1,8 @@ -<tr> - <td class="tdLabel"><label for="myFavouriteFruit" class="label">My Favourite Fruit:</label></td> - <td class="tdInput"> +<input type="text" name="myFavouriteFruit" value="banana" id="myFavouriteFruit"/> <script src="/static/combobox.js"></script> -<input type="text" name="myFavouriteFruit" value="banana" id="myFavouriteFruit"/><br/> <select data-struts-combobox="myFavouriteFruit" data-struts-combobox-target="myFavouriteFruit" data-struts-header-key="-1" data-struts-empty-option="true"> - <option value="-1">--- Please Select ---</option> - <option value=""></option> + <option value="-1">--- Please Select ---</option> + <option value=""></option> <option value="apple">apple</option> <option value="banana" selected="selected">banana</option> - <option value="pineaple">pineaple</option> - <option value="grapes">grapes</option> </select> - </td> -</tr> \ No newline at end of file
