PageSourceSearch

https://isteqdamejaz.com/frontend/backEndFiles/validation/jquery.form-validator.js

js isteqdamejaz.com collected 2026-10-01 14:21:18 UTC 79,466 bytes, 2,370 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.77
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    var $elements = this[0].nodeName === 'FORM' ? this.find('*[data-validation-event]') : this;
569    $elements
570      .each(function () {
571        var $el = $(this),
572          etype = $el.valAttr('event');
573        if (etype) {
574          $el
575            .unbind(etype + '.validation')
576            .bind(etype + '.validation', function (evt) {
577              if( (evt || {}).keyCode !== 9 ) {
578                $(this).validateInputOnBlur(language, config, true, etype);
579              }
580            });
581        }
582      });
583    return this;
584  };
585
586  /**
587   * fade in help message when input gains focus
588   * fade out when input loses focus
589   * <input data-help="The info that I want to display for the user when input is focused" ... />
590   *
591   * @param {String} attrName - Optional, default is data-help
592   * @return {jQuery}
593   */
594  $.fn.showHelpOnFocus = function (attrName) {
595    if (!attrName) {
596      attrName = 'data-validation-help';
597    }
598
599    // Add help text listeners
600    this.find('textarea,input').each(function () {
601      var $elem = $(this),
602        className = 'jquery_form_help_' + (++_helpers),
603        help = $elem.attr(attrName);
604
605      // Reset
606      $elem
607        .removeClass('has-help-text')
608        .unbind('focus.help')
609        .unbind('blur.help');
610
611      if (help) {
612        $elem
613          .addClass('has-help-txt')
614          .bind('focus.help', function () {
615            var $help = $elem.parent().find('.' + className);
616            if ($help.length === 0) {
617              $help = $('<span />')
618                .addClass(className)
619                .addClass('help')
620                .addClass('help-block') // twitter bs
621                .text(help)
622                .hide();
623
624              $elem.after($help);
625            }
626            $help.fadeIn();
627          })
628          .bind('blur.help', function () {
629            $(this)
630              .parent()
631              .find('.' + className)
632              .fadeOut('slow');
633          });
634      }
635    });
636
637    return this;
638  };
639
640  /**
641   * @param {Function} cb
642   * @param {Object} [conf]
643   * @param {Object} [lang]
644   */
645  $.fn.validate = function(cb, conf, lang) {
646    var language = $.extend({}, $.formUtils.LANG, lang || {});
647    this.each(function() {
648      var $elem = $(this),
649        closestFormElem = $elem.closest('form').get(0) || {},
650        formDefaultConfig = closestFormElem.validationConfig || $.formUtils.defaultConfig();
651
652      $elem.one('validation', function(evt, isValid) {
653        if ( typeof cb === 'function' ) {
654          cb(isValid, this, evt);
655        }
656      });
657
658      $elem.validateInputOnBlur(
659        language,
660        $.extend({}, formDefaultConfig, conf || {}),
661        true
662      );
663    });
664  };
665
666  /**
667   * Tells whether or not validation of this input will have to postpone the form submit ()
668   * @returns {Boolean}
669   */
670  $.fn.willPostponeValidation = function() {
671    return (this.valAttr('suggestion-nr') ||
672      this.valAttr('postpone') ||
673      this.hasClass('hasDatepicker')) &&
674      !window.postponedValidation;
675  };
676
677  /**
678   * Validate single input when it loses focus
679   * shows error message in a span element
680   * that is appended to the parent element
681   *
682   * @param {Object} [language] Optional, will override $.formUtils.LANG
683   * @param {Object} [conf] Optional, will override the default settings
684   * @param {Boolean} attachKeyupEvent Optional
685   * @param {String} eventContext
686   * @return {jQuery}
687   */
688  $.fn.validateInputOnBlur = function (language, conf, attachKeyupEvent, eventContext) {
689
690    $.formUtils.eventType = eventContext;
691
692    if ( this.willPostponeValidation() ) {
693      // This validation has to be postponed
694      var _self = this,
695        postponeTime = this.valAttr('postpone') || 200;
696
697      window.postponedValidation = function () {
698        _self.validateInputOnBlur(language, conf, attachKeyupEvent, eventContext);
699        window.postponedValidation = false;
700      };
701
702      setTimeout(function () {
703        if (window.postponedValidation) {
704          window.postponedValidation();
705        }
706      }, postponeTime);
707
708      return this;
709    }
710
711    language = $.extend({}, $.formUtils.LANG, language || {});
712    $.formUtils.dialogs.removeInputStylingAndMessage(this, conf);
713
714    var $elem = this,
715      $form = $elem.closest('form'),
716      result = $.formUtils.validateInput(
717        $elem,
718        language,
719        conf,
720        $form,
721        eventContext
722      );
723
724    var reValidate = function() {
725      $elem.validateInputOnBlur(language, conf, false, 'blur.revalidated');
726    };
727
728    if (eventContext === 'blur') {
729      $elem
730        .unbind('validation.revalidate', reValidate)
731        .one('validation.revalidate', reValidate);
732    }
733
734    if (attachKeyupEvent) {
735      $elem.removeKeyUpValidation();
736    }
737
738    if (result.shouldChangeDisplay) {
739      if (result.isValid) {
740        $.formUtils.dialogs.applyInputSuccessStyling($elem, conf);
741      } else {
742        $.formUtils.dialogs.setInlineMessage($elem, result.errorMsg, conf);
743      }
744    }
745
746    if (!result.isValid && attachKeyupEvent) {
747      $elem.validateOnKeyUp(language, conf);
748    }
749
750    return this;
751  };
752
753  /**
754   * Validate element on keyup-event
755   */
756  $.fn.validateOnKeyUp = function(language, conf) {
757    this.each(function() {
758      var $input = $(this);
759      if (!$input.valAttr('has-keyup-event')) {
760        $input
761          .valAttr('has-keyup-event', 'true')
762          .bind('keyup.validation', function (evt) {
763            if( evt.keyCode !== 9 ) {
764              $input.validateInputOnBlur(language, conf, false, 'keyup');
765            }
766          });
767      }
768    });
769    return this;
770  };
771
772  /**
773   * Remove validation on keyup
774   */
775  $.fn.removeKeyUpValidation = function() {
776    this.each(function() {
777      $(this)
778        .valAttr('has-keyup-event', false)
779        .unbind('keyup.validation');
780    });
781    return this;
782  };
783
784  /**
785   * Short hand for fetching/adding/removing element attributes
786   * prefixed with 'data-validation-'
787   *
788   * @param {String} name
789   * @param {String|Boolean} [val]
790   * @return {String|undefined|jQuery}
791   * @protected
792   */
793  $.fn.valAttr = function (name, val) {
794    if (val === undefined) {
795      return this.attr('data-validation-' + name);
796    } else if (val === false || val === null) {
797      return this.removeAttr('data-validation-' + name);
798    } else {
799      name = ((name.length > 0) ? '-' + name : '');
800      return this.attr('data-validation' + name, val);
801    }
802  };
803
804  /**
805   * Function that validates all inputs in active form
806   *
807   * @param {Object} [language]
808   * @param {Object} [conf]
809   * @param {Boolean} [displayError] Defaults to true
810   */
811  $.fn.isValid = function (language, conf, displayError) {
812
813    if ($.formUtils.isLoadingModules) {
814      var $self = this;
815      setTimeout(function () {
816        $self.isValid(language, conf, displayError);
817      }, 200);
818      return null;
819    }
820
821    conf = $.extend({}, $.formUtils.defaultConfig(), conf || {});
822    language = $.extend({}, $.formUtils.LANG, language || {});
823    displayError = displayError !== false;
824
825    if ($.formUtils.errorDisplayPreventedWhenHalted) {
826      // isValid() was called programmatically with argument displayError set
827      // to false when the validation was halted by any of the validators
828      delete $.formUtils.errorDisplayPreventedWhenHalted;
829      displayError = false;
830    }
831
832    /**
833     * Adds message to error message stack if not already in the message stack
834     *
835     * @param {String} mess
836     * @para {jQuery} $elem
837     */
838    var addErrorMessage = function (mess, $elem) {
839        if ($.inArray(mess, errorMessages) < 0) {
840          errorMessages.push(mess);
841        }
842        errorInputs.push($elem);
843        $elem.valAttr('current-error', mess);
844        if (displayError) {
845          $.formUtils.dialogs.applyInputErrorStyling($elem, conf);
846        }
847      },
848
849      /** Holds inputs (of type checkox or radio) already validated, to prevent recheck of mulitple checkboxes & radios */
850      checkedInputs = [],
851
852      /** Error messages for this validation */
853      errorMessages = [],
854
855      /** Input elements which value was not valid */
856      errorInputs = [],
857
858      /** Form instance */
859      $form = this,
860
861      /**
862       * Tells whether or not to validate element with this name and of this type
863       *
864       * @param {String} name
865       * @param {String} type
866       * @return {Boolean}
867       */
868      ignoreInput = function (name, type) {
869        if (type === 'submit' || type === 'button' || type === 'reset') {
870          return true;
871        }
872        return $.inArray(name, conf.ignore || []) > -1;
873      };
874
875    // Reset style and remove error class
876    if (displayError) {
877      $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf);
878    }
879
880    // Validate element values
881    $form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function () {
882      var $elem = $(this),
883        elementType = $elem.attr('type'),
884        isCheckboxOrRadioBtn = elementType === 'radio' || elementType === 'checkbox',
885        elementName = $elem.attr('name');
886
887      if (!ignoreInput(elementName, elementType) && (!isCheckboxOrRadioBtn || $.inArray(elementName, checkedInputs) < 0)) {
888
889        if (isCheckboxOrRadioBtn) {
890          checkedInputs.push(elementName);
891        }
892
893        var result = $.formUtils.validateInput(
894          $elem,
895          language,
896          conf,
897          $form,
898          'submit'
899        );
900
901        if (!result.isValid) {
902          addErrorMessage(result.errorMsg, $elem);
903        } else if (result.isValid && result.shouldChangeDisplay) {
904          $elem.valAttr('current-error', false);
905          $.formUtils.dialogs.applyInputSuccessStyling($elem, conf);
906        }
907      }
908
909    });
910
911    // Run validation callback
912    if (typeof conf.onValidate === 'function') {
913      var errors = conf.onValidate($form);
914      if ($.isArray(errors)) {
915        $.each(errors, function (i, err) {
916          addErrorMessage(err.message, err.element);
917        });
918      }
919      else if (errors && errors.element && errors.message) {
920        addErrorMessage(errors.message, errors.element);
921      }
922    }
923
924    // Reset form validation flag
925    $.formUtils.isValidatingEntireForm = false;
926
927    // Validation failed
928    if (errorInputs.length > 0) {
929      if (displayError) {
930        if (conf.errorMessagePosition === 'top') {
931          $.formUtils.dialogs.setMessageInTopOfForm($form, errorMessages, conf, language);
932        } else {
933          $.each(errorInputs, function (i, $input) {
934            $.formUtils.dialogs.setInlineMessage($input, $input.valAttr('current-error'), conf);
935          });
936        }
937        if (conf.scrollToTopOnError) {
938          $.formUtils.$win.scrollTop($form.offset().top - 20);
939        }
940      }
941    }
942
943    if (!displayError && $.formUtils.haltValidation) {
944      $.formUtils.errorDisplayPreventedWhenHalted = true;
945    }
946
947    return errorInputs.length === 0 && !$.formUtils.haltValidation;
948  };
949
950  /**
951   * Plugin for displaying input length restriction
952   */
953  $.fn.restrictLength = function (maxLengthElement) {
954    new $.formUtils.lengthRestriction(this, maxLengthElement);
955    return this;
956  };
957
958  /**
959   * Add suggestion dropdown to inputs having data-suggestions with a comma
960   * separated string with suggestions
961   * @param {Array} [settings]
962   * @returns {jQuery}
963   */
964  $.fn.addSuggestions = function (settings) {
965    var sugs = false;
966    this.find('input').each(function () {
967      var $field = $(this);
968
969      sugs = $.split($field.attr('data-suggestions'));
970
971      if (sugs.length > 0 && !$field.hasClass('has-suggestions')) {
972        $.formUtils.suggest($field, sugs, settings);
973        $field.addClass('has-suggestions');
974      }
975    });
976    return this;
977  };
978
979
980})(jQuery, window);
981
982/**
983 * Utility methods used for handling loading of modules (attached to $.formUtils)
984 */
985(function($) {
986
987  'use strict';
988
989  $.formUtils = $.extend($.formUtils || {}, {
990
991    /**
992     * @var {Boolean}
993     */
994    isLoadingModules: false,
995
996    /**
997     * @var {Object}
998     */
999    loadedModules: {},
1000
1001    /**
1002     * @param {String} name
1003     */
1004    registerLoadedModule: function (name) {
1005      this.loadedModules[$.trim(name).toLowerCase()] = true;
1006    },
1007
1008    /**
1009     * @param {String} name
1010     * @return {Boolean}
1011     */
1012    hasLoadedModule: function (name) {
1013      return $.trim(name).toLowerCase() in this.loadedModules;
1014    },
1015
1016    /**
1017     * @example
1018     *  $.formUtils.loadModules('date, security.dev');
1019     *
1020     * Will load the scripts date.js and security.dev.js from the
1021     * directory where this script resides. If you want to load
1022     * the modules from another directory you can use the
1023     * path argument.
1024     *
1025     * The script will be cached by the browser unless the module
1026     * name ends with .dev
1027     *
1028     * @param {String} modules - Comma separated string with module file names (no directory nor file extension)
1029     * @param {String} [path] - Path where the module files are located if their not in the same directory as the core modules
1030     * @param {function} [callback] - Callback invoked when all modules are loaded
1031     */
1032    loadModules: function (modules, path, callback) {
1033
1034      if ($.formUtils.isLoadingModules) {
1035        setTimeout(function () {
1036          $.formUtils.loadModules(modules, path, callback);
1037        }, 100);
1038        return;
1039      }
1040
1041      var loadModuleScripts = function (modules, path) {
1042
1043          var moduleList = $.split(modules),
1044            numModules = moduleList.length,
1045            moduleLoadedCallback = function () {
1046              numModules--;
1047              if (numModules === 0) {
1048                $.formUtils.isLoadingModules = false;
1049                if (typeof callback === 'function') {
1050                    callback();
1051                }
1052              }
1053            };
1054
1055          if (numModules > 0) {
1056            $.formUtils.isLoadingModules = true;
1057          }
1058
1059          var cacheSuffix = '?_=' + ( new Date().getTime() ),
1060            appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0];
1061
1062          $.each(moduleList, function (i, modName) {
1063            modName = $.trim(modName);
1064            if (modName.length === 0 || $.formUtils.hasLoadedModule(modName)) {
1065              moduleLoadedCallback();
1066            } else {
1067              var scriptUrl = path + modName + (modName.slice(-3) === '.js' ? '' : '.js'),
1068                script = document.createElement('SCRIPT');
1069
1070              if (typeof define === 'function' && define.amd) {
1071                require([scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' )], moduleLoadedCallback);
1072              } else {
1073                // Load the script
1074                script.type = 'text/javascript';
1075                script.onload = moduleLoadedCallback;
1076                script.src = scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' );
1077                script.onerror = function() {
1078                  $.formUtils.warn('Unable to load form validation module '+scriptUrl, true);
1079                  moduleLoadedCallback();
1080                };
1081                script.onreadystatechange = function () {
1082                  // IE 7 fix
1083                  if (this.readyState === 'complete' || this.readyState === 'loaded') {
1084                    moduleLoadedCallback();
1085                    // Handle memory leak in IE
1086                    this.onload = null;
1087                    this.onreadystatechange = null;
1088                  }
1089                };
1090                appendToElement.appendChild(script);
1091              }
1092            }
1093          });
1094        };
1095
1096      if (path) {
1097        loadModuleScripts(modules, path);
1098      } else {
1099        var findScriptPathAndLoadModules = function () {
1100          var foundPath = false;
1101          $('script[src*="form-validator"]').each(function () {
1102            var isScriptFromPluginNodeModulesDirectory = this.src.split('form-validator')[1].split('node_modules').length > 1;
1103            if (!isScriptFromPluginNodeModulesDirectory) {
1104              foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
1105              if (foundPath === '/') {
1106                foundPath = '';
1107              }
1108              return false;
1109            }
1110          });
1111
1112          if (foundPath !== false) {
1113            loadModuleScripts(modules, foundPath);
1114            return true;
1115          }
1116          return false;
1117        };
1118
1119        if (!findScriptPathAndLoadModules()) {
1120          $(function () {
1121            var hasLoadedModuleScripts = findScriptPathAndLoadModules();
1122            if (!hasLoadedModuleScripts) {
1123              // The modules may have been inserted via a minified script
1124              if (typeof callback === 'function') {
1125                callback();
1126              }
1127            }
1128          });
1129        }
1130      }
1131    }
1132
1133  });
1134
1135})(jQuery);
1136
1137/**
1138 * Setup function for the plugin
1139 */
1140(function ($) {
1141
1142  'use strict';
1143
1144
1145  /**
1146   * A bit smarter split function
1147   * delimiter can be space, comma, dash or pipe
1148   * @param {String} val
1149   * @param {Function|String} [callback]
1150   * @param {Boolean}
1150 [allowSpaceAsDelimiter]
1151   * @returns {Array|void}
1152   */
1153  $.split = function (val, callback, allowSpaceAsDelimiter) {
1154    // default to true
1155    allowSpaceAsDelimiter = allowSpaceAsDelimiter === undefined || allowSpaceAsDelimiter === true;
1156    var pattern = '[,|'+(allowSpaceAsDelimiter ? '\\s':'')+'-]\\s*',
1157      regex = new RegExp(pattern, 'g');
1158    if (typeof callback !== 'function') {
1159      // return array
1160      if (!val) {
1161        return [];
1162      }
1163      var values = [];
1164      $.each(val.split(callback ? callback : regex),
1165        function (i, str) {
1166          str = $.trim(str);
1167          if (str.length) {
1168            values.push(str);
1169          }
1170        }
1171      );
1172      return values;
1173    } else if (val) {
1174      // exec callback func on each
1175      $.each(val.split(regex),
1176        function (i, str) {
1177          str = $.trim(str);
1178          if (str.length) {
1179            return callback(str, i);
1180          }
1181        }
1182      );
1183    }
1184  };
1185
1186  /**
1187   * Short hand function that makes the validation setup require less code
1188   * @param conf
1189   */
1190  $.validate = function (conf) {
1191
1192    var defaultConf = $.extend($.formUtils.defaultConfig(), {
1193      form: 'form',
1194      validateOnEvent: false,
1195      validateOnBlur: true,
1196      validateCheckboxRadioOnClick: true,
1197      showHelpOnFocus: true,
1198      addSuggestions: true,
1199      modules: '',
1200      onModulesLoaded: null,
1201      language: false,
1202      onSuccess: false,
1203      onError: false,
1204      onElementValidate: false
1205    });
1206
1207    conf = $.extend(defaultConf, conf || {});
1208
1209    $(window).trigger('formValidationPluginInit', [conf]);
1210
1211    if( conf.lang && conf.lang !== 'en' ) {
1212      var langModule = 'lang/'+conf.lang+'.js';
1213      conf.modules += conf.modules.length ? ','+langModule : langModule;
1214    }
1215
1216    // Add validation to forms
1217    $(conf.form).each(function (i, form) {
1218
1219      // Make a reference to the config for this form
1220      form.validationConfig = conf;
1221
1222      // Trigger jQuery event that we're about to setup validation
1223      var $form = $(form);
1224      $form.trigger('formValidationSetup', [$form, conf]);
1225
1226      // Remove classes and event handlers that might have been
1227      // added by a previous call to $.validate
1228      $form.find('.has-help-txt')
1229          .unbind('focus.validation')
1230          .unbind('blur.validation');
1231
1232      $form
1233        .removeClass('has-validation-callback')
1234        .unbind('submit.validation')
1235        .unbind('reset.validation')
1236        .find('input[data-validation],textarea[data-validation]')
1237          .unbind('blur.validation');
1238
1239      // Validate when submitted
1240      $form.bind('submit.validation', function (evt) {
1241
1242        var $form = $(this),
1243          stop = function() {
1244            evt.stopImmediatePropagation();
1245            return false;
1246          };
1247
1248        if ($.formUtils.haltValidation) {
1249          // pressing several times on submit button while validation is halted
1250          return stop();
1251        }
1252
1253        if ($.formUtils.isLoadingModules) {
1254          setTimeout(function () {
1255            $form.trigger('submit.validation');
1256          }, 200);
1257          return stop();
1258        }
1259
1260        var valid = $form.isValid(conf.language, conf);
1261        if ($.formUtils.haltValidation) {
1262          // Validation got halted by one of the validators
1263          return stop();
1264        } else {
1265          if (valid && typeof conf.onSuccess === 'function') {
1266            var callbackResponse = conf.onSuccess($form);
1267            if (callbackResponse === false) {
1268              return stop();
1269            }
1270          } else if (!valid && typeof conf.onError === 'function') {
1271            conf.onError($form);
1272            return stop();
1273          } else {
1274            return valid ? true : stop();
1275          }
1276        }
1277      })
1278      .bind('reset.validation', function () {
1279        $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf);
1280      })
1281      .addClass('has-validation-callback');
1282
1283      if (conf.showHelpOnFocus) {
1284        $form.showHelpOnFocus();
1285      }
1286      if (conf.addSuggestions) {
1287        $form.addSuggestions();
1288      }
1289      if (conf.validateOnBlur) {
1290        $form.validateOnBlur(conf.language, conf);
1291        $form.bind('html5ValidationAttrsFound', function () {
1292          $form.validateOnBlur(conf.language, conf);
1293        });
1294      }
1295      if (conf.validateOnEvent) {
1296        $form.validateOnEvent(conf.language, conf);
1297      }
1298    });
1299
1300    if (conf.modules !== '') {
1301      $.formUtils.loadModules(conf.modules, null, function() {
1302        if (typeof conf.onModulesLoaded === 'function') {
1303          conf.onModulesLoaded();
1304        }
1305        var $form = typeof conf.form === 'string' ? $(conf.form) : conf.form;
1306        $.formUtils.$win.trigger('validatorsLoaded', [$form, conf]);
1307      });
1308    }
1309  };
1310
1311})(jQuery);
1312
1313/**
1314 * Utility methods and properties attached to $.formUtils
1315 */
1316(function($, window) {
1317
1318  'use strict';
1319
1320  var $win = $(window);
1321
1322  $.formUtils = $.extend($.formUtils || {}, {
1323
1324    $win: $win,
1325
1326    /**
1327     * Default config for $(...).isValid();
1328     */
1329    defaultConfig: function () {
1330      return {
1331        ignore: [], // Names of inputs not to be validated even though `validationRuleAttribute` containing the validation rules tells us to
1332        errorElementClass: 'error', // Class that will be put on elements which value is invalid
1333        successElementClass: 'valid', // Class that will be put on elements that has been validated with success
1334        borderColorOnError: '#b94a48', // Border color of elements which value is invalid, empty string to not change border color
1335        errorMessageClass: 'form-error', // class name of div containing error messages when validation fails
1336        validationRuleAttribute: 'data-validation', // name of the attribute holding the validation rules
1337        validationErrorMsgAttribute: 'data-validation-error-msg', // define custom err msg inline with element
1338        errorMessagePosition: 'inline', // Can be either "top" or "inline"
1339        errorMessageTemplate: {
1340          container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>',
1341          messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
1342          field: '<li>{msg}</li>'
1343        },
1344        scrollToTopOnError: true,
1345        dateFormat: 'yyyy-mm-dd',
1346        addValidClassOnAll: false, // whether or not to apply class="valid" even if the input wasn't validated
1347        decimalSeparator: '.',
1348        inputParentClassOnError: 'has-error', // twitter-bootstrap default class name
1349        inputParentClassOnSuccess: 'has-success', // twitter-bootstrap default class name
1350        validateHiddenInputs: false, // whether or not hidden inputs should be validated
1351        inlineErrorMessageCallback: false,
1352        submitErrorMessageCallback: false
1353      };
1354    },
1355
1356    /**
1357     * Available validators
1358     */
1359    validators: {},
1360
1361    /**
1362     * Events triggered by form validator
1363     */
1364    _events: {load: [], valid: [], invalid: []},
1365
1366    /**
1367     * Setting this property to true during validation will
1368     * stop further validation from taking place and form will
1369     * not be sent
1370     */
1371    haltValidation: false,
1372
1373    /**
1374     * Function for adding a validator
1375     * @see $.formUtils.addAsyncValidator (async.js)
1376     * @param {Object} validator
1377     */
1378    addValidator: function (validator) {
1379      // prefix with "validate_" for backward compatibility reasons
1380      var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_' + validator.name;
1381      if (validator.validateOnKeyUp === undefined) {
1382        validator.validateOnKeyUp = true;
1383      }
1384      this.validators[name] = validator;
1385    },
1386
1387    /**
1388     * Warn user via the console if available
1389     */
1390    warn: function(msg, fallbackOnAlert) {
1391      if( 'console' in window ) {
1392        if( typeof window.console.warn === 'function' ) {
1393          window.console.warn(msg);
1394        } else if( typeof window.console.log === 'function' ) {
1395          window.console.log(msg);
1396        }
1397      } else if (fallbackOnAlert) {
1398        // This is for some old IE version...
1399        alert(msg);
1400      }
1401    },
1402
1403    /**
1404     * Same as input $.fn.val() but also supporting input of typ radio or checkbox
1405     * @example
1406     *
1407     *  $.formUtils.getValue('.myRadioButtons', $('#some-form'));
1408     *  $.formUtils.getValue($('#some-form').find('.check-boxes'));
1409     *
1410     * @param query
1411     * @param $parent
1412     * @returns {String|Boolean}
1413     */
1414    getValue: function(query, $parent) {
1415      var $inputs = $parent ? $parent.find(query) : query;
1416      if ($inputs.length > 0 ) {
1417        var type = $inputs.eq(0).attr('type');
1418        if (type === 'radio' || type === 'checkbox') {
1419          return $inputs.filter(':checked').val() || '';
1420        } else {
1421          return $inputs.val() || '';
1422        }
1423      }
1424      return false;
1425    },
1426
1427    /**
1428     * Validate the value of given element according to the validation rules
1429     * found in the attribute data-validation. Will return an object representing
1430     * a validation result, having the props shouldChangeDisplay, isValid and errorMsg
1431     * @param {jQuery} $elem
1432     * @param {Object} language ($.formUtils.LANG)
1433     * @param {Object} conf
1434     * @param {jQuery} $form
1435     * @param {String} [eventContext]
1436     * @return {Object}
1437     */
1438    validateInput: function ($elem, language, conf, $form, eventContext) {
1439
1440      conf = conf || $.formUtils.defaultConfig();
1441      language = language || $.formUtils.LANG;
1442
1443      if (!$form.length) {
1444        $form = $elem.parent();
1445      }
1446
1447      var value = this.getValue($elem);
1448
1449      $elem
1450        .valAttr('skipped', false)
1451        .one('beforeValidation', function() {
1452          // Skip input because its hidden or disabled
1453          // Doing this in a callback makes it possible for others to prevent the default
1454          // behaviour by binding to the same event and call evt.stopImmediatePropagation()
1455          if ($elem.attr('disabled') || (!$elem.is(':visible') && !conf.validateHiddenInputs)) {
1456            $elem.valAttr('skipped', 1);
1457          }
1458        })
1459        .trigger('beforeValidation', [value, language, conf]);
1460
1461      var inputIsOptional = $elem.valAttr('optional') === 'true',
1462          skipBecauseItsEmpty = !value && inputIsOptional,
1463          validationRules = $elem.attr(conf.validationRuleAttribute),
1464          isValid = true,
1465          errorMsg = '',
1466          result = {isValid: true, shouldChangeDisplay:true, errorMsg:''};
1467
1468      // For input type="number", browsers attempt to parse the entered value into a number.
1469      // If the input is not numeric, browsers handle the situation differently:
1470      // Chrome 48 simply disallows non-numeric input; FF 44 clears out the input box on blur;
1471      // Safari 5 parses the entered string to find a leading number.
1472      // If the input fails browser validation, the browser sets the input value equal to an empty string.
1473      // Therefore, we cannot distinguish (apart from hacks) between an empty input type="text" and one with a
1474      // value that can't be parsed by the browser.
1475
1476      if (!validationRules || skipBecauseItsEmpty || $elem.valAttr('skipped')) {
1477        result.shouldChangeDisplay = conf.addValidClassOnAll;
1478        return result;
1479      }
1480
1481      // Filter out specified characters
1482      var ignore = $elem.valAttr('ignore');
1483      if (ignore) {
1484        $.each(ignore.split(''), function(i, character) {
1485          value = value.replace(new RegExp('\\'+character, 'g'), '');
1486        });
1487      }
1488
1489      $.split(validationRules, function (rule) {
1490
1491        if (rule.indexOf('validate_') !== 0) {
1492          rule = 'validate_' + rule;
1493        }
1494
1495        var validator = $.formUtils.validators[rule];
1496
1497        if (validator) {
1498
1499          // special change of element for checkbox_group rule
1500          if (rule === 'validate_checkbox_group') {
1501            // set element to first in group, so error msg attr doesn't need to be set on all elements in group
1502            $elem = $form.find('[name="' + $elem.attr('name') + '"]:eq(0)');
1503          }
1504
1505          if (eventContext !== 'keyup' || validator.validateOnKeyUp) {
1506            // A validator can prevent itself from getting triggered on keyup
1507            isValid = validator.validatorFunction(value, $elem, conf, language, $form, eventContext);
1508          }
1509
1510          if (!isValid) {
1511            if (conf.validateOnBlur) {
1512              $elem.validateOnKeyUp(language, conf);
1513            }
1514            errorMsg = $.formUtils.dialogs.resolveErrorMessage($elem, validator, rule, conf, language);
1515            return false; // break iteration
1516          }
1517
1518        } else {
1519
1520          // todo: Add some validator lookup function and tell immediately which module is missing
1521          throw new Error('Using undefined validator "' + rule +
1522            '". Maybe you have forgotten to load the module that "' + rule +'" belongs to?');
1523
1524        }
1525
1526      });
1527
1528
1529      if (isValid === false) {
1530        $elem.trigger('validation', false);
1531        result.errorMsg = errorMsg;
1532        result.isValid = false;
1533        result.shouldChangeDisplay = true;
1534      } else if (isValid === null) {
1535        // A validatorFunction returning null means that it's not able to validate
1536        // the input at this time. Most probably some async stuff need to gets finished
1537        // first and then the validator will re-trigger the validation.
1538        result.shouldChangeDisplay = false;
1539      } else {
1540        $elem.trigger('validation', true);
1541        result.shouldChangeDisplay = true;
1542      }
1543
1544      // Run element validation callback
1545      if (typeof conf.onElementValidate === 'function' && errorMsg !== null) {
1546        conf.onElementValidate(result.isValid, $elem, $form, errorMsg);
1547      }
1548
1549      $elem.trigger('afterValidation', [result, eventContext]);
1550
1551      return result;
1552    },
1553
1554    /**
1555     * Is it a correct date according to given dateFormat. Will return false if not, otherwise
1556     * an array 0=>year 1=>month 2=>day
1557     *
1558     * @param {String} val
1559     * @param {String} dateFormat
1560     * @param {Boolean} [addMissingLeadingZeros]
1561     * @return {Array}|{Boolean}
1562     */
1563    parseDate: function (val, dateFormat, addMissingLeadingZeros) {
1564      var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0, 1),
1565        regexp = '^',
1566        formatParts = dateFormat.split(divider || null),
1567        matches, day, month, year;
1568
1569      $.each(formatParts, function (i, part) {
1570        regexp += (i > 0 ? '\\' + divider : '') + '(\\d{' + part.length + '})';
1571      });
1572
1573      regexp += '$';
1574
1575      if (addMissingLeadingZeros) {
1576        var newValueParts = [];
1577        $.each(val.split(divider), function(i, part) {
1578          if(part.length === 1) {
1579            part = '0'+part;
1580          }
1581          newValueParts.push(part);
1582        });
1583        val = newValueParts.join(divider);
1584      }
1585
1586      matches = val.match(new RegExp(regexp));
1587      if (matches === null) {
1588        return false;
1589      }
1590
1591      var findDateUnit = function (unit, formatParts, matches) {
1592        for (var i = 0; i < formatParts.length; i++) {
1593          if (formatParts[i].substring(0, 1) === unit) {
1594            return $.formUtils.parseDateInt(matches[i + 1]);
1595          }
1596        }
1597        return -1;
1598      };
1599
1600      month = findDateUnit('m', formatParts, matches);
1601      day = findDateUnit('d', formatParts, matches);
1602      year = findDateUnit('y', formatParts, matches);
1603
1604      if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0)) ||
1605        (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0)) ||
1606        month > 12 || month === 0) {
1607        return false;
1608      }
1609      if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) {
1610        return false;
1611      }
1612
1613      return [year, month, day];
1614    },
1615
1616    /**
1617     * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt?
1618     *
1619     * @param {String} val
1620     * @return {Number}
1621     */
1622    parseDateInt: function (val) {
1623      if (val.indexOf('0') === 0) {
1624        val = val.replace('0', '');
1625      }
1626      return parseInt(val, 10);
1627    },
1628
1629    /**
1630     * Has month only 30 days?
1631     *
1632     * @param {Number} m
1633     * @return {Boolean}
1634     */
1635    isShortMonth: function (m) {
1636      return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
1637    },
1638
1639    /**
1640     * Restrict input length
1641     *
1642     * @param {jQuery} $inputElement Jquery Html object
1643     * @param {jQuery} $maxLengthElement jQuery Html Object
1644     * @return void
1645     */
1646    lengthRestriction: function ($inputElement, $maxLengthElement) {
1647      // read maxChars from counter display initial text value
1648      var maxChars = parseInt($maxLengthElement.text(), 10),
1649        charsLeft = 0,
1650
1651      // internal function does the counting and sets display value
1652        countCharacters = function () {
1653          var numChars = $inputElement.val().length;
1654          if (numChars > maxChars) {
1655            // get current scroll bar position
1656            var currScrollTopPos = $inputElement.scrollTop();
1657            // trim value to max length
1658            $inputElement.val($inputElement.val().substring(0, maxChars));
1659            $inputElement.scrollTop(currScrollTopPos);
1660          }
1661          charsLeft = maxChars - numChars;
1662          if (charsLeft < 0) {
1663            charsLeft = 0;
1664          }
1665
1666          // set counter text
1667          $maxLengthElement.text(charsLeft);
1668        };
1669
1670      // bind events to this element
1671      // setTimeout is needed, cut or paste fires before val is available
1672      $($inputElement).bind('keydown keyup keypress focus blur', countCharacters)
1673        .bind('cut paste', function () {
1674          setTimeout(countCharacters, 100);
1675        });
1676
1677      // count chars on pageload, if there are prefilled input-values
1678      $(document).bind('ready', countCharacters);
1679    },
1680
1681    /**
1682     * Test numeric against allowed range
1683     *
1684     * @param $value int
1685     * @param $rangeAllowed str; (1-2, min1, max2, 10)
1686     * @return array
1687     */
1688    numericRangeCheck: function (value, rangeAllowed) {
1689      // split by dash
1690      var range = $.split(rangeAllowed),
1691      // min or max
1692        minmax = parseInt(rangeAllowed.substr(3), 10);
1693
1694      if( range.length === 1 && rangeAllowed.indexOf('min') === -1 && rangeAllowed.indexOf('max') === -1 ) {
1695        range = [rangeAllowed, rangeAllowed]; // only a number, checking agains an exact number of characters
1696      }
1697
1698      // range ?
1699      if (range.length === 2 && (value < parseInt(range[0], 10) || value > parseInt(range[1], 10) )) {
1700        return [ 'out', range[0], range[1] ];
1701      } // value is out of range
1702      else if (rangeAllowed.indexOf('min') === 0 && (value < minmax )) // min
1703      {
1704        return ['min', minmax];
1705      } // value is below min
1706      else if (rangeAllowed.indexOf('max') === 0 && (value > minmax )) // max
1707      {
1708        return ['max', minmax];
1709      } // value is above max
1710      // since no other returns executed, value is in allowed range
1711      return [ 'ok' ];
1712    },
1713
1714
1715    _numSuggestionElements: 0,
1716    _selectedSuggestion: null,
1717    _previousTypedVal: null,
1718
1719    /**
1720     * Utility function that can be used to create plugins that gives
1721     * suggestions when inputs is typed into
1722     * @param {jQuery} $elem
1723     * @param {Array} suggestions
1724     * @param {Object} settings - Optional
1725     * @return {jQuery}
1726     */
1727    suggest: function ($elem, suggestions, settings) {
1728      var conf = {
1729          css: {
1730            maxHeight: '150px',
1731            background: '#FFF',
1732            lineHeight: '150%',
1733            textDecoration: 'underline',
1734            overflowX: 'hidden',
1735            overflowY: 'auto',
1736            border: '#CCC solid 1px',
1737            borderTop: 'none',
1738            cursor: 'pointer'
1739          },
1740          activeSuggestionCSS: {
1741            background: '#E9E9E9'
1742          }
1743        },
1744        setSuggsetionPosition = function ($suggestionContainer, $input) {
1745          var offset = $input.offset();
1746          $suggestionContainer.css({
1747            width: $input.outerWidth(),
1748            left: offset.left + 'px',
1749            top: (offset.top + $input.outerHeight()) + 'px'
1750          });
1751        };
1752
1753      if (settings) {
1754        $.extend(conf, settings);
1755      }
1756
1757      conf.css.position = 'absolute';
1758      conf.css['z-index'] = 9999;
1759      $elem.attr('autocomplete', 'off');
1760
1761      if (this._numSuggestionElements === 0) {
1762        // Re-position suggestion container if window size changes
1763        $win.bind('resize', function () {
1764          $('.jquery-form-suggestions').each(function () {
1765            var $container = $(this),
1766              suggestID = $container.attr('data-suggest-container');
1767            setSuggsetionPosition($container, $('.suggestions-' + suggestID).eq(0));
1768          });
1769        });
1770      }
1771
1772      this._numSuggestionElements++;
1773
1774      var onSelectSuggestion = function ($el) {
1775        var suggestionId = $el.valAttr('suggestion-nr');
1776        $.formUtils._selectedSuggestion = null;
1777        $.formUtils._previousTypedVal = null;
1778        $('.jquery-form-suggestion-' + suggestionId).fadeOut('fast');
1779      };
1780
1781      $elem
1782        .data('suggestions', suggestions)
1783        .valAttr('suggestion-nr', this._numSuggestionElements)
1784        .unbind('focus.suggest')
1785        .bind('focus.suggest', function () {
1786          $(this).trigger('keyup');
1787          $.formUtils._selectedSuggestion = null;
1788        })
1789        .unbind('keyup.suggest')
1790        .bind('keyup.suggest', function () {
1791          var $input = $(this),
1792            foundSuggestions = [],
1793            val = $.trim($input.val()).toLocaleLowerCase();
1794
1795          if (val === $.formUtils._previousTypedVal) {
1796            return;
1797          }
1798          else {
1799            $.formUtils._previousTypedVal = val;
1800          }
1801
1802          var hasTypedSuggestion = false,
1803            suggestionId = $input.valAttr('suggestion-nr'),
1804            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1805
1806          $suggestionContainer.scrollTop(0);
1807
1808          // Find the right suggestions
1809          if (val !== '') {
1810            var findPartial = val.length > 2;
1811            $.each($input.data('suggestions'), function (i, suggestion) {
1812              var lowerCaseVal = suggestion.toLocaleLowerCase();
1813              if (lowerCaseVal === val) {
1814                foundSuggestions.push('<strong>' + suggestion + '</strong>');
1815                hasTypedSuggestion = true;
1816                return false;
1817              } else if (lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) {
1818                foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>'));
1819              }
1820            });
1821          }
1822
1823          // Hide suggestion container
1824          if (hasTypedSuggestion || (foundSuggestions.length === 0 && $suggestionContainer.length > 0)) {
1825            $suggestionContainer.hide();
1826          }
1827
1828          // Create suggestion container if not already exists
1829          else if (foundSuggestions.length > 0 && $suggestionContainer.length === 0) {
1830            $suggestionContainer = $('<div></div>').css(conf.css).appendTo('body');
1831            $elem.addClass('suggestions-' + suggestionId);
1832            $suggestionContainer
1833              .attr('data-suggest-container', suggestionId)
1834              .addClass('jquery-form-suggestions')
1835              .addClass('jquery-form-suggestion-' + suggestionId);
1836          }
1837
1838          // Show hidden container
1839          else if (foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) {
1840            $suggestionContainer.show();
1841          }
1842
1843          // add suggestions
1844          if (foundSuggestions.length > 0 && val.length !== foundSuggestions[0].length) {
1845
1846            // put container in place every time, just in case
1847            setSuggsetionPosition($suggestionContainer, $input);
1848
1849            // Add suggestions HTML to container
1850            $suggestionContainer.html('');
1851            $.each(foundSuggestions, function (i, text) {
1852              $('<div></div>')
1853                .append(text)
1854                .css({
1855                  overflow: 'hidden',
1856                  textOverflow: 'ellipsis',
1857                  whiteSpace: 'nowrap',
1858                  padding: '5px'
1859                })
1860                .addClass('form-suggest-element')
1861                .appendTo($suggestionContainer)
1862                .click(function () {
1863                  $input.focus();
1864                  $input.val($(this).text());
1865                  $input.trigger('change');
1866                  onSelectSuggestion($input);
1867                });
1868            });
1869          }
1870        })
1871        .unbind('keydown.validation')
1872        .bind('keydown.validation', function (e) {
1873          var code = (e.keyCode ? e.keyCode : e.which),
1874            suggestionId,
1875            $suggestionContainer,
1876            $input = $(this);
1877
1878          if (code === 13 && $.formUtils._selectedSuggestion !== null) {
1879            suggestionId = $input.valAttr('suggestion-nr');
1880            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1881            if ($suggestionContainer.length > 0) {
1882              var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
1883              $input.val(newText);
1884              $input.trigger('change');
1885              onSelectSuggestion($input);
1886              e.preventDefault();
1887            }
1888          }
1889          else {
1890            suggestionId = $input.valAttr('suggestion-nr');
1891            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1892            var $suggestions = $suggestionContainer.children();
1893            if ($suggestions.length > 0 && $.inArray(code, [38, 40]) > -1) {
1894              if (code === 38) { // key up
1895                if ($.formUtils._selectedSuggestion === null) {
1896                  $.formUtils._selectedSuggestion = $suggestions.length - 1;
1897                }
1898                else{
1899                  $.formUtils._selectedSuggestion--;
1900                }
1901                if ($.formUtils._selectedSuggestion < 0) {
1902                  $.formUtils._selectedSuggestion = $suggestions.length - 1;
1903                }
1904              }
1905              else if (code === 40) { // key down
1906                if ($.formUtils._selectedSuggestion === null) {
1907                  $.formUtils._selectedSuggestion = 0;
1908                }
1909                else {
1910                  $.formUtils._selectedSuggestion++;
1911                }
1912                if ($.formUtils._selectedSuggestion > ($suggestions.length - 1)) {
1913                  $.formUtils._selectedSuggestion = 0;
1914                }
1915              }
1916
1917              // Scroll in suggestion window
1918              var containerInnerHeight = $suggestionContainer.innerHeight(),
1919                containerScrollTop = $suggestionContainer.scrollTop(),
1920                suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(),
1921                activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion);
1922
1923              if (activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop + containerInnerHeight)) {
1924                $suggestionContainer.scrollTop(activeSuggestionPosY);
1925              }
1926
1927              $suggestions
1928                .removeClass('active-suggestion')
1929                .css('background', 'none')
1930                .eq($.formUtils._selectedSuggestion)
1931                .addClass('active-suggestion')
1932                .css(conf.activeSuggestionCSS);
1933
1934              e.preventDefault();
1935              return false;
1936            }
1937          }
1938        })
1939        .unbind('blur.suggest')
1940        .bind('blur.suggest', function () {
1941          onSelectSuggestion($(this));
1942        });
1943
1944      return $elem;
1945    },
1946
1947    /**
1948     * Error dialogs
1949     *
1950     * @var {Object}
1951     */
1952    LANG: {
1953      errorTitle: 'فَشِلَ إرسال النموذج',
1954      requiredField: '',
1955      requiredFields: 'لم يتم ملأ جميع الحقول المطلوبة.',
1956      badTime: 'حقل الوقت خاطىء',
1957      badEmail: 'البريد الإلكتروني المدخل خاطئ',
1958      badTelephone: 'رقم الهاتف المدخل خاطئ',
1959      badSecurityAnswer: 'لم يتم الإجابة عن سؤال الأمان',
1960      badDate: 'تاريخ مدخل خاطئ',
1961      lengthBadStart: 'القيمة المدخلة يجب أن تكون بين ',
1962      lengthBadEnd: ' حروف',
1963      lengthTooLongStart: 'القيمة المدخل أطول من ',
1964      lengthTooShortStart: 'القيمة المدخل أقصر من ',
1965      notConfirmed: 'لم يتم تأكيد القيمة المدخلة',
1966      badDomain: 'قيمة نطاق خاطئة',
1967      badUrl: 'القيمة المدخلة ليست رابطاً صالحاً',
1968      badCustomVal: 'القيمة المدخلة غير صالحة',
1969      andSpaces: ' ومسافات ',
1970      badInt: 'القيمة المدخلة ليست رقماً صحيحاً',
1971      badSecurityNumber: 'رقم بطاقة الهوية غير صحيح',
1972      badUKVatAnswer: 'رقم UK VAT غير صحيح',
1973      badUKNin: 'غير صحيح UK NINرقم ',
1974      badUKUtr: 'غير صحيح UK UTR رقم',
1975      badStrength: 'كلمة المرور غير قوية',
1976      badNumberOfSelectedOptionsStart: 'يجب اختيار على الأقل ',
1977      badNumberOfSelectedOptionsEnd: ' أجوبة',
1978      badAlphaNumeric: 'القيمة المدخلة يجب أن تتضمن حروف وأرقام فقط ',
1979      badAlphaNumericExtra: ' و ',
1980      wrongFileSize: 'الملف المراد تحميله كبير جداً (الحد المسموج %s)',
1981      wrongFileType: 'ملفات من نوع %s فقط مسموحة',
1982      groupCheckedRangeStart: 'من فضلك اختر بين ',
1983      groupCheckedTooFewStart: 'من فضلك اختر على الأقل ',
1984      groupCheckedTooManyStart: 'من فضلك اختر بحد أقصى ',
1985      groupCheckedEnd: ' مرات',
1986      badCreditCard: 'رقم بطاقة ائتمانية خاطىء',
1987      badCVV: 'رمز الأمان خاطئ',
1988      wrongFileDim : 'حدود الصورة غير صالحة',
1989      imageTooTall : 'الصورة يمكن أن تكون أطول من',
1990      imageTooWide : 'الصورة يمكن أن تكون أعرض من',
1991      imageTooSmall : 'صورة صغيرة جداً',
1992      min : 'أدنى',
1993      max : 'أقصى',
1994      imageRatioNotAccepted : 'أبعاد صورة غير مقبولة',
1995      badBrazilTelephoneAnswer: 'رقم هاتف مدخل خاطىء',
1996      badBrazilCEPAnswer: 'قيمة CEP المدخلة غير صحيحة',
1997      badBrazilCPFAnswer: 'قيمة CPF المدخلة غير صحيحة',
1998      badPlPesel: 'قيمة Pl PESEL المدخلة غير صحيحة',
1999      badPlNip: 'قيمة Pl NIP المدخلة غير صحيحة',
2000      badPlRegon: 'قيمة Pl REGON المدخلة غير صحيحة',
2001      badreCaptcha: 'من فضلك أكد أنك لست روبوتاً',
2002      passwordComplexityStart: 'كملة المرور تتكون على الأقل من ',
2003      passwordComplexitySeparator: ', ',
2004      passwordComplexityUppercaseInfo: ' حروف كبيرة',
2005      passwordComplexityLowercaseInfo: ' حروف صغيرة',
2006      passwordComplexitySpecialCharsInfo: ' رموز خاصة',
2007      passwordComplexityNumericCharsInfo: ' أرقام',
2008      passwordComplexityEnd: '.'
2009    }
2010  });
2011
2012})(jQuery, window);
2013
2014/**
2015 * File declaring all default validators.
2016 */
2017(function($) {
2018
2019  /*
2020   * Validate email
2021   */
2022  $.formUtils.addValidator({
2023    name: 'email',
2024    validatorFunction: function (email) {
2025
2026      var emailParts = email.toLowerCase().split('@'),
2027        localPart = emailParts[0],
2028        domain = emailParts[1];
2029
2030      if (localPart && domain) {
2031
2032        if( localPart.indexOf('"') === 0 ) {
2033          var len = localPart.length;
2034          localPart = localPart.replace(/\"/g, '');
2035          if( localPart.length !== (len-2) ) {
2036            return false; // It was not allowed to have more than two apostrophes
2037          }
2038        }
2039
2040        return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
2041          localPart.indexOf('.') !== 0 &&
2042          localPart.substring(localPart.length-1, localPart.length) !== '.' &&
2043          localPart.indexOf('..') === -1 &&
2044          !(/[^\w\+\.\-\#\-\_\~\!\$\&\'\(\)\*\+\,\;\=\:]/.test(localPart));
2045      }
2046
2047      return false;
2048    },
2049    errorMessage: '',
2050    errorMessageKey: 'badEmail'
2051  });
2052
2053  /*
2054   * Validate domain name
2055   */
2056  $.formUtils.addValidator({
2057    name: 'domain',
2058    validatorFunction: function (val) {
2059      return val.length > 0 &&
2060        val.length <= 253 && // Including sub domains
2061        !(/[^a-zA-Z0-9]/.test(val.slice(-2))) && !(/[^a-zA-Z0-9]/.test(val.substr(0, 1))) && !(/[^a-zA-Z0-9\.\-]/.test(val)) &&
2062        val.split('..').length === 1 &&
2063        val.split('.').length > 1;
2064    },
2065    errorMessage: '',
2066    errorMessageKey: 'badDomain'
2067  });
2068
2069  /*
2070   * Validate required
2071   */
2072  $.formUtils.addValidator({
2073    name: 'required',
2074    validatorFunction: function (val, $el, config, language, $form) {
2075      switch ($el.attr('type')) {
2076        case 'checkbox':
2077          return $el.is(':checked');
2078        case 'radio':
2079          return $form.find('input[name="' + $el.attr('name') + '"]').filter(':checked').length > 0;
2080        default:
2081          return $.trim(val) !== '';
2082      }
2083    },
2084    errorMessage: '',
2085    errorMessageKey: function(config) {
2086      if (config.errorMessagePosition === 'top' || typeof config.errorMessagePosition === 'function') {
2087        return 'requiredFields';
2088      }
2089      else {
2090        return 'requiredField';
2091      }
2092    }
2093  });
2094
2095  /*
2096   * Validate length range
2097   */
2098  $.formUtils.addValidator({
2099    name: 'length',
2100    validatorFunction: function (val, $el, conf, lang) {
2101      var lengthAllowed = $el.valAttr('length'),
2102        type = $el.attr('type');
2103
2104      if (lengthAllowed === undefined) {
2105        alert('Please add attribute "data-validation-length" to ' + $el[0].nodeName + ' named ' + $el.attr('name'));
2106        return true;
2107      }
2108
2109      // check if length is above min, below max or within range.
2110      var len = type === 'file' && $el.get(0).files !== undefined ? $el.get(0).files.length : val.length,
2111        lengthCheckResults = $.formUtils.numericRangeCheck(len, lengthAllowed),
2112        checkResult;
2113
2114      switch (lengthCheckResults[0]) {   // outside of allowed range
2115        case 'out':
2116          this.errorMessage = lang.lengthBadStart + lengthAllowed + lang.lengthBadEnd;
2117          checkResult = false;
2118          break;
2119        // too short
2120        case 'min':
2121          this.errorMessage = lang.lengthTooShortStart + lengthCheckResults[1] + lang.lengthBadEnd;
2122          checkResult = false;
2123          break;
2124        // too long
2125        case 'max':
2126          this.errorMessage = lang.lengthTooLongStart + lengthCheckResults[1] + lang.lengthBadEnd;
2127          checkResult = false;
2128          break;
2129        // ok
2130        default:
2131          checkResult = true;
2132      }
2133
2134      return checkResult;
2135    },
2136    errorMessage: '',
2137    errorMessageKey: ''
2138  });
2139
2140  /*
2141   * Validate url
2142   */
2143  $.formUtils.addValidator({
2144    name: 'url',
2145    validatorFunction: function (url) {
2146      // written by Scott Gonzalez: http://projects.scottsplayground.com/iri/
2147      // - Victor Jonsson added support for arrays in the url ?arg[]=sdfsdf
2148      // - General improvements made by Stéphane Moureau <https://github.com/TraderStf>
2149
2150      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;
2151      if (urlFilter.test(url)) {
2152        var domain = url.split('://')[1],
2153          domainSlashPos = domain.indexOf('/');
2154
2155        if (domainSlashPos > -1) {
2156          domain = domain.substr(0, domainSlashPos);
2157        }
2158
2159        return $.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add support for IP-addresses
2160      }
2161      return false;
2162    },
2163    errorMessage: '',
2164    errorMessageKey: 'badUrl'
2165  });
2166
2167  /*
2168   * Validate number (floating or integer)
2169   */
2170  $.formUtils.addValidator({
2171    name: 'number',
2172    validatorFunction: function (val, $el, conf) {
2173      if (val !== '') {
2174        var allowing = $el.valAttr('allowing') || '',
2175          decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator,
2176          allowsRange = false,
2177          begin, end,
2178          steps = $el.valAttr('step') || '',
2179          allowsSteps = false,
2180          sanitize = $el.attr('data-sanitize') || '',
2181          isFormattedWithNumeral = sanitize.match(/(^|[\s])numberFormat([\s]|$)/i);
2182
2183        if (isFormattedWithNumeral) {
2184          if (!window.numeral) {
2185            throw new ReferenceError('The data-sanitize value numberFormat cannot be used without the numeral' +
2186              ' library. Please see Data Validation in http://www.formvalidator.net for more information.');
2187          }
2188          //Unformat input first, then convert back to String
2189          if (val.length) {
2190            val = String(numeral().unformat(val));
2191          }
2192        }
2193
2194        if (allowing.indexOf('number') === -1) {
2195          allowing += ',number';
2196        }
2197
2198        if (allowing.indexOf('negative') === -1 && val.indexOf('-') === 0) {
2199          return false;
2200        }
2201
2202        if (allowing.indexOf('range') > -1) {
2203          begin = parseFloat(allowing.substring(allowing.indexOf('[') + 1, allowing.indexOf(';')));
2204          end = parseFloat(allowing.substring(allowing.indexOf(';') + 1, allowing.indexOf(']')));
2205          allowsRange = true;
2206        }
2207
2208        if (steps !== '') {
2209          allowsSteps = true;
2210        }
2211
2212        if (decimalSeparator === ',') {
2213          if (val.indexOf('.') > -1) {
2214            return false;
2215          }
2216          // Fix for checking range with floats using ,
2217          val = val.replace(',', '.');
2218        }
2219        if (val.replace(/[0-9-]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) {
2220          return true;
2221        }
2222
2223        if (allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9-]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) {
2224          return true;
2225        }
2226      }
2227      return false;
2228    },
2229    errorMessage: '',
2230    errorMessageKey: 'badInt'
2231  });
2232
2233  /*
2234   * Validate alpha numeric
2235   */
2236  $.formUtils.addValidator({
2237    name: 'alphanumeric',
2238    validatorFunction: function (val, $el, conf, language) {
2239      var patternStart = '^([a-zA-Z0-9',
2240        patternEnd = ']+)$',
2241        additionalChars = $el.valAttr('allowing'),
2242        pattern = '',
2243        hasSpaces = false;
2244
2245      if (additionalChars) {
2246        pattern = patternStart + additionalChars + patternEnd;
2247        var extra = additionalChars.replace(/\\/g, '');
2248        if (extra.indexOf(' ') > -1) {
2249          hasSpaces = true;
2250          extra = extra.replace(' ', '');
2251          extra += language.andSpaces || $.formUtils.LANG.andSpaces;
2252        }
2253
2254        if(language.badAlphaNumericAndExtraAndSpaces && language.badAlphaNumericAndExtra) {
2255          if(hasSpaces) {
2256            this.errorMessage = language.badAlphaNumericAndExtraAndSpaces + extra;
2257          } else {
2258            this.errorMessage = language.badAlphaNumericAndExtra + extra + language.badAlphaNumericExtra;
2259          }
2260        } else {
2261          this.errorMessage = language.badAlphaNumeric + language.badAlphaNumericExtra + extra;
2262        }
2263      } else {
2264        pattern = patternStart + patternEnd;
2265        this.errorMessage = language.badAlphaNumeric;
2266      }
2267
2268      return new RegExp(pattern).test(val);
2269    },
2270    errorMessage: '',
2271    errorMessageKey: ''
2272  });
2273
2274  /*
2275   * Validate against regexp
2276   */
2277  $.formUtils.addValidator({
2278    name: 'custom',
2279    validatorFunction: function (val, $el) {
2280      var regexp = new RegExp($el.valAttr('regexp'));
2281      return regexp.test(val);
2282    },
2283    errorMessage: '',
2284    errorMessageKey: 'badCustomVal'
2285  });
2286
2287  /*
2288   * Validate date
2289   */
2290  $.formUtils.addValidator({
2291    name: 'date',
2292    validatorFunction: function (date, $el, conf) {
2293      var dateFormat = $el.valAttr('format') || conf.dateFormat || 'yyyy-mm-dd',
2294        addMissingLeadingZeros = $el.valAttr('require-leading-zero') === 'false';
2295      return $.formUtils.parseDate(date, dateFormat, addMissingLeadingZeros) !== false;
2296    },
2297    errorMessage: '',
2298    errorMessageKey: 'badDate'
2299  });
2300
2301
2302  /*
2303   * Validate group of checkboxes, validate qty required is checked
2304   * written by Steve Wasiura : http://stevewasiura.waztech.com
2305   * element attrs
2306   *    data-validation="checkbox_group"
2307   *    data-validation-qty="1-2"  // min 1 max 2
2308   *    data-validation-error-msg="chose min 1, max of 2 checkboxes"
2309   */
2310  $.formUtils.addValidator({
2311    name: 'checkbox_group',
2312    validatorFunction: function (val, $el, conf, lang, $form) {
2313      // preset return var
2314      var isValid = true,
2315      // get name of element. since it is a checkbox group, all checkboxes will have same name
2316        elname = $el.attr('name'),
2317      // get checkboxes and count the checked ones
2318        $checkBoxes = $('input[type=checkbox][name^="' + elname + '"]', $form),
2319        checkedCount = $checkBoxes.filter(':checked').length,
2320      // get el attr that specs qty required / allowed
2321        qtyAllowed = $el.valAttr('qty');
2322
2323      if (qtyAllowed === undefined) {
2324        var elementType = $el.get(0).nodeName;
2325        alert('Attribute "data-validation-qty" is missing from ' + elementType + ' named ' + $el.attr('name'));
2326      }
2327
2328      // call Utility function to check if count is above min, below max, within range etc.
2329      var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed);
2330
2331      // results will be array, [0]=result str, [1]=qty int
2332      switch (qtyCheckResults[0]) {
2333        // outside allowed range
2334        case 'out':
2335          this.errorMessage = lang.groupCheckedRangeStart + qtyAllowed + lang.groupCheckedEnd;
2336          isValid = false;
2337          break;
2338        // below min qty
2339        case 'min':
2340          this.errorMessage = lang.groupCheckedTooFewStart + qtyCheckResults[1] + (lang.groupCheckedTooFewEnd || lang.groupCheckedEnd);
2341          isValid = false;
2342          break;
2343        // above max qty
2344        case 'max':
2345          this.errorMessage = lang.groupCheckedTooManyStart + qtyCheckResults[1] + (lang.groupCheckedTooManyEnd || lang.groupCheckedEnd);
2346          isValid = false;
2347          break;
2348        // ok
2349        default:
2350          isValid = true;
2351      }
2352
2353      if( !isValid ) {
2354        var _triggerOnBlur = function() {
2355          $checkBoxes.unbind('click', _triggerOnBlur);
2356          $checkBoxes.filter('*[data-validation]').validateInputOnBlur(lang, conf, false, 'blur');
2357        };
2358        $checkBoxes.bind('click', _triggerOnBlur);
2359      }
2360
2361      return isValid;
2362    }
2363    //   errorMessage : '', // set above in switch statement
2364    //   errorMessageKey: '' // not used
2365  });
2366
2367})(jQuery);
2368
2369
2370}));

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.