/** * @constructor */ greppy.Validator = function() { }; /** * Initializes greppy validators. */ greppy.Validator.prototype.init = function () { var self = this; this.allValidators = $('input, select, textarea').filter('.greppy-validator'); this.events = []; this.bindEvent('invalid', 'gValidationInvalid'); this.bindEvent('change', 'gValidationUpdate'); this.bindEvent('keyup', 'gValidationUpdate'); $(document).on({ gValidationUpdate: function(e) { // check if it's valid or invalid self.validate(e.target); }, gValidationInvalid: function(e) { self.markInvalid(self.getMark(e.target)); self.showMsg(e.target); e.preventDefault(); } }); }; /** * Bind an event to trigger Greppy validator events. * * @param {String} origEvtName Name of the event to be bound. * @param {String} gEvtName May be 'gValidationInvalid' or 'gValidationUpdate'. */ greppy.Validator.prototype.bindEvent = function(origEvtName, gEvtName) { var self = this; if ('gValidationInvalid' !== gEvtName && 'gValidationUpdate' !== gEvtName) { throw new Error('No such Greppy validator event exists: ' + gEvtName); } this.events.push({ origEvtName : origEvtName, gEvtName : gEvtName }); $(this.allValidators).each(function(idx, el) { self.bindEventToValidator(el, origEvtName, gEvtName); }); }; /** * This binds an element's event to a specified greppy Validator event. * * @param {jQuery} validator * @param {String} origEvtName * @param {String} gEvtName */ greppy.Validator.prototype.bindEventToValidator = function(validator, origEvtName, gEvtName) { validator = $(validator); validator.on(origEvtName, function(e) { $(this).trigger(gEvtName); if ('gValidationInvalid' === gEvtName) { e.preventDefault(); } }); }; /** * Gets the element which should be marked if an error occurs. * * @param {jQuery} el The validator. * @returns {jQuery} */ greppy.Validator.prototype.getMark = function (el) { el = $(el); var name = el.attr('name'); var result; if (null === name) { return el; } result = el.parents('*[data-greppy-validator-mark="' + name + '"]'); if (0 === result.length && el.hasClass('multiselect')) { result = el.nextAll('.btn-group'); } return 0 < result.length ? result : el; }; /** * Add a validator to the current set of validators. * * @param {type} el * @returns {undefined} */ greppy.Validator.prototype.addValidator = function(el) { if (!$(el).hasClass('greppy-validator')) { throw new Error('Element passed is not a Greppy validator!'); } this.allValidators.add(el); this.bindAllEventsToValidator(el); }; /** * Applies the defined events to the specified validator. * * @param {jQuery} validator */ greppy.Validator.prototype.bindAllEventsToValidator = function(validator) { var self = this; this.events.forEach(function(el, idx) { self.bindEventToValidator(validator, el.origEvtName, el.gEvtName); }); }; /** * Validates an element. * * @param {Object} el The element to validate. */ greppy.Validator.prototype.validate = function (el) { if (false === el.checkValidity()) { this.markInvalid(this.getMark(el)); //this.showMsg(el); return; } this.removeInvalidMark(this.getMark(el)); this.removeMsg(this.getMark(el)); }; /** * Marks the provided element as invalid. * * @param {Object} el */ greppy.Validator.prototype.markInvalid = function(el) { $(el).addClass('greppy-validator-invalid'); }; /** * Removes an invalid mark from the provided element. * * @param {Object} el */ greppy.Validator.prototype.removeInvalidMark = function(el) { $(el).removeClass('greppy-validator-invalid'); }; /** * Shows the validation message of a provided element. * * @param {type} el */ greppy.Validator.prototype.showMsg = function(el) { //el = this.getUniqueValidator(el); el = $(el); var mark = this.getMark(el); var self = this; if (this.hasActiveMsg(el)) { return; } $('<div class="greppy-validator-msg btn btn-danger" data-greppy-validator-name="' + el.attr('name') + '" />') .html(mark.attr('data-greppy-validator-msg') || el.attr('data-greppy-validator-msg') || 'Validation failed') .insertAfter(mark) .hide() .fadeIn() .css({ top: mark.position().top + mark.outerHeight() + 4, left: mark.position().left }) .on('mouseleave', function() { self.removeMsg(mark); }); }; /** * Returns wether the passed element has an active message. * * @param {jQuery} el * @returns {Boolean} */ greppy.Validator.prototype.hasActiveMsg = function(el) { var name = el.attr('name'); var mark = this.getMark(el); if (name && mark.nextAll('.greppy-validator-msg[data-greppy-validator-name="' + name + '"]').length) { return true; } return false; }; /** * Removes the msg-element of a provided mark element, if there's any. * * @param {Object} el The mark element * @param {Boolean} fast No fading out; fast removing. */ greppy.Validator.prototype.removeMsg = function(el, fast) { el = $(el).nextAll('.greppy-validator-msg'); if (fast) { el.remove(); return; } el.fadeOut(function() { el.remove(); }); };