/*--------------------------------------------------------------------------------------------*\ validation.js ------------- v2.2, May 2007 This script provides generic validation for any web form. For a discussion and example usage of this script, go to http://www.benjaminkeen.com/software/js_validation This script is written by Ben Keen with additional code contributed by Mihai Ionescu and Nathan Howard. It is free to distribute, to re-write - to do what ever you want with it. Before using it, please read the following disclaimer. THIS SOFTWARE IS PROVIDED ON AN "AS-IS" BASIS WITHOUT WARRANTY OF ANY KIND. BENJAMINKEEN.COM SPECIFICALLY DISCLAIMS ANY OTHER WARRANTY, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL BENJAMINKEEN.COM BE LIABLE FOR ANY CONSEQUENTIAL, INDIRECT, SPECIAL OR INCIDENTAL DAMAGES, EVEN IF BENJAMINKEEN.COM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH POTENTIAL LOSS OR DAMAGE. USER AGREES TO HOLD BENJAMINKEEN.COM HARMLESS FROM AND AGAINST ANY AND ALL CLAIMS, LOSSES, LIABILITIES AND EXPENSES. \*--------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------------*\ Function: validateFields() Purpose: generic form field validation. Parameters: form - the name of the form to validate rules - an array of the validation rules. Each rule is a string of the form: "[if:FIELDNAME=VALUE,]REQUIREMENT,fieldname[,fieldname2 [,fieldname3, date_flag]],error message" if:FIELDNAME=VALUE, This allows us to only validate a field only if a fieldname FIELDNAME has a value VALUE. This option allows for nesting; i.e. you can have multiple if clauses, separated by a comma. They will be examined in the order in which they appear in the line. Valid REQUIREMENT strings are: "required" - field must be filled in "digits_only" - field must contain digits only "is_alpha" - field must only contain alphanumeric characters (0-9, a-Z) "custom_alpha" - field must be of the custom format specified. fieldname: the name of the field fieldname2: a character or sequence of special characters. These characters are: L An uppercase Letter. V An uppercase Vowel. l A lowercase letter. v A lowercase vowel. D A letter (upper or lower). F A vowel (upper or lower). C An uppercase Consonant. x Any number, 0-9. c A lowercase consonant. X Any number, 1-9. E A consonant (upper or lower). "reg_exp" - field must match the supplied regular expression. fieldname: the name of the field fieldname2: the regular expression fieldname3: (optional) flags for the reg exp (like i for case insensitive "letters_only" - field must only contains letters (a-Z) "length=X" - field has to be X characters long "length=X-Y" - field has to be between X and Y (inclusive) characters long "length>X" - field has to be greater than X characters long "length>=X" - field has to be greater than or equal to X characters long "lengthX" - field must be a number greater than X "range>=X" - field must be a number greater than or equal to X "range= before > if (lengthRequirements.match(/length=/)) { comparison_rule = "equal"; rule_string = lengthRequirements.replace("length=", ""); } else if (lengthRequirements.match(/length>=/)) { comparison_rule = "greater_than_or_equal"; rule_string = lengthRequirements.replace("length>=", ""); } else if (lengthRequirements.match(/length>/)) { comparison_rule = "greater_than"; rule_string = lengthRequirements.replace("length>", ""); } else if (lengthRequirements.match(/length<=/)) { comparison_rule = "less_than_or_equal"; rule_string = lengthRequirements.replace("length<=", ""); } else if (lengthRequirements.match(/length= parseInt(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "greater_than": if (!(form[fieldName].value.length > parseInt(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "less_than_or_equal": if (!(form[fieldName].value.length <= parseInt(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "less_than": if (!(form[fieldName].value.length < parseInt(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "equal": var range_or_exact_number = rule_string.match(/[^_]+/); var fieldCount = range_or_exact_number[0].split("-"); // if the user supplied two length fields, make sure the field is within that range if (fieldCount.length == 2) { if (form[fieldName].value.length < fieldCount[0] || form[fieldName].value.length > fieldCount[1]) { alertMessage(form[fieldName], errorMessage); return false; } } // otherwise, check it's EXACTLY the size the user specified else { if (form[fieldName].value.length != fieldCount[0]) { alertMessage(form[fieldName], errorMessage); return false; } } break; } break; // this is also true if field is empty [should be same for digits_only] case "valid_email": if (form[fieldName].value && !isValidEmail(form[fieldName].value)) { alertMessage(form[fieldName], errorMessage); return false; } break; case "valid_date": // this is written for future extensibility of isValidDate function to allow // checking for dates BEFORE today, AFTER today, IS today and ANY day. var isLaterDate = false; if (date_flag == "later_date") isLaterDate = true; else if (date_flag == "any_date") isLaterDate = false; if (!isValidDate(form[fieldName].value, form[fieldName2].value, form[fieldName3].value, isLaterDate)) { alertMessage(form[fieldName], errorMessage); return false; } break; case "same_as": if (form[fieldName].value != form[fieldName2].value) { alertMessage(form[fieldName], errorMessage); return false; } break; case "range": comparison_rule = ""; rule_string = ""; // if-else order is important here: needs to check for >= before > if (rangeRequirements.match(/range=/)) { comparison_rule = "equal"; rule_string = rangeRequirements.replace("range=", ""); } else if (rangeRequirements.match(/range>=/)) { comparison_rule = "greater_than_or_equal"; rule_string = rangeRequirements.replace("range>=", ""); } else if (rangeRequirements.match(/range>/)) { comparison_rule = "greater_than"; rule_string = rangeRequirements.replace("range>", ""); } else if (rangeRequirements.match(/range<=/)) { comparison_rule = "less_than_or_equal"; rule_string = rangeRequirements.replace("range<=", ""); } else if (rangeRequirements.match(/range= Number(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "greater_than": if (!(form[fieldName].value > Number(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "less_than_or_equal": if (!(form[fieldName].value <= Number(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "less_than": if (!(form[fieldName].value < Number(rule_string))) { alertMessage(form[fieldName], errorMessage); return false; } break; case "equal": var rangeValues = rule_string.split("-"); // if the user supplied two length fields, make sure the field is within that range if ((form[fieldName].value < Number(rangeValues[0])) || (form[fieldName].value > Number(rangeValues[1]))) { alertMessage(form[fieldName], errorMessage); return false; } break; } break; case "function": custom_function = fieldName; return eval(custom_function + "()"); break; default: alert("Unknown requirement flag in validateFields(): " + requirement); return false; } } return true; } /*--------------------------------------------------------------------------------------------*\ Function: alertMessage() Purpose: simple helper function which alerts a message, then focuses on and highlights a particular field. \*--------------------------------------------------------------------------------------------*/ function alertMessage(obj, message) { var backgroundColor = "#F2F9FF"; alert(message); // if "obj" is an array: it's a radio button. Focus on the first element. if (obj.type == undefined) obj[0].focus(); else { obj.style.background = backgroundColor; obj.focus(); } return false; } /*--------------------------------------------------------------------------------------------*\ Function: isValidEmail Purpose: tests a string is a valid email \*--------------------------------------------------------------------------------------------*/ function isValidEmail(str) { // trim starting / ending whitespace str = str.replace(/^\s*/, ""); str = str.replace(/\s*$/, ""); var at="@" var dot="." var lat=str.indexOf(at) var lstr=str.length var ldot=str.indexOf(dot) if (str.indexOf(at)==-1) return false if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr) return false if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr) return false if (str.indexOf(at,(lat+1))!=-1) return false if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot) return false if (str.indexOf(dot,(lat+2))==-1) return false if (str.indexOf(" ")!=-1) return false return true; } // helper function to check to see if a string is empty function isEmpty(str) { return ((str == null) || (str.length == 0)); } /*--------------------------------------------------------------------------------------------*\ Function: isWhitespace() Purpose: Returns true if string parameter is empty or whitespace characters only. \*--------------------------------------------------------------------------------------------*/ function isWhitespace(s) { var i; // Is s empty? if (isEmpty(s)) return true; for (var i=0; i month || month > 12) return false; if (year < 0) return false; if (1 > day || day > daysInMonth[month-1]) return false; // if required, verify the incoming date is LATER than the current date. if (isLaterDate) { // get current date var today = new Date(); var currMonth = today.getMonth() + 1; // since returns 0-11 var currDay = today.getDate(); var currYear = today.getFullYear(); // zero-pad today's month & day if (String(currMonth).length == 1) currMonth = "0" + currMonth; if (String(currDay).length == 1) currDay = "0" + currDay; currDate = String(currYear) + String(currMonth) + String(currDay); // zero-pad incoming month & day if (String(month).length == 1) month = "0" + month; if (String(day).length == 1) day = "0" + day; incomingDate = String(year) + String(month) + String(day); if (Number(currDate) > Number(incomingDate)) return false; } return true; }