- adding some tests for types with restrictions.

- using xsi:nil to deal with invalid values (based on restrictions) for optional elements.  no equivalent solution for attributes which is unfortunate.  for attributes, the types will need to be able to accept empty string as a value for all types where no default is specified.  this fixes part of the bug with dealing with comboboxes with no default.

- more predictable inclusion of group headers using xf:appearance="repeated" attribute.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4821 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ariel Backenroth
2007-01-13 21:16:45 +00:00
parent 504c7f3528
commit 98fe7f854f
5 changed files with 342 additions and 105 deletions

View File

@@ -51,4 +51,15 @@ public class FormBuilderException
{ {
super(x); super(x);
} }
/**
* Constructs an instance of <code>FormBuilderException</code> with the specified root exception.
*
* @param msg the detail message.
* @param x The root exception.
*/
public FormBuilderException(String msg, Exception x)
{
super(msg, x);
}
} }

View File

@@ -723,11 +723,14 @@ public class SchemaFormBuilder
final String pathToRoot, final String pathToRoot,
final boolean checkIfExtension, final boolean checkIfExtension,
final ResourceBundle resourceBundle) final ResourceBundle resourceBundle)
throws FormBuilderException
{ {
XSObjectList attrUses = controlType.getAttributeUses(); XSObjectList attrUses = controlType.getAttributeUses();
if (attrUses == null) if (attrUses == null)
{
return; return;
}
for (int i = 0; i < attrUses.getLength(); i++) for (int i = 0; i < attrUses.getLength(); i++)
{ {
final XSAttributeUse currentAttributeUse = (XSAttributeUse)attrUses.item(i); final XSAttributeUse currentAttributeUse = (XSAttributeUse)attrUses.item(i);
@@ -771,41 +774,56 @@ public class SchemaFormBuilder
{ {
if (LOGGER.isDebugEnabled()) if (LOGGER.isDebugEnabled())
LOGGER.debug("bindId found: " + bindId); LOGGER.debug("bindId found: " + bindId);
JXPathContext context = JXPathContext.newContext(formSection.getOwnerDocument()); JXPathContext context = JXPathContext.newContext(formSection.getOwnerDocument());
final Pointer pointer = final Pointer pointer =
context.getPointer("//*[@" + NamespaceConstants.XFORMS_PREFIX + ":bind='" + bindId + "']"); context.getPointer("//*[@" + NamespaceConstants.XFORMS_PREFIX + ":bind='" + bindId + "']");
if (pointer != null) if (pointer != null)
{
control = (Element)pointer.getNode(); control = (Element)pointer.getNode();
}
} }
//copy it //copy it
if (control == null) if (control == null)
{
LOGGER.warn("Corresponding control not found"); LOGGER.warn("Corresponding control not found");
}
else else
{ {
Element newControl = (Element) control.cloneNode(true); Element newControl = (Element) control.cloneNode(true);
//set new Ids to XForm elements //set new Ids to XForm elements
this.resetXFormIds(newControl); this.resetXFormIds(newControl);
formSection.appendChild(newControl); formSection.appendChild(newControl);
} }
} }
else else
{ {
defaultInstanceElement.setAttributeNS(this.targetNamespace,
// XXXarielb - i probably need the prefix here i.e. "alf:" + attributeName
attributeName,
(currentAttributeUse.getConstraintType() == XSConstants.VC_NONE
? null
: currentAttributeUse.getConstraintValue()));
final String newPathToRoot = final String newPathToRoot =
(pathToRoot == null || pathToRoot.length() == 0 (pathToRoot == null || pathToRoot.length() == 0
? "@" + currentAttribute.getName() ? "@" + currentAttribute.getName()
: (pathToRoot.endsWith("/") : (pathToRoot.endsWith("/")
? pathToRoot + "@" + currentAttribute.getName() ? pathToRoot + "@" + currentAttribute.getName()
: pathToRoot + "/@" + currentAttribute.getName())); : pathToRoot + "/@" + currentAttribute.getName()));
LOGGER.debug("adding attribute " + attributeName +
" at " + newPathToRoot);
try
{
final String defaultValue = (currentAttributeUse.getConstraintType() == XSConstants.VC_NONE
? null
: currentAttributeUse.getConstraintValue());
defaultInstanceElement.setAttributeNS(this.targetNamespace,
// XXXarielb - i probably need the prefix here i.e. "alf:" + attributeName
attributeName,
defaultValue);
}
catch (Exception e)
{
throw new FormBuilderException("error retrieving default value for attribute " +
attributeName + " at " + newPathToRoot, e);
}
this.addSimpleType(xForm, this.addSimpleType(xForm,
modelSection, modelSection,
formSection, formSection,
@@ -829,6 +847,7 @@ public class SchemaFormBuilder
boolean relative, boolean relative,
final boolean checkIfExtension, final boolean checkIfExtension,
final ResourceBundle resourceBundle) final ResourceBundle resourceBundle)
throws FormBuilderException
{ {
if (controlType == null) if (controlType == null)
{ {
@@ -846,37 +865,32 @@ public class SchemaFormBuilder
// add a group node and recurse // add a group node and recurse
// //
Element groupElement = this.createGroup(xForm, final Element groupElement = this.createGroup(xForm,
modelSection, modelSection,
formSection, formSection,
owner, owner,
resourceBundle); resourceBundle);
Element groupWrapper = groupElement;
if (groupElement != modelSection)
{
groupWrapper = groupElement;
}
final SchemaUtil.Occurance o = SchemaUtil.getOccurance(owner); final SchemaUtil.Occurance o = SchemaUtil.getOccurance(owner);
final Element repeatSection = this.addRepeatIfNecessary(xForm, final Element repeatSection = this.addRepeatIfNecessary(xForm,
modelSection, modelSection,
groupWrapper, groupElement,
controlType, controlType,
o, o,
pathToRoot); pathToRoot);
Element repeatContentWrapper = repeatSection; if (repeatSection != groupElement)
if (repeatSection != groupWrapper)
{ {
groupElement.setAttributeNS(NamespaceConstants.XFORMS_NS,
NamespaceConstants.XFORMS_PREFIX + ":appearance",
"repeated");
// we have a repeat // we have a repeat
repeatContentWrapper = repeatSection;
relative = true; relative = true;
} }
this.addComplexTypeChildren(xForm, this.addComplexTypeChildren(xForm,
modelSection, modelSection,
defaultInstanceElement, defaultInstanceElement,
repeatContentWrapper, repeatSection,
schema, schema,
controlType, controlType,
owner, owner,
@@ -897,6 +911,7 @@ public class SchemaFormBuilder
final boolean relative, final boolean relative,
final boolean checkIfExtension, final boolean checkIfExtension,
final ResourceBundle resourceBundle) final ResourceBundle resourceBundle)
throws FormBuilderException
{ {
if (controlType == null) if (controlType == null)
@@ -1015,6 +1030,7 @@ public class SchemaFormBuilder
final XSElementDeclaration elementDecl, final XSElementDeclaration elementDecl,
final String pathToRoot, final String pathToRoot,
final ResourceBundle resourceBundle) final ResourceBundle resourceBundle)
throws FormBuilderException
{ {
XSTypeDefinition controlType = elementDecl.getTypeDefinition(); XSTypeDefinition controlType = elementDecl.getTypeDefinition();
if (controlType == null) if (controlType == null)
@@ -1483,17 +1499,19 @@ public class SchemaFormBuilder
final SchemaUtil.Occurance o, final SchemaUtil.Occurance o,
final boolean checkIfExtension, final boolean checkIfExtension,
final ResourceBundle resourceBundle) final ResourceBundle resourceBundle)
throws FormBuilderException
{ {
if (group == null) if (group == null)
{
return; return;
}
final Element repeatSection = final Element repeatSection = this.addRepeatIfNecessary(xForm,
this.addRepeatIfNecessary(xForm, modelSection,
modelSection, formSection,
formSection, owner.getTypeDefinition(),
owner.getTypeDefinition(), o,
o, pathToRoot);
pathToRoot);
Element repeatContentWrapper = repeatSection; Element repeatContentWrapper = repeatSection;
if (repeatSection != formSection) if (repeatSection != formSection)
@@ -1629,12 +1647,11 @@ public class SchemaFormBuilder
" default instance element for " + elementName + " default instance element for " + elementName +
" at path " + path); " at path " + path);
// update the default instance // update the default instance
if (elementOccurs.maximum == 1) if (elementOccurs.isRepeated())
{
defaultInstanceElement.appendChild(newDefaultInstanceElement.cloneNode(true));
}
else
{ {
LOGGER.debug("adding " + (elementOccurs.minimum + 1) +
" default instance elements for " + elementName +
" at path " + path);
for (int i = 0; i < elementOccurs.minimum + 1; i++) for (int i = 0; i < elementOccurs.minimum + 1; i++)
{ {
final Element e = (Element)newDefaultInstanceElement.cloneNode(true); final Element e = (Element)newDefaultInstanceElement.cloneNode(true);
@@ -1647,6 +1664,18 @@ public class SchemaFormBuilder
defaultInstanceElement.appendChild(e); defaultInstanceElement.appendChild(e);
} }
} }
else
{
LOGGER.debug("adding one default instance element for " + elementName +
" at path " + path);
if (elementOccurs.minimum == 0)
{
newDefaultInstanceElement.setAttributeNS(NamespaceConstants.XMLSCHEMA_INSTANCE_NS,
NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX + ":nil",
"true");
}
defaultInstanceElement.appendChild(newDefaultInstanceElement);
}
} }
} }
else else
@@ -1671,13 +1700,16 @@ public class SchemaFormBuilder
{ {
// add xforms:repeat section if this element re-occurs // add xforms:repeat section if this element re-occurs
//
if (o.maximum == 1) if (o.maximum == 1)
{
return formSection; return formSection;
}
if (LOGGER.isDebugEnabled()) if (LOGGER.isDebugEnabled())
{
LOGGER.debug("AddRepeatIfNecessary for multiple element for type " + LOGGER.debug("AddRepeatIfNecessary for multiple element for type " +
controlType.getName() + ", maxOccurs=" + o.maximum); controlType.getName() + ", maxOccurs=" + o.maximum);
}
final Element repeatSection = final Element repeatSection =
xForm.createElementNS(NamespaceConstants.XFORMS_NS, xForm.createElementNS(NamespaceConstants.XFORMS_NS,
@@ -1724,6 +1756,10 @@ public class SchemaFormBuilder
//add a group inside the repeat? //add a group inside the repeat?
final Element group = xForm.createElementNS(NamespaceConstants.XFORMS_NS, final Element group = xForm.createElementNS(NamespaceConstants.XFORMS_NS,
NamespaceConstants.XFORMS_PREFIX + ":group"); NamespaceConstants.XFORMS_PREFIX + ":group");
group.setAttributeNS(NamespaceConstants.XFORMS_NS,
NamespaceConstants.XFORMS_PREFIX + ":appearance",
"repeated");
this.setXFormsId(group); this.setXFormsId(group);
repeatSection.appendChild(group); repeatSection.appendChild(group);
return group; return group;
@@ -1770,6 +1806,10 @@ public class SchemaFormBuilder
formSection, formSection,
(XSElementDeclaration)owner, (XSElementDeclaration)owner,
resourceBundle); resourceBundle);
groupElement.setAttributeNS(NamespaceConstants.XFORMS_NS,
NamespaceConstants.XFORMS_PREFIX + ":appearance",
"repeated");
//set content //set content
formSection = groupElement; formSection = groupElement;
} }

View File

@@ -0,0 +1,169 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:alf="http://www.alfresco.org"
elementFormDefault="qualified">
<xs:simpleType name="restricted_integer">
<xs:restriction>
<xs:union>
<xs:simpleType base="xs:integer">
<xs:maxInclusive value="10"/>
<xs:minInclusive value="-10"/>
</xs:simpleType>
<xs:simpleType base="xs:string">
<xs:length value="0"/>
</xs:simpleType>
</xs:union>
</xs:restriction>
</xs:simpleType>
<xs:element name="integer-test">
<xs:complexType>
<xs:sequence>
<xs:element name="integer">
<xs:complexType>
<xs:sequence>
<xs:element name="elements">
<xs:complexType>
<xs:sequence>
<xs:element name="required">
<xs:complexType>
<xs:sequence>
<xs:element name="has_default"
type="xs:integer"
minOccurs="1"
maxOccurs="1"
default="11"/>
<xs:element name="no_default"
minOccurs="1"
maxOccurs="1"
type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="optional">
<xs:complexType>
<xs:sequence>
<xs:element name="has_default"
type="xs:integer"
minOccurs="0"
maxOccurs="1"
default="11"/>
<xs:element name="no_default"
minOccurs="0"
maxOccurs="1"
type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="attributes">
<xs:complexType>
<xs:sequence>
<xs:element name="required">
<xs:complexType>
<xs:attribute name="has_default"
type="xs:integer"
use="required"
default="11"/>
<xs:attribute name="no_default"
use="required"
type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="optional">
<xs:complexType>
<xs:attribute name="has_default"
type="xs:integer"
use="optional"
default="11"/>
<xs:attribute name="no_default"
use="optional"
type="xs:integer"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="integer_restricted">
<xs:annotation>
<xs:appinfo>
<alf:label>Integer Restricted -10 to 10</alf:label>
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="elements">
<xs:complexType>
<xs:sequence>
<xs:element name="required">
<xs:complexType>
<xs:sequence>
<xs:element name="has_default"
type="restricted_integer"
minOccurs="1"
maxOccurs="1"
default="5"/>
<xs:element name="no_default"
minOccurs="1"
maxOccurs="1"
type="restricted_integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="optional">
<xs:complexType>
<xs:sequence>
<xs:element name="has_default"
type="restricted_integer"
minOccurs="0"
maxOccurs="1"
default="5"/>
<xs:element name="no_default"
minOccurs="0"
maxOccurs="1"
type="restricted_integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="attributes">
<xs:complexType>
<xs:sequence>
<xs:element name="required">
<xs:complexType>
<xs:attribute name="has_default"
type="restricted_integer"
use="required"
default="5"/>
<xs:attribute name="no_default"
use="required"
type="restricted_integer"/>
</xs:complexType>
</xs:element>
<xs:element name="optional">
<xs:complexType>
<xs:attribute name="has_default"
type="restricted_integer"
use="optional"
default="5"/>
<xs:attribute name="no_default"
use="optional"
type="restricted_integer"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -19,24 +19,70 @@
<xs:element name="select1-test"> <xs:element name="select1-test">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element name="required_combobox_with_default" <xs:element name="elements">
type="ten_string_values" <xs:complexType>
minOccurs="1" <xs:sequence>
maxOccurs="1" <xs:element name="required">
default="five"/> <xs:complexType>
<xs:element name="required_combobox_with_no_default" <xs:sequence>
minOccurs="1" <xs:element name="has_default"
maxOccurs="1" type="ten_string_values"
type="ten_string_values"/> minOccurs="1"
<xs:element name="optional_combobox_with_default" maxOccurs="1"
type="ten_string_values" default="five"/>
minOccurs="0" <xs:element name="no_default"
maxOccurs="1" minOccurs="1"
default="five"/> maxOccurs="1"
<xs:element name="optional_combobox_with_no_default" type="ten_string_values"/>
minOccurs="0" </xs:sequence>
maxOccurs="1" </xs:complexType>
type="ten_string_values"/> </xs:element>
<xs:element name="optional">
<xs:complexType>
<xs:sequence>
<xs:element name="has_default"
type="ten_string_values"
minOccurs="0"
maxOccurs="1"
default="five"/>
<xs:element name="no_default"
minOccurs="0"
maxOccurs="1"
type="ten_string_values"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="attributes">
<xs:complexType>
<xs:sequence>
<xs:element name="required">
<xs:complexType>
<xs:attribute name="has_default"
type="ten_string_values"
use="required"
default="five"/>
<xs:attribute name="no_default"
use="required"
type="ten_string_values"/>
</xs:complexType>
</xs:element>
<xs:element name="optional">
<xs:complexType>
<xs:attribute name="has_default"
type="ten_string_values"
use="optional"
default="five"/>
<xs:attribute name="no_default"
use="optional"
type="ten_string_values"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>

View File

@@ -548,14 +548,12 @@ dojo.declare("alfresco.xforms.AbstractSelectWidget",
valid = _evaluateXPath(binding.constraint, value, XPathResult.BOOLEAN_TYPE); valid = _evaluateXPath(binding.constraint, value, XPathResult.BOOLEAN_TYPE);
} }
dojo.debug("valid " + dojo.dom.textContent(value) + "? " + valid); dojo.debug("valid " + dojo.dom.textContent(value) + "? " + valid);
if (valid) result.push({
{ id: value.getAttribute("id"),
result.push({ label: valid ? dojo.dom.textContent(label) : "",
id: value.getAttribute("id"), value: valid ? dojo.dom.textContent(value) : "xxx",
label: dojo.dom.textContent(label), valid: valid
value: dojo.dom.textContent(value) });
});
}
} }
return result; return result;
} }
@@ -566,7 +564,6 @@ dojo.declare("alfresco.xforms.Select",
{ {
initializer: function(xform, xformsNode) initializer: function(xform, xformsNode)
{ {
// this.inherited("initializer", [ xform, xformsNode ]);
}, },
render: function(attach_point) render: function(attach_point)
{ {
@@ -662,7 +659,6 @@ dojo.declare("alfresco.xforms.Select1",
{ {
initializer: function(xform, xformsNode) initializer: function(xform, xformsNode)
{ {
// this.inherited("initializer", [ xform, xformsNode ]);
}, },
render: function(attach_point) render: function(attach_point)
{ {
@@ -707,6 +703,11 @@ dojo.declare("alfresco.xforms.Select1",
attach_point.appendChild(this.widget); attach_point.appendChild(this.widget);
for (var i = 0; i < values.length; i++) for (var i = 0; i < values.length; i++)
{ {
if (initial_value && !values[i].valid)
{
// skip the invalid value if we have a default value
continue;
}
var option = document.createElement("option"); var option = document.createElement("option");
this.widget.appendChild(option); this.widget.appendChild(option);
option.appendChild(document.createTextNode(values[i].label)); option.appendChild(document.createTextNode(values[i].label));
@@ -789,24 +790,9 @@ dojo.declare("alfresco.xforms.Group",
{ {
this.children = []; this.children = [];
dojo.html.removeClass(this.domNode, "xformsItem"); dojo.html.removeClass(this.domNode, "xformsItem");
this.showHeader = false; this.showHeader =
}, (this.xformsNode.getAttribute("appearance") != "repeated" &&
setShowHeader: function(showHeader) this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":appearance") != "repeated");
{
if (showHeader == this.showHeader)
{
return;
}
this.showHeader = showHeader;
if (this.showHeader && this.groupHeaderNode.style.display == "none")
{
this.groupHeaderNode.style.display = "block";
}
if (!this.showHeader && this.groupHeaderNode.style.display == "block")
{
this.groupHeaderNode.style.display = "none";
}
}, },
getWidgetsInvalidForSubmit: function() getWidgetsInvalidForSubmit: function()
{ {
@@ -947,6 +933,8 @@ dojo.declare("alfresco.xforms.Group",
return child; return child;
}, },
_childAdded: function(child) { },
_childRemoved: function(child) { },
_destroy: function() _destroy: function()
{ {
this.inherited("_destroy", []); this.inherited("_destroy", []);
@@ -977,11 +965,12 @@ dojo.declare("alfresco.xforms.Group",
this.domNode.appendChild(idNode); this.domNode.appendChild(idNode);
} }
this.showHeader = this.showHeader && this.parent != null;
this.groupHeaderNode = document.createElement("div"); this.groupHeaderNode = document.createElement("div");
this.groupHeaderNode.id = this.id + "-groupHeaderNode"; this.groupHeaderNode.id = this.id + "-groupHeaderNode";
this.domNode.appendChild(this.groupHeaderNode); this.domNode.appendChild(this.groupHeaderNode);
dojo.html.setClass(this.groupHeaderNode, "xformsGroupHeader"); dojo.html.setClass(this.groupHeaderNode, "xformsGroupHeader");
this.groupHeaderNode.style.display = "none"; this.groupHeaderNode.style.display = this.showHeader ? "block" : "none";
this.toggleExpandedImage = document.createElement("img"); this.toggleExpandedImage = document.createElement("img");
this.groupHeaderNode.appendChild(this.toggleExpandedImage); this.groupHeaderNode.appendChild(this.toggleExpandedImage);
@@ -1042,24 +1031,6 @@ dojo.declare("alfresco.xforms.Group",
{ {
this.children[i].hideAlert(); this.children[i].hideAlert();
} }
},
_childAdded: function(child)
{
var hasNonGroupChildren = false;
for (var i in this.children)
{
if (!(this.children[i] instanceof alfresco.xforms.Group))
{
hasNonGroupChildren = true;
break;
}
}
this.setShowHeader(hasNonGroupChildren &&
this.children.length != 1 &&
this.parent != null);
},
_childRemoved: function(child)
{
} }
}); });