/*

	see validate_test.js for an example


	SETUP FOR FORM VALIDATION
	
	1. include this script in your page
	2. add onsubmit="return validate('formname',validate_settings)" to every form you wish to validate
	3. create a validate_settings variable in the page to specify which things to check for


	AVAILABLE SUBFUNCTIONS
	
	not_blank -- make sure a field has something in it, or that a menu is set (the value of the "unset" option of menus should be -1 for this to work)
	not_blank_menu -- make sure one element of a popup menu is selected (preferred over not_blank for menus)
	not_blank_radio -- make sure one element of a radio button is selected
	not_blank_checkbox -- make sure one element of a checkbox is selected
	not_zero -- for numeric values, make sure the value is not zero
	no_letters -- require that a field contain no letters (punctuation is okay)
	no_numbers -- require that a field contain no numbers (punctuation is okay)
	no_punctuation -- require that a field contain no punctuation
	mixed_case -- don't allow all uppercase or all lowercase
	match -- see if the field's value matches another field's value
			 doesn't support menus, radio buttons, or checkboxes
			 using the subfunction match_password_confirm checks to see if the field has the same value as the password_confirm field
	allowed -- specify which characters are allowed in the field
			   allowed_1234. allows only the numbers 1, 2, 3, 4 and a dot
			   (actually, Netscape doesn't like slashes, even when escaped -- can we work around this in a future version?)
	required -- specify which characters are required in the field
			   required_a\n requires a letter a or a line break
			   (actually, Netscape doesn't like slashes, even when escaped -- can we work around this in a future version?)
	length -- check for a length range or list of possible lengths (counts letters and numbers only)
			  also counts the length of a checkbox array
			  length_6 requires 6 characters, length_1-12 requires between 1 and 12 characters, length_1|3|5 requires 1, 3, or 5 characters
	email_characters -- check for various requirements of a valid email address
	credit_card -- check for the proper lengths and required characters of each type of credit card (ignore punctuation)
		      	   this assumes a field named card_type is also present on the form
	taxexempt_format -- check if the value has a valid tax exempt ID number format (Exxxx-xxxx-xx)
	SSN_format -- check if the value has a valid social security number format (xxx-xx-xxxx)
	valid_date -- check that the supplied date is valid (e.g., Feb 31 is never valid)
				  this assumes that fields named FIELDNAME_month, FIELDNAME_year and FIELDNAME_day are present on the form
	
	REGULAR EXPRESSION SYMBOLS USED IN THE SUBFUNCTIONS

	\w matches alphanumeric, including "_".
	\W matches non-alphanumeric (i.e., punctuation) 

	\b matches word boundaries
	\B matches non-boundaries 

	\s matches whitespace
	\S matches non-whitespace 

	\d matches numeric
	\D matches non-numeric 
	
	
	VERSION HISTORY
	
	01/19/02 - Initial development
	10/21/02 - Added not_blank_menu, not_blank_radio, and not_blank_checkbox subfunctions; made card type switch not case-sensitive; added a setting to allow card_type to be a popup menu or a radio button
	11/11/02 - Fixed get_checkbox_value and get_menu_value, added get_menu_text, tweaked focus on not_blank_menu to avoid errors
	06/20/03 - Tweaked checkbox functions to support [] in element names; added match subfunction to compare two fields
	07/22/03 - Added array_length check to get_checkbox_value, get_radio_value, not_blank_checkbox, and not_blank_radio to avoid an error when those arrays only contain one element
	10/22/03 - Tweaked credit_card to avoid a duplicate missing card type message, fixed a typo in a comment
	11/07/03 - Tweaked radio functions to support [] in element names
	05/19/04 - Added support for a default blank_value for text fields; tweaked alert message to be more user-friendly
	06/08/04 - Added support for customizing the alert message by providing an alternate initial sentence and/or skipping the field details.
	06/08/04 - Added required subfunction, removed need to escape regex characters in allowed values.
	08/05/04 - Tweaked previous change for compatibility with radio buttons and checkboxes
	08/17/04 - Added show_full_report option to show just the first error message; tweaked not_blank_menu to correct problem introduced in previous version
	10/14/04 - Changed lengthx function to count checkbox arrays
	05/16/05 - Added the valid_date subfunction and validate_date function
	06/10/05 - Fixed match function to work when one field is blank; tweaked spacing and added some missing semicolons to line endings
	06/17/05 - Changed some_caps to mixed_case so that all-uppercase entries as well as all-lowercase entries are blocked
	01/24/06 - Added a stub function to pass some_caps calls to mixed_case for backwards compatibility
	03/14/06 - Merged the validate_date function into the valid_date subfunction; showed specific reports for blank date fields; corrected related comments; avoided an error if a set of checkboxes is given both not_blank_checkbox and length settings; tweaked spacing

	to do: make length function count items in a multiple-select menu
	
*/


// offer a few site-wide settings; developers can also set these on a page-by-page basis in their scripts

	var card_type_style = "menu"; // possible values are menu and radio
	var blank_value = ""; // allows an initial value that's also considered blank, like "(one per line)"
	var include_field_details = 1; // includes details about which fields have problems in the alert message
	var show_full_report = 1; // includes all error messages; set to 0 to show just the first message 
	var report_intro = "We're sorry, the information you entered is incomplete. Please correct the following entries and submit again:"; // the first sentence of the alert message
	

// parse the validate settings and trigger all the other functions

	function validate(form_name, validate_settings) {
		validate_report = "";
		field_name_focus = "";
		
		fields_count = validate_settings.length / 3;
		for (i=0; i<fields_count; i++) {
			field_name = validate_settings[i*3];
			field_label = validate_settings[(i*3)+1];
			field_settings = validate_settings[(i*3)+2];
			
			if (field_settings.indexOf("not_blank_menu") != -1) {
				field_value = get_menu_value(form_name, field_name);
			} else if (field_settings.indexOf("not_blank_radio") != -1) {
				field_value = get_radio_value(form_name, field_name);
			} else if (field_settings.indexOf("not_blank_checkbox") != -1) {
				is_array = 1;
				field_value = get_checkbox_value(form_name, field_name);
			} else if (field_settings.indexOf("length_") != -1) {
				eval("field = document." + form_name + "." + field_name);
				is_array = (typeof(field.length) == "undefined") ? 0 : 1 ;  // determine if this field is an array (checkbox group)
				if (is_array) {
					field_value = get_checkbox_value(form_name, field_name);
				} else {
					eval("field_value = document." + form_name + "." + field_name + ".value");
				}
			} else if (field_settings.indexOf("valid_date") != -1) {
				field_value = get_menu_value(form_name, field_name + "_year") + ",";
				field_value += get_menu_value(form_name, field_name + "_month") + ",";
				field_value += get_menu_value(form_name, field_name + "_day");
			} else {
				eval("field_value = document." + form_name + "." + field_name + ".value");
			}
			
			field_settings = field_settings.replace(/\\/g,"");																		
			field_settings = field_settings.replace(/,\s+/g,",");
			field_settings = field_settings.split(",");
			settings_count = field_settings.length;
						
			for (j=0; j<settings_count; j++) {
				function_name = field_settings[j];
				
				// don't bother checking if the field is blank (unless we're checking not_blank!)
				if ((function_name.indexOf("not_blank") != -1)||(function_name.indexOf("length") != -1)||(function_name.indexOf("match") != -1)||((field_value.replace(/\s/g,"") != "")&&(field_value.replace(/\s/g,"") != "-1"))) {

					if (function_name.indexOf("length_") == 0) {
						// do some special parsing for the length function
						length_settings = function_name.substr(7,function_name.length);
						lengthx(field_value, is_array, length_settings);
					} else if (function_name.indexOf("allowed_") == 0) {
						// do some special parsing for the allowed function
						allowed_characters = function_name.substr(8,function_name.length);
						allowed(field_value, allowed_characters);
					} else if (function_name.indexOf("required_") == 0) {
						// do some special parsing for the required function
						required_characters = function_name.substr(9,function_name.length);
						required(field_value, required_characters);
					} else if (function_name.indexOf("match_") == 0) {
						// do some special parsing for the match function
						target_field = function_name.substr(6,function_name.length);
						match(form_name, field_value, target_field, validate_settings);
					} else if (function_name.indexOf("credit_card") == 0) {
						// send the card_type value to the credit_card function
						//eval("card_type = document." + form_name + ".card_type.options[document." + form_name + ".card_type.selectedIndex].text");
						if (card_type_style == "menu") {
							card_type = get_menu_text(form_name, "card_type");
						} else {
							// for this to return user-friendly results, you need to set your card IDs to words rather than numbers;
							// this isn't a problem with menus because there you can have an ID (option.value) -and- a human-readable name (option.text)
							card_type = get_radio_value(form_name, "card_type");
						}
						credit_card(field_value, card_type);
					} else {
						eval(function_name + "('" + eval_escape(field_value) + "')");
					}
				
				}
			}
		}
		
		if (validate_report == "") {
			return true;
		} else {
			if (include_field_details) {
				divider = (report_intro && validate_report) ? "\n\n" : "" ;
				if (!show_full_report) {
					validate_report = validate_report.substr(0,validate_report.indexOf("\n"));
				}
				validate_report = report_intro + divider + validate_report;
				alert(validate_report);
			} else {
				alert(report_intro);
			}
			if (field_name_focus) { eval("document." + form_name + "." + field_name_focus + ".focus()"); }
			return false;
		}
	}
	

// make sure a field has something in it, or that a menu is set (the value of the "unset" option of menus should be -1 for this to work)

	function not_blank(field_value) {
		if ((field_value.replace(/\s/g,"") == "")||(field_value == blank_value)||(field_value == "-1")) { // we could take out the -1 but for backwards compatibility with popup menus
			validate_report += field_label + " is blank\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// make sure one element of a popup menu is selected

	function not_blank_menu(field_value) {
		if ((field_value == "")||(field_value == "-1")) {
			validate_report += field_label + " is not selected\n";
			if (! field_name_focus) {
				field_name_focus = "elements['" + field_name + "']";
			}
		}
	}


// make sure one element of a radio button is selected

	function not_blank_radio(field_value) {
		if (field_value == "") {
			validate_report += field_label + " is not selected\n";
			if (! field_name_focus) {
				if (array_length > 0) {
					field_name_focus = "elements['" + field_name + "']" + "[0]";
				} else {
					field_name_focus = "elements['" + field_name + "']";
				}
			}
		}
	}


// make sure one element of a checkbox is selected

	function not_blank_checkbox(field_value) {
		field_value_array = field_value.split(",");
		this_length = field_value_array.length;
		
		if (field_value == "") {
			validate_report += field_label + " is not selected\n";
			if (! field_name_focus) {
				if (array_length > 0) {
					field_name_focus = "elements['" + field_name + "']" + "[0]";
				} else {
					field_name_focus = "elements['" + field_name + "']";
				}
			}
		}
	}
	

// for numeric values, make sure the value is not zero
	
	function not_zero(field_value) {
		field_value = parseFloat(field_value);
		if (field_value == 0) {
			validate_report += field_label + " is blank\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// require that a field contain no letters (punctuation is okay)

	function no_letters(field_value) {
		field_value_compare = field_value.replace(/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]/g,""); // remove all letters
		if (field_value.length != field_value_compare.length) {
			validate_report += field_label + " should only contain numbers\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// require that a field contain no numbers (punctuation is okay)

	function no_numbers(field_value) {
		field_value_compare = field_value.replace(/\d/g,""); // remove all numbers
		if (field_value.length != field_value_compare.length) {
			validate_report += field_label + " should not contain numbers\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// require that a field contain no punctuation

	function no_punctuation(field_value) {
		field_value_compare = field_value.replace(/\W/g,""); // remove all punctuation, except underscores
		field_value_compare = field_value.replace(/_/g,""); // remove underscores
		if (field_value.length != field_value_compare.length) {
			validate_report += field_label + " should not contain numbers\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// encourage proper capitalization

	// provide backwards compatibility with the old name for this subfunction
	function some_caps(field_value) {
		mixed_case(field_value);
	}
	
	function mixed_case(field_value) {
		field_value_compare = field_value.replace(/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]/g,"");
		if (field_value_compare.length < field_value.length) { // don't bother checking if there aren't any letters
			field_value_lower = field_value.toLowerCase(); // change to all lowercase
			field_value_upper = field_value.toUpperCase(); // change to all uppercase
			if ((field_value == field_value_lower)||(field_value == field_value_upper)) {
				validate_report += field_label + " should use normal capitalization\n";
				if (! field_name_focus) { field_name_focus = field_name; }
			}
		}
	}


// see if the field's value matches another field's value
// doesn't support menus, radio buttons, or checkboxes

	function match(form_name,field_value,target_field_name,validate_settings) {
		eval("target_field_value = document."+form_name+"."+target_field_name+".value");
		if (field_value != target_field_value) {
			// figure out the target field's label so we can display it in the report
			target_field_index = get_position(target_field_name, validate_settings);
			target_field_label = validate_settings[target_field_index + 1];
			validate_report += field_label + " and " + target_field_label + " should match\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// specify which characters are allowed in a field
// allowed_1234. allows only the numbers 1, 2, 3, 4 and a dot

	function allowed(field_value,allowed_characters) {
		eval("field_value = field_value.replace(/["+eval_escape(regex_escape(allowed_characters))+"]/g,'')");
		if (field_value != "") {
			validate_report += field_label + " can't contain the characters '" + eval_escape(field_value) + "'\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// specify which characters are required in a field
// required_a\n requires a letter a or a line break

	function required(field_value,required_characters) {
		eval("characters_present = field_value.search(/["+eval_escape(regex_escape(required_characters))+"]/)");
		if (characters_present == -1) {
			validate_report += field_label + " must contain at least one of the characters '" + eval_escape(required_characters) + "'\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// check that the supplied date is valid (i.e., Feb 31 is never valid)
// this assumes that fields named FIELDNAME_year, FIELDNAME_month and FIELDNAME_day are present on the form

	function valid_date(field_value) {
		field_value_array = field_value.split(",");
		year = field_value_array[0];
		month = field_value_array[1];
		day = field_value_array[2];
		
		// save the group name and label before we test the individual fields
		field_name_save = field_name;
		field_label_save = field_label;
		
		// save the current validation report so we can find out whether the individual fields change the report
		report_before = validate_report;
		
		// make sure each of the three fields is set
		field_name = field_name_save + "_month";
		field_label = field_label_save + " month";
		not_blank_menu(month);
		field_name = field_name_save + "_day";
		field_label = field_label_save + " day";
		not_blank_menu(day);
		field_name = field_name_save + "_year";
		field_label = field_label_save + " year";
		not_blank_menu(year);
		
		// save the validation report now so we can find out whether the individual fields changes the report
		report_after = validate_report;
		
		// restore the group field name and label
		field_name = field_name_save;
		field_label = field_label_save;
		
		// then check the date as a whole, unless one of the individual fields is already showing up in the validation report
		if (report_before == report_after) {
			this_date = new Date(year, month-1, day);
			if ((this_date.getFullYear() != year)||(this_date.getMonth() != (month-1))||(this_date.getDate() != day)) {
				validate_report += field_label + " is not a valid date\n";
				if (! field_name_focus) { field_name_focus = field_name + "_day"; }
			}
		}
	}


// check for a length range or list of possible lengths (counts letters and numbers only)
// also counts the length of a checkbox array
// length_6 requires 6 characters, length_1-12 requires between 1 and 12 characters, length_1|3|5 requires 1, 3, or 5 characters

	function lengthx(field_value,is_array,length_settings) {
		error = 0;
		
		if (is_array) {	// checkbox group
			field_value_array = field_value.split(",");
			field_value_length = field_value_array.length;
			if (field_value == "") { field_value_length = 0; }
			
		} else {
			field_value = field_value.replace(/\W/g,""); // ignore punctuation
			field_value_length = field_value.length;
		}		
		
		if (length_settings.indexOf("-") != -1) {	// length_1-12 requires between 1 and 12 characters
			length_settings = length_settings.split("-");
			min = parseInt(length_settings[0]);
			max = parseInt(length_settings[1]);
			if ((field_value_length < min)||(field_value_length > max)) {
				if (is_array) {
					validate_report += field_label + " should have between " + min + " and " + max + " items selected\n";
				} else {
					validate_report += field_label + " should be between " + min + " and " + max + " characters long\n";
				}
				error = 1;
			}
			
		} else if (length_settings.indexOf("|") != -1) {	// length_1|3|5 requires 1, 3, or 5 characters
			length_settings = length_settings.split("|");
			success = 0;
			oks = "";
			for (k=0; k<length_settings.length; k++) {
				ok = parseInt(length_settings[k]);
				if (field_value_length == ok) {
					success = 1;
					break;
				}
				if (k < length_settings.length - 1) {
					if (length_settings.length > 2) {
						oks += ok + ", ";
					} else {
						oks += ok + " ";
					}
				} else {
					oks += "or " + ok;
				}
			}
			if (success == 0) {	
				if (is_array) {
					validate_report += oks + " " + field_label + " should be selected\n";
				} else {
					validate_report += field_label + " should be " + oks + " characters long\n";
				}
				error = 1;
			}
			
		} else {
			ok = parseInt(length_settings);
			if (field_value_length != ok) {
				if (is_array) {
					validate_report += ok + " " + field_label + " should be selected\n";
				} else {
					validate_report += field_label + " should be " + ok + " characters long\n";
				}
				error = 1;
			}
		}
		
		if (error == 1) {
			if (! field_name_focus) {
				if (is_array) {
					if (array_length > 0) {
						field_name_focus = "elements['" + field_name + "']" + "[0]";
					} else {
						field_name_focus = "elements['" + field_name + "']";
					}
				} else {
					field_name_focus = field_name;
				}
			}
		}
	}


// check for various requirements of a valid email address

	function email_characters(field_value) {
			
		// checks for legal characters (@-._aZ09), characters that can't start the address,
		// characters that can't be together, only one @ symbol, legal characters after the @ (aZ09.-)
		check_general = /[^@\-\.\w_]|^[_@\.\-]|[@\._\-]{2}|(@)[^@]*\1|@[\w\-.]{1,}_/;
		
		// checks for at least one a-Z or 0-9 between the @ and the .
		check_domain = /@[\w\-]{1,}\./;
		
		// checks for two-, three- or four- character TLD (e.g. .de, .com, .info)
		check_TLD = /\.[a-zA-Z]{2,4}$/;

		if (((field_value.search(check_general) != -1)||(field_value.search(check_domain)) == -1)||(field_value.search(check_TLD) == -1)) {
			validate_report += field_label + " does not contain a valid email address\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	
	}


// check for the proper lengths and required characters of each type of credit card (ignore punctuation)
// this assumes a field named card_type is also present on the form

	function credit_card(field_value,card_type) {
		if ((card_type != "")&&(card_type.indexOf("...") == -1)) {
			field_value = field_value.replace(/[^\d]/g,"");  // remove all but numbers
			success = 1;
			switch (card_type.substr(0,3).toLowerCase()) {
				case "vis" :
					// Visa: 16 or 13 digits long, first digit is 4
					if (!((field_value.length == 16)||(field_value.length == 13))||!(parseInt(field_value.substr(0,1)) == 4)) {
						success = 0;
					}
					break;
				case "mas" :
					// Mastercard: 16 digits long, first digit is 5, second digit is between 1 and 5 inclusive
					if (!(field_value.length == 16)||!((parseInt(field_value.substr(0,1)) == 5)&&(parseInt(field_value.substr(1,1)) >= 1)&&(parseInt(field_value.substr(1,1)) <= 5))) {
						success = 0;
					}
					break;
				case "dis" :
					// Discover: 16 digits long, first four digits are 6011
					if (!(field_value.length == 16)||!(parseInt(field_value.substr(0,4)) == 6011)) {
						success = 0;
					}
					break;
				case "ame" :
					// American Express: 15 digits long, first digit is 3, second digit is 4 or 7
					if (!(field_value.length == 15)||!((parseInt(field_value.substr(0,1)) == 3)&&((parseInt(field_value.substr(1,1)) == 4)||(parseInt(field_value.substr(1,1)) == 7)))) {
						success = 0;
					}
					break;
				case "din" :
					// Diner's Club: 14 digits long, first digit is 3, second digit is 0, 6, or 8
					if (!(field_value.length == 14)||!((parseInt(field_value.substr(0,1)) == 3)&&((parseInt(field_value.substr(1,1)) == 0)||(parseInt(field_value.substr(1,1)) == 6)||(parseInt(field_value.substr(1,1)) == 8)))) {
						success = 0;
					}
					break;
				case "car" :
					// Carte Blanche: 14 digits long, first digit is 3, second digit is 0, 6, or 8
					if (!(field_value.length == 14)||!((parseInt(field_value.substr(0,1)) == 3)&&((parseInt(field_value.substr(1,1)) == 0)||(parseInt(field_value.substr(1,1)) == 6)||(parseInt(field_value.substr(1,1)) == 8)))) {
						success = 0;
					}
					break;
				case "enr" :
					// EnRoute: 15 digits long, first four digits are 2014 or 2149
					if (!(field_value.length == 15)||!((parseInt(field_value.substr(0,4)) == 2014)||(parseInt(field_value.substr(0,4)) == 2149))) {
						success = 0;
					}
					break;
				case "jcb" :
					// JCB: 16 digits long, first four digits are 3088, 3096, 3112, 3158, 3337, or 3528
					if (!(field_value.length == 16)||!((parseInt(field_value.substr(0,4)) == 3088)||(parseInt(field_value.substr(0,4)) == 3096)||(parseInt(field_value.substr(0,4)) == 3112)||(parseInt(field_value.substr(0,4)) == 3158)||(parseInt(field_value.substr(0,4)) == 3337)||(parseInt(field_value.substr(0,4)) == 3528))) {
						success = 0;
					}
					break;
				default : 
					validate_report += card_type + " is not a valid credit card type\n";
					break;
			}
			if (! success) {
				validate_report += field_label + " is not a valid " + card_type + " number\n";
				if (! field_name_focus) { field_name_focus = field_name; }
			}
		} //else { // we probably don't need this because we'll have a not_blank on the card type field
		//	validate_report += field_label + " needs an associated card type\n";
		//}
	}


// check if the value has a valid tax exempt ID number format (Exxxx-xxxx-xx)

	function taxexempt_format(field_value) {
		field_value = field_value.replace(/E\d{4}-\d{4}-\d{2}/,"okay");
		if (field_value != "okay") {
			validate_report += field_label + " is not a valid tax exempt ID\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}


// check if the value has a valid social security number format (xxx-xx-xxxx)

	function SSN_format(field_value) {
		field_value = field_value.replace(/\d{3}-\d{2}-\d{4}/,"okay");
		if (field_value != "okay") {
			validate_report += field_label + " is not a valid SSN\n";
			if (! field_name_focus) { field_name_focus = field_name; }
		}
	}
	

// return the texts of the selected menu items

	function get_menu_text(form_name, field_name) {
		eval("this_element = document."+form_name+"."+field_name+".options");
		selected_texts = new Array();
		for (k=0; k<this_element.length; k++) {
			if (this_element[k].selected) {
				//selected_texts.push(this_element[k].text); // why doesn't this line work? ("object doesn't support...")
				selected_texts[selected_texts.length] = this_element[k].text;
			}
		}
		selected_texts = selected_texts.join(",");
		return selected_texts;
	}


// return the values of the selected menu items (not_blank works on some, but not all, browsers, so this is safer)

	function get_menu_value(form_name, field_name) {
		eval("this_element = document."+form_name+".elements['"+field_name+"'].options"); // the extra bit here allows us to use names that contain [] without throwing syntax errors
		selected_values = new Array();
		for (k=0; k<this_element.length; k++) {
			if (this_element[k].selected) {
				//selected_values.push(this_element[k].value); // why doesn't this line work? ("object doesn't support...")
				selected_values[selected_values.length] = this_element[k].value;
			}
		}
		selected_values = selected_values.join(",");
		return selected_values;
	}


// return the value of the selected radio button

	function get_radio_value(form_name, field_name) {
		eval("this_element = document."+form_name+".elements['"+field_name+"']"); // the extra bit here allows us to use names that contain [] without throwing syntax errors
		selected_value = "";
		array_length = this_element.length; // the not_blank functions will use this, too
		if (array_length > 0) {
			for (k=0; k<array_length; k++) {
				if (this_element[k].checked) {
					selected_value = this_element[k].value;
					break;
				}
			}
		} else {
			if (this_element.checked) {
				selected_value = this_element.value;
			}
		}
		return selected_value;
	}


// return the values of the selected checkboxes as a comma-delimited list

	function get_checkbox_value(form_name, field_name) {
		eval("this_element = document."+form_name+".elements['"+field_name+"']"); // the extra bit here allows us to use names that contain [] without throwing syntax errors
		selected_values = new Array();
		array_length = this_element.length; // the not_blank functions will use this, too
		if (array_length > 0) {
			for (k=0; k<array_length; k++) {
				if (this_element[k].checked) {
					//selected_values.push(this_element[k].value); // why isn't this line working? ("object doesn't support...")
					selected_values[selected_values.length] = this_element[k].value;
				}
			}
		} else {
			if (this_element.checked) {
				selected_values[0] = this_element.value;
			}
		}
		selected_values = selected_values.join(",");
		return selected_values;
	}


	// escape any metacharacters in the string so we don't accidentally evaluate them as regular expression symbols
	
	function regex_escape(string) {
		string = string.replace(/\\/g, "\\\\");
		string = string.replace(/\./g, "\\.");
		string = string.replace(/\+/g, "\\+");
		string = string.replace(/\*/g, "\\*");
		string = string.replace(/\?/g, "\\?");
		string = string.replace(/\[/g, "\\[");
		string = string.replace(/\^/g, "\\^");
		string = string.replace(/\]/g, "\\]");
		string = string.replace(/\$/g, "\\$");
		string = string.replace(/\(/g, "\\(");
		string = string.replace(/\)/g, "\\)");
		string = string.replace(/\{/g, "\\{");
		string = string.replace(/\}/g, "\\}");
		string = string.replace(/\//g, "\\/");
		return string;
	}
	

	// escape any line breaks in the string so we can use them in alerts and evals
	
	function eval_escape(string) {
		string = string.replace(/"/g, "\\\"");
		string = string.replace(/'/g, "\\'");
		string = string.replace(/\n/g, "\\n");
		string = string.replace(/\r/g, "\\r");
		return string;
	}
	

/*

	would this be a better way to format the validate_settings variable?
	
	validate_settings = "
		
		name: not_blank, letters_only;
		
		phone: not_blank, numbers_only;
		
		email: not_blank, email;
		
		card_number: not_blank, numbers_only;
		
	"

*/
