add missing escapedIds
diff --git a/core/src/main/java/org/apache/struts2/components/FormButton.java b/core/src/main/java/org/apache/struts2/components/FormButton.java
index 5cf88bc..d9e75f1 100644
--- a/core/src/main/java/org/apache/struts2/components/FormButton.java
+++ b/core/src/main/java/org/apache/struts2/components/FormButton.java
@@ -122,6 +122,7 @@
             }
         }
         addParameter("id", _tmp_id);
+        addParameter("escapedId", escape(_tmp_id));
     }
 
     /**
diff --git a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
index a302e8a..3fa1925 100644
--- a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
+++ b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
@@ -191,7 +191,9 @@
 
             // if the id isn't specified, use the action name
             if (formComponent.getId() == null && actionName != null) {
-                formComponent.addParameter("id", formComponent.escape(actionName));
+                String escapedId = formComponent.escape(actionName);
+                formComponent.addParameter("id", escapedId);
+                formComponent.addParameter("escapedId", escapedId);
             }
         } else if (action != null) {
             // Since we can't find an action alias in the configuration, we just
@@ -226,7 +228,9 @@
                 } else {
                     id = result.substring(slash + 1);
                 }
-                formComponent.addParameter("id", formComponent.escape(id));
+                String escapedId = formComponent.escape(id);
+                formComponent.addParameter("id", escapedId);
+                formComponent.addParameter("escapedId", escapedId);
             }
         }
 
diff --git a/core/src/main/java/org/apache/struts2/components/UIBean.java b/core/src/main/java/org/apache/struts2/components/UIBean.java
index c47f7ac..24b47fa 100644
--- a/core/src/main/java/org/apache/struts2/components/UIBean.java
+++ b/core/src/main/java/org/apache/struts2/components/UIBean.java
@@ -907,7 +907,7 @@
     protected String escape(String name) {
         // escape any possible values that can make the ID painful to work with in JavaScript
         if (name != null) {
-            return name.replaceAll("[/.\\[\\]'\"]", "_");
+            return name.replaceAll("[^a-zA-Z0-9_]", "_");
         } else {
             return null;
         }
diff --git a/core/src/main/resources/template/css_xhtml/form-validate.ftl b/core/src/main/resources/template/css_xhtml/form-validate.ftl
index a45aa71..da7b240 100644
--- a/core/src/main/resources/template/css_xhtml/form-validate.ftl
+++ b/core/src/main/resources/template/css_xhtml/form-validate.ftl
@@ -21,8 +21,8 @@
 <#if parameters.validate!false == true>
 <script type="text/javascript" src="${base}${parameters.staticContentPath}/css_xhtml/validation.js"></script>
     <#if parameters.onsubmit??>
-        ${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.id}();")}
+        ${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.escapedId}();")}
     <#else>
-        ${tag.addParameter('onsubmit', "return validateForm_${parameters.id}();")}
+        ${tag.addParameter('onsubmit', "return validateForm_${parameters.escapedId}();")}
     </#if>
 </#if>
diff --git a/core/src/main/resources/template/simple/combobox.ftl b/core/src/main/resources/template/simple/combobox.ftl
index 390e20d..761b577 100644
--- a/core/src/main/resources/template/simple/combobox.ftl
+++ b/core/src/main/resources/template/simple/combobox.ftl
@@ -21,7 +21,7 @@
 <script type="text/javascript" <#include "/${parameters.templateDir}/simple/nonce.ftl" /> >
 	function autoPopulate_${parameters.escapedId}(targetElement) {
 		<#if parameters.headerKey?? && parameters.headerValue??>
-		if (targetElement.options[targetElement.selectedIndex].value == '${parameters.headerKey}') {
+		if (targetElement.options[targetElement.selectedIndex].value == '${parameters.headerKey?js_string}') {
 			return;
 		}
 		</#if>
@@ -30,7 +30,7 @@
 		    return;
 		}
 		</#if>
-		targetElement.form.elements['${parameters.name}'].value=targetElement.options[targetElement.selectedIndex].value;
+		targetElement.form.elements['${parameters.name?js_string}'].value=targetElement.options[targetElement.selectedIndex].value;
 	}
 </script>
 <#include "/${parameters.templateDir}/simple/text.ftl" />
diff --git a/core/src/main/resources/template/simple/doubleselect.ftl b/core/src/main/resources/template/simple/doubleselect.ftl
index 67aafee..58f9b5d 100644
--- a/core/src/main/resources/template/simple/doubleselect.ftl
+++ b/core/src/main/resources/template/simple/doubleselect.ftl
@@ -72,9 +72,9 @@
 </#if>
 <script type="text/javascript" <#include "/${parameters.templateDir}/simple/nonce.ftl" /> >
     <#assign itemCount = startCount/>
-    var ${parameters.id}Group = new Array(${parameters.listSize} + ${startCount});
-    for (var i = 0; i < (${parameters.listSize} + ${startCount}); i++) {
-        ${parameters.id}Group[i] = [];
+    var ${parameters.escapedId}Group = new Array(${parameters.listSize?number?c} + ${startCount});
+    for (var i = 0; i < (${parameters.listSize?number?c} + ${startCount}); i++) {
+        ${parameters.escapedId}Group[i] = [];
     }
 
     <@s.iterator value="parameters.list">
@@ -90,11 +90,11 @@
         </#if>
         <#assign doubleItemCount = 0/>
         <#if parameters.doubleHeaderKey?? && parameters.doubleHeaderValue??>
-        ${parameters.id}Group[${itemCount}][${doubleItemCount}] = new Option("${parameters.doubleHeaderValue?js_string}", "${parameters.doubleHeaderKey?js_string}");
+        ${parameters.escapedId}Group[${itemCount}][${doubleItemCount}] = new Option("${parameters.doubleHeaderValue?js_string}", "${parameters.doubleHeaderKey?js_string}");
             <#assign doubleItemCount = doubleItemCount + 1/>
         </#if>
         <#if parameters.doubleEmptyOption??>
-        ${parameters.id}Group[${itemCount}][${doubleItemCount}] = new Option("", "");
+        ${parameters.escapedId}Group[${itemCount}][${doubleItemCount}] = new Option("", "");
             <#assign doubleItemCount = doubleItemCount + 1/>
         </#if>
     <@s.iterator value="${parameters.doubleList}">
@@ -130,15 +130,15 @@
               <#assign itemDoubleTitle = ''/>
             </#if>
         </#if>
-    ${parameters.id}Group[${itemCount}][${doubleItemCount}] = new Option("${doubleItemValue?js_string}", "${doubleItemKeyStr?js_string}");
+    ${parameters.escapedId}Group[${itemCount}][${doubleItemCount}] = new Option("${doubleItemValue?js_string}", "${doubleItemKeyStr?js_string}");
         <#if itemDoubleCssClass??>
-    ${parameters.id}Group[${itemCount}][${doubleItemCount}].setAttribute("class","${itemDoubleCssClass}");
+    ${parameters.escapedId}Group[${itemCount}][${doubleItemCount}].setAttribute("class","${itemDoubleCssClass}");
         </#if>
         <#if itemDoubleCssStyle??>
-        ${parameters.id}Group[${itemCount}][${doubleItemCount}].setAttribute("style","${itemDoubleCssStyle}");
+        ${parameters.escapedId}Group[${itemCount}][${doubleItemCount}].setAttribute("style","${itemDoubleCssStyle}");
         </#if>
         <#if itemDoubleTitle??>
-        ${parameters.id}Group[${itemCount}][${doubleItemCount}].setAttribute("title","${itemDoubleTitle}");
+        ${parameters.escapedId}Group[${itemCount}][${doubleItemCount}].setAttribute("title","${itemDoubleTitle}");
         </#if>
 
         <#assign doubleItemCount = doubleItemCount + 1/>
@@ -146,7 +146,7 @@
         <#assign itemCount = itemCount + 1/>
     </@s.iterator>
 
-    var ${parameters.id}Temp = document.${parameters.formName}.${parameters.doubleId};
+    var ${parameters.escapedId}Temp = document.${parameters.formName}.${parameters.doubleId};
     <#assign itemCount = startCount/>
     <#assign redirectTo = 0/>
     <@s.iterator value="parameters.list">
@@ -160,34 +160,34 @@
         </#if>
         <#assign itemCount = itemCount + 1/>
     </@s.iterator>
-    ${parameters.id}Redirect(${redirectTo});
-    function ${parameters.id}Redirect(x) {
+    ${parameters.escapedId}Redirect(${redirectTo});
+    function ${parameters.escapedId}Redirect(x) {
         var selected = false;
-        for (var m = ${parameters.id}Temp.options.length - 1; m >= 0; m--) {
-            ${parameters.id}Temp.remove(m);
+        for (var m = ${parameters.escapedId}Temp.options.length - 1; m >= 0; m--) {
+            ${parameters.escapedId}Temp.remove(m);
         }
 
-        for (var i = 0; i < ${parameters.id}Group[x].length; i++) {
-            ${parameters.id}Temp.options[i] = new Option(${parameters.id}Group[x][i].text, ${parameters.id}Group[x][i].value);
+        for (var i = 0; i < ${parameters.escapedId}Group[x].length; i++) {
+            ${parameters.escapedId}Temp.options[i] = new Option(${parameters.escapedId}Group[x][i].text, ${parameters.escapedId}Group[x][i].value);
         <#if parameters.doubleNameValue??>
             <#if parameters.doubleMultiple??>
                 for (var j = 0; j < ${parameters.doubleNameValue}.length; j++) {
-                    if (${parameters.id}Temp.options[i].value == ${parameters.doubleNameValue?js_string}[j]) {
-                        ${parameters.id}Temp.options[i].selected = true;
+                    if (${parameters.escapedId}Temp.options[i].value == ${parameters.doubleNameValue?js_string}[j]) {
+                        ${parameters.escapedId}Temp.options[i].selected = true;
                         selected = true;
                     }
                 }
                 <#else>
-                    if (${parameters.id}Temp.options[i].value == '${parameters.doubleNameValue?js_string}') {
-                        ${parameters.id}Temp.options[i].selected = true;
+                    if (${parameters.escapedId}Temp.options[i].value == '${parameters.doubleNameValue?js_string}') {
+                        ${parameters.escapedId}Temp.options[i].selected = true;
                         selected = true;
                     }
             </#if>
         </#if>
         }
 
-        if ((${parameters.id}Temp.options.length > 0) && (! selected)) {
-            ${parameters.id}Temp.options[0].selected = true;
+        if ((${parameters.escapedId}Temp.options.length > 0) && (! selected)) {
+            ${parameters.escapedId}Temp.options[0].selected = true;
         }
     }
 </script>
\ No newline at end of file
diff --git a/core/src/main/resources/template/simple/form-close.ftl b/core/src/main/resources/template/simple/form-close.ftl
index 1929329..c2285b2 100644
--- a/core/src/main/resources/template/simple/form-close.ftl
+++ b/core/src/main/resources/template/simple/form-close.ftl
@@ -27,15 +27,15 @@
   submission.
 -->
 <#if (parameters.optiontransferselectIds!?size > 0)>
-	var containingForm = document.getElementById("${parameters.id}");
+	var containingForm = document.getElementById("${parameters.id?js_string}");
 	<#assign selectObjIds = parameters.optiontransferselectIds.keySet() />
 	<#list selectObjIds as selectObjectId>
 		StrutsUtils.addEventListener(containingForm, "submit",
 			function(evt) {
-				var selectObj = document.getElementById("${selectObjectId}");
+				var selectObj = document.getElementById("${selectObjectId?js_string}");
 				<#if parameters.optiontransferselectIds.get(selectObjectId)??>
 					<#assign selectTagHeaderKey = parameters.optiontransferselectIds.get(selectObjectId)/>
-					selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey}");
+					selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey?js_string}");
 				<#else>
 					selectAllOptionsExceptSome(selectObj, "key", "");
 				</#if>
@@ -43,15 +43,15 @@
 	</#list>
 </#if>
 <#if (parameters.inputtransferselectIds!?size > 0)>
-	var containingForm = document.getElementById("${parameters.id}");
+	var containingForm = document.getElementById("${parameters.id?js_string}");
 	<#assign selectObjIds = parameters.inputtransferselectIds.keySet() />
 	<#list selectObjIds as selectObjectId>
 		StrutsUtils.addEventListener(containingForm, "submit",
 			function(evt) {
-				var selectObj = document.getElementById("${selectObjectId}");
+				var selectObj = document.getElementById("${selectObjectId?js_string}");
 				<#if parameters.inputtransferselectIds.get(selectObjectId)??>
 					<#assign selectTagHeaderKey = parameters.inputtransferselectIds.get(selectObjectId)/>
-					selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey}");
+					selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey?js_string}");
 				<#else>
 					selectAllOptionsExceptSome(selectObj, "key", "");
 				</#if>
@@ -59,15 +59,15 @@
 	</#list>
 </#if>
 <#if (parameters.optiontransferselectDoubleIds!?size > 0)>
-	var containingForm = document.getElementById("${parameters.id}");
+	var containingForm = document.getElementById("${parameters.id?js_string}");
 	<#assign selectDoubleObjIds = parameters.optiontransferselectDoubleIds.keySet() />
 	<#list selectDoubleObjIds as selectObjId>
 		StrutsUtils.addEventListener(containingForm, "submit",
 			function(evt) {
-				var selectObj = document.getElementById("${selectObjId}");
+				var selectObj = document.getElementById("${selectObjId?js_string}");
 				<#if parameters.optiontransferselectDoubleIds.get(selectObjId)??>
 					<#assign selectTagHeaderKey = parameters.optiontransferselectDoubleIds.get(selectObjId)/>
-					selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey}");
+					selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey?js_string}");
 				<#else>
 					selectAllOptionsExceptSome(selectObj, "key", "");
 				</#if>
@@ -81,15 +81,15 @@
 	submission
 -->
 <#if (parameters.updownselectIds!?size > 0)>
-	var containingForm = document.getElementById("${parameters.id}");
+	var containingForm = document.getElementById("${parameters.id?js_string}");
 	<#assign tmpIds = parameters.updownselectIds.keySet() />
 	<#list tmpIds as tmpId>
 		StrutsUtils.addEventListener(containingForm, "submit",
 			function(evt) {
-				var updownselectObj = document.getElementById("${tmpId}");
+				var updownselectObj = document.getElementById("${tmpId?js_string}");
 				<#if parameters.updownselectIds.get(tmpId)??>
 					<#assign tmpHeaderKey = parameters.updownselectIds.get(tmpId) />
-					selectAllOptionsExceptSome(updownselectObj, "key", "${tmpHeaderKey}");
+					selectAllOptionsExceptSome(updownselectObj, "key", "${tmpHeaderKey?js_string}");
 				<#else>
 					selectAllOptionsExceptSome(updownselectObj, "key", "");
 				</#if>
diff --git a/core/src/main/resources/template/xhtml/form-close-validate.ftl b/core/src/main/resources/template/xhtml/form-close-validate.ftl
index 0a17aac..afa1c50 100644
--- a/core/src/main/resources/template/xhtml/form-close-validate.ftl
+++ b/core/src/main/resources/template/xhtml/form-close-validate.ftl
@@ -33,7 +33,7 @@
 -->
 <#if ((parameters.validate!false == true) && (parameters.performValidation!false == true))>
 <script type="text/javascript" <#include "/${parameters.templateDir}/simple/nonce.ftl" /> >
-    function validateForm_${parameters.id?replace('[^a-zA-Z0-9_]', '_', 'r')}() {
+    function validateForm_${parameters.escapedId}() {
         <#--
             In case of multiselect fields return only the first value.
         -->
@@ -54,7 +54,7 @@
             }
             return field.value;
         }
-        form = document.getElementById("${parameters.id}");
+        form = document.getElementById("${parameters.id?js_string}");
         clearErrorMessages(form);
         clearErrorLabels(form);
 
@@ -62,10 +62,10 @@
         var continueValidation = true;
     <#list parameters.tagNames as tagName>
         <#list tag.getValidators("${tagName}") as aValidator>
-        // field name: ${aValidator.fieldName}
+        // field name: ${aValidator.fieldName?js_string}
         // validator name: ${aValidator.validatorType}
-        if (form.elements['${aValidator.fieldName}']) {
-            field = form.elements['${aValidator.fieldName}'];
+        if (form.elements['${aValidator.fieldName?js_string}']) {
+            field = form.elements['${aValidator.fieldName?js_string}'];
             <#if aValidator.validatorType = "field-visitor">
                 <#assign validator = aValidator.fieldValidator >
                 //visitor validator switched to: ${validator.validatorType}
diff --git a/core/src/main/resources/template/xhtml/form-close.ftl b/core/src/main/resources/template/xhtml/form-close.ftl
index 0992f8e..b8a90fc 100644
--- a/core/src/main/resources/template/xhtml/form-close.ftl
+++ b/core/src/main/resources/template/xhtml/form-close.ftl
@@ -24,7 +24,7 @@
 <#if parameters.focusElement??>
 <script type="text/javascript" <#include "/${parameters.templateDir}/simple/nonce.ftl" /> >
     StrutsUtils.addOnLoad(function() {
-        var element = document.getElementById("${parameters.focusElement}");
+        var element = document.getElementById("${parameters.focusElement?js_string}");
         if(element) {
             element.focus();
         }
diff --git a/core/src/main/resources/template/xhtml/form-validate.ftl b/core/src/main/resources/template/xhtml/form-validate.ftl
index 33e8b55..2880ffb 100644
--- a/core/src/main/resources/template/xhtml/form-validate.ftl
+++ b/core/src/main/resources/template/xhtml/form-validate.ftl
@@ -21,8 +21,8 @@
 <#if parameters.validate!false == true>
 	<script type="text/javascript" src="${base}${parameters.staticContentPath}/xhtml/validation.js" <#include "/${parameters.templateDir}/simple/nonce.ftl" /> ></script>
 	<#if parameters.onsubmit??>
-		${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.id?replace('[^a-zA-Z0-9_]', '_', 'r')}();")}
+		${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.escapedId}();")}
 	<#else>
-		${tag.addParameter('onsubmit', "return validateForm_${parameters.id?replace('[^a-zA-Z0-9_]', '_', 'r')}();")}
+		${tag.addParameter('onsubmit', "return validateForm_${parameters.escapedId}();")}
 	</#if>
 </#if>
diff --git a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
index 9b90e0c..90575f3 100644
--- a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
+++ b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java
@@ -114,8 +114,8 @@
         assertEquals(bean.escape("hello[world"), "hello_world");
         assertEquals(bean.escape("hello.world"), "hello_world");
         assertEquals(bean.escape("hello]world"), "hello_world");
-        assertEquals(bean.escape("hello!world"), "hello!world");
-        assertEquals(bean.escape("hello!@#$%^&*()world"), "hello!@#$%^&*()world");
+        assertEquals(bean.escape("hello!world"), "hello_world");
+        assertEquals(bean.escape("hello!@#$%^&*()world"), "hello__________world");
     }
 
     public void testEscapeId() {
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 a3f5027..03b627e 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
@@ -147,7 +147,7 @@
         tag.setPageContext(pageContext);
         tag.setLabel("mylabel");
         tag.setName("foo");
-        tag.setId("cb.bc");
+        tag.setId("cb['\".\"'] = bc(){};//");
         tag.setList("collection");
 
         tag.doStartTag();
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 cea7465..f724754 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,13 +1,13 @@
  <tr>
-     <td class="tdLabel"><label for="cb.bc" class="label">mylabel:</label></td>
+     <td class="tdLabel"><label for="cb[&#39;&quot;.&quot;&#39;]=bc(){};//" class="label">mylabel:</label></td>
      <td class="tdInput">
  <script type="text/javascript">
-    function autoPopulate_cb_bc(targetElement) {
+    function autoPopulate_cb__________bc_______(targetElement) {
         targetElement.form.elements['foo'].value=targetElement.options[targetElement.selectedIndex].value;
     }
  </script>
- <input type="text" name="foo" value="hello" id="cb.bc"/><br/>
- <select onChange="autoPopulate_cb_bc(this);">
+ <input type="text" name="foo" value="hello" id="cb[&#39;&quot;.&quot;&#39;]=bc(){};//"/><br/>
+ <select onChange="autoPopulate_cb__________bc_______(this);">
      <option value="foo">foo</option>
  </select>
      </td>
diff --git a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
index 4b51f7e..a286deb 100644
--- a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
+++ b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
@@ -192,7 +192,9 @@
                 } else {

                     id = action.substring(slash + 1);

                 }

-                formComponent.addParameter("id", formComponent.escape(id));

+                String escapedId = formComponent.escape(id);

+                formComponent.addParameter("id", escapedId);

+                formComponent.addParameter("escapedId", escapedId);

             }

         }

     }