﻿/*
$.jbecool.validator类
支持多个表单的校验。
内置$.jbecool._validator对象，包含大量校验方法，可独立使用。

需要校验的表单需要设置校验器的唯一名称：
<form validatorName="vn1">...</form>
接下来撰写代码：
var vd1=$.jbecool.validators.getValidator("vn1");   //得到校验器
vd1.validate(); //进行校验
vd1.isAllValid; //判断是否全部合法

每个错误的提示可单独设定对应的label以显示错误，特别适合一个元素需要同时满足多个条件的情况
可通过byCallBack来实现调用某个函数判断是否合法，例如判断用户名是否已存在
@author:jerry
@version:1.0
*/
(function ($) {
    $.jbecool.validators = [];
    $.jbecool.validators.getValidator = function (validatorName) {
        for (var i = 0; i < $.jbecool.validators.length; i++) {
            if ($.jbecool.validators[i].name == validatorName)
                return $.jbecool.validators[i].validator;
        }
        return null;
    };

    $.jbecool._validator = {
        //下面所有函数的返回值：成功true，失败false

        //元素、对比值，对于普通元素，判断是否为空，对于下拉框，判断是否为value
        //class='.required'
        required: function (elementValue, value) {
            if (!value)
                return $.trim(elementValue).length > 0;
            else
                return elementValue != value;
        },
        //class='.minlength' attr=[minlength=12]
        minlength: function (value, param) {
            return $.trim(value).length == 0 || ($.trim(value)).length >= param;
        },
        //class='.maxlength' attr=[maxlength=12]
        maxlength: function (value, param) {
            return $.trim(value).length == 0 || ($.trim(value)).length <= param;
        },
        //class='.rangelength' attr=[start=12,end=22]
        //请输入一个长度介于 start 和 end之间的字符串
        rangelength: function (value, fromlength, tolength) {
            return $.trim(value).length == 0 || (value.toString().length >= fromlength && value.toString().length <= tolength);
        },
        //class='.min' attr=[min=12]
        min: function (elementValue, value) {
            return $.trim(value).length == 0 || Number(elementValue) >= Number(value);
        },
        //class='.max' attr=[max=12]
        max: function (value, param) {
            return $.trim(value).length == 0 || Number(value) <= Number(param);
        },
        //class='.range' attr=[start=12,end=22]
        //请输入一个介于 start 和 end之间的值
        range: function (value, from, to) {
            return $.trim(value).length == 0 || (Number(value) >= Number(from) && Number(value) <= Number(to));
        },
        //class='.email'
        email: function (elementValue) {
            return $.trim(elementValue).length == 0 || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(elementValue);
        },
        //class='.url'
        //输入一个网址
        url: function (value) {
            return $.trim(value).length == 0 || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
        },
        //class='.date'
        //输入一个日期
        date: function (value) {
            return $.trim(value).length == 0 || !/Invalid|NaN/.test(new Date(value));
        },
        //class='.dateISO'
        //请输入合法的日期 (ISO)
        dateISO: function (value) {
            return $.trim(value).length == 0 || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
        },
        //class='.number'
        number: function (value) {
            return $.trim(value).length == 0 || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
        },
        //class='.digits'
        digits: function (value) {
            return $.trim(value).length == 0 || /^\d+$/.test(value);
        },

        //class='.accept' attr=[accept=jpg]
        //用于文件域，判断可以上传的文件类型，默认是图片类型
        accept: function (value, param) {
            param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
            return value.match(new RegExp(".(" + param + ")$", "i"));
        },

        //class='equalTo' attr=[equalTo=比对元素]
        equalTo: function (value1, value2) {
            return value1 == value2;
        },
        //class='byCallBack',attr=[CallBack="函数名"]
        byCallBack: function (result) {
            return result;
        }
    };
})(jQuery);

(function ($) {
    $.jbecool.validator = function (myform) {
        var _self = this;

        //是否全有效
        this.isAllValid = false;
        //对应的元素集合
        this.elements = [];
        //对应父级对象，一般是表单
        this.frm = myform;


        //初始化
        this.init = function () {
            //隐藏所有的提示Label
            $("[tolabel]",this.frm).each(function () {
                $("#" + $(this).attr("tolabel")).hide();
            });
            //隐藏requiredToLabel的提示
            $("[requiredToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("requiredToLabel")).hide();
            });
            //隐藏emailToLabel的提示
            $("[emailToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("emailToLabel")).hide();
            });
            //隐藏minToLabel的提示
            $("[minToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("minToLabel")).hide();
            });
            //隐藏maxToLabel的提示
            $("[maxToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("maxToLabel")).hide();
            });
            //隐藏digitsToLabel的提示
            $("[digitsToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("digitsToLabel")).hide();
            });
            //隐藏numberToLabel的提示
            $("[numberToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("numberToLabel")).hide();
            });
            //隐藏dateToLabel的提示
            $("[dateToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("dateToLabel")).hide();
            });
            //隐藏urlToLabel的提示
            $("[urlToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("urlToLabel")).hide();
            });
            //隐藏dateISOToLabel的提示
            $("[dateISOToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("dateISOToLabel")).hide();
            });
            //隐藏acceptToLabel的提示
            $("[acceptToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("acceptToLabel")).hide();
            });
            //隐藏minlengthToLabel的提示
            $("[minlengthToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("minlengthToLabel")).hide();
            });
            //隐藏maxlengthToLabel的提示
            $("[maxlengthToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("maxlengthToLabel")).hide();
            });
            //隐藏rangelengthToLabel的提示
            $("[rangelengthToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("rangelengthToLabel")).hide();
            });
            //隐藏rangeToLabel的提示
            $("[rangeToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("rangeToLabel")).hide();
            });
            //隐藏equalToToLabel的提示
            $("[equalToToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("equalToToLabel")).hide();
            });
            //隐藏byCallBackToLabel的提示
            $("[byCallBackToLabel]",this.frm).each(function () {
                $("#" + $(this).attr("byCallBackToLabel")).hide();
            });
            $(" .required",_self.frm).each(
                function () {
                    _self.pushElement($(this));
                    $(this).blur(
                    function () {
                        _self.showError($(this), $.jbecool._validator.required($(this).val()), $(this).attr('requiredToLabel'));
                    });
                });

            $(" .email",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.email($(this).val()), $(this).attr('emailToLabel'));
                });
            });
            $(" .min",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.min($(this).val(), $(this).attr("min")), $(this).attr('minToLabel'));
                });
            });
            $(" .max",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.max($(this).val(), $(this).attr("max")), $(this).attr('maxToLabel'));
                });
            });
            $(" .digits",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.digits($(this).val()), $(this).attr('digitsToLabel'));
                });
            });

            $(" .number",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.number($(this).val()), $(this).attr('numberToLabel'));
                });
            });
            $(" .date",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.date($(this).val()), $(this).attr('dateToLabel'));
                });
            });
            $(" .url",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.url($(this).val()), $(this).attr('urlToLabel'));
                });
            });
            $(" .dateISO",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.dateISO($(this).val()), $(this).attr('dateISOToLabel'));
                });
            });
            $(" .accept",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.accept($(this).val(), $(this).attr("accept")), $(this).attr('acceptToLabel'));
                });
            });
            $(" .minlength",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.minlength($(this).val(), $(this).attr("minlength")), $(this).attr('minlengthToLabel'));
                });
            });
            $(" .maxlength",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.maxlength($(this).val(), $(this).attr("maxlength")), $(this).attr('maxlengthToLabel'));
                });
            });
            $(" .rangelength",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.rangelength($(this).val(), $(this).attr("fromlength"), $(this).attr("tolength")), $(this).attr('rangelengthToLabel'));
                });
            });
            $(" .range",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.range($(this).val(), $(this).attr("from"), $(this).attr("to")), $(this).attr('rangeToLabel'));
                });
            });
            $(" .equalTo",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(
                function () {
                    _self.showError($(this), $.jbecool._validator.equalTo($("#" + $(this).attr("equalTo")).val(), $(this).val()), $(this).attr('equalToToLabel'));
                });
            });
            $(" .byCallBack",_self.frm).each(
            function () {
                _self.pushElement($(this));
                $(this).blur(function () {
                    var res = eval($(this).attr("CallBack"));
                    self.showError($(this), $.jbecool._validator.byCallBack(res), $(this).attr('byCallBackToLabel'));
                });
            });
        };
        //获取校验结果，在showError里面调用
        this.refreshResult = function () {
            for (var i = 0; i < _self.elements.length; i++) {
                var errors = parseInt(_self.elements[i].attr("errors"));
                if (isNaN(errors))
                    continue;
                else
                    if (errors > 0)
                        return false;
            }
            return true;
        };
        //压入要校验的元素
        this.pushElement = function (element) {
            //errors表示有多少个错误，每个校验器校验失效为一个错误，有些元素有多个校验器
            var errors = parseInt(element.attr("errors"));
            if (isNaN(errors))
                errors = 1;
            else
                errors++;
            //共有多少个校验器
            var validators = parseInt(element.attr("validators"));
            if (isNaN(validators))
                validators = 1;
            else
                validators++;

            element.attr("errors", errors);
            element.attr("validators", validators);
            _self.elements[_self.elements.length] = element;
        };
        //显示和隐藏错误
        this.showError = function (element, isValid, toLabel) {
            var _tolabel;
            if (toLabel == undefined || toLabel == null)
                _tolabel = $("#" + element.attr("tolabel"));
            else
                _tolabel = $("#" + toLabel);

            var errors = parseInt(element.attr("errors"));
            var validators = parseInt(element.attr("validators"));

            if (isValid == true) {
                errors--;
                if (errors < 0) errors = 0;
                if (errors == 0)
                    element.removeClass("errorElement");
                _tolabel.removeClass("errorLabel").hide();

            } else {
                errors++;
                if (errors > validators) errors = validators;
                element.addClass("errorElement");
                _tolabel.addClass("errorLabel").show();
            }

            element.attr("errors", errors);

            _self.isAllValid = _self.refreshResult();
        };

        //外部调用来主动验证
        this.validate = function () {
            _self.frm.focus()
            for (var i = 0; i < _self.elements.length; i++) {
                //触发验证
                _self.elements[i].trigger("blur");
            }
        };

        this.init();
    }
})(jQuery);

$(function () {
    $("form").each(
        function () {
            if (!$.jbecool.isNullOrEmpty($(this).attr("validatorName"))) {
                $.jbecool.validators.push(
                {
                    name: $(this).attr("validatorName"),
                    validator: new $.jbecool.validator($(this))
                });
            }
        }
    );
});
