/*************************************************
Validator v1.03
code by 呵呵 wfsr@msn.com
2nd code by 王熹饭 wangyiguang@gmail.com 
*************************************************/
Validator = {

Require : /.+/,
Email : /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
Phone : /^((\(\d{3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/,
Mobile : /^((\(\d{3}\))|(\d{3}\-))?13\d{9}$/,
Url : /^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/,
IdCard : /^\d{15}(\d{2}[A-Za-z0-9])?$/,
Currency : /^\d+(\.\d+)?$/,
Number : /^\d+$/,
Zip : /^[1-9]\d{5}$/,
QQ : /^[1-9]\d{4,8}$/,
Integer : /^[-\+]?\d+$/,
Double : /^[-\+]?\d+(\.\d+)?$/,
English : /^[A-Za-z]+$/,
Chinese : /^[\u0391-\uFFE5]+$/,
Username : /^[a-z]\w{3,}$/i,
UnSafe : /^(([A-Z]*|[a-z]*|\d*|[-_\~!@#\$%\^&\*\.\(\)\[\]\{\}<>\?\\\/\'\"]*)|.{0,5})$|\s/,
SafeString : "this.IsSafe(value)",
Limit : "this.limit(value.length,getAttribute('min'), getAttribute('max'))",
LimitB : "this.limit(this.LenB(value), getAttribute('min'), getAttribute('max'))",
Date : "this.IsDate(value, getAttribute('min'), getAttribute('format'))",
Repeat : "value == document.getElementsByName(getAttribute('to'))[0].value",
Range : "getAttribute('min') < (value|0) && (value|0) < getAttribute('max')",
Compare : "this.compare(value,getAttribute('operator'),getAttribute('to'))",
Custom : "this.Exec(value, getAttribute('regexp'))",
Group : "this.MustChecked(getAttribute('name'), getAttribute('min'), getAttribute('max'))",

ErrorItem : [document.forms[0]],
ErrorMessage : ["对不起，以下信息不符合要求：\t\t\t\t"], //!!!! 此变量是alert时的第一行提示，可以修改成个性化的语句 !!!!//

//ExtraRight : "", //!!!! 此变量必须重新指定，默认为空值，请把它改成当验证成功时你想要显示的图标 !!!!//
//ExtraError : "", //!!!! 此变量必须重新指定，默认为空值，请把它改成当验证失败时你想要显示的图标 !!!!//
ExtraRight : "<img src=\"images/check_right.gif\">&nbsp;", //!!!! 此变量必须重新指定，默认为空值，请把它改成当验证成功时你想要显示的图标 !!!!//
ExtraError : "<img src=\"images/check_error.gif\">&nbsp;", //!!!! 此变量必须重新指定，默认为空值，请把它改成当验证失败时你想要显示的图标 !!!!//

IsSafe : function(str) {return !this.UnSafe.test(str);},

ValidateForm : function(theForm, mode) { //验证整个表单 在提交的时候

	var obj = theForm || event.srcElement;
	var count = obj.elements.length;

	this.ErrorMessage.length = 1;
	this.ErrorItem.length = 1;
	this.ErrorItem[0] = obj;

	for(var i=0;i<count;i++) {

		with(obj.elements[i]) {
			var _dataType = getAttribute("dataType");

			//alert(typeof(_dataType)); //一般会提示String

			if(typeof(_dataType) == "object" || typeof(this[_dataType]) == "undefined") continue; //非String时继续下一个表单项

			this.ClearState(obj.elements[i]);

			if(getAttribute("require") == "false" && value == "") continue; //非必须时继续下一个表单项

			switch(_dataType) {
				case "Date" :
				case "Repeat" :
				case "Range" :
				case "Compare" :
				case "Custom" :
				case "Group" : 
				case "Limit" :
				case "LimitB" :
				case "SafeString" :
					if(!eval(this[_dataType])) { //一部分自定义形式，会直接执行函数，判断这个项是否为对应类型
						this.AddErrorForm(i, getAttribute("msg"));
					}
				break;
				default :
					if(!this[_dataType].test(value)){ //另一部分会执行与该形式相关的test(正则式)的函数，来判断
						this.AddErrorForm(i, getAttribute("msg"));
					}
				break;
			}
		}
	}

	if(this.ErrorMessage.length > 1) { //如果有错误信息了（不仅仅是只有一项——“对不起，以下信息不符合要求：\t\t\t\t”）
		mode = mode || 1; //非操作的作用：如果左边的运算不成立就进行右边的运算，左边的成立直接取左边的运算值
		var errCount = this.ErrorItem.length;
		switch(mode){
			case 2 :
				for(var i=1;i<errCount;i++)
					this.ErrorItem[i].style.color = "red"; //它会加红该元素，并且不会break，就是说，虽然并非值为1，却执行了case 1后面的内容。这里并非语法错误，case a:case b:并且不加break时，会自动执行该case之后的所有语句直到break为止。而case 1:之前的语句则不会在值为1的情况下执行到，它是属于case 2的:D
			case 1 :
				alert(this.ErrorMessage.join("\n"));
				this.ErrorItem[1].focus();
			break;
			case 3 :
				for(var i=1;i<errCount;i++){
					try //先试着找到该表单项的对应span，并改变其内容。如果找不到将执行传统方式
					{
						with(this.ErrorItem[i]){
							document.getElementById(getAttribute("name")+"Warning").style.color = "red";
							document.getElementById(getAttribute("name")+"Warning").innerHTML= this.ErrorMessage[i].replace(/\d+:/,this.ExtraError);
						}
					}
					catch (e)
					{
						try {
							var span = document.createElement("SPAN");
							span.id = "__ErrorMessagePanel";
							span.style.color = "red";
							this.ErrorItem[i].parentNode.appendChild(span);
							span.innerHTML = "<br />"+this.ErrorMessage[i].replace(/\d+:/,this.ExtraError);
						} catch(e) {
							alert(e.description);
						}
					}
				}
				this.ErrorItem[1].focus();
			break;
			/*case 4:
				//2006-12-21王熹饭添加 用途：在每个表单项blur时都验证，但只对第一项加红
				try {
					var span = document.createElement("SPAN");
					span.id = "__ErrorMessagePanel";
					span.style.color = "red";
					this.ErrorItem[1].parentNode.appendChild(span);
					span.innerHTML = "<br />"+this.ErrorMessage[1].replace(/\d+:/,"*");
				} catch(e) {
					alert(e.description);
				}
			break;*/
			default :
				alert(this.ErrorMessage.join("\n"));
			break;
		}
		return false;
	}

	return true;
},

Validate : function(theItem) { //验证单个表单项 在blur的时候

	var obj = theItem || event.srcElement; //这里再用srcElement就不行了，暂时留观后效
	
	this.ErrorMessage.length = 1;
	this.ErrorItem.length = 1;
	this.ErrorItem[0] = obj;

	with(obj) {
		var _dataType = getAttribute("dataType");

		//alert(typeof(_dataType)); //一般会提示String

		if(typeof(_dataType) == "object" || typeof(this[_dataType]) == "undefined") return; //非String时继续

		this.ClearState(obj);

		if(getAttribute("require") == "false" && value == "") return; //非必须时继续

		switch(_dataType) {
			case "Date" :
			case "Repeat" :
			case "Range" :
			case "Compare" :
			case "Custom" :
			case "Group" : 
			case "Limit" :
			case "LimitB" :
			case "SafeString" :
				if(!eval(this[_dataType])) { //一部分自定义形式，会直接执行函数，判断这个项是否为对应类型
					this.AddError(getAttribute("msg"));
				}
			break;
			default :
				if(!this[_dataType].test(value)){ //另一部分会执行与该形式相关的test(正则式)的函数，来判断
					this.AddError(getAttribute("msg"));
				}
			break;
		}

	}

	if(this.ErrorMessage.length > 1) { //如果有错误信息了（不仅仅是只有一项——“对不起，以下信息不符合要求：\t\t\t\t”）
		try //先试着找到该表单项的对应span，并改变其内容。如果找不到将执行传统方式
		{
			with(obj){
				document.getElementById(getAttribute("name")+"Warning").style.color = "red";
				document.getElementById(getAttribute("name")+"Warning").innerHTML=this.ErrorMessage[1].replace(/\d+:/,this.ExtraError);
			}
		}
		catch (e)
		{
			try {
				var span = document.createElement("SPAN");
				span.id = "__ErrorMessagePanel";
				span.style.color = "red";
				obj.parentNode.appendChild(span);
				span.innerHTML = "<br />"+this.ErrorMessage[1].replace(/\d+:/,this.ExtraError);
			} catch(e) {
				alert(e.description);
			}
		}
	} else { //如果验证成功，则显示成功的内容
		try //先试着找到该表单项的对应span，并改变其内容。如果找不到将执行传统方式
		{
			with(obj){
				document.getElementById(getAttribute("name")+"Warning").style.color = "green";
				document.getElementById(getAttribute("name")+"Warning").innerHTML = this.ExtraRight;
			}
		}
		catch (e)
		{
			
		}
	}
},

limit : function(len,min, max) {
	min = min || 0;
	max = max || Number.MAX_VALUE;
	return min <= len && len <= max;
},

LenB : function(str) {
	return str.replace(/[^\x00-\xff]/g,"**").length;
},

ClearState : function(elem) {
	with(elem) {
		if(style.color == "red")
			style.color = "";
		var lastNode = parentNode.childNodes[parentNode.childNodes.length-1];
		if(lastNode.id == "__ErrorMessagePanel")
			parentNode.removeChild(lastNode);
	}
},

AddErrorForm : function(index, str) {
	this.ErrorItem[this.ErrorItem.length] = this.ErrorItem[0].elements[index];
	this.ErrorMessage[this.ErrorMessage.length] = this.ErrorMessage.length + ":" + str;
},

AddError : function(str) {
	this.ErrorMessage[this.ErrorMessage.length] = this.ErrorMessage.length + ":" + str;
},

Exec : function(op, reg) {
	return new RegExp(reg,"g").test(op);
},

compare : function(op1,operator,op2) {
	switch (operator) {
		case "NotEqual":
			return (op1 != op2);
		case "GreaterThan":
			return (op1 > op2);
		case "GreaterThanEqual":
			return (op1 >= op2);
		case "LessThan":
			return (op1 < op2);
		case "LessThanEqual":
			return (op1 <= op2);
		default:
			return (op1 == op2); 
	}
},

MustChecked : function(name, min, max) {
	var groups = document.getElementsByName(name);
	var hasChecked = 0;
	min = min || 1;
	max = max || groups.length;
	for(var i=groups.length-1;i>=0;i--)
		if(groups[i].checked) hasChecked++;
	return min <= hasChecked && hasChecked <= max;
},

IsDate : function(op, formatString) {
	formatString = formatString || "ymd";
	var m, year, month, day;
	switch(formatString) {
		case "ymd" :
			m = op.match(new RegExp("^((\\d{4})|(\\d{2}))([-./])(\\d{1,2})\\4(\\d{1,2})$"));
			if(m == null ) return false;
			day = m[6];
			month = m[5]*1;
			year = (m[2].length == 4) ? m[2] : GetFullYear(parseInt(m[3], 10));
		break;
		case "dmy" :
			m = op.match(new RegExp("^(\\d{1,2})([-./])(\\d{1,2})\\2((\\d{4})|(\\d{2}))$"));
			if(m == null ) return false;
			day = m[1];
			month = m[3]*1;
			year = (m[5].length == 4) ? m[5] : GetFullYear(parseInt(m[6], 10));
		break;
		default :
		break;
	}
	if(!parseInt(month)) return false;
	month = month==0 ?12:month;
	var date = new Date(year, month-1, day);
	return (typeof(date) == "object" && year == date.getFullYear() && month == (date.getMonth()+1) && day == date.getDate());
	function GetFullYear(y){return ((y<30 ? "20" : "19") + y)|0;}
}

}
