作者 Karson

修复validator的语言包BUG

@@ -306,6 +306,16 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], function ($ @@ -306,6 +306,16 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], function ($
306 } 306 }
307 return val; 307 return val;
308 }); 308 });
  309 + },
  310 + init: function () {
  311 + //后台的公用代码
  312 + //点击包含.btn-dialog的元素时弹出dialog
  313 + $(document).on('click', '.btn-dialog', function (e) {
  314 + Backend.api.open(Backend.api.fixurl($(this).attr('href')), $(this).attr('title'));
  315 + e.preventDefault();
  316 + });
  317 + //支持data-bind-url方式进行渲染select元素
  318 +
309 } 319 }
310 }; 320 };
311 //将Layer暴露到全局中去 321 //将Layer暴露到全局中去
@@ -318,10 +328,6 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], function ($ @@ -318,10 +328,6 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], function ($
318 window.Backend = Backend; 328 window.Backend = Backend;
319 //Toastr定义 329 //Toastr定义
320 Toastr.options = Backend.config.toastr; 330 Toastr.options = Backend.config.toastr;
321 - //点击包含.btn-dialog的元素时弹出dialog  
322 - $(document).on('click', '.btn-dialog', function (e) {  
323 - Backend.api.open(Backend.api.fixurl($(this).attr('href')), $(this).attr('title'));  
324 - e.preventDefault();  
325 - }); 331 +
326 return Backend; 332 return Backend;
327 }); 333 });
@@ -45,7 +45,7 @@ require.config({ @@ -45,7 +45,7 @@ require.config({
45 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll', 45 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll',
46 'crontab': '../libs/jqcron/src/jqCron.cn', 46 'crontab': '../libs/jqcron/src/jqCron.cn',
47 'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min', 47 'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min',
48 - 'validator': '../libs/nice-validator/dist/jquery.validator.js?local=zh-CN', 48 + 'validator': '../libs/nice-validator/dist/jquery.validator',
49 'plupload': '../libs/plupload/js/plupload.min', 49 'plupload': '../libs/plupload/js/plupload.min',
50 'toastr': '../libs/toastr/toastr', 50 'toastr': '../libs/toastr/toastr',
51 'jstree': '../libs/jstree/dist/jstree.min', 51 'jstree': '../libs/jstree/dist/jstree.min',
@@ -62,7 +62,7 @@ require.config({ @@ -62,7 +62,7 @@ require.config({
62 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll', 62 'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll',
63 'crontab': '../libs/jqcron/src/jqCron.cn', 63 'crontab': '../libs/jqcron/src/jqCron.cn',
64 'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min', 64 'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min',
65 - 'validator': '../libs/nice-validator/dist/jquery.validator.js?local=zh-CN', 65 + 'validator': '../libs/nice-validator/dist/jquery.validator',
66 'plupload': '../libs/plupload/js/plupload.min', 66 'plupload': '../libs/plupload/js/plupload.min',
67 'toastr': '../libs/toastr/toastr', 67 'toastr': '../libs/toastr/toastr',
68 'jstree': '../libs/jstree/dist/jstree.min', 68 'jstree': '../libs/jstree/dist/jstree.min',
@@ -2220,6 +2220,16 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], f @@ -2220,6 +2220,16 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], f
2220 } 2220 }
2221 return val; 2221 return val;
2222 }); 2222 });
  2223 + },
  2224 + init: function () {
  2225 + //后台的公用代码
  2226 + //点击包含.btn-dialog的元素时弹出dialog
  2227 + $(document).on('click', '.btn-dialog', function (e) {
  2228 + Backend.api.open(Backend.api.fixurl($(this).attr('href')), $(this).attr('title'));
  2229 + e.preventDefault();
  2230 + });
  2231 + //支持data-bind-url方式进行渲染select元素
  2232 +
2223 } 2233 }
2224 }; 2234 };
2225 //将Layer暴露到全局中去 2235 //将Layer暴露到全局中去
@@ -2232,11 +2242,7 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], f @@ -2232,11 +2242,7 @@ define('backend',['jquery', 'bootstrap', 'toastr', 'layer', 'lang', 'config'], f
2232 window.Backend = Backend; 2242 window.Backend = Backend;
2233 //Toastr定义 2243 //Toastr定义
2234 Toastr.options = Backend.config.toastr; 2244 Toastr.options = Backend.config.toastr;
2235 - //点击包含.btn-dialog的元素时弹出dialog  
2236 - $(document).on('click', '.btn-dialog', function (e) {  
2237 - Backend.api.open(Backend.api.fixurl($(this).attr('href')), $(this).attr('title'));  
2238 - e.preventDefault();  
2239 - }); 2245 +
2240 return Backend; 2246 return Backend;
2241 }); 2247 });
2242 //! moment.js 2248 //! moment.js
@@ -8492,6 +8498,2145 @@ define('upload',['jquery', 'bootstrap', 'backend', 'config', 'plupload'], functi @@ -8492,6 +8498,2145 @@ define('upload',['jquery', 'bootstrap', 'backend', 'config', 'plupload'], functi
8492 8498
8493 return Upload; 8499 return Upload;
8494 }); 8500 });
  8501 +/*! nice-validator 1.0.10
  8502 + * (c) 2012-2017 Jony Zhang <niceue@live.com>, MIT Licensed
  8503 + * https://github.com/niceue/nice-validator
  8504 + */
  8505 +;(function(factory) {
  8506 + typeof module === "object" && module.exports ? module.exports = factory( require( "jquery" ) ) :
  8507 + typeof define === 'function' && define.amd ? define('validator',['jquery'], factory) :
  8508 + factory(jQuery);
  8509 +}(function($, undefined) {
  8510 + "use strict";
  8511 +
  8512 + var NS = 'validator',
  8513 + CLS_NS = '.' + NS,
  8514 + CLS_NS_RULE = '.rule',
  8515 + CLS_NS_FIELD = '.field',
  8516 + CLS_NS_FORM = '.form',
  8517 + CLS_WRAPPER = 'nice-' + NS,
  8518 + CLS_MSG_BOX = 'msg-box',
  8519 + ARIA_REQUIRED = 'aria-required',
  8520 + ARIA_INVALID = 'aria-invalid',
  8521 + DATA_RULE = 'data-rule',
  8522 + DATA_MSG = 'data-msg',
  8523 + DATA_TIP = 'data-tip',
  8524 + DATA_OK = 'data-ok',
  8525 + DATA_TIMELY = 'data-timely',
  8526 + DATA_TARGET = 'data-target',
  8527 + DATA_DISPLAY = 'data-display',
  8528 + DATA_MUST = 'data-must',
  8529 + NOVALIDATE = 'novalidate',
  8530 + INPUT_SELECTOR = ':verifiable',
  8531 +
  8532 + rRules = /(&)?(!)?\b(\w+)(?:\[\s*(.*?\]?)\s*\]|\(\s*(.*?\)?)\s*\))?\s*(;|\|)?/g,
  8533 + rRule = /(\w+)(?:\[\s*(.*?\]?)\s*\]|\(\s*(.*?\)?)\s*\))?/,
  8534 + rDisplay = /(?:([^:;\(\[]*):)?(.*)/,
  8535 + rDoubleBytes = /[^\x00-\xff]/g,
  8536 + rPos = /top|right|bottom|left/,
  8537 + rAjaxType = /(?:(cors|jsonp):)?(?:(post|get):)?(.+)/i,
  8538 + rUnsafe = /[<>'"`\\]|&#x?\d+[A-F]?;?|%3[A-F]/gmi,
  8539 +
  8540 + noop = $.noop,
  8541 + proxy = $.proxy,
  8542 + trim = $.trim,
  8543 + isFunction = $.isFunction,
  8544 + isString = function(s) {
  8545 + return typeof s === 'string';
  8546 + },
  8547 + isObject = function(o) {
  8548 + return o && Object.prototype.toString.call(o) === '[object Object]';
  8549 + },
  8550 + isIE = document.documentMode || +(navigator.userAgent.match(/MSIE (\d+)/) && RegExp.$1),
  8551 + attr = function(el, key, value) {
  8552 + if (!el || !el.tagName) return null;
  8553 + if (value !== undefined) {
  8554 + if (value === null) el.removeAttribute(key);
  8555 + else el.setAttribute(key, '' + value);
  8556 + } else {
  8557 + return el.getAttribute(key);
  8558 + }
  8559 + },
  8560 + novalidateonce,
  8561 + preinitialized = {},
  8562 +
  8563 + defaults = {
  8564 + debug: 0,
  8565 + theme: 'default',
  8566 + ignore: '',
  8567 + focusInvalid: true,
  8568 + focusCleanup: false,
  8569 + stopOnError: false,
  8570 + beforeSubmit: null,
  8571 + valid: null,
  8572 + invalid: null,
  8573 + validation: null,
  8574 + formClass: 'n-default',
  8575 + validClass: 'n-valid',
  8576 + invalidClass: 'n-invalid',
  8577 + bindClassTo: null
  8578 + },
  8579 + fieldDefaults = {
  8580 + timely: 1,
  8581 + display: null,
  8582 + target: null,
  8583 + ignoreBlank: false,
  8584 + showOk: true,
  8585 + // Translate ajax response to validation result
  8586 + dataFilter: function (data) {
  8587 + if ( isString(data) || ( isObject(data) && ('error' in data || 'ok' in data) ) ) {
  8588 + return data;
  8589 + }
  8590 + },
  8591 + msgMaker: function(opt) {
  8592 + var html;
  8593 + html = '<span role="alert" class="msg-wrap n-'+ opt.type + '">' + opt.arrow;
  8594 + if (opt.result) {
  8595 + $.each(opt.result, function(i, obj){
  8596 + html += '<span class="n-'+ obj.type +'">' + opt.icon + '<span class="n-msg">' + obj.msg + '</span></span>';
  8597 + });
  8598 + } else {
  8599 + html += opt.icon + '<span class="n-msg">' + opt.msg + '</span>';
  8600 + }
  8601 + html += '</span>';
  8602 + return html;
  8603 + },
  8604 + msgWrapper: 'span',
  8605 + msgArrow: '',
  8606 + msgIcon: '<span class="n-icon"></span>',
  8607 + msgClass: 'n-right',
  8608 + msgStyle: '',
  8609 + msgShow: null,
  8610 + msgHide: null
  8611 + },
  8612 + themes = {};
  8613 +
  8614 + /** jQuery Plugin
  8615 + * @param {Object} options
  8616 + debug {Boolean} 0 Whether to enable debug mode
  8617 + timely {Number} 1 Whether to enable timely validation
  8618 + theme {String} 'default' Theme name
  8619 + stopOnError {Boolean} false Whether to stop validate when found an error input
  8620 + focusCleanup {Boolean} false Whether to clean up the field message when focus the field
  8621 + focusInvalid {Boolean} true Whether to focus the field that is invalid
  8622 + ignoreBlank {Boolean} false When the field has no value, whether to ignore validation
  8623 + ignore {jqSelector} '' Ignored fields (Using jQuery selector)
  8624 +
  8625 + beforeSubmit {Function} Do something before submit form
  8626 + dataFilter {Function} Convert ajax results
  8627 + valid {Function} Triggered when the form is valid
  8628 + invalid {Function} Triggered when the form is invalid
  8629 + validClass {String} 'n-valid' Add this class name to a valid field
  8630 + invalidClass {String} 'n-invalid' Add this class name to a invalid field
  8631 + bindClassTo {jqSelector} ':verifiable' Which element should the className binding to
  8632 +
  8633 + display {Function} Callback function to get dynamic display
  8634 + target {Function} Callback function to get dynamic target
  8635 + msgShow {Function} Trigger this callback when show message
  8636 + msgHide {Function} Trigger this callback when hide message
  8637 + msgWrapper {String} 'span' Message wrapper tag name
  8638 + msgMaker {Function} Callback function to make message HTML
  8639 + msgArrow {String} Message arrow template
  8640 + msgIcon {String} Message icon template
  8641 + msgStyle {String} Custom message css style
  8642 + msgClass {String} Additional added to the message class names
  8643 + formClass {String} Additional added to the form class names
  8644 +
  8645 + messages {Object} Custom messages for the current instance
  8646 + rules {Object} Custom rules for the current instance
  8647 + fields {Object} Field validation configuration
  8648 + {String} key name|#id
  8649 + {String|Object} value Rule string or an object which can pass more arguments
  8650 +
  8651 + fields[key][rule] {String} Rule string
  8652 + fields[key][display] {String|Function}
  8653 + fields[key][tip] {String} Custom tip message
  8654 + fields[key][ok] {String} Custom success message
  8655 + fields[key][msg] {Object} Custom error message
  8656 + fields[key][msgStyle] {String} Custom message style
  8657 + fields[key][msgClass] {String} A className which added to message placeholder element
  8658 + fields[key][msgWrapper] {String} Tag name of the message placeholder element
  8659 + fields[key][msgMaker] {Function} A function to custom message HTML
  8660 + fields[key][dataFilter] {Function} A function to convert ajax results
  8661 + fields[key][valid] {Function} A function triggered when field is valid
  8662 + fields[key][invalid] {Function} A function triggered when field is invalid
  8663 + fields[key][must] {Boolean} If set true, we always check the field even has remote checking
  8664 + fields[key][timely] {Boolean} Whether to enable timely validation
  8665 + fields[key][target] {jqSelector} Define placement of a message
  8666 + */
  8667 + $.fn.validator = function(options) {
  8668 + var that = this,
  8669 + args = arguments;
  8670 +
  8671 + if (that.is(INPUT_SELECTOR)) return that;
  8672 + if (!that.is('form')) that = this.find('form');
  8673 + if (!that.length) that = this;
  8674 +
  8675 + that.each(function() {
  8676 + var instance = $(this).data(NS);
  8677 +
  8678 + if (instance) {
  8679 + if ( isString(options) ) {
  8680 + if ( options.charAt(0) === '_' ) return;
  8681 + instance[options].apply(instance, [].slice.call(args, 1));
  8682 + }
  8683 + else if (options) {
  8684 + instance._reset(true);
  8685 + instance._init(this, options);
  8686 + }
  8687 + } else {
  8688 + new Validator(this, options);
  8689 + }
  8690 + });
  8691 +
  8692 + return this;
  8693 + };
  8694 +
  8695 +
  8696 + // Validate a field, or an area
  8697 + $.fn.isValid = function(callback, hideMsg) {
  8698 + var me = _getInstance(this[0]),
  8699 + hasCallback = isFunction(callback),
  8700 + ret, opt;
  8701 +
  8702 + if (!me) return true;
  8703 + if (!hasCallback && hideMsg === undefined) hideMsg = callback;
  8704 + me.checkOnly = !!hideMsg;
  8705 + opt = me.options;
  8706 +
  8707 + ret = me._multiValidate(
  8708 + this.is(INPUT_SELECTOR) ? this : this.find(INPUT_SELECTOR),
  8709 + function(isValid){
  8710 + if (!isValid && opt.focusInvalid && !me.checkOnly) {
  8711 + // navigate to the error element
  8712 + me.$el.find('[' + ARIA_INVALID + ']:first').focus();
  8713 + }
  8714 + if (hasCallback) {
  8715 + if (callback.length) {
  8716 + callback(isValid);
  8717 + } else if (isValid) {
  8718 + callback();
  8719 + }
  8720 + }
  8721 + me.checkOnly = false;
  8722 + }
  8723 + );
  8724 +
  8725 + // If you pass a callback, we maintain the jQuery object chain
  8726 + return hasCallback ? this : ret;
  8727 + };
  8728 +
  8729 + $.extend($.expr.pseudos || $.expr[':'], {
  8730 + // A faster selector than ":input:not(:submit,:button,:reset,:image,:disabled,[contenteditable])"
  8731 + verifiable: function(elem) {
  8732 + var name = elem.nodeName.toLowerCase();
  8733 +
  8734 + return ( name === 'input' && !({submit: 1, button: 1, reset: 1, image: 1})[elem.type] ||
  8735 + name === 'select' ||
  8736 + name === 'textarea' ||
  8737 + elem.contentEditable === 'true'
  8738 + ) && !elem.disabled;
  8739 + },
  8740 + // any value, but not only whitespace
  8741 + filled: function(elem) {
  8742 + return !!trim($(elem).val());
  8743 + }
  8744 + });
  8745 +
  8746 + /**
  8747 + * Creates a new Validator
  8748 + *
  8749 + * @class
  8750 + * @param {Element} element - form element
  8751 + * @param {Object} options - options for validator
  8752 + */
  8753 + function Validator(element, options) {
  8754 + var me = this;
  8755 +
  8756 + if ( !(me instanceof Validator) ) {
  8757 + return new Validator(element, options);
  8758 + }
  8759 +
  8760 + if (Validator.pending) {
  8761 + $(window).on('validatorready', init);
  8762 + } else {
  8763 + init();
  8764 + }
  8765 +
  8766 + function init() {
  8767 + me.$el = $(element);
  8768 + if (me.$el.length) {
  8769 + me._init(me.$el[0], options);
  8770 + }
  8771 + else if (isString(element)) {
  8772 + preinitialized[element] = options;
  8773 + }
  8774 + }
  8775 + }
  8776 +
  8777 + Validator.prototype = {
  8778 + _init: function(element, options) {
  8779 + var me = this,
  8780 + opt, themeOpt, dataOpt;
  8781 +
  8782 + // Initialization options
  8783 + if ( isFunction(options) ) {
  8784 + options = {
  8785 + valid: options
  8786 + };
  8787 + }
  8788 + options = me._opt = options || {};
  8789 + dataOpt = attr(element, 'data-'+ NS +'-option');
  8790 + dataOpt = me._dataOpt = dataOpt && dataOpt.charAt(0) === '{' ? (new Function("return " + dataOpt))() : {};
  8791 + themeOpt = me._themeOpt = themes[ options.theme || dataOpt.theme || defaults.theme ];
  8792 + opt = me.options = $.extend({}, defaults, fieldDefaults, themeOpt, me.options, options, dataOpt);
  8793 +
  8794 + me.rules = new Rules(opt.rules, true);
  8795 + me.messages = new Messages(opt.messages, true);
  8796 + me.Field = _createFieldFactory(me);
  8797 + me.elements = me.elements || {};
  8798 + me.deferred = {};
  8799 + me.errors = {};
  8800 + me.fields = {};
  8801 + // Initialization fields
  8802 + me._initFields(opt.fields);
  8803 +
  8804 + // Initialization events and make a cache
  8805 + if ( !me.$el.data(NS) ) {
  8806 + me.$el.data(NS, me).addClass(CLS_WRAPPER +' '+ opt.formClass)
  8807 + .on('form-submit-validate', function(e, a, $form, opts, veto) {
  8808 + me.vetoed = veto.veto = !me.isValid;
  8809 + me.ajaxFormOptions = opts;
  8810 + })
  8811 + .on('submit'+ CLS_NS +' validate'+ CLS_NS, proxy(me, '_submit'))
  8812 + .on('reset'+ CLS_NS, proxy(me, '_reset'))
  8813 + .on('showmsg'+ CLS_NS, proxy(me, '_showmsg'))
  8814 + .on('hidemsg'+ CLS_NS, proxy(me, '_hidemsg'))
  8815 + .on('focusin'+ CLS_NS + ' click'+ CLS_NS, INPUT_SELECTOR, proxy(me, '_focusin'))
  8816 + .on('focusout'+ CLS_NS +' validate'+ CLS_NS, INPUT_SELECTOR, proxy(me, '_focusout'))
  8817 + .on('keyup'+ CLS_NS +' input'+ CLS_NS + ' compositionstart compositionend', INPUT_SELECTOR, proxy(me, '_focusout'))
  8818 + .on('click'+ CLS_NS, ':radio,:checkbox', 'click', proxy(me, '_focusout'))
  8819 + .on('change'+ CLS_NS, 'select,input[type="file"]', 'change', proxy(me, '_focusout'));
  8820 +
  8821 + // cache the novalidate attribute value
  8822 + me._NOVALIDATE = attr(element, NOVALIDATE);
  8823 + // Initialization is complete, stop off default HTML5 form validation
  8824 + // If use "jQuery.attr('novalidate')" in IE7 will complain: "SCRIPT3: Member not found."
  8825 + attr(element, NOVALIDATE, NOVALIDATE);
  8826 + }
  8827 +
  8828 + // Display all messages in target container
  8829 + if ( isString(opt.target) ) {
  8830 + me.$el.find(opt.target).addClass('msg-container');
  8831 + }
  8832 + },
  8833 +
  8834 + // Guess whether the form use ajax submit
  8835 + _guessAjax: function(form) {
  8836 + var me = this;
  8837 +
  8838 + if ( !(me.isAjaxSubmit = !!me.options.valid) ) {
  8839 + // if there is a "valid.form" event
  8840 + var events = ($._data || $.data)(form, "events");
  8841 + me.isAjaxSubmit = issetEvent(events, 'valid', 'form') || issetEvent(events, 'submit', 'form-plugin');
  8842 + }
  8843 +
  8844 + function issetEvent(events, name, namespace) {
  8845 + if ( events && events[name] &&
  8846 + $.map(events[name], function(e){
  8847 + return ~e.namespace.indexOf(namespace) ? 1 : null;
  8848 + }).length
  8849 + ) {
  8850 + return true;
  8851 + }
  8852 + return false;
  8853 + }
  8854 + },
  8855 +
  8856 + _initFields: function(fields) {
  8857 + var me = this, k, arr, i,
  8858 + clear = fields === null;
  8859 +
  8860 + // Processing field information
  8861 + if (clear) fields = me.fields;
  8862 +
  8863 + if ( isObject(fields) ) {
  8864 + for (k in fields) {
  8865 + if (~k.indexOf(',')) {
  8866 + arr = k.split(',');
  8867 + i = arr.length;
  8868 + while (i--) {
  8869 + initField(trim(arr[i]), fields[k]);
  8870 + }
  8871 + } else {
  8872 + initField(k, fields[k]);
  8873 + }
  8874 + }
  8875 + }
  8876 +
  8877 + // Parsing DOM rules
  8878 + me.$el.find(INPUT_SELECTOR).each(function() {
  8879 + me._parse(this);
  8880 + });
  8881 +
  8882 + function initField(k, v) {
  8883 + // delete a field from settings
  8884 + if ( v === null || clear ) {
  8885 + var el = me.elements[k];
  8886 + if (el) me._resetElement(el, true);
  8887 + delete me.fields[k];
  8888 + } else {
  8889 + me.fields[k] = new me.Field(k, isString(v) ? {rule: v} : v, me.fields[k]);
  8890 + }
  8891 + }
  8892 + },
  8893 +
  8894 + // Parsing a field
  8895 + _parse: function(el) {
  8896 + var me = this,
  8897 + field,
  8898 + key = el.name,
  8899 + display,
  8900 + timely,
  8901 + dataRule = attr(el, DATA_RULE);
  8902 +
  8903 + dataRule && attr(el, DATA_RULE, null);
  8904 +
  8905 + // If the field has passed the key as id mode, or it doesn't has a name
  8906 + if ( el.id && (
  8907 + ('#' + el.id in me.fields) ||
  8908 + !key ||
  8909 + // If dataRule and element are diffrent from old's, we use ID mode.
  8910 + (dataRule !== null && (field = me.fields[key]) && dataRule !== field.rule && el.id !== field.key)
  8911 + )
  8912 + ) {
  8913 + key = '#' + el.id;
  8914 + }
  8915 + // doesn't verify a field that has neither id nor name
  8916 + if (!key) return;
  8917 +
  8918 + field = me.getField(key, true);
  8919 + // The priority of passing parameter by DOM is higher than by JS.
  8920 + field.rule = dataRule || field.rule;
  8921 +
  8922 + if (display = attr(el, DATA_DISPLAY)) {
  8923 + field.display = display;
  8924 + }
  8925 + if (field.rule) {
  8926 + if ( attr(el, DATA_MUST) !== null || /\b(?:match|checked)\b/.test(field.rule) ) {
  8927 + field.must = true;
  8928 + }
  8929 + if ( /\brequired\b/.test(field.rule) ) {
  8930 + field.required = true;
  8931 + attr(el, ARIA_REQUIRED, true);
  8932 + }
  8933 + if (timely = attr(el, DATA_TIMELY)) {
  8934 + field.timely = +timely;
  8935 + } else if (field.timely > 3) {
  8936 + attr(el, DATA_TIMELY, field.timely);
  8937 + }
  8938 + me._parseRule(field);
  8939 + field.old = {};
  8940 + }
  8941 + if ( isString(field.target) ) {
  8942 + attr(el, DATA_TARGET, field.target);
  8943 + }
  8944 + if ( isString(field.tip) ) {
  8945 + attr(el, DATA_TIP, field.tip);
  8946 + }
  8947 +
  8948 + return me.fields[key] = field;
  8949 + },
  8950 +
  8951 + // Parsing field rules
  8952 + _parseRule: function(field) {
  8953 + var arr = rDisplay.exec(field.rule);
  8954 +
  8955 + if (!arr) return;
  8956 + // current rule index
  8957 + field._i = 0;
  8958 + if (arr[1]) {
  8959 + field.display = arr[1];
  8960 + }
  8961 + if (arr[2]) {
  8962 + field._rules = [];
  8963 + arr[2].replace(rRules, function(){
  8964 + var args = arguments;
  8965 + args[4] = args[4] || args[5];
  8966 + field._rules.push({
  8967 + and: args[1] === "&",
  8968 + not: args[2] === "!",
  8969 + or: args[6] === "|",
  8970 + method: args[3],
  8971 + params: args[4] ? $.map( args[4].split(', '), trim ) : undefined
  8972 + });
  8973 + });
  8974 + }
  8975 + },
  8976 +
  8977 + // Verify a zone
  8978 + _multiValidate: function($inputs, doneCallback){
  8979 + var me = this,
  8980 + opt = me.options;
  8981 +
  8982 + me.hasError = false;
  8983 +
  8984 + if (opt.ignore) {
  8985 + $inputs = $inputs.not(opt.ignore);
  8986 + }
  8987 +
  8988 + $inputs.each(function() {
  8989 + me._validate(this);
  8990 + if (me.hasError && opt.stopOnError) {
  8991 + // stop the validation
  8992 + return false;
  8993 + }
  8994 + });
  8995 +
  8996 + // Need to wait for all fields validation complete, especially asynchronous validation
  8997 + if (doneCallback) {
  8998 + me.validating = true;
  8999 + $.when.apply(
  9000 + null,
  9001 + $.map(me.deferred, function(v){return v;})
  9002 + ).done(function(){
  9003 + doneCallback.call(me, !me.hasError);
  9004 + me.validating = false;
  9005 + });
  9006 + }
  9007 +
  9008 + // If the form does not contain asynchronous validation, the return value is correct.
  9009 + // Otherwise, you should detect form validation result through "doneCallback".
  9010 + return !$.isEmptyObject(me.deferred) ? undefined : !me.hasError;
  9011 + },
  9012 +
  9013 + // Validate the whole form
  9014 + _submit: function(e) {
  9015 + var me = this,
  9016 + opt = me.options,
  9017 + form = e.target,
  9018 + canSubmit = e.type === 'submit' && !e.isDefaultPrevented();
  9019 +
  9020 + e.preventDefault();
  9021 +
  9022 + if (
  9023 + novalidateonce && ~(novalidateonce = false) ||
  9024 + // Prevent duplicate submission
  9025 + me.submiting ||
  9026 + // Receive the "validate" event only from the form.
  9027 + e.type === 'validate' && me.$el[0] !== form ||
  9028 + // trigger the beforeSubmit callback.
  9029 + isFunction(opt.beforeSubmit) && opt.beforeSubmit.call(me, form) === false
  9030 + ) {
  9031 + return;
  9032 + }
  9033 +
  9034 + if (me.isAjaxSubmit === undefined) {
  9035 + me._guessAjax(form);
  9036 + }
  9037 +
  9038 + me._debug('log', '\n<<< event: ' + e.type);
  9039 +
  9040 + me._reset();
  9041 + me.submiting = true;
  9042 +
  9043 + me._multiValidate(
  9044 + me.$el.find(INPUT_SELECTOR),
  9045 + function(isValid){
  9046 + var ret = (isValid || opt.debug === 2) ? 'valid' : 'invalid',
  9047 + errors;
  9048 +
  9049 + if (!isValid) {
  9050 + if (opt.focusInvalid) {
  9051 + // navigate to the error element
  9052 + me.$el.find('[' + ARIA_INVALID + ']:first').focus();
  9053 + }
  9054 + errors = $.map(me.errors, function(err){return err;});
  9055 + }
  9056 +
  9057 + // releasing submit
  9058 + me.submiting = false;
  9059 + me.isValid = isValid;
  9060 +
  9061 + // trigger callback and event
  9062 + isFunction(opt[ret]) && opt[ret].call(me, form, errors);
  9063 + me.$el.trigger(ret + CLS_NS_FORM, [form, errors]);
  9064 +
  9065 + me._debug('log', '>>> ' + ret);
  9066 +
  9067 + if (!isValid) return;
  9068 + // For jquery.form plugin
  9069 + if (me.vetoed) {
  9070 + $(form).ajaxSubmit(me.ajaxFormOptions);
  9071 + }
  9072 + else if (canSubmit && !me.isAjaxSubmit) {
  9073 + document.createElement('form').submit.call(form);
  9074 + }
  9075 + }
  9076 + );
  9077 + },
  9078 +
  9079 + _reset: function(e) {
  9080 + var me = this;
  9081 +
  9082 + me.errors = {};
  9083 + if (e) {
  9084 + me.reseting = true;
  9085 + me.$el.find(INPUT_SELECTOR).each( function(){
  9086 + me._resetElement(this);
  9087 + });
  9088 + delete me.reseting;
  9089 + }
  9090 + },
  9091 +
  9092 + _resetElement: function(el, all) {
  9093 + this._setClass(el, null);
  9094 + this.hideMsg(el);
  9095 + if (all) {
  9096 + attr(el, ARIA_REQUIRED, null);
  9097 + }
  9098 + },
  9099 +
  9100 + // Handle events: "focusin/click"
  9101 + _focusin: function(e) {
  9102 + var me = this,
  9103 + opt = me.options,
  9104 + el = e.target,
  9105 + timely,
  9106 + msg;
  9107 +
  9108 + if ( me.validating || ( e.type==='click' && document.activeElement === el ) ) {
  9109 + return;
  9110 + }
  9111 +
  9112 + if (opt.focusCleanup) {
  9113 + if ( attr(el, ARIA_INVALID) === 'true' ) {
  9114 + me._setClass(el, null);
  9115 + me.hideMsg(el);
  9116 + }
  9117 + }
  9118 +
  9119 + msg = attr(el, DATA_TIP);
  9120 +
  9121 + if (msg) {
  9122 + me.showMsg(el, {
  9123 + type: 'tip',
  9124 + msg: msg
  9125 + });
  9126 + } else {
  9127 + if (attr(el, DATA_RULE)) {
  9128 + me._parse(el);
  9129 + }
  9130 + if (timely = attr(el, DATA_TIMELY)) {
  9131 + if ( timely === 8 || timely === 9 ) {
  9132 + me._focusout(e);
  9133 + }
  9134 + }
  9135 + }
  9136 + },
  9137 +
  9138 + // Handle events: "focusout/validate/keyup/click/change/input/compositionstart/compositionend"
  9139 + _focusout: function(e) {
  9140 + var me = this,
  9141 + opt = me.options,
  9142 + el = e.target,
  9143 + etype = e.type,
  9144 + etype0,
  9145 + focusin = etype === 'focusin',
  9146 + special = etype === 'validate',
  9147 + elem,
  9148 + field,
  9149 + old,
  9150 + value,
  9151 + timestamp,
  9152 + key, specialKey,
  9153 + timely,
  9154 + timer = 0;
  9155 +
  9156 + if (etype === 'compositionstart') {
  9157 + me.pauseValidate = true;
  9158 + }
  9159 + if (etype === 'compositionend') {
  9160 + me.pauseValidate = false;
  9161 + }
  9162 + if (me.pauseValidate) {
  9163 + return;
  9164 + }
  9165 +
  9166 + // For checkbox and radio
  9167 + elem = el.name && _checkable(el) ? me.$el.find('input[name="'+ el.name +'"]').get(0) : el;
  9168 + // Get field
  9169 + if (!(field = me.getField(elem)) || !field.rule) {
  9170 + return;
  9171 + }
  9172 + // Cache event type
  9173 + etype0 = field._e;
  9174 + field._e = etype;
  9175 + timely = field.timely;
  9176 +
  9177 + if (!special) {
  9178 + if (!timely || (_checkable(el) && etype !== 'click')) {
  9179 + return;
  9180 + }
  9181 +
  9182 + value = field.getValue();
  9183 +
  9184 + // not validate field unless fill a value
  9185 + if ( field.ignoreBlank && !value && !focusin ) {
  9186 + me.hideMsg(el);
  9187 + return;
  9188 + }
  9189 +
  9190 + if ( etype === 'focusout' ) {
  9191 + if (etype0 === 'change') {
  9192 + return;
  9193 + }
  9194 + if ( timely === 2 || timely === 8 ) {
  9195 + old = field.old;
  9196 + if (value && old) {
  9197 + if (field.isValid && !old.showOk) {
  9198 + me.hideMsg(el);
  9199 + } else {
  9200 + me._makeMsg(el, field, old);
  9201 + }
  9202 + } else {
  9203 + return;
  9204 + }
  9205 + }
  9206 + }
  9207 + else {
  9208 + if ( timely < 2 && !e.data ) {
  9209 + return;
  9210 + }
  9211 +
  9212 + // mark timestamp to reduce the frequency of the received event
  9213 + timestamp = +new Date();
  9214 + if ( timestamp - (el._ts || 0) < 100 ) {
  9215 + return;
  9216 + }
  9217 + el._ts = timestamp;
  9218 +
  9219 + // handle keyup
  9220 + if ( etype === 'keyup' ) {
  9221 + if (etype0 === 'input') {
  9222 + return;
  9223 + }
  9224 + key = e.keyCode;
  9225 + specialKey = {
  9226 + 8: 1, // Backspace
  9227 + 9: 1, // Tab
  9228 + 16: 1, // Shift
  9229 + 32: 1, // Space
  9230 + 46: 1 // Delete
  9231 + };
  9232 +
  9233 + // only gets focus, no validation
  9234 + if ( key === 9 && !value ) {
  9235 + return;
  9236 + }
  9237 +
  9238 + // do not validate, if triggered by these keys
  9239 + if ( key < 48 && !specialKey[key] ) {
  9240 + return;
  9241 + }
  9242 + }
  9243 + if ( !focusin ) {
  9244 + // keyboard events, reducing the frequency of validation
  9245 + timer = timely <100 ? (etype === 'click' || el.tagName === 'SELECT') ? 0 : 400 : timely;
  9246 + }
  9247 + }
  9248 + }
  9249 +
  9250 + // if the current field is ignored
  9251 + if ( opt.ignore && $(el).is(opt.ignore) ) {
  9252 + return;
  9253 + }
  9254 +
  9255 + clearTimeout(field._t);
  9256 +
  9257 + if (timer) {
  9258 + field._t = setTimeout(function() {
  9259 + me._validate(el, field);
  9260 + }, timer);
  9261 + } else {
  9262 + if (special) field.old = {};
  9263 + me._validate(el, field);
  9264 + }
  9265 + },
  9266 +
  9267 + _setClass: function(el, isValid) {
  9268 + var $el = $(el), opt = this.options;
  9269 + if (opt.bindClassTo) {
  9270 + $el = $el.closest(opt.bindClassTo);
  9271 + }
  9272 + $el.removeClass( opt.invalidClass + ' ' + opt.validClass );
  9273 + if (isValid !== null) {
  9274 + $el.addClass( isValid ? opt.validClass : opt.invalidClass );
  9275 + }
  9276 + },
  9277 +
  9278 + _showmsg: function(e, type, msg) {
  9279 + var me = this,
  9280 + el = e.target;
  9281 +
  9282 + if ( me.$el.is(el) ) {
  9283 + if (isObject(type)) {
  9284 + me.showMsg(type)
  9285 + }
  9286 + else if ( type === 'tip' ) {
  9287 + me.$el.find(INPUT_SELECTOR +"["+ DATA_TIP +"]", el).each(function(){
  9288 + me.showMsg(this, {type: type, msg: msg});
  9289 + });
  9290 + }
  9291 + }
  9292 + else {
  9293 + me.showMsg(el, {type: type, msg: msg});
  9294 + }
  9295 + },
  9296 +
  9297 + _hidemsg: function(e) {
  9298 + var $el = $(e.target);
  9299 +
  9300 + if ( $el.is(INPUT_SELECTOR) ) {
  9301 + this.hideMsg($el);
  9302 + }
  9303 + },
  9304 +
  9305 + // Validated a field
  9306 + _validatedField: function(el, field, ret) {
  9307 + var me = this,
  9308 + opt = me.options,
  9309 + isValid = field.isValid = ret.isValid = !!ret.isValid,
  9310 + callback = isValid ? 'valid' : 'invalid';
  9311 +
  9312 + ret.key = field.key;
  9313 + ret.ruleName = field._r;
  9314 + ret.id = el.id;
  9315 + ret.value = field.value;
  9316 +
  9317 + me.elements[field.key] = ret.element = el;
  9318 + me.isValid = me.$el[0].isValid = isValid ? me.isFormValid() : isValid;
  9319 +
  9320 + if (isValid) {
  9321 + ret.type = 'ok';
  9322 + } else {
  9323 + if (me.submiting) {
  9324 + me.errors[field.key] = ret.msg;
  9325 + }
  9326 + me.hasError = true;
  9327 + }
  9328 +
  9329 + // cache result
  9330 + field.old = ret;
  9331 +
  9332 + // trigger callback
  9333 + isFunction(field[callback]) && field[callback].call(me, el, ret);
  9334 + isFunction(opt.validation) && opt.validation.call(me, el, ret);
  9335 +
  9336 + // trigger event
  9337 + $(el).attr( ARIA_INVALID, isValid ? null : true )
  9338 + .trigger( callback + CLS_NS_FIELD, [ret, me] );
  9339 + me.$el.triggerHandler('validation', [ret, me]);
  9340 +
  9341 + if (me.checkOnly) return;
  9342 + // set className
  9343 + me._setClass(el, ret.skip || ret.type === 'tip' ? null : isValid);
  9344 + me._makeMsg.apply(me, arguments);
  9345 + },
  9346 +
  9347 + _makeMsg: function(el, field, ret) {
  9348 + // show or hide the message
  9349 + if (field.msgMaker) {
  9350 + ret = $.extend({}, ret);
  9351 + if (field._e === 'focusin') {
  9352 + ret.type = 'tip';
  9353 + }
  9354 + this[ ret.showOk || ret.msg || ret.type === 'tip' ? 'showMsg' : 'hideMsg' ](el, ret, field);
  9355 + }
  9356 + },
  9357 +
  9358 + // Validated a rule
  9359 + _validatedRule: function(el, field, ret, msgOpt) {
  9360 + field = field || me.getField(el);
  9361 + msgOpt = msgOpt || {};
  9362 +
  9363 + var me = this,
  9364 + msg,
  9365 + rule,
  9366 + method = field._r,
  9367 + timely = field.timely,
  9368 + special = timely === 9 || timely === 8,
  9369 + transfer,
  9370 + temp,
  9371 + isValid = false;
  9372 +
  9373 + // use null to break validation from a field
  9374 + if (ret === null) {
  9375 + me._validatedField(el, field, {isValid: true, skip: true});
  9376 + field._i = 0;
  9377 + return;
  9378 + }
  9379 + else if (ret === undefined) {
  9380 + transfer = true;
  9381 + }
  9382 + else if (ret === true || ret === '') {
  9383 + isValid = true;
  9384 + }
  9385 + else if (isString(ret)) {
  9386 + msg = ret;
  9387 + }
  9388 + else if (isObject(ret)) {
  9389 + if (ret.error) {
  9390 + msg = ret.error;
  9391 + } else {
  9392 + msg = ret.ok;
  9393 + isValid = true;
  9394 + }
  9395 + }
  9396 +
  9397 + rule = field._rules[field._i];
  9398 + if (rule.not) {
  9399 + msg = undefined;
  9400 + isValid = method === "required" || !isValid;
  9401 + }
  9402 + if (rule.or) {
  9403 + if (isValid) {
  9404 + while ( field._i < field._rules.length && field._rules[field._i].or ) {
  9405 + field._i++;
  9406 + }
  9407 + } else {
  9408 + transfer = true;
  9409 + }
  9410 + }
  9411 + else if (rule.and) {
  9412 + if (!field.isValid) transfer = true;
  9413 + }
  9414 +
  9415 + if (transfer) {
  9416 + isValid = true;
  9417 + }
  9418 + // message analysis, and throw rule level event
  9419 + else {
  9420 + if (isValid) {
  9421 + if (field.showOk !== false) {
  9422 + temp = attr(el, DATA_OK);
  9423 + msg = temp === null ? isString(field.ok) ? field.ok : msg : temp;
  9424 + if (!isString(msg) && isString(field.showOk)) {
  9425 + msg = field.showOk;
  9426 + }
  9427 + if (isString(msg)) {
  9428 + msgOpt.showOk = isValid;
  9429 + }
  9430 + }
  9431 + }
  9432 + if (!isValid || special) {
  9433 + /* rule message priority:
  9434 + 1. custom DOM message
  9435 + 2. custom field message;
  9436 + 3. global defined message;
  9437 + 4. rule returned message;
  9438 + 5. default message;
  9439 + */
  9440 + msg = (_getDataMsg(el, field, msg || rule.msg || me.messages[method]) || me.messages.fallback).replace(/\{0\|?([^\}]*)\}/, function(m, defaultDisplay){
  9441 + return me._getDisplay(el, field.display) || defaultDisplay || me.messages[0];
  9442 + });
  9443 + }
  9444 + if (!isValid) field.isValid = isValid;
  9445 + msgOpt.msg = msg;
  9446 + $(el).trigger( (isValid ? 'valid' : 'invalid') + CLS_NS_RULE, [method, msg]);
  9447 + }
  9448 +
  9449 + if (special && (!transfer || rule.and)) {
  9450 + if (!isValid && !field._m) field._m = msg;
  9451 + field._v = field._v || [];
  9452 + field._v.push({
  9453 + type: isValid ? !transfer ? 'ok' : 'tip' : 'error',
  9454 + msg: msg || rule.msg
  9455 + });
  9456 + }
  9457 +
  9458 + me._debug('log', ' ' + field._i + ': ' + method + ' => ' + (isValid || msg));
  9459 +
  9460 + // the current rule has passed, continue to validate
  9461 + if ( (isValid || special) && field._i < field._rules.length - 1) {
  9462 + field._i++;
  9463 + me._checkRule(el, field);
  9464 + }
  9465 + // field was invalid, or all fields was valid
  9466 + else {
  9467 + field._i = 0;
  9468 +
  9469 + if (special) {
  9470 + msgOpt.isValid = field.isValid;
  9471 + msgOpt.result = field._v;
  9472 + msgOpt.msg = field._m || '';
  9473 + if (!field.value && (field._e === 'focusin')) {
  9474 + msgOpt.type = 'tip';
  9475 + }
  9476 + } else {
  9477 + msgOpt.isValid = isValid;
  9478 + }
  9479 +
  9480 + me._validatedField(el, field, msgOpt);
  9481 + delete field._m;
  9482 + delete field._v;
  9483 + }
  9484 + },
  9485 +
  9486 + // Verify a rule form a field
  9487 + _checkRule: function(el, field) {
  9488 + var me = this,
  9489 + ret,
  9490 + fn,
  9491 + old,
  9492 + key = field.key,
  9493 + rule = field._rules[field._i],
  9494 + method = rule.method,
  9495 + params = rule.params;
  9496 +
  9497 + // request has been sent, wait it
  9498 + if (me.submiting && me.deferred[key]) {
  9499 + return;
  9500 + }
  9501 + old = field.old;
  9502 + field._r = method;
  9503 +
  9504 + if (old && !field.must && !rule.must && rule.result !== undefined &&
  9505 + old.ruleName === method && old.id === el.id &&
  9506 + field.value && old.value === field.value )
  9507 + {
  9508 + // get result from cache
  9509 + ret = rule.result;
  9510 + }
  9511 + else {
  9512 + // get result from current rule
  9513 + fn = _getDataRule(el, method) || me.rules[method] || noop;
  9514 + ret = fn.call(field, el, params, field);
  9515 + if (fn.msg) rule.msg = fn.msg;
  9516 + }
  9517 +
  9518 + // asynchronous validation
  9519 + if (isObject(ret) && isFunction(ret.then)) {
  9520 + me.deferred[key] = ret;
  9521 +
  9522 + // whether the field valid is unknown
  9523 + field.isValid = undefined;
  9524 +
  9525 + // show loading message
  9526 + !me.checkOnly && me.showMsg(el, {
  9527 + type: 'loading',
  9528 + msg: me.messages.loading
  9529 + }, field);
  9530 +
  9531 + // waiting to parse the response data
  9532 + ret.then(
  9533 + function(d, textStatus, jqXHR) {
  9534 + var data = trim(jqXHR.responseText),
  9535 + result,
  9536 + dataFilter = field.dataFilter;
  9537 +
  9538 + // detect if data is json or jsonp format
  9539 + if (/jsonp?/.test(this.dataType)) {
  9540 + data = d;
  9541 + } else if (data.charAt(0) === '{') {
  9542 + data = $.parseJSON(data);
  9543 + }
  9544 +
  9545 + // filter data
  9546 + result = dataFilter.call(this, data, field);
  9547 + if (result === undefined) result = dataFilter.call(this, data.data, field);
  9548 +
  9549 + rule.data = this.data;
  9550 + rule.result = field.old ? result : undefined;
  9551 + me._validatedRule(el, field, result);
  9552 + },
  9553 + function(jqXHR, textStatus){
  9554 + me._validatedRule(el, field, me.messages[textStatus] || textStatus);
  9555 + }
  9556 + ).always(function(){
  9557 + delete me.deferred[key];
  9558 + });
  9559 + }
  9560 + // other result
  9561 + else {
  9562 + me._validatedRule(el, field, ret);
  9563 + }
  9564 + },
  9565 +
  9566 + // Processing the validation
  9567 + _validate: function(el, field) {
  9568 + var me = this;
  9569 +
  9570 + // doesn't validate the element that has "disabled" or "novalidate" attribute
  9571 + if ( el.disabled || attr(el, NOVALIDATE) !== null ) {
  9572 + return;
  9573 + }
  9574 +
  9575 + field = field || me.getField(el);
  9576 + if (!field) return;
  9577 + if (!field._rules) me._parse(el);
  9578 + if (!field._rules) return;
  9579 +
  9580 + me._debug('info', field.key);
  9581 +
  9582 + field.isValid = true;
  9583 + field.element = el;
  9584 + // Cache the value
  9585 + field.value = field.getValue();
  9586 +
  9587 + // if the field is not required, and that has a blank value
  9588 + if (!field.required && !field.must && !field.value) {
  9589 + if (!_checkable(el)) {
  9590 + me._validatedField(el, field, {isValid: true});
  9591 + return true;
  9592 + }
  9593 + }
  9594 +
  9595 + me._checkRule(el, field);
  9596 + return field.isValid;
  9597 + },
  9598 +
  9599 + _debug: function(type, messages) {
  9600 + if (window.console && this.options.debug) {
  9601 + console[type](messages);
  9602 + }
  9603 + },
  9604 +
  9605 + /**
  9606 + * Detecting whether the value of an element that matches a rule
  9607 + *
  9608 + * @method test
  9609 + * @param {Element} el - input element
  9610 + * @param {String} rule - rule name
  9611 + */
  9612 + test: function(el, rule) {
  9613 + var me = this,
  9614 + ret,
  9615 + parts = rRule.exec(rule),
  9616 + field,
  9617 + method,
  9618 + params;
  9619 +
  9620 + if (parts) {
  9621 + method = parts[1];
  9622 + if (method in me.rules) {
  9623 + params = parts[2] || parts[3];
  9624 + params = params ? params.split(', ') : undefined;
  9625 + field = me.getField(el, true);
  9626 + field._r = method;
  9627 + field.value = field.getValue();
  9628 + ret = me.rules[method].call(field, el, params);
  9629 + }
  9630 + }
  9631 +
  9632 + return ret === true || ret === undefined || ret === null;
  9633 + },
  9634 +
  9635 + _getDisplay: function(el, str) {
  9636 + return !isString(str) ? isFunction(str) ? str.call(this, el) : '' : str;
  9637 + },
  9638 +
  9639 + _getMsgOpt: function(obj, field) {
  9640 + var opt = field ? field : this.options;
  9641 + return $.extend({
  9642 + type: 'error',
  9643 + pos: _getPos(opt.msgClass),
  9644 + target: opt.target,
  9645 + wrapper: opt.msgWrapper,
  9646 + style: opt.msgStyle,
  9647 + cls: opt.msgClass,
  9648 + arrow: opt.msgArrow,
  9649 + icon: opt.msgIcon
  9650 + }, isString(obj) ? {msg: obj} : obj);
  9651 + },
  9652 +
  9653 + _getMsgDOM: function(el, msgOpt) {
  9654 + var $el = $(el), $msgbox, datafor, tgt, container;
  9655 +
  9656 + if ( $el.is(INPUT_SELECTOR) ) {
  9657 + tgt = msgOpt.target || attr(el, DATA_TARGET);
  9658 + if (tgt) {
  9659 + tgt = isFunction(tgt) ? tgt.call(this, el) : this.$el.find(tgt);
  9660 + if (tgt.length) {
  9661 + if ( tgt.is(INPUT_SELECTOR) ) {
  9662 + $el = tgt
  9663 + el = tgt.get(0);
  9664 + } else if ( tgt.hasClass(CLS_MSG_BOX) ) {
  9665 + $msgbox = tgt;
  9666 + } else {
  9667 + container = tgt;
  9668 + }
  9669 + }
  9670 + }
  9671 + if (!$msgbox) {
  9672 + datafor = (!_checkable(el) || !el.name) && el.id ? el.id : el.name;
  9673 + $msgbox = this.$el.find(msgOpt.wrapper + '.' + CLS_MSG_BOX + '[for="' + datafor + '"]');
  9674 + }
  9675 + } else {
  9676 + $msgbox = $el;
  9677 + }
  9678 +
  9679 + // Create new message box
  9680 + if (!msgOpt.hide && !$msgbox.length) {
  9681 + $msgbox = $('<'+ msgOpt.wrapper + '>').attr({
  9682 + 'class': CLS_MSG_BOX + (msgOpt.cls ? ' ' + msgOpt.cls : ''),
  9683 + 'style': msgOpt.style || undefined,
  9684 + 'for': datafor
  9685 + });
  9686 +
  9687 + if ( _checkable(el) ) {
  9688 + var $parent = $el.parent();
  9689 + $msgbox.appendTo( $parent.is('label') ? $parent.parent() : $parent );
  9690 + } else {
  9691 + if (container) {
  9692 + $msgbox.appendTo(container);
  9693 + } else {
  9694 + $msgbox[!msgOpt.pos || msgOpt.pos === 'right' ? 'insertAfter' : 'insertBefore']($el);
  9695 + }
  9696 + }
  9697 + }
  9698 +
  9699 + return $msgbox;
  9700 + },
  9701 +
  9702 + /**
  9703 + * Show validation message
  9704 + *
  9705 + * @method showMsg
  9706 + * @param {Element} el - input element
  9707 + * @param {Object} msgOpt
  9708 + */
  9709 + showMsg: function(el, msgOpt, /*INTERNAL*/ field) {
  9710 + if (!el) return;
  9711 + var me = this,
  9712 + opt = me.options,
  9713 + msgShow,
  9714 + msgMaker,
  9715 + temp,
  9716 + $msgbox;
  9717 +
  9718 + if (isObject(el) && !el.jquery && !msgOpt) {
  9719 + $.each(el, function(key, msg) {
  9720 + var el = me.elements[key] || me.$el.find(_key2selector(key))[0];
  9721 + me.showMsg(el, msg);
  9722 + });
  9723 + return;
  9724 + }
  9725 +
  9726 + if ($(el).is(INPUT_SELECTOR)) {
  9727 + field = field || me.getField(el);
  9728 + }
  9729 +
  9730 + if (!(msgMaker = (field || opt).msgMaker)) {
  9731 + return;
  9732 + }
  9733 +
  9734 + msgOpt = me._getMsgOpt(msgOpt, field);
  9735 + el = (el.name && _checkable(el) ? me.$el.find('input[name="'+ el.name +'"]') : $(el)).get(0);
  9736 +
  9737 + // ok or tip
  9738 + if (!msgOpt.msg && msgOpt.type !== 'error') {
  9739 + temp = attr(el, 'data-' + msgOpt.type);
  9740 + if (temp !== null) msgOpt.msg = temp;
  9741 + }
  9742 +
  9743 + if ( !isString(msgOpt.msg) ) {
  9744 + return;
  9745 + }
  9746 +
  9747 + $msgbox = me._getMsgDOM(el, msgOpt);
  9748 +
  9749 + !rPos.test($msgbox[0].className) && $msgbox.addClass(msgOpt.cls);
  9750 + if ( isIE === 6 && msgOpt.pos === 'bottom' ) {
  9751 + $msgbox[0].style.marginTop = $(el).outerHeight() + 'px';
  9752 + }
  9753 + $msgbox.html( msgMaker.call(me, msgOpt) )[0].style.display = '';
  9754 +
  9755 + if (isFunction(msgShow = field && field.msgShow || opt.msgShow)) {
  9756 + msgShow.call(me, $msgbox, msgOpt.type);
  9757 + }
  9758 + },
  9759 +
  9760 + /**
  9761 + * Hide validation message
  9762 + *
  9763 + * @method hideMsg
  9764 + * @param {Element} el - input element
  9765 + * @param {Object} msgOpt optional
  9766 + */
  9767 + hideMsg: function(el, msgOpt, /*INTERNAL*/ field) {
  9768 + var me = this,
  9769 + opt = me.options,
  9770 + msgHide,
  9771 + $msgbox;
  9772 +
  9773 + el = $(el).get(0);
  9774 + if ($(el).is(INPUT_SELECTOR)) {
  9775 + field = field || me.getField(el);
  9776 + if (field) {
  9777 + if (field.isValid || me.reseting) attr(el, ARIA_INVALID, null);
  9778 + }
  9779 + }
  9780 +
  9781 + msgOpt = me._getMsgOpt(msgOpt, field);
  9782 + msgOpt.hide = true;
  9783 +
  9784 + $msgbox = me._getMsgDOM(el, msgOpt);
  9785 + if (!$msgbox.length) return;
  9786 +
  9787 + if ( isFunction(msgHide = field && field.msgHide || opt.msgHide) ) {
  9788 + msgHide.call(me, $msgbox, msgOpt.type);
  9789 + } else {
  9790 + $msgbox[0].style.display = 'none';
  9791 + $msgbox[0].innerHTML = null;
  9792 + }
  9793 + },
  9794 +
  9795 + /**
  9796 + * Get field information
  9797 + *
  9798 + * @method getField
  9799 + * @param {Element} - input element
  9800 + * @return {Object} field
  9801 + */
  9802 + getField: function(el, must) {
  9803 + var me = this,
  9804 + key,
  9805 + field;
  9806 +
  9807 + if (isString(el)) {
  9808 + key = el;
  9809 + el = undefined;
  9810 + } else {
  9811 + if (attr(el, DATA_RULE)) {
  9812 + return me._parse(el);
  9813 + }
  9814 + if (el.id && '#' + el.id in me.fields || !el.name) {
  9815 + key = '#' + el.id;
  9816 + } else {
  9817 + key = el.name;
  9818 + }
  9819 + }
  9820 +
  9821 + if ( (field = me.fields[key]) || must && (field = new me.Field(key)) ) {
  9822 + field.element = el;
  9823 + }
  9824 +
  9825 + return field;
  9826 + },
  9827 +
  9828 + /**
  9829 + * Config a field
  9830 + *
  9831 + * @method: setField
  9832 + * @param {String} key
  9833 + * @param {Object} obj
  9834 + */
  9835 + setField: function(key, obj) {
  9836 + var fields = {};
  9837 +
  9838 + if (!key) return;
  9839 +
  9840 + // update this field
  9841 + if (isString(key)) {
  9842 + fields[key] = obj;
  9843 + }
  9844 + // update fields
  9845 + else {
  9846 + fields = key;
  9847 + }
  9848 +
  9849 + this._initFields(fields);
  9850 + },
  9851 +
  9852 + /**
  9853 + * Detecting whether the form is valid
  9854 + *
  9855 + * @method isFormValid
  9856 + * @return {Boolean}
  9857 + */
  9858 + isFormValid: function() {
  9859 + var fields = this.fields, k, field;
  9860 + for (k in fields) {
  9861 + field = fields[k];
  9862 + if (!field._rules || !field.required && !field.must && !field.value) continue;
  9863 + if (!field.isValid) return false;
  9864 + }
  9865 + return true;
  9866 + },
  9867 +
  9868 + /**
  9869 + * Prevent submission form
  9870 + *
  9871 + * @method holdSubmit
  9872 + * @param {Boolean} hold - If set to false, will release the hold
  9873 + */
  9874 + holdSubmit: function(hold) {
  9875 + this.submiting = hold === undefined || hold;
  9876 + },
  9877 +
  9878 + /**
  9879 + * Clean validation messages
  9880 + *
  9881 + * @method cleanUp
  9882 + */
  9883 + cleanUp: function() {
  9884 + this._reset(1);
  9885 + },
  9886 +
  9887 + /**
  9888 + * Destroy the validation
  9889 + *
  9890 + * @method destroy
  9891 + */
  9892 + destroy: function() {
  9893 + this._reset(1);
  9894 + this.$el.off(CLS_NS).removeData(NS);
  9895 + attr(this.$el[0], NOVALIDATE, this._NOVALIDATE);
  9896 + }
  9897 + };
  9898 +
  9899 + /**
  9900 + * Create Field Factory
  9901 + *
  9902 + * @class
  9903 + * @param {Object} context
  9904 + * @return {Function} Factory
  9905 + */
  9906 + function _createFieldFactory(context) {
  9907 + function FieldFactory() {
  9908 + var options = this.options;
  9909 + for (var i in options) {
  9910 + if (i in fieldDefaults) this[i] = options[i];
  9911 + }
  9912 + $.extend(this, {
  9913 + _valHook: function() {
  9914 + return this.element.contentEditable === 'true' ? 'text' : 'val';
  9915 + },
  9916 + getValue: function() {
  9917 + var elem = this.element;
  9918 + if (elem.type === "number" && elem.validity && elem.validity.badInput) {
  9919 + return 'NaN';
  9920 + }
  9921 + return $(elem)[this._valHook()]();
  9922 + },
  9923 + setValue: function(value) {
  9924 + $(this.element)[this._valHook()](this.value = value);
  9925 + },
  9926 + // Get a range of validation messages
  9927 + getRangeMsg: function(value, params, suffix) {
  9928 + if (!params) return;
  9929 +
  9930 + var me = this,
  9931 + msg = me.messages[me._r] || '',
  9932 + result,
  9933 + p = params[0].split('~'),
  9934 + e = params[1] === 'false',
  9935 + a = p[0],
  9936 + b = p[1],
  9937 + c = 'rg',
  9938 + args = [''],
  9939 + isNumber = trim(value) && +value === +value;
  9940 +
  9941 + function compare(large, small) {
  9942 + return !e ? large >= small : large > small;
  9943 + }
  9944 +
  9945 + if (p.length === 2) {
  9946 + if (a && b) {
  9947 + if (isNumber && compare(value, +a) && compare(+b, value)) {
  9948 + result = true;
  9949 + }
  9950 + args = args.concat(p);
  9951 + c = e ? 'gtlt' : 'rg';
  9952 + }
  9953 + else if (a && !b) {
  9954 + if (isNumber && compare(value, +a)) {
  9955 + result = true;
  9956 + }
  9957 + args.push(a);
  9958 + c = e ? 'gt' : 'gte';
  9959 + }
  9960 + else if (!a && b) {
  9961 + if (isNumber && compare(+b, value)) {
  9962 + result = true;
  9963 + }
  9964 + args.push(b);
  9965 + c = e ? 'lt' : 'lte';
  9966 + }
  9967 + }
  9968 + else {
  9969 + if (value === +a) {
  9970 + result = true;
  9971 + }
  9972 + args.push(a);
  9973 + c = 'eq';
  9974 + }
  9975 +
  9976 + if (msg) {
  9977 + if (suffix && msg[c + suffix]) {
  9978 + c += suffix;
  9979 + }
  9980 + args[0] = msg[c];
  9981 + }
  9982 +
  9983 + return result || me._rules && ( me._rules[me._i].msg = me.renderMsg.apply(null, args) );
  9984 + },
  9985 + // Render message template
  9986 + renderMsg: function() {
  9987 + var args = arguments,
  9988 + tpl = args[0],
  9989 + i = args.length;
  9990 +
  9991 + if (!tpl) return;
  9992 +
  9993 + while (--i) {
  9994 + tpl = tpl.replace('{' + i + '}', args[i]);
  9995 + }
  9996 +
  9997 + return tpl;
  9998 + }
  9999 + });
  10000 + }
  10001 + function Field(key, obj, oldField) {
  10002 + this.key = key;
  10003 + this.validator = context;
  10004 + $.extend(this, oldField, obj);
  10005 + }
  10006 +
  10007 + FieldFactory.prototype = context;
  10008 + Field.prototype = new FieldFactory();
  10009 +
  10010 + return Field;
  10011 + }
  10012 +
  10013 + /**
  10014 + * Create Rules
  10015 + *
  10016 + * @class
  10017 + * @param {Object} obj rules
  10018 + * @param {Object} context context
  10019 + */
  10020 + function Rules(obj, context) {
  10021 + if (!isObject(obj)) return;
  10022 +
  10023 + var k, that = context ? context === true ? this : context : Rules.prototype;
  10024 +
  10025 + for (k in obj) {
  10026 + if (_checkRuleName(k))
  10027 + that[k] = _getRule(obj[k]);
  10028 + }
  10029 + }
  10030 +
  10031 + /**
  10032 + * Create Messages
  10033 + *
  10034 + * @class
  10035 + * @param {Object} obj rules
  10036 + * @param {Object} context context
  10037 + */
  10038 + function Messages(obj, context) {
  10039 + if (!isObject(obj)) return;
  10040 +
  10041 + var k, that = context ? context === true ? this : context : Messages.prototype;
  10042 +
  10043 + for (k in obj) {
  10044 + that[k] = obj[k];
  10045 + }
  10046 + }
  10047 +
  10048 + // Rule converted factory
  10049 + function _getRule(fn) {
  10050 + switch ($.type(fn)) {
  10051 + case 'function':
  10052 + return fn;
  10053 + case 'array':
  10054 + var f = function() {
  10055 + return fn[0].test(this.value) || fn[1] || false;
  10056 + };
  10057 + f.msg = fn[1];
  10058 + return f;
  10059 + case 'regexp':
  10060 + return function() {
  10061 + return fn.test(this.value);
  10062 + };
  10063 + }
  10064 + }
  10065 +
  10066 + // Get instance by an element
  10067 + function _getInstance(el) {
  10068 + var wrap, k, options;
  10069 +
  10070 + if (!el || !el.tagName) return;
  10071 +
  10072 + switch (el.tagName) {
  10073 + case 'INPUT':
  10074 + case 'SELECT':
  10075 + case 'TEXTAREA':
  10076 + case 'BUTTON':
  10077 + case 'FIELDSET':
  10078 + wrap = el.form || $(el).closest('.' + CLS_WRAPPER);
  10079 + break;
  10080 + case 'FORM':
  10081 + wrap = el;
  10082 + break;
  10083 + default:
  10084 + wrap = $(el).closest('.' + CLS_WRAPPER);
  10085 + }
  10086 +
  10087 + for (k in preinitialized) {
  10088 + if ($(wrap).is(k)) {
  10089 + options = preinitialized[k];
  10090 + break;
  10091 + }
  10092 + }
  10093 +
  10094 + return $(wrap).data(NS) || $(wrap)[NS](options).data(NS);
  10095 + }
  10096 +
  10097 + // Get custom rules on the node
  10098 + function _getDataRule(el, method) {
  10099 + var fn = trim(attr(el, DATA_RULE + '-' + method));
  10100 +
  10101 + if ( fn && (fn = new Function("return " + fn)()) ) {
  10102 + return _getRule(fn);
  10103 + }
  10104 + }
  10105 +
  10106 + // Get custom messages on the node
  10107 + function _getDataMsg(el, field, m) {
  10108 + var msg = field.msg,
  10109 + item = field._r;
  10110 +
  10111 + if ( isObject(msg) ) msg = msg[item];
  10112 + if ( !isString(msg) ) {
  10113 + msg = attr(el, DATA_MSG + '-' + item) || attr(el, DATA_MSG) || ( m ? isString(m) ? m : m[item] : '');
  10114 + }
  10115 +
  10116 + return msg;
  10117 + }
  10118 +
  10119 + // Get message position
  10120 + function _getPos(str) {
  10121 + var pos;
  10122 +
  10123 + if (str) pos = rPos.exec(str);
  10124 + return pos && pos[0];
  10125 + }
  10126 +
  10127 + // Check whether the element is checkbox or radio
  10128 + function _checkable(el) {
  10129 + return el.tagName === 'INPUT' && el.type === 'checkbox' || el.type === 'radio';
  10130 + }
  10131 +
  10132 + // Parse date string to timestamp
  10133 + function _parseDate(str) {
  10134 + return Date.parse(str.replace(/\.|\-/g, '/'));
  10135 + }
  10136 +
  10137 + // Rule name only allows alphanumeric characters and underscores
  10138 + function _checkRuleName(name) {
  10139 + return /^\w+$/.test(name);
  10140 + }
  10141 +
  10142 + // Translate field key to jQuery selector.
  10143 + function _key2selector(key) {
  10144 + var isID = key.charAt(0) === "#";
  10145 + key = key.replace(/([:.{(|)}/\[\]])/g, "\\$1");
  10146 + return isID ? key : '[name="'+ key +'"]:first';
  10147 + }
  10148 +
  10149 +
  10150 + // Fixed a issue cause by refresh page in IE.
  10151 + $(window).on('beforeunload', function(){
  10152 + this.focus();
  10153 + });
  10154 +
  10155 + $(document)
  10156 + .on('click', ':submit', function(){
  10157 + var input = this, attrNode;
  10158 + if (!input.form) return;
  10159 + // Shim for "formnovalidate"
  10160 + attrNode = input.getAttributeNode('formnovalidate');
  10161 + if (attrNode && attrNode.nodeValue !== null || attr(input, NOVALIDATE)!== null) {
  10162 + novalidateonce = true;
  10163 + }
  10164 + })
  10165 + // Automatic initializing form validation
  10166 + .on('focusin submit validate', 'form,.'+CLS_WRAPPER, function(e) {
  10167 + if ( attr(this, NOVALIDATE) !== null ) return;
  10168 + var $form = $(this), me;
  10169 +
  10170 + if ( !$form.data(NS) && (me = _getInstance(this)) ) {
  10171 + if ( !$.isEmptyObject(me.fields) ) {
  10172 + // Execute event handler
  10173 + if (e.type === 'focusin') {
  10174 + me._focusin(e);
  10175 + } else {
  10176 + me._submit(e);
  10177 + }
  10178 + } else {
  10179 + attr(this, NOVALIDATE, NOVALIDATE);
  10180 + $form.off(CLS_NS).removeData(NS);
  10181 + }
  10182 + }
  10183 + });
  10184 +
  10185 + new Messages({
  10186 + fallback: "This field is not valid.",
  10187 + loading: 'Validating...'
  10188 + });
  10189 +
  10190 +
  10191 + // Built-in rules (global)
  10192 + new Rules({
  10193 +
  10194 + /**
  10195 + * required
  10196 + *
  10197 + * @example:
  10198 + required
  10199 + required(anotherRule)
  10200 + required(not, -1)
  10201 + required(from, .contact)
  10202 + */
  10203 + required: function(element, params) {
  10204 + var me = this,
  10205 + val = trim(me.value),
  10206 + isValid = true;
  10207 +
  10208 + if (params) {
  10209 + if ( params.length === 1 ) {
  10210 + if ( !_checkRuleName(params[0]) ) {
  10211 + if (!val && !$(params[0], me.$el).length ) {
  10212 + return null;
  10213 + }
  10214 + }
  10215 + else if ( me.rules[params[0]] ) {
  10216 + if ( !val && !me.test(element, params[0]) ) {
  10217 + attr(element, ARIA_REQUIRED, null);
  10218 + return null;
  10219 + } else {
  10220 + attr(element, ARIA_REQUIRED, true);
  10221 + }
  10222 + }
  10223 + }
  10224 + else if ( params[0] === 'not' ) {
  10225 + $.each(params.slice(1), function() {
  10226 + return (isValid = val !== trim(this));
  10227 + });
  10228 + }
  10229 + else if ( params[0] === 'from' ) {
  10230 + var $elements = me.$el.find(params[1]),
  10231 + VALIDATED = '_validated_',
  10232 + ret;
  10233 +
  10234 + isValid = $elements.filter(function(){
  10235 + var field = me.getField(this);
  10236 + return field && !!trim(field.getValue());
  10237 + }).length >= (params[2] || 1);
  10238 +
  10239 + if (isValid) {
  10240 + if (!val) ret = null;
  10241 + } else {
  10242 + ret = _getDataMsg($elements[0], me) || false;
  10243 + }
  10244 +
  10245 + if ( !$(element).data(VALIDATED) ) {
  10246 + $elements.data(VALIDATED, 1).each(function(){
  10247 + if (element !== this) {
  10248 + me._validate(this);
  10249 + }
  10250 + }).removeData(VALIDATED);
  10251 + }
  10252 +
  10253 + return ret;
  10254 + }
  10255 + }
  10256 +
  10257 + return isValid && !!val;
  10258 + },
  10259 +
  10260 + /**
  10261 + * integer
  10262 + *
  10263 + * @example:
  10264 + integer
  10265 + integer[+]
  10266 + integer[+0]
  10267 + integer[-]
  10268 + integer[-0]
  10269 + */
  10270 + integer: function(element, params) {
  10271 + var re, z = '0|',
  10272 + p = '[1-9]\\d*',
  10273 + key = params ? params[0] : '*';
  10274 +
  10275 + switch (key) {
  10276 + case '+':
  10277 + re = p;
  10278 + break;
  10279 + case '-':
  10280 + re = '-' + p;
  10281 + break;
  10282 + case '+0':
  10283 + re = z + p;
  10284 + break;
  10285 + case '-0':
  10286 + re = z + '-' + p;
  10287 + break;
  10288 + default:
  10289 + re = z + '-?' + p;
  10290 + }
  10291 + re = '^(?:' + re + ')$';
  10292 +
  10293 + return new RegExp(re).test(this.value) || this.messages.integer[key];
  10294 + },
  10295 +
  10296 + /**
  10297 + * match another field
  10298 + *
  10299 + * @example:
  10300 + match[password] Match the password field (two values ​​must be the same)
  10301 + match[eq, password] Ditto
  10302 + match[neq, count] The value must be not equal to the value of the count field
  10303 + match[lt, count] The value must be less than the value of the count field
  10304 + match[lte, count] The value must be less than or equal to the value of the count field
  10305 + match[gt, count] The value must be greater than the value of the count field
  10306 + match[gte, count] The value must be greater than or equal to the value of the count field
  10307 + match[gte, startDate, date]
  10308 + match[gte, startTime, time]
  10309 + **/
  10310 + match: function(element, params) {
  10311 + if (!params) return;
  10312 +
  10313 + var me = this,
  10314 + a, b,
  10315 + key, msg, type = 'eq', parser,
  10316 + selector2, elem2, field2;
  10317 +
  10318 + if (params.length === 1) {
  10319 + key = params[0];
  10320 + } else {
  10321 + type = params[0];
  10322 + key = params[1];
  10323 + }
  10324 +
  10325 + selector2 = _key2selector(key);
  10326 + elem2 = me.$el.find(selector2)[0];
  10327 + // If the compared field is not exist
  10328 + if (!elem2) return;
  10329 + field2 = me.getField(elem2);
  10330 + a = me.value;
  10331 + b = field2.getValue();
  10332 +
  10333 + if (!me._match) {
  10334 + me.$el.on('valid'+CLS_NS_FIELD+CLS_NS, selector2, function(){
  10335 + $(element).trigger('validate');
  10336 + });
  10337 + me._match = field2._match = 1;
  10338 + }
  10339 +
  10340 + // If both fields are blank
  10341 + if (!me.required && a === "" && b === "") {
  10342 + return null;
  10343 + }
  10344 +
  10345 + parser = params[2];
  10346 + if (parser) {
  10347 + if (/^date(time)?$/i.test(parser)) {
  10348 + a = _parseDate(a);
  10349 + b = _parseDate(b);
  10350 + } else if (parser === 'time') {
  10351 + a = +a.replace(/:/g, '');
  10352 + b = +b.replace(/:/g, '');
  10353 + }
  10354 + }
  10355 +
  10356 + // If the compared field is incorrect, we only ensure that this field is correct.
  10357 + if (type !== "eq" && !isNaN(+a) && isNaN(+b)) {
  10358 + return true;
  10359 + }
  10360 +
  10361 + msg = me.messages.match[type].replace( '{1}', me._getDisplay( element, field2.display || key ) );
  10362 +
  10363 + switch (type) {
  10364 + case 'lt':
  10365 + return (+a < +b) || msg;
  10366 + case 'lte':
  10367 + return (+a <= +b) || msg;
  10368 + case 'gte':
  10369 + return (+a >= +b) || msg;
  10370 + case 'gt':
  10371 + return (+a > +b) || msg;
  10372 + case 'neq':
  10373 + return (a !== b) || msg;
  10374 + default:
  10375 + return (a === b) || msg;
  10376 + }
  10377 + },
  10378 +
  10379 + /**
  10380 + * range numbers
  10381 + *
  10382 + * @example:
  10383 + range[0~99] Number 0-99
  10384 + range[0~] Number greater than or equal to 0
  10385 + range[~100] Number less than or equal to 100
  10386 + **/
  10387 + range: function(element, params) {
  10388 + return this.getRangeMsg(this.value, params);
  10389 + },
  10390 +
  10391 + /**
  10392 + * how many checkbox or radio inputs that checked
  10393 + *
  10394 + * @example:
  10395 + checked; no empty, same to required
  10396 + checked[1~3] 1-3 items
  10397 + checked[1~] greater than 1 item
  10398 + checked[~3] less than 3 items
  10399 + checked[3] 3 items
  10400 + **/
  10401 + checked: function(element, params) {
  10402 + if ( !_checkable(element) ) return;
  10403 +
  10404 + var me = this,
  10405 + elem, count;
  10406 +
  10407 + if (element.name) {
  10408 + count = me.$el.find('input[name="' + element.name + '"]').filter(function() {
  10409 + var el = this;
  10410 + if (!elem && _checkable(el)) elem = el;
  10411 + return !el.disabled && el.checked;
  10412 + }).length;
  10413 + } else {
  10414 + elem = element;
  10415 + count = elem.checked;
  10416 + }
  10417 +
  10418 + if (params) {
  10419 + return me.getRangeMsg(count, params);
  10420 + } else {
  10421 + return !!count || _getDataMsg(elem, me, '') || me.messages.required;
  10422 + }
  10423 + },
  10424 +
  10425 + /**
  10426 + * length of a characters (You can pass the second parameter "true", will calculate the length in bytes)
  10427 + *
  10428 + * @example:
  10429 + length[6~16] 6-16 characters
  10430 + length[6~] Greater than 6 characters
  10431 + length[~16] Less than 16 characters
  10432 + length[~16, true] Less than 16 characters, non-ASCII characters calculating two-character
  10433 + **/
  10434 + length: function(element, params) {
  10435 + var value = this.value,
  10436 + len = (params[1] === 'true' ? value.replace(rDoubleBytes, 'xx') : value).length;
  10437 +
  10438 + return this.getRangeMsg(len, params, (params[1] ? '_2' : ''));
  10439 + },
  10440 +
  10441 + /**
  10442 + * remote validation
  10443 + *
  10444 + * @description
  10445 + * remote([get:]url [, name1, [name2 ...]]);
  10446 + * Adaptation three kinds of results (Front for the successful, followed by a failure):
  10447 + 1. text:
  10448 + '' 'Error Message'
  10449 + 2. json:
  10450 + {"ok": ""} {"error": "Error Message"}
  10451 + 3. json wrapper:
  10452 + {"status": 1, "data": {"ok": ""}} {"status": 1, "data": {"error": "Error Message"}}
  10453 + * @example
  10454 + The simplest: remote(path/to/server);
  10455 + With parameters: remote(path/to/server, name1, name2, ...);
  10456 + By GET: remote(get:path/to/server, name1, name2, ...);
  10457 + Name proxy: remote(path/to/server, name1, proxyname2:name2, proxyname3:#id3, ...)
  10458 + Query String remote(path/to/server, foo=1&bar=2, name1, name2, ...)
  10459 + */
  10460 + remote: function(element, params) {
  10461 + if (!params) return;
  10462 +
  10463 + var me = this,
  10464 + arr = rAjaxType.exec(params[0]),
  10465 + rule = me._rules[me._i],
  10466 + data = {},
  10467 + queryString = '',
  10468 + url = arr[3],
  10469 + type = arr[2] || 'POST', // GET / POST
  10470 + rType = (arr[1]||'').toLowerCase(), // CORS / JSONP
  10471 + dataType;
  10472 +
  10473 + rule.must = true;
  10474 + data[element.name] = me.value;
  10475 +
  10476 + // There are extra fields
  10477 + if (params[1]) {
  10478 + $.map(params.slice(1), function(name) {
  10479 + var arr, key;
  10480 + if (~name.indexOf('=')) {
  10481 + queryString += '&' + name;
  10482 + } else {
  10483 + arr = name.split(':');
  10484 + name = trim(arr[0]);
  10485 + key = trim(arr[1]) || name;
  10486 + data[ name ] = me.$el.find( _key2selector(key) ).val();
  10487 + }
  10488 + });
  10489 + }
  10490 +
  10491 + data = $.param(data) + queryString;
  10492 + if (!me.must && rule.data && rule.data === data) {
  10493 + return rule.result;
  10494 + }
  10495 +
  10496 + // Cross-domain request, force jsonp dataType
  10497 + if (rType !== 'cors' && /^https?:/.test(url) && !~url.indexOf(location.host)) {
  10498 + dataType = 'jsonp';
  10499 + }
  10500 +
  10501 + // Asynchronous validation need return jqXHR objects
  10502 + return $.ajax({
  10503 + url: url,
  10504 + type: type,
  10505 + data: data,
  10506 + dataType: dataType
  10507 + });
  10508 + },
  10509 +
  10510 + /**
  10511 + * filter characters, direct filtration without prompting error (support custom regular expressions)
  10512 + *
  10513 + * @example
  10514 + * filter filtering unsafe characters
  10515 + * filter(regexp) filtering the "regexp" matched characters
  10516 + */
  10517 + filter: function(element, params) {
  10518 + var value = this.value,
  10519 + temp = value.replace( params ? (new RegExp("[" + params[0] + "]", "gm")) : rUnsafe, '' );
  10520 + if (temp !== value) this.setValue(temp);
  10521 + }
  10522 + });
  10523 +
  10524 +
  10525 + /**
  10526 + * Config global options
  10527 + *
  10528 + * @static config
  10529 + * @param {Object} options
  10530 + */
  10531 + Validator.config = function(key, value) {
  10532 + if (isObject(key)) {
  10533 + $.each(key, _config);
  10534 + }
  10535 + else if (isString(key)) {
  10536 + _config(key, value);
  10537 + }
  10538 +
  10539 + function _config(k, o) {
  10540 + if (k === 'rules') {
  10541 + new Rules(o);
  10542 + }
  10543 + else if (k === 'messages') {
  10544 + new Messages(o);
  10545 + }
  10546 + else if (k in fieldDefaults) {
  10547 + fieldDefaults[k] = o;
  10548 + }
  10549 + else {
  10550 + defaults[k] = o;
  10551 + }
  10552 + }
  10553 + };
  10554 +
  10555 + /**
  10556 + * Config themes
  10557 + *
  10558 + * @static setTheme
  10559 + * @param {String|Object} name
  10560 + * @param {Object} obj
  10561 + * @example
  10562 + .setTheme( themeName, themeOptions )
  10563 + .setTheme( multiThemes )
  10564 + */
  10565 + Validator.setTheme = function(name, obj) {
  10566 + if ( isObject(name) ) {
  10567 + $.extend(true, themes, name);
  10568 + }
  10569 + else if ( isString(name) && isObject(obj) ) {
  10570 + themes[name] = $.extend(themes[name], obj);
  10571 + }
  10572 + };
  10573 +
  10574 + /**
  10575 + * Resource loader
  10576 + *
  10577 + * @static load
  10578 + * @param {String} str
  10579 + * @example
  10580 + .load('local=zh-CN') // load: local/zh-CN.js and jquery.validator.css
  10581 + .load('local=zh-CN&css=') // load: local/zh-CN.js
  10582 + .load('local&css') // load: local/en.js (set <html lang="en">) and jquery.validator.css
  10583 + .load('local') // dito
  10584 + */
  10585 + Validator.load = function(str) {
  10586 + if (!str) return;
  10587 + var doc = document,
  10588 + params = {},
  10589 + node = doc.scripts[0],
  10590 + dir, el, ONLOAD;
  10591 +
  10592 + str.replace(/([^?=&]+)=([^&#]*)/g, function(m, key, value){
  10593 + params[key] = value;
  10594 + });
  10595 +
  10596 + dir = params.dir || Validator.dir;
  10597 +
  10598 + if (!Validator.css && params.css !== '') {
  10599 + el = doc.createElement('link');
  10600 + el.rel = 'stylesheet';
  10601 + el.href = Validator.css = dir + 'jquery.validator.css';
  10602 + node.parentNode.insertBefore(el, node);
  10603 + }
  10604 + if (!Validator.local && ~str.indexOf('local') && params.local !== '') {
  10605 + Validator.local = (params.local || doc.documentElement.lang || 'en').replace('_','-');
  10606 + Validator.pending = 1;
  10607 + el = doc.createElement('script');
  10608 + el.src = dir + 'local/' + Validator.local + '.js';
  10609 + ONLOAD = 'onload' in el ? 'onload' : 'onreadystatechange';
  10610 + el[ONLOAD] = function() {
  10611 + if (!el.readyState || /loaded|complete/.test(el.readyState)) {
  10612 + el = el[ONLOAD] = null;
  10613 + delete Validator.pending;
  10614 + $(window).triggerHandler('validatorready');
  10615 + }
  10616 + };
  10617 + node.parentNode.insertBefore(el, node);
  10618 + }
  10619 + };
  10620 +
  10621 + // Auto loading resources
  10622 + (function(){
  10623 + var scripts = document.scripts,
  10624 + i = scripts.length, node, arr,
  10625 + re = /(.*validator(?:\.min)?.js)(\?.*(?:local|css|dir)(?:=[\w\-]*)?)?/;
  10626 +
  10627 + while (i-- && !arr) {
  10628 + node = scripts[i];
  10629 + arr = (node.hasAttribute ? node.src : node.getAttribute('src',4)||'').match(re);
  10630 + }
  10631 +
  10632 + if (!arr) return;
  10633 + Validator.dir = arr[1].split('/').slice(0, -1).join('/')+'/';
  10634 + Validator.load(arr[2]);
  10635 + })();
  10636 +
  10637 + return $[NS] = Validator;
  10638 +}));
  10639 +
8495 define('form',['jquery', 'bootstrap', 'backend', 'config', 'toastr', 'upload', 'validator'], function ($, undefined, Backend, Config, Toastr, Upload, Validator) { 10640 define('form',['jquery', 'bootstrap', 'backend', 'config', 'toastr', 'upload', 'validator'], function ($, undefined, Backend, Config, Toastr, Upload, Validator) {
8496 var Form = { 10641 var Form = {
8497 config: { 10642 config: {