|
|
@@ -22,10 +22,14 @@
|
|
|
$.bootstrapValidator = function(form, options) {
|
|
|
this.$form = $(form);
|
|
|
this.options = $.extend({}, $.bootstrapValidator.DEFAULT_OPTIONS, options);
|
|
|
- this.validate();
|
|
|
- this.xhrRequests = {};
|
|
|
+
|
|
|
+ this.invalidFields = {};
|
|
|
+ this.xhrRequests = {};
|
|
|
this.numPendingRequests = 0;
|
|
|
+
|
|
|
+ this.init();
|
|
|
};
|
|
|
+
|
|
|
$.extend($.bootstrapValidator, {
|
|
|
/**
|
|
|
* The default options
|
|
|
@@ -35,13 +39,7 @@
|
|
|
message: 'This value is not valid',
|
|
|
|
|
|
// Map the field name with validator rules
|
|
|
- fields: null,
|
|
|
-
|
|
|
- // CSS class of icons indicating that the field value is valid or not
|
|
|
- iconClass: {
|
|
|
- valid: 'icon-ok',
|
|
|
- invalid: 'icon-remove'
|
|
|
- }
|
|
|
+ fields: null
|
|
|
},
|
|
|
|
|
|
// Available validators
|
|
|
@@ -59,16 +57,31 @@
|
|
|
/**
|
|
|
* Validate form
|
|
|
*/
|
|
|
- validate: function() {
|
|
|
+ init: function() {
|
|
|
if (this.options.fields == null) {
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ var that = this;
|
|
|
+ this.$form
|
|
|
+ .addClass('bootstrap-validate-form')
|
|
|
+ .on('submit', function(e) {
|
|
|
+ if (that.options.fields) {
|
|
|
+ for (var field in that.options.fields) {
|
|
|
+ that.validateField(field);
|
|
|
+ }
|
|
|
+ if (!that.isValid()) {
|
|
|
+ e.preventDefault();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
for (var field in this.options.fields) {
|
|
|
- this.validateField(field);
|
|
|
+ this.initField(field);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- validateField: function(field) {
|
|
|
+ initField: function(field) {
|
|
|
if (this.options.fields[field] == null || this.options.fields[field].validator == null) {
|
|
|
return;
|
|
|
}
|
|
|
@@ -78,97 +91,89 @@
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- var that = this,
|
|
|
- $field = $(foundFields[0]),
|
|
|
- type = $field.attr('type'),
|
|
|
- event = ('checkbox' == type || 'radio' == type) ? 'change' : 'keyup';
|
|
|
-
|
|
|
- $field
|
|
|
- .on(event, function() {
|
|
|
- var validators = that.options.fields[field].validator;
|
|
|
- for (var validatorName in validators) {
|
|
|
- if (!$.bootstrapValidator.validator[validatorName]) {
|
|
|
- continue;
|
|
|
+ // Create a help block element for showing the error
|
|
|
+ var that = this,
|
|
|
+ $field = $(foundFields[0]),
|
|
|
+ $parent = $field.parents('.form-group'),
|
|
|
+ helpBlock = $parent.find('.help-block');
|
|
|
+
|
|
|
+ if (helpBlock.length == 0) {
|
|
|
+ var $small = $('<small/>').addClass('help-block').appendTo($parent);
|
|
|
+ $field.data('bootstrapValidator.error', $small);
|
|
|
+
|
|
|
+ // Calculate the number of columns of the label/field element
|
|
|
+ // Then set offset to the help block element
|
|
|
+ var label, cssClasses, offset;
|
|
|
+ if (label = $parent.find('label').get(0)) {
|
|
|
+ cssClasses = $(label).attr('class').split(' ');
|
|
|
+ for (var i = 0; i < cssClasses.length; i++) {
|
|
|
+ if (cssClasses[i].substr(0, 7) == 'col-lg-') {
|
|
|
+ offset = cssClasses[i].substr(7);
|
|
|
+ break;
|
|
|
}
|
|
|
- var isValid = $.bootstrapValidator.validator[validatorName].validate(that, $field, validators[validatorName]);
|
|
|
- if (isValid === false) {
|
|
|
- that.showError($field, validatorName);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ cssClasses = $parent.children().eq(0).attr('class').split(' ');
|
|
|
+ for (var i = 0; i < cssClasses.length; i++) {
|
|
|
+ if (cssClasses[i].substr(0, 14) == 'col-lg-offset-') {
|
|
|
+ offset = cssClasses[i].substr(14);
|
|
|
break;
|
|
|
- } else if (isValid === true) {
|
|
|
- that.removeError($field);
|
|
|
}
|
|
|
}
|
|
|
- })
|
|
|
- .blur(function() {
|
|
|
- that.hideError($field);
|
|
|
- });
|
|
|
+ }
|
|
|
+ $small.addClass('col-lg-offset-' + offset).addClass('col-lg-' + parseInt(12 - offset));
|
|
|
+ } else {
|
|
|
+ $field.data('bootstrapValidator.error', helpBlock.eq(0));
|
|
|
+ }
|
|
|
+
|
|
|
+ var type = $field.attr('type'),
|
|
|
+ event = ('checkbox' == type || 'radio' == type) ? 'change' : 'keyup';
|
|
|
+ $field.on(event, function() {
|
|
|
+ that.validateField(field);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ validateField: function(field) {
|
|
|
+ var foundFields = this.$form.find('[name="' + field + '"]');
|
|
|
+ if (foundFields.length == 0) {
|
|
|
+ // Return if cannot find the field with given name
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var that = this,
|
|
|
+ $field = $(foundFields[0]),
|
|
|
+ validators = that.options.fields[field].validator;
|
|
|
+ for (var validatorName in validators) {
|
|
|
+ if (!$.bootstrapValidator.validator[validatorName]) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ var isValid = $.bootstrapValidator.validator[validatorName].validate(that, $field, validators[validatorName]);
|
|
|
+ if (isValid === false) {
|
|
|
+ that.showError($field, validatorName);
|
|
|
+ break;
|
|
|
+ } else if (isValid === true) {
|
|
|
+ that.removeError($field);
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
showError: function($field, validatorName) {
|
|
|
var field = $field.attr('name'),
|
|
|
validator = this.options.fields[field].validator[validatorName],
|
|
|
- message = validator.message || this.options.message;
|
|
|
-
|
|
|
- if (!$field.data('bootstrapValidator.tooltip')) {
|
|
|
- var $a = $('<a/>').attr('href', '#')
|
|
|
- .attr('title', message)
|
|
|
- // Bootstrap tooltip options
|
|
|
- // see http://getbootstrap.com/javascript/#tooltips
|
|
|
- .attr('data-toggle', 'tooltip').attr('data-placement', 'right')
|
|
|
- .css('text-decoration', 'none')
|
|
|
- .css('position', 'absolute')
|
|
|
- .insertAfter($field);
|
|
|
- $('<i/>').addClass(this.options.iconClass.invalid).appendTo($a);
|
|
|
- $field.data('bootstrapValidator.tooltip', $a);
|
|
|
-
|
|
|
- $a.on('shown.bs.tooltip', function() {
|
|
|
- if (!$(this).data('bootstrapValidator.tooltip.calculated')) {
|
|
|
- $(this).data('bootstrapValidator.tooltip.calculated', true);
|
|
|
- var $parent = $(this).parent(),
|
|
|
- $tip = $(this).data('bs.tooltip').$tip,
|
|
|
- w = $parent.width(),
|
|
|
- h = $parent.height(),
|
|
|
- tipWidth = parseInt($tip.width()),
|
|
|
- tipHeight = parseInt($tip.height()),
|
|
|
- tipLeft = parseInt($tip.css('left')),
|
|
|
- tipTop = parseInt($tip.css('top'));
|
|
|
- $tip.css('left', tipLeft + w + 10)
|
|
|
- .css('top', tipTop - h + 5)
|
|
|
- .width(tipWidth);
|
|
|
- $(this).css('position', 'absolute')
|
|
|
- .css('left', tipLeft - $(this).width() + w + 5)
|
|
|
- .css('top', tipTop + tipHeight / 2 - $(this).height() / 2 - h + 5);
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
+ message = validator.message || this.options.message,
|
|
|
+ $parent = $field.parents('.form-group');
|
|
|
+
|
|
|
+ this.invalidFields[field] = true;
|
|
|
|
|
|
// Add has-error class to parent element
|
|
|
- $field.parents('.form-group').removeClass('has-success').addClass('has-error');
|
|
|
-
|
|
|
- $field
|
|
|
- .data('bootstrapValidator.tooltip')
|
|
|
- .find('i').attr('class', this.options.iconClass.invalid).end()
|
|
|
- .attr('title', message)
|
|
|
- .attr('data-original-title', message)
|
|
|
- .tooltip('show');
|
|
|
- },
|
|
|
+ $parent.removeClass('has-success').addClass('has-error');
|
|
|
|
|
|
- hideError: function($field) {
|
|
|
- var $tip = $field.data('bootstrapValidator.tooltip');
|
|
|
- if ($tip) {
|
|
|
- $tip.tooltip('hide');
|
|
|
- }
|
|
|
+ $field.data('bootstrapValidator.error').html(message).show();
|
|
|
},
|
|
|
|
|
|
removeError: function($field) {
|
|
|
+ this.invalidFields[$field.attr('name')] = false;
|
|
|
$field.parents('.form-group').removeClass('has-error').addClass('has-success');
|
|
|
- var $tip = $field.data('bootstrapValidator.tooltip');
|
|
|
- if ($tip) {
|
|
|
- $tip.find('i').attr('class', this.options.iconClass.valid).end()
|
|
|
- .tooltip('destroy')
|
|
|
- .remove();
|
|
|
- $field.removeData('bootstrapValidator.tooltip');
|
|
|
- }
|
|
|
+ $field.data('bootstrapValidator.error').hide();
|
|
|
},
|
|
|
|
|
|
startRequest: function($field, validatorName, xhr) {
|
|
|
@@ -192,10 +197,23 @@
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- var xhr = this.xhrRequests[field][validatorName];
|
|
|
this.numPendingRequests--;
|
|
|
+ var xhr = this.xhrRequests[field][validatorName];
|
|
|
xhr.abort();
|
|
|
delete this.xhrRequests[field][validatorName];
|
|
|
+ },
|
|
|
+
|
|
|
+ isValid: function() {
|
|
|
+ console.log(this.numPendingRequests);
|
|
|
+ if (this.numPendingRequests > 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ for (var field in this.invalidFields) {
|
|
|
+ if (this.invalidFields[field]) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
});
|