// VARIABLE DECLARATIONS var digits = "0123456789"; var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz" var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // whitespace characters var whitespace = " \t\n\r"; // non-digit characters which are allowed in phone numbers var phoneNumberDelimiters = "()- "; // characters which are allowed in US phone numbers var validUSPhoneChars = digits + phoneNumberDelimiters; // U.S. phone numbers have 10 digits. // They are formatted as 123 456 7890 or (123) 456-7890. var digitsInUSPhoneNumber = 10; // CONSTANT STRING DECLARATIONS // (grouped for ease of translation and localization) // m is an abbreviation for "missing" var mPrefix = "You did not enter a value into the " var mSuffix = " field.\n\nThis is a required field.\n\nPlease enter it now." // s is an abbreviation for "string" var sUSFirstName = "First Name" var sPhone = "Phone Number" var sEmail = "Email" // i is an abbreviation for "invalid" var iUSPhone = "This field must be a 10 digit U.S. phone number (like 415 555 1212).\n\nPlease reenter it now." var iEmail = "This field must be a valid email address (like foo@bar.com).\n\nPlease reenter it now." // p is an abbreviation for "prompt" var pEntryPrompt = "Please enter a " var pUSPhone = "10 digit U.S. phone number (like 415 555 1212)." var pEmail = "valid email address (like foo@bar.com)." // Global variable defaultEmptyOK defines default return value // for many functions when they are passed the empty string. // By default, they will return defaultEmptyOK. // // defaultEmptyOK is false, which means that by default, // these functions will do "strict" validation. Function // isInteger, for example, will only return true if it is // passed a string containing an integer; if it is passed // the empty string, it will return false. // // You can change this default behavior globally (for all // functions which use defaultEmptyOK) by changing the value // of defaultEmptyOK. // // Most of these functions have an optional argument emptyOK // which allows you to override the default behavior for // the duration of a function call. // // This functionality is useful because it is possible to // say "if the user puts anything in this field, it must // be an integer (or a phone number, or a string, etc.), // but it's OK to leave the field empty too." // This is the case for fields which are optional but which // must have a certain kind of content if filled in. var defaultEmptyOK = false // Check whether string s is empty. function isEmpty(s) { return ((s == null) || (s.length == 0)) } // Returns true if string s is empty or // whitespace characters only. function isWhitespace (s) { var i; // Is s empty? if (isEmpty(s)) return true; // Search through string's characters one by one // until we find a non-whitespace character. // When we do, return false; if we don't, return true. for (i = 0; i < s.length; i++) { // Check that current character isn't whitespace. var c = s.charAt(i); if (whitespace.indexOf(c) == -1) return false; } // All characters are whitespace. return true; } // Removes all characters which appear in string bag from string s. function stripCharsInBag (s, bag) { var i; var returnString = ""; // Search through string's characters one by one. // If character is not in bag, append to returnString. for (i = 0; i < s.length; i++) { // Check that current character isn't whitespace. var c = s.charAt(i); if (bag.indexOf(c) == -1) returnString += c; } return returnString; } // Removes all characters which do NOT appear in string bag // from string s. function stripCharsNotInBag (s, bag) { var i; var returnString = ""; // Search through string's characters one by one. // If character is in bag, append to returnString. for (i = 0; i < s.length; i++) { // Check that current character isn't whitespace. var c = s.charAt(i); if (bag.indexOf(c) != -1) returnString += c; } return returnString; } // Removes all whitespace characters from s. // Global variable whitespace (see above) // defines which characters are considered whitespace. function stripWhitespace (s) { return stripCharsInBag (s, whitespace) } // WORKAROUND FUNCTION FOR NAVIGATOR 2.0.2 COMPATIBILITY. // // The below function *should* be unnecessary. In general, // avoid using it. Use the standard method indexOf instead. // // However, because of an apparent bug in indexOf on // Navigator 2.0.2, the below loop does not work as the // body of stripInitialWhitespace: // // while ((i < s.length) && (whitespace.indexOf(s.charAt(i)) != -1)) // i++; // // ... so we provide this workaround function charInString // instead. // // charInString (CHARACTER c, STRING s) // // Returns true if single character c (actually a string) // is contained within string s. function charInString (c, s) { for (i = 0; i < s.length; i++) { if (s.charAt(i) == c) return true; } return false } // Removes initial (leading) whitespace characters from s. // Global variable whitespace (see above) // defines which characters are considered whitespace. function stripInitialWhitespace (s) { var i = 0; while ((i < s.length) && charInString (s.charAt(i), whitespace)) i++; return s.substring (i, s.length); } // Returns true if character c is an English letter // (A .. Z, a..z). // // NOTE: Need i18n version to support European characters. // This could be tricky due to different character // sets and orderings for various languages and platforms. function isLetter (c) { return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) ) } // Returns true if character c is a digit // (0 .. 9). function isDigit (c) { return ((c >= "0") && (c <= "9")) } // Returns true if character c is a letter or digit. function isLetterOrDigit (c) { return (isLetter(c) || isDigit(c)) } // isInteger (STRING s [, BOOLEAN emptyOK]) // // Returns true if all characters in string s are numbers. // // Accepts non-signed integers only. Does not accept floating // point, exponential notation, etc. // // We don't use parseInt because that would accept a string // with trailing non-numeric characters. // // By default, returns defaultEmptyOK if s is empty. // There is an optional second argument called emptyOK. // emptyOK is used to override for a single function call // the default behavior which is specified globally by // defaultEmptyOK. // If emptyOK is false (or any value other than true), // the function will return false if s is empty. // If emptyOK is true, the function will return true if s is empty. // // EXAMPLE FUNCTION CALL: RESULT: // isInteger ("5") true // isInteger ("") defaultEmptyOK // isInteger ("-5") false // isInteger ("", true) true // isInteger ("", false) false // isInteger ("5", false) true function isInteger (s) { var i; if (isEmpty(s)) if (isInteger.arguments.length == 1) return defaultEmptyOK; else return (isInteger.arguments[1] == true); // Search through string's characters one by one // until we find a non-numeric character. // When we do, return false; if we don't, return true. for (i = 0; i < s.length; i++) { // Check that current character is number. var c = s.charAt(i); if (!isDigit(c)) return false; } // All characters are numbers. return true; } // isSignedInteger (STRING s [, BOOLEAN emptyOK]) // // Returns true if all characters are numbers; // first character is allowed to be + or - as well. // // Does not accept floating point, exponential notation, etc. // // We don't use parseInt because that would accept a string // with trailing non-numeric characters. // // For explanation of optional argument emptyOK, // see comments of function isInteger. // // EXAMPLE FUNCTION CALL: RESULT: // isSignedInteger ("5") true // isSignedInteger ("") defaultEmptyOK // isSignedInteger ("-5") true // isSignedInteger ("+5") true // isSignedInteger ("", false) false // isSignedInteger ("", true) true function isSignedInteger (s) { if (isEmpty(s)) if (isSignedInteger.arguments.length == 1) return defaultEmptyOK; else return (isSignedInteger.arguments[1] == true); else { var startPos = 0; var secondArg = defaultEmptyOK; if (isSignedInteger.arguments.length > 1) secondArg = isSignedInteger.arguments[1]; // skip leading + or - if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") ) startPos = 1; return (isInteger(s.substring(startPos, s.length), secondArg)) } } // isPositiveInteger (STRING s [, BOOLEAN emptyOK]) // // Returns true if string s is an integer > 0. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isPositiveInteger (s) { var secondArg = defaultEmptyOK; if (isPositiveInteger.arguments.length > 1) secondArg = isPositiveInteger.arguments[1]; // The next line is a bit byzantine. What it means is: // a) s must be a signed integer, AND // b) one of the following must be true: // i) s is empty and we are supposed to return true for // empty strings // ii) this is a positive, not negative, number return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg) || (parseInt (s) > 0) ) ); } // isNonnegativeInteger (STRING s [, BOOLEAN emptyOK]) // // Returns true if string s is an integer >= 0. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isNonnegativeInteger (s) { var secondArg = defaultEmptyOK; if (isNonnegativeInteger.arguments.length > 1) secondArg = isNonnegativeInteger.arguments[1]; // The next line is a bit byzantine. What it means is: // a) s must be a signed integer, AND // b) one of the following must be true: // i) s is empty and we are supposed to return true for // empty strings // ii) this is a number >= 0 return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg) || (parseInt (s) >= 0) ) ); } // isNegativeInteger (STRING s [, BOOLEAN emptyOK]) // // Returns true if string s is an integer < 0. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isNegativeInteger (s) { var secondArg = defaultEmptyOK; if (isNegativeInteger.arguments.length > 1) secondArg = isNegativeInteger.arguments[1]; // The next line is a bit byzantine. What it means is: // a) s must be a signed integer, AND // b) one of the following must be true: // i) s is empty and we are supposed to return true for // empty strings // ii) this is a negative, not positive, number return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg) || (parseInt (s) < 0) ) ); } // isNonpositiveInteger (STRING s [, BOOLEAN emptyOK]) // // Returns true if string s is an integer <= 0. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isNonpositiveInteger (s) { var secondArg = defaultEmptyOK; if (isNonpositiveInteger.arguments.length > 1) secondArg = isNonpositiveInteger.arguments[1]; // The next line is a bit byzantine. What it means is: // a) s must be a signed integer, AND // b) one of the following must be true: // i) s is empty and we are supposed to return true for // empty strings // ii) this is a number <= 0 return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg) || (parseInt (s) <= 0) ) ); } // isFloat (STRING s [, BOOLEAN emptyOK]) // // True if string s is an unsigned floating point (real) number. // // Also returns true for unsigned integers. If you wish // to distinguish between integers and floating point numbers, // first call isInteger, then call isFloat. // // Does not accept exponential notation. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isFloat (s) { var i; var seenDecimalPoint = false; if (isEmpty(s)) if (isFloat.arguments.length == 1) return defaultEmptyOK; else return (isFloat.arguments[1] == true); if (s == decimalPointDelimiter) return false; // Search through string's characters one by one // until we find a non-numeric character. // When we do, return false; if we don't, return true. for (i = 0; i < s.length; i++) { // Check that current character is number. var c = s.charAt(i); if ((c == decimalPointDelimiter) && !seenDecimalPoint) seenDecimalPoint = true; else if (!isDigit(c)) return false; } // All characters are numbers. return true; } // isSignedFloat (STRING s [, BOOLEAN emptyOK]) // // True if string s is a signed or unsigned floating point // (real) number. First character is allowed to be + or -. // // Also returns true for unsigned integers. If you wish // to distinguish between integers and floating point numbers, // first call isSignedInteger, then call isSignedFloat. // // Does not accept exponential notation. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isSignedFloat (s) { if (isEmpty(s)) if (isSignedFloat.arguments.length == 1) return defaultEmptyOK; else return (isSignedFloat.arguments[1] == true); else { var startPos = 0; var secondArg = defaultEmptyOK; if (isSignedFloat.arguments.length > 1) secondArg = isSignedFloat.arguments[1]; // skip leading + or - if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") ) startPos = 1; return (isFloat(s.substring(startPos, s.length), secondArg)) } } // isAlphabetic (STRING s [, BOOLEAN emptyOK]) // // Returns true if string s is English letters // (A .. Z, a..z) only. // // For explanation of optional argument emptyOK, // see comments of function isInteger. // // NOTE: Need i18n version to support European characters. // This could be tricky due to different character // sets and orderings for various languages and platforms. function isAlphabetic (s) { var i; if (isEmpty(s)) if (isAlphabetic.arguments.length == 1) return defaultEmptyOK; else return (isAlphabetic.arguments[1] == true); // Search through string's characters one by one // until we find a non-alphabetic character. // When we do, return false; if we don't, return true. for (i = 0; i < s.length; i++) { // Check that current character is letter. var c = s.charAt(i); if (!isLetter(c)) return false; } // All characters are letters. return true; } // isAlphanumeric (STRING s [, BOOLEAN emptyOK]) // // Returns true if string s is English letters // (A .. Z, a..z) and numbers only. // // For explanation of optional argument emptyOK, // see comments of function isInteger. // // NOTE: Need i18n version to support European characters. // This could be tricky due to different character // sets and orderings for various languages and platforms. function isAlphanumeric (s) { var i; if (isEmpty(s)) if (isAlphanumeric.arguments.length == 1) return defaultEmptyOK; else return (isAlphanumeric.arguments[1] == true); // Search through string's characters one by one // until we find a non-alphanumeric character. // When we do, return false; if we don't, return true. for (i = 0; i < s.length; i++) { // Check that current character is number or letter. var c = s.charAt(i); if (! (isLetter(c) || isDigit(c) ) ) return false; } // All characters are numbers or letters. return true; } // reformat (TARGETSTRING, STRING, INTEGER, STRING, INTEGER ... ) // // Handy function for arbitrarily inserting formatting characters // or delimiters of various kinds within TARGETSTRING. // // reformat takes one named argument, a string s, and any number // of other arguments. The other arguments must be integers or // strings. These other arguments specify how string s is to be // reformatted and how and where other strings are to be inserted // into it. // // reformat processes the other arguments in order one by one. // * If the argument is an integer, reformat appends that number // of sequential characters from s to the resultString. // * If the argument is a string, reformat appends the string // to the resultString. // // NOTE: The first argument after TARGETSTRING must be a string. // (It can be empty.) The second argument must be an integer. // Thereafter, integers and strings must alternate. This is to // provide backward compatibility to Navigator 2.0.2 JavaScript // by avoiding use of the typeof operator. // // It is the caller's responsibility to make sure that we do not // try to copy more characters from s than s.length. // // EXAMPLES: // // * To reformat a 10-digit U.S. phone number from "1234567890" // to "(123) 456-7890" make this function call: // reformat("1234567890", "(", 3, ") ", 3, "-", 4) // // * To reformat a 9-digit U.S. Social Security number from // "123456789" to "123-45-6789" make this function call: // reformat("123456789", "", 3, "-", 2, "-", 4) // // HINT: // // If you have a string which is already delimited in one way // (example: a phone number delimited with spaces as "123 456 7890") // and you want to delimit it in another way using function reformat, // call function stripCharsNotInBag to remove the unwanted // characters, THEN call function reformat to delimit as desired. // // EXAMPLE: // // reformat (stripCharsNotInBag ("123 456 7890", digits), // "(", 3, ") ", 3, "-", 4) function reformat (s) { var arg; var sPos = 0; var resultString = ""; for (var i = 1; i < reformat.arguments.length; i++) { arg = reformat.arguments[i]; if (i % 2 == 1) resultString += arg; else { resultString += s.substring(sPos, sPos + arg); sPos += arg; } } return resultString; } // isUSPhoneNumber (STRING s [, BOOLEAN emptyOK]) // // isUSPhoneNumber returns true if string s is a valid U.S. Phone // Number. Must be 10 digits. // // NOTE: Strip out any delimiters (spaces, hyphens, parentheses, etc.) // from string s before calling this function. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isUSPhoneNumber (s) { if (isEmpty(s)) if (isUSPhoneNumber.arguments.length == 1) return defaultEmptyOK; else return (isUSPhoneNumber.arguments[1] == true); return (isInteger(s) && s.length == digitsInUSPhoneNumber) } // isEmail (STRING s [, BOOLEAN emptyOK]) // // Email address must be of form a b c -- in other words: // * there must be at least one character before the @ // * there must be at least one character before and after the . // * the characters @ and . are both required // // For explanation of optional argument emptyOK, // see comments of function isInteger. function isEmail (s) { if (isEmpty(s)) if (isEmail.arguments.length == 1) return defaultEmptyOK; else return (isEmail.arguments[1] == true); // is s whitespace? if (isWhitespace(s)) return false; // there must be >= 1 character before @, so we // start looking at character position 1 // (i.e. second character) var i = 1; var sLength = s.length; // look for @ while ((i < sLength) && (s.charAt(i) != "@")) { i++ } if ((i >= sLength) || (s.charAt(i) != "@")) return false; else i += 2; // look for . while ((i < sLength) && (s.charAt(i) != ".")) { i++ } // there must be at least one character after the . if ((i >= sLength - 1) || (s.charAt(i) != ".")) return false; else return true; } /* FUNCTIONS TO NOTIFY USER OF INPUT REQUIREMENTS OR MISTAKES. */ // Display prompt string s in status bar. function prompt (s) { window.status = s } // Display data entry prompt string s in status bar. function promptEntry (s) { window.status = pEntryPrompt + s } // Notify user that required field theField is empty. // String s describes expected contents of theField.value. // Put focus in theField and return false. function warnEmpty (theField, s) { theField.focus() alert(mPrefix + s + mSuffix) return false } // Notify user that contents of field theField are invalid. // String s describes expected contents of theField.value. // Put select theField, pu focus in it, and return false. function warnInvalid (theField, s) { theField.focus() theField.select() alert(s) return false } /* FUNCTIONS TO INTERACTIVELY CHECK VARIOUS FIELDS. */ // checkString (TEXTFIELD theField, STRING s, [, BOOLEAN emptyOK==false]) // // Check that string theField.value is not all whitespace. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function checkString (theField, s, emptyOK) { // Next line is needed on NN3 to avoid "undefined is not a number" error // in equality comparison below. if (checkString.arguments.length == 2) emptyOK = defaultEmptyOK; if ((emptyOK == true) && (isEmpty(theField.value))) return true; if (isWhitespace(theField.value)) return warnEmpty (theField, s); else return true; } // takes USPhone, a string of 10 digits // and reformats as (123) 456-789 function reformatUSPhone (USPhone) { return (reformat (USPhone, "(", 3, ") ", 3, "-", 4)) } // checkUSPhone (TEXTFIELD theField [, BOOLEAN emptyOK==false]) // // Check that string theField.value is a valid US Phone. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function checkUSPhone (theField, emptyOK) { if (checkUSPhone.arguments.length == 1) emptyOK = defaultEmptyOK; if ((emptyOK == true) && (isEmpty(theField.value))) return true; else { var normalizedPhone = stripCharsInBag(theField.value, phoneNumberDelimiters) if (!isUSPhoneNumber(normalizedPhone, false)) return warnInvalid (theField, iUSPhone); else { // if you don't want to reformat as (123) 456-789, comment next line out theField.value = reformatUSPhone(normalizedPhone) return true; } } } // checkEmail (TEXTFIELD theField [, BOOLEAN emptyOK==false]) // // Check that string theField.value is a valid Email. // // For explanation of optional argument emptyOK, // see comments of function isInteger. function checkEmail (theField, emptyOK) { if (checkEmail.arguments.length == 1) emptyOK = defaultEmptyOK; if ((emptyOK == true) && (isEmpty(theField.value))) return true; else if (!isEmail(theField.value, false)) return warnInvalid (theField, iEmail); else return true; }