javaeye3/public/javascripts/validation.js

569 lines
21 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//modified by Quake (added tooltip integration and remove some unused code)
/**
* modified by badqiu (badqiu(a)gmail.com)
* blog: http://badqiu.javaeye.com
* Project Home: http://code.google.com/p/rapid-validation/
*/
/*
* Really easy field validation with Prototype
* http://tetlaw.id.au/view/blog/really-easy-field-validation-with-prototype
* Andrew Tetlaw
* Version 1.5.3 (2006-07-15)
*
* Copyright (c) 2006 Andrew Tetlaw
* http://www.opensource.org/licenses/mit-license.php
*/
var ValidationDefaultOptions = function(){};
ValidationDefaultOptions.prototype = {
onSubmit : true, //是否监听form的submit事件
stopOnFirst : false, //表单验证时停留在第一个验证的地方,不继续验证下去
immediate : true, //是否实时检查数据的合法性
focusOnError : true, //是否出错时将光标指针移到出错的输入框上
useTitles : false, //是否使用input的title属性作为出错时的提示信息
onFormValidate : function(result, form) {},//Form验证时的回调函数
onElementValidate : function(result, elm) {} //某个input验证时的回调函数
};
var ValidatorDefaultOptions = function(){};
ValidatorDefaultOptions.prototype = {
ignoreEmptyValue : true, //是否忽略空值
depends : [] //相关依赖项
};
Validator = Class.create();
ValidationUtils = {
getReferenceForm : function(elm) {
while(elm && elm.tagName != 'BODY') {
if(elm.tagName == 'FORM') return elm;
elm = elm.parentNode;
}
return null;
},
getInputValue : function(elm) {
var elm = $(elm);
if(elm.type.toLowerCase() == 'file') {
return elm.value;
}else {
return $F(elm);
}
},
getElmID : function(elm) {
return elm.id ? elm.id : elm.name;
},
format : function(str,args) {
args = args || [];
ValidationUtils.assert(args.constructor == Array,"ValidationUtils.format() arguement 'args' must is Array");
var result = str;
for (var i = 0; i < args.length; i++){
result = result.replace(/%s/, args[i]);
}
return result;
},
// 通过classname传递的参数必须通过'-'分隔各个参数
// 返回值包含一个参数singleArgument,例:validate-pattern-/[a-c]/gi,singleArgument值为/[a-c]/gi
getArgumentsByClassName : function(prefix,className) {
if(!className || !prefix)
return [];
var pattern = new RegExp(prefix+'-(\\S+)');
var matchs = className.match(pattern);
if(!matchs)
return [];
var results = [];
results.singleArgument = matchs[1];
var args = matchs[1].split('-');
for(var i = 0; i < args.length; i++) {
if(args[i] == '') {
if(i+1 < args.length) args[i+1] = '-'+args[i+1];
}else{
results.push(args[i]);
}
}
return results;
},
assert : function(condition,message) {
var errorMessage = message || ("assert failed error,condition="+condition);
if (!condition) {
alert(errorMessage);
throw new Error(errorMessage);
}else {
return condition;
}
},
isDate : function(v,dateFormat) {
var MONTH = "MM";
var DAY = "dd";
var YEAR = "yyyy";
var regex = '^'+dateFormat.replace(YEAR,'\\d{4}').replace(MONTH,'\\d{2}').replace(DAY,'\\d{2}')+'$';
if(!new RegExp(regex).test(v)) return false;
var year = v.substr(dateFormat.indexOf(YEAR),4);
var month = v.substr(dateFormat.indexOf(MONTH),2);
var day = v.substr(dateFormat.indexOf(DAY),2);
var d = new Date(ValidationUtils.format('%s/%s/%s',[year,month,day]));
return ( parseInt(month, 10) == (1+d.getMonth()) ) &&
(parseInt(day, 10) == d.getDate()) &&
(parseInt(year, 10) == d.getFullYear() );
},
getLanguage : function() {
var lang = null;
if (typeof navigator.userLanguage == 'undefined')
lang = navigator.language.toLowerCase();
else
lang = navigator.userLanguage.toLowerCase();
return lang;
},
getMessageSource : function() {
var lang = ValidationUtils.getLanguage();
var messageSource = Validator.messageSource['zh-cn'];
if(Validator.messageSource[lang]) {
messageSource = Validator.messageSource[lang];
}
return messageSource;
}
};
Validator.messages = {
'validation-failed' : '验证失败.',
'required' : '请填写值.',
'validate-number' : '请填写有效的数字.',
'validate-digits' : '请填写数字.',
'validate-alpha' : '请填写英文字母.',
'validate-alphanum' : '请填写英文字母或是数字,其它字符是不允许的.',
'validate-email' : '请填写有效的邮件地址,只能使用a-z A-Z 0-9 _ . -\',如 username@example.com。 ',
'validate-url' : '请填写有效的URL地址.',
'validate-currency-dollar' : 'Please enter a valid $ amount. For example $100.00 .',
'validate-one-required' : '在上面选项至少选择一个.',
'validate-integer' : '请填写正确的整数',
'validate-pattern' : '填写的值不匹配',
'validate-ip' : '请填写正确的IP地址',
'min-value' : '最小值为%s',
'max-value' : '最大值为%s',
'min-length' : '最小长度为%s,当前长度为%s.',
'max-length' : '最大长度为%s,当前长度为%s.',
'int-range' : '填写值应该为 %s 至 %s 的整数',
'float-range' : '填写值应该为 %s 至 %s 的数字',
'length-range' : '填写值的长度应该在 %s 至 %s 之间,当前长度为%s',
'equals' : '两次填写不一致,请重新填写',
'less-than' : '请填写小于前面的值',
'great-than' : '请填写大于前面的值',
'validate-date' : '请填写有效的日期,格式为 %s. 例如:%s.',
'validate-file' : function(v,elm,args,metadata) {
return ValidationUtils.format("文件类型应该为[%s]其中之一",[args.join(',')]);
},
'validate-id-number' : '请填写合法的身份证号码',
'validate-chinese' : '请填写中文',
'validate-phone' : '请填写正确的电话号码,如:021-87654321,当前长度为%s.',
'validate-mobile-phone' : '请填写正确的手机号码,当前长度为%s.',
'validate-zip' : '请填写有效的邮政编码',
'validate-qq' : '请填写有效的QQ号码.',
'validate-richeditor' : '请填写值.',
'validate-combobox' : '请填写值或选取前面的选项.',
'max-tag' : '请填写1-%s个Tag.'
};
Validator.bad_words=[/fuck/i,/shit/i,/QQ群/i,/MSN群/i,/求(助|救)/,/(跪|裸)求/,/急急|我很急|紧急寻求/,/在线等/,/救(命|我|急|救)/,/急(!|)/,/(高手|高人|大虾|大侠|达人|前辈|快来|没有人)(指点|解答|帮忙|帮帮|指教|赐教|提点|不吝赐教|到哪)/,/(我是|帮帮)(新手|小弟|菜鸟)/,/帮帮忙/, /万分火急/, /我顶|顶上去|好贴要顶|帮顶|看看先|顶一下/,/有*没有人(回答|帮忙|关注|知道啊|回复)/,/教主|装B|装13/,/关注(ing|中)/i,/收藏先/,/先收藏/,/收藏了/,/图书兼职作者/,/谢谢楼主/,/传智播客/,/FineReport/i];
Validator.prototype = {
initialize : function(className, test, options) {
this.options = Object.extend(new ValidatorDefaultOptions(), options || {});
this._test = test ? test : function(v,elm){ return true; };
this._error = Validator.messages[className] ? Validator.messages[className] : Validator.messages['validation-failed'];
this.className = className;
this._dependsTest = this._dependsTest.bind(this);
this._getDependError = this._getDependError.bind(this);
},
_dependsTest : function(v,elm) {
if(this.options.depends && this.options.depends.length > 0) {
var dependsResult = $A(this.options.depends).all(function(depend){
return Validation.get(depend).test(v,elm);
});
return dependsResult;
}
return true;
},
test : function(v, elm) {
if(!this._dependsTest(v,elm))
return false;
if(!elm) elm = {};
return (this.options.ignoreEmptyValue && ((v == null) || (v.length == 0))) || this._test(v,elm,ValidationUtils.getArgumentsByClassName(this.className,elm.className),this);
},
_getDependError : function(v,elm,useTitle) {
var dependError = null;
$A(this.options.depends).any(function(depend){
var validation = Validation.get(depend);
if(!validation.test(v,elm)) {
dependError = validation.error(v,elm,useTitle);
return true;
}
return false;
});
return dependError;
},
error : function(v,elm,useTitle) {
var dependError = this._getDependError(v,elm,useTitle);
if(dependError != null) return dependError;
var args = ValidationUtils.getArgumentsByClassName(this.className,elm.className);
var error = this._error;
if(typeof error == 'string') {
if(v) args.push(v.length);
error = ValidationUtils.format(this._error,args);
}else if(typeof error == 'function') {
error = error(v,elm,args,this);
}else {
alert('property "_error" must type of string or function');
}
if(!useTitle) useTitle = elm.className.indexOf('useTitle') >= 0;
return useTitle ? ((elm && elm.title) ? elm.title : error) : error;
}
};
var Validation = Class.create();
Validation.prototype = {
initialize : function(form, options){
this.options = Object.extend(new ValidationDefaultOptions(), options || {});
this.form = $(form);
var formId = ValidationUtils.getElmID($(form));
Validation.validations[formId] = this;
if(this.options.onSubmit) Event.observe(this.form,'submit',this.onSubmit.bind(this),false);
if(this.options.immediate) {
var useTitles = this.options.useTitles;
var callback = this.options.onElementValidate;
Form.getElements(this.form).each(function(input) { // Thanks Mike!
Event.observe(input, 'blur', function(ev) { Validation.validateElement(Event.element(ev),{useTitle : useTitles, onElementValidate : callback}); });
});
}
},
onSubmit : function(ev){
if(this.form.spinner && this.form.spinner.visible()) {
Event.stop(ev);
}else if(!this.validate()) {
Event.stop(ev);
}else {
Event.observe(this.form,'submit',function(e){Event.stop(e);}.bind(this.form),false);
if(this.form.spinner) {
this.form.spinner.show();
}else{
this.form.spinner = $(document.createElement("img"));
this.form.spinner.className = 'spinner_img';
this.form.spinner.src = 'http://www.iteye.com/images/spinner.gif';
Element.insert(this.form.select('input.submit')[0], {"after" : this.form.spinner});
}
}
},
validate : function() {
var result = false;
var useTitles = this.options.useTitles;
var callback = this.options.onElementValidate;
if(this.options.stopOnFirst) {
result = Form.getElements(this.form).all(function(elm) { return Validation.validateElement(elm,{useTitle : useTitles, onElementValidate : callback}); });
} else {
result = Form.getElements(this.form).collect(function(elm) { return Validation.validateElement(elm,{useTitle : useTitles, onElementValidate : callback}); }).all();
}
if(!result && this.options.focusOnError) {
var first = Form.getElements(this.form).findAll(function(elm){return $(elm).hasClassName('validation-failed');}).first();
try{
if(first.select) first.select();
first.focus();
}catch(e){}
}
this.options.onFormValidate(result, this.form);
return result;
}
};
Object.extend(Validation, {
validateElement : function(elm, options){
options = Object.extend({
useTitle : false,
onElementValidate : function(result, elm) {}
}, options || {});
elm = $(elm);
var cn = elm.classNames();
return cn.all(function(value) {
var test = Validation.test(value,elm,options.useTitle);
options.onElementValidate(test, elm);
return test;
});
},
showErrorMsg : function(name,elm,errorMsg) {
if(!elm.tooltip) elm.tooltip = new Tooltip(elm, {backgroundColor: "#FC9", borderColor: "#C96", textColor: "#000", textShadowColor: "#FFF"});
elm.tooltip.content = errorMsg;
elm.removeClassName('validation-passed');
elm.addClassName('validation-failed');
},
showErrorMsgByValidator : function(name,elm,useTitle) {
Validation.showErrorMsg(name,elm,Validation.get(name).error(ValidationUtils.getInputValue(elm),elm,useTitle));
},
hideErrorMsg : function(name,elm) {
if(elm.tooltip) {
elm.tooltip.stop();
elm.tooltip = false;
}
elm.removeClassName('validation-failed');
elm.addClassName('validation-passed');
},
test : function(name, elm, useTitle) {
var v = Validation.get(name);
if(!v.test(ValidationUtils.getInputValue(elm),elm)) {
Validation.showErrorMsgByValidator(name,elm,useTitle);
return false;
} else {
Validation.hideErrorMsg(name,elm);
return true;
}
},
getAdvice : function(name, elm) {
return Try.these(
function(){ return $('advice-' + name + '-' + ValidationUtils.getElmID(elm)); },
function(){ return $('advice-' + ValidationUtils.getElmID(elm)); }
);
},
add : function(className, test, options) {
var nv = {};
var testFun = test;
if(test instanceof RegExp)
testFun = function(v,elm,args,metadata){ return test.test(v); };
nv[className] = new Validator(className, testFun, options);
Object.extend(Validation.methods, nv);
},
addAllThese : function(validators) {
$A(validators).each(function(value) {
Validation.add(value[0], value[1], (value.length > 2 ? value[2] : {}));
});
},
get : function(name) {
var resultMethodName;
for(var methodName in Validation.methods) {
if(name == methodName) {
resultMethodName = methodName;
break;
}
if(name.indexOf(methodName) >= 0) {
resultMethodName = methodName;
}
}
return Validation.methods[resultMethodName] ? Validation.methods[resultMethodName] : new Validator();
},
$ : function(formId) {
return Validation.validations[formId];
},
methods : {},
validations : {}
});
Validation.addAllThese([
['required', function(v) {
return !((v == null) || (v.length == 0) || /^[\s|\u3000]+$/.test(v));
},{ignoreEmptyValue:false}],
['validate-number', function(v) {
return (!isNaN(v) && !/^\s+$/.test(v));
}],
['validate-digits', function(v) {
return !/[^\d]/.test(v);
}],
['validate-alphanum', function(v) {
return !/\W/.test(v);
}],
['validate-one-required', function (v,elm) {
var p = elm.parentNode;
var options = p.getElementsByTagName('INPUT');
return $A(options).any(function(elm) {
return $F(elm);
});
},{ignoreEmptyValue : false}],
['validate-digits',/^[\d]+$/],
['validate-alphanum',/^[a-zA-Z0-9]+$/],
['validate-alpha',/^[a-zA-Z]+$/],
['validate-email',/^[\w.+-]+@(?:[-a-z0-9]+\.)+[a-z]{2,4}$/i],
['validate-url',/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i],
// [$]1[##][,###]+[.##]
// [$]1###+[.##]
// [$]0.##
// [$].##
['validate-currency-dollar',/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/]
]);
//custom validate start
Validation.addAllThese([
/**
* Usage : equals-$otherInputId
* Example : equals-username or equals-email etc..
*/
['equals', function(v,elm,args,metadata) {
return $F(args[0]) == v;
},{ignoreEmptyValue:false}],
/**
* Usage : less-than-$otherInputId
*/
['less-than', function(v,elm,args,metadata) {
if(Validation.get('validate-number').test(v) && Validation.get('validate-number').test($F(args[0])))
return parseFloat(v) < parseFloat($F(args[0]));
return v < $F(args[0]);
}],
/**
* Usage : great-than-$otherInputId
*/
['great-than', function(v,elm,args,metadata) {
if(Validation.get('validate-number').test(v) && Validation.get('validate-number').test($F(args[0])))
return parseFloat(v) > parseFloat($F(args[0]));
return v > $F(args[0]);
}],
/*
* Usage: min-length-$number
* Example: min-length-10
*/
['min-length',function(v,elm,args,metadata) {
return v.length >= parseInt(args[0]);
}],
/*
* Usage: max-length-$number
* Example: max-length-10
*/
['max-length',function(v,elm,args,metadata) {
return v.length <= parseInt(args[0]);
}],
/*
* Usage: validate-file-$type1-$type2-$typeX
* Example: validate-file-png-jpg-jpeg
*/
['validate-file',function(v,elm,args,metadata) {
return $A(args).any(function(extentionName) {
return new RegExp('\\.'+extentionName+'$','i').test(v);
});
}],
/*
* Usage: float-range-$minValue-$maxValue
* Example: -2.1 to 3 = float-range--2.1-3
*/
['float-range',function(v,elm,args,metadata) {
return (parseFloat(v) >= parseFloat(args[0]) && parseFloat(v) <= parseFloat(args[1]));
},{depends : ['validate-number']}],
/*
* Usage: int-range-$minValue-$maxValue
* Example: -10 to 20 = int-range--10-20
*/
['int-range',function(v,elm,args,metadata) {
return (parseInt(v) >= parseInt(args[0]) && parseInt(v) <= parseInt(args[1]));
},{depends : ['validate-integer']}],
/*
* Usage: length-range-$minLength-$maxLength
* Example: 10 to 20 = length-range-10-20
*/
['length-range',function(v,elm,args,metadata) {
return (v.length >= parseInt(args[0]) && v.length <= parseInt(args[1]));
}],
/*
* Usage: max-value-$number
* Example: max-value-10
*/
['max-value',function(v,elm,args,metadata) {
return parseFloat(v) <= parseFloat(args[0]);
},{depends : ['validate-number']}],
/*
* Usage: min-value-$number
* Example: min-value-10
*/
['min-value',function(v,elm,args,metadata) {
return parseFloat(v) >= parseFloat(args[0]);
},{depends : ['validate-number']}],
/*
* Usage: validate-pattern-$RegExp
* Example: <input id='sex' class='validate-pattern-/^[fm]$/i'>
*/
['validate-pattern',function(v,elm,args,metadata) {
return eval('('+args.singleArgument+'.test(v))');
}],
/*
* Usage: validate-ajax-$url
* Example: <input id='email' class='validate-ajax-http://localhost:8080/validate-email.jsp'>
*/
['validate-ajax',function(v,elm,args,metadata) {
var form = ValidationUtils.getReferenceForm(elm);
var params = (form ? Form.serialize(form) : Form.Element.serialize(elm));
params += ValidationUtils.format("&what=%s&value=%s",[elm.name,encodeURIComponent(v)]);
var request = new Ajax.Request(args.singleArgument,{
parameters : params,
asynchronous : false,
method : "post"
});
var responseText = request.transport.responseText;
if("" == responseText.strip()) return true;
metadata._error = responseText;
return false;
}],
/*
* Usage: validate-date-$dateFormat or validate-date($dateFormat default is yyyy-MM-dd)
* Example: validate-date-yyyy/MM/dd
*/
['validate-date', function(v,elm,args,metadata) {
var dateFormat = args.singleArgument || 'yyyy-MM-dd';
metadata._error = ValidationUtils.format(Validator.messages[metadata.className],[dateFormat,dateFormat.replace('yyyy','2006').replace('MM','03').replace('dd','12')]);
return ValidationUtils.isDate(v,dateFormat);
}],
['validate-integer',/^[-+]?[1-9]\d*$|^0$/],
['validate-ip',/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/],
//中国相关验证开始
['validate-id-number',function(v,elm,args,metadata) {
if(!(/^\d{17}(\d|x)$/i.test(v) || /^\d{15}$/i.test(v))) return false;
var provinceCode = parseInt(v.substr(0,2));
if((provinceCode < 11) || (provinceCode > 91)) return false;
var forTestDate = v.length == 18 ? v : v.substr(0,6)+"19"+v.substr(6,15);
var birthday = forTestDate.substr(6,8);
if(!ValidationUtils.isDate(birthday,'yyyyMMdd')) return false;
if(v.length == 18) {
v = v.replace(/x$/i,"a");
var verifyCode = 0;
for(var i = 17;i >= 0;i--)
verifyCode += (Math.pow(2,i) % 11) * parseInt(v.charAt(17 - i),11);
if(verifyCode % 11 != 1) return false;
}
return true;
}],
['validate-chinese',/^[\u4e00-\u9fa5]+$/],
['validate-phone',/^((0[1-9]{3})?(0[12][0-9])?[-])?\d{6,8}$/],
['validate-mobile-phone',/(^0?[1][35][0-9]{9}$)/],
['validate-zip',/^[1-9]\d{5}$/],
['validate-qq',/^[1-9]\d{4,8}$/],
//javaeye added
['validate-richeditor', function(v, elm) {
if(editor.mode == "rich") {
v = tinyMCE.activeEditor.getContent().stripTags().replace(/&nbsp;/g,' ');
}
return !((v == null) || (v.length == 0) || /^[\s|\u3000]+$/.test(v));
},{ignoreEmptyValue:false}],
['bad-words', function(v) {
for (var i=0; i < Validator.bad_words.length; i++) {
var m = v.match(Validator.bad_words[i]);
if (m) {
alert("ITeye发贴提示\n\nITeye网站不允许您使用 \"" + m[0] + "\" 这样的词汇发贴!\n\n您很可能违反了网站规则请仔细阅读并遵守网站规则否则将被扣分删贴。\n\n");
return false;
}}
return true;
}],
['validate-combobox', function(v, elm, args) {
var v = $F(args[0]);
return Validation.get('required').test(elm.value) || Validation.get('required').test(v);
},{ignoreEmptyValue:false}],
/*
* Usage: max-tag-$number
* Example: max-tag-3
*/
['max-tag', function(v, elm, args){
return v.replace(/^\s+|\s+$/g, '').split(/,\s*|\s*/).length <= parseInt(args[0]);
}]
]);