From 12dee5d75e2a32e41a41d4f500593236d31900ea Mon Sep 17 00:00:00 2001 From: Ariel Backenroth Date: Thu, 18 Jan 2007 17:05:40 +0000 Subject: [PATCH] making alerts (required error messages) more accurate for repeats. implementing setValue calls consistently adding some debugging in the XFormsBean to dump out all invalid model items. i don't know how to map this to xforms contros - if i did - then alert indicators in the ui would be much more accurate. i'll post to the chiba lists today and see if there are any suggestions out there. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4881 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../alfresco/web/forms/xforms/XFormsBean.java | 49 +++++-- .../web/forms/xforms/XFormsProcessor.java | 6 +- source/web/scripts/ajax/xforms.js | 132 +++++++++++++++--- 3 files changed, 156 insertions(+), 31 deletions(-) diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java index a77b068539..23e576b461 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java @@ -67,6 +67,7 @@ import org.chiba.xml.xforms.core.Instance; import org.chiba.xml.xforms.core.ModelItem; import org.chiba.xml.xforms.core.Model; import org.chiba.xml.xforms.core.UpdateHandler; +import org.chiba.xml.xforms.core.impl.DefaultValidatorMode; import org.chiba.xml.xforms.exception.XFormsException; import org.chiba.xml.xforms.ui.RepeatItem; import org.chiba.xml.xforms.ui.Upload; @@ -92,7 +93,7 @@ public class XFormsBean /** */ - static class XFormsSession implements FormProcessor.Session + class XFormsSession implements FormProcessor.Session { private final Document formInstanceData; @@ -221,6 +222,11 @@ public class XFormsBean et.addEventListener(ChibaEventNames.LOAD_URI, el, true); et.addEventListener(ChibaEventNames.RENDER_MESSAGE, el, true); et.addEventListener(ChibaEventNames.REPLACE_ALL, el, true); + et.addEventListener(XFormsEventNames.REQUIRED, el, true); + et.addEventListener(XFormsEventNames.OPTIONAL, el, true); + et.addEventListener(XFormsEventNames.VALID, el, true); + et.addEventListener(XFormsEventNames.INVALID, el, true); + et.addEventListener(XFormsEventNames.OUT_OF_RANGE, el, true); chibaBean.init(); @@ -228,11 +234,6 @@ public class XFormsBean et.addEventListener(XFormsEventNames.SUBMIT, el, true); et.addEventListener(XFormsEventNames.SUBMIT_DONE, el, true); et.addEventListener(XFormsEventNames.SUBMIT_ERROR, el, true); - et.addEventListener(XFormsEventNames.REQUIRED, el, true); - et.addEventListener(XFormsEventNames.OPTIONAL, el, true); - et.addEventListener(XFormsEventNames.VALID, el, true); - et.addEventListener(XFormsEventNames.INVALID, el, true); - et.addEventListener(XFormsEventNames.OUT_OF_RANGE, el, true); et.addEventListener(ChibaEventNames.STATE_CHANGED, el, true); et.addEventListener(ChibaEventNames.PROTOTYPE_CLONED, el, true); et.addEventListener(ChibaEventNames.ID_GENERATED, el, true); @@ -247,8 +248,8 @@ public class XFormsBean * Initializes the chiba process with the xform and registers any necessary * event listeners. */ - public static XFormsSession createSession(final Document formInstanceData, - final Form form) + public XFormsSession createSession(final Document formInstanceData, + final Form form) { if (LOGGER.isDebugEnabled()) { @@ -265,7 +266,7 @@ public class XFormsBean request.getServerName() + ':' + request.getServerPort() + request.getContextPath()); - return new XFormsSession(formInstanceData, form, baseUrl); + return this.new XFormsSession(formInstanceData, form, baseUrl); } /** @@ -672,6 +673,7 @@ public class XFormsBean { LOGGER.debug("adding event " + type + " to the event log"); } + final Element target = (Element)xfe.getTarget(); final Element eventElement = result.createElement(type); @@ -698,6 +700,35 @@ public class XFormsBean value != null ? value.toString() : null); } } + + if (LOGGER.isDebugEnabled() && XFormsEventNames.SUBMIT_ERROR.equals(type)) + { + // debug for figuring out which elements aren't valid for submit + LOGGER.debug("performing full revalidate"); + try + { + final Model model = this.xformsSession.chibaBean.getContainer().getDefaultModel(); + final Instance instance = model.getDefaultInstance(); + model.getValidator().validate(instance, "/", new DefaultValidatorMode()); + final Iterator it = instance.iterateModelItems("/"); + while (it.hasNext()) + { + final ModelItem modelItem = it.next(); + if (!modelItem.isValid()) + { + LOGGER.debug("model node " + modelItem.getNode() + " is invalid"); + } + if (modelItem.isRequired() && modelItem.getValue().length() == 0) + { + LOGGER.debug("model node " + modelItem.getNode() + " is empty and required"); + } + } + } + catch (final XFormsException xfe2) + { + LOGGER.debug("error performing revaliation", xfe2); + } + } } this.xformsSession.eventLog.clear(); diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java index 11a51dd846..4a790eeb81 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java @@ -68,8 +68,12 @@ public class XFormsProcessor final Writer out) throws FormProcessor.ProcessingException { + final FacesContext fc = FacesContext.getCurrentInstance(); + //make the XFormsBean available for this session + final XFormsBean xforms = (XFormsBean) + FacesHelper.getManagedBean(fc, "XFormsBean"); final Session result = - XFormsBean.createSession(instanceDataDocument, form); + xforms.createSession(instanceDataDocument, form); this.process(result, out); return result; } diff --git a/source/web/scripts/ajax/xforms.js b/source/web/scripts/ajax/xforms.js index 6e31ce29d5..8e106f4f7c 100644 --- a/source/web/scripts/ajax/xforms.js +++ b/source/web/scripts/ajax/xforms.js @@ -160,16 +160,26 @@ dojo.declare("alfresco.xforms.Widget", { if (!this._valid) { + dojo.debug(this.id + " is invalid"); return false; } - if (!this._modified && this.isRequired() && this.getInitialValue() == null) + if (!this._modified && + this.isRequired() && + this.getInitialValue() == null) { + dojo.debug(this.id + " is unmodified and required and empty"); return false; } if (this.isRequired() && this.getValue() == null) { + dojo.debug(this.id + " is required and empty"); return false; } + dojo.debug(this.id + " is valid: {" + + "modified: " + this._modified + + ", required: " + this.isRequired() + + ", initial_value: " + this.getInitialValue() + + ", value: " + this.getValue() + "}"); return true; }, @@ -206,7 +216,7 @@ dojo.declare("alfresco.xforms.Widget", return this._required; } var binding = this.xform.getBinding(this.xformsNode); - return binding && binding.required == "true()"; + return binding && binding.isRequired(); }, /** Sets the widget's readonly state, as indicated by an XFormsEvent */ @@ -223,13 +233,14 @@ dojo.declare("alfresco.xforms.Widget", return this._readonly; } var binding = this.xform.getBinding(this.xformsNode); - return binding && binding.readonly == "true()"; + return binding && binding.isReadonly(); }, /** Sets the widget's initial value. */ setInitialValue: function(value) { - this.initialValue = value; + this.initialValue = + (typeof value == "string" && value.length == 0 ? null : value); }, /** @@ -258,6 +269,10 @@ dojo.declare("alfresco.xforms.Widget", result = (result.nodeType == dojo.dom.ELEMENT_NODE ? dojo.dom.textContent(result) : result.nodeValue); + if (typeof result == "string" && result.length == 0) + { + result = null; + } dojo.debug("resolved xpath " + xpath + " to " + result); return result; }, @@ -466,7 +481,10 @@ dojo.declare("alfresco.xforms.FilePicker", _filePicker_resizeHandler: function(fpw) { var w = fpw.node.widget; - w.domContainer.style.height = fpw.node.offsetHeight + "px"; + w.domContainer.style.height = + Math.max(fpw.node.offsetHeight + + dojo.style.getMarginHeight(w.domNode.parentNode), + 20) + "px"; } }); @@ -521,7 +539,8 @@ dojo.declare("alfresco.xforms.DatePicker", } else { - throw new Error("setValue unimplemented for DatePicker"); + this.widget.setAttribute("value", value); + this.widget.picker.setDate(value); } }, @@ -541,7 +560,9 @@ dojo.declare("alfresco.xforms.DatePicker", dojo.style.hide(this.widget); this.widget.picker.show(); this.domContainer.style.height = - this.widget.picker.domNode.offsetHeight + "px"; + Math.max(this.widget.picker.domNode.offsetHeight + + dojo.style.getMarginHeight(this.domNode.parentNode), + 20) + "px"; }, _datePicker_setDateHandler: function(event) @@ -549,7 +570,9 @@ dojo.declare("alfresco.xforms.DatePicker", this.widget.picker.hide(); dojo.style.show(this.widget); this.domContainer.style.height = - Math.max(this.widget.offsetHeight, 20) + "px"; + Math.max(this.domNode.parentNode.offsetHeight + + dojo.style.getMarginHeight(this.domNode.parentNode), + 20) + "px"; this.widget.value = dojo.widget.DatePicker.util.toRfcDate(this.widget.picker.date); this.xform.setXFormsValue(this.id, this.getValue()); } @@ -895,13 +918,35 @@ dojo.declare("alfresco.xforms.Select", } else { - throw new Error("setValue unimplemented for Select"); + this._selectedValues = value.split(' '); + if (this.widget.nodeName == "div") + { + var checkboxes = this.widgets.getElementsByTagName("input"); + for (var i = 0; i < checkboxes.length; i++) + { + checkboxes[i].checked = + this._selectedValues.indexOf(checkboxes[i].getAttribute("value")) != -1; + } + } + else if (this.widget.nodeName == "select") + { + var options = this.widgets.getElementsByTagName("option"); + for (var i = 0; i < options.length; i++) + { + options[i].selected = + this._selectedValues.indexOf(options[i].getAttribute("value")) != -1; + } + } + else + { + throw new Error("unexpected nodeName for Select widget: " + this.widget.nodeName); + } } }, getValue: function() { - return this._selectedValues.join(" "); + return this._selectedValues.length == 0 ? null : this._selectedValues.join(" "); }, ///////////////////////////////////////////////////////////////// @@ -928,7 +973,9 @@ dojo.declare("alfresco.xforms.Select", { var checkbox = document.getElementById(this.id + "_" + i + "-widget"); if (checkbox && checkbox.checked) + { this._selectedValues.push(checkbox.value); + } } this.xform.setXFormsValue(this.id, this._selectedValues.join(" ")); } @@ -1019,7 +1066,27 @@ dojo.declare("alfresco.xforms.Select1", } else { - throw new Error("setValue unimplemented for Select1"); + this._selectedValue = value; + if (this.widget.nodeName == "div") + { + var radios = this.widget.getElementsByTagName("input"); + for (var i = 0; i < radios.length; i++) + { + radios[i].checked = radios[i].getAttribute("value") == this._selectedValue; + } + } + else if (this.widget.nodeName == "select") + { + var options = this.widget.getElementsByTagName("option"); + for (var i = 0; i < options.length; i++) + { + options[i].selected = options[i].getAttribute("value") == this._selectedValue; + } + } + else + { + throw new Error("unexpected nodeName for Select1 widget: " + this.widget.nodeName); + } } }, @@ -2139,15 +2206,24 @@ dojo.declare("alfresco.xforms.Binding", { this.xformsNode = xformsNode; this.id = this.xformsNode.getAttribute("id"); - this.readonly = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":readonly"); - this.required = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":required"); this.nodeset = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":nodeset"); - this._type = (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":type") - ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":type") - : null); - this.constraint = (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") - ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") - : null); + this._readonly = + (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":readonly") + ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":readonly") == "true()" + : null); + this._required = + (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":required") + ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":required") == "true()" + : null); + + this._type = + (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":type") + ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":type") + : null); + this.constraint = + (_hasAttribute(this.xformsNode, alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") + ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") + : null); this.maximum = parseInt(this.xformsNode.getAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":maximum")); this.minimum = parseInt(this.xformsNode.getAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":minimum")); this.parent = parent; @@ -2162,12 +2238,26 @@ dojo.declare("alfresco.xforms.Binding", : (this.parent != null ? this.parent.getType() : null)); }, + /** Returns true if a node bound by this binding has a readonly value */ + isReadonly: function() + { + return (this._readonly != null ? this._readonly : + (this.parent != null ? this.parent.isReadonly() : false)); + }, + + /** Returns true if a node bound by this binding has a required value */ + isRequired: function() + { + return (this._required != null ? this._required : + (this.parent != null ? this.parent.isRequired() : false)); + }, + toString: function() { return ("{id: " + this.id + ",type: " + this.getType() + - ",required: " + this.required + - ",readonly: " + this.readonly + + ",required: " + this.isRequired() + + ",readonly: " + this.isReadonly() + ",nodeset: " + this.nodeset + "}"); } });