Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for 
change notification.

The following page has been changed by AndreasAndreou:
http://wiki.apache.org/tapestry/DojoTooltipsForClientValidation

New page:
Andrea Chiumenti has 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.

Here's the code for validation.js (copied from 
https://issues.apache.org/jira/browse/TAPESTRY-1246)

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

}}}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to