- Added list of values constraint support

- Setup regex validation support (but not working yet)
- Added required field icon to replace asterisk

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2701 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gavin Cornwell
2006-04-25 07:58:44 +00:00
parent a872096f72
commit 6477e0ccfb
14 changed files with 243 additions and 172 deletions

View File

@@ -964,6 +964,6 @@ status_space_updated=Successfully updated space ''{0}''.
# Validation Messages
validation_mandatory={0} is a mandatory field.
validation_string_length={0} must be between {1} and {2} characters in length.
validation_regex={0} must match the expression {1}.
validation_regex_not_match={0} must not match the expression {1}.
validation_regex={0} is invalid.
validation_regex_not_match={0} is invalid.
validation_numeric_range={0} must be between {1} and {2}.

View File

@@ -1,19 +1,12 @@
package org.alfresco.web.bean.generator;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.repo.RepoConstants;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet.ClientValidation;
/**
* Generates a component to manage associations.
@@ -33,31 +26,16 @@ public class AssociationGenerator extends BaseComponentGenerator
@Override
protected void setupMandatoryValidation(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item, UIComponent component, boolean realTimeChecking)
PropertySheetItem item, UIComponent component, boolean realTimeChecking, String idSuffix)
{
// Override the setup of the mandatory validation as the
// [form][element] approach needs to be used to locate the
// field and the <comp-id>_current_value hidden field needs
// to be used. We also enable real time so the page load
// Override the setup of the mandatory validation
// so we can send the _current_value id suffix.
// We also enable real time so the page load
// check disables the ok button if necessary, as the user
// adds or removes items from the multi value list the
// page will be refreshed and therefore re-check the status.
List<String> params = new ArrayList<String>(3);
// add the value parameter
String value = "document.forms['" +
Utils.getParentForm(context, component).getId() + "']['" +
component.getClientId(context) + "_current_value'].value";
params.add(value);
// add the validation failed message to show (use the value of the
// label component of the given item)
String msg = Application.getMessage(context, "validation_mandatory");
params.add("'" + MessageFormat.format(msg, new Object[] {item.getResolvedDisplayLabel()}) + "'");
// add the validation case to the property sheet
propertySheet.addClientValidation(new ClientValidation("validateMandatory",
params, true));
super.setupMandatoryValidation(context, propertySheet, item,
component, true, "_current_value");
}
}

View File

@@ -1,16 +1,20 @@
package org.alfresco.web.bean.generator;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIGraphic;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.el.ValueBinding;
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.repo.dictionary.constraint.NumericRangeConstraint;
import org.alfresco.repo.dictionary.constraint.RegexConstraint;
import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
@@ -335,7 +339,7 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
if (propertySheet.inEditMode() && propertySheet.isValidationEnabled() &&
propertyDef != null && propertyDef.isMandatory())
{
setupMandatoryValidation(context, propertySheet, property, component, false);
setupMandatoryValidation(context, propertySheet, property, component, false, null);
setupMandatoryMarker(context, property);
}
}
@@ -358,7 +362,7 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
if (propertySheet.inEditMode() && propertySheet.isValidationEnabled() &&
associationDef != null && associationDef.isTargetMandatory())
{
setupMandatoryValidation(context, propertySheet, association, component, false);
setupMandatoryValidation(context, propertySheet, association, component, false, null);
setupMandatoryMarker(context, association);
}
}
@@ -372,17 +376,24 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
* @param item The item being generated
* @param component The component representing the item
* @param realTimeChecking true to make the client validate as the user types
* @param idSuffix An optional suffix to add to the client id
*/
protected void setupMandatoryValidation(FacesContext context,
UIPropertySheet propertySheet, PropertySheetItem item,
UIComponent component, boolean realTimeChecking)
UIComponent component, boolean realTimeChecking,
String idSuffix)
{
List<String> params = new ArrayList<String>(3);
// add the value parameter
String value = "document.getElementById('" +
component.getClientId(context) + "').value";
params.add(value);
StringBuilder value = new StringBuilder("document.getElementById('");
value.append(component.getClientId(context));
if (idSuffix != null)
{
value.append(idSuffix);
}
value.append("')");
params.add(value.toString());
// add the validation failed message to show (use the value of the
// label component of the given item)
@@ -403,12 +414,14 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
@SuppressWarnings("unchecked")
protected void setupMandatoryMarker(FacesContext context, PropertySheetItem item)
{
// create an output text component and set value to "*"
UIOutput component = createOutputTextComponent(context, null);
component.setValue("*");
// create the required field graphic
UIGraphic image = (UIGraphic)context.getApplication().
createComponent(UIGraphic.COMPONENT_TYPE);
image.setUrl("/images/icons/required_field.gif");
image.getAttributes().put("style", "padding-right: 4px;");
// add marker as child to the property sheet item
item.getChildren().add(component);
item.getChildren().add(image);
}
/**
@@ -449,6 +462,11 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
setupNumericRangeConstraint(context, propertySheet, property, component,
(NumericRangeConstraint)constraint, false);
}
else if (constraint instanceof ListOfValuesConstraint)
{
// NOTE: This is dealt with at the component creation stage
// as a different component is usually required.
}
else
{
logger.warn("Unrecognized constaint object: " + constraint.getClass().getName());
@@ -479,27 +497,32 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
// add the value parameter
String value = "document.getElementById('" +
component.getClientId(context) + "').value";
component.getClientId(context) + "')";
params.add(value);
// add the min parameter
// add the regular expression parameter
try
{
// encode the expression so it can be unescaped by JavaScript
params.add("'" + URLEncoder.encode(expression, "UTF-8") + "'");
}
catch (UnsupportedEncodingException e)
{
// just add the expression as is
params.add("'" + expression + "'");
}
// add the max parameter
// add the requiresMatch parameter
params.add(Boolean.toString(requiresMatch));
// add the validation failed message to show
String msg = null;
if (requiresMatch)
{
msg = Application.getMessage(context, "validation_regex");
}
else
{
msg = Application.getMessage(context, "validation_regex_not_match");
}
params.add("'" + MessageFormat.format(msg, new Object[]
{property.getResolvedDisplayLabel(), expression}) + "'");
// add the validation failed messages
String matchMsg = Application.getMessage(context, "validation_regex");
params.add("'" + MessageFormat.format(matchMsg, new Object[]
{property.getResolvedDisplayLabel()}) + "'");
String noMatchMsg = Application.getMessage(context, "validation_regex_not_match");
params.add("'" + MessageFormat.format(noMatchMsg, new Object[]
{property.getResolvedDisplayLabel()}) + "'");
// add the validation case to the property sheet
propertySheet.addClientValidation(new ClientValidation("validateRegex",
@@ -528,7 +551,7 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
// add the value parameter
String value = "document.getElementById('" +
component.getClientId(context) + "').value";
component.getClientId(context) + "')";
params.add(value);
// add the min parameter
@@ -569,7 +592,7 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
// add the value parameter
String value = "document.getElementById('" +
component.getClientId(context) + "').value";
component.getClientId(context) + "')";
params.add(value);
// add the min parameter

View File

@@ -1,19 +1,12 @@
package org.alfresco.web.bean.generator;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.repo.RepoConstants;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet.ClientValidation;
/**
* Generates a category selector component.
@@ -42,31 +35,16 @@ public class CategorySelectorGenerator extends BaseComponentGenerator
@Override
protected void setupMandatoryValidation(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item, UIComponent component, boolean realTimeChecking)
PropertySheetItem item, UIComponent component, boolean realTimeChecking, String idSuffix)
{
// Override the setup of the mandatory validation as the
// [form][element] approach needs to be used to locate the field
// and the <comp-id>_selected hidden field needs to be
// used. We also enable real time so the page load check disabled
// Override the setup of the mandatory validation
// so we can send the _selected id suffix.
// We also enable real time so the page load check disabled
// the ok button if necessary, as the control is used the
// page will be refreshed and therefore re-check the status.
List<String> params = new ArrayList<String>(3);
// add the value parameter
String value = "document.forms['" +
Utils.getParentForm(context, component).getId() + "']['" +
component.getClientId(context) + "_selected'].value";
params.add(value);
// add the validation failed message to show (use the value of the
// label component of the given item)
String msg = Application.getMessage(context, "validation_mandatory");
params.add("'" + MessageFormat.format(msg, new Object[] {item.getResolvedDisplayLabel()}) + "'");
// add the validation case to the property sheet
propertySheet.addClientValidation(new ClientValidation("validateMandatory",
params, true));
super.setupMandatoryValidation(context, propertySheet, item,
component, true, "_selected");
}
@Override

View File

@@ -52,7 +52,7 @@ public class CheckboxGenerator extends BaseComponentGenerator
@Override
protected void setupMandatoryValidation(FacesContext context,
UIPropertySheet propertySheet, PropertySheetItem item,
UIComponent component, boolean realTimeChecking)
UIComponent component, boolean realTimeChecking, String idSuffix)
{
// a checkbox will always have one value or another so there
// is no need to create a mandatory validation rule

View File

@@ -1,19 +1,12 @@
package org.alfresco.web.bean.generator;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.repo.RepoConstants;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet.ClientValidation;
/**
* Generates a component to manage child associations.
@@ -33,31 +26,16 @@ public class ChildAssociationGenerator extends BaseComponentGenerator
@Override
protected void setupMandatoryValidation(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item, UIComponent component, boolean realTimeChecking)
PropertySheetItem item, UIComponent component, boolean realTimeChecking, String idSuffix)
{
// Override the setup of the mandatory validation as the
// [form][element] approach needs to be used to locate the
// field and the <comp-id>_current_value hidden field needs
// to be used. We also enable real time so the page load
// Override the setup of the mandatory validation
// so we can send the _current_value id suffix.
// We also enable real time so the page load
// check disables the ok button if necessary, as the user
// adds or removes items from the multi value list the
// page will be refreshed and therefore re-check the status.
List<String> params = new ArrayList<String>(3);
// add the value parameter
String value = "document.forms['" +
Utils.getParentForm(context, component).getId() + "']['" +
component.getClientId(context) + "_current_value'].value";
params.add(value);
// add the validation failed message to show (use the value of the
// label component of the given item)
String msg = Application.getMessage(context, "validation_mandatory");
params.add("'" + MessageFormat.format(msg, new Object[] {item.getResolvedDisplayLabel()}) + "'");
// add the validation case to the property sheet
propertySheet.addClientValidation(new ClientValidation("validateMandatory",
params, true));
super.setupMandatoryValidation(context, propertySheet, item,
component, true, "_current_value");
}
}

View File

@@ -57,7 +57,7 @@ public class DatePickerGenerator extends BaseComponentGenerator
@Override
protected void setupMandatoryValidation(FacesContext context,
UIPropertySheet propertySheet, PropertySheetItem item,
UIComponent component, boolean realTimeChecking)
UIComponent component, boolean realTimeChecking, String idSuffix)
{
// a date picker will always have a date value so there
// is no need to create a mandatory validation rule

View File

@@ -48,7 +48,7 @@ public class MimeTypeSelectorGenerator extends BaseComponentGenerator
@Override
protected void setupMandatoryValidation(FacesContext context,
UIPropertySheet propertySheet, PropertySheetItem item,
UIComponent component, boolean realTimeChecking)
UIComponent component, boolean realTimeChecking, String idSuffix)
{
// a mime type selector will always have one value or another
// so there is no need to create a mandatory validation rule.

View File

@@ -1,20 +1,23 @@
package org.alfresco.web.bean.generator;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectItems;
import javax.faces.component.UISelectOne;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import org.alfresco.web.app.Application;
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.service.cmr.dictionary.Constraint;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.ui.common.ComponentConstants;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.repo.component.UIMultiValueEditor;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet.ClientValidation;
/**
* Generates a text field component.
@@ -36,46 +39,126 @@ public class TextFieldGenerator extends BaseComponentGenerator
return component;
}
@Override
@SuppressWarnings("unchecked")
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item)
{
UIComponent component = null;
if (propertySheet.inEditMode())
{
// if the field has the list of values constraint a
// SelectOne component is required otherwise create
// the standard edit component
ListOfValuesConstraint constraint = getListOfValuesConstraint(
context, propertySheet, item);
if (constraint != null)
{
component = context.getApplication().createComponent(
UISelectOne.COMPONENT_TYPE);
FacesHelper.setupComponentId(context, component, item.getName());
// create the list of choices
UISelectItems itemsComponent = (UISelectItems)context.getApplication().
createComponent("javax.faces.SelectItems");
List<SelectItem> items = new ArrayList<SelectItem>(3);
List<String> values = constraint.getAllowedValues();
for (String value : values)
{
items.add(new SelectItem(value, value));
}
itemsComponent.setValue(items);
// add the items as a child component
component.getChildren().add(itemsComponent);
}
else
{
// use the standard component in edit mode
component = generate(context, item.getName());
}
}
else
{
// create an output text component in view mode
component = createOutputTextComponent(context, item.getName());
}
return component;
}
@Override
@SuppressWarnings("unchecked")
protected void setupMandatoryValidation(FacesContext context,
UIPropertySheet propertySheet, PropertySheetItem item,
UIComponent component, boolean realTimeChecking)
UIComponent component, boolean realTimeChecking,
String idSuffix)
{
if (component instanceof UIMultiValueEditor)
{
// Override the setup of the mandatory validation as the
// [form][element] approach needs to be used to locate the
// field and the <comp-id>_current_value hidden field needs
// to be used. We also enable real time so the page load
// Override the setup of the mandatory validation
// so we can send the _current_value id suffix.
// We also enable real time so the page load
// check disables the ok button if necessary, as the user
// adds or removes items from the multi value list the
// page will be refreshed and therefore re-check the status.
List<String> params = new ArrayList<String>(3);
// add the value parameter
String value = "document.forms['" +
Utils.getParentForm(context, component).getId() + "']['" +
component.getClientId(context) + "_current_value'].value";
params.add(value);
// add the validation failed message to show (use the value of the
// label component of the given item)
String msg = Application.getMessage(context, "validation_mandatory");
params.add("'" + MessageFormat.format(msg, new Object[] {item.getResolvedDisplayLabel()}) + "'");
// add the validation case to the property sheet
propertySheet.addClientValidation(new ClientValidation("validateMandatory",
params, true));
super.setupMandatoryValidation(context, propertySheet, item,
component, true, "_current_value");
}
else if (component instanceof UISelectOne)
{
// when there is a list of values constraint there
// will always be a value so validation is not required.
}
else
{
// setup the client validation rule with real time validation enabled
super.setupMandatoryValidation(context, propertySheet, item, component, true);
super.setupMandatoryValidation(context, propertySheet, item,
component, true, idSuffix);
// add event handler to kick off real time checks
component.getAttributes().put("onkeyup", "javascript:processButtonState();");
component.getAttributes().put("onkeyup", "processButtonState();");
}
}
/**
* Retrieves the list of values constraint for the item, if it has one
*
* @param context FacesContext
* @param propertySheet The property sheet being generated
* @param item The item being generated
* @return The constraint if the item has one, null otherwise
*/
protected ListOfValuesConstraint getListOfValuesConstraint(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item)
{
ListOfValuesConstraint lovConstraint = null;
// get the property definition for the item
PropertyDefinition propertyDef = getPropertyDefinition(context,
propertySheet.getNode(), item.getName());
if (propertyDef != null)
{
// go through the constaints and see if it has the
// list of values constraint
List<ConstraintDefinition> constraints = propertyDef.getConstraints();
for (ConstraintDefinition constraintDef : constraints)
{
Constraint constraint = constraintDef.getConstraint();
if (constraint instanceof ListOfValuesConstraint)
{
lovConstraint = (ListOfValuesConstraint)constraint;
break;
}
}
}
return lovConstraint;
}
}

View File

@@ -394,7 +394,10 @@ public abstract class BaseAssociationEditor extends UIInput
out.write("</table>");
// output a hidden field containing the current value
out.write("<input type='hidden' name='");
out.write("<input type='hidden' id='");
out.write(this.getClientId(context));
out.write("_current_value");
out.write("' name='");
out.write(this.getClientId(context));
out.write("_current_value");
out.write("' value='");

View File

@@ -191,7 +191,10 @@ public abstract class BaseMultiValueRenderer extends BaseRenderer
out.write("</table></td></tr></table>\n");
// output a hidden field containing the current value
out.write("<input type='hidden' name='");
out.write("<input type='hidden' id='");
out.write(component.getClientId(context));
out.write("_current_value");
out.write("' name='");
out.write(component.getClientId(context));
out.write("_current_value");
out.write("' value='");

View File

@@ -70,9 +70,25 @@ public class PropertySheetItemRenderer extends BaseRenderer
UIComponent label = children.get(0);
UIComponent control = children.get(1);
out.write("</td>");
// encode the mandatory marker component if present
if (count == 3)
{
out.write("<td>");
UIComponent mandatoryMarker = children.get(2);
Utils.encodeRecursive(context, mandatoryMarker);
out.write("</td>");
}
else
{
// output an empty column
out.write("<td>&nbsp;</td>");
}
// place a style class on the label column if necessary
String labelStylceClass = (String)component.getParent().getAttributes().get("labelStyleClass");
out.write("</td><td");
out.write("<td");
if (labelStylceClass != null)
{
outputAttribute(out, labelStylceClass, "class");
@@ -86,14 +102,6 @@ public class PropertySheetItemRenderer extends BaseRenderer
out.write("</td><td>");
Utils.encodeRecursive(context, control);
// encode the mandatory marker component if present
if (count == 3)
{
out.write("</td><td>");
UIComponent mandatoryMarker = children.get(2);
Utils.encodeRecursive(context, mandatoryMarker);
}
// NOTE: we'll allow the property sheet's grid renderer close off the last <td>
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

View File

@@ -5,27 +5,29 @@
/**
* Informs the user of the given 'message', if 'showMessage' is true.
* If 'showMessage' is true focus is given to the 'control'.
*/
function informUser(message, showMessage)
function informUser(control, message, showMessage)
{
if (showMessage)
{
alert(message);
control.focus();
}
}
/**
* Ensures the 'value' is not null or 0.
* Ensures the value of the 'control' is not null or 0.
*
* @return true if the mandatory validation passed
*/
function validateMandatory(value, message, showMessage)
function validateMandatory(control, message, showMessage)
{
var result = true;
if (value == null || value.length == 0)
if (control.value == null || control.value.length == 0)
{
informUser(message, showMessage);
informUser(control, message, showMessage);
result = false;
}
@@ -33,17 +35,17 @@ function validateMandatory(value, message, showMessage)
}
/**
* Ensures the 'value' is more than 'min' and less than 'max'.
* Ensures the value of the 'control' is more than 'min' and less than 'max'.
*
* @return true if the number range validation passed
*/
function validateNumberRange(value, min, max, message, showMessage)
function validateNumberRange(control, min, max, message, showMessage)
{
var result = true;
if (value < min || value > max)
if (isNaN(control.value) || control.value < min || control.value > max)
{
informUser(message, showMessage);
informUser(control, message, showMessage);
result = false;
}
@@ -51,17 +53,17 @@ function validateNumberRange(value, min, max, message, showMessage)
}
/**
* Ensures the 'value' has a string length more than 'min' and less than 'max'.
* Ensures the value of the 'control' has a string length more than 'min' and less than 'max'.
*
* @return true if the string length validation passed
*/
function validateStringLength(value, min, max, message, showMessage)
function validateStringLength(control, min, max, message, showMessage)
{
var result = true;
if (value.length < min || value.length > max)
if (control.value.length < min || control.value.length > max)
{
informUser(message, showMessage);
informUser(control, message, showMessage);
result = false;
}
@@ -69,16 +71,31 @@ function validateStringLength(value, min, max, message, showMessage)
}
/**
* Ensures the 'value' matches the 'expression' if 'requiresMatch' is true.
* Ensures the 'value' does not matche the 'expression' if 'requiresMatch' is false.
* Ensures the value of the 'control' matches the 'expression' if 'requiresMatch' is true.
* Ensures the value of the 'control' does not match the 'expression' if 'requiresMatch' is false.
*
* @return true if the regex validation passed
*/
function validateRegex(value, expression, requiresMatch, message, showMessage)
function validateRegex(control, expression, requiresMatch, matchMessage, noMatchMessage, showMessage)
{
var result = true;
// TODO: implement the regular expression matching
var pattern = new RegExp(unescape(expression));
var matches = pattern.test(control.value);
if (matches != requiresMatch)
{
if (requiresMatch)
{
informUser(control, noMatchMessage, showMessage);
}
else
{
informUser(control, matchMessage, showMessage);
}
result = false;
}
return result;
}