DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8788>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8788 Indexed field validation patch Summary: Indexed field validation patch Product: Struts Version: Nightly Build Platform: All OS/Version: All Status: NEW Severity: Enhancement Priority: Other Component: Custom Tags AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] I need indexed field validation for my application. I've started to work on it and realized it's quite a large project. This is what I've got so far. I still need to change validation-rules.xml to work with these changes, but this code generates field names for indexed properties. You'll also need the patch I've submitted for commons-validator. Comments? Suggestions? Am I even on the right path? Index: src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java =================================================================== RCS file: /home/cvspublic/jakarta-struts/src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java,v retrieving revision 1.2 diff -u -3 -p -r1.2 JavascriptValidatorTag.java --- src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java 18 Mar 2002 02:06:41 -0000 1.2 +++ src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java 3 May 2002 +17:12:41 -0000 @@ -56,10 +56,13 @@ package org.apache.struts.taglib.html; +import java.lang.reflect.Array; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -76,13 +79,15 @@ import org.apache.commons.validator.Vali import org.apache.commons.validator.Var; import org.apache.struts.action.Action; import org.apache.struts.validator.ValidatorPlugIn; +import org.apache.struts.util.IteratorAdapter; import org.apache.struts.util.MessageResources; +import org.apache.struts.util.RequestUtils; import org.apache.struts.util.StrutsValidatorUtil; /** - * Custom tag that generates JavaScript for client side validation based - * on the validation rules loaded by the <code>ValidatorPlugIn</code> + * Custom tag that generates JavaScript for client side validation based + * on the validation rules loaded by the <code>ValidatorPlugIn</code> * defined in the struts-config.xml file. * * @since 1.1 @@ -92,6 +97,12 @@ public class JavascriptValidatorTag exte // ----------------------------------------------------------- Properties + /** + * The message resources for this package. + */ + protected static MessageResources messages = + MessageResources.getMessageResources + ("org.apache.struts.taglib.html.LocalStrings"); /** @@ -106,18 +117,18 @@ public class JavascriptValidatorTag exte protected static Locale defaultLocale = Locale.getDefault(); /** - * The name of the form that corresponds with the action name + * The name of the form that corresponds with the action name * in struts-config.xml. */ protected String formName = null; /** - * The current page number of a multi-part form. + * The current page number of a multi-part form. */ protected int page = 0; /** - * This will be used as is for the JavaScript validation method name if it has a value. This is + * This will be used as is for the JavaScript validation method name if it has a value. This is * the method name of the main JavaScript method that the form calls to perform validations. */ protected String methodName = null; @@ -138,17 +149,17 @@ public class JavascriptValidatorTag exte protected String src = null; /** - * Gets the key (form name) that will be used - * to retrieve a set of validation rules to be + * Gets the key (form name) that will be used + * to retrieve a set of validation rules to be * performed on the bean passed in for validation. */ public String getFormName() { - return formName; + return formName; } /** - * Sets the key (form name) that will be used - * to retrieve a set of validation rules to be + * Sets the key (form name) that will be used + * to retrieve a set of validation rules to be * performed on the bean passed in for validation. */ public void setFormName(String formName) { @@ -156,17 +167,17 @@ public class JavascriptValidatorTag exte } /** - * Gets the current page number of a multi-part form. - * Only field validations with a matching page numer + * Gets the current page number of a multi-part form. + * Only field validations with a matching page numer * will be generated that match the current page number. */ public int getPage() { - return page; + return page; } /** - * Sets the current page number of a multi-part form. - * Only field validations with a matching page numer + * Sets the current page number of a multi-part form. + * Only field validations with a matching page numer * will be generated that match the current page number. */ public void setPage(int page) { @@ -174,19 +185,19 @@ public class JavascriptValidatorTag exte } /** - * Gets the method name that will be used for the Javascript - * validation method name if it has a value. This overrides - * the auto-generated method name based on the key (form name) + * Gets the method name that will be used for the Javascript + * validation method name if it has a value. This overrides + * the auto-generated method name based on the key (form name) * passed in. */ public String getMethod() { - return methodName; + return methodName; } /** - * Sets the method name that will be used for the Javascript - * validation method name if it has a value. This overrides - * the auto-generated method name based on the key (form name) + * Sets the method name that will be used for the Javascript + * validation method name if it has a value. This overrides + * the auto-generated method name based on the key (form name) * passed in. */ public void setMethod(String methodName) { @@ -194,17 +205,17 @@ public class JavascriptValidatorTag exte } /** - * Gets whether or not to generate the static - * JavaScript. If this is set to 'true', which + * Gets whether or not to generate the static + * JavaScript. If this is set to 'true', which * is the default, the static JavaScript will be generated. */ public String getStaticJavascript() { - return staticJavascript; + return staticJavascript; } /** - * Sets whether or not to generate the static - * JavaScript. If this is set to 'true', which + * Sets whether or not to generate the static + * JavaScript. If this is set to 'true', which * is the default, the static JavaScript will be generated. */ public void setStaticJavascript(String staticJavascript) { @@ -212,17 +223,17 @@ public class JavascriptValidatorTag exte } /** - * Gets whether or not to generate the dynamic - * JavaScript. If this is set to 'true', which + * Gets whether or not to generate the dynamic + * JavaScript. If this is set to 'true', which * is the default, the dynamic JavaScript will be generated. */ public String getDynamicJavascript() { - return dynamicJavascript; + return dynamicJavascript; } /** - * Sets whether or not to generate the dynamic - * JavaScript. If this is set to 'true', which + * Sets whether or not to generate the dynamic + * JavaScript. If this is set to 'true', which * is the default, the dynamic JavaScript will be generated. */ public void setDynamicJavascript(String dynamicJavascript) { @@ -230,15 +241,15 @@ public class JavascriptValidatorTag exte } /** - * Gets the src attribute's value when defining + * Gets the src attribute's value when defining * the html script element. */ public String getSrc() { - return src; + return src; } /** - * Sets the src attribute's value when defining + * Sets the src attribute's value when defining * the html script element. */ public void setSrc(String src) { @@ -279,7 +290,7 @@ public class JavascriptValidatorTag exte for (Iterator i = form.getFields().iterator(); i.hasNext(); ) { Field field = (Field)i.next(); - for (Iterator x = field.getDependencies().iterator(); x.hasNext(); ) { + for (Iterator x = field.getDependencies().iterator(); x.hasNext(); ) { Object o = x.next(); if (o != null && !lActionMethods.contains(o)) { @@ -306,20 +317,20 @@ public class JavascriptValidatorTag exte ValidatorAction va1 = (ValidatorAction)o1; ValidatorAction va2 = (ValidatorAction)o2; - if ((va1.getDepends() == null || va1.getDepends().length() == 0) && + if ((va1.getDepends() == null || va1.getDepends().length() == 0) && (va2.getDepends() == null || va2.getDepends().length() == 0)) { return 0; } else if ((va1.getDepends() != null && va1.getDepends().length() > 0) && (va2.getDepends() == null || va2.getDepends().length() == 0)) { return 1; - } else if ((va1.getDepends() == null || va1.getDepends().length() == 0) && + } else if ((va1.getDepends() == null || va1.getDepends().length() == 0) && (va2.getDepends() != null && va2.getDepends().length() > 0)) { return -1; } else { return va1.getDependencies().size() - va2.getDependencies().size(); } } - }); + }); String methods = null; for (Iterator i = lActions.iterator(); i.hasNext(); ) { @@ -347,43 +358,46 @@ public class JavascriptValidatorTag exte results.append(" function " + functionName + " () { \n"); for (Iterator x = form.getFields().iterator(); x.hasNext(); ) { - Field field = (Field)x.next(); + Field field = (Field)x.next(); - // Skip indexed fields for now until there is + // Skip indexed fields for now until there is // a good way to handle error messages (and the length of the list (could retrieve from scope?)) - if (!field.isIndexed() && field.getPage() == page && field.isDependency(va.getName())) { + if ( field.getPage() == page && field.isDependency(va.getName())) { String message = StrutsValidatorUtil.getMessage(messages, locale, va, field); message = (message != null ? message : ""); - jscriptVar = getNextVar(jscriptVar); - - results.append(" this." + jscriptVar + " = new Array(\"" + field.getKey() + "\", \"" + message + "\", "); - - results.append("new Function (\"varName\", \""); - - Map hVars = field.getVars(); - // Loop through the field's variables. - for (Iterator iVars = hVars.keySet().iterator(); iVars.hasNext(); ) { - String varKey = (String)iVars.next(); - Var var = (Var)hVars.get(varKey); - String varValue = var.getValue(); - String jsType = var.getJsType(); - - if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) { - results.append("this." + varKey + "=" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "; "); - } else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(jsType)) { - results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; "); - } else if (Var.JSTYPE_STRING.equalsIgnoreCase(jsType)) { - results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; "); - // So everyone using the latest format doesn't need to change their xml files immediately. - } else if ("mask".equalsIgnoreCase(varKey)) { - results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; "); - } else { - results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; "); - } - } - - results.append(" return this[varName];\"));\n"); + generateParameterNames( results, field, message, jscriptVar ); +// jscriptVar = getNextVar(jscriptVar); +// +// results.append(" this." + jscriptVar + " = new Array(\"" ); +// results.append( field.getKey() ); +// results.append( "\", \"" + message + "\", "); +// +// results.append("new Function (\"varName\", \""); +// +// Map hVars = field.getVars(); +// // Loop through the field's variables. +// for (Iterator iVars = hVars.keySet().iterator(); iVars.hasNext(); ) { +// String varKey = (String)iVars.next(); +// Var var = (Var)hVars.get(varKey); +// String varValue = var.getValue(); +// String jsType = var.getJsType(); +// +// if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) { +// results.append("this." + varKey + "=" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "; "); +// } else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(jsType)) { +// results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; "); +// } else if (Var.JSTYPE_STRING.equalsIgnoreCase(jsType)) { +// results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; "); +// // So everyone using the latest format doesn't need to change their xml files immediately. +// } else if ("mask".equalsIgnoreCase(varKey)) { +// results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; "); +// } else { +// results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; "); +// } +// } +// +// results.append(" return this[varName];\"));\n"); } } results.append(" } \n\n"); @@ -444,12 +458,12 @@ public class JavascriptValidatorTag exte if (methodName == null || methodName.length() == 0) sb.append(" function validate" + name + "(form) { \n"); - else + else sb.append(" function " + methodName + "(form) { \n"); sb.append(" if (bCancel) \n"); sb.append(" return true; \n"); - sb.append(" else \n"); + sb.append(" else \n"); // Always return true if there aren't any Javascript validation methods if (methods == null || methods.length() == 0) { @@ -489,12 +503,119 @@ public class JavascriptValidatorTag exte sb.append("</SCRIPT>\n\n"); return sb.toString(); - } + } + + /** + * Hopefully creates correct parameter names for indexed fields + */ + protected void generateParameterNames( StringBuffer results, + Field field, String message, + String jscriptVar ) + throws JspException + { + jscriptVar = getNextVar(jscriptVar); + results.append(" this." + jscriptVar + " = new Array(" ); + + if( field.isIndexed() ) { + //Get the collection (worry about scope??) + Object collection = RequestUtils.lookup(pageContext, + field.getIteratorName(), + field.getIndexedListProperty(), + null ); + if (collection == null) { + JspException e = new JspException( messages.getMessage("javascriptValidatorTag.collection")); + RequestUtils.saveException(pageContext, e); + throw e; + } + // Construct an iterator for this collection + Iterator iterator = null; + + if (collection.getClass().isArray()) { + int length = Array.getLength(collection); + ArrayList c = new ArrayList(length); + for (int i = 0; i < length; i++) { + c.add(Array.get(collection, i)); + } + iterator = c.iterator(); + } else if (collection instanceof Collection) + iterator = ((Collection) collection).iterator(); + else if (collection instanceof Iterator) + iterator = (Iterator) collection; + else if (collection instanceof Map) + iterator = ((Map) collection).entrySet().iterator(); + else if (collection instanceof Enumeration) + iterator = new IteratorAdapter((Enumeration)collection); + else { + JspException e = new JspException + (messages.getMessage("javascriptValidatorTag.iterator")); + RequestUtils.saveException(pageContext, e); + throw e; + } + + //And finally build the parameter names + for (int pos = 0; (iterator != null) && iterator.hasNext(); pos++) { + StringBuffer fieldName = new StringBuffer(); + iterator.next(); + + results.append( "new Array(\"" ); + fieldName.append( field.getIndexedProperty() ); + fieldName.append( "[" ); + fieldName.append( pos ); + fieldName.append( "]." ); + fieldName.append( field.getKey() ); + generateParameterName( results, field, message, fieldName.toString() ); + + if( iterator.hasNext() ) results.append( ",\n" ); + } + results.append( ")" ); + } + else { + results.append( "\"" ); + generateParameterName( results, field, message, field.getKey() ); + } + + results.append( ";\n" ); + } + /** + * Hopefully creates correct parameter names for indexed fields + */ + protected static void generateParameterName( StringBuffer results, + Field field, String message, + String fieldName ) + { + results.append( fieldName ); + results.append( "\", \"" + message + "\", "); + results.append("new Function (\"varName\", \""); + + Map hVars = field.getVars(); + // Loop through the field's variables. + for (Iterator iVars = hVars.keySet().iterator(); iVars.hasNext(); ) { + String varKey = (String)iVars.next(); + Var var = (Var)hVars.get(varKey); + String varValue = var.getValue(); + String jsType = var.getJsType(); + + if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) { + results.append("this." + varKey + "=" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "; "); + } else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(jsType)) { + results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; "); + } else if (Var.JSTYPE_STRING.equalsIgnoreCase(jsType)) { + results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; "); + // So everyone using the latest format doesn't need to change their xml files immediately. + } else if ("mask".equalsIgnoreCase(varKey)) { + results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; "); + } else { + results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; "); + } + } + + results.append(" return this[varName];\"))"); + } /** - * The value <code>null</code> will be returned at the end of the sequence. + * The value <code>null</code> will be returned at the end of the sequence. * ex: "zz" will return <code>null</code> - */ - private String getNextVar(String input) { + */ + private static String getNextVar(String input) { if (input == null) { return "aa"; } @@ -528,7 +649,7 @@ public class JavascriptValidatorTag exte /** * Replaces a single character in a <code>String</code> */ - private String replaceChar(String input, int pos, char c) { + private static String replaceChar(String input, int pos, char c) { if (pos == 0) { return c + input.substring(pos, input.length()); } else if (pos == input.length()) { @@ -537,6 +658,9 @@ public class JavascriptValidatorTag exte return input.substring(0, pos) + c + input.substring(pos, input.length() - 1); } } + + + } Index: src/share/org/apache/struts/taglib/html/LocalStrings.properties =================================================================== RCS file: /home/cvspublic/jakarta-struts/src/share/org/apache/struts/taglib/html/LocalStrings.properties,v retrieving revision 1.14 diff -u -3 -p -r1.14 LocalStrings.properties --- src/share/org/apache/struts/taglib/html/LocalStrings.properties 23 Feb 2002 07:10:30 -0000 1.14 +++ src/share/org/apache/struts/taglib/html/LocalStrings.properties 3 May 2002 +17:12:41 -0000 @@ -23,7 +23,8 @@ imgTag.type=Object must be of type Map includeTag.include=Error including page {0}: {1} includeTag.lookup=Cannot find global forward named {0} indexed.noEnclosingIterate=indexed=\"true\" is only valid within an enclosing iterate tag -iterateTag.iterator=Cannot create iterator for {0} +javascriptValidatorTag.iterator=Cannot create iterator for {0} +javascriptValidatorTag.collection=No collection found linkTag.destination=You must specify exactly one of 'forward', 'href', or 'page' linkTag.forward=Cannot locate global forwarding for {0} linkTag.forwards=Cannot locate forwards mapping table -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>