diff --git a/core/src/main/resources/org/apache/struts2/static/inputtransferselect.js b/core/src/main/resources/org/apache/struts2/static/inputtransferselect.js index 80e5a270ff..36f70b71f4 100644 --- a/core/src/main/resources/org/apache/struts2/static/inputtransferselect.js +++ b/core/src/main/resources/org/apache/struts2/static/inputtransferselect.js @@ -133,3 +133,46 @@ function swapOptions(objTargetElement, first, second) { opt[first] = temp2; opt[second] = temp; } + +/* + * Buttons rendered by the inputtransferselect tag carry their action and target select id in data-* attributes + * instead of inline onclick handlers, so the tag works under a Content-Security-Policy without 'unsafe-inline': + * data-struts-inputtransferselect="add|remove|removeAll|moveUp|moveDown", data-struts-target, optional + * data-struts-header-key + * The listener is registered once per page, in the capture phase, so it is not stopped by an ancestor's + * stopPropagation(). + */ +(function () { + if (window.strutsInputTransferSelectListener) { + return; + } + window.strutsInputTransferSelectListener = true; + + document.addEventListener('click', function (event) { + var button = event.target; + if (!button || !button.getAttribute) { + return; + } + var action = button.getAttribute('data-struts-inputtransferselect'); + if (!action) { + return; + } + var targetId = button.getAttribute('data-struts-target'); + var target = document.getElementById(targetId); + if (!target) { + return; + } + var headerKey = button.getAttribute('data-struts-header-key') || ''; + if (action === 'add') { + addOption(document.getElementById(targetId + '_input'), target); + } else if (action === 'remove') { + removeOptions(target); + } else if (action === 'removeAll') { + removeAllOptions(target); + } else if (action === 'moveUp') { + moveOptionUp(target, 'key', headerKey); + } else if (action === 'moveDown') { + moveOptionDown(target, 'key', headerKey); + } + }, true); +})(); diff --git a/core/src/main/resources/org/apache/struts2/static/optiontransferselect.js b/core/src/main/resources/org/apache/struts2/static/optiontransferselect.js index 681450b7b9..a9d91312f8 100644 --- a/core/src/main/resources/org/apache/struts2/static/optiontransferselect.js +++ b/core/src/main/resources/org/apache/struts2/static/optiontransferselect.js @@ -189,3 +189,96 @@ function swapOptions(objTargetElement, first, second) { opt[first] = temp2; opt[second] = temp; } + +/* + * Buttons rendered by the optiontransferselect and updownselect tags carry their action, target select ids and header + * keys in data-* attributes instead of inline onclick handlers, so the tags work under a Content-Security-Policy + * without 'unsafe-inline': + * data-struts-updownselect="moveUp|moveDown|selectAll", data-struts-target, optional data-struts-header-key + * data-struts-optiontransferselect="leftUp|leftDown|rightUp|rightDown|addToLeft|addToRight|addAllToLeft| + * addAllToRight|selectAll", data-struts-left, data-struts-right, optional data-struts-header-key and + * data-struts-double-header-key + * The listener is registered once per page, in the capture phase, so the framework action still runs before a + * developer-supplied onclick attribute on the same button and is not stopped by an ancestor's stopPropagation(). + */ +(function () { + if (window.strutsOptionTransferSelectListener) { + return; + } + window.strutsOptionTransferSelectListener = true; + + function headerKey(button, name) { + return button.hasAttribute(name) ? button.getAttribute(name) : undefined; + } + + function selectAll(target, key) { + if (key === undefined) { + selectAllOptions(target); + } else { + selectAllOptionsExceptSome(target, 'key', key); + } + } + + function transfer(move, source, target, key) { + if (key === undefined) { + move(source, target, false, ''); + } else { + move(source, target, false, key, ''); + } + } + + function updownselect(button, action) { + var target = document.getElementById(button.getAttribute('data-struts-target')); + var key = headerKey(button, 'data-struts-header-key'); + if (action === 'moveUp') { + moveOptionUp(target, 'key', key === undefined ? '' : key); + } else if (action === 'moveDown') { + moveOptionDown(target, 'key', key === undefined ? '' : key); + } else if (action === 'selectAll') { + selectAll(target, key); + } + } + + function optiontransferselect(button, action) { + var left = document.getElementById(button.getAttribute('data-struts-left')); + var right = document.getElementById(button.getAttribute('data-struts-right')); + var leftKey = headerKey(button, 'data-struts-header-key'); + var rightKey = headerKey(button, 'data-struts-double-header-key'); + if (action === 'leftDown') { + moveOptionDown(left, 'key', leftKey === undefined ? '' : leftKey); + } else if (action === 'leftUp') { + moveOptionUp(left, 'key', leftKey === undefined ? '' : leftKey); + } else if (action === 'rightDown') { + moveOptionDown(right, 'key', rightKey === undefined ? '' : rightKey); + } else if (action === 'rightUp') { + moveOptionUp(right, 'key', rightKey === undefined ? '' : rightKey); + } else if (action === 'addToLeft') { + transfer(moveSelectedOptions, right, left, rightKey); + } else if (action === 'addToRight') { + transfer(moveSelectedOptions, left, right, leftKey); + } else if (action === 'addAllToLeft') { + transfer(moveAllOptions, right, left, rightKey); + } else if (action === 'addAllToRight') { + transfer(moveAllOptions, left, right, leftKey); + } else if (action === 'selectAll') { + selectAll(left, leftKey); + selectAll(right, rightKey); + } + } + + document.addEventListener('click', function (event) { + var button = event.target; + if (!button || !button.getAttribute) { + return; + } + var action = button.getAttribute('data-struts-updownselect'); + if (action) { + updownselect(button, action); + return; + } + action = button.getAttribute('data-struts-optiontransferselect'); + if (action) { + optiontransferselect(button, action); + } + }, true); +})(); diff --git a/core/src/main/resources/template/html5/combobox.ftl b/core/src/main/resources/template/html5/combobox.ftl index 2ef917f781..dedda39d6e 100644 --- a/core/src/main/resources/template/html5/combobox.ftl +++ b/core/src/main/resources/template/html5/combobox.ftl @@ -37,7 +37,7 @@ function autoPopulate_${attributes.escapedId}(targetElement) { <#include "/${attributes.templateDir}/${attributes.expandTheme}/controlheader.ftl" /> <#if attributes.list??> - <#include "/${attributes.templateDir}/${attributes.expandTheme}/css.ftl" /><#rt/> <#if attributes.disabled!false> disabled="disabled"<#rt/> @@ -97,5 +97,18 @@ function autoPopulate_${attributes.escapedId}(targetElement) { >${tmpListValue}<#rt/> <#rt/> +<@s.script> + (function () { + var selects = document.querySelectorAll('select[data-struts-combobox="${attributes.escapedId}"]'); + for (var i = 0; i < selects.length; i++) { + if (!selects[i].strutsComboboxBound) { + selects[i].strutsComboboxBound = true; + selects[i].addEventListener('change', function () { + autoPopulate_${attributes.escapedId}(this); + }); + } + } + })(); + <#include "/${attributes.templateDir}/${attributes.expandTheme}/controlfooter.ftl" /><#rt/> diff --git a/core/src/main/resources/template/simple/combobox.ftl b/core/src/main/resources/template/simple/combobox.ftl index 400ae450da..ca17e4a050 100644 --- a/core/src/main/resources/template/simple/combobox.ftl +++ b/core/src/main/resources/template/simple/combobox.ftl @@ -36,7 +36,7 @@ <#include "/${attributes.templateDir}/simple/text.ftl" />
<#if attributes.list??> - <#include "/${attributes.templateDir}/${attributes.expandTheme}/css.ftl" /> <#if attributes.disabled!false> disabled="disabled"<#rt/> @@ -98,4 +98,17 @@ <#lt/> +<@s.script> + (function () { + var selects = document.querySelectorAll('select[data-struts-combobox="${attributes.escapedId}"]'); + for (var i = 0; i < selects.length; i++) { + if (!selects[i].strutsComboboxBound) { + selects[i].strutsComboboxBound = true; + selects[i].addEventListener('change', function () { + autoPopulate_${attributes.escapedId}(this); + }); + } + } + })(); + diff --git a/core/src/main/resources/template/simple/inputtransferselect.ftl b/core/src/main/resources/template/simple/inputtransferselect.ftl index c0ff17a146..90f124d2eb 100644 --- a/core/src/main/resources/template/simple/inputtransferselect.ftl +++ b/core/src/main/resources/template/simple/inputtransferselect.ftl @@ -69,7 +69,7 @@ <#if attributes.buttonCssStyle?has_content> style="${attributes.buttonCssStyle}" <#t/> - value="${addLabel}" onclick="addOption(document.getElementById('${attributes.id}_input'), document.getElementById('${attributes.id}'))" />

+ value="${addLabel}" data-struts-inputtransferselect="add" data-struts-target="${attributes.id}" />

<#t/> <#assign removeLabel=(attributes.removeLabel!"<-") /><#t/> style="${attributes.buttonCssStyle}" <#t/> - value="${removeLabel}" onclick="removeOptions(document.getElementById('${attributes.id}'))" />

+ value="${removeLabel}" data-struts-inputtransferselect="remove" data-struts-target="${attributes.id}" />

<#t/> <#assign removeAllLabel=(attributes.removeAllLabel!"<<--") /><#t/> style="${attributes.buttonCssStyle}" <#t/> - value="${removeAllLabel}" onclick="removeAllOptions(document.getElementById('${attributes.id}'))" />

+ value="${removeAllLabel}" data-struts-inputtransferselect="removeAll" data-struts-target="${attributes.id}" />

<#if attributes.rightTitle?has_content><#t/> @@ -99,20 +99,18 @@ <#include "/${attributes.templateDir}/simple/select.ftl" /> <#if attributes.allowUpDown!true> - onclick="moveOptionDown(document.getElementById('${attributes.id}'), 'key', '${attributes.headerKey}');" -<#else> - onclick="moveOptionDown(document.getElementById('${attributes.id}'), 'key', '');" + data-struts-header-key="${attributes.headerKey}" <#if attributes.downLabel?has_content> value="${attributes.downLabel}" /> - onclick="moveOptionUp(document.getElementById('${attributes.id}'), 'key', '${attributes.headerKey}');" -<#else> - onclick="moveOptionUp(document.getElementById('${attributes.id}'), 'key', '');" + data-struts-header-key="${attributes.headerKey}" <#if attributes.upLabel?has_content> value="${attributes.upLabel}" diff --git a/core/src/main/resources/template/simple/optiontransferselect.ftl b/core/src/main/resources/template/simple/optiontransferselect.ftl index abf920cd8a..28d1fdec04 100644 --- a/core/src/main/resources/template/simple/optiontransferselect.ftl +++ b/core/src/main/resources/template/simple/optiontransferselect.ftl @@ -22,6 +22,18 @@ <@s.script src="${base}${attributes.staticContentPath}/optiontransferselect.js" /> <#assign temporaryVariable = stack.setValue("#optiontransferselect_js_included", "true") /><#t/> <#t/> +<#-- + Buttons carry their action, both select ids and the header keys in data-* attributes; optiontransferselect.js binds + them, so the tag needs no framework-generated inline JavaScript under a Content-Security-Policy. A developer-supplied + *Onclick attribute is still rendered as onclick and runs after the framework action. The attribute line uses <#rt/>, + not <#t/>, to keep the space that separates it from the preceding attribute. +--> +<#macro transferButton action onclick><#t/> + data-struts-optiontransferselect="${action}" data-struts-left="${attributes.id}" data-struts-right="${attributes.doubleId!}"<#rt/> +<#if attributes.headerKey??> data-struts-header-key="${attributes.headerKey}"<#t/> +<#if attributes.doubleHeaderKey??> data-struts-double-header-key="${attributes.doubleHeaderKey}"<#t/> +<#if onclick?has_content> onclick="<#outputformat 'JavaScript'>${onclick};"<#t/> + diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/OptionTransferSelectTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/OptionTransferSelectTagTest.java index 97338d5d52..389d6db713 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/ui/OptionTransferSelectTagTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/OptionTransferSelectTagTest.java @@ -1142,6 +1142,34 @@ public void testDisableSomeButtons_clearTagStateSet() throws Exception { strutsBodyTagsAreReflectionEqual(tag, freshTag)); } + public void testButtonsCarryHeaderKeysAsDataAttributesWithoutInlineHandlers() throws Exception { + TestAction testaction = (TestAction) action; + testaction.setCollection(new ArrayList<>(List.of("Left1"))); + testaction.setList2(new ArrayList<>(List.of("Right1"))); + + OptionTransferSelectTag tag = new OptionTransferSelectTag(); + tag.setPageContext(pageContext); + tag.setId("id"); + tag.setName("collection"); + tag.setList("collection"); + tag.setHeaderKey("it's-left"); + tag.setHeaderValue("Left"); + tag.setDoubleId("doubleId"); + tag.setDoubleName("list2"); + tag.setDoubleList("list2"); + tag.setDoubleHeaderKey("it's-right"); + tag.setDoubleHeaderValue("Right"); + + tag.doStartTag(); + tag.doEndTag(); + + String output = writer.toString(); + assertFalse("framework buttons must not need inline event handlers", output.contains("onclick=")); + assertFalse("data-* attributes must be separated from the preceding attribute", output.contains("\"data-struts-")); + assertTrue(output.contains("value=\"<-\" data-struts-optiontransferselect=\"addToLeft\" data-struts-left=\"id\" data-struts-right=\"doubleId\"" + + " data-struts-header-key=\"it's-left\" data-struts-double-header-key=\"it's-right\"")); + } + public void testDynamicAttributes() throws Exception { List left = new ArrayList(); left.add("Left1"); diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/UpDownSelectTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/UpDownSelectTagTest.java index dc05b54bfc..1cba9bd97d 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/ui/UpDownSelectTagTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/UpDownSelectTagTest.java @@ -161,6 +161,24 @@ public void testWithHeaderAndEmptyOption() throws Exception { strutsBodyTagsAreReflectionEqual(tag, freshTag)); } + public void testButtonsCarryHeaderKeyAsDataAttributeWithoutInlineHandlers() throws Exception { + UpDownSelectTag tag = new UpDownSelectTag(); + tag.setPageContext(pageContext); + tag.setId("myId"); + tag.setName("myName"); + tag.setList("myMap"); + tag.setValue("mySelectedMapIds"); + tag.setHeaderKey("it's-a-key"); + tag.setHeaderValue("--- Please Order ---"); + + tag.doStartTag(); + tag.doEndTag(); + + String output = writer.toString(); + assertFalse("framework buttons must not need inline event handlers", output.contains("onclick=")); + assertTrue(output.contains("data-struts-updownselect=\"selectAll\" data-struts-target=\"myId\" data-struts-header-key=\"it's-a-key\"")); + } + public void testWithHeaderAndEmptyOption_clearTagStateSet() throws Exception { UpDownSelectTag tag = new UpDownSelectTag(); 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 670f704c3d..b3c6f098a3 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 @@ -7,10 +7,23 @@ }
- + 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 4f908b1e7b..7bea2770fc 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 @@ -13,7 +13,7 @@ }
- @@ -21,5 +21,18 @@ + \ No newline at end of file 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 4f908b1e7b..7bea2770fc 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 @@ -13,7 +13,7 @@ }
- @@ -21,5 +21,18 @@ + \ No newline at end of file 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 2e925eff7a..71063a4aba 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 @@ -7,8 +7,21 @@ }
- + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-11.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-11.txt index 6098d380ee..40dd8f001b 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-11.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-11.txt @@ -10,9 +10,9 @@
@@ -32,13 +44,13 @@ <#include "/${attributes.templateDir}/simple/select.ftl" /> <#if attributes.allowUpDownOnLeft!true> <#if attributes.leftDownLabel??> value="${attributes.leftDownLabel}" /> <#if attributes.leftUpLabel??> value="${attributes.leftUpLabel}" @@ -48,132 +60,59 @@ <#if attributes.allowAddToLeft!true><#t/> - <#assign addToLeftLabel = attributes.addToLeftLabel!"<-"/><#t/> - <#if attributes.doubleHeaderKey??><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addToLeftLabel}" onclick="moveSelectedOptions(document.getElementById('${attributes.doubleId}'), document.getElementById('${attributes.id}'), false, '${attributes.doubleHeaderKey}', '');<#if attributes.addToLeftOnclick?has_content><#outputformat 'JavaScript'>${attributes.addToLeftOnclick};" />

- <#else><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addToLeftLabel}" onclick="moveSelectedOptions(document.getElementById('${attributes.doubleId}'), document.getElementById('${attributes.id}'), false, '');<#if attributes.addToLeftOnclick?has_content><#outputformat 'JavaScript'>${attributes.addToLeftOnclick};" />

+ <#assign addToLeftLabel=attributes.addToLeftLabel!"<-" /><#t/> + <#t/> + class="${attributes.buttonCssClass}" <#t/> + <#if attributes.buttonCssStyle??><#t/> + style="${attributes.buttonCssStyle}" + <#t/> + value="${addToLeftLabel}"<@transferButton action="addToLeft" onclick=attributes.addToLeftOnclick!""/> />

<#t/> <#if attributes.allowAddToRight!true><#t/> <#assign addToRightLabel=attributes.addToRightLabel!"->" /><#t/> - <#if attributes.headerKey??><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addToRightLabel}" onclick="moveSelectedOptions(document.getElementById('${attributes.id}'), document.getElementById('${attributes.doubleId}'), false, '${attributes.headerKey}', '');<#if attributes.addToRightOnclick?has_content><#outputformat 'JavaScript'>${attributes.addToRightOnclick};" />

- <#else><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addToRightLabel}" onclick="moveSelectedOptions(document.getElementById('${attributes.id}'), document.getElementById('${attributes.doubleId}'), false, '');<#if attributes.addToRightOnclick?has_content><#outputformat 'JavaScript'>${attributes.addToRightOnclick};" />

+ <#t/> + class="${attributes.buttonCssClass}" + <#t/> + <#if attributes.buttonCssStyle??><#t/> + style="${attributes.buttonCssStyle}" <#t/> + value="${addToRightLabel}"<@transferButton action="addToRight" onclick=attributes.addToRightOnclick!""/> />

<#t/> <#if attributes.allowAddAllToLeft!true><#t/> <#assign addAllToLeftLabel=attributes.addAllToLeftLabel!"<<--" /><#t/> - <#if attributes.doubleHeaderKey??><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addAllToLeftLabel}" onclick="moveAllOptions(document.getElementById('${attributes.doubleId}'), document.getElementById('${attributes.id}'), false, '${attributes.doubleHeaderKey}', '');<#if attributes.addAllToLeftOnclick?has_content><#outputformat 'JavaScript'>${attributes.addAllToLeftOnclick};" />

- <#else><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addAllToLeftLabel}" onclick="moveAllOptions(document.getElementById('${attributes.doubleId}'), document.getElementById('${attributes.id}'), false, '');<#if attributes.addAllToLeftOnclick?has_content><#outputformat 'JavaScript'>${attributes.addAllToLeftOnclick};" />

+ <#t/> + class="${attributes.buttonCssClass}" <#t/> + <#if attributes.buttonCssStyle??><#t/> + style="${attributes.buttonCssStyle}" + <#t/> + value="${addAllToLeftLabel}"<@transferButton action="addAllToLeft" onclick=attributes.addAllToLeftOnclick!""/> />

<#t/> <#if attributes.allowAddAllToRight!true><#t/> <#assign addAllToRightLabel=attributes.addAllToRightLabel!"-->>" /><#t/> - <#if attributes.headerKey??><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addAllToRightLabel}" onclick="moveAllOptions(document.getElementById('${attributes.id}'), document.getElementById('${attributes.doubleId}'), false, '${attributes.headerKey}', '');<#if attributes.addAllToRightOnclick?has_content><#outputformat 'JavaScript'>${attributes.addAllToRightOnclick};" />

- <#else><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${addAllToRightLabel}" onclick="moveAllOptions(document.getElementById('${attributes.id}'), document.getElementById('${attributes.doubleId}'), false, '');<#if attributes.addAllToRightOnclick?has_content><#outputformat 'JavaScript'>${attributes.addAllToRightOnclick};" />

+ <#t/> + class="${attributes.buttonCssClass}" + <#t/> + <#if attributes.buttonCssStyle??><#t/> + style="${attributes.buttonCssStyle}" <#t/> + value="${addAllToRightLabel}"<@transferButton action="addAllToRight" onclick=attributes.addAllToRightOnclick!""/> />

<#t/> <#if attributes.allowSelectAll!true><#t/> <#assign selectAllLabel=attributes.selectAllLabel!"<*>" /><#t/> - <#if attributes.headerKey?? && attributes.doubleHeaderKey??><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${selectAllLabel}" onclick="selectAllOptionsExceptSome(document.getElementById('${attributes.id}'), 'key', '${attributes.headerKey}');selectAllOptionsExceptSome(document.getElementById('${attributes.doubleId}'), 'key', '${attributes.doubleHeaderKey}');<#if attributes.selectAllOnclick?has_content><#outputformat 'JavaScript'>${attributes.selectAllOnclick};" />

- <#elseif attributes.headerKey??><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${selectAllLabel}" onclick="selectAllOptionsExceptSome(document.getElementById('${attributes.id}'), 'key', '${attributes.headerKey}');selectAllOptions(document.getElementById('${attributes.doubleId}'));<#if attributes.selectAllOnclick?has_content><#outputformat 'JavaScript'>${attributes.selectAllOnclick};" />

- <#elseif attributes.doubleHeaderKey??><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${selectAllLabel}" onclick="selectAllOptions(document.getElementById('${attributes.id}'));selectAllOptionsExceptSome(document.getElementById('${attributes.doubleId}'), 'key', '${attributes.doubleHeaderKey}');<#if attributes.selectAllOnclick?has_content><#outputformat 'JavaScript'>${attributes.selectAllOnclick};" />

- <#else><#t/> - <#t/> - class="${attributes.buttonCssClass}" - <#t/> - <#if attributes.buttonCssStyle??><#t/> - style="${attributes.buttonCssStyle}" - <#t/> - value="${selectAllLabel}" onclick="selectAllOptions(document.getElementById('${attributes.id}'));selectAllOptions(document.getElementById('${attributes.doubleId}'));<#if attributes.selectAllOnclick?has_content><#outputformat 'JavaScript'>${attributes.selectAllOnclick};" />

+ <#t/> + class="${attributes.buttonCssClass}" + <#t/> + <#if attributes.buttonCssStyle??><#t/> + style="${attributes.buttonCssStyle}" <#t/> + value="${selectAllLabel}"<@transferButton action="selectAll" onclick=attributes.selectAllOnclick!""/> />

<#t/>
@@ -285,13 +224,13 @@ <#if attributes.allowUpDownOnRight!true> <#if attributes.rightDownLabel??> value="${attributes.rightDownLabel}" /> <#if attributes.rightUpLabel??> value="${attributes.rightUpLabel}" diff --git a/core/src/main/resources/template/simple/updownselect.ftl b/core/src/main/resources/template/simple/updownselect.ftl index a2e652702b..16431e6683 100644 --- a/core/src/main/resources/template/simple/updownselect.ftl +++ b/core/src/main/resources/template/simple/updownselect.ftl @@ -30,25 +30,25 @@ <#if attributes.allowMoveUp!true><#t/> <#assign defMoveUpLabel="${attributes.moveUpLabel!'^'}" /><#t/> <#if attributes.headerKey??><#t/> -    +    <#else><#t/> -    +    <#t/> <#t/> <#if attributes.allowMoveDown!true><#t/> <#assign defMoveDownLabel="${attributes.moveDownLabel!'v'}" /><#t/> <#if attributes.headerKey??><#t/> -    +    <#else><#t/> -    +    <#t/> <#t/> <#if attributes.allowSelectAll!true><#t/> <#assign defSelectAllLabel="${attributes.selectAllLabel!'*'}" /><#t/> <#if attributes.headerKey??><#t/> -    +    <#else><#t/> -    +    <#t/> <#t/>
-    -    -    +    +    +   
diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-2.txt index 4a698bffbb..4d2404bb08 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-2.txt @@ -10,9 +10,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-22.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-22.txt index bb5ebea3d6..90c8293b95 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-22.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-22.txt @@ -10,9 +10,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-24.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-24.txt index f63d81d2de..1af874b6b4 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-24.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-24.txt @@ -10,9 +10,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-6.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-6.txt index 859c79a6f3..cb74c99deb 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-6.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/Formtag-6.txt @@ -9,9 +9,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt index ef160a5c2b..e69306856c 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-1.txt @@ -4,11 +4,11 @@ - @@ -17,8 +17,8 @@ ItemOne ItemTwo - - + +
+

- +

- +

\ No newline at end of file diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt index 6260cc68c5..af5acfdb27 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/inputtransferselect-2.txt @@ -7,11 +7,11 @@ + data-struts-inputtransferselect="add" data-struts-target="collection" />

- +

- +

@@ -21,8 +21,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt index c94d405654..f9e7edff16 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-1.txt @@ -13,20 +13,20 @@ - - + +

+ value="Left" data-struts-optiontransferselect="addToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Right" data-struts-optiontransferselect="addToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Left" data-struts-optiontransferselect="addAllToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Right" data-struts-optiontransferselect="addAllToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Select All" data-struts-optiontransferselect="selectAll" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />


@@ -44,8 +44,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt index 1939871cb9..5de903cad0 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-2.txt @@ -14,20 +14,20 @@ - - + +

+ value="Left" data-struts-optiontransferselect="addToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Right" data-struts-optiontransferselect="addToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Left" data-struts-optiontransferselect="addAllToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Right" data-struts-optiontransferselect="addAllToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Select All" data-struts-optiontransferselect="selectAll" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />


- - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt index 1b0d645d59..617cbd685a 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-3.txt @@ -13,20 +13,20 @@ - - + +

+ value="Left" data-struts-optiontransferselect="addToLeft" data-struts-left="id" data-struts-right="doubleId" />



+ value="Right" data-struts-optiontransferselect="addToRight" data-struts-left="id" data-struts-right="doubleId" />



+ value="All Left" data-struts-optiontransferselect="addAllToLeft" data-struts-left="id" data-struts-right="doubleId" />



+ value="All Right" data-struts-optiontransferselect="addAllToRight" data-struts-left="id" data-struts-right="doubleId" />



+ value="Select All" data-struts-optiontransferselect="selectAll" data-struts-left="id" data-struts-right="doubleId" />


@@ -42,8 +42,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt index 6f09523278..7150a9c0c1 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-4.txt @@ -14,20 +14,20 @@ - - + +

+ value="Left" data-struts-optiontransferselect="addToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" />



+ value="Right" data-struts-optiontransferselect="addToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" />



+ value="All Left" data-struts-optiontransferselect="addAllToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" />



+ value="All Right" data-struts-optiontransferselect="addAllToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" />



+ value="Select All" data-struts-optiontransferselect="selectAll" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" />


@@ -43,8 +43,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt index 2cdccaefe8..dd7ccb14f3 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-5.txt @@ -13,20 +13,20 @@ - - + +

+ value="Left" data-struts-optiontransferselect="addToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Right" data-struts-optiontransferselect="addToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Left" data-struts-optiontransferselect="addAllToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Right" data-struts-optiontransferselect="addAllToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Select All" data-struts-optiontransferselect="selectAll" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />


@@ -42,8 +42,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt index 56fdba726e..6e13c164e9 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-6.txt @@ -14,20 +14,20 @@ - - + +

+ value="Left" data-struts-optiontransferselect="addToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Right" data-struts-optiontransferselect="addToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Left" data-struts-optiontransferselect="addAllToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="All Right" data-struts-optiontransferselect="addAllToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />



+ value="Select All" data-struts-optiontransferselect="selectAll" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" />


@@ -43,8 +43,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt index e5a0392301..07f3d26b0e 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-7.txt @@ -14,14 +14,14 @@ - - + +

+ value="Left" data-struts-optiontransferselect="addToLeft" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" onclick="alert('Moving Left');" />



+ value="Right" data-struts-optiontransferselect="addToRight" data-struts-left="id" data-struts-right="doubleId" data-struts-header-key="Header Key" data-struts-double-header-key="Double Header Key" onclick="alert('Moving Right');" />


@@ -38,8 +38,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt index 69358f9328..d8225ee1a7 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/optiontransferselect-8.txt @@ -10,28 +10,28 @@ - - + + + data-struts-optiontransferselect="addToLeft" data-struts-left="collection" data-struts-right="list2" />

+ data-struts-optiontransferselect="addToRight" data-struts-left="collection" data-struts-right="list2" />

+ data-struts-optiontransferselect="addAllToLeft" data-struts-left="collection" data-struts-right="list2" />

+ data-struts-optiontransferselect="addAllToRight" data-struts-left="collection" data-struts-right="list2" />

+ data-struts-optiontransferselect="selectAll" data-struts-left="collection" data-struts-right="list2" />

@@ -41,8 +41,8 @@ - - + + diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt index eb86508da8..f757cae418 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-1.txt @@ -12,9 +12,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt index 76489dda30..8a26cab2cc 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-10.txt @@ -12,9 +12,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt index 943766ef62..ba63777497 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-11.txt @@ -12,9 +12,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt index fd2d70840d..816e0c1e17 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-2.txt @@ -11,9 +11,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt index 3a1cf7e652..9766b0a350 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-3.txt @@ -13,9 +13,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt index c27eeb97d4..bb0f751494 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-4.txt @@ -12,9 +12,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt index 168ed9c071..69436b8222 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-5.txt @@ -12,9 +12,9 @@ -    -    -    +    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt index 47644f52d2..4981f617b1 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-6.txt @@ -12,8 +12,8 @@ -    -    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt index 551e397415..d47a496d6f 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-7.txt @@ -12,8 +12,8 @@ -    -    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt index d089a88be4..55de5f3f6b 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-8.txt @@ -12,8 +12,8 @@ -    -    +    +    diff --git a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt index 26d4629bc3..3b99f0ad71 100644 --- a/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt +++ b/core/src/test/resources/org/apache/struts2/views/jsp/ui/updownselecttag-9.txt @@ -12,9 +12,9 @@ -    -    -    +    +    +