| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141 | /*! nice-validator 1.1.5 * (c) 2012-2020 Jony Zhang <niceue@live.com>, MIT Licensed * https://github.com/niceue/nice-validator */;(function(factory) {    typeof module === 'object' && module.exports ? module.exports = factory( require( 'jquery' ) ) :    typeof define === 'function' && define.amd ? define(['jquery'], factory) :    factory(jQuery);}(function($, undefined) {    'use strict';    var NS = 'validator',        CLS_NS = '.' + NS,        CLS_NS_RULE = '.rule',        CLS_NS_FIELD = '.field',        CLS_NS_FORM = '.form',        CLS_WRAPPER = 'nice-' + NS,        CLS_MSG_BOX = 'msg-box',        ARIA_INVALID = 'aria-invalid',        DATA_RULE = 'data-rule',        DATA_MSG = 'data-msg',        DATA_TIP = 'data-tip',        DATA_OK = 'data-ok',        DATA_TIMELY = 'data-timely',        DATA_TARGET = 'data-target',        DATA_DISPLAY = 'data-display',        DATA_MUST = 'data-must',        NOVALIDATE = 'novalidate',        INPUT_SELECTOR = ':verifiable',        rRules = /(&)?(!)?\b(\w+)(?:\[\s*(.*?\]?)\s*\]|\(\s*(.*?\)?)\s*\))?\s*(;|\|)?/g,        rRule = /(\w+)(?:\[\s*(.*?\]?)\s*\]|\(\s*(.*?\)?)\s*\))?/,        rDisplay = /(?:([^:;\(\[]*):)?(.*)/,        rDoubleBytes = /[^\x00-\xff]/g,        rPos = /top|right|bottom|left/,        rAjaxType = /(?:(cors|jsonp):)?(?:(post|get):)?(.+)/i,        rUnsafe = /[<>'"`\\]|&#x?\d+[A-F]?;?|%3[A-F]/gmi,        noop = $.noop,        proxy = $.proxy,        trim = $.trim,        isFunction = $.isFunction,        isString = function(s) {            return typeof s === 'string';        },        isObject = function(o) {            return o && Object.prototype.toString.call(o) === '[object Object]';        },        isIE = document.documentMode || +(navigator.userAgent.match(/MSIE (\d+)/) && RegExp.$1),        attr = function(el, key, value) {            if (!el || !el.tagName) return null;            if (value !== undefined) {                if (value === null) el.removeAttribute(key);                else el.setAttribute(key, '' + value);            } else {                return el.getAttribute(key);            }        },        novalidateonce,        preinitialized = {},        defaults = {            debug: 0,            theme: 'default',            ignore: '',            focusInvalid: true,            focusCleanup: false,            stopOnError: false,            beforeSubmit: null,            valid: null,            invalid: null,            validation: null,            formClass: 'n-default',            validClass: 'n-valid',            invalidClass: 'n-invalid',            bindClassTo: null        },        fieldDefaults = {            timely: 1,            display: null,            target: null,            ignoreBlank: false,            showOk: true,            // Translate ajax response to validation result            dataFilter: function (data) {                if ( isString(data) || ( isObject(data) && ('error' in data || 'ok' in data) ) ) {                    return data;                }            },            msgMaker: function(opt) {                var html;                html = '<span role="alert" class="msg-wrap n-'+ opt.type + '">' + opt.arrow;                if (opt.result) {                    $.each(opt.result, function(i, obj){                        html += '<span class="n-'+ obj.type +'">' + opt.icon + '<span class="n-msg">' + obj.msg + '</span></span>';                    });                } else {                    html += opt.icon + '<span class="n-msg">' + opt.msg + '</span>';                }                html += '</span>';                return html;            },            msgWrapper: 'span',            msgArrow: '',            msgIcon: '<span class="n-icon"></span>',            msgClass: 'n-right',            msgStyle: '',            msgShow: null,            msgHide: null        },        themes = {};    /** jQuery Plugin     * @param {Object} options        debug         {Boolean}     0               Whether to enable debug mode        timely        {Number}      1               Whether to enable timely validation        theme         {String}     'default'        Theme name        stopOnError   {Boolean}     false           Whether to stop validate when found an error input        focusCleanup  {Boolean}     false           Whether to clean up the field message when focus the field        focusInvalid  {Boolean}     true            Whether to focus the field that is invalid        ignoreBlank   {Boolean}     false           When the field has no value, whether to ignore validation        ignore        {jqSelector}    ''            Ignored fields (Using jQuery selector)        beforeSubmit  {Function}                    Do something before submit form        dataFilter    {Function}                    Convert ajax results        valid         {Function}                    Triggered when the form is valid        invalid       {Function}                    Triggered when the form is invalid        validClass    {String}      'n-valid'       Add this class name to a valid field        invalidClass  {String}      'n-invalid'     Add this class name to a invalid field        bindClassTo   {jqSelector}  ':verifiable'   Which element should the className binding to        display       {Function}                    Callback function to get dynamic display        target        {Function}                    Callback function to get dynamic target        msgShow       {Function}                    Trigger this callback when show message        msgHide       {Function}                    Trigger this callback when hide message        msgWrapper    {String}      'span'          Message wrapper tag name        msgMaker      {Function}                    Callback function to make message HTML        msgArrow      {String}                      Message arrow template        msgIcon       {String}                      Message icon template        msgStyle      {String}                      Custom message css style        msgClass      {String}                      Additional added to the message class names        formClass     {String}                      Additional added to the form class names        messages      {Object}                      Custom messages for the current instance        rules         {Object}                      Custom rules for the current instance        fields        {Object}                      Field validation configuration        {String}        key    name|#id        {String|Object} value                       Rule string or an object which can pass more arguments        fields[key][rule]       {String}            Rule string        fields[key][display]    {String|Function}        fields[key][tip]        {String}            Custom tip message        fields[key][ok]         {String}            Custom success message        fields[key][msg]        {Object}            Custom error message        fields[key][msgStyle]   {String}            Custom message style        fields[key][msgClass]   {String}            A className which added to message placeholder element        fields[key][msgWrapper] {String}            Tag name of the message placeholder element        fields[key][msgMaker]   {Function}          A function to custom message HTML        fields[key][dataFilter] {Function}          A function to convert ajax results        fields[key][valid]      {Function}          A function triggered when field is valid        fields[key][invalid]    {Function}          A function triggered when field is invalid        fields[key][must]       {Boolean}           If set true, we always check the field even has remote checking        fields[key][timely]     {Boolean}           Whether to enable timely validation        fields[key][target]     {jqSelector}        Define placement of a message     */    $.fn.validator = function(options) {        var that = this,            args = arguments;        if (that.is(INPUT_SELECTOR)) return that;        if (!that.is('form')) that = this.find('form');        if (!that.length) that = this;        that.each(function() {            var instance = $(this).data(NS);            if (instance) {                if ( isString(options) ) {                    if ( options.charAt(0) === '_' ) return;                    instance[options].apply(instance, [].slice.call(args, 1));                }                else if (options) {                    instance._reset(true);                    instance._init(this, options);                }            } else {                new Validator(this, options);            }        });        return this;    };    // Validate a field, or an area    $.fn.isValid = function(callback, hideMsg) {        var me = _getInstance(this[0]),            hasCallback = isFunction(callback),            ret, opt;        if (!me) return true;        if (!hasCallback && hideMsg === undefined) hideMsg = callback;        me.checkOnly = !!hideMsg;        opt = me.options;        ret = me._multiValidate(            this.is(INPUT_SELECTOR) ? this : this.find(INPUT_SELECTOR),            function(isValid){                if (!isValid && opt.focusInvalid && !me.checkOnly) {                    // navigate to the error element                    me.$el.find('[' + ARIA_INVALID + ']:first').focus();                }                if (hasCallback) {                    if (callback.length) {                        callback(isValid);                    } else if (isValid) {                        callback();                    }                }                me.checkOnly = false;            }        );        // If you pass a callback, we maintain the jQuery object chain        return hasCallback ? this : ret;    };    $.extend($.expr.pseudos || $.expr[':'], {        // A faster selector than ":input:not(:submit,:button,:reset,:image,:disabled,[contenteditable])"        verifiable: function(elem) {            var name = elem.nodeName.toLowerCase();            return ( name === 'input' && !({submit: 1, button: 1, reset: 1, image: 1})[elem.type] ||                     name === 'select' ||                     name === 'textarea' ||                     elem.contentEditable === 'true'                    ) && !elem.disabled;        },        // any value, but not only whitespace        filled: function(elem) {            return !!trim($(elem).val());        }    });    /**     * Creates a new Validator     *     * @class     * @param {Element} element - form element     * @param {Object}  options - options for validator     */    function Validator(element, options) {        var me = this;        if ( !(me instanceof Validator) ) {            return new Validator(element, options);        }        if (Validator.pending) {            $(window).on('validatorready', init);        } else {            init();        }        function init() {            me.$el = $(element);            if (me.$el.length) {                me._init(me.$el[0], options);            }            else if (isString(element)) {                preinitialized[element] = options;            }        }    }    Validator.prototype = {        _init: function(element, options) {            var me = this,                opt, themeOpt, dataOpt;            // Initialization options            if ( isFunction(options) ) {                options = {                    valid: options                };            }            options = me._opt = options || {};            dataOpt = attr(element, 'data-'+ NS +'-option');            dataOpt = me._dataOpt = dataOpt && dataOpt.charAt(0) === '{' ? (new Function('return ' + dataOpt))() : {};            themeOpt = me._themeOpt = themes[ options.theme || dataOpt.theme || defaults.theme ];            opt = me.options = $.extend({}, defaults, fieldDefaults, themeOpt, me.options, options, dataOpt);            me.rules = new Rules(opt.rules, true);            me.messages = new Messages(opt.messages, true);            me.Field = _createFieldFactory(me);            me.elements = me.elements || {};            me.deferred = {};            me.errors = {};            me.fields = {};            // Initialization fields            me._initFields(opt.fields);            // Initialization events and make a cache            if ( !me.$el.data(NS) ) {                me.$el.data(NS, me).addClass(CLS_WRAPPER +' '+ opt.formClass)                    .on('form-submit-validate', function(e, a, $form, opts, veto) {                        me.vetoed = veto.veto = !me.isValid;                        me.ajaxFormOptions = opts;                    })                    .on('submit'+ CLS_NS +' validate'+ CLS_NS, proxy(me, '_submit'))                    .on('reset'+ CLS_NS, proxy(me, '_reset'))                    .on('showmsg'+ CLS_NS, proxy(me, '_showmsg'))                    .on('hidemsg'+ CLS_NS, proxy(me, '_hidemsg'))                    .on('focusin'+ CLS_NS + ' click'+ CLS_NS, INPUT_SELECTOR, proxy(me, '_focusin'))                    .on('focusout'+ CLS_NS +' validate'+ CLS_NS, INPUT_SELECTOR, proxy(me, '_focusout'))                    .on('keyup'+ CLS_NS +' input'+ CLS_NS + ' compositionstart compositionend', INPUT_SELECTOR, proxy(me, '_focusout'))                    .on('click'+ CLS_NS, ':radio,:checkbox', 'click', proxy(me, '_focusout'))                    .on('change'+ CLS_NS, 'select,input[type="file"]', 'change', proxy(me, '_focusout'));                // cache the novalidate attribute value                me._NOVALIDATE = attr(element, NOVALIDATE);                // Initialization is complete, stop off default HTML5 form validation                // If use "jQuery.attr('novalidate')" in IE7 will complain: "SCRIPT3: Member not found."                attr(element, NOVALIDATE, NOVALIDATE);            }            // Display all messages in target container            if ( isString(opt.target) ) {                me.$el.find(opt.target).addClass('msg-container');            }        },        // Guess whether the form use ajax submit        _guessAjax: function(form) {            var me = this;            if ( !(me.isAjaxSubmit = !!me.options.valid) ) {                // if there is a "valid.form" event                var events = ($._data || $.data)(form, 'events');                me.isAjaxSubmit = issetEvent(events, 'valid', 'form') || issetEvent(events, 'submit', 'form-plugin');            }            function issetEvent(events, name, namespace) {                return !!(                    events && events[name]                    && $.map(events[name], function(e){                        return ~e.namespace.indexOf(namespace) ? 1 : null;                    }).length )            }        },        _initFields: function(fields) {            var me = this, k, arr, i,                clear = fields === null;            // Processing field information            if (clear) fields = me.fields;            if ( isObject(fields) ) {                for (k in fields) {                    if (~k.indexOf(',')) {                        arr = k.split(',');                        i = arr.length;                        while (i--) {                            initField(trim(arr[i]), fields[k]);                        }                    } else {                        initField(k, fields[k]);                    }                }            }            // Parsing DOM rules            me.$el.find(INPUT_SELECTOR).each(function() {                me._parse(this);            });            function initField(k, v) {                // delete a field from settings                if ( v === null || clear ) {                    var el = me.elements[k];                    if (el) me._resetElement(el, true);                    delete me.fields[k];                } else {                    me.fields[k] = new me.Field(k, isString(v) ? {rule: v} : v, me.fields[k]);                }            }        },        // Parsing a field        _parse: function(el) {            var me = this,                field,                key = el.name,                display,                timely,                dataRule = attr(el, DATA_RULE);            dataRule && attr(el, DATA_RULE, null);            // If the field has passed the key as id mode, or it doesn't has a name            if ( el.id && (                ('#' + el.id in me.fields) ||                !key ||                // If dataRule and element are diffrent from old's, we use ID mode.                (dataRule !== null && (field = me.fields[key]) && dataRule !== field.rule && el.id !== field.key)                )            ) {                key = '#' + el.id;            }            // Generate id            if (!key) {                key = '#' + (el.id = 'N' + String(Math.random()).slice(-12));            }            field = me.getField(key, true);            // The priority of passing parameter by DOM is higher than by JS.            field.rule = dataRule || field.rule;            if (display = attr(el, DATA_DISPLAY)) {                field.display = display;            }            if (field.rule) {                if ( attr(el, DATA_MUST) !== null || /\b(?:match|checked)\b/.test(field.rule) ) {                    field.must = true;                }                if ( /\brequired\b/.test(field.rule) ) {                    field.required = true;                }                if (timely = attr(el, DATA_TIMELY)) {                    field.timely = +timely;                } else if (field.timely > 3) {                    attr(el, DATA_TIMELY, field.timely);                }                me._parseRule(field);                field.old = {};            }            if ( isString(field.target) ) {                attr(el, DATA_TARGET, field.target);            }            if ( isString(field.tip) ) {                attr(el, DATA_TIP, field.tip);            }            return me.fields[key] = field;        },        // Parsing field rules        _parseRule: function(field) {            var arr = rDisplay.exec(field.rule);            if (!arr) return;            // current rule index            field._i = 0;            if (arr[1]) {                field.display = arr[1];            }            if (arr[2]) {                field._rules = [];                arr[2].replace(rRules, function(){                    var args = arguments;                    args[4] = args[4] || args[5];                    field._rules.push({                        and: args[1] === '&',                        not: args[2] === '!',                        or:  args[6] === '|',                        method: args[3],                        params: args[4] ? $.map( args[4].split(', '), trim ) : undefined                    });                });            }        },        // Verify a zone        _multiValidate: function($inputs, doneCallback){            var me = this,                opt = me.options;            me.hasError = false;            if (opt.ignore) {                $inputs = $inputs.not(opt.ignore);            }            $inputs.each(function() {                me._validate(this);                if (me.hasError && opt.stopOnError) {                    // stop the validation                    return false;                }            });            // Need to wait for all fields validation complete, especially asynchronous validation            if (doneCallback) {                me.validating = true;                $.when.apply(                    null,                    $.map(me.deferred, function(v){return v;})                ).done(function(){                    doneCallback.call(me, !me.hasError);                    me.validating = false;                });            }            // If the form does not contain asynchronous validation, the return value is correct.            // Otherwise, you should detect form validation result through "doneCallback".            return !$.isEmptyObject(me.deferred) ? undefined : !me.hasError;        },        // Validate the whole form        _submit: function(e) {            var me = this,                opt = me.options,                form = e.target,                canSubmit = e.type === 'submit' && form.tagName === 'FORM' && !e.isDefaultPrevented();            e.preventDefault();            if (                novalidateonce && ~(novalidateonce = false) ||                // Prevent duplicate submission                me.submiting ||                // Receive the "validate" event only from the form.                e.type === 'validate' && me.$el[0] !== form ||                // trigger the beforeSubmit callback.                isFunction(opt.beforeSubmit) && opt.beforeSubmit.call(me, form) === false            ) {                return;            }            if (me.isAjaxSubmit === undefined) {                me._guessAjax(form);            }            me._debug('log', '\n<<< event: ' + e.type);            me._reset();            me.submiting = true;            me._multiValidate(                me.$el.find(INPUT_SELECTOR),                function(isValid){                    var ret = (isValid || opt.debug === 2) ? 'valid' : 'invalid',                        errors;                    if (!isValid) {                        if (opt.focusInvalid) {                            // navigate to the error element                            me.$el.find('[' + ARIA_INVALID + ']:first').focus();                        }                        errors = $.map(me.errors, function(err){return err;});                    }                    // releasing submit                    me.submiting = false;                    me.isValid = isValid;                    // trigger callback and event                    isFunction(opt[ret]) && opt[ret].call(me, form, errors);                    me.$el.trigger(ret + CLS_NS_FORM, [form, errors]);                    me._debug('log', '>>> ' + ret);                    if (!isValid) return;                    // For jquery.form plugin                    if (me.vetoed) {                        $(form).ajaxSubmit(me.ajaxFormOptions);                    }                    else if (canSubmit && !me.isAjaxSubmit) {                        document.createElement('form').submit.call(form);                    }                }            );        },        _reset: function(e) {            var me = this;            me.errors = {};            if (e) {                me.reseting = true;                me.$el.find(INPUT_SELECTOR).each( function(){                    me._resetElement(this);                });                delete me.reseting;            }        },        _resetElement: function(el, all) {            this._setClass(el, null);            this.hideMsg(el);        },        // Handle events: "focusin/click"        _focusin: function(e) {            var me = this,                opt = me.options,                el = e.target,                timely,                msg;            if ( me.validating || ( e.type==='click' && document.activeElement === el ) ) {                return;            }            if (opt.focusCleanup) {                if ( attr(el, ARIA_INVALID) === 'true' ) {                    me._setClass(el, null);                    me.hideMsg(el);                }            }            msg = attr(el, DATA_TIP);            if (msg) {                me.showMsg(el, {                    type: 'tip',                    msg: msg                });            } else {                if (attr(el, DATA_RULE)) {                    me._parse(el);                }                if (timely = attr(el, DATA_TIMELY)) {                    if ( timely === 8 || timely === 9 ) {                        me._focusout(e);                    }                }            }        },        // Handle events: "focusout/validate/keyup/click/change/input/compositionstart/compositionend"        _focusout: function(e) {            var me = this,                opt = me.options,                el = e.target,                etype = e.type,                etype0,                focusin = etype === 'focusin',                special = etype === 'validate',                elem,                field,                old,                value,                timestamp,                key, specialKey,                timely,                timer = 0;            if (etype === 'compositionstart') {                me.pauseValidate = true;            }            if (etype === 'compositionend') {                me.pauseValidate = false;            }            if (me.pauseValidate) {                return;            }            // For checkbox and radio            elem = el.name && _checkable(el) ? me.$el.find('input[name="'+ el.name +'"]').get(0) : el;            // Get field            if (!(field = me.getField(elem)) || !field.rule) {                return;            }            // Cache event type            etype0 = field._e;            field._e = etype;            timely = field.timely;            if (!special) {                if (!timely || (_checkable(el) && etype !== 'click')) {                    return;                }                value = field.getValue();                // not validate field unless fill a value                if ( field.ignoreBlank && !value && !focusin ) {                    me.hideMsg(el);                    return;                }                if ( etype === 'focusout' ) {                    if (etype0 === 'change') {                        return;                    }                    if ( timely === 2 || timely === 8 ) {                        old = field.old;                        if (value && old) {                            if (field.isValid && !old.showOk) {                                me.hideMsg(el);                            } else {                                me._makeMsg(el, field, old);                            }                        } else {                            return;                        }                    }                }                else {                    if ( timely < 2 && !e.data ) {                        return;                    }                    // mark timestamp to reduce the frequency of the received event                    timestamp = +new Date();                    if ( timestamp - (el._ts || 0) < 100 ) {                        return;                    }                    el._ts = timestamp;                    // handle keyup                    if ( etype === 'keyup' ) {                        if (etype0 === 'input') {                            return;                        }                        key = e.keyCode;                        specialKey = {                            8: 1,  // Backspace                            9: 1,  // Tab                            16: 1, // Shift                            32: 1, // Space                            46: 1  // Delete                        };                        // only gets focus, no validation                        if ( key === 9 && !value ) {                            return;                        }                        // do not validate, if triggered by these keys                        if ( key < 48 && !specialKey[key] ) {                            return;                        }                    }                    if ( !focusin ) {                        // keyboard events, reducing the frequency of validation                        timer = timely <100 ?  (etype === 'click' || el.tagName === 'SELECT') ? 0 : 400 : timely;                    }                }            }            // if the current field is ignored            if ( opt.ignore && $(el).is(opt.ignore) ) {                return;            }            clearTimeout(field._t);            if (timer) {                field._t = setTimeout(function() {                    me._validate(el, field);                }, timer);            } else {                if (special) field.old = {};                me._validate(el, field);            }        },        _setClass: function(el, isValid) {            var $el = $(el), opt = this.options;            if (opt.bindClassTo) {                $el = $el.closest(opt.bindClassTo);            }            $el.removeClass( opt.invalidClass + ' ' + opt.validClass );            if (isValid !== null) {                $el.addClass( isValid ? opt.validClass : opt.invalidClass );            }        },        _showmsg: function(e, type, msg) {            var me = this,                el = e.target;            if ( me.$el.is(el) ) {                if (isObject(type)) {                    me.showMsg(type)                }                else if ( type === 'tip' ) {                    me.$el.find(INPUT_SELECTOR +'['+ DATA_TIP +']', el).each(function(){                        me.showMsg(this, {type: type, msg: msg});                    });                }            }            else {                me.showMsg(el, {type: type, msg: msg});            }        },        _hidemsg: function(e) {            var $el = $(e.target);            if ( $el.is(INPUT_SELECTOR) ) {                this.hideMsg($el);            }        },        // Validated a field        _validatedField: function(el, field, ret) {            var me = this,                opt = me.options,                isValid = field.isValid = ret.isValid = !!ret.isValid,                callback = isValid ? 'valid' : 'invalid';            ret.key = field.key;            ret.ruleName = field._r;            ret.id = el.id;            ret.value = field.value;            me.elements[field.key] = ret.element = el;            me.isValid = me.$el[0].isValid = isValid ? me.isFormValid() : isValid;            if (isValid) {                ret.type = 'ok';            } else {                if (me.submiting) {                    me.errors[field.key] = ret.msg;                }                me.hasError = true;            }            // cache result            field.old = ret;            // trigger callback            isFunction(field[callback]) && field[callback].call(me, el, ret);            isFunction(opt.validation) && opt.validation.call(me, el, ret);            // trigger event            $(el).attr( ARIA_INVALID, isValid ? null : true )                 .trigger( callback + CLS_NS_FIELD, [ret, me] );            me.$el.triggerHandler('validation', [ret, me]);            if (me.checkOnly) return;            // set className            me._setClass(el, ret.skip || ret.type === 'tip' ? null : isValid);            me._makeMsg.apply(me, arguments);        },        _makeMsg: function(el, field, ret) {            // show or hide the message            if (field.msgMaker) {                ret = $.extend({}, ret);                if (field._e === 'focusin') {                    ret.type = 'tip';                }                this[ ret.showOk || ret.msg || ret.type === 'tip' ? 'showMsg' : 'hideMsg' ](el, ret, field);            }        },        // Validated a rule        _validatedRule: function(el, field, ret, msgOpt) {            field = field || me.getField(el);            msgOpt = msgOpt || {};            var me = this,                msg,                rule,                method = field._r,                timely = field.timely,                special = timely === 9 || timely === 8,                transfer,                temp,                isValid = false;            // use null to break validation from a field            if (ret === null) {                me._validatedField(el, field, {isValid: true, skip: true});                field._i = 0;                return;            }            else if (ret === undefined) {                transfer = true;            }            else if (ret === true || ret === '') {                isValid = true;            }            else if (isString(ret)) {                msg = ret;            }            else if (isObject(ret)) {                if (ret.error) {                    msg = ret.error;                } else {                    msg = ret.ok;                    isValid = true;                }            }            else {                isValid = !!ret            }            rule = field._rules[field._i];            if (rule.not) {                msg = undefined;                isValid = method === 'required' || !isValid;            }            if (rule.or) {                if (isValid) {                    while ( field._i < field._rules.length && field._rules[field._i].or ) {                        field._i++;                    }                } else {                    transfer = true;                }            }            else if (rule.and) {                if (!field.isValid) transfer = true;            }            if (transfer) {                isValid = true;            }            // message analysis, and throw rule level event            else {                if (isValid) {                    if (field.showOk !== false) {                        temp = attr(el, DATA_OK);                        msg = temp === null ? isString(field.ok) ? field.ok : msg : temp;                        if (!isString(msg) && isString(field.showOk)) {                            msg = field.showOk;                        }                        if (isString(msg)) {                            msgOpt.showOk = isValid;                        }                    }                }                if (!isValid || special) {                    /* rule message priority:                        1. custom DOM message                        2. custom field message;                        3. global defined message;                        4. rule returned message;                        5. default message;                    */                    msg = (_getDataMsg(el, field, msg || rule.msg || me.messages[method]) || me.messages.fallback).replace(/\{0\|?([^\}]*)\}/, function(m, defaultDisplay){                        return me._getDisplay(el, field.display) || defaultDisplay || me.messages[0];                    });                }                if (!isValid) field.isValid = isValid;                msgOpt.msg = msg;                $(el).trigger( (isValid ? 'valid' : 'invalid') + CLS_NS_RULE, [method, msg]);            }            if (special && (!transfer || rule.and)) {                if (!isValid && !field._m) field._m = msg;                field._v = field._v || [];                field._v.push({                    type: isValid ? !transfer ? 'ok' : 'tip' : 'error',                    msg: msg || rule.msg                });            }            me._debug('log', '   ' + field._i + ': ' + method + ' => ' + (isValid || msg));            // the current rule has passed, continue to validate            if ( (isValid || special) && field._i < field._rules.length - 1) {                field._i++;                me._checkRule(el, field);            }            // field was invalid, or all fields was valid            else {                field._i = 0;                if (special) {                    msgOpt.isValid = field.isValid;                    msgOpt.result = field._v;                    msgOpt.msg = field._m || '';                    if (!field.value && (field._e === 'focusin')) {                        msgOpt.type = 'tip';                    }                } else {                    msgOpt.isValid = isValid;                }                me._validatedField(el, field, msgOpt);                delete field._m;                delete field._v;            }        },        // Verify a rule form a field        _checkRule: function(el, field) {            var me = this,                ret,                fn,                old,                key = field.key,                rule = field._rules[field._i],                method = rule.method,                params = rule.params;            // request has been sent, wait it            if (me.submiting && me.deferred[key]) {                return;            }            old = field.old;            field._r = method;            if (old && !field.must && !rule.must && rule.result !== undefined &&                old.ruleName === method && old.id === el.id &&                field.value && old.value === field.value )            {                // get result from cache                ret = rule.result;            }            else {                // get result from current rule                fn = _getDataRule(el, method) || me.rules[method] || noop;                ret = fn.call(field, el, params, field);                if (fn.msg) rule.msg = fn.msg;            }            // asynchronous validation            if (isObject(ret) && isFunction(ret.then)) {                me.deferred[key] = ret;                // whether the field valid is unknown                field.isValid = undefined;                // show loading message                !me.checkOnly && me.showMsg(el, {                    type: 'loading',                    msg: me.messages.loading                }, field);                // waiting to parse the response data                ret.then(                    function(d, textStatus, jqXHR) {                        var data = trim(jqXHR.responseText),                            result,                            dataFilter = field.dataFilter;                        // detect if data is json or jsonp format                        if (/jsonp?/.test(this.dataType)) {                            data = d;                        } else if (data.charAt(0) === '{') {                            data = $.parseJSON(data);                        }                        // filter data                        result = dataFilter.call(this, data, field);                        if (result === undefined) result = dataFilter.call(this, data.data, field);                        rule.data = this.data;                        rule.result = field.old ? result : undefined;                        me._validatedRule(el, field, result);                    },                    function(jqXHR, textStatus){                        me._validatedRule(el, field, me.messages[textStatus] || textStatus);                    }                ).always(function(){                    delete me.deferred[key];                });            }            // other result            else {                me._validatedRule(el, field, ret);            }        },        // Processing the validation        _validate: function(el, field) {            var me = this;            // doesn't validate the element that has "disabled" or "novalidate" attribute            if ( el.disabled || attr(el, NOVALIDATE) !== null ) {                return;            }            field = field || me.getField(el);            if (!field) return;            if (!field._rules) me._parse(el);            if (!field._rules) return;            me._debug('info', field.key);            field.isValid = true;            field.element = el;            // Cache the value            field.value = field.getValue();            // if the field is not required, and that has a blank value            if (!field.required && !field.must && !field.value) {                if (!_checkable(el)) {                    me._validatedField(el, field, {isValid: true});                    return true;                }            }            me._checkRule(el, field);            return field.isValid;        },        _debug: function(type, messages) {            if (window.console && this.options.debug) {                console[type](messages);            }        },        /**         * Detecting whether the value of an element that matches a rule         *         * @method test         * @param {Element} el - input element         * @param {String} rule - rule name         */        test: function(el, rule) {            var me = this,                ret,                parts = rRule.exec(rule),                field,                method,                params;            if (parts) {                method = parts[1];                if (method in me.rules) {                    params = parts[2] || parts[3];                    params = params ? params.split(', ') : undefined;                    field = me.getField(el, true);                    field._r = method;                    field.value = field.getValue();                    ret = me.rules[method].call(field, el, params);                }            }            return ret === true || ret === undefined || ret === null;        },        _getDisplay: function(el, str) {            return !isString(str) ? isFunction(str) ? str.call(this, el) : '' : str;        },        _getMsgOpt: function(obj, field) {            var opt = field ? field : this.options;            return $.extend({                type: 'error',                pos: _getPos(opt.msgClass),                target: opt.target,                wrapper: opt.msgWrapper,                style: opt.msgStyle,                cls: opt.msgClass,                arrow: opt.msgArrow,                icon: opt.msgIcon            }, isString(obj) ? {msg: obj} : obj);        },        _getMsgDOM: function(el, msgOpt) {            var $el = $(el), $msgbox, datafor, tgt, container;            if ( $el.is(INPUT_SELECTOR) ) {                tgt = msgOpt.target || attr(el, DATA_TARGET);                if (tgt) {                    tgt = !isFunction(tgt) ? tgt.charAt(0) === '#' ? $(tgt) : this.$el.find(tgt) : tgt.call(this, el);                    if (tgt.length) {                        if ( tgt.is(INPUT_SELECTOR) ) {                            $el = tgt                            el = tgt.get(0);                        } else if ( tgt.hasClass(CLS_MSG_BOX) ) {                            $msgbox = tgt;                        } else {                            container = tgt;                        }                    }                }                if (!$msgbox) {                    datafor = (!_checkable(el) || !el.name) && el.id ? el.id : el.name;                    $msgbox = (container || this.$el).find(msgOpt.wrapper + '.' + CLS_MSG_BOX + '[for="' + datafor + '"]');                }            } else {                $msgbox = $el;            }            // Create new message box            if (!msgOpt.hide && !$msgbox.length) {                $msgbox = $('<'+ msgOpt.wrapper + '>').attr({                    'class': CLS_MSG_BOX + (msgOpt.cls ? ' ' + msgOpt.cls : ''),                    'style': msgOpt.style || undefined,                    'for': datafor                });                if (container) {                    $msgbox.appendTo(container);                } else {                    if ( _checkable(el) ) {                        var $parent = $el.parent();                        $msgbox.appendTo( $parent.is('label') ? $parent.parent() : $parent );                    } else {                        $msgbox[!msgOpt.pos || msgOpt.pos === 'right' ? 'insertAfter' : 'insertBefore']($el);                    }                }            }            return $msgbox;        },        /**         * Show validation message         *         * @method showMsg         * @param {Element} el - input element         * @param {Object} msgOpt         */        showMsg: function(el, msgOpt, /*INTERNAL*/ field) {            if (!el) return;            var me = this,                opt = me.options,                msgShow,                msgMaker,                temp,                $msgbox;            if (isObject(el) && !el.jquery && !msgOpt) {                $.each(el, function(key, msg) {                    var el = me.elements[key] || me.$el.find(_key2selector(key))[0];                    me.showMsg(el, msg);                });                return;            }            if ($(el).is(INPUT_SELECTOR)) {                field = field || me.getField(el);            }            if (!(msgMaker = (field || opt).msgMaker)) {                return;            }            msgOpt = me._getMsgOpt(msgOpt, field);            el = (el.name && _checkable(el) ? me.$el.find('input[name="'+ el.name +'"]') : $(el)).get(0);            // ok or tip            if (!msgOpt.msg && msgOpt.type !== 'error') {                temp = attr(el, 'data-' + msgOpt.type);                if (temp !== null) msgOpt.msg = temp;            }            if ( !isString(msgOpt.msg) ) {                return;            }            $msgbox = me._getMsgDOM(el, msgOpt);            !rPos.test($msgbox[0].className) && $msgbox.addClass(msgOpt.cls);            if ( isIE === 6 && msgOpt.pos === 'bottom' ) {                $msgbox[0].style.marginTop = $(el).outerHeight() + 'px';            }            $msgbox.html( msgMaker.call(me, msgOpt) )[0].style.display = '';            if (isFunction(msgShow = field && field.msgShow || opt.msgShow)) {                msgShow.call(me, $msgbox, msgOpt.type);            }        },        /**         * Hide validation message         *         * @method hideMsg         * @param {Element} el - input element         * @param {Object} msgOpt optional         */        hideMsg: function(el, msgOpt, /*INTERNAL*/ field) {            var me = this,                opt = me.options,                msgHide,                $msgbox;            el = $(el).get(0);            if ($(el).is(INPUT_SELECTOR)) {                field = field || me.getField(el);                if (field) {                    if (field.isValid || me.reseting) attr(el, ARIA_INVALID, null);                }            }            msgOpt = me._getMsgOpt(msgOpt, field);            msgOpt.hide = true;            $msgbox = me._getMsgDOM(el, msgOpt);            if (!$msgbox.length) return;            if ( isFunction(msgHide = field && field.msgHide || opt.msgHide) ) {                msgHide.call(me, $msgbox, msgOpt.type);            } else {                $msgbox[0].style.display = 'none';                $msgbox[0].innerHTML = '';            }        },        /**         * Get field information         *         * @method getField         * @param {Element} - input element         * @return {Object} field         */        getField: function(el, must) {            var me = this,                key,                field;            if (isString(el)) {                key = el;                el = undefined;            } else {                if (attr(el, DATA_RULE)) {                    return me._parse(el);                }                if (el.id && '#' + el.id in me.fields || !el.name) {                    key = '#' + el.id;                } else {                    key = el.name;                }            }            if ( (field = me.fields[key]) || must && (field = new me.Field(key)) ) {                field.element = el;            }            return field;        },        /**         * Config a field         *         * @method: setField         * @param {String} key         * @param {Object} obj         */        setField: function(key, obj) {            var fields = {};            if (!key) return;            // update this field            if (isString(key)) {                fields[key] = obj;            }            // update fields            else {                fields = key;            }            this._initFields(fields);        },        /**         * Detecting whether the form is valid         *         * @method isFormValid         * @return {Boolean}         */        isFormValid: function() {            var fields = this.fields, k, field;            for (k in fields) {                field = fields[k];                if (!field._rules || !field.required && !field.must && !field.value) continue;                if (!field.isValid) return false;            }            return true;        },        /**         * Prevent submission form         *         * @method holdSubmit         * @param {Boolean} hold - If set to false, will release the hold         */        holdSubmit: function(hold) {            this.submiting = hold === undefined || hold;        },        /**         * Clean validation messages         *         * @method cleanUp         */        cleanUp: function() {            this._reset(1);        },        /**         * Destroy the validation         *         * @method destroy         */        destroy: function() {            this._reset(1);            this.$el.off(CLS_NS).removeData(NS);            attr(this.$el[0], NOVALIDATE, this._NOVALIDATE);        }    };    /**     * Create Field Factory     *     * @class     * @param  {Object}     context     * @return {Function}   Factory     */    function _createFieldFactory(context) {        function FieldFactory() {            var options = this.options;            for (var i in options) {                if (i in fieldDefaults) this[i] = options[i];            }            $.extend(this, {                _valHook: function() {                    return this.element.contentEditable === 'true' ? 'text' : 'val';                },                getValue: function() {                    var elem = this.element;                    if (elem.type === 'number' && elem.validity && elem.validity.badInput) {                        return 'NaN';                    }                    return  $(elem)[this._valHook()]();                },                setValue: function(value) {                    $(this.element)[this._valHook()](this.value = value);                },                // Get a range of validation messages                getRangeMsg: function(value, params, suffix) {                    if (!params) return;                    var me = this,                        msg = me.messages[me._r] || '',                        result,                        p = params[0].split('~'),                        e = params[1] === 'false',                        a = p[0],                        b = p[1],                        c = 'rg',                        args = [''],                        isNumber = trim(value) && +value === +value;                    function compare(large, small) {                        return !e ? large >= small : large > small;                    }                    if (p.length === 2) {                        if (a && b) {                            if (isNumber && compare(value, +a) && compare(+b, value)) {                                result = true;                            }                            args = args.concat(p);                            c = e ? 'gtlt' : 'rg';                        }                        else if (a && !b) {                            if (isNumber && compare(value, +a)) {                                result = true;                            }                            args.push(a);                            c = e ? 'gt' : 'gte';                        }                        else if (!a && b) {                            if (isNumber && compare(+b, value)) {                                result = true;                            }                            args.push(b);                            c = e ? 'lt' : 'lte';                        }                    }                    else {                        if (value === +a) {                            result = true;                        }                        args.push(a);                        c = 'eq';                    }                    if (msg) {                        if (suffix && msg[c + suffix]) {                            c += suffix;                        }                        args[0] = msg[c];                    }                    return result || me._rules && ( me._rules[me._i].msg = me.renderMsg.apply(null, args) );                },                // Render message template                renderMsg: function() {                    var args = arguments,                        tpl = args[0],                        i = args.length;                    if (!tpl) return;                    while (--i) {                        tpl = tpl.replace('{' + i + '}', args[i]);                    }                    return tpl;                }            });        }        function Field(key, obj, oldField) {            this.key = key;            this.validator = context;            $.extend(this, oldField, obj);        }        FieldFactory.prototype = context;        Field.prototype = new FieldFactory();        return Field;    }    /**     * Create Rules     *     * @class     * @param {Object} obj     rules     * @param {Object} context context     */    function Rules(obj, context) {        if (!isObject(obj)) return;        var k, that = context ? context === true ? this : context : Rules.prototype;        for (k in obj) {            if (_checkRuleName(k)) {                that[k] = _getRule(obj[k]);            }        }    }    /**     * Create Messages     *     * @class     * @param {Object} obj     rules     * @param {Object} context context     */    function Messages(obj, context) {        if (!isObject(obj)) return;        var k, that = context ? context === true ? this : context : Messages.prototype;        for (k in obj) {            that[k] = obj[k];        }    }    // Rule converted factory    function _getRule(fn) {        switch ($.type(fn)) {            case 'function':                return fn;            case 'array':                var f = function() {                    return fn[0].test(this.value) || fn[1] || false;                };                f.msg = fn[1];                return f;            case 'regexp':                return function() {                    return fn.test(this.value);                };        }    }    // Get instance by an element    function _getInstance(el) {        var wrap, k, options;        if (!el || !el.tagName) return;        switch (el.tagName) {            case 'INPUT':            case 'SELECT':            case 'TEXTAREA':            case 'BUTTON':            case 'FIELDSET':                wrap = el.form || $(el).closest('.' + CLS_WRAPPER);                break;            case 'FORM':                wrap = el;                break;            default:                wrap = $(el).closest('.' + CLS_WRAPPER);        }        for (k in preinitialized) {            if ($(wrap).is(k)) {                options = preinitialized[k];                break;            }        }        return $(wrap).data(NS) || $(wrap)[NS](options).data(NS);    }    // Get custom rules on the node    function _getDataRule(el, method) {        var fn = trim(attr(el, DATA_RULE + '-' + method));        if ( fn && (fn = new Function('return ' + fn)()) ) {            return _getRule(fn);        }    }    // Get custom messages on the node    function _getDataMsg(el, field, m) {        var msg = field.msg,            item = field._r;        if ( isObject(msg) ) msg = msg[item];        if ( !isString(msg) ) {            msg = attr(el, DATA_MSG + '-' + item) || attr(el, DATA_MSG) || ( m ? isString(m) ? m : m[item] : '');        }        return msg;    }    // Get message position    function _getPos(str) {        var pos;        if (str) pos = rPos.exec(str);        return pos && pos[0];    }    // Check whether the element is checkbox or radio    function _checkable(el) {        return el.tagName === 'INPUT' && el.type === 'checkbox' || el.type === 'radio';    }    // Parse date string to timestamp    function _parseDate(str) {        return Date.parse(str.replace(/\.|\-/g, '/'));    }    // Rule name only allows alphanumeric characters and underscores    function _checkRuleName(name) {        return /^\w+$/.test(name);    }    // Translate field key to jQuery selector.    function _key2selector(key) {        var isID = key.charAt(0) === '#';        key = key.replace(/([:.{(|)}/\[\]])/g, '\\$1');        return isID ? key : '[name="'+ key +'"]:first';    }    // Fixed a issue cause by refresh page in IE.    $(window).on('beforeunload', function(){        this.focus();    });    $(document)    .on('click', ':submit', function(){        var input = this, attrNode;        if (!input.form) return;        // Shim for "formnovalidate"        attrNode = input.getAttributeNode('formnovalidate');        if (attrNode && attrNode.nodeValue !== null || attr(input, NOVALIDATE)!== null) {            novalidateonce = true;        }    })    // Automatic initializing form validation    .on('focusin submit validate', 'form,.'+CLS_WRAPPER, function(e) {        if ( attr(this, NOVALIDATE) !== null ) return;        var $form = $(this), me;        if ( !$form.data(NS) && (me = _getInstance(this)) ) {            if ( !$.isEmptyObject(me.fields) ) {                // Execute event handler                if (e.type === 'focusin') {                    me._focusin(e);                } else {                    me._submit(e);                }            } else {                attr(this, NOVALIDATE, NOVALIDATE);                $form.off(CLS_NS).removeData(NS);            }        }    });    new Messages({        fallback: 'This field is not valid.',        loading: 'Validating...'    });    // Built-in rules (global)    new Rules({        /**         * required         *         * @example:            required            required(jqSelector)            required(anotherRule)            required(not, -1)            required(from, .contact)         */        required: function(element, params) {            var me = this,                val = trim(me.value),                isValid = true;            if (params) {                if ( params.length === 1 ) {                    if ( !_checkRuleName(params[0]) ) {                        if (!val && !$(params[0], me.$el).length ) {                            return null;                        }                    }                    else if ( me.rules[params[0]] ) {                        if ( !val && !me.test(element, params[0]) ) {                            return null;                        }                        me._r = 'required'                    }                }                else if ( params[0] === 'not' ) {                    $.each(params.slice(1), function() {                        return (isValid = val !== trim(this));                    });                }                else if ( params[0] === 'from' ) {                    var $elements = me.$el.find(params[1]),                        VALIDATED = '_validated_',                        ret;                    isValid = $elements.filter(function(){                        var field = me.getField(this);                        return field && !!trim(field.getValue());                    }).length >= (params[2] || 1);                    if (isValid) {                        if (!val) ret = null;                    } else {                        ret = _getDataMsg($elements[0], me) || false;                    }                    if ( !$(element).data(VALIDATED) ) {                        $elements.data(VALIDATED, 1).each(function(){                            if (element !== this) {                                me._validate(this);                            }                        }).removeData(VALIDATED);                    }                    return ret;                }            }            return isValid && !!val;        },        /**         * integer         *         * @example:            integer            integer[+]            integer[+0]            integer[-]            integer[-0]         */        integer: function(element, params) {            var re, z = '0|',                p = '[1-9]\\d*',                key = params ? params[0] : '*';            switch (key) {                case '+':                    re = p;                    break;                case '-':                    re = '-' + p;                    break;                case '+0':                    re = z + p;                    break;                case '-0':                    re = z + '-' + p;                    break;                default:                    re = z + '-?' + p;            }            re = '^(?:' + re + ')$';            return new RegExp(re).test(this.value) || (this.messages.integer && this.messages.integer[key]);        },        /**         * match another field         *         * @example:            match[password]    Match the password field (two values must be the same)            match[eq, password]  Ditto            match[neq, count]  The value must be not equal to the value of the count field            match[lt, count]   The value must be less than the value of the count field            match[lte, count]  The value must be less than or equal to the value of the count field            match[gt, count]   The value must be greater than the value of the count field            match[gte, count]  The value must be greater than or equal to the value of the count field            match[gte, startDate, date]            match[gte, startTime, time]         **/        match: function(element, params) {            if (!params) return;            var me = this,                isValid = true,                a, b,                key, msg, type = 'eq', parser,                selector2, elem2, field2;            if (params.length === 1) {                key = params[0];            } else {                type = params[0];                key = params[1];            }            selector2 = _key2selector(key);            elem2 = me.$el.find(selector2)[0];            // If the compared field is not exist            if (!elem2) return;            field2 = me.getField(elem2);            a = me.value;            b = field2.getValue();            if (!me._match) {                me.$el.on('valid'+CLS_NS_FIELD+CLS_NS, selector2, function(){                    $(element).trigger('validate');                });                me._match = field2._match = 1;            }            // If both fields are blank            if (!me.required && a === '' && b === '') {                return null;            }            parser = params[2];            if (parser) {                if (/^date(time)?$/i.test(parser)) {                    a = _parseDate(a);                    b = _parseDate(b);                } else if (parser === 'time') {                    a = +a.replace(/:/g, '');                    b = +b.replace(/:/g, '');                }            }            // If the compared field is incorrect, we only ensure that this field is correct.            if (type !== 'eq' && !isNaN(+a) && isNaN(+b)) {                return true;            }            switch (type) {                case 'lt':                    isValid = +a < +b; break;                case 'lte':                    isValid = +a <= +b; break;                case 'gte':                    isValid = +a >= +b; break;                case 'gt':                    isValid = +a > +b; break;                case 'neq':                    isValid = a !== b; break;                default:                    isValid = a === b;            }            return isValid || (                isObject(me.messages.match)                && me.messages.match[type].replace( '{1}', me._getDisplay( elem2, field2.display || key ) )            );        },        /**         * range numbers         *         * @example:            range[0~99]    Number 0-99            range[0~]      Number greater than or equal to 0            range[~100]    Number less than or equal to 100         **/        range: function(element, params) {            return this.getRangeMsg(this.value, params);        },        /**         * how many checkbox or radio inputs that checked         *         * @example:            checked;       no empty, same to required            checked[1~3]   1-3 items            checked[1~]    greater than 1 item            checked[~3]    less than 3 items            checked[3]     3 items         **/        checked: function(element, params) {            if ( !_checkable(element) ) return;            var me = this,                elem, count;            if (element.name) {                count = me.$el.find('input[name="' + element.name + '"]').filter(function() {                    var el = this;                    if (!elem && _checkable(el)) elem = el;                    return !el.disabled && el.checked;                }).length;            } else {                elem = element;                count = elem.checked;            }            if (params) {                return me.getRangeMsg(count, params);            } else {                return !!count || _getDataMsg(elem, me, '') || me.messages.required || false;            }        },        /**         * length of a characters (You can pass the second parameter "true", will calculate the length in bytes)         *         * @example:            length[6~16]        6-16 characters            length[6~]          Greater than 6 characters            length[~16]         Less than 16 characters            length[~16, true]   Less than 16 characters, non-ASCII characters calculating two-character         **/        length: function(element, params) {            var value = this.value,                len = (params[1] === 'true' ? value.replace(rDoubleBytes, 'xx') : value).length;            return this.getRangeMsg(len, params, (params[1] ? '_2' : ''));        },        /**         * remote validation         *         * @description         *  remote([get:]url [, name1, [name2 ...]]);         *  Adaptation three kinds of results (Front for the successful, followed by a failure):                1. text:                    ''  'Error Message'                2. json:                    {"ok": ""}  {"error": "Error Message"}                3. json wrapper:                    {"status": 1, "data": {"ok": ""}}  {"status": 1, "data": {"error": "Error Message"}}         * @example            The simplest:       remote(path/to/server);            With parameters:    remote(path/to/server, name1, name2, ...);            By GET:             remote(get:path/to/server, name1, name2, ...);            Name proxy:         remote(path/to/server, name1, proxyname2:name2, proxyname3:#id3, ...)            Query String        remote(path/to/server, foo=1&bar=2, name1, name2, ...)            CORS                remote(cors:path/to/server)            JSONP               remote(jsonp:path/to/server)         */        remote: function(element, params) {            if (!params) return;            var me = this,                arr = rAjaxType.exec(params[0]),                rule = me._rules[me._i],                data = {},                queryString = '',                url = arr[3],                type = arr[2] || 'POST',            // GET / POST                rType = (arr[1]||'').toLowerCase(), // CORS / JSONP                dataType;            rule.must = true;            data[element.name] = me.value;            // There are extra fields            if (params[1]) {                $.map(params.slice(1), function(name) {                    var arr, key;                    if (~name.indexOf('=')) {                        queryString += '&' + name;                    } else {                        arr = name.split(':');                        name = trim(arr[0]);                        key = trim(arr[1]) || name;                        data[ name ] = me.$el.find( _key2selector(key) ).val();                    }                });            }            data = $.param(data) + queryString;            if (!me.must && rule.data && rule.data === data) {                return rule.result;            }            // Cross-domain request, force jsonp dataType            if (rType !== 'cors' && /^https?:/.test(url) && !~url.indexOf(location.host)) {                dataType = 'jsonp';            }            // Asynchronous validation need return jqXHR objects            return $.ajax({                url: url,                type: type,                data: data,                dataType: dataType            });        },        /**         * filter characters, direct filtration without prompting error (support custom regular expressions)         *         * @example         *  filter          filtering unsafe characters         *  filter(regexp)  filtering the "regexp" matched characters         */        filter: function(element, params) {            var value = this.value,                temp = value.replace( params ? (new RegExp('[' + params[0] + ']', 'gm')) : rUnsafe, '' );            if (temp !== value) this.setValue(temp);        }    });    /**     * Config global options     *     * @static  config     * @param {Object} options     */    Validator.config = function(key, value) {        if (isObject(key)) {            $.each(key, _config);        }        else if (isString(key)) {            _config(key, value);        }        function _config(k, o) {            if (k === 'rules') {                new Rules(o);            }            else if (k === 'messages') {                new Messages(o);            }            else if (k in fieldDefaults) {                fieldDefaults[k] = o;            }            else {                defaults[k] = o;            }        }    };    /**     * Config themes     *     * @static setTheme     * @param {String|Object} name     * @param {Object} obj     * @example        .setTheme( themeName, themeOptions )        .setTheme( multiThemes )     */    Validator.setTheme = function(name, obj) {        if ( isObject(name) ) {            $.extend(true, themes, name);        }        else if ( isString(name) && isObject(obj) ) {            themes[name] = $.extend(themes[name], obj);        }    };    /**     * Resource loader     *     * @static load     * @param {String} str     * @example        .load('local=zh-CN')        // load: local/zh-CN.js and jquery.validator.css        .load('local=zh-CN&css=')   // load: local/zh-CN.js        .load('local&css')          // load: local/en.js (set <html lang="en">) and jquery.validator.css        .load('local')              // dito     */    Validator.load = function(str) {        if (!str) return;        var doc = document,            params = {},            node = doc.scripts[0],            dir, el, ONLOAD;        str.replace(/([^?=&]+)=([^&#]*)/g, function(m, key, value){            params[key] = value;        });        dir = params.dir || Validator.dir;        if (!Validator.css && params.css !== '') {            el = doc.createElement('link');            el.rel = 'stylesheet';            el.href = Validator.css = dir + 'jquery.validator.css';            node.parentNode.insertBefore(el, node);        }        if (!Validator.local && ~str.indexOf('local') && params.local !== '') {            Validator.local = (params.local || doc.documentElement.lang || 'en').replace('_','-');            Validator.pending = 1;            el = doc.createElement('script');            el.src = dir + 'local/' + Validator.local + '.js';            ONLOAD = 'onload' in el ? 'onload' : 'onreadystatechange';            el[ONLOAD] = function() {                if (!el.readyState || /loaded|complete/.test(el.readyState)) {                    el = el[ONLOAD] = null;                    delete Validator.pending;                    $(window).triggerHandler('validatorready');                }            };            node.parentNode.insertBefore(el, node);        }    };    // Auto loading resources    (function(){        var scripts = document.scripts,            i = scripts.length, node, arr,            re = /(.*validator(?:\.min)?.js)(\?.*(?:local|css|dir)(?:=[\w\-]*)?)?/;        while (i-- && !arr) {            node = scripts[i];            arr = (node.hasAttribute ? node.src : node.getAttribute('src',4)||'').match(re);        }        if (!arr) return;        Validator.dir = arr[1].split('/').slice(0, -1).join('/')+'/';        Validator.load(arr[2]);    })();    return $[NS] = Validator;}));
 |