+function($){'use strict';var Validator=function(element,options){this.$element=$(element) this.options=options options.errors=$.extend({},Validator.DEFAULTS.errors,options.errors) for(var custom in options.custom){if(!options.errors[custom])throw new Error('Missing default error message for custom validator: '+custom)} $.extend(Validator.VALIDATORS,options.custom) this.$element.attr('novalidate',!0) this.toggleSubmit() this.$element.on('input.bs.validator change.bs.validator focusout.bs.validator',$.proxy(this.validateInput,this)) this.$element.on('submit.bs.validator',$.proxy(this.onSubmit,this)) this.$element.find('[data-match]').each(function(){var $this=$(this) var target=$this.data('match') $(target).on('input.bs.validator',function(e){$this.val()&&$this.trigger('input.bs.validator')})})} Validator.INPUT_SELECTOR=':input:not([type="submit"], button):enabled:visible' Validator.DEFAULTS={delay:500,html:!1,disable:!0,custom:{},errors:{match:'Does not match',minlength:'Not long enough'},feedback:{success:'glyphicon-ok',error:'glyphicon-remove'}} Validator.VALIDATORS={'native':function($el){var el=$el[0] return el.checkValidity?el.checkValidity():!0},'match':function($el){var target=$el.data('match') return!$el.val()||$el.val()===$(target).val()},'minlength':function($el){var minlength=$el.data('minlength') return!$el.val()||$el.val().length>=minlength}} Validator.prototype.validateInput=function(e){var $el=$(e.target) var prevErrors=$el.data('bs.validator.errors') var errors if($el.is('[type="radio"]'))$el=this.$element.find('input[name="'+$el.attr('name')+'"]') this.$element.trigger(e=$.Event('validate.bs.validator',{relatedTarget:$el[0]})) if(e.isDefaultPrevented())return var self=this this.runValidators($el).done(function(errors){$el.data('bs.validator.errors',errors) errors.length?self.showErrors($el):self.clearErrors($el) if(!prevErrors||errors.toString()!==prevErrors.toString()){e=errors.length?$.Event('invalid.bs.validator',{relatedTarget:$el[0],detail:errors}):$.Event('valid.bs.validator',{relatedTarget:$el[0],detail:prevErrors}) self.$element.trigger(e)} self.toggleSubmit() self.$element.trigger($.Event('validated.bs.validator',{relatedTarget:$el[0]}))})} Validator.prototype.runValidators=function($el){var errors=[] var deferred=$.Deferred() var options=this.options $el.data('bs.validator.deferred')&&$el.data('bs.validator.deferred').reject() $el.data('bs.validator.deferred',deferred) function getErrorMessage(key){return $el.data(key+'-error')||$el.data('error')||key=='native'&&$el[0].validationMessage||options.errors[key]} $.each(Validator.VALIDATORS,$.proxy(function(key,validator){if(($el.data(key)||key=='native')&&!validator.call(this,$el)){var error=getErrorMessage(key) !~errors.indexOf(error)&&errors.push(error)}},this)) if(!errors.length&&$el.val()&&$el.data('remote')){this.defer($el,function(){var data={} data[$el.attr('name')]=$el.val() $.get($el.data('remote'),data).fail(function(jqXHR,textStatus,error){errors.push(getErrorMessage('remote')||error)}).always(function(){deferred.resolve(errors)})})}else deferred.resolve(errors) return deferred.promise()} Validator.prototype.validate=function(){var delay=this.options.delay this.options.delay=0 this.$element.find(Validator.INPUT_SELECTOR).trigger('input.bs.validator') this.options.delay=delay return this} Validator.prototype.showErrors=function($el){var method=this.options.html?'html':'text' this.defer($el,function(){var $group=$el.closest('.form-group') var $block=$group.find('.help-block.with-errors') var $feedback=$group.find('.form-control-feedback') var errors=$el.data('bs.validator.errors') if(!errors.length)return errors=$('