001: package org.makumba.forms.validation;
002:
003: import java.io.Serializable;
004: import java.util.Collection;
005: import java.util.HashSet;
006: import java.util.Iterator;
007:
008: import org.makumba.FieldDefinition;
009: import org.makumba.ValidationRule;
010: import org.makumba.commons.StringUtils;
011: import org.makumba.forms.html.FieldEditor;
012: import org.makumba.providers.datadefinition.makumba.validation.ComparisonValidationRule;
013: import org.makumba.providers.datadefinition.makumba.validation.NumberRangeValidationRule;
014: import org.makumba.providers.datadefinition.makumba.validation.RangeValidationRule;
015: import org.makumba.providers.datadefinition.makumba.validation.RegExpValidationRule;
016: import org.makumba.providers.datadefinition.makumba.validation.StringLengthValidationRule;
017:
018: /**
019: * This class implements java-script based client side validation using the <i>LiveValidation</i> library. For more
020: * details, please refer to the webpage at <a href="http://www.livevalidation.com/">http://www.livevalidation.com/</a>.
021: *
022: * @author Rudolf Mayer
023: * @version $Id: LiveValidationProvider.java,v 1.1 15.09.2007 13:32:07 Rudolf Mayer Exp $
024: */
025: public class LiveValidationProvider implements
026: ClientsideValidationProvider, Serializable {
027:
028: private static final long serialVersionUID = 1L;
029:
030: /**
031: * Gathers all validation object definitions and calls to it, e.g.<br>
032: * <code>
033: * var ageValidation = new LiveValidation('age', { validMessage: " " });<br>
034: * ageValidation.add( Validate.Numericality , { onlyInteger: true, failureMessage: "invalid integer" } );<br>
035: * ageValidation.add( Validate.Numericality , { minimum: 12, failureMessage: "Age must be at least 12 years" } );<br>
036: * </code>
037: */
038: private StringBuffer validationObjects = new StringBuffer();
039:
040: /**
041: * Gathers all the names of the validation variables defined. this is needed to make mass validation in
042: * {@link #getOnSubmitValidation(boolean)}.
043: */
044: private HashSet<String> definitionVarNames = new HashSet<String>();
045:
046: /** initialises a field, basically does create the variables and calls for this field. */
047: public void initField(String inputName,
048: FieldDefinition fieldDefinition, boolean validateLive) {
049: Collection validationRules = fieldDefinition
050: .getValidationRules();// def.getValidationRules(inputName);
051: int size = validationRules != null ? validationRules.size() : 1;
052: StringBuffer validations = new StringBuffer(100 + size * 50);
053: String inputVarName = inputName.replaceAll("\\.", "__")
054: + "Validation";
055:
056: if (fieldDefinition == null) {
057: System.out.println("null def for " + inputName);
058: }
059:
060: if (fieldDefinition.isNotNull()) {
061: validations
062: .append(getValidationLine(inputVarName,
063: "Validate.Presence",
064: FieldDefinition.ERROR_NOT_NULL));
065: }
066: if (fieldDefinition.isIntegerType()) {
067: validations.append(getValidationLine(inputVarName,
068: "Validate.Numericality", FieldEditor.ERROR_NO_INT,
069: "onlyInteger: true,"));
070: } else if (fieldDefinition.isRealType()) {
071: validations.append(getValidationLine(inputVarName,
072: "Validate.Numericality", FieldEditor.ERROR_NO_INT));
073: }
074: if (validationRules != null) {
075: for (Iterator iter = validationRules.iterator(); iter
076: .hasNext();) {
077: ValidationRule rule = (ValidationRule) iter.next();
078: if (rule instanceof StringLengthValidationRule) {
079: validations.append(getValidationLine(inputVarName,
080: "Validate.Length", rule,
081: getRangeLimits(rule)));
082: } else if (rule instanceof NumberRangeValidationRule) {
083: validations.append(getValidationLine(inputVarName,
084: "Validate.Numericality", rule,
085: getRangeLimits(rule)));
086: } else if (rule instanceof RegExpValidationRule) {
087: validations.append(getValidationLine(inputVarName,
088: "Validate.Format", rule, "pattern: /^"
089: + ((RegExpValidationRule) rule)
090: .getRegExp() + "$/i, "));
091: } else if (rule instanceof ComparisonValidationRule) {
092: ComparisonValidationRule c = (ComparisonValidationRule) rule;
093:
094: // FIXME: need to implement date comparisions
095: if (c.getFieldDefinition().isDateType()) {
096: continue;
097: }
098:
099: String arguments = "element1: \""
100: + c.getFieldName() + "\", element2: \""
101: + c.getOtherFieldName()
102: + "\", comparisonOperator: \""
103: + c.getCompareOperator() + "\", ";
104:
105: if (c.getFieldDefinition().isNumberType()) {
106: validations.append(getValidationLine(
107: inputVarName,
108: "MakumbaValidate.NumberComparison",
109: rule, arguments));
110: } else if (c.getFieldDefinition().isDateType()) {
111: // todo: implement!
112: } else if (c.getFieldDefinition().isStringType()) {
113: if (c.getFunctionName() != null
114: && c.getFunctionName().length() > 0) {
115: arguments += "functionToApply: \""
116: + c.getFunctionName() + "\", ";
117: validations.append(getValidationLine(
118: inputVarName,
119: "MakumbaValidate.StringComparison",
120: rule, arguments));
121: }
122: }
123: }
124: }
125: }
126: if (fieldDefinition.isUnique() && !fieldDefinition.isDateType()) {
127: validations.append(getValidationLine(inputVarName,
128: "MakumbaValidate.Uniqueness",
129: FieldDefinition.ERROR_NOT_UNIQUE, "table: \""
130: + fieldDefinition.getDataDefinition()
131: .getName() + "\", " + "field: \""
132: + fieldDefinition.getName() + "\", "));
133: }
134:
135: if (validations.length() > 0) {
136: definitionVarNames.add(inputVarName);
137: validationObjects.append("var " + inputVarName
138: + " = new LiveValidation('" + inputName
139: + "', { validMessage: \" \" });\n");
140: validationObjects.append(validations);
141: validationObjects.append("\n");
142: }
143: }
144:
145: /** Returns the result of the initialisation, surrounded by a <code><script></code> tag. */
146: public StringBuffer getClientValidation(boolean validateLive) {
147: StringBuffer b = new StringBuffer();
148: if (validationObjects.length() > 0) {
149: b.append("<script type=\"text/javascript\">\n");
150: b.append(validationObjects);
151:
152: b.append("function " + getValidationFunction() + " {\n");
153: b.append(" valid = LiveValidation.massValidate( ").append(
154: StringUtils.toString(definitionVarNames)).append(
155: " );\n");
156: b.append(" if (!valid) {");
157: b
158: .append(" alert('Please correct all form errors first!');");
159: b.append(" }\n");
160: b.append(" return valid;\n");
161: b.append("}\n");
162: b.append("</script>\n");
163: }
164:
165: return b;
166: }
167:
168: private StringBuffer getValidationFunction() {
169: return new StringBuffer("validateForm_").append(
170: StringUtils
171: .concatAsString(definitionVarNames
172: .toArray(new Object[definitionVarNames
173: .size()]))).append("()");
174: }
175:
176: /**
177: * returns the call for the onSubmit validation, e.g.:<br>
178: * <code>function(e) { return LiveValidation.massValidate( [emailValidation, weightValidation, hobbiesValidation, ageValidation] );</code>
179: */
180: public StringBuffer getOnSubmitValidation(boolean validateLive) {
181: if (definitionVarNames.size() > 0) {
182: StringBuffer sb = new StringBuffer(getValidationFunction())
183: .append(";");
184: return sb;
185: } else {
186: return null;
187: }
188: }
189:
190: public String[] getNeededJavaScriptFileNames() {
191: // the order gets reversed for some reason... therefore we reverse it here as well
192: return new String[] { "makumba-livevalidation.js",
193: "livevalidation_1.2_standalone.js" };
194: }
195:
196: private String getValidationLine(String inputVarName,
197: String validationType, ValidationRule rule, String arguments) {
198: return getValidationLine(inputVarName, validationType, rule
199: .getErrorMessage(), arguments);
200: }
201:
202: private String getValidationLine(String inputVarName,
203: String validationType, String failureMessage) {
204: return getValidationLine(inputVarName, validationType,
205: failureMessage, "");
206: }
207:
208: private String getValidationLine(String inputVarName,
209: String validationType, String failureMessage,
210: String arguments) {
211: return inputVarName + ".add( " + validationType + " , { "
212: + arguments + " failureMessage: \"" + failureMessage
213: + "\" } );\n";
214: }
215:
216: private String getRangeLimits(ValidationRule rule) {
217: String lower = ((RangeValidationRule) rule)
218: .getLowerLimitString();
219: String upper = ((RangeValidationRule) rule)
220: .getUpperLimitString();
221: String s = "";
222: if (!lower.equals("?")) {
223: s += "minimum: " + lower;
224: }
225: if (!upper.equals("?")) {
226: if (s.length() > 0) {
227: s += ", ";
228: }
229: s += "maximum: " + upper;
230: }
231: if (s.length() > 0) {
232: s += ", ";
233: }
234: return s;
235: }
236: }
|