- removing usage of dojo for textfield widgets - they were basically useless and i'm working towards consistent presentation for valid/invalid states

- implementing preliminary validation feedback for submit errors meaning that for the most part, the client knows which elements are in an invalid state on submit and require fixes

next steps:
- add in xforms:alerts so we get better error messages when a control is not filled out/filled out with an invalid value
- fix up the error reporting in the ui so it looks more presentable
- add in support for custom xforms:alerts as metadata within the xsd so that we can have truly informative error messages.



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@4026 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ariel Backenroth
2006-10-05 02:24:33 +00:00
parent 6da8f919df
commit 54ac87ef6b
5 changed files with 918 additions and 862 deletions

View File

@@ -538,19 +538,19 @@ public class SchemaFormBuilder
? this.submitMethod ? this.submitMethod
: SchemaFormBuilder.SUBMIT_METHOD_POST)); : SchemaFormBuilder.SUBMIT_METHOD_POST));
//Element submitButton = (Element) formSection.appendChild(xForm.createElementNS(XFORMS_NS,SchemaFormBuilder.XFORMS_NS_PREFIX+"submit")); final Element submitButton =
Element submitButton =
xForm.createElementNS(XFORMS_NS, SchemaFormBuilder.XFORMS_NS_PREFIX + "submit"); xForm.createElementNS(XFORMS_NS, SchemaFormBuilder.XFORMS_NS_PREFIX + "submit");
Element submitControlWrapper = this.wrapper.createControlsWrapper(submitButton); final Element submitControlWrapper = this.wrapper.createControlsWrapper(submitButton);
formContentWrapper.appendChild(submitControlWrapper); formContentWrapper.appendChild(submitControlWrapper);
submitButton.setAttributeNS(XFORMS_NS, submitButton.setAttributeNS(XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "submission", SchemaFormBuilder.XFORMS_NS_PREFIX + "submission",
submissionId); submissionId);
this.setXFormsId(submitButton); this.setXFormsId(submitButton);
Element submitButtonCaption = (Element) final Element submitButtonCaption =
submitButton.appendChild(xForm.createElementNS(XFORMS_NS, xForm.createElementNS(XFORMS_NS,
SchemaFormBuilder.XFORMS_NS_PREFIX + "label")); SchemaFormBuilder.XFORMS_NS_PREFIX + "label");
submitButton.appendChild(submitButtonCaption);
submitButtonCaption.appendChild(xForm.createTextNode("Submit")); submitButtonCaption.appendChild(xForm.createTextNode("Submit"));
this.setXFormsId(submitButtonCaption); this.setXFormsId(submitButtonCaption);
return xForm; return xForm;
@@ -2407,9 +2407,6 @@ public class SchemaFormBuilder
SchemaFormBuilder.XFORMS_NS_PREFIX + "label"); SchemaFormBuilder.XFORMS_NS_PREFIX + "label");
this.setXFormsId(triggerLabel); this.setXFormsId(triggerLabel);
trigger.appendChild(triggerLabel); trigger.appendChild(triggerLabel);
//triggerLabel_insert.setAttributeNS(SchemaFormBuilder.XLINK_NS,
// SchemaFormBuilder.XLINK_NS_PREFIX + "href",
// "images/add_new.gif");
triggerLabel.appendChild(xForm.createTextNode(label)); triggerLabel.appendChild(xForm.createTextNode(label));

View File

@@ -132,6 +132,8 @@ public class XFormsBean
et.addEventListener(XFormsEventFactory.SUBMIT_DONE, el, true); et.addEventListener(XFormsEventFactory.SUBMIT_DONE, el, true);
et.addEventListener(XFormsEventFactory.SUBMIT_ERROR, el, true); et.addEventListener(XFormsEventFactory.SUBMIT_ERROR, el, true);
et.addEventListener(XFormsEventFactory.REQUIRED, el, true); et.addEventListener(XFormsEventFactory.REQUIRED, el, true);
et.addEventListener(XFormsEventFactory.OPTIONAL, el, true);
et.addEventListener(XFormsEventFactory.VALID, el, true);
et.addEventListener(XFormsEventFactory.INVALID, el, true); et.addEventListener(XFormsEventFactory.INVALID, el, true);
et.addEventListener(XFormsEventFactory.OUT_OF_RANGE, el, true); et.addEventListener(XFormsEventFactory.OUT_OF_RANGE, el, true);
et.addEventListener(XFormsEventFactory.CHIBA_STATE_CHANGED, el, true); et.addEventListener(XFormsEventFactory.CHIBA_STATE_CHANGED, el, true);

View File

@@ -42,7 +42,7 @@
<xs:element name="optional_textfield" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="optional_textfield" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="prefilled_textfield" type="xs:string" minOccurs="0" maxOccurs="1" default="i am the default value"/> <xs:element name="prefilled_textfield" type="xs:string" minOccurs="0" maxOccurs="1" default="i am the default value"/>
<xs:element name="integer" type="xs:integer"/> <xs:element name="integer" type="xs:integer"/>
<xs:element name="positiveInteger" type="xs:positiveInteger"/> <xs:element name="positive_integer" type="xs:positiveInteger"/>
<xs:element name="double" type="xs:double"/> <xs:element name="double" type="xs:double"/>
<xs:element name="date" type="xs:date"/> <xs:element name="date" type="xs:date"/>
<xs:element name="radio" type="five_string_values"/> <xs:element name="radio" type="five_string_values"/>

View File

@@ -43,7 +43,7 @@ body
<xsl:template match="/components/integer"> <xsl:template match="/components/integer">
<div style="line-height: 25px;"><span class="name">Integer:</span> <xsl:value-of select="/components/integer"/></div> <div style="line-height: 25px;"><span class="name">Integer:</span> <xsl:value-of select="/components/integer"/></div>
</xsl:template> </xsl:template>
<xsl:template match="/components/positiveInteger"> <xsl:template match="/components/positive_integer">
<div style="line-height: 25px;"><span class="name">Positive Integer:</span> <xsl:value-of select="/components/positiveInteger"/></div> <div style="line-height: 25px;"><span class="name">Positive Integer:</span> <xsl:value-of select="/components/positiveInteger"/></div>
</xsl:template> </xsl:template>
<xsl:template match="/components/double"> <xsl:template match="/components/double">

View File

@@ -35,6 +35,8 @@ dojo.declare("alfresco.xforms.Widget",
this.node = node; this.node = node;
this.node.widget = this; this.node.widget = this;
this.id = this.node.getAttribute("id"); this.id = this.node.getAttribute("id");
this.modified = false;
this.valid = true;
}, },
parent: null, parent: null,
domContainer: null, domContainer: null,
@@ -42,6 +44,32 @@ dojo.declare("alfresco.xforms.Widget",
{ {
return this.xform.getBinding(this.node); return this.xform.getBinding(this.node);
}, },
setModified: function(b)
{
this.modified = b;
this._updateDisplay();
},
setValid: function(b)
{
this.valid = b;
this._updateDisplay();
},
setRequired: function(b)
{
this.required = b;
this._updateDisplay();
},
isValidForSubmit: function()
{
var result = true;
if (!this.valid)
result = false;
else if (!this.modified &&
this.isRequired() &&
this.getInitialValue() == null)
result = false;
return result;
},
getDepth: function() getDepth: function()
{ {
var result = 1; var result = 1;
@@ -78,7 +106,9 @@ dojo.declare("alfresco.xforms.Widget",
nsResolver, nsResolver,
XPathResult.STRING_TYPE, XPathResult.STRING_TYPE,
null); null);
return result.stringValue; return (result.stringValue != null && result.stringValue.length > 0
? result.stringValue
: null);
}, },
_getLabelNode: function() _getLabelNode: function()
{ {
@@ -96,44 +126,11 @@ dojo.declare("alfresco.xforms.Widget",
{ {
var node = this._getLabelNode(); var node = this._getLabelNode();
return node ? dojo.dom.textContent(node) : ""; return node ? dojo.dom.textContent(node) : "";
}
});
dojo.declare("alfresco.xforms.NumericStepper",
alfresco.xforms.Widget,
{
initializer: function(xform, node, stepper_type)
{
this.inherited("initializer", [ xform, node ]);
this.stepper_type = stepper_type;
}, },
render: function(attach_point) _updateDisplay: function()
{ {
var nodeRef = document.createElement("div"); // this.domContainer.style.backgroundColor =
attach_point.appendChild(nodeRef); // (!this.valid ? "yellow" : this.modified ? "lightgreen" : "white");
var initial_value = this.getInitialValue() || "";
var w = dojo.widget.createWidget((this.stepper_type == "double"
? "AdjustableRealNumberTextBox"
: "AdjustableIntegerTextBox"),
{
widgetId: this.id + "-widget",
required: this.isRequired(),
value: initial_value
},
nodeRef);
w.widget = this;
this.widget = w;
dojo.event.connect(w, "adjustValue", this, this._widget_changeHandler);
dojo.event.connect(w, "onkeyup", this, this._widget_changeHandler);
},
getValue: function()
{
return this.widget.getValue();
},
_widget_changeHandler: function(event)
{
this.xform.setXFormsValue(this.id, this.getValue());
} }
}); });
@@ -146,22 +143,16 @@ dojo.declare("alfresco.xforms.DatePicker",
}, },
render: function(attach_point) render: function(attach_point)
{ {
var initial_value = this.getInitialValue(); var initial_value = this.getInitialValue() || "";
var dateTextBoxDiv = document.createElement("div"); this.domNode = document.createElement("div");
attach_point.appendChild(dateTextBoxDiv); attach_point.appendChild(this.domNode);
this.dateTextBox = dojo.widget.createWidget("DateTextBox", this.widget = document.createElement("input");
{ this.widget.setAttribute("id", this.id + "-widget");
widgetId: this.id + "-widget", this.widget.setAttribute("type", "text");
required: this.isRequired(), this.widget.setAttribute("value", initial_value);
format: "YYYY-MM-DD", this.domNode.appendChild(this.widget);
value: initial_value dojo.event.connect(this.widget, "onfocus", this, this._dateTextBox_focusHandler);
},
dateTextBoxDiv);
dojo.event.connect(this.dateTextBox,
"onfocus",
this,
this._dateTextBox_focusHandler);
var datePickerDiv = document.createElement("div"); var datePickerDiv = document.createElement("div");
attach_point.appendChild(datePickerDiv); attach_point.appendChild(datePickerDiv);
@@ -169,36 +160,36 @@ dojo.declare("alfresco.xforms.DatePicker",
var dp_initial_value = (initial_value var dp_initial_value = (initial_value
? initial_value ? initial_value
: dojo.widget.DatePicker.util.toRfcDate(new Date())); : dojo.widget.DatePicker.util.toRfcDate(new Date()));
this.dateTextBox.picker = dojo.widget.createWidget("DatePicker", this.widget.picker = dojo.widget.createWidget("DatePicker",
{ {
isHidden: true, isHidden: true,
storedDate: dp_initial_value storedDate: dp_initial_value
}, },
datePickerDiv); datePickerDiv);
this.dateTextBox.picker.hide(); this.widget.picker.hide();
dojo.event.connect(this.dateTextBox.picker, dojo.event.connect(this.widget.picker,
"onSetDate", "onSetDate",
this, this,
this._datePicker_setDateHandler); this._datePicker_setDateHandler);
}, },
getValue: function() getValue: function()
{ {
return this.dateTextBox.getValue(); return this.widget.value;
}, },
_dateTextBox_focusHandler: function(event) _dateTextBox_focusHandler: function(event)
{ {
this.dateTextBox.hide(); dojo.style.hide(this.widget);
this.dateTextBox.picker.show(); this.widget.picker.show();
this.domContainer.style.height = this.domContainer.style.height =
this.dateTextBox.picker.domNode.offsetHeight + "px"; this.widget.picker.domNode.offsetHeight + "px";
}, },
_datePicker_setDateHandler: function(event) _datePicker_setDateHandler: function(event)
{ {
this.dateTextBox.picker.hide(); this.widget.picker.hide();
this.dateTextBox.show(); dojo.style.show(this.widget);
this.domContainer.style.height = this.domContainer.style.height =
this.dateTextBox.domNode.offsetHeight + "px"; Math.max(this.widget.offsetHeight, 20) + "px";
this.dateTextBox.setValue(dojo.widget.DatePicker.util.toRfcDate(this.dateTextBox.picker.date)); this.widget.value = dojo.widget.DatePicker.util.toRfcDate(this.widget.picker.date);
this.xform.setXFormsValue(this.id, this.getValue()); this.xform.setXFormsValue(this.id, this.getValue());
} }
}); });
@@ -210,26 +201,43 @@ dojo.declare("alfresco.xforms.TextField",
{ {
this.inherited("initializer", [ xform, node ]); this.inherited("initializer", [ xform, node ]);
}, },
isValidForSubmit: function()
{
var result = this.inherited("isValidForSubmit", []);
if (!result)
return false;
if (this.isRequired() && this.getValue() == null)
return false;
return true;
},
render: function(attach_point) render: function(attach_point)
{ {
var nodeRef = document.createElement("div");
attach_point.appendChild(nodeRef);
var initial_value = this.getInitialValue() || ""; var initial_value = this.getInitialValue() || "";
this.domNode = document.createElement("div");
this.domNode.setAttribute("id", this.id + "-domNode");
attach_point.appendChild(this.domNode);
var w = dojo.widget.createWidget("ValidationTextBox", this.widget = document.createElement("input");
{ this.widget.setAttribute("type", "text");
widgetId: this.id + "-widget", this.widget.setAttribute("id", this.id + "-widget");
required: this.isRequired(), this.widget.setAttribute("value", initial_value);
value: initial_value this.domNode.appendChild(this.widget);
}, // this.widget = dojo.widget.createWidget("ValidationTextBox",
nodeRef); // {
w.widget = this; // widgetId: this.id + "-widget",
this.widget = w; // required: this.isRequired(),
dojo.event.connect(w, "onkeyup", this, this._widget_keyUpHandler); // value: initial_value
// },
// this.domNode);
dojo.event.connect(this.widget, "onkeyup", this, this._widget_keyUpHandler);
}, },
getValue: function() getValue: function()
{ {
return this.widget.getValue(); var result = this.widget.value;
if (result != null && result.length == 0)
result = null;
return result;
}, },
_widget_keyUpHandler: function(event) _widget_keyUpHandler: function(event)
{ {
@@ -335,6 +343,7 @@ dojo.declare("alfresco.xforms.Select",
} }
else else
{ {
initial_value = initial_value ? initial_value.split(' ') : [];
var list = document.createElement("select"); var list = document.createElement("select");
list.setAttribute("id", this.id + "-widget"); list.setAttribute("id", this.id + "-widget");
list.setAttribute("multiple", true); list.setAttribute("multiple", true);
@@ -344,7 +353,7 @@ dojo.declare("alfresco.xforms.Select",
var option = document.createElement("option"); var option = document.createElement("option");
option.appendChild(document.createTextNode(values[i].label)); option.appendChild(document.createTextNode(values[i].label));
option.setAttribute("value", values[i].value); option.setAttribute("value", values[i].value);
if (values[i].value == initial_value) if (initial_value.indexOf(values[i].value) != -1)
option.setAttribute("selected", "true"); option.setAttribute("selected", "true");
list.appendChild(option); list.appendChild(option);
} }
@@ -468,6 +477,18 @@ dojo.declare("alfresco.xforms.Group",
this.children = []; this.children = [];
}, },
children: null, children: null,
getWidgetsInvalidForSubmit: function()
{
var result = [];
for (var i = 0; i < this.children.length; i++)
{
if (this.children[i] instanceof alfresco.xforms.Group)
result = result.concat(this.children[i].getWidgetsInvalidForSubmit());
else if (!this.children[i].isValidForSubmit())
result.push(this.children[i]);
}
return result;
},
getChildAt: function(index) getChildAt: function(index)
{ {
return index < this.children.length ? this.children[index] : null; return index < this.children.length ? this.children[index] : null;
@@ -546,7 +567,7 @@ dojo.declare("alfresco.xforms.Group",
child.domContainer.style.lineHeight = child.domContainer.style.height; child.domContainer.style.lineHeight = child.domContainer.style.height;
} }
contentDiv.style.top = "-" + contentDiv.offsetTop + "px"; contentDiv.style.top = "-" + contentDiv.offsetTop + "px";
contentDiv.widget = child;
this._updateDisplay(); this._updateDisplay();
return child.domContainer; return child.domContainer;
@@ -587,6 +608,10 @@ dojo.declare("alfresco.xforms.Group",
}, },
_updateDisplay: function() _updateDisplay: function()
{ {
for (var i = 0; i < this.children.length; i++)
{
this.children[i]._updateDisplay();
}
} }
}); });
@@ -645,6 +670,7 @@ dojo.declare("alfresco.xforms.Repeat",
}, },
_updateDisplay: function() _updateDisplay: function()
{ {
this.inherited("_updateDisplay", []);
for (var i = 0; i < this.children.length; i++) for (var i = 0; i < this.children.length; i++)
{ {
this.children[i].domContainer.style.backgroundColor = this.children[i].domContainer.style.backgroundColor =
@@ -888,9 +914,9 @@ dojo.declare("alfresco.xforms.XFormsEvent",
}, },
getTarget: function() getTarget: function()
{ {
var targetDomNode = document.getElementById(this.targetId + "-domNode"); var targetDomNode = document.getElementById(this.targetId + "-content");
if (!targetDomNode) if (!targetDomNode)
throw new Error("unable to find node " + this.targetId + "-domNode"); throw new Error("unable to find node " + this.targetId + "-content");
return targetDomNode.widget; return targetDomNode.widget;
} }
}); });
@@ -925,9 +951,10 @@ dojo.declare("alfresco.xforms.XForm",
var alfUI = document.getElementById("alf-ui"); var alfUI = document.getElementById("alf-ui");
alfUI.style.width = "100%"; alfUI.style.width = "100%";
var root = new alfresco.xforms.Group(this, alfUI); this.rootWidget = new alfresco.xforms.Group(this, alfUI);
root.render(alfUI); this.rootWidget.render(alfUI);
this.loadWidgets(this.getBody(), root); this.loadWidgets(this.getBody(), this.rootWidget);
this.rootWidget._updateDisplay();
}, },
createWidget: function(node) createWidget: function(node)
{ {
@@ -960,7 +987,6 @@ dojo.declare("alfresco.xforms.XForm",
case "unsignedLong": case "unsignedLong":
case "unsignedShort": case "unsignedShort":
case "positiveInteger": case "positiveInteger":
return new alfresco.xforms.NumericStepper(this, node, type);
case "string": case "string":
default: default:
return new alfresco.xforms.TextField(this, node); return new alfresco.xforms.TextField(this, node);
@@ -1077,6 +1103,7 @@ dojo.declare("alfresco.xforms.XForm",
}, },
setXFormsValue: function(id, value) setXFormsValue: function(id, value)
{ {
value = value == null ? "" : value;
dojo.debug("setting value " + id + " = " + value); dojo.debug("setting value " + id + " = " + value);
var req = create_ajax_request(this, var req = create_ajax_request(this,
"setXFormsValue", "setXFormsValue",
@@ -1105,6 +1132,13 @@ dojo.declare("alfresco.xforms.XForm",
xfe.getTarget().handleIndexChanged(index); xfe.getTarget().handleIndexChanged(index);
break; break;
} }
case "chiba-state-changed":
{
var valid = xfe.properties["valid"] == "true";
xfe.getTarget().setValid(valid);
xfe.getTarget().setModified(true);
break;
}
case "chiba-prototype-cloned": case "chiba-prototype-cloned":
{ {
var prototypeId = xfe.properties["prototypeId"]; var prototypeId = xfe.properties["prototypeId"];
@@ -1152,8 +1186,30 @@ dojo.declare("alfresco.xforms.XForm",
document.submitWidget.currentButton = null; document.submitWidget.currentButton = null;
} }
break; break;
case "xforms-valid":
xfe.getTarget().setValid(true);
xfe.getTarget().setModified(true);
break;
case "xforms-invalid":
xfe.getTarget().setValid(false);
xfe.getTarget().setModified(true);
break;
case "xforms-required":
xfe.getTarget().setRequired(true);
break;
case "xforms-optional":
xfe.getTarget().setRequired(false);
break;
case "xforms-submit-error": case "xforms-submit-error":
_show_error("Please provide values for all required fields."); var invalid = this.rootWidget.getWidgetsInvalidForSubmit();
var msg = "Please provide values for all required fields.";
msg += "<br/><ul>";
for (var j = 0; j < invalid.length; j++)
{
msg += "<li>" + invalid[j].getLabel() + "</li>";
}
msg += "</ul>";
_show_error(msg);
break; break;
default: default:
{ {
@@ -1174,6 +1230,7 @@ function addSubmitHandlerToButton(b)
{ {
dojo.debug("not done, resubmitting"); dojo.debug("not done, resubmitting");
tinyMCE.triggerSave(); tinyMCE.triggerSave();
_hide_errors();
document.submitWidget.currentButton = this; document.submitWidget.currentButton = this;
document.submitWidget.widget.buttonClick(); document.submitWidget.widget.buttonClick();
return false; return false;
@@ -1247,7 +1304,7 @@ function _show_error(msg)
dojo.dom.prependChild(errorDiv, alfUI); dojo.dom.prependChild(errorDiv, alfUI);
} }
if (errorDiv.style.display == "block") if (errorDiv.style.display == "block")
errorDiv.innerHTML = errorDiv.innerHTML + "<br/>" + e.message; errorDiv.innerHTML = errorDiv.innerHTML + "<br/>" + msg;
else else
{ {
errorDiv.innerHTML = msg; errorDiv.innerHTML = msg;