You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by "Andreas Andreou (JIRA)" <de...@tapestry.apache.org> on 2008/02/27 18:09:57 UTC
[jira] Resolved: (TAPESTRY-1246) Clientside validation patch
[ https://issues.apache.org/jira/browse/TAPESTRY-1246?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Andreas Andreou resolved TAPESTRY-1246.
---------------------------------------
Resolution: Won't Fix
Added the code to the wiki - https://issues.apache.org/jira/browse/TAPESTRY-1246
> Clientside validation patch
> ---------------------------
>
> Key: TAPESTRY-1246
> URL: https://issues.apache.org/jira/browse/TAPESTRY-1246
> Project: Tapestry
> Issue Type: Improvement
> Components: JavaScript
> Affects Versions: 4.1.2
> Environment: Any
> Reporter: Andrea Chiumenti
> Priority: Minor
> Fix For: 4.1.6
>
> Attachments: validation.js
>
>
> I've patched the client side validation script file so that an input field in exception status reports its related exceptions with a dojo tooltip.
> When the validation is performed a second time all the exception tooltip widgets are disposed and recreated as necessary.
> I hope you find it useful.
> Ciao,
> kiuma
> vlidation.js
> ===============================================================================================
> dojo.provide("tapestry.form.validation");
> dojo.require("dojo.validate.check");
> dojo.require("dojo.html.style");
> dojo.require("dojo.widget.*");
> dojo.require("tapestry.widget.AlertDialog");
> dojo.require("dojo.widget.Tooltip");
> dojo.require("dojo.collections.ArrayList");
> tapestry.form.validation={
> //exceptionWidgets: [], //new dojo.collections.ArrayList(),
> missingClass:"fieldMissing", // default css class that will be applied to fields missing a value
> invalidClass:"fieldInvalid", // default css class applied to fields with invalid data
>
> dialogName:"tapestry:AlertDialog",
>
> /**
> * Main entry point for running form validation. The
> * props object passed in contains a number of fields that
> * are managed by tapestry.form:
> *
> * props = {
> * validateForm:[true|false] // whether to run validation at all
> * profiles:[profile1, profile2] // set of dojo.validate.check() style profiles
> * // that may have been registered with form
> * }
> *
> * The individual profiles will contain any of the data described by the dojo documentation
> * for dojo.validate.check(). In addition to that, each profile will also have a corresponding
> * string message to display if the specified condition has been met. For example, if you have
> * specified that a select field named "select1" was required your profile would look something
> * like:
> *
> * profile = {
> * "required":["select1"], // normal dojo.validate.check data
> * "select1":{ // tapestry field/error type specific data
> * "required":"You must select a value for select1."
> * }
> * }
> *
> * It is intended for you to call dojo.validate.check(form, profile) for each profile
> * stored in the "profiles" field, as well as deciding how to display errors / warnings.
> *
> * @return Boolean indicating if form submission should continue. If false the form
> * will ~not~ be submitted.
> */
> validateForm:function(form, props){
> if (typeof form == "undefined") {return false;}
> if (typeof props == "undefined") {return true;} // form exists but no profile? just submit I guess..
> if (!props.validateForm) {return true;}
>
> try {
> this.clearValidationDecorations(form, props);
> for (var i=0; i < props.profiles.length; i++) {
> this._clearExceptionWidgets(props.profiles[i]);
> var results=dojo.validate.check(form, props.profiles[i]);
> if (!this.processResults(form, results, props.profiles[i])) {
> this.summarizeErrors(form, results, props.profiles[i]);
> return false;
> }
> }
> } catch (e) {
> // since so many dynamic function calls may happen in here it's best that we
> // catch all of them and log them or else peoples forms might still get submitted
> // and they'd never be able to figure out what was wrong
> dojo.log.exception("Error validating", e, true);
> return false;
> }
>
> return true;
> },
>
> /**
> * Called for each registered profile on a form after
> * dojo.validate.check() has been called. This function is
> * expected to do UI related notifications of fields in error.
> *
> * @param form The form that was validated.
> * @param results The result of calling dojo.validate.check(form,profile)
> * @param profile The original profile used to validate form, also holds
> * validation error messages to be used for each field.
> *
> * @return Boolean, if false form should not be submitted and all validation
> * should be stopped. If true validation will continue and eventually
> * form will be submitted.
> */
> processResults:function(form, results, profile){
> if (results.isSuccessful()) { return true; }
>
> var formValid=true;
> if (results.hasMissing()) {
> var missing=results.getMissing();
> for (var i=0; i < missing.length; i++) {
> this.handleMissingField(missing[i], profile);
> }
>
> formValid=false;
> }
>
> if (results.hasInvalid()) {
> var invalid=results.getInvalid();
> for (var i=0; i < invalid.length; i++) {
> this.handleInvalidField(invalid[i], profile);
> }
>
> formValid=false;
> }
>
> return formValid; // if got past successful everything is invalid
> },
>
> /**
> * Default field decorator for missing fields.
> *
> * @param field The field element that was missing data.
> * @param profile The form validation profile.
> */
> handleMissingField:function(field, profile){
> field=dojo.byId(field);
> if (dj_undef("type", field)) {return;}
> dojo.html.removeClass(field, this.invalidClass);
>
> if (!dojo.html.hasClass(field, this.missingClass)){
> dojo.html.prependClass(field, this.missingClass);
> }
> },
>
> /**
> * Default field decorator for invalid fields.
> *
> * @param field The field element that had invalid data.
> * @param profile The form validation profile.
> */
> handleInvalidField:function(field, profile){
> field=dojo.byId(field);
> if (dj_undef("type", field)) {return;}
> dojo.html.removeClass(field, this.missingClass);
>
> if (!dojo.html.hasClass(field, this.invalidClass)){
> dojo.html.prependClass(field, this.invalidClass);
> }
> },
>
> /**
> * Clears out previous css classes set on fields
> * in error.
> */
> clearValidationDecorations:function(form, props){
> for (var i=0; i< form.elements.length; i++) {
> if (dj_undef("type", form.elements[i]) || typeof form.elements[i].type == "undefined"
> || form.elements[i].type == "submit"
> || form.elements[i].type == "hidden") { continue; }
>
> dojo.html.removeClass(form.elements[i], this.missingClass);
> dojo.html.removeClass(form.elements[i], this.invalidClass);
> }
> },
>
> /**
> * Optionally allows an alert dialog/dhtml dialog/etc to
> * be displayed to user to alert them to the invalid state
> * of their form if validation errors have occurred.
> *
> * @param form The form being validated.
> * @param results Returned value of dojo.validate.check(form, profile)
> * @param profile Validation profile definition
> */
> summarizeErrors:function(form, results, profile){
> var merrs=[];
> var ierrs=[];
> var fieldErrs=[];
>
> tapestry.form.currentFocus=null;
> //this._clearExceptionWidgets();
> if (results.hasMissing()){
> var fields=results.getMissing();
> for (var i=0; i<fields.length; i++){
> fieldErrs=[];
> if(i==0 && !tapestry.form.currentFocus){
> tapestry.form.currentFocus=fields[i];
> }
>
> if (profile[fields[i]] && profile[fields[i]]["required"]){
> if (dojo.lang.isArray(profile[fields[i]]["required"])) {
> for (var z=0; z < profile[fields[i]]["required"].length; z++) {
> merrs.push(profile[fields[i]]["required"][z]);
> fieldErrs.push(profile[fields[i]]["required"][z]);
> }
> } else {
> merrs.push(profile[fields[i]]["required"]);
> fieldErrs.push(profile[fields[i]]["required"]);
> }
> //alert(fields[i]);
> this._buildExceptionTooltipWidget(profile, fields[i], fieldErrs, null);
> }
> }
> }
> if (results.hasInvalid()){
> var fields=results.getInvalid();
> for (var i=0; i<fields.length; i++){
> fieldErrs=[];
> if(i==0 && !tapestry.form.currentFocus){
> tapestry.form.currentFocus=fields[i];
> }
> if (profile[fields[i]] && profile[fields[i]]["constraints"]){
> if (dojo.lang.isArray(profile[fields[i]]["constraints"])) {
> for (var z=0; z < profile[fields[i]]["constraints"].length; z++) {
> ierrs.push(profile[fields[i]]["constraints"][z]);
> fieldErrs.push(profile[fields[i]]["constraints"][z]);
> }
> } else {
> ierrs.push(profile[fields[i]]["constraints"]);
> fieldErrs.push(profile[fields[i]]["constraints"]);
> }
> //alert(fields[i]);
> this._buildExceptionTooltipWidget(profile, fields[i], null, fieldErrs);
> }
> }
> }
>
> var msg="";
> if (merrs.length > 0) {
> msg+='<ul class="missingList">';
> for (var i=0; i<merrs.length;i++) {
> msg+="<li>"+merrs[i]+"</li>";
> }
> msg+="</ul>";
> }
> if (ierrs.length > 0) {
> msg+='<ul class="invalidList">';
> for (var i=0; i<ierrs.length;i++) {
> msg+="<li>"+ierrs[i]+"</li>";
> }
> msg+="</ul>";
> }
>
> var ad=dojo.widget.byId("validationDialog");
> if (ad) {
> ad.setMessage(msg);
> ad.show();
> return;
> }
>
> var node=document.createElement("span");
> document.body.appendChild(node);
> var dialog=dojo.widget.createWidget(this.dialogName,
> {
> widgetId:"validationDialog",
> message:msg
> }, node);
> dialog.show();
> },
>
> /**
> * Clears all exception tooltip widgets
> *
> */
> _clearExceptionWidgets: function(profile) {
> if (!profile.exceptionWidgets) {
> profile.exceptionWidgets = new dojo.collections.ArrayList();
> }
> var iter = profile.exceptionWidgets.getIterator();
>
> while (widget = iter.get()) {
> try {
> widget.destroy()
> } catch (e) {
> dojo.log.exception("Error destroying widget.", e, true);
> }
>
> }
> profile.exceptionWidgets.clear();
> },
> /**
> * Creates the field exception tooltip if necessary.
> *
> * @param fieldId The id of the field that has to expose an exception tooltip
> * @return Returns The exception tooltip dom element.
> */
> _createExceptionTooltip: function(fieldId) {
>
> var id = fieldId + "-err";
>
> var el = dojo.byId(id);
> if (!el) {
> el = document.createElement("div");
> el.id=id;
> el.className="exceptionTooltip";
> dojo.dom.insertBefore(el, dojo.byId(fieldId));
> }
> el.innerHTML = "";
> return el;
> },
> /**
> * Fills the content of the exception tooltip with exception messages
> * if messages is not empty
> *
> * @param exceptions The exception message array
> * @param listType May be 'missingList' or 'invalidList', default is 'missingList'.
> *
> * @return Returns the innerHTML that needs to be added to the tooltip dom element
> */
> _buildExceptionTooltip: function(exceptions, listType) {
> var msg ="";
>
> if ((exceptions)&&(exceptions.length > 0)) {
> if (!listType) {
> listType = "missingList";
> }
> msg+='<ul class="'+listType+'">';
> for (var i=0; i<exceptions.length;i++) {
> msg+="<li>"+exceptions[i]+"</li>";
> }
> msg+="</ul>";
> }
> return msg;
> },
> /**
> * Creates a tooltip exception widget.
> *
> * @param fieldId. The id of the field in exception status.
> * @param missingListExceptions The array containing missing value exception messages
> * @param invalidListExceptions The array containing invalid value exception messages
> */
> _buildExceptionTooltipWidget: function(profile, fieldId, missingListExceptions, invalidListExceptions) {
> if (!profile.exceptionWidgets) {
> profile.exceptionWidgets = new dojo.collections.ArrayList();
> }
> var tooltipEl = this._createExceptionTooltip(fieldId);
> tooltipEl.innerHTML = this._buildExceptionTooltip(missingListExceptions, "missingList");
> tooltipEl.innerHTML += this._buildExceptionTooltip(invalidListExceptions, "invalidList");
> var widget = dojo.widget.createWidget("Tooltip", {id:fieldId + "-tip", connectId:fieldId, toggle:"explode"}, tooltipEl);
> profile.exceptionWidgets.add(widget);
> },
> /**
> * Validates that the input value matches the given
> * regexp pattern.
> *
> * @param value The string value to be evaluated.
> * @param pattern The regexp pattern used to match against value.
> */
> isValidPattern:function(value, pattern){
> if (typeof value != "string" || typeof pattern != "string") { return false; }
>
> var re = new RegExp(pattern);
> return re.test(value);
> },
>
> isPalleteSelected:function(elem){
> if (elem.length > 0) { return true; }
> return false;
> }
> }
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org