diff --git a/resources/static/js/validator.js b/resources/static/js/validator.js new file mode 100644 index 0000000..cfd442d --- /dev/null +++ b/resources/static/js/validator.js @@ -0,0 +1,323 @@ +/* ======================================================================== + * Bootstrap (plugin): validator.js v0.8.1 + * ======================================================================== + * The MIT License (MIT) + * + * Copyright (c) 2015 Cina Saffary. + * Made by @1000hz in the style of Bootstrap 3 era @fat + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + var inputSelector = ':input:not([type="submit"], button):enabled:visible' + // VALIDATOR CLASS DEFINITION + // ========================== + + 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', true) // disable automatic native validation + 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.DEFAULTS = { + delay: 500, + html: false, + disable: true, + custom: {}, + errors: { + match: 'Does not match', + minlength: 'Not long enough' + }, + feedback: { + success: 'glyphicon-ok', + error: 'glyphicon-warning-sign' + } + } + + Validator.VALIDATORS = { + 'native': function ($el) { + var el = $el[0] + return el.checkValidity ? el.checkValidity() : true + }, + 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(inputSelector).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 = $('