PageSourceSearch

https://lestoitsdumonde.ca/wp-content/plugins/hbook/front-end/js/jquery.form-validator.js?ver=2.0.12

js lestoitsdumonde.ca collected 2026-10-08 16:34:29 UTC 79,730 bytes, 2,400 lines download raw bytes

1(function (root, factory) {
2  if (typeof define === 'function' && define.amd) {
3    // AMD. Register as an anonymous module unless amdModuleId is set
4    define(["jquery"], function (a0) {
5      return (factory(a0));
6    });
7  } else if (typeof module === 'object' && module.exports) {
8    // Node. Does not work with strict CommonJS, but
9    // only CommonJS-like environments that support module.exports,
10    // like Node.
11    module.exports = factory(require("jquery"));
12  } else {
13    factory(root["jQuery"]);
14  }
15}(this, function (jQuery) {
16
17/** File generated by Grunt -- do not modify
18 *  JQUERY-FORM-VALIDATOR
19 *
20 *  @version 2.3.79
21 *  @website http://formvalidator.net/
22 *  @author Victor Jonsson, http://victorjonsson.se
23 *  @license MIT
24 */
25/**
26 */
27(function ($, window, undefined) {
28
29  var disableFormSubmit = function () {
30      return false;
31    },
32    lastFormEvent = null,
33    HaltManager = {
34      numHalted: 0,
35      haltValidation: function($form) {
36        this.numHalted++;
37        $.formUtils.haltValidation = true;
38        $form
39          .unbind('submit', disableFormSubmit)
40          .bind('submit', disableFormSubmit)
41          .find('*[type="submit"]')
42            .addClass('disabled')
43            .attr('disabled', 'disabled');
44      },
45      unHaltValidation: function($form) {
46        this.numHalted--;
47        if (this.numHalted === 0) {
48          $.formUtils.haltValidation = false;
49          $form
50            .unbind('submit', disableFormSubmit)
51            .find('*[type="submit"]')
52              .removeClass('disabled')
53              .removeAttr('disabled', 'disabled');
54        }
55      }
56    };
57
58  function AsyncValidation($form, $input) {
59    this.$form = $form;
60    this.$input = $input;
61    this.reset();
62    $input.on('change paste', this.reset.bind(this));
63  }
64
65  AsyncValidation.prototype.reset = function() {
66    this.haltedFormValidation = false;
67    this.hasRun = false;
68    this.isRunning = false;
69    this.result = undefined;
70  };
71
72  AsyncValidation.prototype.run = function(eventContext, callback) {
73    if (eventContext === 'keyup') {
74      return null;
75    } else if (this.isRunning) {
76      lastFormEvent = eventContext;
77      if (!this.haltedFormValidation) {
78        HaltManager.haltValidation();
79        this.haltedFormValidation = true;
80      }
81      return null; // Waiting for result
82    } else if(this.hasRun) {
83      //this.$input.one('keyup change paste', this.reset.bind(this));
84      return this.result;
85    } else {
86      lastFormEvent = eventContext;
87      HaltManager.haltValidation(this.$form);
88      this.haltedFormValidation = true;
89      this.isRunning = true;
90      this.$input
91        .attr('disabled', 'disabled')
92        .addClass('async-validation');
93      this.$form.addClass('async-validation');
94
95      callback(function(result) {
96        this.done(result);
97      }.bind(this));
98
99      return null;
100    }
101  };
102
103  AsyncValidation.prototype.done = function(result) {
104    this.result = result;
105    this.hasRun = true;
106    this.isRunning = false;
107    this.$input
108      .removeAttr('disabled')
109      .removeClass('async-validation');
110    this.$form.removeClass('async-validation');
111    if (this.haltedFormValidation) {
112      HaltManager.unHaltValidation(this.$form);
113      if (lastFormEvent === 'submit') {
114        this.$form.trigger('submit');
115      } else {
116        this.$input.trigger('validation.revalidate');
117      }
118    }
119  };
120
121  AsyncValidation.loadInstance = function(validatorName, $input, $form) {
122    // Return async validator attached to this input element
123    // or create a new async validator and attach it to the input
124    var asyncValidation,
125      input = $input.get(0);
126
127    if (!input.asyncValidators) {
128      input.asyncValidators = {};
129    }
130
131    if (input.asyncValidators[validatorName]) {
132      asyncValidation = input.asyncValidators[validatorName];
133    } else {
134      asyncValidation = new AsyncValidation($form, $input);
135      input.asyncValidators[validatorName] = asyncValidation;
136    }
137
138    return asyncValidation;
139  };
140
141  $.formUtils = $.extend($.formUtils || {}, {
142
143    /**
144     * @deprecated
145     * @param validatorName
146     * @param $input
147     * @param $form
148     */
149    asyncValidation: function(validatorName, $input, $form) {
150      // @todo: Remove when moving up to version 3.0
151      this.warn('Use of deprecated function $.formUtils.asyncValidation, use $.formUtils.addAsyncValidator() instead');
152      return AsyncValidation.loadInstance(validatorName, $input, $form);
153    },
154
155    /**
156     * @param {Object} asyncValidator
157     */
158    addAsyncValidator: function (asyncValidator) {
159      var validator = $.extend({}, asyncValidator),
160        originalValidatorFunc = validator.validatorFunction;
161      validator.async = true;
162      validator.validatorFunction = function (value, $el, config, language, $form, eventContext) {
163        var asyncValidation = AsyncValidation.loadInstance(this.name, $el, $form);
164        return asyncValidation.run(eventContext, function(done) {
165          originalValidatorFunc.apply(validator, [
166            done, value, $el, config, language, $form, eventContext
167          ]);
168        });
169      };
170      this.addValidator(validator);
171    }
172  });
173
174  // Tag elements having async validators
175  $(window).bind('validatorsLoaded formValidationSetup', function (evt, $form) {
176    if (!$form) {
177      $form = $('form');
178    }
179    $form.find('[data-validation]').each(function () {
180      var $input = $(this);
181      $input.valAttr('async', false);
182      $.each($.split($input.attr('data-validation')), function (i, validatorName) {
183        var validator = $.formUtils.validators['validate_'+validatorName];
184        if (validator && validator.async) {
185          $input.valAttr('async', 'yes');
186        }
187      });
188    });
189  });
190
191})(jQuery, window);
192
193/**
194 * Deprecated functions and attributes
195 * @todo: Remove in release of 3.0
196 */
197(function ($, undefined) {
198
199  'use strict';
200
201  /**
202   * @deprecated
203   * @param language
204   * @param conf
205   */
206  $.fn.validateForm = function (language, conf) {
207    $.formUtils.warn('Use of deprecated function $.validateForm, use $.isValid instead');
208    return this.isValid(language, conf, true);
209  };
210
211  $(window)
212    .on('formValidationPluginInit', function(evt, config) {
213      convertDeprecatedLangCodeToISO6391(config);
214      addSupportForCustomErrorMessageCallback(config);
215      addSupportForElementReferenceInPositionParam(config);
216    })
217    .on('validatorsLoaded formValidationSetup', function(evt, $form) {
218      if( !$form ) {
219        $form = $('form');
220      }
221      addSupportForValidationDependingOnCheckedInput($form);
222    });
223
224
225  function addSupportForCustomErrorMessageCallback(config) {
226    if (config &&
227        config.errorMessagePosition === 'custom' &&
228        typeof config.errorMessageCustom === 'function') {
229
230      $.formUtils.warn('Use of deprecated function errorMessageCustom, use config.submitErrorMessageCallback instead');
231
232      config.submitErrorMessageCallback = function($form, errorMessages) {
233        config.errorMessageCustom(
234            $form,
235            config.language.errorTitle,
236            errorMessages,
237            config
238        );
239      };
240    }
241  }
242
243  function addSupportForElementReferenceInPositionParam(config) {
244    if (config.errorMessagePosition && typeof config.errorMessagePosition === 'object') {
245      $.formUtils.warn('Deprecated use of config parameter errorMessagePosition, use config.submitErrorMessageCallback instead');
246      var $errorMessageContainer = config.errorMessagePosition;
247      config.errorMessagePosition = 'top';
248      config.submitErrorMessageCallback = function() {
249        return $errorMessageContainer;
250      };
251    }
252  }
253
254  function addSupportForValidationDependingOnCheckedInput($form) {
255    var $inputsDependingOnCheckedInputs = $form.find('[data-validation-if-checked]');
256    if ($inputsDependingOnCheckedInputs.length) {
257      $.formUtils.warn(
258        'Detected use of attribute "data-validation-if-checked" which is '+
259        'deprecated. Use "data-validation-depends-on" provided by module "logic"'
260      );
261    }
262
263    $inputsDependingOnCheckedInputs
264      .on('beforeValidation', function() {
265
266        var $elem = $(this),
267          nameOfDependingInput = $elem.valAttr('if-checked');
268
269        // Set the boolean telling us that the validation depends
270        // on another input being checked
271        var $dependingInput = $('input[name="' + nameOfDependingInput + '"]', $form),
272          dependingInputIsChecked = $dependingInput.is(':checked'),
273          valueOfDependingInput = ($.formUtils.getValue($dependingInput) || '').toString(),
274          requiredValueOfDependingInput = $elem.valAttr('if-checked-value');
275
276        if (!dependingInputIsChecked || !(
277              !requiredValueOfDependingInput ||
278              requiredValueOfDependingInput === valueOfDependingInput
279          )) {
280          $elem.valAttr('skipped', true);
281        }
282
283      });
284    }
285
286    function convertDeprecatedLangCodeToISO6391(config) {
287      var deprecatedLangCodes = {
288        se: 'sv',
289        cz: 'cs',
290        dk: 'da'
291      };
292
293      if (config.lang in deprecatedLangCodes) {
294        var newLangCode = deprecatedLangCodes[config.lang];
295        $.formUtils.warn(
296          'Deprecated use of lang code "'+config.lang+'" use "'+newLangCode+'" instead'
297        );
298        config.lang = newLangCode;
299      }
300    }
301
302})(jQuery);
303
304/**
305 * Utility methods used for displaying error messages (attached to $.formUtils)
306 */
307(function ($) {
308
309  'use strict';
310
311  var dialogs = {
312
313    resolveErrorMessage: function($elem, validator, validatorName, conf, language) {
314      var errorMsgAttr = conf.validationErrorMsgAttribute + '-' + validatorName.replace('validate_', ''),
315        validationErrorMsg = $elem.attr(errorMsgAttr);
316
317      if (!validationErrorMsg) {
318        validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
319        if (!validationErrorMsg) {
320          if (typeof validator.errorMessageKey !== 'function') {
321            validationErrorMsg = language[validator.errorMessageKey];
322          }
323          else {
324            validationErrorMsg = language[validator.errorMessageKey(conf)];
325          }
326          if (!validationErrorMsg) {
327            validationErrorMsg = validator.errorMessage;
328          }
329        }
330      }
331      return validationErrorMsg;
332    },
333    getParentContainer: function ($elem) {
334      if ($elem.valAttr('error-msg-container')) {
335        return $($elem.valAttr('error-msg-container'));
336      } else {
337        var $parent = $elem.parent();
338        if($elem.attr('type') === 'checkbox' && $elem.closest('.checkbox').length) {
339          $parent = $elem.closest('.checkbox').parent();
340        } else if($elem.attr('type') === 'radio' && $elem.closest('.radio').length) {
341          $parent = $elem.closest('.radio').parent();
342        }
343        if($parent.closest('.input-group').length) {
344          $parent = $parent.closest('.input-group').parent();
345        }
346        return $parent;
347      }
348    },
349    applyInputErrorStyling: function ($input, conf) {
350      $input
351        .addClass(conf.errorElementClass)
352        .removeClass(conf.successElementClass);
353
354      this.getParentContainer($input)
355        .addClass(conf.inputParentClassOnError)
356        .removeClass(conf.inputParentClassOnSuccess);
357
358      if (conf.borderColorOnError !== '') {
359        $input.css('border-color', conf.borderColorOnError);
360      }
361    },
362    applyInputSuccessStyling: function($input, conf) {
363      $input.addClass(conf.successElementClass);
364      this.getParentContainer($input)
365        .addClass(conf.inputParentClassOnSuccess);
366    },
367    removeInputStylingAndMessage: function($input, conf) {
368
369      // Reset input css
370      $input
371        .removeClass(conf.successElementClass)
372        .removeClass(conf.errorElementClass)
373        .css('border-color', '');
374
375      var $parentContainer = dialogs.getParentContainer($input);
376
377      // Reset parent css
378      $parentContainer
379        .removeClass(conf.inputParentClassOnError)
380        .removeClass(conf.inputParentClassOnSuccess);
381
382      // Remove possible error message
383      if (typeof conf.inlineErrorMessageCallback === 'function') {
384        var $errorMessage = conf.inlineErrorMessageCallback($input, false, conf);
385        if ($errorMessage) {
386          $errorMessage.html('');
387        }
388      } else {
389        $parentContainer
390          .find('.' + conf.errorMessageClass)
391          .remove();
392      }
393
394    },
395    removeAllMessagesAndStyling: function($form, conf) {
396
397      // Remove error messages in top of form
398      if (typeof conf.submitErrorMessageCallback === 'function') {
399        var $errorMessagesInTopOfForm = conf.submitErrorMessageCallback($form, false, conf);
400        if ($errorMessagesInTopOfForm) {
401          $errorMessagesInTopOfForm.html('');
402        }
403      } else {
404        $form.find('.' + conf.errorMessageClass + '.alert').remove();
405      }
406
407      // Remove input css/messages
408      $form.find('.' + conf.errorElementClass + ',.' + conf.successElementClass).each(function() {
409        dialogs.removeInputStylingAndMessage($(this), conf);
410      });
411    },
412    setInlineMessage: function ($input, errorMsg, conf) {
413
414      this.applyInputErrorStyling($input, conf);
415
416      var custom = document.getElementById($input.attr('name') + '_err_msg'),
417        $messageContainer = false,
418        setErrorMessage = function ($elem) {
419          $.formUtils.$win.trigger('validationErrorDisplay', [$input, $elem]);
420          $elem.html(errorMsg);
421        },
422        addErrorToMessageContainer = function() {
423          var $found = false;
424          $messageContainer.find('.' + conf.errorMessageClass).each(function () {
425            if (this.inputReferer === $input[0]) {
426              $found = $(this);
427              return false;
428            }
429          });
430          if ($found) {
431            if (!errorMsg) {
432              $found.remove();
433            } else {
434              setErrorMessage($found);
435            }
436          } else if(errorMsg !== '') {
437            $message = $('<div class="' + conf.errorMessageClass + ' alert"></div>');
438            setErrorMessage($message);
439            $message[0].inputReferer = $input[0];
440            $messageContainer.prepend($message);
441          }
442        },
443        $message;
444
445      if (custom) {
446        // Todo: remove in 3.0
447        $.formUtils.warn('Using deprecated element reference ' + custom.id);
448        $messageContainer = $(custom);
449        addErrorToMessageContainer();
450      } else if (typeof conf.inlineErrorMessageCallback === 'function') {
451        $messageContainer = conf.inlineErrorMessageCallback($input, errorMsg, conf);
452        if (!$messageContainer) {
453          // Error display taken care of by inlineErrorMessageCallback
454          return;
455        }
456        addErrorToMessageContainer();
457      } else {
458        var $parent = this.getParentContainer($input);
459        $message = $parent.find('.' + conf.errorMessageClass + '.help-block');
460        if ($message.length === 0) {
461          $message = $('<span></span>').addClass('help-block').addClass(conf.errorMessageClass);
462          $message.appendTo($parent);
463        }
464        setErrorMessage($message);
465      }
466    },
467    setMessageInTopOfForm: function ($form, errorMessages, conf, lang) {
468      var view = '<div class="{errorMessageClass} alert alert-danger">'+
469                    '<strong>{errorTitle}</strong>'+
470                    '<ul>{fields}</ul>'+
471                '</div>',
472          $container = false;
473
474      if (typeof conf.submitErrorMessageCallback === 'function') {
475        $container = conf.submitErrorMessageCallback($form, errorMessages, conf);
476        if (!$container) {
477          // message display taken care of by callback
478          return;
479        }
480      }
481
482      var viewParams = {
483            errorTitle: lang.errorTitle,
484            fields: '',
485            errorMessageClass: conf.errorMessageClass
486          };
487
488      $.each(errorMessages, function (i, msg) {
489        viewParams.fields += '<li>'+msg+'</li>';
490      });
491
492      $.each(viewParams, function(param, value) {
493        view = view.replace('{'+param+'}', value);
494      });
495
496      if ($container) {
497        $container.html(view);
498      } else {
499        $form.children().eq(0).before($(view));
500      }
501    }
502  };
503
504  $.formUtils = $.extend($.formUtils || {}, {
505    dialogs: dialogs
506  });
507
508})(jQuery);
509
510/**
511 * File declaring all methods if this plugin which is applied to $.fn.
512 */
513(function($, window, undefined) {
514
515  'use strict';
516
517  var _helpers = 0;
518
519
520  /**
521   * Assigns validateInputOnBlur function to elements blur event
522   *
523   * @param {Object} language Optional, will override $.formUtils.LANG
524   * @param {Object} conf Optional, will override the default settings
525   * @return {jQuery}
526   */
527  $.fn.validateOnBlur = function (language, conf) {
528    var $form = this,
529        $elems = this.find('*[data-validation]');
530
531    $elems.each(function(){
532      var $this = $(this);
533      if ($this.is('[type=radio]')){
534        var $additionals = $form.find('[type=radio][name="' + $this.attr('name') + '"]');
535        $additionals.bind('blur.validation', function(){
536          $this.validateInputOnBlur(language, conf, true, 'blur');
537        });
538        if (conf.validateCheckboxRadioOnClick) {
539          $additionals.bind('click.validation', function () {
540            $this.validateInputOnBlur(language, conf, true, 'click');
541          });
542        }
543      }
544    });
545
546    $elems.bind('blur.validation', function () {
547      $(this).validateInputOnBlur(language, conf, true, 'blur');
548    });
549
550    if (conf.validateCheckboxRadioOnClick) {
551      // bind click event to validate on click for radio & checkboxes for nice UX
552      this.find('input[type=checkbox][data-validation],input[type=radio][data-validation]')
553        .bind('click.validation', function () {
554          $(this).validateInputOnBlur(language, conf, true, 'click');
555        });
556    }
557
558    return this;
559  };
560
561  /*
562   * Assigns validateInputOnBlur function to elements custom event
563   * @param {Object} language Optional, will override $.formUtils.LANG
564   * @param {Object} settings Optional, will override the default settings
565   * * @return {jQuery}
566   */
567  $.fn.validateOnEvent = function (language, config) {
568    if(this.length === 0) {
569      return;
570    }
571
572    var $elements = this[0].nodeName === 'FORM' ? this.find('*[data-validation-event]') : this;
573    $elements
574      .each(function () {
575        var $el = $(this),
576          etype = $el.valAttr('event');
577        if (etype) {
578          $el
579            .unbind(etype + '.validation')
580            .bind(etype + '.validation', function (evt) {
581              if( (evt || {}).keyCode !== 9 ) {
582                $(this).validateInputOnBlur(language, config, true, etype);
583              }
584            });
585        }
586      });
587    return this;
588  };
589
590  /**
591   * fade in help message when input gains focus
592   * fade out when input loses focus
593   * <input data-help="The info that I want to display for the user when input is focused" ... />
594   *
595   * @param {String} attrName - Optional, default is data-help
596   * @return {jQuery}
597   */
598  $.fn.showHelpOnFocus = function (attrName) {
599    if (!attrName) {
600      attrName = 'data-validation-help';
601    }
602
603    // Add help text listeners
604    this.find('textarea,input').each(function () {
605      var $elem = $(this),
606        className = 'jquery_form_help_' + (++_helpers),
607        help = $elem.attr(attrName);
608
609      // Reset
610      $elem
611        .removeClass('has-help-text')
612        .unbind('focus.help')
613        .unbind('blur.help');
614
615      if (help) {
616        $elem
617          .addClass('has-help-txt')
618          .bind('focus.help', function () {
619            var $help = $elem.parent().find('.' + className);
620            if ($help.length === 0) {
621              $help = $('<span />')
622                .addClass(className)
623                .addClass('help')
624                .addClass('help-block') // twitter bs
625                .text(help)
626                .hide();
627
628              $elem.after($help);
629            }
630            $help.fadeIn();
631          })
632          .bind('blur.help', function () {
633            $(this)
634              .parent()
635              .find('.' + className)
636              .fadeOut('slow');
637          });
638      }
639    });
640
641    return this;
642  };
643
644  /**
645   * @param {Function} cb
646   * @param {Object} [conf]
647   * @param {Object} [lang]
648   */
649  $.fn.validate = function(cb, conf, lang) {
650    var language = $.extend({}, $.formUtils.LANG, lang || {});
651    this.each(function() {
652      var $elem = $(this),
653        closestFormElem = $elem.closest('form').get(0) || {},
654        formDefaultConfig = closestFormElem.validationConfig || $.formUtils.defaultConfig();
655
656      $elem.one('validation', function(evt, isValid) {
657        if ( typeof cb === 'function' ) {
658          cb(isValid, this, evt);
659        }
660      });
661
662      $elem.validateInputOnBlur(
663        language,
664        $.extend({}, formDefaultConfig, conf || {}),
665        true
666      );
667    });
668  };
669
670  /**
671   * Tells whether or not validation of this input will have to postpone the form submit ()
672   * @returns {Boolean}
673   */
674  $.fn.willPostponeValidation = function() {
675    return (this.valAttr('suggestion-nr') ||
676      this.valAttr('postpone') ||
677      this.hasClass('hasDatepicker')) &&
678      !window.postponedValidation;
679  };
680
681  /**
682   * Validate single input when it loses focus
683   * shows error message in a span element
684   * that is appended to the parent element
685   *
686   * @param {Object} [language] Optional, will override $.formUtils.LANG
687   * @param {Object} [conf] Optional, will override the default settings
688   * @param {Boolean} attachKeyupEvent Optional
689   * @param {String} eventContext
690   * @return {jQuery}
691   */
692  $.fn.validateInputOnBlur = function (language, conf, attachKeyupEvent, eventContext) {
693
694    $.formUtils.eventType = eventContext;
695
696    if ( this.willPostponeValidation() ) {
697      // This validation has to be postponed
698      var _self = this,
699        postponeTime = this.valAttr('postpone') || 200;
700
701      window.postponedValidation = function () {
702        _self.validateInputOnBlur(language, conf, attachKeyupEvent, eventContext);
703        window.postponedValidation = false;
704      };
705
706      setTimeout(function () {
707        if (window.postponedValidation) {
708          window.postponedValidation();
709        }
710      }, postponeTime);
711
712      return this;
713    }
714
715    language = $.extend({}, $.formUtils.LANG, language || {});
716    $.formUtils.dialogs.removeInputStylingAndMessage(this, conf);
717
718    var $elem = this,
719      $form = $elem.closest('form'),
720      result = $.formUtils.validateInput(
721        $elem,
722        language,
723        conf,
724        $form,
725        eventContext
726      );
727
728    var reValidate = function() {
729      $elem.validateInputOnBlur(language, conf, false, 'blur.revalidated');
730    };
731
732    if (eventContext === 'blur') {
733      $elem
734        .unbind('validation.revalidate', reValidate)
735        .one('validation.revalidate', reValidate);
736    }
737
738    if (attachKeyupEvent) {
739      $elem.removeKeyUpValidation();
740    }
741
742    if (result.shouldChangeDisplay) {
743      if (result.isValid) {
744        $.formUtils.dialogs.applyInputSuccessStyling($elem, conf);
745      } else {
746        $.formUtils.dialogs.setInlineMessage($elem, result.errorMsg, conf);
747      }
748    }
749
750    if (!result.isValid && attachKeyupEvent) {
751      $elem.validateOnKeyUp(language, conf);
752    }
753
754    return this;
755  };
756
757  /**
758   * Validate element on keyup-event
759   */
760  $.fn.validateOnKeyUp = function(language, conf) {
761    this.each(function() {
762      var $input = $(this);
763      if (!$input.valAttr('has-keyup-event')) {
764        $input
765          .valAttr('has-keyup-event', 'true')
766          .bind('keyup.validation', function (evt) {
767            if( evt.keyCode !== 9 ) {
768              $input.validateInputOnBlur(language, conf, false, 'keyup');
769            }
770          });
771      }
772    });
773    return this;
774  };
775
776  /**
777   * Remove validation on keyup
778   */
779  $.fn.removeKeyUpValidation = function() {
780    this.each(function() {
781      $(this)
782        .valAttr('has-keyup-event', false)
783        .unbind('keyup.validation');
784    });
785    return this;
786  };
787
788  /**
789   * Short hand for fetching/adding/removing element attributes
790   * prefixed with 'data-validation-'
791   *
792   * @param {String} name
793   * @param {String|Boolean} [val]
794   * @return {String|undefined|jQuery}
795   * @protected
796   */
797  $.fn.valAttr = function (name, val) {
798    if (val === undefined) {
799      return this.attr('data-validation-' + name);
800    } else if (val === false || val === null) {
801      return this.removeAttr('data-validation-' + name);
802    } else {
803      name = ((name.length > 0) ? '-' + name : '');
804      return this.attr('data-validation' + name, val);
805    }
806  };
807
808  /**
809   * Function that validates all inputs in active form
810   *
811   * @param {Object} [language]
812   * @param {Object} [conf]
813   * @param {Boolean} [displayError] Defaults to true
814   */
815  $.fn.isValid = function (language, conf, displayError) {
816
817    if ($.formUtils.isLoadingModules) {
818      var $self = this;
819      setTimeout(function () {
820        $self.isValid(language, conf, displayError);
821      }, 200);
822      return null;
823    }
824
825    conf = $.extend({}, $.formUtils.defaultConfig(), conf || {});
826    language = $.extend({}, $.formUtils.LANG, language || {});
827    displayError = displayError !== false;
828
829    if ($.formUtils.errorDisplayPreventedWhenHalted) {
830      // isValid() was called programmatically with argument displayError set
831      // to false when the validation was halted by any of the validators
832      delete $.formUtils.errorDisplayPreventedWhenHalted;
833      displayError = false;
834    }
835
836    /**
837     * Adds message to error message stack if not already in the message stack
838     *
839     * @param {String} mess
840     * @para {jQuery} $elem
841     */
842    var addErrorMessage = function (mess, $elem) {
843        if ($.inArray(mess, errorMessages) < 0) {
844          errorMessages.push(mess);
845        }
846        errorInputs.push($elem);
847        $elem.valAttr('current-error', mess);
848        if (displayError) {
849          $.formUtils.dialogs.applyInputErrorStyling($elem, conf);
850        }
851      },
852
853      /** Holds inputs (of type checkox or radio) already validated, to prevent recheck of mulitple checkboxes & radios */
854      checkedInputs = [],
855
856      /** Error messages for this validation */
857      errorMessages = [],
858
859      /** Input elements which value was not valid */
860      errorInputs = [],
861
862      /** Form instance */
863      $form = this,
864
865      /**
866       * Tells whether or not to validate element with this name and of this type
867       *
868       * @param {String} name
869       * @param {String} type
870       * @return {Boolean}
871       */
872      ignoreInput = function (name, type) {
873        if (type === 'submit' || type === 'button' || type === 'reset') {
874          return true;
875		}
876		/*added by ad */
877		if (
878			name &&
879			( $form.find( '[name="' + name + '"]' ).attr( 'type' ) == 'text' ) &&
880			( $form.find( '[name="' + name + '"]' ).attr( 'data-validation' ) ) &&
881			( $form.find( '[name="' + name + '"]' ).attr( 'data-validation' ).indexOf( 'required' ) == -1 ) &&
882			( $form.find( '[name="' + name + '"]' ).val() == '' )
883		) {
884			return true;
885		}
886		/*added by ad */
887        return $.inArray(name, conf.ignore || []) > -1;
888      };
889
890    // Reset style and remove error class
891    if (displayError) {
892      $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf);
893    }
894
895    // Validate element values
896    $form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function () {
897      var $elem = $(this),
898        elementType = $elem.attr('type'),
899        isCheckboxOrRadioBtn = elementType === 'radio' || elementType === 'checkbox',
900        elementName = $elem.attr('name');
901
902      if (!ignoreInput(elementName, elementType) && (!isCheckboxOrRadioBtn || $.inArray(elementName, checkedInputs) < 0)) {
903        // added by ad
904        $elem.val( $elem.val().trim() );
905
906        if (isCheckboxOrRadioBtn) {
907          checkedInputs.push(elementName);
908        }
909
910        var result = $.formUtils.validateInput(
911          $elem,
912          language,
913          conf,
914          $form,
915          'submit'
916        );
917
918        if (!result.isValid) {
919          addErrorMessage(result.errorMsg, $elem);
920        } else if (result.isValid && result.shouldChangeDisplay) {
921          $elem.valAttr('current-error', false);
922          $.formUtils.dialogs.applyInputSuccessStyling($elem, conf);
923        }
924      }
925
926    });
927
928    // Run validation callback
929    if (typeof conf.onValidate === 'function') {
930      var errors = conf.onValidate($form);
931      if ($.isArray(errors)) {
932        $.each(errors, function (i, err) {
933          addErrorMessage(err.message, err.element);
934        });
935      }
936      else if (errors && errors.element && errors.message) {
937        addErrorMessage(errors.message, errors.element);
938      }
939    }
940
941    // Reset form validation flag
942    $.formUtils.isValidatingEntireForm = false;
943
944    // Validation failed
945    if (errorInputs.length > 0) {
946      if (displayError) {
947        if (conf.errorMessagePosition === 'top') {
948          $.formUtils.dialogs.setMessageInTopOfForm($form, errorMessages, conf, language);
949        } else {
950          $.each(errorInputs, function (i, $input) {
951            $.formUtils.dialogs.setInlineMessage($input, $input.valAttr('current-error'), conf);
952          });
953        }
954        if (conf.scrollToTopOnError) {
955          $.formUtils.$win.scrollTop($form.offset().top - 20);
956        }
957      }
958    }
959
960    if (!displayError && $.formUtils.haltValidation) {
961      $.formUtils.errorDisplayPreventedWhenHalted = true;
962    }
963
964    return errorInputs.length === 0 && !$.formUtils.haltValidation;
965  };
966
967  /**
968   * Plugin for displaying input length restriction
969   */
970  $.fn.restrictLength = function (maxLengthElement) {
971    new $.formUtils.lengthRestriction(this, maxLengthElement);
972    return this;
973  };
974
975  /**
976   * Add suggestion dropdown to inputs having data-suggestions with a comma
977   * separated string with suggestions
978   * @param {Array} [settings]
979   * @returns {jQuery}
980   */
981  $.fn.addSuggestions = function (settings) {
982    var sugs = false;
983    this.find('input').each(function () {
984      var $field = $(this);
985
986      sugs = $.split($field.attr('data-suggestions'));
987
988      if (sugs.length > 0 && !$field.hasClass('has-suggestions')) {
989        $.formUtils.suggest($field, sugs, settings);
990        $field.addClass('has-suggestions');
991      }
992    });
993    return this;
994  };
995
996
997})(jQuery, window);
998
999/**
1000 * Utility methods used for handling loading of modules (attached to $.formUtils)
1001 */
1002(function($) {
1003
1004  'use strict';
1005
1006  $.formUtils = $.extend($.formUtils || {}, {
1007
1008    /**
1009     * @var {Boolean}
1010     */
1011    isLoadingModules: false,
1012
1013    /**
1014     * @var {Object}
1015     */
1016    loadedModules: {},
1017
1018    /**
1019     * @param {String} name
1020     */
1021    registerLoadedModule: function (name) {
1022      this.loadedModules[$.trim(name).toLowerCase()] = true;
1023    },
1024
1025    /**
1026     * @param {String} name
1027     * @return {Boolean}
1028     */
1029    hasLoadedModule: function (name) {
1030      return $.trim(name).toLowerCase() in this.loadedModules;
1031    },
1032
1033    /**
1034     * @example
1035     *  $.formUtils.loadModules('date, security.dev');
1036     *
1037     * Will load the scripts date.js and security.dev.js from the
1038     * directory where this script resides. If you want to load
1039     * the modules from another directory you can use the
1040     * path argument.
1041     *
1042     * The script will be cached by the browser unless the module
1043     * name ends with .dev
1044     *
1045     * @param {String} modules - Comma separated string with module file names (no directory nor file extension)
1046     * @param {String} [path] - Path where the module files are located if their not in the same directory as the core modules
1047     * @param {function} [callback] - Callback invoked when all modules are loaded
1048     */
1049    loadModules: function (modules, path, callback) {
1050
1051      if ($.formUtils.isLoadingModules) {
1052        setTimeout(function () {
1053          $.formUtils.loadModules(modules, path, callback);
1054        }, 100);
1055        return;
1056      }
1057
1058      var loadModuleScripts = function (modules, path) {
1059
1060          var moduleList = $.split(modules),
1061            numModules = moduleList.length,
1062            moduleLoadedCallback = function () {
1063              numModules--;
1064              if (numModules === 0) {
1065                $.formUtils.isLoadingModules = false;
1066                if (typeof callback === 'function') {
1067                    callback();
1068                }
1069              }
1070            };
1071
1072          if (numModules > 0) {
1073            $.formUtils.isLoadingModules = true;
1074          }
1075
1076          var cacheSuffix = '?_=' + ( new Date().getTime() ),
1077            appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0];
1078
1079          $.each(moduleList, function (i, modName) {
1080            modName = $.trim(modName);
1081            if (modName.length === 0 || $.formUtils.hasLoadedModule(modName)) {
1082              moduleLoadedCallback();
1083            } else {
1084              var scriptUrl = path + modName + (modName.slice(-3) === '.js' ? '' : '.js'),
1085                script = document.createElement('SCRIPT');
1086
1087              if (typeof define === 'function' && define.amd) {
1088                require([scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' )], moduleLoadedCallback);
1089              } else {
1090                // Load the script
1091                script.type = 'text/javascript';
1092                script.onload = moduleLoadedCallback;
1093                script.src = scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' );
1094                script.onerror = function() {
1095                  $.formUtils.warn('Unable to load form validation module '+scriptUrl, true);
1096                  moduleLoadedCallback();
1097                };
1098                script.onreadystatechange = function () {
1099                  // IE 7 fix
1100                  if (this.readyState === 'complete' || this.readyState === 'loaded') {
1101                    moduleLoadedCallback();
1102                    // Handle memory leak in IE
1103                    this.onload = null;
1104                    this.onreadystatechange = null;
1105                  }
1106                };
1107                appendToElement.appendChild(script);
1108              }
1109            }
1110          });
1111        };
1112
1113      if (path) {
1114        loadModuleScripts(modules, path);
1115      } else {
1116        var findScriptPathAndLoadModules = function () {
1117          var foundPath = false;
1118          $('script[src*="form-validator"]').each(function () {
1119            var isScriptFromPluginNodeModulesDirectory = this.src.split('form-validator')[1].split('node_modules').length > 1;
1120            if (!isScriptFromPluginNodeModulesDirectory) {
1121              foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
1122              if (foundPath === '/') {
1123                foundPath = '';
1124              }
1125              return false;
1126            }
1127          });
1128
1129          if (foundPath !== false) {
1130            loadModuleScripts(modules, foundPath);
1131            return true;
1132          }
1133          return false;
1134        };
1135
1136        if (!findScriptPathAndLoadModules()) {
1137          $(function () {
1138            var hasLoadedModuleScripts = findScriptPathAndLoadModules();
1139            if (!hasLoadedModuleScripts) {
1140              // The modules may have been inserted via a minified script
1141              if (typeof callback === 'function') {
1142                callback();
1143              }
1144            }
1145          });
1146        }
1147      }
1148    }
1149
1150  });
1151
1152})(jQuery);
1153
1154/**
1155 * Setup function for the plugin
1156 */
1157(function ($) {
1158
1159  'use strict';
1160
1161
1162  /**
1163   * A bit smarter split function
1164   * delimiter can be space, comma, dash or pipe
1165   * @param {String} val
1166   * @param {Function|String} [callback]
1167   * @param {Boolean}
1167 [allowSpaceAsDelimiter]
1168   * @returns {Array|void}
1169   */
1170  $.split = function (val, callback, allowSpaceAsDelimiter) {
1171    // default to true
1172    allowSpaceAsDelimiter = allowSpaceAsDelimiter === undefined || allowSpaceAsDelimiter === true;
1173    var pattern = '[,|'+(allowSpaceAsDelimiter ? '\\s':'')+'-]\\s*',
1174      regex = new RegExp(pattern, 'g');
1175    if (typeof callback !== 'function') {
1176      // return array
1177      if (!val) {
1178        return [];
1179      }
1180      var values = [];
1181      $.each(val.split(callback ? callback : regex),
1182        function (i, str) {
1183          str = $.trim(str);
1184          if (str.length) {
1185            values.push(str);
1186          }
1187        }
1188      );
1189      return values;
1190    } else if (val) {
1191      // exec callback func on each
1192      $.each(val.split(regex),
1193        function (i, str) {
1194          str = $.trim(str);
1195          if (str.length) {
1196            return callback(str, i);
1197          }
1198        }
1199      );
1200    }
1201  };
1202
1203  /**
1204   * Short hand function that makes the validation setup require less code
1205   * @param conf
1206   */
1207  $.validate = function (conf) {
1208
1209    var defaultConf = $.extend($.formUtils.defaultConfig(), {
1210      form: 'form',
1211      validateOnEvent: false,
1212      validateOnBlur: true,
1213      validateCheckboxRadioOnClick: true,
1214      showHelpOnFocus: true,
1215      addSuggestions: true,
1216      modules: '',
1217      onModulesLoaded: null,
1218      language: false,
1219      onSuccess: false,
1220      onError: false,
1221      onElementValidate: false
1222    });
1223
1224    conf = $.extend(defaultConf, conf || {});
1225
1226    $(window).trigger('formValidationPluginInit', [conf]);
1227
1228    if( conf.lang && conf.lang !== 'en' ) {
1229      var langModule = 'lang/'+conf.lang+'.js';
1230      conf.modules += conf.modules.length ? ','+langModule : langModule;
1231    }
1232
1233    // Add validation to forms
1234    $(conf.form).each(function (i, form) {
1235
1236      // Make a reference to the config for this form
1237      form.validationConfig = conf;
1238
1239      // Trigger jQuery event that we're about to setup validation
1240      var $form = $(form);
1241      $form.trigger('formValidationSetup', [$form, conf]);
1242
1243      // Remove classes and event handlers that might have been
1244      // added by a previous call to $.validate
1245      $form.find('.has-help-txt')
1246          .unbind('focus.validation')
1247          .unbind('blur.validation');
1248
1249      $form
1250        .removeClass('has-validation-callback')
1251        .unbind('submit.validation')
1252        .unbind('reset.validation')
1253        .find('input[data-validation],textarea[data-validation]')
1254          .unbind('blur.validation');
1255
1256      // Validate when submitted
1257      $form.bind('submit.validation', function (evt) {
1258
1259        var $form = $(this),
1260          stop = function() {
1261            evt.stopImmediatePropagation();
1262            return false;
1263          };
1264
1265        if ($.formUtils.haltValidation) {
1266          // pressing several times on submit button while validation is halted
1267          return stop();
1268        }
1269
1270        if ($.formUtils.isLoadingModules) {
1271          setTimeout(function () {
1272            $form.trigger('submit.validation');
1273          }, 200);
1274          return stop();
1275        }
1276
1277        var valid = $form.isValid(conf.language, conf);
1278        if ($.formUtils.haltValidation) {
1279          // Validation got halted by one of the validators
1280          return stop();
1281        } else {
1282          if (valid && typeof conf.onSuccess === 'function') {
1283            var callbackResponse = conf.onSuccess($form);
1284            if (callbackResponse === false) {
1285              return stop();
1286            }
1287          } else if (!valid && typeof conf.onError === 'function') {
1288            conf.onError($form);
1289            return stop();
1290          } else {
1291            return valid ? true : stop();
1292          }
1293        }
1294      })
1295      .bind('reset.validation', function () {
1296        $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf);
1297      })
1298      .addClass('has-validation-callback');
1299
1300      if (conf.showHelpOnFocus) {
1301        $form.showHelpOnFocus();
1302      }
1303      if (conf.addSuggestions) {
1304        $form.addSuggestions();
1305      }
1306      if (conf.validateOnBlur) {
1307        $form.validateOnBlur(conf.language, conf);
1308        $form.bind('html5ValidationAttrsFound', function () {
1309          $form.validateOnBlur(conf.language, conf);
1310        });
1311      }
1312      if (conf.validateOnEvent) {
1313        $form.validateOnEvent(conf.language, conf);
1314      }
1315    });
1316
1317    if (conf.modules !== '') {
1318      $.formUtils.loadModules(conf.modules, null, function() {
1319        if (typeof conf.onModulesLoaded === 'function') {
1320          conf.onModulesLoaded();
1321        }
1322        var $form = typeof conf.form === 'string' ? $(conf.form) : conf.form;
1323        $.formUtils.$win.trigger('validatorsLoaded', [$form, conf]);
1324      });
1325    }
1326  };
1327
1328})(jQuery);
1329
1330/**
1331 * Utility methods and properties attached to $.formUtils
1332 */
1333(function($, window) {
1334
1335  'use strict';
1336
1337  var $win = $(window);
1338
1339  $.formUtils = $.extend($.formUtils || {}, {
1340
1341    $win: $win,
1342
1343    /**
1344     * Default config for $(...).isValid();
1345     */
1346    defaultConfig: function () {
1347      return {
1348        ignore: [], // Names of inputs not to be validated even though `validationRuleAttribute` containing the validation rules tells us to
1349        errorElementClass: 'error', // Class that will be put on elements which value is invalid
1350        successElementClass: 'valid', // Class that will be put on elements that has been validated with success
1351        borderColorOnError: '#b94a48', // Border color of elements which value is invalid, empty string to not change border color
1352        errorMessageClass: 'form-error', // class name of div containing error messages when validation fails
1353        validationRuleAttribute: 'data-validation', // name of the attribute holding the validation rules
1354        validationErrorMsgAttribute: 'data-validation-error-msg', // define custom err msg inline with element
1355        errorMessagePosition: 'inline', // Can be either "top" or "inline"
1356        errorMessageTemplate: {
1357          container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>',
1358          messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
1359          field: '<li>{msg}</li>'
1360        },
1361        scrollToTopOnError: true,
1362        dateFormat: 'yyyy-mm-dd',
1363        addValidClassOnAll: false, // whether or not to apply class="valid" even if the input wasn't validated
1364        decimalSeparator: '.',
1365        inputParentClassOnError: 'has-error', // twitter-bootstrap default class name
1366        inputParentClassOnSuccess: 'has-success', // twitter-bootstrap default class name
1367        validateHiddenInputs: false, // whether or not hidden inputs should be validated
1368        inlineErrorMessageCallback: false,
1369        submitErrorMessageCallback: false
1370      };
1371    },
1372
1373    /**
1374     * Available validators
1375     */
1376    validators: {},
1377
1378    /**
1379     * Available sanitizers
1380     */
1381    sanitizers: {},
1382
1383    /**
1384     * Events triggered by form validator
1385     */
1386    _events: {load: [], valid: [], invalid: []},
1387
1388    /**
1389     * Setting this property to true during validation will
1390     * stop further validation from taking place and form will
1391     * not be sent
1392     */
1393    haltValidation: false,
1394
1395    /**
1396     * Function for adding a validator
1397     * @see $.formUtils.addAsyncValidator (async.js)
1398     * @param {Object} validator
1399     */
1400    addValidator: function (validator) {
1401      // prefix with "validate_" for backward compatibility reasons
1402      var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_' + validator.name;
1403      if (validator.validateOnKeyUp === undefined) {
1404        validator.validateOnKeyUp = true;
1405      }
1406      this.validators[name] = validator;
1407    },
1408
1409    /**
1410     * Function for adding a sanitizer
1411     * @param {Object} sanitizer
1412     */
1413    addSanitizer: function (sanitizer) {
1414      this.sanitizers[sanitizer.name] = sanitizer;
1415    },
1416
1417    /**
1418     * Warn user via the console if available
1419     */
1420    warn: function(msg, fallbackOnAlert) {
1421      if( 'console' in window ) {
1422        if( typeof window.console.warn === 'function' ) {
1423          window.console.warn(msg);
1424        } else if( typeof window.console.log === 'function' ) {
1425          window.console.log(msg);
1426        }
1427      } else if (fallbackOnAlert) {
1428        // This is for some old IE version...
1429        alert(msg);
1430      }
1431    },
1432
1433    /**
1434     * Same as input $.fn.val() but also supporting input of typ radio or checkbox
1435     * @example
1436     *
1437     *  $.formUtils.getValue('.myRadioButtons', $('#some-form'));
1438     *  $.formUtils.getValue($('#some-form').find('.check-boxes'));
1439     *
1440     * @param query
1441     * @param $parent
1442     * @returns {String|Boolean}
1443     */
1444    getValue: function(query, $parent) {
1445      var $inputs = $parent ? $parent.find(query) : query;
1446      if ($inputs.length > 0 ) {
1447        var type = $inputs.eq(0).attr('type');
1448        if (type === 'radio' || type === 'checkbox') {
1449          return $inputs.filter(':checked').val() || '';
1450        } else {
1451          return $inputs.val() || '';
1452        }
1453      }
1454      return false;
1455    },
1456
1457    /**
1458     * Validate the value of given element according to the validation rules
1459     * found in the attribute data-validation. Will return an object representing
1460     * a validation result, having the props shouldChangeDisplay, isValid and errorMsg
1461     * @param {jQuery} $elem
1462     * @param {Object} language ($.formUtils.LANG)
1463     * @param {Object} conf
1464     * @param {jQuery} $form
1465     * @param {String} [eventContext]
1466     * @return {Object}
1467     */
1468    validateInput: function ($elem, language, conf, $form, eventContext) {
1469
1470      conf = conf || $.formUtils.defaultConfig();
1471      language = language || $.formUtils.LANG;
1472
1473      if (!$form.length) {
1474        $form = $elem.parent();
1475      }
1476
1477      var value = this.getValue($elem);
1478
1479      $elem
1480        .valAttr('skipped', false)
1481        .one('beforeValidation', function() {
1482          // Skip input because its hidden or disabled
1483          // Doing this in a callback makes it possible for others to prevent the default
1484          // behaviour by binding to the same event and call evt.stopImmediatePropagation()
1485          if ($elem.attr('disabled') || (!$elem.is(':visible') && !conf.validateHiddenInputs)) {
1486            $elem.valAttr('skipped', 1);
1487          }
1488        })
1489        .trigger('beforeValidation', [value, language, conf]);
1490
1491      var inputIsOptional = $elem.valAttr('optional') === 'true',
1492          skipBecauseItsEmpty = !value && inputIsOptional,
1493          validationRules = $elem.attr(conf.validationRuleAttribute),
1494          isValid = true,
1495          errorMsg = '',
1496          result = {isValid: true, shouldChangeDisplay:true, errorMsg:''};
1497
1498      // For input type="number", browsers attempt to parse the entered value into a number.
1499      // If the input is not numeric, browsers handle the situation differently:
1500      // Chrome 48 simply disallows non-numeric input; FF 44 clears out the input box on blur;
1501      // Safari 5 parses the entered string to find a leading number.
1502      // If the input fails browser validation, the browser sets the input value equal to an empty string.
1503      // Therefore, we cannot distinguish (apart from hacks) between an empty input type="text" and one with a
1504      // value that can't be parsed by the browser.
1505
1506      if (!validationRules || skipBecauseItsEmpty || $elem.valAttr('skipped')) {
1507        result.shouldChangeDisplay = conf.addValidClassOnAll;
1508        return result;
1509      }
1510
1511      // Filter out specified characters
1512      var ignore = $elem.valAttr('ignore');
1513      if (ignore) {
1514        $.each(ignore.split(''), function(i, character) {
1515          value = value.replace(new RegExp('\\'+character, 'g'), '');
1516        });
1517      }
1518
1519      $.split(validationRules, function (rule) {
1520
1521        if (rule.indexOf('validate_') !== 0) {
1522          rule = 'validate_' + rule;
1523        }
1524
1525        var validator = $.formUtils.validators[rule];
1526
1527        if (validator) {
1528
1529          // special change of element for checkbox_group rule
1530          if (rule === 'validate_checkbox_group') {
1531            // set element to first in group, so error msg attr doesn't need to be set on all elements in group
1532            $elem = $form.find('[name="' + $elem.attr('name') + '"]:eq(0)');
1533          }
1534
1535          if (eventContext !== 'keyup' || validator.validateOnKeyUp) {
1536            // A validator can prevent itself from getting triggered on keyup
1537            isValid = validator.validatorFunction(value, $elem, conf, language, $form, eventContext);
1538          }
1539
1540          if (!isValid) {
1541            if (conf.validateOnBlur) {
1542              $elem.validateOnKeyUp(language, conf);
1543            }
1544            errorMsg = $.formUtils.dialogs.resolveErrorMessage($elem, validator, rule, conf, language);
1545            return false; // break iteration
1546          }
1547
1548        } else {
1549
1550          // todo: Add some validator lookup function and tell immediately which module is missing
1551          throw new Error('Using undefined validator "' + rule +
1552            '". Maybe you have forgotten to load the module that "' + rule +'" belongs to?');
1553
1554        }
1555
1556      });
1557
1558
1559      if (isValid === false) {
1560        $elem.trigger('validation', false);
1561        result.errorMsg = errorMsg;
1562        result.isValid = false;
1563        result.shouldChangeDisplay = true;
1564      } else if (isValid === null) {
1565        // A validatorFunction returning null means that it's not able to validate
1566        // the input at this time. Most probably some async stuff need to gets finished
1567        // first and then the validator will re-trigger the validation.
1568        result.shouldChangeDisplay = false;
1569      } else {
1570        $elem.trigger('validation', true);
1571        result.shouldChangeDisplay = true;
1572      }
1573
1574      // Run element validation callback
1575      if (typeof conf.onElementValidate === 'function' && errorMsg !== null) {
1576        conf.onElementValidate(result.isValid, $elem, $form, errorMsg);
1577      }
1578
1579      $elem.trigger('afterValidation', [result, eventContext]);
1580
1581      return result;
1582    },
1583
1584    /**
1585     * Is it a correct date according to given dateFormat. Will return false if not, otherwise
1586     * an array 0=>year 1=>month 2=>day
1587     *
1588     * @param {String} val
1589     * @param {String} dateFormat
1590     * @param {Boolean} [addMissingLeadingZeros]
1591     * @return {Array}|{Boolean}
1592     */
1593    parseDate: function (val, dateFormat, addMissingLeadingZeros) {
1594      var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0, 1),
1595        regexp = '^',
1596        formatParts = dateFormat.split(divider || null),
1597        matches, day, month, year;
1598
1599      $.each(formatParts, function (i, part) {
1600        regexp += (i > 0 ? '\\' + divider : '') + '(\\d{' + part.length + '})';
1601      });
1602
1603      regexp += '$';
1604
1605      if (addMissingLeadingZeros) {
1606        var newValueParts = [];
1607        $.each(val.split(divider), function(i, part) {
1608          if(part.length === 1) {
1609            part = '0'+part;
1610          }
1611          newValueParts.push(part);
1612        });
1613        val = newValueParts.join(divider);
1614      }
1615
1616      matches = val.match(new RegExp(regexp));
1617      if (matches === null) {
1618        return false;
1619      }
1620
1621      var findDateUnit = function (unit, formatParts, matches) {
1622        for (var i = 0; i < formatParts.length; i++) {
1623          if (formatParts[i].substring(0, 1) === unit) {
1624            return $.formUtils.parseDateInt(matches[i + 1]);
1625          }
1626        }
1627        return -1;
1628      };
1629
1630      month = findDateUnit('m', formatParts, matches);
1631      day = findDateUnit('d', formatParts, matches);
1632      year = findDateUnit('y', formatParts, matches);
1633
1634      if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0)) ||
1635        (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0)) ||
1636        month > 12 || month === 0) {
1637        return false;
1638      }
1639      if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) {
1640        return false;
1641      }
1642
1643      return [year, month, day];
1644    },
1645
1646    /**
1647     * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt?
1648     *
1649     * @param {String} val
1650     * @return {Number}
1651     */
1652    parseDateInt: function (val) {
1653      if (val.indexOf('0') === 0) {
1654        val = val.replace('0', '');
1655      }
1656      return parseInt(val, 10);
1657    },
1658
1659    /**
1660     * Has month only 30 days?
1661     *
1662     * @param {Number} m
1663     * @return {Boolean}
1664     */
1665    isShortMonth: function (m) {
1666      return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
1667    },
1668
1669    /**
1670     * Restrict input length
1671     *
1672     * @param {jQuery} $inputElement Jquery Html object
1673     * @param {jQuery} $maxLengthElement jQuery Html Object
1674     * @return void
1675     */
1676    lengthRestriction: function ($inputElement, $maxLengthElement) {
1677      // read maxChars from counter display initial text value
1678      var maxChars = parseInt($maxLengthElement.text(), 10),
1679        charsLeft = 0,
1680
1681      // internal function does the counting and sets display value
1682        countCharacters = function () {
1683          var numChars = $inputElement.val().length;
1684          if (numChars > maxChars) {
1685            // get current scroll bar position
1686            var currScrollTopPos = $inputElement.scrollTop();
1687            // trim value to max length
1688            $inputElement.val($inputElement.val().substring(0, maxChars));
1689            $inputElement.scrollTop(currScrollTopPos);
1690          }
1691          charsLeft = maxChars - numChars;
1692          if (charsLeft < 0) {
1693            charsLeft = 0;
1694          }
1695
1696          // set counter text
1697          $maxLengthElement.text(charsLeft);
1698        };
1699
1700      // bind events to this element
1701      // setTimeout is needed, cut or paste fires before val is available
1702      $($inputElement).bind('keydown keyup keypress focus blur', countCharacters)
1703        .bind('cut paste', function () {
1704          setTimeout(countCharacters, 100);
1705        });
1706
1707      // count chars on pageload, if there are prefilled input-values
1708      $(document).bind('ready', countCharacters);
1709    },
1710
1711    /**
1712     * Test numeric against allowed range
1713     *
1714     * @param $value int
1715     * @param $rangeAllowed str; (1-2, min1, max2, 10)
1716     * @return array
1717     */
1718    numericRangeCheck: function (value, rangeAllowed) {
1719      // split by dash
1720      var range = $.split(rangeAllowed),
1721      // min or max
1722        minmax = parseInt(rangeAllowed.substr(3), 10);
1723
1724      if( range.length === 1 && rangeAllowed.indexOf('min') === -1 && rangeAllowed.indexOf('max') === -1 ) {
1725        range = [rangeAllowed, rangeAllowed]; // only a number, checking agains an exact number of characters
1726      }
1727
1728      // range ?
1729      if (range.length === 2 && (value < parseInt(range[0], 10) || value > parseInt(range[1], 10) )) {
1730        return [ 'out', range[0], range[1] ];
1731      } // value is out of range
1732      else if (rangeAllowed.indexOf('min') === 0 && (value < minmax )) // min
1733      {
1734        return ['min', minmax];
1735      } // value is below min
1736      else if (rangeAllowed.indexOf('max') === 0 && (value > minmax )) // max
1737      {
1738        return ['max', minmax];
1739      } // value is above max
1740      // since no other returns executed, value is in allowed range
1741      return [ 'ok' ];
1742    },
1743
1744
1745    _numSuggestionElements: 0,
1746    _selectedSuggestion: null,
1747    _previousTypedVal: null,
1748
1749    /**
1750     * Utility function that can be used to create plugins that gives
1751     * suggestions when inputs is typed into
1752     * @param {jQuery} $elem
1753     * @param {Array} suggestions
1754     * @param {Object} settings - Optional
1755     * @return {jQuery}
1756     */
1757    suggest: function ($elem, suggestions, settings) {
1758      var conf = {
1759          css: {
1760            maxHeight: '150px',
1761            background: '#FFF',
1762            lineHeight: '150%',
1763            textDecoration: 'underline',
1764            overflowX: 'hidden',
1765            overflowY: 'auto',
1766            border: '#CCC solid 1px',
1767            borderTop: 'none',
1768            cursor: 'pointer'
1769          },
1770          activeSuggestionCSS: {
1771            background: '#E9E9E9'
1772          }
1773        },
1774        setSuggsetionPosition = function ($suggestionContainer, $input) {
1775          var offset = $input.offset();
1776          $suggestionContainer.css({
1777            width: $input.outerWidth(),
1778            left: offset.left + 'px',
1779            top: (offset.top + $input.outerHeight()) + 'px'
1780          });
1781        };
1782
1783      if (settings) {
1784        $.extend(conf, settings);
1785      }
1786
1787      conf.css.position = 'absolute';
1788      conf.css['z-index'] = 9999;
1789      $elem.attr('autocomplete', 'off');
1790
1791      if (this._numSuggestionElements === 0) {
1792        // Re-position suggestion container if window size changes
1793        $win.bind('resize', function () {
1794          $('.jquery-form-suggestions').each(function () {
1795            var $container = $(this),
1796              suggestID = $container.attr('data-suggest-container');
1797            setSuggsetionPosition($container, $('.suggestions-' + suggestID).eq(0));
1798          });
1799        });
1800      }
1801
1802      this._numSuggestionElements++;
1803
1804      var onSelectSuggestion = function ($el) {
1805        var suggestionId = $el.valAttr('suggestion-nr');
1806        $.formUtils._selectedSuggestion = null;
1807        $.formUtils._previousTypedVal = null;
1808        $('.jquery-form-suggestion-' + suggestionId).fadeOut('fast');
1809      };
1810
1811      $elem
1812        .data('suggestions', suggestions)
1813        .valAttr('suggestion-nr', this._numSuggestionElements)
1814        .unbind('focus.suggest')
1815        .bind('focus.suggest', function () {
1816          $(this).trigger('keyup');
1817          $.formUtils._selectedSuggestion = null;
1818        })
1819        .unbind('keyup.suggest')
1820        .bind('keyup.suggest', function () {
1821          var $input = $(this),
1822            foundSuggestions = [],
1823            val = $.trim($input.val()).toLocaleLowerCase();
1824
1825          if (val === $.formUtils._previousTypedVal) {
1826            return;
1827          }
1828          else {
1829            $.formUtils._previousTypedVal = val;
1830          }
1831
1832          var hasTypedSuggestion = false,
1833            suggestionId = $input.valAttr('suggestion-nr'),
1834            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1835
1836          $suggestionContainer.scrollTop(0);
1837
1838          // Find the right suggestions
1839          if (val !== '') {
1840            var findPartial = val.length > 2;
1841            $.each($input.data('suggestions'), function (i, suggestion) {
1842              var lowerCaseVal = suggestion.toLocaleLowerCase();
1843              if (lowerCaseVal === val) {
1844                foundSuggestions.push('<strong>' + suggestion + '</strong>');
1845                hasTypedSuggestion = true;
1846                return false;
1847              } else if (lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) {
1848                foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>'));
1849              }
1850            });
1851          }
1852
1853          // Hide suggestion container
1854          if (hasTypedSuggestion || (foundSuggestions.length === 0 && $suggestionContainer.length > 0)) {
1855            $suggestionContainer.hide();
1856          }
1857
1858          // Create suggestion container if not already exists
1859          else if (foundSuggestions.length > 0 && $suggestionContainer.length === 0) {
1860            $suggestionContainer = $('<div></div>').css(conf.css).appendTo('body');
1861            $elem.addClass('suggestions-' + suggestionId);
1862            $suggestionContainer
1863              .attr('data-suggest-container', suggestionId)
1864              .addClass('jquery-form-suggestions')
1865              .addClass('jquery-form-suggestion-' + suggestionId);
1866          }
1867
1868          // Show hidden container
1869          else if (foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) {
1870            $suggestionContainer.show();
1871          }
1872
1873          // add suggestions
1874          if (foundSuggestions.length > 0 && val.length !== foundSuggestions[0].length) {
1875
1876            // put container in place every time, just in case
1877            setSuggsetionPosition($suggestionContainer, $input);
1878
1879            // Add suggestions HTML to container
1880            $suggestionContainer.html('');
1881            $.each(foundSuggestions, function (i, text) {
1882              $('<div></div>')
1883                .append(text)
1884                .css({
1885                  overflow: 'hidden',
1886                  textOverflow: 'ellipsis',
1887                  whiteSpace: 'nowrap',
1888                  padding: '5px'
1889                })
1890                .addClass('form-suggest-element')
1891                .appendTo($suggestionContainer)
1892                .click(function () {
1893                  $input.focus();
1894                  $input.val($(this).text());
1895                  $input.trigger('change');
1896                  onSelectSuggestion($input);
1897                });
1898            });
1899          }
1900        })
1901        .unbind('keydown.validation')
1902        .bind('keydown.validation', function (e) {
1903          var code = (e.keyCode ? e.keyCode : e.which),
1904            suggestionId,
1905            $suggestionContainer,
1906            $input = $(this);
1907
1908          if (code === 13 && $.formUtils._selectedSuggestion !== null) {
1909            suggestionId = $input.valAttr('suggestion-nr');
1910            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1911            if ($suggestionContainer.length > 0) {
1912              var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
1913              $input.val(newText);
1914              $input.trigger('change');
1915              onSelectSuggestion($input);
1916              e.preventDefault();
1917            }
1918          }
1919          else {
1920            suggestionId = $input.valAttr('suggestion-nr');
1921            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1922            var $suggestions = $suggestionContainer.children();
1923            if ($suggestions.length > 0 && $.inArray(code, [38, 40]) > -1) {
1924              if (code === 38) { // key up
1925                if ($.formUtils._selectedSuggestion === null) {
1926                  $.formUtils._selectedSuggestion = $suggestions.length - 1;
1927                }
1928                else{
1929                  $.formUtils._selectedSuggestion--;
1930                }
1931                if ($.formUtils._selectedSuggestion < 0) {
1932                  $.formUtils._selectedSuggestion = $suggestions.length - 1;
1933                }
1934              }
1935              else if (code === 40) { // key down
1936                if ($.formUtils._selectedSuggestion === null) {
1937                  $.formUtils._selectedSuggestion = 0;
1938                }
1939                else {
1940                  $.formUtils._selectedSuggestion++;
1941                }
1942                if ($.formUtils._selectedSuggestion > ($suggestions.length - 1)) {
1943                  $.formUtils._selectedSuggestion = 0;
1944                }
1945              }
1946
1947              // Scroll in suggestion window
1948              var containerInnerHeight = $suggestionContainer.innerHeight(),
1949                containerScrollTop = $suggestionContainer.scrollTop(),
1950                suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(),
1951                activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion);
1952
1953              if (activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop + containerInnerHeight)) {
1954                $suggestionContainer.scrollTop(activeSuggestionPosY);
1955              }
1956
1957              $suggestions
1958                .removeClass('active-suggestion')
1959                .css('background', 'none')
1960                .eq($.formUtils._selectedSuggestion)
1961                .addClass('active-suggestion')
1962                .css(conf.activeSuggestionCSS);
1963
1964              e.preventDefault();
1965              return false;
1966            }
1967          }
1968        })
1969        .unbind('blur.suggest')
1970        .bind('blur.suggest', function () {
1971          onSelectSuggestion($(this));
1972        });
1973
1974      return $elem;
1975    },
1976
1977    /**
1978     * Error dialogs
1979     *
1980     * @var {Object}
1981     */
1982    LANG: {
1983      errorTitle: 'Form submission failed!',
1984      requiredField: 'This is a required field',
1985      requiredFields: 'You have not answered all required fields',
1986      badTime: 'You have not given a correct time',
1987      badEmail: 'You have not given a correct e-mail address',
1988      badTelephone: 'You have not given a correct phone number',
1989      badSecurityAnswer: 'You have not given a correct answer to the security question',
1990      badDate: 'You have not given a correct date',
1991      lengthBadStart: 'The input value must be between ',
1992      lengthBadEnd: ' characters',
1993      lengthTooLongStart: 'The input value is longer than ',
1994      lengthTooShortStart: 'The input value is shorter than ',
1995      notConfirmed: 'Input values could not be confirmed',
1996      badDomain: 'Incorrect domain value',
1997      badUrl: 'The input value is not a correct URL',
1998      badCustomVal: 'The input value is incorrect',
1999      andSpaces: ' and spaces ',
2000      badInt: 'The input value was not a correct number',
2001      badSecurityNumber: 'Your social security number was incorrect',
2002      badUKVatAnswer: 'Incorrect UK VAT Number',
2003      badUKNin: 'Incorrect UK NIN',
2004      badUKUtr: 'Incorrect UK UTR Number',
2005      badStrength: 'The password isn\'t strong enough',
2006      badNumberOfSelectedOptionsStart: 'You have to choose at least ',
2007      badNumberOfSelectedOptionsEnd: ' answers',
2008      badAlphaNumeric: 'The input value can only contain alphanumeric characters ',
2009      badAlphaNumericExtra: ' and ',
2010      wrongFileSize: 'The file you are trying to upload is too large (max %s)',
2011      wrongFileType: 'Only files of type %s is allowed',
2012      groupCheckedRangeStart: 'Please choose between ',
2013      groupCheckedTooFewStart: 'Please choose at least ',
2014      groupCheckedTooManyStart: 'Please choose a maximum of ',
2015      groupCheckedEnd: ' item(s)',
2016      badCreditCard: 'The credit card number is not correct',
2017      badCVV: 'The CVV number was not correct',
2018      wrongFileDim : 'Incorrect image dimensions,',
2019      imageTooTall : 'the image can not be taller than',
2020      imageTooWide : 'the image can not be wider than',
2021      imageTooSmall : 'the image was too small',
2022      min : 'min',
2023      max : 'max',
2024      imageRatioNotAccepted : 'Image ratio is not be accepted',
2025      badBrazilTelephoneAnswer: 'The phone number entered is invalid',
2026      badBrazilCEPAnswer: 'The CEP entered is invalid',
2027      badBrazilCPFAnswer: 'The CPF entered is invalid',
2028      badPlPesel: 'The PESEL entered is invalid',
2029      badPlNip: 'The NIP entered is invalid',
2030      badPlRegon: 'The REGON entered is invalid',
2031      badreCaptcha: 'Please confirm that you are not a bot',
2032      passwordComplexityStart: 'Password must contain at least ',
2033      passwordComplexitySeparator: ', ',
2034      passwordComplexityUppercaseInfo: ' uppercase letter(s)',
2035      passwordComplexityLowercaseInfo: ' lowercase letter(s)',
2036      passwordComplexitySpecialCharsInfo: ' special character(s)',
2037      passwordComplexityNumericCharsInfo: ' numeric character(s)',
2038      passwordComplexityEnd: '.'
2039    }
2040  });
2041
2042})(jQuery, window);
2043
2044/**
2045 * File declaring all default validators.
2046 */
2047(function($) {
2048
2049  /*
2050   * Validate email
2051   */
2052  $.formUtils.addValidator({
2053    name: 'email',
2054    validatorFunction: function (email) {
2055
2056      var emailParts = email.toLowerCase().split('@'),
2057        localPart = emailParts[0],
2058        domain = emailParts[1];
2059
2060      if (localPart && domain) {
2061
2062        if( localPart.indexOf('"') === 0 ) {
2063          var len = localPart.length;
2064          localPart = localPart.replace(/\"/g, '');
2065          if( localPart.length !== (len-2) ) {
2066            return false; // It was not allowed to have more than two apostrophes
2067          }
2068        }
2069
2070        return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
2071          localPart.indexOf('.') !== 0 &&
2072          localPart.substring(localPart.length-1, localPart.length) !== '.' &&
2073          localPart.indexOf('..') === -1 &&
2074          !(/[^\w\+\.\-\#\-\_\~\!\$\&\'\(\)\*\+\,\;\=\:]/.test(localPart));
2075      }
2076
2077      return false;
2078    },
2079    errorMessage: '',
2080    errorMessageKey: 'badEmail'
2081  });
2082
2083  /*
2084   * Validate domain name
2085   */
2086  $.formUtils.addValidator({
2087    name: 'domain',
2088    validatorFunction: function (val) {
2089      return val.length > 0 &&
2090        val.length <= 253 && // Including sub domains
2091        !(/[^a-zA-Z0-9]/.test(val.slice(-2))) && !(/[^a-zA-Z0-9]/.test(val.substr(0, 1))) && !(/[^a-zA-Z0-9\.\-]/.test(val)) &&
2092        val.split('..').length === 1 &&
2093        val.split('.').length > 1;
2094    },
2095    errorMessage: '',
2096    errorMessageKey: 'badDomain'
2097  });
2098
2099  /*
2100   * Validate required
2101   */
2102  $.formUtils.addValidator({
2103    name: 'required',
2104    validatorFunction: function (val, $el, config, language, $form) {
2105      switch ($el.attr('type')) {
2106        case 'checkbox':
2107          return $el.is(':checked');
2108        case 'radio':
2109          return $form.find('input[name="' + $el.attr('name') + '"]').filter(':checked').length > 0;
2110        default:
2111          return $.trim(val) !== '';
2112      }
2113    },
2114    errorMessage: '',
2115    errorMessageKey: function(config) {
2116      if (config.errorMessagePosition === 'top' || typeof config.errorMessagePosition === 'function') {
2117        return 'requiredFields';
2118      }
2119      else {
2120        return 'requiredField';
2121      }
2122    }
2123  });
2124
2125  /*
2126   * Validate length range
2127   */
2128  $.formUtils.addValidator({
2129    name: 'length',
2130    validatorFunction: function (val, $el, conf, lang) {
2131      var lengthAllowed = $el.valAttr('length'),
2132        type = $el.attr('type');
2133
2134      if (lengthAllowed === undefined) {
2135        alert('Please add attribute "data-validation-length" to ' + $el[0].nodeName + ' named ' + $el.attr('name'));
2136        return true;
2137      }
2138
2139      // check if length is above min, below max or within range.
2140      var len = type === 'file' && $el.get(0).files !== undefined ? $el.get(0).files.length : val.length,
2141        lengthCheckResults = $.formUtils.numericRangeCheck(len, lengthAllowed),
2142        checkResult;
2143
2144      switch (lengthCheckResults[0]) {   // outside of allowed range
2145        case 'out':
2146          this.errorMessage = lang.lengthBadStart + lengthAllowed + lang.lengthBadEnd;
2147          checkResult = false;
2148          break;
2149        // too short
2150        case 'min':
2151          this.errorMessage = lang.lengthTooShortStart + lengthCheckResults[1] + lang.lengthBadEnd;
2152          checkResult = false;
2153          break;
2154        // too long
2155        case 'max':
2156          this.errorMessage = lang.lengthTooLongStart + lengthCheckResults[1] + lang.lengthBadEnd;
2157          checkResult = false;
2158          break;
2159        // ok
2160        default:
2161          checkResult = true;
2162      }
2163
2164      return checkResult;
2165    },
2166    errorMessage: '',
2167    errorMessageKey: ''
2168  });
2169
2170  /*
2171   * Validate url
2172   */
2173  $.formUtils.addValidator({
2174    name: 'url',
2175    validatorFunction: function (url) {
2176      // written by Scott Gonzalez: http://projects.scottsplayground.com/iri/
2177      // - Victor Jonsson added support for arrays in the url ?arg[]=sdfsdf
2178      // - General improvements made by Stéphane Moureau <https://github.com/TraderStf>
2179
2180      var urlFilter = /^(https?|ftp):\/\/((((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|\[|\]|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
2181      if (urlFilter.test(url)) {
2182        var domain = url.split('://')[1],
2183          domainSlashPos = domain.indexOf('/');
2184
2185        if (domainSlashPos > -1) {
2186          domain = domain.substr(0, domainSlashPos);
2187        }
2188
2189        return $.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add support for IP-addresses
2190      }
2191      return false;
2192    },
2193    errorMessage: '',
2194    errorMessageKey: 'badUrl'
2195  });
2196
2197  /*
2198   * Validate number (floating or integer)
2199   */
2200  $.formUtils.addValidator({
2201    name: 'number',
2202    validatorFunction: function (val, $el, conf) {
2203      if (val !== '') {
2204        var allowing = $el.valAttr('allowing') || '',
2205          decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator,
2206          allowsRange = false,
2207          begin, end,
2208          steps = $el.valAttr('step') || '',
2209          allowsSteps = false,
2210          sanitize = $el.attr('data-sanitize') || '',
2211          isFormattedWithNumeral = sanitize.match(/(^|[\s])numberFormat([\s]|$)/i);
2212
2213        if (isFormattedWithNumeral) {
2214          if (!window.numeral) {
2215            throw new ReferenceError('The data-sanitize value numberFormat cannot be used without the numeral' +
2216              ' library. Please see Data Validation in http://www.formvalidator.net for more information.');
2217          }
2218          //Unformat input first, then convert back to String
2219          if (val.length) {
2220            val = String(numeral().unformat(val));
2221          }
2222        }
2223
2224        if (allowing.indexOf('number') === -1) {
2225          allowing += ',number';
2226        }
2227
2228        if (allowing.indexOf('negative') === -1 && val.indexOf('-') === 0) {
2229          return false;
2230        }
2231
2232        if (allowing.indexOf('range') > -1) {
2233          begin = parseFloat(allowing.substring(allowing.indexOf('[') + 1, allowing.indexOf(';')));
2234          end = parseFloat(allowing.substring(allowing.indexOf(';') + 1, allowing.indexOf(']')));
2235          allowsRange = true;
2236        }
2237
2238        if (steps !== '') {
2239          allowsSteps = true;
2240        }
2241
2242        if (decimalSeparator === ',') {
2243          if (val.indexOf('.') > -1) {
2244            return false;
2245          }
2246          // Fix for checking range with floats using ,
2247          val = val.replace(',', '.');
2248        }
2249        if (val.replace(/[0-9-]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) {
2250          return true;
2251        }
2252
2253        if (allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9-]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) {
2254          return true;
2255        }
2256      }
2257      return false;
2258    },
2259    errorMessage: '',
2260    errorMessageKey: 'badInt'
2261  });
2262
2263  /*
2264   * Validate alpha numeric
2265   */
2266  $.formUtils.addValidator({
2267    name: 'alphanumeric',
2268    validatorFunction: function (val, $el, conf, language) {
2269      var patternStart = '^([a-zA-Z0-9',
2270        patternEnd = ']+)$',
2271        additionalChars = $el.valAttr('allowing'),
2272        pattern = '',
2273        hasSpaces = false;
2274
2275      if (additionalChars) {
2276        pattern = patternStart + additionalChars + patternEnd;
2277        var extra = additionalChars.replace(/\\/g, '');
2278        if (extra.indexOf(' ') > -1) {
2279          hasSpaces = true;
2280          extra = extra.replace(' ', '');
2281          extra += language.andSpaces || $.formUtils.LANG.andSpaces;
2282        }
2283
2284        if(language.badAlphaNumericAndExtraAndSpaces && language.badAlphaNumericAndExtra) {
2285          if(hasSpaces) {
2286            this.errorMessage = language.badAlphaNumericAndExtraAndSpaces + extra;
2287          } else {
2288            this.errorMessage = language.badAlphaNumericAndExtra + extra + language.badAlphaNumericExtra;
2289          }
2290        } else {
2291          this.errorMessage = language.badAlphaNumeric + language.badAlphaNumericExtra + extra;
2292        }
2293      } else {
2294        pattern = patternStart + patternEnd;
2295        this.errorMessage = language.badAlphaNumeric;
2296      }
2297
2298      return new RegExp(pattern).test(val);
2299    },
2300    errorMessage: '',
2301    errorMessageKey: ''
2302  });
2303
2304  /*
2305   * Validate against regexp
2306   */
2307  $.formUtils.addValidator({
2308    name: 'custom',
2309    validatorFunction: function (val, $el) {
2310      var regexp = new RegExp($el.valAttr('regexp'));
2311      return regexp.test(val);
2312    },
2313    errorMessage: '',
2314    errorMessageKey: 'badCustomVal'
2315  });
2316
2317  /*
2318   * Validate date
2319   */
2320  $.formUtils.addValidator({
2321    name: 'date',
2322    validatorFunction: function (date, $el, conf) {
2323      var dateFormat = $el.valAttr('format') || conf.dateFormat || 'yyyy-mm-dd',
2324        addMissingLeadingZeros = $el.valAttr('require-leading-zero') === 'false';
2325      return $.formUtils.parseDate(date, dateFormat, addMissingLeadingZeros) !== false;
2326    },
2327    errorMessage: '',
2328    errorMessageKey: 'badDate'
2329  });
2330
2331
2332  /*
2333   * Validate group of checkboxes, validate qty required is checked
2334   * written by Steve Wasiura : http://stevewasiura.waztech.com
2335   * element attrs
2336   *    data-validation="checkbox_group"
2337   *    data-validation-qty="1-2"  // min 1 max 2
2338   *    data-validation-error-msg="chose min 1, max of 2 checkboxes"
2339   */
2340  $.formUtils.addValidator({
2341    name: 'checkbox_group',
2342    validatorFunction: function (val, $el, conf, lang, $form) {
2343      // preset return var
2344      var isValid = true,
2345      // get name of element. since it is a checkbox group, all checkboxes will have same name
2346        elname = $el.attr('name'),
2347      // get checkboxes and count the checked ones
2348        $checkBoxes = $('input[type=checkbox][name^="' + elname + '"]', $form),
2349        checkedCount = $checkBoxes.filter(':checked').length,
2350      // get el attr that specs qty required / allowed
2351        qtyAllowed = $el.valAttr('qty');
2352
2353      if (qtyAllowed === undefined) {
2354        var elementType = $el.get(0).nodeName;
2355        alert('Attribute "data-validation-qty" is missing from ' + elementType + ' named ' + $el.attr('name'));
2356      }
2357
2358      // call Utility function to check if count is above min, below max, within range etc.
2359      var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed);
2360
2361      // results will be array, [0]=result str, [1]=qty int
2362      switch (qtyCheckResults[0]) {
2363        // outside allowed range
2364        case 'out':
2365          this.errorMessage = lang.groupCheckedRangeStart + qtyAllowed + lang.groupCheckedEnd;
2366          isValid = false;
2367          break;
2368        // below min qty
2369        case 'min':
2370          this.errorMessage = lang.groupCheckedTooFewStart + qtyCheckResults[1] + (lang.groupCheckedTooFewEnd || lang.groupCheckedEnd);
2371          isValid = false;
2372          break;
2373        // above max qty
2374        case 'max':
2375          this.errorMessage = lang.groupCheckedTooManyStart + qtyCheckResults[1] + (lang.groupCheckedTooManyEnd || lang.groupCheckedEnd);
2376          isValid = false;
2377          break;
2378        // ok
2379        default:
2380          isValid = true;
2381      }
2382
2383      if( !isValid ) {
2384        var _triggerOnBlur = function() {
2385          $checkBoxes.unbind('click', _triggerOnBlur);
2386          $checkBoxes.filter('*[data-validation]').validateInputOnBlur(lang, conf, false, 'blur');
2387        };
2388        $checkBoxes.bind('click', _triggerOnBlur);
2389      }
2390
2391      return isValid;
2392    }
2393    //   errorMessage : '', // set above in switch statement
2394    //   errorMessageKey: '' // not used
2395  });
2396
2397})(jQuery);
2398
2399
2400}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.