(function($, win) { var cls = win.Validator = new win.Class(); cls.include({ init: function($form, options) { this.$form = $form; this.options = options; this.$btnSubmit = null; }, bindSubmit: function() { if (this.options.btnSubmit) { this.$btnSubmit = $('#'+this.options.btnSubmit, this.$form); } else { this.$btnSubmit = $('input[type=submit]', this.$form); } if (this.$btnSubmit.length !== 1) { console.log('Validator cannot position submit button'); return; } else { if (this.$btnSubmit.attr('type') === 'submit') { this.$form.bind('submit', this.proxy(function() { this.validate(); return false; })); } else { this.$btnSubmit.bind('click', this.proxy(this.validate)); } this.bindChange(); } }, validate: function() { var remotes = []; var cond = { pass: true, req: 0, fn: this.doSubmit }; var rules = this.options.rules; var messages = this.options.messages; for (var name in rules) { var $elm = $('[name='+name+']', this.$form); if ($elm.length > 0) { var rule = rules[name]; var message = messages[name]; var methods = this.constructor.methods; for (var rn in rule) { var method = methods[rn]; var msg = message[rn] if (method) { $elm.next('#tip_' + name).remove(); if (rn === 'remote') { var cb = (function($elm, param, msg, cond, method) { return function() { method($elm, param, msg, cond); } })($elm, rule[rn], msg, cond, method); cond.req = cond.req + 1; remotes.push(cb); } else { if (!method($elm, rule[rn])) { var $tip = $('<label>').attr('id', 'tip_' + name); $tip.append(msg); $elm.after($tip); cond.pass = false; break; } } } else if(typeof rule[rn] === 'function') { //TODO } else { continue; } } } } if (cond.req > 0) { for (var i=-1, len=remotes.length; ++i<len;) { remotes[i](); } } else { if (cond.pass) { this.doSubmit(); } } }, doSubmit: function() { alert('ok'); }, bindChange: function() { var rules = this.options.rules; var messages = this.options.messages; for (var name in rules) { var $elm = $('[name='+name+']', this.$form); if ($elm.length > 0) { var rule = rules[name]; var message = messages[name]; (function($elm, rule, message){ $elm.bind('change', this.proxy(function(e) { var methods = this.constructor.methods; for (var rn in rule) { var method = methods[rn]; var msg = message[rn] if (method) { $elm.next('#tip_' + $elm[0].name).remove(); if (rn === 'remote') { method($elm, rule[rn], msg); } else { if (!method($elm, rule[rn])) { var $tip = $('<label>').attr('id', 'tip_' + $elm[0].name); $tip.append(msg); $elm.after($tip); break; } } } else if(typeof rule[rn] === 'function') { //rule[rn](); } else { continue; } } })); }).call(this, $elm, rule, message); } } } }); cls.extend({ init: function($form, options) { var o = new this($form, options); o.bindSubmit(); return o; }, methods: { required: function($elm, param) { var value = $elm.val(); return value.length > 0; }, remote: function($elm, param, msg, cond) { var ajaxParam = null; if (param.constructor == String) { ajaxParam = { url: param } } else if (param.constructor == Object) { ajaxParam = param; } else if (param.constructor == Function) { ajaxParam = param(); } var data = {}; data[$elm[0].name] = $elm.val(); if (!ajaxParam.url) { return; } $.ajax($.extend(true, { type: 'GET', dataType: 'json', data: data, success: function(data) { if (cond != undefined) { if (typeof data === 'boolean') { cond.pass = data && cond.pass; } else if (typeof data === 'string') { cond.pass = ('true' === data) && cond.pass; } else { cond.pass = false; } var req = cond.req = cond.req - 1; if (cond.pass && req === 0) { cond.fn(); return; } else if (cond.pass) { return; } } else { if (typeof data === 'boolean') { var pass = data; } else if (typeof data === 'string') { var pass = 'true' === data; } else { var pass =false; } if (pass) { return; } } var $tip = $('<label>').attr('id', 'tip_' + $elm[0].name); $tip.append(msg); $elm.after($tip); }, error: function() { if (cond != undefined) { cond.pass = false; //cond.req = cond.req - 1; var $tip = $('<label>').attr('id', 'tip_' + $elm[0].name); $tip.append(msg); $elm.after($tip); } } }, ajaxParam)) } } }); })(jQuery, window);