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:
Gavin Cornwell
2006-04-19 08:30:47 +00:00
parent 73cfa5262b
commit f584f83e4c
33 changed files with 1419 additions and 769 deletions

View File

@@ -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}.

View File

@@ -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
}
}

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
*

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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");
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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";

View File

@@ -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();

View File

@@ -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) +

View File

@@ -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 + "(" +

View File

@@ -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)

View File

@@ -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 + "(" +

View File

@@ -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)

View File

@@ -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 + "(" +

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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;
}