mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Intial version of property sheet constraints support, no regex or list of values suppport yet though.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2664 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -959,3 +959,10 @@ delete_companyroot_confirm=WARNING: This folder is a special folder accessed by
|
||||
status_space_created=Successfully created space ''{0}''.
|
||||
status_space_deleted=Successfully deleted space ''{0}''.
|
||||
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_numeric_range={0} must be between {1} and {2}.
|
||||
|
@@ -3,11 +3,9 @@ package org.alfresco.web.bean.generator;
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
|
||||
import org.alfresco.web.ui.repo.component.property.UIAssociationEditor;
|
||||
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
|
||||
/**
|
||||
@@ -25,26 +23,14 @@ public class AssociationGenerator extends BaseComponentGenerator
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
|
||||
@Override
|
||||
protected void setupMandatoryValidation(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item, UIComponent component, boolean realTimeChecking)
|
||||
{
|
||||
// generate the standard association editor
|
||||
UIAssociationEditor component = (UIAssociationEditor)generate(context, item.getName());
|
||||
|
||||
AssociationDefinition assocDef = this.getAssociationDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
// set the association name and set to disabled if appropriate
|
||||
component.setAssociationName(assocDef.getName().toString());
|
||||
if (propertySheet.inEditMode() == false || item.isReadOnly() || assocDef.isProtected())
|
||||
{
|
||||
component.setDisabled(true);
|
||||
}
|
||||
|
||||
// setup the converter if one was specified
|
||||
setupConverter(context, propertySheet, item, component);
|
||||
|
||||
return component;
|
||||
// TODO: the association editor component needs to use the
|
||||
// 'current_value' hidden field rather than the standard
|
||||
// 'value' field as this is always null (it's used internally
|
||||
// by the component) for now disable mandatory checks completely
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,9 @@
|
||||
package org.alfresco.web.bean.generator;
|
||||
|
||||
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.UIOutput;
|
||||
@@ -7,7 +11,12 @@ import javax.faces.context.FacesContext;
|
||||
import javax.faces.convert.Converter;
|
||||
import javax.faces.el.ValueBinding;
|
||||
|
||||
import org.alfresco.repo.dictionary.constraint.NumericRangeConstraint;
|
||||
import org.alfresco.repo.dictionary.constraint.RegexConstraint;
|
||||
import org.alfresco.repo.dictionary.constraint.StringLengthConstraint;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
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.Application;
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
@@ -15,9 +24,11 @@ import org.alfresco.web.bean.repository.DataDictionary;
|
||||
import org.alfresco.web.bean.repository.Node;
|
||||
import org.alfresco.web.ui.common.ComponentConstants;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
import org.alfresco.web.ui.repo.component.property.BaseAssociationEditor;
|
||||
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
|
||||
import org.alfresco.web.ui.repo.component.property.UIProperty;
|
||||
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
import org.alfresco.web.ui.repo.component.property.UIPropertySheet.ClientValidation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.web.jsf.FacesContextUtils;
|
||||
@@ -26,8 +37,615 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(BaseComponentGenerator.class);
|
||||
|
||||
protected enum ControlType { FIELD, SELECTOR; }
|
||||
|
||||
private DataDictionary dataDictionary;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public UIComponent generateAndAdd(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
{
|
||||
UIComponent component = null;
|
||||
|
||||
if (item instanceof UIProperty)
|
||||
{
|
||||
// get the property definition
|
||||
PropertyDefinition propertyDef = getPropertyDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
// create the component and add it to the property sheet
|
||||
component = createComponent(context, propertySheet, item);
|
||||
|
||||
// setup the component for multi value editing if necessary
|
||||
component = setupMultiValuePropertyIfNecessary(context, propertySheet,
|
||||
item, propertyDef, component);
|
||||
|
||||
// setup common aspects of the property i.e. value binding
|
||||
setupProperty(context, propertySheet, item, propertyDef, component);
|
||||
|
||||
// add the component now, it needs to be added before the validations
|
||||
// are setup as we need access to the component id, which in turn needs
|
||||
// to have a parent to get the correct id
|
||||
item.getChildren().add(component);
|
||||
|
||||
// setup the component for mandatory validation if necessary
|
||||
setupMandatoryPropertyIfNecessary(context, propertySheet, item,
|
||||
propertyDef, component);
|
||||
|
||||
// setup any constraints the property has
|
||||
setupConstraints(context, propertySheet, item, propertyDef, component);
|
||||
|
||||
// setup any converter the property needs
|
||||
setupConverter(context, propertySheet, item, propertyDef, component);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the association definition
|
||||
AssociationDefinition assocationDef = this.getAssociationDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
// create the component and add it to the property sheet
|
||||
component = createComponent(context, propertySheet, item);
|
||||
|
||||
// setup common aspects of the association i.e. value binding
|
||||
setupAssociation(context, propertySheet, item, assocationDef, component);
|
||||
|
||||
// add the component now, it needs to be added before the validations
|
||||
// are setup as we need access to the component id, which needs have a
|
||||
// parent to get the correct id
|
||||
item.getChildren().add(component);
|
||||
|
||||
// setup the component for mandatory validation if necessary
|
||||
setupMandatoryAssociationIfNecessary(context, propertySheet, item,
|
||||
assocationDef, component);
|
||||
|
||||
// setup any converter the association needs
|
||||
setupConverter(context, propertySheet, item, assocationDef, component);
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the component for the given proerty sheet item.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param item The property or association being generated
|
||||
* @return The newly created component
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
{
|
||||
UIComponent component = null;
|
||||
|
||||
if (item instanceof UIProperty)
|
||||
{
|
||||
if (propertySheet.inEditMode())
|
||||
{
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the standard association component
|
||||
component = generate(context, item.getName());
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the converter with the given id and adds it to the component.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param converterId The name of the converter to create
|
||||
* @param component The component to add the converter to
|
||||
*/
|
||||
protected void createAndSetConverter(FacesContext context, String converterId,
|
||||
UIComponent component)
|
||||
{
|
||||
if (converterId != null && component instanceof UIOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
Converter conv = context.getApplication().createConverter(converterId);
|
||||
((UIOutput)component).setConverter(conv);
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
// workaround a NPE bug in MyFaces
|
||||
logger.warn("Converter " + converterId + " could not be applied");
|
||||
}
|
||||
catch (FacesException fe)
|
||||
{
|
||||
logger.warn("Converter " + converterId + " could not be applied");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an output text component.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param id Optional id to set
|
||||
* @return The new component
|
||||
*/
|
||||
protected UIOutput createOutputTextComponent(FacesContext context, String id)
|
||||
{
|
||||
UIOutput component = (UIOutput)context.getApplication().createComponent(
|
||||
ComponentConstants.JAVAX_FACES_OUTPUT);
|
||||
|
||||
component.setRendererType(ComponentConstants.JAVAX_FACES_TEXT);
|
||||
FacesHelper.setupComponentId(context, component, id);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the property component i.e. setting the value binding
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet
|
||||
* @param item The parent component
|
||||
* @param propertyDef The property definition
|
||||
* @param component The component representing the property
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setupProperty(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item, PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
// create and set the value binding
|
||||
ValueBinding vb = null;
|
||||
|
||||
if (propertyDef != null)
|
||||
{
|
||||
vb = context.getApplication().createValueBinding(
|
||||
"#{" + propertySheet.getVar() + ".properties[\"" +
|
||||
propertyDef.getName().toString() + "\"]}");
|
||||
}
|
||||
else
|
||||
{
|
||||
vb = context.getApplication().createValueBinding(
|
||||
"#{" + propertySheet.getVar() + ".properties[\"" +
|
||||
item.getName() + "\"]}");
|
||||
}
|
||||
|
||||
component.setValueBinding("value", vb);
|
||||
|
||||
// disable the component if it is read only or protected
|
||||
// or if the property sheet is in view mode
|
||||
if (propertySheet.inEditMode() == false || item.isReadOnly() ||
|
||||
(propertyDef != null && propertyDef.isProtected()))
|
||||
{
|
||||
component.getAttributes().put("disabled", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the association component i.e. setting the value binding
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet
|
||||
* @param item The parent component
|
||||
* @param associationDef The association definition
|
||||
* @param component The component representing the association
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setupAssociation(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item, AssociationDefinition associationDef, UIComponent component)
|
||||
{
|
||||
// create and set the value binding
|
||||
ValueBinding vb = context.getApplication().createValueBinding(
|
||||
"#{" + propertySheet.getVar() + "}");
|
||||
component.setValueBinding("value", vb);
|
||||
|
||||
// set the association name and set to disabled if appropriate
|
||||
((BaseAssociationEditor)component).setAssociationName(
|
||||
associationDef.getName().toString());
|
||||
|
||||
// disable the component if it is read only or protected
|
||||
// or if the property sheet is in view mode
|
||||
if (propertySheet.inEditMode() == false || item.isReadOnly() ||
|
||||
(associationDef != null && associationDef.isProtected()))
|
||||
{
|
||||
component.getAttributes().put("disabled", Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapper component around the given component to enable the user
|
||||
* to edit multiple values.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param property The property being generated
|
||||
* @param propertyDef The data dictionary definition for the property
|
||||
* @param component The component representing the property
|
||||
* @return A wrapped component if the property is multi-valued or the
|
||||
* original component if it is not multi-valued
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected UIComponent setupMultiValuePropertyIfNecessary(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
UIComponent multiValueComponent = component;
|
||||
|
||||
if (propertySheet.inEditMode() && property.isReadOnly() == false &&
|
||||
propertyDef != null && propertyDef.isProtected() == false &&
|
||||
propertyDef.isMultiValued())
|
||||
{
|
||||
// if the property is multi-valued create a multi value editor wrapper component
|
||||
String id = "multi_" + property.getName();
|
||||
multiValueComponent = context.getApplication().createComponent(
|
||||
RepoConstants.ALFRESCO_FACES_MULTIVALUE_EDITOR);
|
||||
FacesHelper.setupComponentId(context, multiValueComponent, id);
|
||||
|
||||
// set the renderer depending on whether the item is a 'field' or a 'selector'
|
||||
if (getControlType() == ControlType.FIELD)
|
||||
{
|
||||
multiValueComponent.setRendererType(RepoConstants.ALFRESCO_FACES_FIELD_RENDERER);
|
||||
}
|
||||
else
|
||||
{
|
||||
multiValueComponent.setRendererType(RepoConstants.ALFRESCO_FACES_SELECTOR_RENDERER);
|
||||
|
||||
// set the value binding for the wrapped component and the lastItemAdded attribute of
|
||||
// the multi select component, needs to point somewhere that can hold any object, it
|
||||
// will store the item last added by the user.
|
||||
String expr = "#{MultiValueEditorBean.lastItemsAdded['" +
|
||||
property.getName() + "']}";
|
||||
ValueBinding vb = context.getApplication().createValueBinding(expr);
|
||||
multiValueComponent.setValueBinding("lastItemAdded", vb);
|
||||
component.setValueBinding("value", vb);
|
||||
}
|
||||
|
||||
// add the original component as a child of the wrapper
|
||||
multiValueComponent.getChildren().add(component);
|
||||
}
|
||||
|
||||
return multiValueComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a mandatory validation rule for the given property.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param property The property being generated
|
||||
* @param propertyDef The data dictionary definition of the property
|
||||
* @param component The component representing the property
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setupMandatoryPropertyIfNecessary(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
// only setup validations if the property sheet is in edit mode,
|
||||
// validation is enabled and the property is declared as mandatory
|
||||
if (propertySheet.inEditMode() && propertySheet.isValidationEnabled() &&
|
||||
propertyDef != null && propertyDef.isMandatory())
|
||||
{
|
||||
setupMandatoryValidation(context, propertySheet, property, component, false);
|
||||
setupMandatoryMarker(context, property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a mandatory validation rule for the given association.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param association The association being generated
|
||||
* @param associationDef The data dictionary definition of the association
|
||||
* @param component The component representing the association
|
||||
*/
|
||||
protected void setupMandatoryAssociationIfNecessary(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem association,
|
||||
AssociationDefinition associationDef, UIComponent component)
|
||||
{
|
||||
// only setup validations if the property sheet is in edit mode,
|
||||
// validation is enabled and the association is declared as mandatory
|
||||
if (propertySheet.inEditMode() && propertySheet.isValidationEnabled() &&
|
||||
associationDef != null && associationDef.isTargetMandatory())
|
||||
{
|
||||
setupMandatoryValidation(context, propertySheet, association, component, false);
|
||||
setupMandatoryMarker(context, association);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a client mandatory validation rule with the property
|
||||
* sheet for the given item.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet to add the validation rule to
|
||||
* @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
|
||||
*/
|
||||
protected void setupMandatoryValidation(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem item,
|
||||
UIComponent component, boolean realTimeChecking)
|
||||
{
|
||||
List<String> params = new ArrayList<String>(3);
|
||||
|
||||
// add the value parameter
|
||||
String value = "document.getElementById('" +
|
||||
component.getClientId(context) + "').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, realTimeChecking));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the marker to show that the item is mandatory.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param item The item being generated
|
||||
*/
|
||||
@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("*");
|
||||
|
||||
// add marker as child to the property sheet item
|
||||
item.getChildren().add(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up client validation rules for any constraints the property has.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* propertySheet The property sheet being generated
|
||||
* @param property The property being generated
|
||||
* @param propertyDef The data dictionary definition of the property
|
||||
* @param component The component representing the property
|
||||
*/
|
||||
protected void setupConstraints(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
// only setup constraints if the property sheet is in edit mode,
|
||||
// validation is enabled
|
||||
if (propertySheet.inEditMode() && propertySheet.isValidationEnabled() &&
|
||||
propertyDef != null)
|
||||
{
|
||||
List<ConstraintDefinition> constraints = propertyDef.getConstraints();
|
||||
for (ConstraintDefinition constraintDef : constraints)
|
||||
{
|
||||
Constraint constraint = constraintDef.getConstraint();
|
||||
|
||||
if (constraint instanceof RegexConstraint)
|
||||
{
|
||||
setupRegexConstraint(context, propertySheet, property, component,
|
||||
(RegexConstraint)constraint, false);
|
||||
}
|
||||
else if (constraint instanceof StringLengthConstraint)
|
||||
{
|
||||
setupStringLengthConstraint(context, propertySheet, property, component,
|
||||
(StringLengthConstraint)constraint, false);
|
||||
}
|
||||
else if (constraint instanceof NumericRangeConstraint)
|
||||
{
|
||||
setupNumericRangeConstraint(context, propertySheet, property, component,
|
||||
(NumericRangeConstraint)constraint, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("Unrecognized constaint object: " + constraint.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a default validation rule for the regular expression constraint
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet to add the validation rule to
|
||||
* @param property The property being generated
|
||||
* @param component The component representing the property
|
||||
* @param constraint The constraint to setup
|
||||
* @param realTimeChecking true to make the client validate as the user types
|
||||
*/
|
||||
protected void setupRegexConstraint(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
UIComponent component, RegexConstraint constraint,
|
||||
boolean realTimeChecking)
|
||||
{
|
||||
String expression = constraint.getExpression();
|
||||
boolean requiresMatch = constraint.getRequiresMatch();
|
||||
|
||||
List<String> params = new ArrayList<String>(3);
|
||||
|
||||
// add the value parameter
|
||||
String value = "document.getElementById('" +
|
||||
component.getClientId(context) + "').value";
|
||||
params.add(value);
|
||||
|
||||
// add the min parameter
|
||||
params.add("'" + expression + "'");
|
||||
|
||||
// add the max 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 case to the property sheet
|
||||
propertySheet.addClientValidation(new ClientValidation("validateRegex",
|
||||
params, realTimeChecking));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a default validation rule for the string length constraint
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet to add the validation rule to
|
||||
* @param property The property being generated
|
||||
* @param component The component representing the property
|
||||
* @param constraint The constraint to setup
|
||||
* @param realTimeChecking true to make the client validate as the user types
|
||||
*/
|
||||
protected void setupStringLengthConstraint(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
UIComponent component, StringLengthConstraint constraint,
|
||||
boolean realTimeChecking)
|
||||
{
|
||||
int min = constraint.getMinLength();
|
||||
int max = constraint.getMaxLength();
|
||||
|
||||
List<String> params = new ArrayList<String>(3);
|
||||
|
||||
// add the value parameter
|
||||
String value = "document.getElementById('" +
|
||||
component.getClientId(context) + "').value";
|
||||
params.add(value);
|
||||
|
||||
// add the min parameter
|
||||
params.add(Integer.toString(min));
|
||||
|
||||
// add the max parameter
|
||||
params.add(Integer.toString(max));
|
||||
|
||||
// add the validation failed message to show
|
||||
String msg = Application.getMessage(context, "validation_string_length");
|
||||
params.add("'" + MessageFormat.format(msg, new Object[]
|
||||
{property.getResolvedDisplayLabel(), min, max}) + "'");
|
||||
|
||||
// add the validation case to the property sheet
|
||||
propertySheet.addClientValidation(new ClientValidation("validateStringLength",
|
||||
params, realTimeChecking));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a default validation rule for the numeric range constraint
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet to add the validation rule to
|
||||
* @param property The property being generated
|
||||
* @param component The component representing the property
|
||||
* @param constraint The constraint to setup
|
||||
* @param realTimeChecking true to make the client validate as the user types
|
||||
*/
|
||||
protected void setupNumericRangeConstraint(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
UIComponent component, NumericRangeConstraint constraint,
|
||||
boolean realTimeChecking)
|
||||
{
|
||||
double min = constraint.getMinValue();
|
||||
double max = constraint.getMaxValue();
|
||||
|
||||
List<String> params = new ArrayList<String>(3);
|
||||
|
||||
// add the value parameter
|
||||
String value = "document.getElementById('" +
|
||||
component.getClientId(context) + "').value";
|
||||
params.add(value);
|
||||
|
||||
// add the min parameter
|
||||
params.add(Double.toString(min));
|
||||
|
||||
// add the max parameter
|
||||
params.add(Double.toString(max));
|
||||
|
||||
// add the validation failed message to show
|
||||
String msg = Application.getMessage(context, "validation_numeric_range");
|
||||
params.add("'" + MessageFormat.format(msg, new Object[]
|
||||
{property.getResolvedDisplayLabel(), min, max}) + "'");
|
||||
|
||||
// add the validation case to the property sheet
|
||||
propertySheet.addClientValidation(new ClientValidation("validateNumberRange",
|
||||
params, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the appropriate converter for the given property
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param property The property being generated
|
||||
* @param propertyDef The data dictionary definition of the property
|
||||
* @param component The component representing the property
|
||||
*/
|
||||
protected void setupConverter(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
if (property.getConverter() != null)
|
||||
{
|
||||
// create and add the custom converter
|
||||
createAndSetConverter(context, property.getConverter(), component);
|
||||
}
|
||||
else if (propertySheet.inEditMode() == false &&
|
||||
propertyDef != null && propertyDef.isMultiValued())
|
||||
{
|
||||
// if there isn't a custom converter and the property is
|
||||
// multi-valued add the multi value converter as a default
|
||||
createAndSetConverter(context, RepoConstants.ALFRESCO_FACES_MULTIVALUE_CONVERTER,
|
||||
component);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the appropriate converter for the given association
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param association The association being generated
|
||||
* @param associationDef The data dictionary definition of the property
|
||||
* @param component The component representing the association
|
||||
*/
|
||||
protected void setupConverter(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem association,
|
||||
AssociationDefinition associationDef, UIComponent component)
|
||||
{
|
||||
if (association.getConverter() != null)
|
||||
{
|
||||
// create and add the custom converter
|
||||
createAndSetConverter(context, association.getConverter(), component);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the control being generated
|
||||
*
|
||||
* @return The type of the control either a FIELD or a SELECTOR
|
||||
*/
|
||||
protected ControlType getControlType()
|
||||
{
|
||||
return ControlType.FIELD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the PropertyDefinition for the given property name on the given node
|
||||
*
|
||||
@@ -54,105 +672,6 @@ public abstract class BaseComponentGenerator implements IComponentGenerator
|
||||
return getDataDictionary(context).getAssociationDefinition(node, associationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapper component around the given component to enable the user
|
||||
* to edit multiple values.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param item The item being generated
|
||||
* @param component The component to wrap if necessary
|
||||
* @param field true if the property being enabled is a field style
|
||||
* component i.e. text field or checkbox. false if the component
|
||||
* is a selector style component i.e. category selector
|
||||
*/
|
||||
protected UIComponent enableForMultiValue(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item, UIComponent component, boolean field)
|
||||
{
|
||||
UIComponent multiValueComponent = component;
|
||||
|
||||
// NOTE: Associations have built in support for multiple values so we only deal
|
||||
// with UIProperty instances in here currently
|
||||
|
||||
if (item instanceof UIProperty)
|
||||
{
|
||||
// if the property is multi-valued create a multi value editor wrapper component
|
||||
String id = "multi_" + item.getName();
|
||||
multiValueComponent = context.getApplication().createComponent(
|
||||
RepoConstants.ALFRESCO_FACES_MULTIVALUE_EDITOR);
|
||||
FacesHelper.setupComponentId(context, multiValueComponent, id);
|
||||
|
||||
// set the renderer depending on whether the item is a 'field' or a 'selector'
|
||||
if (field)
|
||||
{
|
||||
multiValueComponent.setRendererType(RepoConstants.ALFRESCO_FACES_FIELD_RENDERER);
|
||||
}
|
||||
else
|
||||
{
|
||||
multiValueComponent.setRendererType(RepoConstants.ALFRESCO_FACES_SELECTOR_RENDERER);
|
||||
|
||||
// set the value binding for the wrapped component and the lastItemAdded attribute of
|
||||
// the multi select component, needs to point somewhere that can hold any object, it
|
||||
// will store the item last added by the user.
|
||||
String expr = "#{MultiValueEditorBean.lastItemsAdded['" +
|
||||
item.getName() + "']}";
|
||||
ValueBinding vb = context.getApplication().createValueBinding(expr);
|
||||
multiValueComponent.setValueBinding("lastItemAdded", vb);
|
||||
component.setValueBinding("value", vb);
|
||||
}
|
||||
|
||||
// add the original component as a child of the wrapper
|
||||
multiValueComponent.getChildren().add(component);
|
||||
}
|
||||
|
||||
return multiValueComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up any converters configured for the item
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet being generated
|
||||
* @param item The item being generated
|
||||
* @param component The component to disable
|
||||
*/
|
||||
protected void setupConverter(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item, UIComponent component)
|
||||
{
|
||||
// if the item has a converter, create it and apply it
|
||||
String converter = item.getConverter();
|
||||
if (converter != null && component instanceof UIOutput)
|
||||
{
|
||||
try
|
||||
{
|
||||
Converter conv = context.getApplication().createConverter(converter);
|
||||
((UIOutput)component).setConverter(conv);
|
||||
}
|
||||
catch (FacesException fe)
|
||||
{
|
||||
logger.warn("Converter " + converter + " could not be applied");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an output text component
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param id Optional id to set
|
||||
* @return The new component
|
||||
*/
|
||||
protected UIOutput createOutputTextComponent(FacesContext context, String id)
|
||||
{
|
||||
UIOutput component = (UIOutput)context.getApplication().createComponent(
|
||||
ComponentConstants.JAVAX_FACES_OUTPUT);
|
||||
|
||||
component.setRendererType(ComponentConstants.JAVAX_FACES_TEXT);
|
||||
FacesHelper.setupComponentId(context, component, id);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
private DataDictionary getDataDictionary(FacesContext context)
|
||||
{
|
||||
if (this.dataDictionary == null)
|
||||
|
@@ -1,58 +0,0 @@
|
||||
package org.alfresco.web.bean.generator;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
import org.alfresco.web.ui.repo.component.UICategorySelector;
|
||||
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
|
||||
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
|
||||
/**
|
||||
* Generates a text field component.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class CategoryPickerGenerator extends BaseComponentGenerator
|
||||
{
|
||||
public UIComponent generate(FacesContext context, String id)
|
||||
{
|
||||
UIComponent component = context.getApplication().
|
||||
createComponent(RepoConstants.ALFRESCO_FACES_CATEGORY_SELECTOR);
|
||||
FacesHelper.setupComponentId(context, component, id);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
{
|
||||
// create the standard component
|
||||
UIComponent component = generate(context, item.getName());
|
||||
|
||||
// get the property definition
|
||||
PropertyDefinition propertyDef = getPropertyDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
if (propertySheet.inEditMode() && propertyDef != null && propertyDef.isMultiValued())
|
||||
{
|
||||
// if the item is multi valued we need to wrap the standard component
|
||||
// but only when the property sheet is in edit mode
|
||||
component = enableForMultiValue(context, propertySheet, item, component, false);
|
||||
}
|
||||
else if (propertySheet.inEditMode() == false || item.isReadOnly() ||
|
||||
(propertyDef != null && propertyDef.isProtected()))
|
||||
{
|
||||
// disable the component if it is read only or protected
|
||||
// or if the property sheet is in view mode
|
||||
component.getAttributes().put("disabled", Boolean.TRUE);
|
||||
}
|
||||
|
||||
// setup the converter if one was specified
|
||||
setupConverter(context, propertySheet, item, component);
|
||||
|
||||
return component;
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package org.alfresco.web.bean.generator;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Generates a category selector component.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class CategorySelectorGenerator extends BaseComponentGenerator
|
||||
{
|
||||
public UIComponent generate(FacesContext context, String id)
|
||||
{
|
||||
UIComponent component = context.getApplication().
|
||||
createComponent(RepoConstants.ALFRESCO_FACES_CATEGORY_SELECTOR);
|
||||
FacesHelper.setupComponentId(context, component, id);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
{
|
||||
// the category selector component is used whatever mode the property sheet is in
|
||||
return generate(context, item.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupMandatoryValidation(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item, UIComponent component, boolean realTimeChecking)
|
||||
{
|
||||
// TODO: the category selector component needs to use the
|
||||
// 'current_value' hidden field rather than the standard
|
||||
// 'value' field as this is always null (it's used internally
|
||||
// by the component) for now disable mandatory checks completely
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ControlType getControlType()
|
||||
{
|
||||
return ControlType.SELECTOR;
|
||||
}
|
||||
}
|
@@ -1,22 +1,18 @@
|
||||
package org.alfresco.web.bean.generator;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.component.UIOutput;
|
||||
import javax.faces.component.UISelectBoolean;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.convert.Converter;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
import org.alfresco.web.ui.common.ComponentConstants;
|
||||
import org.alfresco.web.ui.common.converter.XMLDateConverter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Generates a text field component.
|
||||
* Generates a checkbox component.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
@@ -32,58 +28,46 @@ public class CheckboxGenerator extends BaseComponentGenerator
|
||||
return component;
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
@Override
|
||||
protected void setupConverter(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
UIComponent component = null;
|
||||
|
||||
// get the property definition
|
||||
PropertyDefinition propertyDef = getPropertyDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
if (propertySheet.inEditMode())
|
||||
if (property.getConverter() != null)
|
||||
{
|
||||
// use the standard component in edit mode
|
||||
component = generate(context, item.getName());
|
||||
|
||||
// disable the component if it is read only or protected
|
||||
if (item.isReadOnly() || (propertyDef != null && propertyDef.isProtected()))
|
||||
{
|
||||
component.getAttributes().put("disabled", Boolean.TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the item is multi valued we need to wrap the standard component
|
||||
if (propertyDef != null && propertyDef.isMultiValued())
|
||||
{
|
||||
component = enableForMultiValue(context, propertySheet, item, component, true);
|
||||
}
|
||||
}
|
||||
// create and add the custom converter
|
||||
createAndSetConverter(context, property.getConverter(), component);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create an output text component in view mode
|
||||
component = createOutputTextComponent(context, item.getName());
|
||||
|
||||
// if there is no overridden converter add a default
|
||||
if (item.getConverter() == null)
|
||||
if (propertySheet.inEditMode() == false)
|
||||
{
|
||||
if (propertyDef != null && propertyDef.isMultiValued())
|
||||
{
|
||||
// add multi-value converter if property is such
|
||||
item.setConverter(RepoConstants.ALFRESCO_FACES_MULTIVALUE_CONVERTER);
|
||||
// if there isn't a custom converter and the property is
|
||||
// multi-valued add the multi value converter as a default
|
||||
createAndSetConverter(context,
|
||||
RepoConstants.ALFRESCO_FACES_MULTIVALUE_CONVERTER,
|
||||
component);
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the default boolean label converter
|
||||
item.setConverter(RepoConstants.ALFRESCO_FACES_BOOLEAN_CONVERTER);
|
||||
// if there isn't a custom converter and the property is
|
||||
// not multi-valued add the boolean converter as a default
|
||||
createAndSetConverter(context,
|
||||
RepoConstants.ALFRESCO_FACES_BOOLEAN_CONVERTER,
|
||||
component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup the converter if one was specified
|
||||
setupConverter(context, propertySheet, item, component);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupMandatoryValidation(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem item,
|
||||
UIComponent component, boolean realTimeChecking)
|
||||
{
|
||||
// a checkbox will always have one value or another so there
|
||||
// is no need to create a mandatory validation rule
|
||||
}
|
||||
}
|
||||
|
@@ -3,15 +3,13 @@ package org.alfresco.web.bean.generator;
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
|
||||
import org.alfresco.web.ui.repo.component.property.UIChildAssociationEditor;
|
||||
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
|
||||
/**
|
||||
* Generates a text field component.
|
||||
* Generates a component to manage child associations.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
@@ -25,27 +23,14 @@ public class ChildAssociationGenerator extends BaseComponentGenerator
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
|
||||
@Override
|
||||
protected void setupMandatoryValidation(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item, UIComponent component, boolean realTimeChecking)
|
||||
{
|
||||
// generate the standard child association editor
|
||||
UIChildAssociationEditor component = (UIChildAssociationEditor)generate(context,
|
||||
item.getName());
|
||||
|
||||
AssociationDefinition assocDef = this.getAssociationDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
// set the association name and set to disabled if appropriate
|
||||
component.setAssociationName(assocDef.getName().toString());
|
||||
if (propertySheet.inEditMode() == false || item.isReadOnly() || assocDef.isProtected())
|
||||
{
|
||||
component.setDisabled(true);
|
||||
}
|
||||
|
||||
// setup the converter if one was specified
|
||||
setupConverter(context, propertySheet, item, component);
|
||||
|
||||
return component;
|
||||
// TODO: the child assocation editor component needs to use the
|
||||
// 'current_value' hidden field rather than the standard
|
||||
// 'value' field as this is always null (it's used internally
|
||||
// by the component) for now disable mandatory checks completely
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package org.alfresco.web.bean.generator;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.component.UIInput;
|
||||
import javax.faces.component.UIOutput;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.convert.Converter;
|
||||
@@ -16,7 +15,7 @@ import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
|
||||
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
|
||||
/**
|
||||
* Generates a text field component.
|
||||
* Generates a date picker component.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
@@ -24,6 +23,7 @@ public class DatePickerGenerator extends BaseComponentGenerator
|
||||
{
|
||||
private static final String MSG_DATE = "date_pattern";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public UIComponent generate(FacesContext context, String id)
|
||||
{
|
||||
UIComponent component = context.getApplication().
|
||||
@@ -36,44 +36,15 @@ public class DatePickerGenerator extends BaseComponentGenerator
|
||||
return component;
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
@Override
|
||||
protected void setupConverter(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem property,
|
||||
PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
UIComponent component = null;
|
||||
|
||||
if (propertySheet.inEditMode())
|
||||
if (property.getConverter() != null)
|
||||
{
|
||||
// use the standard date picker component
|
||||
component = generate(context, item.getName());
|
||||
|
||||
// get the property definition
|
||||
PropertyDefinition propertyDef = getPropertyDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
// disable the component if it is read only or protected
|
||||
if (item.isReadOnly() || (propertyDef != null && propertyDef.isProtected()))
|
||||
{
|
||||
component.getAttributes().put("disabled", Boolean.TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the item is multi valued we need to wrap the standard component
|
||||
if (propertyDef != null && propertyDef.isMultiValued())
|
||||
{
|
||||
component = enableForMultiValue(context, propertySheet, item, component, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// create an output text component in view mode
|
||||
component = createOutputTextComponent(context, item.getName());
|
||||
}
|
||||
|
||||
if (item.getConverter() != null)
|
||||
{
|
||||
// setup the converter if one was specified
|
||||
setupConverter(context, propertySheet, item, component);
|
||||
// create and add the custom converter
|
||||
createAndSetConverter(context, property.getConverter(), component);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -81,10 +52,17 @@ public class DatePickerGenerator extends BaseComponentGenerator
|
||||
// we can cast this as we know it is an UIOutput type
|
||||
((UIOutput)component).setConverter(getDefaultConverter(context));
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupMandatoryValidation(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem item,
|
||||
UIComponent component, boolean realTimeChecking)
|
||||
{
|
||||
// a date picker will always have a date value so there
|
||||
// is no need to create a mandatory validation rule
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default converter for the date component
|
||||
*
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package org.alfresco.web.bean.generator;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.component.UIOutput;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.convert.Converter;
|
||||
|
||||
@@ -10,7 +9,7 @@ import org.alfresco.web.ui.common.converter.XMLDateConverter;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
|
||||
/**
|
||||
* Generates a text field component.
|
||||
* Generates a date time picker component.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
@@ -18,6 +17,7 @@ public class DateTimePickerGenerator extends DatePickerGenerator
|
||||
{
|
||||
private static final String MSG_DATE_TIME = "date_time_pattern";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public UIComponent generate(FacesContext context, String id)
|
||||
{
|
||||
UIComponent component = super.generate(context, id);
|
||||
|
@@ -7,8 +7,7 @@ import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
|
||||
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
|
||||
/**
|
||||
* Interface definition for objects that dynamically generate components
|
||||
* on behalf of the PropertySheet component.
|
||||
* Interface definition for objects that dynamically generate components.
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
@@ -25,8 +24,9 @@ public interface IComponentGenerator
|
||||
UIComponent generate(FacesContext context, String id);
|
||||
|
||||
/**
|
||||
* Dynamically generates a component for use in the given property sheet
|
||||
* to represent the given property definition.
|
||||
* Dynamically generates a component for the given property sheet item.
|
||||
* The generated component is also setup appropriately for it's model
|
||||
* definition and added to the given property sheet.
|
||||
*
|
||||
* @param context FacesContext
|
||||
* @param propertySheet The property sheet component
|
||||
@@ -34,6 +34,6 @@ public interface IComponentGenerator
|
||||
* either a property, association or child association
|
||||
* @return The component instance
|
||||
*/
|
||||
UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
UIComponent generateAndAdd(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item);
|
||||
}
|
||||
|
@@ -18,11 +18,16 @@ public class LabelGenerator extends BaseComponentGenerator
|
||||
return createOutputTextComponent(context, id);
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public UIComponent generateAndAdd(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
{
|
||||
UIComponent component = generate(context, "label_" + item.getName());
|
||||
|
||||
// add the component to the property sheet item
|
||||
item.getChildren().add(component);
|
||||
|
||||
// TODO: Turn the label red if the field is required
|
||||
// setup the 'for' attribute to associate with it the control
|
||||
|
||||
|
@@ -19,6 +19,7 @@ import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
*/
|
||||
public class SpaceIconPickerGenerator extends BaseComponentGenerator
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
public UIComponent generate(FacesContext context, String id)
|
||||
{
|
||||
// create the outer component
|
||||
@@ -35,21 +36,20 @@ public class SpaceIconPickerGenerator extends BaseComponentGenerator
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setupProperty(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem item,
|
||||
PropertyDefinition propertyDef, UIComponent component)
|
||||
{
|
||||
UIComponent component = null;
|
||||
// do the standard setup
|
||||
super.setupProperty(context, propertySheet, item, propertyDef, component);
|
||||
|
||||
// get the property definition
|
||||
PropertyDefinition propertyDef = getPropertyDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
// if the property sheet is in edit mode we also need to setup the
|
||||
// list of icons the user can select from
|
||||
if (propertySheet.inEditMode())
|
||||
{
|
||||
// use the standard component in edit mode
|
||||
component = generate(context, item.getName());
|
||||
|
||||
// create the list items child component
|
||||
UIListItems items = (UIListItems)context.getApplication().
|
||||
createComponent(RepoConstants.ALFRESCO_FACES_LIST_ITEMS);
|
||||
@@ -76,37 +76,6 @@ public class SpaceIconPickerGenerator extends BaseComponentGenerator
|
||||
|
||||
// add the list items component to the image picker component
|
||||
component.getChildren().add(items);
|
||||
|
||||
// disable the component if it is read only or protected
|
||||
if (item.isReadOnly() || (propertyDef != null && propertyDef.isProtected()))
|
||||
{
|
||||
component.getAttributes().put("disabled", Boolean.TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the item is multi valued we need to wrap the standard component
|
||||
if (propertyDef != null && propertyDef.isMultiValued())
|
||||
{
|
||||
component = enableForMultiValue(context, propertySheet, item, component, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// create an output text component in view mode
|
||||
component = createOutputTextComponent(context, item.getName());
|
||||
|
||||
// if the property is multi-valued and there isn't a custom converter
|
||||
// specified, add the MultiValue converter as a default
|
||||
if (propertyDef.isMultiValued() && item.getConverter() == null)
|
||||
{
|
||||
item.setConverter(RepoConstants.ALFRESCO_FACES_MULTIVALUE_CONVERTER);
|
||||
}
|
||||
}
|
||||
|
||||
// setup the converter if one was specified
|
||||
setupConverter(context, propertySheet, item, component);
|
||||
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,11 @@
|
||||
package org.alfresco.web.bean.generator;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.component.UIInput;
|
||||
import javax.faces.component.UIOutput;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
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.repo.RepoConstants;
|
||||
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;
|
||||
|
||||
@@ -19,6 +16,7 @@ import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
|
||||
*/
|
||||
public class TextFieldGenerator extends BaseComponentGenerator
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
public UIComponent generate(FacesContext context, String id)
|
||||
{
|
||||
UIComponent component = context.getApplication().
|
||||
@@ -31,50 +29,31 @@ public class TextFieldGenerator extends BaseComponentGenerator
|
||||
return component;
|
||||
}
|
||||
|
||||
public UIComponent generate(FacesContext context, UIPropertySheet propertySheet,
|
||||
PropertySheetItem item)
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setupMandatoryValidation(FacesContext context,
|
||||
UIPropertySheet propertySheet, PropertySheetItem item,
|
||||
UIComponent component, boolean realTimeChecking)
|
||||
{
|
||||
UIComponent component = null;
|
||||
|
||||
// get the property definition
|
||||
PropertyDefinition propertyDef = getPropertyDefinition(context,
|
||||
propertySheet.getNode(), item.getName());
|
||||
|
||||
if (propertySheet.inEditMode())
|
||||
if (component instanceof UIMultiValueEditor)
|
||||
{
|
||||
// use the standard component in edit mode
|
||||
component = generate(context, item.getName());
|
||||
// if the text field has multiple values don't allow real time
|
||||
// checking of the mandatory status
|
||||
|
||||
// disable the component if it is read only or protected
|
||||
if (item.isReadOnly() || (propertyDef != null && propertyDef.isProtected()))
|
||||
{
|
||||
component.getAttributes().put("disabled", Boolean.TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the item is multi valued we need to wrap the standard component
|
||||
if (propertyDef != null && propertyDef.isMultiValued())
|
||||
{
|
||||
component = enableForMultiValue(context, propertySheet, item, component, true);
|
||||
}
|
||||
}
|
||||
// TODO: the multi-value editor component needs to use the
|
||||
// 'current_value' hidden field rather than the standard
|
||||
// 'value' field as this is always null (it's used internally
|
||||
// by the component) for now disable mandatory checks completely
|
||||
|
||||
//super.setupMandatoryValidation(context, propertySheet, item, component, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create an output text component in view mode
|
||||
component = createOutputTextComponent(context, item.getName());
|
||||
|
||||
// if the property is multi-valued and there isn't a custom converter
|
||||
// specified, add the MultiValue converter as a default
|
||||
if (propertyDef != null && propertyDef.isMultiValued() && item.getConverter() == null)
|
||||
{
|
||||
item.setConverter(RepoConstants.ALFRESCO_FACES_MULTIVALUE_CONVERTER);
|
||||
}
|
||||
// setup the client validation rule with real time validation enabled
|
||||
super.setupMandatoryValidation(context, propertySheet, item, component, true);
|
||||
|
||||
// add event handler to kick off real time checks
|
||||
component.getAttributes().put("onkeyup", "javascript:processButtonState();");
|
||||
}
|
||||
|
||||
// setup the converter if one was specified
|
||||
setupConverter(context, propertySheet, item, component);
|
||||
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
@@ -484,51 +484,63 @@ public class CreateSpaceWizard extends BaseWizardBean
|
||||
QName idQName = Repository.resolveToQName(child.getAttribute("name"));
|
||||
TypeDefinition typeDef = this.dictionaryService.getType(idQName);
|
||||
|
||||
if (typeDef != null &&
|
||||
this.dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_FOLDER))
|
||||
if (typeDef != null)
|
||||
{
|
||||
// try and get the label from config
|
||||
String label = Utils.getDisplayLabel(context, child);
|
||||
|
||||
// if there wasn't a client based label try and get it from the dictionary
|
||||
if (label == null)
|
||||
if (this.dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_FOLDER))
|
||||
{
|
||||
label = typeDef.getTitle();
|
||||
// try and get the label from config
|
||||
String label = Utils.getDisplayLabel(context, child);
|
||||
|
||||
// if there wasn't a client based label try and get it from the dictionary
|
||||
if (label == null)
|
||||
{
|
||||
label = typeDef.getTitle();
|
||||
}
|
||||
|
||||
// finally use the localname if we still haven't found a label
|
||||
if (label == null)
|
||||
{
|
||||
label = idQName.getLocalName();
|
||||
}
|
||||
|
||||
// resolve a description string for the type
|
||||
String description = Utils.getDescription(context, child);
|
||||
|
||||
// if we don't have a local description just use the label
|
||||
if (description == null)
|
||||
{
|
||||
description = label;
|
||||
}
|
||||
|
||||
// extract the icon to use from the config
|
||||
String icon = child.getAttribute("icon");
|
||||
if (icon == null || icon.length() == 0)
|
||||
{
|
||||
icon = DEFAULT_SPACE_TYPE_ICON_PATH;
|
||||
}
|
||||
|
||||
UIListItem item = new UIListItem();
|
||||
item.getAttributes().put("value", idQName.toString());
|
||||
item.getAttributes().put("label", label);
|
||||
item.getAttributes().put("tooltip", label);
|
||||
item.getAttributes().put("image", icon);
|
||||
this.folderTypes.add(item);
|
||||
|
||||
UIDescription desc = new UIDescription();
|
||||
desc.setControlValue(idQName.toString());
|
||||
desc.setText(description);
|
||||
this.folderTypeDescriptions.add(desc);
|
||||
}
|
||||
|
||||
// finally use the localname if we still haven't found a label
|
||||
if (label == null)
|
||||
else
|
||||
{
|
||||
label = idQName.getLocalName();
|
||||
logger.warn("Failed to add '" + child.getAttribute("name") +
|
||||
"' to the list of folder types as the type is not a subtype of cm:folder");
|
||||
}
|
||||
|
||||
// resolve a description string for the type
|
||||
String description = Utils.getDescription(context, child);
|
||||
|
||||
// if we don't have a local description just use the label
|
||||
if (description == null)
|
||||
{
|
||||
description = label;
|
||||
}
|
||||
|
||||
// extract the icon to use from the config
|
||||
String icon = child.getAttribute("icon");
|
||||
if (icon == null || icon.length() == 0)
|
||||
{
|
||||
icon = DEFAULT_SPACE_TYPE_ICON_PATH;
|
||||
}
|
||||
|
||||
UIListItem item = new UIListItem();
|
||||
item.getAttributes().put("value", idQName.toString());
|
||||
item.getAttributes().put("label", label);
|
||||
item.getAttributes().put("tooltip", label);
|
||||
item.getAttributes().put("image", icon);
|
||||
this.folderTypes.add(item);
|
||||
|
||||
UIDescription desc = new UIDescription();
|
||||
desc.setControlValue(idQName.toString());
|
||||
desc.setText(description);
|
||||
this.folderTypeDescriptions.add(desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("Failed to add '" + child.getAttribute("name") +
|
||||
"' to the list of folder types as the type is not recognised");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -512,25 +512,37 @@ public abstract class BaseContentWizard extends AbstractWizardBean
|
||||
{
|
||||
TypeDefinition typeDef = this.dictionaryService.getType(idQName);
|
||||
|
||||
if (typeDef != null &&
|
||||
this.dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_CONTENT))
|
||||
if (typeDef != null)
|
||||
{
|
||||
// try and get the display label from config
|
||||
String label = Utils.getDisplayLabel(context, child);
|
||||
|
||||
// if there wasn't a client based label try and get it from the dictionary
|
||||
if (label == null)
|
||||
if (this.dictionaryService.isSubClass(typeDef.getName(), ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
label = typeDef.getTitle();
|
||||
// try and get the display label from config
|
||||
String label = Utils.getDisplayLabel(context, child);
|
||||
|
||||
// if there wasn't a client based label try and get it from the dictionary
|
||||
if (label == null)
|
||||
{
|
||||
label = typeDef.getTitle();
|
||||
}
|
||||
|
||||
// finally, just use the localname
|
||||
if (label == null)
|
||||
{
|
||||
label = idQName.getLocalName();
|
||||
}
|
||||
|
||||
this.objectTypes.add(new SelectItem(idQName.toString(), label));
|
||||
}
|
||||
|
||||
// finally, just use the localname
|
||||
if (label == null)
|
||||
else
|
||||
{
|
||||
label = idQName.getLocalName();
|
||||
logger.warn("Failed to add '" + child.getAttribute("name") +
|
||||
"' to the list of content types as the type is not a subtype of cm:content");
|
||||
}
|
||||
|
||||
this.objectTypes.add(new SelectItem(idQName.toString(), label));
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("Failed to add '" + child.getAttribute("name") +
|
||||
"' to the list of content types as the type is not recognised");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ public final class RepoConstants
|
||||
public static final String GENERATOR_CHECKBOX = "CheckboxGenerator";
|
||||
public static final String GENERATOR_DATE_PICKER = "DatePickerGenerator";
|
||||
public static final String GENERATOR_DATETIME_PICKER = "DateTimePickerGenerator";
|
||||
public static final String GENERATOR_CATEGORY_PICKER = "CategoryPickerGenerator";
|
||||
public static final String GENERATOR_CATEGORY_SELECTOR = "CategorySelectorGenerator";
|
||||
public static final String GENERATOR_ASSOCIATION = "AssociationGenerator";
|
||||
public static final String GENERATOR_CHILD_ASSOCIATION = "ChildAssociationGenerator";
|
||||
|
||||
|
@@ -79,7 +79,6 @@ public abstract class BaseAssociationEditor extends UIInput
|
||||
private final static String MSG_SEARCH_SELECT_ITEM = "search_select_item";
|
||||
private final static String MSG_SELECTED_ITEMS = "selected_items";
|
||||
private final static String MSG_REMOVE = "remove";
|
||||
private final static String MSG_ADD = "add";
|
||||
private final static String MSG_OK = "ok";
|
||||
private final static String MSG_CANCEL = "cancel";
|
||||
private final static String MSG_SEARCH = "search";
|
||||
@@ -274,7 +273,6 @@ public abstract class BaseAssociationEditor extends UIInput
|
||||
this.highlightedRow = false;
|
||||
|
||||
ResponseWriter out = context.getResponseWriter();
|
||||
String clientId = getClientId(context);
|
||||
|
||||
// get the child associations currently on the node and any that have been added
|
||||
NodeService nodeService = Repository.getServiceRegistry(context).getNodeService();
|
||||
|
@@ -20,7 +20,6 @@ import java.io.IOException;
|
||||
|
||||
import javax.faces.component.NamingContainer;
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.component.UIOutput;
|
||||
import javax.faces.component.UIPanel;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.el.ValueBinding;
|
||||
@@ -45,6 +44,8 @@ public abstract class PropertySheetItem extends UIPanel implements NamingContain
|
||||
protected Boolean readOnly;
|
||||
protected String componentGenerator;
|
||||
|
||||
protected String resolvedDisplayLabel;
|
||||
|
||||
/**
|
||||
* @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext)
|
||||
*/
|
||||
@@ -210,6 +211,7 @@ public abstract class PropertySheetItem extends UIPanel implements NamingContain
|
||||
this.readOnly = (Boolean)values[3];
|
||||
this.converter = (String)values[4];
|
||||
this.componentGenerator = (String)values[5];
|
||||
this.resolvedDisplayLabel = (String)values[6];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,7 +219,7 @@ public abstract class PropertySheetItem extends UIPanel implements NamingContain
|
||||
*/
|
||||
public Object saveState(FacesContext context)
|
||||
{
|
||||
Object values[] = new Object[6];
|
||||
Object values[] = new Object[7];
|
||||
// standard component attributes are saved by the super class
|
||||
values[0] = super.saveState(context);
|
||||
values[1] = this.name;
|
||||
@@ -225,9 +227,20 @@ public abstract class PropertySheetItem extends UIPanel implements NamingContain
|
||||
values[3] = this.readOnly;
|
||||
values[4] = this.converter;
|
||||
values[5] = this.componentGenerator;
|
||||
values[6] = this.resolvedDisplayLabel;
|
||||
return (values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolved display label
|
||||
*
|
||||
* @return The display label being used at runtime
|
||||
*/
|
||||
public String getResolvedDisplayLabel()
|
||||
{
|
||||
return resolvedDisplayLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the label and control for the item
|
||||
*
|
||||
@@ -252,13 +265,16 @@ public abstract class PropertySheetItem extends UIPanel implements NamingContain
|
||||
* @param propSheet The property sheet that the item is a child of
|
||||
* @param displayLabel The display label text
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void generateLabel(FacesContext context, UIPropertySheet propSheet, String displayLabel)
|
||||
{
|
||||
UIComponent label = FacesHelper.getComponentGenerator(context,
|
||||
RepoConstants.GENERATOR_LABEL).generate(context, propSheet, this);
|
||||
label.getAttributes().put("value", displayLabel + ": ");
|
||||
RepoConstants.GENERATOR_LABEL).generateAndAdd(context, propSheet, this);
|
||||
|
||||
this.getChildren().add(label);
|
||||
// remember the display label used (without the : separator)
|
||||
this.resolvedDisplayLabel = displayLabel;
|
||||
|
||||
label.getAttributes().put("value", displayLabel + ":");
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Created label " + label.getClientId(context) +
|
||||
|
@@ -17,20 +17,13 @@
|
||||
package org.alfresco.web.ui.repo.component.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import javax.faces.FacesException;
|
||||
import javax.faces.component.UIOutput;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.convert.Converter;
|
||||
import javax.faces.el.ValueBinding;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
import org.alfresco.web.bean.repository.DataDictionary;
|
||||
import org.alfresco.web.bean.repository.Node;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -121,14 +114,7 @@ public class UIAssociation extends PropertySheetItem
|
||||
AssociationDefinition assocDef)
|
||||
{
|
||||
UIAssociationEditor control = (UIAssociationEditor)FacesHelper.getComponentGenerator(
|
||||
context, RepoConstants.GENERATOR_ASSOCIATION).generate(context, propSheet, this);
|
||||
|
||||
// set up the value binding
|
||||
ValueBinding vb = context.getApplication().createValueBinding("#{" + propSheet.getVar() + "}");
|
||||
control.setValueBinding("value", vb);
|
||||
|
||||
// add the control itself
|
||||
this.getChildren().add(control);
|
||||
context, RepoConstants.GENERATOR_ASSOCIATION).generateAndAdd(context, propSheet, this);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Created control " + control + "(" +
|
||||
|
@@ -60,6 +60,7 @@ public class UIAssociationEditor extends BaseAssociationEditor
|
||||
/**
|
||||
* @see org.alfresco.web.ui.repo.component.property.BaseAssociationEditor#populateAssocationMaps(org.alfresco.web.bean.repository.Node)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void populateAssocationMaps(Node node)
|
||||
{
|
||||
// we need to remember the original set of associations (if there are any)
|
||||
|
@@ -17,20 +17,13 @@
|
||||
package org.alfresco.web.ui.repo.component.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import javax.faces.FacesException;
|
||||
import javax.faces.component.UIOutput;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.convert.Converter;
|
||||
import javax.faces.el.ValueBinding;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.web.app.Application;
|
||||
import org.alfresco.web.app.servlet.FacesHelper;
|
||||
import org.alfresco.web.bean.repository.DataDictionary;
|
||||
import org.alfresco.web.bean.repository.Node;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -121,14 +114,7 @@ public class UIChildAssociation extends PropertySheetItem
|
||||
AssociationDefinition assocDef)
|
||||
{
|
||||
UIChildAssociationEditor control = (UIChildAssociationEditor)FacesHelper.getComponentGenerator(
|
||||
context, RepoConstants.GENERATOR_CHILD_ASSOCIATION).generate(context, propSheet, this);
|
||||
|
||||
// set up the value binding
|
||||
ValueBinding vb = context.getApplication().createValueBinding("#{" + propSheet.getVar() + "}");
|
||||
control.setValueBinding("value", vb);
|
||||
|
||||
// add the control itself
|
||||
this.getChildren().add(control);
|
||||
context, RepoConstants.GENERATOR_CHILD_ASSOCIATION).generateAndAdd(context, propSheet, this);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Created control " + control + "(" +
|
||||
|
@@ -60,6 +60,7 @@ public class UIChildAssociationEditor extends BaseAssociationEditor
|
||||
/**
|
||||
* @see org.alfresco.web.ui.repo.component.property.BaseAssociationEditor#populateAssocationMaps(org.alfresco.web.bean.repository.Node)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void populateAssocationMaps(Node node)
|
||||
{
|
||||
// we need to remember the original set of associations (if there are any)
|
||||
|
@@ -20,7 +20,6 @@ import java.io.IOException;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.el.ValueBinding;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
@@ -124,6 +123,7 @@ public class UIProperty extends PropertySheetItem
|
||||
* @param propSheet The property sheet this property belongs to
|
||||
* @param propDef The definition of the property to create the control for
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void generateControl(FacesContext context, UIPropertySheet propSheet,
|
||||
PropertyDefinition propDef)
|
||||
{
|
||||
@@ -149,7 +149,7 @@ public class UIProperty extends PropertySheetItem
|
||||
}
|
||||
else if (typeName.equals(DataTypeDefinition.CATEGORY))
|
||||
{
|
||||
componentGeneratorName = RepoConstants.GENERATOR_CATEGORY_PICKER;
|
||||
componentGeneratorName = RepoConstants.GENERATOR_CATEGORY_SELECTOR;
|
||||
}
|
||||
else if (typeName.equals(DataTypeDefinition.DATETIME))
|
||||
{
|
||||
@@ -167,8 +167,8 @@ public class UIProperty extends PropertySheetItem
|
||||
}
|
||||
|
||||
// retrieve the component generator and generate the control
|
||||
control = FacesHelper.getComponentGenerator(context, componentGeneratorName).generate(
|
||||
context, propSheet, this);
|
||||
control = FacesHelper.getComponentGenerator(context, componentGeneratorName).
|
||||
generateAndAdd(context, propSheet, this);
|
||||
|
||||
// if we're in edit mode ensure that we don't allow editing of system properties or scenarios we don't support
|
||||
if (propSheet.inEditMode())
|
||||
@@ -182,15 +182,6 @@ public class UIProperty extends PropertySheetItem
|
||||
}
|
||||
}
|
||||
|
||||
// create and set the value binding
|
||||
ValueBinding vb = context.getApplication().
|
||||
createValueBinding("#{" + propSheet.getVar() + ".properties[\"" +
|
||||
propDef.getName().toString() + "\"]}");
|
||||
control.setValueBinding("value", vb);
|
||||
|
||||
// add the control to this component
|
||||
this.getChildren().add(control);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Created control " + control + "(" +
|
||||
control.getClientId(context) +
|
||||
@@ -208,16 +199,7 @@ public class UIProperty extends PropertySheetItem
|
||||
private void generateControl(FacesContext context, UIPropertySheet propSheet, String propName)
|
||||
{
|
||||
UIComponent control = FacesHelper.getComponentGenerator(context, RepoConstants.GENERATOR_TEXT_FIELD).
|
||||
generate(context, propSheet, this);
|
||||
|
||||
// create and set the value binding
|
||||
ValueBinding vb = context.getApplication().
|
||||
createValueBinding("#{" + propSheet.getVar() + ".properties[\"" +
|
||||
propName + "\"]}");
|
||||
control.setValueBinding("value", vb);
|
||||
|
||||
// add the control to this component
|
||||
this.getChildren().add(control);
|
||||
generateAndAdd(context, propSheet, this);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Created control " + control + "(" +
|
||||
|
@@ -17,13 +17,18 @@
|
||||
package org.alfresco.web.ui.repo.component.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.faces.component.NamingContainer;
|
||||
import javax.faces.component.UIForm;
|
||||
import javax.faces.component.UIPanel;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.ResponseWriter;
|
||||
import javax.faces.el.ValueBinding;
|
||||
|
||||
import org.alfresco.config.Config;
|
||||
@@ -38,6 +43,8 @@ import org.alfresco.web.config.PropertySheetConfigElement.AssociationConfig;
|
||||
import org.alfresco.web.config.PropertySheetConfigElement.ChildAssociationConfig;
|
||||
import org.alfresco.web.config.PropertySheetConfigElement.ItemConfig;
|
||||
import org.alfresco.web.config.PropertySheetConfigElement.PropertyConfig;
|
||||
import org.alfresco.web.ui.common.ComponentConstants;
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.repo.RepoConstants;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -57,12 +64,15 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
private static String PROP_ID_PREFIX = "prop_";
|
||||
private static String ASSOC_ID_PREFIX = "assoc_";
|
||||
|
||||
private List<ClientValidation> validations = new ArrayList<ClientValidation>();
|
||||
private String variable;
|
||||
private NodeRef nodeRef;
|
||||
private Node node;
|
||||
private Boolean readOnly;
|
||||
private Boolean validationEnabled;
|
||||
private String mode;
|
||||
private String configArea;
|
||||
private String finishButtonId;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
@@ -70,7 +80,7 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
public UIPropertySheet()
|
||||
{
|
||||
// set the default renderer for a property sheet
|
||||
setRendererType("javax.faces.Grid");
|
||||
setRendererType(ComponentConstants.JAVAX_FACES_GRID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,12 +88,13 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
*/
|
||||
public String getFamily()
|
||||
{
|
||||
return "javax.faces.Panel";
|
||||
return UIPanel.COMPONENT_FAMILY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.component.UIComponent#encodeBegin(javax.faces.context.FacesContext)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void encodeBegin(FacesContext context) throws IOException
|
||||
{
|
||||
int howManyKids = getChildren().size();
|
||||
@@ -168,10 +179,29 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
|
||||
super.encodeBegin(context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.faces.component.UIComponent#encodeBegin(javax.faces.context.FacesContext)
|
||||
*/
|
||||
public void encodeEnd(FacesContext context) throws IOException
|
||||
{
|
||||
super.encodeEnd(context);
|
||||
|
||||
// NOTE: We should really use a renderer to output the JavaScript below but that would
|
||||
// require extending the MyFaces HtmlGridRenderer class which we should avoid doing.
|
||||
// Until we support multiple client types this will be OK.
|
||||
|
||||
// output the JavaScript to enforce the required validations (if validation is enabled)
|
||||
if (isValidationEnabled() && this.validations.size() > 0)
|
||||
{
|
||||
renderValidationScript(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void restoreState(FacesContext context, Object state)
|
||||
{
|
||||
Object values[] = (Object[])state;
|
||||
@@ -183,6 +213,9 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
this.readOnly = (Boolean)values[4];
|
||||
this.mode = (String)values[5];
|
||||
this.configArea = (String)values[6];
|
||||
this.validationEnabled = (Boolean)values[7];
|
||||
this.validations = (List<ClientValidation>)values[8];
|
||||
this.finishButtonId = (String)values[9];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +223,7 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
*/
|
||||
public Object saveState(FacesContext context)
|
||||
{
|
||||
Object values[] = new Object[7];
|
||||
Object values[] = new Object[10];
|
||||
// standard component attributes are saved by the super class
|
||||
values[0] = super.saveState(context);
|
||||
values[1] = this.nodeRef;
|
||||
@@ -199,6 +232,9 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
values[4] = this.readOnly;
|
||||
values[5] = this.mode;
|
||||
values[6] = this.configArea;
|
||||
values[7] = this.validationEnabled;
|
||||
values[8] = this.validations;
|
||||
values[9] = this.finishButtonId;
|
||||
return (values);
|
||||
}
|
||||
|
||||
@@ -222,8 +258,7 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
value = vb.getValue(getFacesContext());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: for now we presume the object is a Node, but we need to support id's too
|
||||
|
||||
if (value instanceof Node)
|
||||
{
|
||||
node = (Node)value;
|
||||
@@ -291,6 +326,69 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
this.readOnly = Boolean.valueOf(readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if validation is enabled for this property sheet
|
||||
*/
|
||||
public boolean isValidationEnabled()
|
||||
{
|
||||
// if the property sheet is in "view" mode validation will
|
||||
// always be disabled
|
||||
if (inEditMode() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.validationEnabled == null)
|
||||
{
|
||||
ValueBinding vb = getValueBinding("validationEnabled");
|
||||
if (vb != null)
|
||||
{
|
||||
this.validationEnabled = (Boolean)vb.getValue(getFacesContext());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.validationEnabled == null)
|
||||
{
|
||||
this.validationEnabled = Boolean.TRUE;
|
||||
}
|
||||
|
||||
return this.validationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param validationEnabled Sets the validationEnabled flag
|
||||
*/
|
||||
public void setValidationEnabled(boolean validationEnabled)
|
||||
{
|
||||
this.validationEnabled = Boolean.valueOf(validationEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the finish button
|
||||
*
|
||||
* @return The id of the finish button on the page
|
||||
*/
|
||||
public String getFinishButtonId()
|
||||
{
|
||||
// NOTE: This parameter isn't value binding enabled
|
||||
if (this.finishButtonId == null)
|
||||
{
|
||||
this.finishButtonId = "finish-button";
|
||||
}
|
||||
|
||||
return this.finishButtonId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id of the finish button being used on the page
|
||||
*
|
||||
* @param finishButtonId The id of the finish button
|
||||
*/
|
||||
public void setFinishButtonId(String finishButtonId)
|
||||
{
|
||||
this.finishButtonId = finishButtonId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the mode
|
||||
*/
|
||||
@@ -356,6 +454,158 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
this.configArea = configArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a validation case to the property sheet
|
||||
*
|
||||
* @param validation The validation case to enforce
|
||||
*/
|
||||
public void addClientValidation(ClientValidation validation)
|
||||
{
|
||||
this.validations.add(validation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the list of client validations to enforce
|
||||
*/
|
||||
public List<ClientValidation> getClientValidations()
|
||||
{
|
||||
return this.validations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the necessary JavaScript to enforce any constraints the properties
|
||||
* have.
|
||||
*
|
||||
* @param context FacesContext
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void renderValidationScript(FacesContext context) throws IOException
|
||||
{
|
||||
ResponseWriter out = context.getResponseWriter();
|
||||
UIForm form = Utils.getParentForm(context, this);
|
||||
|
||||
// output the validation.js script
|
||||
// TODO: make sure its only included once per page!!
|
||||
out.write("\n<script type='text/javascript' src='");
|
||||
out.write(context.getExternalContext().getRequestContextPath());
|
||||
out.write("/scripts/validation.js");
|
||||
out.write("'></script>\n<script type='text/javascript'>\n");
|
||||
|
||||
// output variable to hold flag for which submit button was pressed
|
||||
out.write("var finishButtonPressed = false;\n");
|
||||
|
||||
// output the validate() function
|
||||
out.write("function validate()\n{\n var result = true;\n if (finishButtonPressed && (");
|
||||
|
||||
int numberValidations = this.validations.size();
|
||||
List<ClientValidation> realTimeValidations =
|
||||
new ArrayList<ClientValidation>(numberValidations);
|
||||
|
||||
for (int x = 0; x < numberValidations; x++)
|
||||
{
|
||||
ClientValidation validation = this.validations.get(x);
|
||||
|
||||
if (validation.RealTimeChecking)
|
||||
{
|
||||
realTimeValidations.add(validation);
|
||||
}
|
||||
|
||||
renderValidationMethod(out, validation, (x == (numberValidations-1)), true);
|
||||
}
|
||||
|
||||
// return false if validation failed to stop the form submitting
|
||||
out.write(")\n { result = false; }\n\n");
|
||||
out.write(" finishButtonPressed = false;\n return result;\n}\n\n");
|
||||
|
||||
// output the processButtonState() function (if necessary)
|
||||
int numberRealTimeValidations = realTimeValidations.size();
|
||||
if (numberRealTimeValidations > 0)
|
||||
{
|
||||
out.write("function processButtonState()\n{\n if (");
|
||||
|
||||
for (int x = 0; x < numberRealTimeValidations; x++)
|
||||
{
|
||||
renderValidationMethod(out, realTimeValidations.get(x),
|
||||
(x == (numberRealTimeValidations-1)), false);
|
||||
}
|
||||
|
||||
// disable the finish button if validation failed
|
||||
out.write("\n { document.getElementById('");
|
||||
out.write(form.getClientId(context));
|
||||
out.write(NamingContainer.SEPARATOR_CHAR);
|
||||
out.write(getFinishButtonId());
|
||||
out.write("').disabled = true; }\n");
|
||||
out.write(" else { document.getElementById('");
|
||||
out.write(form.getClientId(context));
|
||||
out.write(NamingContainer.SEPARATOR_CHAR);
|
||||
out.write(getFinishButtonId());
|
||||
out.write("').disabled = false; }\n}\n\n");
|
||||
}
|
||||
|
||||
// write out a function to initialise everything
|
||||
out.write("function initValidation()\n{\n");
|
||||
|
||||
// register the validate function as the form onsubmit handler
|
||||
out.write(" document.getElementById('");
|
||||
out.write(form.getClientId(context));
|
||||
out.write("').onsubmit = validate;\n");
|
||||
|
||||
// set the flag when the finish button is clicked
|
||||
out.write(" document.getElementById('");
|
||||
out.write(form.getClientId(context));
|
||||
out.write(NamingContainer.SEPARATOR_CHAR);
|
||||
out.write(getFinishButtonId());
|
||||
out.write("').onclick = function() { finishButtonPressed = true; }\n");
|
||||
|
||||
// perform an initial check at page load time (if we have any real time validations)
|
||||
if (numberRealTimeValidations > 0)
|
||||
{
|
||||
out.write(" processButtonState();\n");
|
||||
}
|
||||
|
||||
// close out the init function
|
||||
out.write("}\n\n");
|
||||
|
||||
// setup init function to be called at page load time
|
||||
out.write("window.onload=initValidation;\n");
|
||||
|
||||
// close out the script block
|
||||
out.write("</script>\n");
|
||||
}
|
||||
|
||||
private void renderValidationMethod(ResponseWriter out, ClientValidation validation,
|
||||
boolean lastMethod, boolean showMessage) throws IOException
|
||||
{
|
||||
out.write("!");
|
||||
out.write(validation.Type);
|
||||
out.write("(");
|
||||
|
||||
// add the parameters
|
||||
int numberParams = validation.Params.size();
|
||||
for (int p = 0; p < numberParams; p++)
|
||||
{
|
||||
out.write(validation.Params.get(p));
|
||||
if (p != (numberParams-1))
|
||||
{
|
||||
out.write(", ");
|
||||
}
|
||||
}
|
||||
|
||||
// add the parameter to show any validation messages
|
||||
out.write(", ");
|
||||
out.write(Boolean.toString(showMessage));
|
||||
out.write(")");
|
||||
|
||||
if (lastMethod)
|
||||
{
|
||||
out.write(")");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.write(" || ");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates all the property components required to display the properties held by the node.
|
||||
*
|
||||
@@ -363,6 +613,7 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
* @param node The Node to show all the properties for
|
||||
* @throws IOException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void createComponentsFromNode(FacesContext context, Node node)
|
||||
throws IOException
|
||||
{
|
||||
@@ -458,6 +709,7 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
* @param properties Collection of properties to render (driven from configuration)
|
||||
* @throws IOException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void createComponentsFromConfig(FacesContext context, Collection<ItemConfig> items)
|
||||
throws IOException
|
||||
{
|
||||
@@ -519,4 +771,30 @@ public class UIPropertySheet extends UIPanel implements NamingContainer
|
||||
"' and added it to property sheet " + this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class representing a validation case that must be enforced.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static class ClientValidation implements Serializable
|
||||
{
|
||||
public String Type;
|
||||
public List<String> Params;
|
||||
public boolean RealTimeChecking;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param type The type of the validation
|
||||
* @param params A List of String parameters to use for the validation
|
||||
* @param realTimeChecking true to check the property sheet in real time
|
||||
* i.e. as the user types or uses the mouse
|
||||
*/
|
||||
public ClientValidation(String type, List<String> params, boolean realTimeChecking)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Params = params;
|
||||
this.RealTimeChecking = realTimeChecking;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,98 +16,11 @@
|
||||
*/
|
||||
package org.alfresco.web.ui.repo.renderer.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.ResponseWriter;
|
||||
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.renderer.BaseRenderer;
|
||||
import org.alfresco.web.ui.repo.component.property.UIAssociation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Renderer for the UIAssociation component
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class AssociationRenderer extends BaseRenderer
|
||||
public class AssociationRenderer extends PropertySheetItemRenderer
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(AssociationRenderer.class);
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeBegin(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: we close off the first <td> generated by the property sheet's grid renderer
|
||||
context.getResponseWriter().write("</td>");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeChildren(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UIAssociation association = (UIAssociation)component;
|
||||
ResponseWriter out = context.getResponseWriter();
|
||||
|
||||
// make sure there are exactly 2 child components
|
||||
int count = association.getChildCount();
|
||||
|
||||
if (count == 2)
|
||||
{
|
||||
// get the label and the control
|
||||
List<UIComponent> kids = association.getChildren();
|
||||
UIComponent label = kids.get(0);
|
||||
UIComponent control = kids.get(1);
|
||||
|
||||
// place a style class on the label column if necessary
|
||||
String labelStylceClass = (String)association.getParent().getAttributes().get("labelStyleClass");
|
||||
out.write("</td><td");
|
||||
if (labelStylceClass != null)
|
||||
{
|
||||
outputAttribute(out, labelStylceClass, "class");
|
||||
}
|
||||
|
||||
// close the <td>
|
||||
out.write(">");
|
||||
// encode the label
|
||||
Utils.encodeRecursive(context, label);
|
||||
// encode the control
|
||||
context.getResponseWriter().write("</td><td>");
|
||||
Utils.encodeRecursive(context, control);
|
||||
|
||||
// NOTE: we'll allow the property sheet's grid renderer close off the last <td>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeEnd(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
// we don't need to do anything in here
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#getRendersChildren()
|
||||
*/
|
||||
public boolean getRendersChildren()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -16,98 +16,11 @@
|
||||
*/
|
||||
package org.alfresco.web.ui.repo.renderer.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.ResponseWriter;
|
||||
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.renderer.BaseRenderer;
|
||||
import org.alfresco.web.ui.repo.component.property.UIChildAssociation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Renderer for the UIChildAssociation component
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class ChildAssociationRenderer extends BaseRenderer
|
||||
public class ChildAssociationRenderer extends PropertySheetItemRenderer
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(ChildAssociationRenderer.class);
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeBegin(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: we close off the first <td> generated by the property sheet's grid renderer
|
||||
context.getResponseWriter().write("</td>");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeChildren(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UIChildAssociation association = (UIChildAssociation)component;
|
||||
ResponseWriter out = context.getResponseWriter();
|
||||
|
||||
// make sure there are exactly 2 child components
|
||||
int count = association.getChildCount();
|
||||
|
||||
if (count == 2)
|
||||
{
|
||||
// get the label and the control
|
||||
List<UIComponent> kids = association.getChildren();
|
||||
UIComponent label = kids.get(0);
|
||||
UIComponent control = kids.get(1);
|
||||
|
||||
// place a style class on the label column if necessary
|
||||
String labelStylceClass = (String)association.getParent().getAttributes().get("labelStyleClass");
|
||||
out.write("</td><td");
|
||||
if (labelStylceClass != null)
|
||||
{
|
||||
outputAttribute(out, labelStylceClass, "class");
|
||||
}
|
||||
|
||||
// close the <td>
|
||||
out.write(">");
|
||||
// encode the label
|
||||
Utils.encodeRecursive(context, label);
|
||||
// encode the control
|
||||
context.getResponseWriter().write("</td><td>");
|
||||
Utils.encodeRecursive(context, control);
|
||||
|
||||
// NOTE: we'll allow the property sheet's grid renderer close off the last <td>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeEnd(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
// we don't need to do anything in here
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#getRendersChildren()
|
||||
*/
|
||||
public boolean getRendersChildren()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -16,99 +16,11 @@
|
||||
*/
|
||||
package org.alfresco.web.ui.repo.renderer.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.ResponseWriter;
|
||||
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.renderer.BaseRenderer;
|
||||
import org.alfresco.web.ui.repo.component.property.UIProperty;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Renderer for the UIProperty component
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class PropertyRenderer extends BaseRenderer
|
||||
public class PropertyRenderer extends PropertySheetItemRenderer
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(PropertyRenderer.class);
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeBegin(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: we close off the first <td> generated by the property sheet's grid renderer
|
||||
context.getResponseWriter().write("</td>");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeChildren(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UIProperty property = (UIProperty)component;
|
||||
ResponseWriter out = context.getResponseWriter();
|
||||
|
||||
// make sure there are exactly 2 child components
|
||||
int count = property.getChildCount();
|
||||
|
||||
if (count == 2)
|
||||
{
|
||||
// get the label and the control
|
||||
List<UIComponent> kids = property.getChildren();
|
||||
UIComponent label = kids.get(0);
|
||||
UIComponent control = kids.get(1);
|
||||
|
||||
// place a style class on the label column if necessary
|
||||
String labelStylceClass = (String)property.getParent().getAttributes().get("labelStyleClass");
|
||||
out.write("</td><td");
|
||||
if (labelStylceClass != null)
|
||||
{
|
||||
outputAttribute(out, labelStylceClass, "class");
|
||||
}
|
||||
|
||||
// close the <td>
|
||||
out.write(">");
|
||||
// encode the label
|
||||
Utils.encodeRecursive(context, label);
|
||||
// encode the control
|
||||
out.write("</td><td>");
|
||||
Utils.encodeRecursive(context, control);
|
||||
|
||||
// NOTE: we'll allow the property sheet's grid renderer close off the last <td>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeEnd(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
// we don't need to do anything in here
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#getRendersChildren()
|
||||
*/
|
||||
public boolean getRendersChildren()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.web.ui.repo.renderer.property;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.ResponseWriter;
|
||||
|
||||
import org.alfresco.web.ui.common.Utils;
|
||||
import org.alfresco.web.ui.common.renderer.BaseRenderer;
|
||||
|
||||
/**
|
||||
* Renderer for a PropertySheetItem component
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class PropertySheetItemRenderer extends BaseRenderer
|
||||
{
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeBegin(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: we close off the first <td> generated by the property sheet's grid renderer
|
||||
context.getResponseWriter().write("</td>");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void encodeChildren(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
if (component.isRendered() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ResponseWriter out = context.getResponseWriter();
|
||||
|
||||
// make sure there are 2 or 3 child components
|
||||
int count = component.getChildCount();
|
||||
|
||||
if (count == 2 || count == 3)
|
||||
{
|
||||
// get the label and the control
|
||||
List<UIComponent> children = component.getChildren();
|
||||
UIComponent label = children.get(0);
|
||||
UIComponent control = children.get(1);
|
||||
|
||||
// place a style class on the label column if necessary
|
||||
String labelStylceClass = (String)component.getParent().getAttributes().get("labelStyleClass");
|
||||
out.write("</td><td");
|
||||
if (labelStylceClass != null)
|
||||
{
|
||||
outputAttribute(out, labelStylceClass, "class");
|
||||
}
|
||||
|
||||
// close the <td>
|
||||
out.write(">");
|
||||
// encode the label
|
||||
Utils.encodeRecursive(context, label);
|
||||
// encode the control
|
||||
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>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
|
||||
*/
|
||||
public void encodeEnd(FacesContext context, UIComponent component) throws IOException
|
||||
{
|
||||
// we don't need to do anything in here
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.render.Renderer#getRendersChildren()
|
||||
*/
|
||||
public boolean getRendersChildren()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -34,9 +34,11 @@ public class PropertySheetGridTag extends BaseComponentTag
|
||||
private String configArea;
|
||||
private String readOnly;
|
||||
private String mode;
|
||||
private String validationEnabled;
|
||||
private String labelStyleClass;
|
||||
private String cellpadding;
|
||||
private String cellspacing;
|
||||
private String finishButtonId;
|
||||
|
||||
/**
|
||||
* @see javax.faces.webapp.UIComponentTag#getComponentType()
|
||||
@@ -110,6 +112,14 @@ public class PropertySheetGridTag extends BaseComponentTag
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param validationEnabled The validationEnabled to set.
|
||||
*/
|
||||
public void setValidationEnabled(String validationEnabled)
|
||||
{
|
||||
this.validationEnabled = validationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param labelStyleClass Sets the style class for the label column
|
||||
*/
|
||||
@@ -134,6 +144,14 @@ public class PropertySheetGridTag extends BaseComponentTag
|
||||
this.cellspacing = cellspacing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param finishButtonId Sets the finish button id
|
||||
*/
|
||||
public void setFinishButtonId(String finishButtonId)
|
||||
{
|
||||
this.finishButtonId = finishButtonId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent)
|
||||
*/
|
||||
@@ -149,8 +167,10 @@ public class PropertySheetGridTag extends BaseComponentTag
|
||||
setStringStaticProperty(component, "labelStyleClass", this.labelStyleClass);
|
||||
setBooleanProperty(component, "externalConfig", this.externalConfig);
|
||||
setBooleanProperty(component, "readOnly", this.readOnly);
|
||||
setBooleanProperty(component, "validationEnabled", this.validationEnabled);
|
||||
setStringStaticProperty(component, "cellpadding", this.cellpadding);
|
||||
setStringStaticProperty(component, "cellspacing", this.cellspacing);
|
||||
setStringStaticProperty(component, "finishButtonId", this.finishButtonId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,9 +185,11 @@ public class PropertySheetGridTag extends BaseComponentTag
|
||||
this.configArea = null;
|
||||
this.readOnly = null;
|
||||
this.mode = null;
|
||||
this.validationEnabled = null;
|
||||
this.labelStyleClass = null;
|
||||
this.cellpadding = null;
|
||||
this.cellspacing = null;
|
||||
this.finishButtonId = null;
|
||||
|
||||
super.release();
|
||||
}
|
||||
|
@@ -1458,10 +1458,10 @@
|
||||
|
||||
<managed-bean>
|
||||
<description>
|
||||
Bean that generates a category picker component
|
||||
Bean that generates a category selector component
|
||||
</description>
|
||||
<managed-bean-name>CategoryPickerGenerator</managed-bean-name>
|
||||
<managed-bean-class>org.alfresco.web.bean.generator.CategoryPickerGenerator</managed-bean-class>
|
||||
<managed-bean-name>CategorySelectorGenerator</managed-bean-name>
|
||||
<managed-bean-class>org.alfresco.web.bean.generator.CategorySelectorGenerator</managed-bean-class>
|
||||
<managed-bean-scope>request</managed-bean-scope>
|
||||
</managed-bean>
|
||||
|
||||
|
@@ -49,6 +49,18 @@
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
|
||||
<attribute>
|
||||
<name>validationEnabled</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
|
||||
<attribute>
|
||||
<name>finishButtonId</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
|
||||
<attribute>
|
||||
<name>var</name>
|
||||
<required>false</required>
|
||||
|
@@ -156,7 +156,7 @@
|
||||
<r:propertySheetGrid id="document-props" value="#{EditDocPropsDialog.editableNode}"
|
||||
var="editDocProps" columns="1"
|
||||
rendered="#{EditDocPropsDialog.otherPropertiesPresent}"
|
||||
externalConfig="true" />
|
||||
externalConfig="true" finishButtonId="ok-button" />
|
||||
<h:outputText value="#{msg.no_other_properties}"
|
||||
rendered="#{EditDocPropsDialog.otherPropertiesPresent == false}" />
|
||||
</td>
|
||||
|
85
source/web/scripts/validation.js
Normal file
85
source/web/scripts/validation.js
Normal file
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// Validation functions
|
||||
// Gavin Cornwell 30-11-2005
|
||||
//
|
||||
|
||||
/**
|
||||
* Informs the user of the given 'message', if 'showMessage' is true.
|
||||
*/
|
||||
function informUser(message, showMessage)
|
||||
{
|
||||
if (showMessage)
|
||||
{
|
||||
alert(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the 'value' is not null or 0.
|
||||
*
|
||||
* @return true if the mandatory validation passed
|
||||
*/
|
||||
function validateMandatory(value, message, showMessage)
|
||||
{
|
||||
var result = true;
|
||||
|
||||
if (value == null || value.length == 0)
|
||||
{
|
||||
informUser(message, showMessage);
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the 'value' is more than 'min' and less than 'max'.
|
||||
*
|
||||
* @return true if the number range validation passed
|
||||
*/
|
||||
function validateNumberRange(value, min, max, message, showMessage)
|
||||
{
|
||||
var result = true;
|
||||
|
||||
if (value < min || value > max)
|
||||
{
|
||||
informUser(message, showMessage);
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the 'value' 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)
|
||||
{
|
||||
var result = true;
|
||||
|
||||
if (value.length < min || value.length > max)
|
||||
{
|
||||
informUser(message, showMessage);
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the 'value' matches the 'expression' if 'requiresMatch' is true.
|
||||
* Ensures the 'value' does not matche the 'expression' if 'requiresMatch' is false.
|
||||
*
|
||||
* @return true if the regex validation passed
|
||||
*/
|
||||
function validateRegex(value, expression, requiresMatch, message, showMessage)
|
||||
{
|
||||
var result = true;
|
||||
|
||||
// TODO: implement the regular expression matching
|
||||
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user