/** * Private methods */ module.exports = { _init: function() { var self = this; this.$form = $(this.el); this.$fields = $(); this.$inputs = $(); this._extend($.idealforms.extensions); this._i18n(); this._inject('_init'); this._addMarkupRules(); this.addRules(this.opts.rules || {}); this.$form.submit(function(e) { self._validateAll(true); self.focusFirstInvalid(); self.opts.onSubmit.call(self, self.getInvalid().length, e); }); if (! this.opts.silentLoad) { // 1ms timeout to make sure error shows up setTimeout($.proxy(this.focusFirstInvalid, this), 1); } }, _addMarkupRules: function() { var rules = {}; this.$form.find('input, select, textarea').each(function() { var rule = $(this).data('idealforms-rules'); if (rule && ! rules[this.name]) rules[this.name] = rule; }); this.addRules(rules); }, _i18n: function() { var self = this; $.each($.idealforms.i18n, function(locale, lang) { var errors = lang.errors , options = {}; delete lang.errors; for (var ext in lang) options[ext] = { i18n: lang[ext] }; $.extend($.idealforms.errors, errors); $.extend(true, self.opts, options); }); }, _buildField: function(input) { var self = this , $field = this._getField(input) , $icon; $icon = $(this.opts.iconHtml, { class: this.opts.iconClass, click: function(){ $(input).focus() } }); if (! this.$fields.filter($field).length) { this.$fields = this.$fields.add($field); if (this.opts.iconHtml) $field.append($icon); $field.addClass('idealforms-field idealforms-field-'+ input.type); } this._addEvents(input); this._inject('_buildField', input); }, _addEvents: function(input) { var self = this , $field = this._getField(input); $(input) .on('change keyup', function(e) { if (e.which == 9 || e.which == 16) return; self._validate(this, true, true); }) .focus(function() { if (! self.isValid(this.name)) { $field.find(self.opts.error).show(); } }) .blur(function() { $field.find(self.opts.error).hide(); }); }, _isRequired: function(input) { // We assume non-text inputs with rules are required if ($(input).is(':checkbox, :radio, select')) return true; return this.opts.rules[input.name].indexOf('required') > -1; }, _getRelated: function(input) { return this._getField(input).find('[name="'+ input.name +'"]'); }, _getField: function(input) { return $(input).closest(this.opts.field); }, _getFirstInvalid: function() { return this.getInvalid().first().find('input:first, textarea, select'); }, _handleError: function(input, error, valid) { valid = valid || this.isValid(input.name); var $error = this._getField(input).find(this.opts.error); this.$form.find(this.opts.error).hide(); if (error) $error.text(error); $error.toggle(!valid); }, _handleStyle: function(input, valid) { valid = valid || this.isValid(input.name); this._getField(input) .removeClass(this.opts.validClass +' '+ this.opts.invalidClass) .addClass(valid ? this.opts.validClass : this.opts.invalidClass) .find('.'+ this.opts.iconClass).show(); }, _fresh: function(input) { this._getField(input) .removeClass(this.opts.validClass +' '+ this.opts.invalidClass) .find(this.opts.error).hide() .end() .find('.'+ this.opts.iconClass).toggle(this._isRequired(input)); }, _validate: function(input, handleError, handleStyle) { var self = this , $field = this._getField(input) , userRules = this.opts.rules[input.name].split($.idealforms.ruleSeparator) , oldValue = $field.data('idealforms-value') , valid = true , rule; // Don't validate input if value hasn't changed if (! $(input).is(':checkbox, :radio') && oldValue == input.value) { return $field.data('idealforms-valid'); } $field.data('idealforms-value', input.value); // Non-required input with empty value must pass validation if (! input.value && ! this._isRequired(input)) { $field.removeData('idealforms-valid'); this._fresh(input); // Inputs with value or required } else { $.each(userRules, function(i, userRule) { userRule = userRule.split($.idealforms.argSeparator); rule = userRule[0]; var theRule = $.idealforms.rules[rule] , args = userRule.slice(1) , error; error = $.idealforms._format.apply(null, [ $.idealforms._getKey('errors.'+ input.name +'.'+ rule, self.opts) || $.idealforms.errors[rule] ].concat(args)); valid = typeof theRule == 'function' ? theRule.apply(self, [input, input.value].concat(args)) : theRule.test(input.value); $field.data('idealforms-valid', valid); if (handleError) self._handleError(input, error, valid); if (handleStyle) self._handleStyle(input, valid); self.opts.onValidate.call(self, input, rule, valid); return valid; }); } this._inject('_validate', input, rule, valid); return valid; }, _validateAll: function(handleError, handleStyle) { var self = this; this.$inputs.each(function(){ self._validate(this, handleError, handleStyle); }); } };