private.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /**
  2. * Private methods
  3. */
  4. module.exports = {
  5. _init: function() {
  6. var self = this;
  7. this.$form = $(this.el);
  8. this.$fields = $();
  9. this.$inputs = $();
  10. this._extend($.idealforms.extensions);
  11. this._i18n();
  12. this._inject('_init');
  13. this.addRules(this.opts.rules || {});
  14. this.$form.submit(function(e) {
  15. e.preventDefault();
  16. self._validateAll();
  17. self.focusFirstInvalid();
  18. self.opts.onSubmit.call(self, self.getInvalid().length, e);
  19. });
  20. if (! this.opts.silentLoad) {
  21. // 1ms timeout to make sure error shows up
  22. setTimeout($.proxy(this.focusFirstInvalid, this), 1);
  23. }
  24. },
  25. _i18n: function() {
  26. if (this.opts.i18n == 'en') return;
  27. var lang = $.idealforms.i18n[this.opts.i18n]
  28. , errors = lang.errors
  29. , options = {};
  30. delete lang.errors;
  31. for (var ext in lang) options[ext] = { i18n: lang[ext] };
  32. $.extend($.idealforms.errors, errors);
  33. $.extend(true, this.opts, options);
  34. },
  35. _buildField: function(input) {
  36. var self = this
  37. , $field = this._getField(input)
  38. , $icon;
  39. $icon = $(this.opts.iconHtml, {
  40. class: this.opts.iconClass,
  41. click: function(){ $(input).focus() }
  42. });
  43. if (! this.$fields.filter($field).length) {
  44. this.$fields = this.$fields.add($field);
  45. if (this.opts.iconHtml) $field.append($icon);
  46. $field.addClass('idealforms-field idealforms-field-'+ input.type);
  47. }
  48. this._addEvents(input);
  49. this._inject('_buildField', input);
  50. },
  51. _addEvents: function(input) {
  52. var self = this
  53. , $field = this._getField(input);
  54. $(input)
  55. .on('change keyup', function(e) {
  56. if (e.which == 9 || e.which == 16) return;
  57. self._validate(this, true, true);
  58. })
  59. .focus(function() {
  60. if (! self.isValid(this.name)) {
  61. $field.find(self.opts.error).show();
  62. }
  63. })
  64. .blur(function() {
  65. $field.find(self.opts.error).hide();
  66. });
  67. },
  68. _isRequired: function(input) {
  69. // We assume non-text inputs with rules are required
  70. if ($(input).is(':checkbox, :radio, select')) return true;
  71. return this.opts.rules[input.name].indexOf('required') > -1;
  72. },
  73. _getRelated: function(input) {
  74. return this._getField(input).find('[name="'+ input.name +'"]');
  75. },
  76. _getField: function(input) {
  77. return $(input).closest(this.opts.field);
  78. },
  79. _getFirstInvalid: function() {
  80. return this.getInvalid().first().find('input:first, textarea, select');
  81. },
  82. _handleError: function(input, error, valid) {
  83. valid = valid || this.isValid(input.name);
  84. var $error = this._getField(input).find(this.opts.error);
  85. this.$form.find(this.opts.error).hide();
  86. if (error) $error.text(error);
  87. $error.toggle(!valid);
  88. },
  89. _handleStyle: function(input, valid) {
  90. valid = valid || this.isValid(input.name);
  91. this._getField(input)
  92. .removeClass(this.opts.validClass +' '+ this.opts.invalidClass)
  93. .addClass(valid ? this.opts.validClass : this.opts.invalidClass)
  94. .find('.'+ this.opts.iconClass).show();
  95. },
  96. _fresh: function(input) {
  97. this._getField(input)
  98. .removeClass(this.opts.validClass +' '+ this.opts.invalidClass)
  99. .find(this.opts.error).hide()
  100. .end()
  101. .find('.'+ this.opts.iconClass).toggle(this._isRequired(input));
  102. },
  103. _validate: function(input, handleError, handleStyle) {
  104. var self = this
  105. , $field = this._getField(input)
  106. , userRules = this.opts.rules[input.name].split($.idealforms.ruleSeparator)
  107. , oldValue = $field.data('idealforms-value')
  108. , valid = true
  109. , rule;
  110. // Don't validate input if value hasn't changed
  111. if (! $(input).is(':checkbox, :radio') && oldValue == input.value) {
  112. return $field.data('idealforms-valid');
  113. }
  114. $field.data('idealforms-value', input.value);
  115. // Non-required input with empty value must pass validation
  116. if (! input.value && ! this._isRequired(input)) {
  117. $field.removeData('idealforms-valid');
  118. this._fresh(input);
  119. // Required inputs
  120. } else {
  121. $.each(userRules, function(i, userRule) {
  122. userRule = userRule.split($.idealforms.argSeparator);
  123. rule = userRule[0];
  124. var theRule = $.idealforms.rules[rule]
  125. , args = userRule.slice(1)
  126. , error;
  127. error = $.idealforms._format.apply(null, [
  128. $.idealforms._getKey('errors.'+ input.name +'.'+ rule, self.opts) ||
  129. $.idealforms.errors[rule]
  130. ].concat(args));
  131. valid = typeof theRule == 'function'
  132. ? theRule.apply(self, [input, input.value].concat(args))
  133. : theRule.test(input.value);
  134. $field.data('idealforms-valid', valid);
  135. if (handleError) self._handleError(input, error, valid);
  136. if (handleStyle) self._handleStyle(input, valid);
  137. self.opts.onValidate.call(self, input, rule, valid);
  138. return valid;
  139. });
  140. }
  141. this._inject('_validate', input, rule, valid);
  142. return valid;
  143. },
  144. _validateAll: function() {
  145. var self = this;
  146. this.$inputs.each(function(){ self._validate(this, true); });
  147. }
  148. };