-1; k--) if (radios[k].checked) radioButtonChecked = true;
if (!radioButtonChecked) radioExceptionApplies=true;
}
// toggle visibility
if (typeof obj.toggle != 'undefined') {
var visibleMet = (typeof obj.toggle.visible != 'undefined') ? validanguage.toggleCriteriaMet(this, obj.toggle.visible, settings) : false;
var hiddenMet = (typeof obj.toggle.hidden != 'undefined') ? validanguage.toggleCriteriaMet(this, obj.toggle.hidden, settings) : false;
for (var k = targets.length - 1; k > -1; k--) {
if (visibleMet && !radioExceptionApplies) validanguage.toggleDisplay(targets[k], '');
if (hiddenMet || (settings.toggleVisibilityDefaultsToHidden && !visibleMet)) validanguage.toggleDisplay(targets[k], 'none');
}
} // close toggle visibility
// value control
if (typeof obj.values != 'undefined') {
for (var k = targets.length - 1; k > -1; k--) {
if (typeof obj.values.checked != 'undefined' && this.checked==true) document.getElementById(targets[k]).value=obj.values.checked;
else if (typeof obj.values.unchecked != 'undefined' && this.checked==false) document.getElementById(targets[k]).value=obj.values.unchecked;
else if (typeof obj.values[this.value] != 'undefined') document.getElementById(targets[k]).value=obj.values[this.value];
}
} // close toggle value
// dynamic selects
if (typeof obj.dynamicSelect != 'undefined') {
var sel2 = document.getElementById(targets[0]); // dynamicSelect only supports 1 target
for (var sel1Key in obj.dynamicSelect) {
if (typeof obj.dynamicSelect[sel1Key] == 'object' ) {
var sel1Val = obj.dynamicSelect[sel1Key];
if (sel1Key == this.value) {
// remove the existing options
while (sel2.options.length > 0) { sel2.remove(0); }
for (var sel2Key in sel1Val) {
if (sel2Key == '_default') continue;
var opt = document.createElement('option');
opt.value = sel2Key;
opt.text = sel1Val[sel2Key];
sel2.options.add(opt);
}
if (typeof sel1Val['_default'] != 'undefined') sel2.value = sel1Val['_default'];
}
}
}
} // close dynamicSelect
}
},
/**
* Determines whether the criteria used by the toggle function
* has been met
* @param {Object} field
* @param {string} criteria
* @param {Object} settings object
*/
toggleCriteriaMet: function( field, criteria, settings ) {
if (criteria == 'checked') {
return !!(field.checked);
} else if (criteria == 'unchecked') {
return !(field.checked);
} else if (criteria == 'empty') {
return !!(validanguage.inArray(field.value, settings.emptyOptionElements));
} else if (criteria == 'notEmpty') {
return !(validanguage.inArray(field.value, settings.emptyOptionElements));
} else {
return !!(field.value == criteria);
}
},
/**
* Function used to hide or show a node. This function will also automatically disable or enable
* any form fields contained within the passed node.
* @param {Object} nodeId ID of the node to hide/show
* @param {Object} visibility (optional) Pass either 'none' or '' to hide/show. Or leave blank to toggle
*/
toggleDisplay: function( nodeId, visibility ) {
var node = document.getElementById(nodeId);
var nodeName = node.nodeName.toLowerCase();
if (visibility==null||visibility==undefined) visibility = (node.style.display=='none') ? '' : 'none';
disabledBool = (visibility=='none') ? true : false;
// show/hide the passed node
node.style.display = visibility;
// disable/enable any form fields contained within the node
if (nodeName == 'input' || nodeName == 'textarea' || nodeName == 'select') {
node.disabled = disabledBool;
return;
}
var allInputs = node.getElementsByTagName('input');
var allTextareas = node.getElementsByTagName('textarea');
var allSelect = node.getElementsByTagName('select');
var allObjects = this.concatCollection(allInputs, allTextareas);
var allObjects = this.concatCollection(allObjects, allSelect);
for (var i = allObjects.length - 1; i > -1; i--) {
allObjects[i].disabled = disabledBool;
}
},
/**
* Validates that a field does not contain any of the invalid characters
* listed in the characters validation rules.
*
* @param {string} text
*/
validateCharacters: function( text ) {
var id = this.id;
var mode = validanguage.el[id].characters.mode;
var expression = validanguage.el[id].characters.characterExpression;
switch(mode) {
case 'allow':
outerLoop:
for( var i=text.length-1;i>-1;i--) {
innerLoop:
for (var j=expression.length-1; j>-1; j--) {
if(expression.charAt(j)==text.charAt(i)) continue outerLoop;
}
//if we got here, they entered a disallowed character
return false;
}
break;
case 'deny':
outerLoop:
for( var i=text.length-1;i>-1;i--) {
innerLoop:
for (var j=expression.length-1; j>-1; j--) {
if(expression.charAt(j)==text.charAt(i)) return false;
}
}
break;
}
return true;
},
/**
* Validates that a valid credit card number has been supplied
* @param {string} text
* @param {array} cardTypes
* @param {boolean} testChecksum Pass false to skip the luhn checksum test
*/
validateCreditCard: function (text, cardTypes, testChecksum) {
if (validanguage.empty(cardTypes)) cardTypes = ['amex','disc','mc','visa'];
// Strip any non-digits
var text=text.replace(/\D/g,'');
var cards = {
'amex' : '^3[4|7]\\d{13}$',
'bankcard' : '^56(10\\d\\d|022[1-5])\\d{10}$',
'diners' : '^(?:3(0[0-5]|[68]\\d)\\d{11})|(?:5[1-5]\\d{14})$',
'disc' : '^(?:6011|650\\d)\\d{12}$',
'electron' : '^(?:417500|4917\\d{2}|4913\\d{2})\\d{10}$',
'enroute' : '^2(?:014|149)\\d{11}$',
'jcb' : '^(3\\d{4}|2100|1800)\\d{11}$',
'maestro' : '^(?:5020|6\\d{3})\\d{12}$',
'mc' : '^5[1-5]\\d{14}$',
'solo' : '^(6334[5-9][0-9]|6767[0-9]{2})\\d{10}(\\d{2,3})?$',
'switch' : '^(?:49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})\\d{10}(\\d{2,3})?)|(?:564182\\d{10}(\\d{2,3})?)|(6(3(33[0-4][0-9])|759[0-9]{2})\\d{10}(\\d{2,3})?)$',
'visa' : '^4\\d{12}(\\d{3})?$',
'voyager' : '^8699[0-9]{11}$'
};
var validCard = false;
for (var i = cardTypes.length; i--; i > -1) {
validCard = validanguage.validateRegex(text, { expression: cards[cardTypes[i]] });
if (validCard) break;
}
if (!validCard) return false;
if (testChecksum===false) return true;
/** Run the luhn checksum test
* Luhn algorithm number checker - (c) 2005-2008 shaman - www.planzero.org
*/
// Set the string length and parity
var number_length=text.length;
var parity=number_length % 2;
// Loop through each digit and do the maths
var total=0;
for (var i=0; i < number_length; i++) {
var digit=text.charAt(i);
// Multiply alternate digits by two
if (i % 2 == parity) {
digit=digit * 2;
// If the sum is two digits, add them together (in effect)
if (digit > 9) {
digit=digit - 9;
}
}
// Total up the digits
total = total + parseInt(digit);
}
// If the total mod 10 equals 0, the number is valid
if (total % 10 == 0) {
return true;
} else {
return false;
}
},
/**
* Validates that a valid date is supplied and is entered in the correct format.
* The format is specified by the following arguments
* @param {String} text to be validated
* @param {Object} Options object containing any of the following options
* dateOrder: {String} This must be either 'ymd','mdy','dmy','myd','ydm', or 'dym
* allowedDelimiters: {String}. A string containing the list of delimiters which are allowed.
* Example: './-'
* twoDigitYearsAllowed: {Boolean}. Is a 2-digit year valid
* oneDigitDaysAndMonthsAllowed: {Boolean}. Is a 1-digit month or a 1-digit day valid
* maxYear: {Integer}. Years greater than maxYear will be treated as invalid. Defaults to 15 years from today
* minYear: {Integer}. Years less than minYear will be treated as invalid. Defaults to 1900
* rejectDatesInTheFuture: {Boolean}. Are dates in the future valid? rejectDatesInTheFuture defaults to false
* rejectDatesInThePast: {Boolean}. Are dates in the past valid? rejectDatesInThePast defaults to false
*/
validateDate: function( text, options ) {
//Set default values
options = validanguage.getDateTimeDefaultOptions(options, {dateOrder: 'mdy'} );
//Loop thru the allowedDelimiters to start building our regex and figure out which one was actually used
var delimiterUsed;
var delimiterRegex = '(';
for( var i=options.allowedDelimiters.length-1;i>-1;i--) {
delimiterRegex += '\\' + options.allowedDelimiters.charAt(i);
if (i>0) delimiterRegex += '|';
if (text.indexOf(options.allowedDelimiters.charAt(i)) > -1) {
delimiterUsed = options.allowedDelimiters.charAt(i);
}
}
delimiterRegex += ')';
if( delimiterUsed==null ) return false; //no delimiter was used
var parts = text.split(delimiterUsed);
if( parts.length!=3 ) return false; //they used more than one delimiter or didnt give us a valid date
//Next we need to build the regex to validate the date comprises only integers and delimiters
var regex = '^';
for(var j=0; j<3; j++) {
switch( options.dateOrder.charAt(j) ) {
case 'y':
var num = (options.twoDigitYearsAllowed) ? '{2,4}' : '{4}';
regex += '\\d' + num;
break;
case 'm':
case 'd':
var num = (options.oneDigitDaysAndMonthsAllowed) ? '{1,2}' : '{2}';
regex += '\\d' + num;
break;
}
if(j<2) regex += delimiterRegex;
}
regex += '$';
//Run the regex
var reg = new RegExp( regex );
var thisMatch = reg.exec(text);
if (thisMatch == null) return false;
//grab our dates
var year = parts[options.dateOrder.indexOf('y')];
var month = parts[options.dateOrder.indexOf('m')];
var day = parts[options.dateOrder.indexOf('d')];
// Verify the year isnt 3-digits long to account for me being lazy in the regex check above
if( year.length==3 ) return false;
//Make sure the year is in bounds
if( (year < options.minYear && year.length==4) || (year > options.maxYear) ) return false;
//Next we check that the date actually exists, to rule out stuff like "12/32/1976"
if( !validanguage.validateDateExists(year,month,day) ) return false;
if( options.rejectDatesInTheFuture || options.rejectDatesInThePast ){
var now = new Date();
var then = new Date();
then.setDate(day);
then.setMonth(--month); // January = 0
then.setFullYear(year);
if( (options.rejectDatesInTheFuture && then > now) || (options.rejectDatesInThePast && then < now) ) return false;
}
return true;
},
/**
* Helper function to verify a date actually exists. Used to reject values
* such as "12/35/2009"
* @param {integer} year, preferably 4-digit
* @param {integer} month
* @param {integer} day
* @return {Boolean}
*/
validateDateExists: function(year, month, day) {
if(year.length==2) {
var prefix = (year > 20 ) ? '19' : '20';
year = prefix+year.toString();
}
if( month.charAt(0)=='0' ) month = month.substr(1,1);
if( day.charAt(0)=='0' ) day = day.substr(1,1);
if( month < 0 || month > 12 ) return false;
switch( month.toString() ) {
case '4':
case '6':
case '9':
case '11':
var maxDay = 30;
break;
case '2':
var maxDay = ((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0)) ) ? 29 : 28;
break;
default:
var maxDay = 31;
}
if( day < 0 || day > maxDay ) return false;
return true;
},
/**
* Validates an email address
*/
validateEmail: function( text ) {
if(! text.match(/^([a-zA-Z0-9]+[a-zA-Z0-9._%-]*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,4})$/) )
return false;
else return true;
},
/**
* Calls the validationWrapper function on the passed form ID
* @param {String or Form Node} Id of the form
* @return {Object} Object containing 2 elements:
* Object.result is a boolean to indicate whether any fields in the form failed validation
* Object.failedValidations will contain info detailing any form fields with failed validations
*/
validateForm: function( formId ) {
var form;
if( formId==undefined) form = document.forms[0];
else if (typeof formId=='string') form = document.getElementById(formId);
else form = formId;
return this.validationWrapper( form, 'validateForm' );
},
/**
* Validates that a field contains a valid IPv4 address
*/
validateIP: function( text ) {
var bytes = text.split('.');
if (bytes.length == 4) {
for (var i=bytes.length-1; i> -1; i--) {
if (!(validanguage.validateNumeric(bytes[i]) && bytes[i] >= 0 && bytes[i] <= 255)) {
return false;
}
}
return true;
}
return false;
},
/**
* Function to suppress the keys specified in validanguage.el.characters
* from being entered into a textarea or text box.
*
* This function must be forked to fetch the keyCode
* and differentiate between control and non-control characters.
* For example: in Mozilla both the delete key and . equate to 46.
* We dont fork based on supported functions because IE and Moz event models
* for keyCodes/charCodes are different and confusing, so we're
* better off sniffing the browser.
*
* @param {Event Object} e
*/
validateKeypress: function(e) {
var evt = e || window.evt; var $this = evt.currentTarget || evt.srcElement;
var id = $this.id;
var formName = validanguage.formLookup[id];
var settings = validanguage.getFormSettings(id);
if (validanguage.browser=='ie' || validanguage.browser=='opera' ) {
//branch for IE and opera
//we dont have to worry about noncontrol keys since they dont fire keypress events in IE
charCode = evt.keyCode;
if ( ( (charCode == 16) && (evt.shiftKey) ) || (evt.ctrlKey) ) return true; //prevents firing on ctrl key in opera
} else {
//branch for Mozilla
if ( (evt.charCode == 0) || (evt.ctrlKey) ) return true;
//return true for all control keys and if control is held down
charCode = evt.which; //capture charCode of non-control keys
}
charCode += ';';
searchString = new String(validanguage.el[id].characters.expression);
var mode = validanguage.el[id].characters.mode;
if ( ( (searchString.search(charCode) != -1 ) && (mode == 'allow') ) ||
( (searchString.search(charCode) == -1 ) && (mode == 'deny') ) ){
return true;
} else {
$this.style.backgroundColor = settings.validationErrorColor;
setTimeout("document.getElementById('" + id + "').style.backgroundColor = validanguage.forms['"+formName+"'].settings.normalTextboxColor",validanguage.forms[formName].settings.timeDelay);
evt.returnValue = false; //IE
if(evt.preventDefault) evt.preventDefault(); //Everyone else
return false;
}
},
/**
* Validates that a field is less than maxlength characters long
* @param {string} text
*/
validateMaxlength: function( text, max ) {
var id = this.id;
var maxlength = (validanguage.empty(max)) ? validanguage.el[id].maxlength : max;
if(text.length > maxlength)
return false;
else return true;
},
/**
* Validates that a field is greater than minlength characters long
* @param {string} text
*/
validateMinlength: function( text, min ) {
var id = this.id;
var minlength = (validanguage.empty(min)) ? validanguage.el[id].minlength : min;
if(text.length < minlength)
return false;
else return true;
},
/**
* Validates that a field is numeric
* @param {string} text
*/
validateNumeric: function( text ) {
if(! text.match(/^\d+$/) )
return false;
else return true;
},
/**
* Validates the element against a user-defined regex stored in
* validanguage.el[id].regex
*
* @param {string} text
* @param {object} optional object containing regex settings
*/
validateRegex: function( text, obj ) {
var id = this.id;
var regexObj = (validanguage.empty(obj)) ? validanguage.el[id].regex : obj;
if(typeof regexObj.modifiers=='undefined') regexObj.modifiers='';
if(typeof regexObj.errorOnMatch=='undefined') regexObj.errorOnMatch=false;
var myreg = (typeof regexObj.expression=='string') ? new RegExp(regexObj.expression) : regexObj.expression;
var thisMatch = myreg.exec(text, regexObj.modifiers);
if (thisMatch == null) { //no match
var returnStatus = (regexObj.errorOnMatch==false||regexObj.errorOnMatch=='false') ? false : true;
} else { //match
var returnStatus = (regexObj.errorOnMatch==false||regexObj.errorOnMatch=='false') ? true : false;
}
return returnStatus;
},
/***
* Validates whether or not an element has been filled out,
* selected or checked. This function is a wrapper which
* calls validateRequiredChild()
*
* @param {string} text
*/
validateRequired: function( unused ) {
var id = this.id;
if(typeof validanguage.el[id].requiredAlternatives == 'undefined') {
var alternatives = [ id ];
} else {
var alternatives = validanguage.resolveArray(validanguage.el[id].requiredAlternatives,'string');
alternatives[alternatives.length] = id;
}
for( var i=alternatives.length-1; i>-1; i--) {
id = alternatives[i];
var elem = document.getElementById(id);
var text = elem.value;
var notEmpty = validanguage.validateRequiredChild.call(elem, text);
if(notEmpty==true) return true; //if this element or one of its alternatives is not empty, it validates
}
return false;
},
/**
* This function calls the validateRequired method on the "master/required"
* form field when the "alternative" form field is clicked and then calls
* the appropriate onerorr/onsuccess function.
*/
validateRequiredAlternatives: function(e) {
var evt = e || window.evt;
var $this = evt.currentTarget || evt.srcElement;
var id = $this.id;
var parentId = validanguage.requiredAlternatives[id].parentId;
var onsuccess = validanguage.requiredAlternatives[id].onsuccess;
var onerror = validanguage.requiredAlternatives[id].onerror;
var parent = document.getElementById(parentId);
if (validanguage.validateRequired.call(parent) == true) {
successHandlers = validanguage.resolveArray(onsuccess, 'function');
for (var m = successHandlers.length - 1; m > -1; m--) {
successHandlers[m].call(parent);
}
} else {
errorHandlers = validanguage.resolveArray(onerror, 'function');
for (var m = errorHandlers.length - 1; m > -1; m--) {
errorHandlers[m].call(parent, validanguage.requiredAlternatives[id].errorMsg);
}
}
},
/***
* Child function called by validateRequired to validates whether or not an element has been filled out,
* selected or checked. validateRequiredChild is required to add support for the requiredAlternatives
* array.
*
* @param {string} text
*/
validateRequiredChild: function( text ) {
var type = ( typeof this.type != 'undefined' ) ? this.type : null;
if( this.nodeName.toLowerCase() == 'textarea' ) type = 'text';
if( this.nodeName.toLowerCase() == 'select' ) type = 'select';
switch( type ) {
case 'checkbox':
if( this.checked == false ){
return false;
}
break;
case 'radio':
var formId = validanguage.formLookup[this.id];
var radios = (typeof formId == 'number') ? document.forms[formId][this.name] : document.getElementById(formId)[this.name];
for( var i=radios.length-1; i>-1;i--) {
if (radios[i].checked == true) return true;
}
return false;
break;
case 'text':
case 'password':
case 'file':
if(validanguage.empty(text)) {
return false;
}
break;
case 'select':
if (validanguage.empty(text)) {
return false;
}
settings = validanguage.getFormSettings(this.id);
for( var i=settings.emptyOptionElements.length-1; i>-1; i-- ) {
//see if they have selected any of the "empty" option elements
if( text==settings.emptyOptionElements[i]) return false;
}
break;
} //close switch
return true;
},
/**
* Validates that the entered text is a valid timestamp. The options object supports all the options listed
* under the validateDate function as well as the following additional onces
* @param {String} text to be validated
* @param {Object} Options object containing any of the following options:
* timeIsRequired: {Boolean} Is a date which is provided without an accompanying time considered a valid timestamp?
* timeIsRequired defaults to false.
* timeUnits: {String} A string containing a list of all the time units which are allowed to be entered in the timestamp.
* These may include any of the following: h for hours, m for minutes, s for seconds, u for microseconds,
* and t for timezone. Example: "hms" for hours, minutes and seconds or "hmsut" for all 5 units.
* Defaults to "hms"
* microsecondPrecision {Integer} Indicates the supported number of decimal places for the microseconds. Defaults to 6.
*
*/
validateTimestamp: function( text, options ) {
// Set default options
options = validanguage.getDateTimeDefaultOptions(options, {dateOrder: 'ymd'} );
// Check the date portion of the timestamp
var pos = text.indexOf(' ');
var date = ( pos == -1 ) ? text : text.substr(0,pos);
if( !validanguage.validateDate(date, options) ) return false;
// Check whether they provided a time
if( pos != -1 ) {
var time = text.substring(++pos);
} else {
if( !options.timeIsRequired ) return true;
if( options.timeIsRequired ) return false;
}
// Build the regex to validate the time
var regex = '^\\d{1,2}:\\d{1,2}';
if( options.timeUnits.indexOf('s')!=-1 ) regex += '(:\\d{1,2}';
if( options.timeUnits.indexOf('u')!=-1 ) regex += '(\\.\\d{1,'+options.microsecondPrecision+'})?';
if( options.timeUnits.indexOf('s')!=-1 ) regex += ')?';
if( options.timeUnits.indexOf('t')!=-1 ) {
regex += '( ?[\\+|\\-]{1,1}(\\d|0\\d|10|11|12|13)(\\:(00|30))?)?';
}
regex += '$';
//Run the regex
var reg = new RegExp( regex );
var thisMatch = reg.exec(time);
if (thisMatch == null) return false;
//Finally we need to make sure that the hours, minutes and seconds which were entered are valid
var timeparts = time.split(':');
if( timeparts[0] > 23) return false;
if( timeparts[1] > 59) return false;
if( timeparts.length > 2){
var seconds = timeparts[2].substr(0,2);
if(seconds > 59) return false;
}
return true;
},
/**
* Validates a URL
*
* @param {string} text
*/
validateURL: function( text ) {
if(! text.match(/^((([hH][tT][tT][pP][sS]?|[fF][tT][pP])\:\/\/)?([\w\.\-]+(\:[\w\.\&%\$\-]+)*@)?((([^\s\(\)\<\>\\\"\.\[\]\,@;:]+)(\.[^\s\(\)\<\>\\\"\.\[\]\,@;:]+)*(\.[a-zA-Z]{2,4}))|((([01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}([01]?\d{1,2}|2[0-4]\d|25[0-5])))(\b\:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)\b)?((\/[^\/][\w\.\,\?\'\\\/\+&%\$#\=~_\-@]*)*[^\.\,\?\"\'\(\)\[\]!;<>{}\s\x7F-\xFF])?)$/) )
return false;
else return true;
},
/**
* DEPRECATED - Please use validateDate() instead as validateUSDate
* will be removed in the future. validateDate() defaults to MM/DD/YYYY
* when called without any additional arguments.
* @param {string} text
*/
validateUSDate: function( text ) {
return validanguage.validateDate(text);
},
/**
* Validates that a US Phone number is entered
*
* @param {string} text
*/
validateUSPhoneNumber: function( text ) {
if(! text.match(/^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$/) )
return false;
else return true;
},
/**
* Validates that a US Social Security Number is entered
*
* @param {string} text
*/
validateUSSSN: function( text ) {
if(! text.match(/^\d{3}( |-|.){0,1}\d{2}( |-|.){0,1}\d{4}$/) )
return false;
else return true;
},
/**
* Validates that a US zip code was entered
*
* @param {string} text
*/
validateUSZipCode: function( text ) {
if(! text.match(/^\d{5}( |-|.){0,1}(\d{4})?$/) )
return false;
else return true;
},
/**
* This is a wrapper for all the validation event handlers assigned to both
* form field element and to forms themselves. This function also calls any
* transformations before running the validations.
*
* We use a wrapper for a number of reasons, including exiting validation
* early as soon as a single validation function fails.
*
* @param {Event Object} e
* @param {String} Custom Event
* '
*/
validationWrapper: function(e, customEvent) {
if( customEvent=='typing') {
var $this = document.getElementById(e);
var type = 'typing';
var id = e;
} else if (customEvent=='validateForm') {
var $this = e;
var form = validanguage.whichFormAmI($this);
var type = 'submit';
} else {
var evt = e || window.evt;
var $this = evt.currentTarget || evt.srcElement;
var type = evt.type;
if (type == 'submit') {
var form = validanguage.whichFormAmI($this);
} else {
var id = $this.id;
}
if( customEvent=='typingTimeout') {
if( validanguage.typingDelay[id] ) window.clearTimeout(validanguage.typingDelay[id]);
eval("validanguage.typingDelay[id] = window.setTimeout(\"validanguage.validationWrapper('"+id+"', 'typing')\", validanguage.settings.typingDelay );");
return true;
}
}
// Bail out early if the parent form is marked as disabled
if( typeof validanguage.el[form] != 'undefined' && typeof validanguage.el[form].disabled != 'undefined' && validanguage.el[form].disabled == true ) return true;
var validations = (type=='submit') ? validanguage.forms[form].validations : validanguage.el[id].handlers[type];
var i=validations.length;
var failedValidations = {}; //key value pair of id => validation
if(type=='submit') {
outerLoop:
for(var j=0; j-1; m--) {
if( typeof failedValidations[id] != 'undefined' ) continue innerLoop; //this field already flunked
var result = funcs[m].call($this, $this.value);
if( result == false ) {
failedValidations[id] = validation; //defer onerror handlers till later
failedValidations[id].field = validanguage.el[id].field;
if(! validanguage.forms[form].settings.validateAllFieldsOnsubmit) break outerLoop;
} else {
//run the onsuccess handlers
var onsuccess = validanguage.getElSetting('onsuccess',id,validation);
successHandlers = validanguage.resolveArray(onsuccess, 'function');
for (var n=successHandlers.length-1; n>-1; n--) {
successHandlers[n].call($this);
}
}
}
} //close outerLoop
if( validanguage.empty(failedValidations) ) {
var submitStatus = true;
} else { //call all appropriate onerror handlers
for (var o in failedValidations) {
if( typeof failedValidations[o] == 'function' ) continue;
var id = o;
$this = document.getElementById(o);
validation = failedValidations[o];
var focusOnerror = validanguage.getElSetting('focusOnerror',id,validation);
var errorMsg = validanguage.getElSetting('errorMsg',id,validation);
var onerror = validanguage.getElSetting('onerror',id,validation);
errorHandlers = validanguage.resolveArray(onerror,'function');
for (var m=errorHandlers.length-1; m>-1; m--) {
errorHandlers[m].call($this, errorMsg);
}
var focusOnerror = validanguage.getElSetting('focusOnerror',id,validation);
if( focusOnerror==true ) $this.focus();
var showAlert = validanguage.getElSetting('showAlert',id,validation);
if( showAlert ) validanguage.safeAlert(errorMsg);
}
var submitStatus = false;
}
//Call onsubmit transformations
var transformation = ( typeof validanguage.el[form] != 'undefined' ) ? validanguage.el[form].transformations : [];
for (var n=transformation.length-1; n>-1; n--) {
transformations = validanguage.resolveArray(transformation[n].name,'function');
for (var o=transformations.length-1; o>-1; o--) {
var returnStatus = transformations[o].call(document.getElementById(form), submitStatus, failedValidations);
if(typeof returnStatus == 'boolean') submitStatus = returnStatus;
}
}
if( customEvent=='validateForm' ) {
return { result: submitStatus, failedValidations: failedValidations };
}
return submitStatus;
} else {
//Skip disabled fields
if( (typeof validanguage.el[id].disabled=='boolean' && validanguage.el[id].disabled==true)
|| (typeof $this.disabled!='undefined' && $this.disabled==true) ) {
return;
}
var transformations = validanguage.el[id].transformations;
var p = transformations.length;
for( var q=0; q-1; m--) {
transformation[m].call($this);
}
}
if( typeof validanguage.el[id].failed=='boolean' && validanguage.el[id].failed==true ) {
//Allow a user to manually flunk a field
result = false;
} else {
//see if the field is valid
var validationCounter;
outerLoop:
for(var j=0; j-1; m--) {
var result = funcs[m].call($this, $this.value);
if( result == false ) break outerLoop;
}
}
if(validationCounter == undefined) return true; //exit early if all validations have been removed
}
//handle the result
if( result == true ) {
var onsuccess = validanguage.getElSetting('onsuccess',id,validation);
successHandlers = validanguage.resolveArray(onsuccess,'function');
for (var m=successHandlers.length-1; m>-1; m--) {
successHandlers[m].call($this);
}
return true;
} else {
var focusOnerror = validanguage.getElSetting('focusOnerror',id,validation);
var errorMsg = validanguage.getElSetting('errorMsg',id,validation);
var onerror = validanguage.getElSetting('onerror',id,validation);
errorHandlers = validanguage.resolveArray(onerror,'function');
for (var m=errorHandlers.length-1; m>-1; m--) {
errorHandlers[m].call($this, errorMsg);
}
var focusOnerror = validanguage.getElSetting('focusOnerror',id,validation);
if( focusOnerror==true ) $this.focus();
var showAlert = validanguage.getElSetting('showAlert',id,validation);
if( showAlert ) validanguage.safeAlert(errorMsg);
return false;
}
}
},
/**
* This function returns the ID of a form, if it exists. Otherwise, it
* returns the form's index position in the document.forms array.
* By using this function, we need not require all forms to have
* distinct IDs.
*
* @param {DOM Node} Form Node
* @return {String} Form ID or Index position
*/
whichFormAmI: function ( obj ) {
if (typeof obj.id != 'undefined' && (!validanguage.empty(obj.id)) ) return obj.id;
var forms = document.forms;
for (var i=0, j=forms.length; i