PageSourceSearch

https://fida.org.ng/wp-content/plugins/js-support-ticket/includes/…jquery.form-validator.js?ver=317.1789456333

js fida.org.ng collected 2026-10-02 05:50:24 UTC 72,541 bytes, 1,669 lines download raw bytes

1(function ($) {
2    'use strict';
3    var $window = $(window),
4            _applyErrorStyle = function ($elem, conf) {
5                var $parent = $elem.parent();
6                $elem
7                        .addClass(conf.errorElementClass)
8                        .removeClass('valid');
9                if ($parent.hasClass("input-group"))
10                    $parent = $parent.parent();
11
12                $parent.addClass('has-error').removeClass('has-success'); //twitter bs
13
14
15                if (conf.borderColorOnError !== '') {
16                    $elem.css('border-color', conf.borderColorOnError);
17                }
18            },
19            _removeErrorStyle = function ($elem, conf) {
20                $elem.each(function () {
21                    _setInlineErrorMessage($(this), '', conf, conf.errorMessagePosition);
22                    var $parent = $(this).parent();
23
24                    if ($parent.hasClass("input-group"))
25                        $parent = $parent.parent();
26                    $(this)
27                            .removeClass('valid')
28                            .removeClass(conf.errorElementClass)
29                            .css('border-color', '');
30                    $parent
31                            .removeClass('has-error')
32                            .removeClass('has-success')
33                            .find('.' + conf.errorMessageClass) // remove inline error message
34                            .remove();
35                });
36            },
37            _setInlineErrorMessage = function ($input, mess, conf, $messageContainer) {
38                var custom = _getInlineErrorElement($input);
39                var $parent = $input.parent();
40                if ($parent.hasClass("input-group"))
41                    $parent = $parent.parent();
42                if (custom) {
43                    custom.innerHTML = mess;
44                }
45                else if (typeof $messageContainer == 'object') {
46                    var $found = false;
47                    $messageContainer.find('.' + conf.errorMessageClass).each(function () {
48                        if (this.inputReferer == $input[0]) {
49                            $found = $(this);
50                            return false;
51                        }
52                    });
53                    if ($found) {
54                        if (!mess) {
55                            $found.remove();
56                        } else {
57                            $found.html(mess);
58                        }
59                    } else {
60                        var $mess = $('<div class="' + conf.errorMessageClass + '">' + mess + '</div>');
61                        $mess[0].inputReferer = $input[0];
62                        $messageContainer.prepend($mess);
63                    }
64                }
65                else {
66                    var $mess = $parent.find('.' + conf.errorMessageClass + '.jsst-help-block');
67                    if ($mess.length == 0) {
68                        $mess = $('<span></span>').addClass('jsst-help-block').addClass(conf.errorMessageClass);
69                        $mess.appendTo($parent);
70                    }
71                    $mess.html(mess);
72                }
73            },
74            _getInlineErrorElement = function ($input, conf) {
75                return document.getElementById($input.attr('name') + '_err_msg');
76            },
77            _templateMessage = function ($form, title, errorMessages, conf) {
78                var messages = conf.errorMessageTemplate.messages.replace(/\{errorTitle\}/g, title);
79                var fields = [];
80                $.each(errorMessages, function (i, msg) {
81                    fields.push(conf.errorMessageTemplate.field.replace(/\{msg\}/g, msg));
82                });
83                messages = messages.replace(/\{fields\}/g, fields.join(''));
84                var container = conf.errorMessageTemplate.container.replace(/\{errorMessageClass\}/g, conf.errorMessageClass);
85                container = container.replace(/\{messages\}/g, messages);
86                $form.children().eq(0).before(container);
87            };
88
89    /**
90     * Assigns validateInputOnBlur function to elements blur event
91     *
92     * @param {Object} language Optional, will override $.formUtils.LANG
93     * @param {Object} settings Optional, will override the default settings
94     * @return {jQuery}
95     */
96    $.fn.validateOnBlur = function (language, settings) {
97        this.find('input[data-validation],textarea[data-validation],select[data-validation]')
98                .bind('blur.validation', function () {
99                    $(this).validateInputOnBlur(language, settings, true, 'blur');
100                });
101
102        return this;
103    };
104
105    /*
106     * Assigns validateInputOnBlur function to elements custom event
107     * @param {Object} language Optional, will override $.formUtils.LANG
108     * @param {Object} settings Optional, will override the default settings
109     * * @return {jQuery}	
110     */
111    $.fn.validateOnEvent = function (language, settings) {
112        this.find('input[data-validation][data-validation-event],textarea[data-validation][data-validation-event],select[data-validation][data-validation-event]')
113                .each(function () {
114                    var $el = $(this),
115                            etype = $el.attr("data-validation-event");
116                    if (etype) {
117                        $el.bind(etype + ".validation", function () {
118                            $(this).validateInputOnBlur(language, settings, true, etype);
119                        });
120                    }
121                });
122        return this;
123    };
124
125    /**
126     * fade in help message when input gains focus
127     * fade out when input loses focus
128     * <input data-help="The info that I want to display for the user when input is focused" ... />
129     *
130     * @param {String} attrName - Optional, default is data-help
131     * @return {jQuery}
132     */
133    $.fn.showHelpOnFocus = function (attrName) {
134        if (!attrName) {
135            attrName = 'data-validation-help';
136        }
137
138        // Remove previously added event listeners
139        this.find('.has-help-txt')
140                .valAttr('has-keyup-event', false)
141                .removeClass('has-help-txt');
142
143        // Add help text listeners
144        this.find('textarea,input').each(function () {
145            var $elem = $(this),
146                    className = 'jquery_form_help_' + ($elem.attr('name') || '').replace(/(:|\.|\[|\])/g, ""),
147                    help = $elem.attr(attrName);
148
149            if (help) {
150                $elem
151                        .addClass('has-help-txt')
152                        .unbind('focus.help')
153                        .bind('focus.help', function () {
154                            var $help = $elem.parent().find('.' + className);
155                            if ($help.length == 0) {
156                                $help = $('<span />')
157                                        .addClass(className)
158                                        .addClass('help')
159                                        .addClass('jsst-help-block') // twitter bs
160                                        .text(help)
161                                        .hide();
162
163                                $elem.after($help);
164
165                            }
166                            $help.fadeIn();
167                        })
168                        .unbind('blur.help')
169                        .bind('blur.help', function () {
170                            $(this)
171                                    .parent()
172                                    .find('.' + className)
173                                    .fadeOut('slow');
174                        });
175            }
176        });
177
178        return this;
179    };
180
181    /**
182     * Validate single input when it loses focus
183     * shows error message in a span element 
184     * that is appended to the parent element
185     *
186     * @param {Object} [language] Optional, will override $.formUtils.LANG
187     * @param {Object} [conf] Optional, will override the default settings
188     * @param {Boolean} attachKeyupEvent Optional
189     * @param {String} eventType
190     * @return {jQuery}
191     */
192    $.fn.validateInputOnBlur = function (language, conf, attachKeyupEvent, eventType) {
193        $.formUtils.eventType = eventType;
194
195        if ((this.valAttr('suggestion-nr') || this.valAttr('postpone') || this.hasClass('hasDatepicker')) && !window.postponedValidation) {
196            // This validation has to be postponed
197            var _self = this,
198                    postponeTime = this.valAttr('postpone') || 200;
199
200            window.postponedValidation = function () {
201                _self.validateInputOnBlur(language, conf, attachKeyupEvent, eventType);
202                window.postponedValidation = false;
203            };
204            setTimeout(function () {
205                if (window.postponedValidation) {
206                    window.postponedValidation();
207                }
208            }, postponeTime);
209
210            return this;
211        }
212
213        language = $.extend({}, $.formUtils.LANG, language || {});
214        _removeErrorStyle(this, conf);
215        var $elem = this,
216                $form = $elem.closest("form"),
217                validationRule = $elem.attr(conf.validationRuleAttribute),
218                validation = $.formUtils.validateInput(
219                        $elem,
220                        language,
221                        $.extend({}, conf, {errorMessagePosition: 'element'}),
222                        $form,
223                        eventType
224                        );
225
226        if (validation === true) {
227            $elem
228                    .addClass('valid')
229                    .parent()
230                    .addClass('has-success'); // twitter bs
231        } else if (validation !== null) {
232
233            _applyErrorStyle($elem, conf);
234            _setInlineErrorMessage($elem, validation, conf, conf.errorMessagePosition);
235
236            if (attachKeyupEvent) {
237                $elem
238                        .unbind('keyup.validation')
239                        .bind('keyup.validation', function () {
240                            $(this).validateInputOnBlur(language, conf, false, 'keyup');
241                        });
242            }
243        }
244
245        return this;
246    };
247
248    /**
249     * Short hand for fetching/adding/removing element attributes
250     * prefixed with 'data-validation-'
251     *
252     * @param {String} name
253     * @param {String|Boolean} [val]
254     * @return string|undefined
255     * @protected
256     */
257    $.fn.valAttr = function (name, val) {
258        if (val === undefined) {
259            return this.attr('data-validation-' + name);
260        } else if (val === false || val === null) {
261            return this.removeAttr('data-validation-' + name);
262        } else {
263            if (name.length > 0)
264                name = '-' + name;
265            return this.attr('data-validation' + name, val);
266        }
267    };
268
269    /**
270     * Function that validate all inputs in given element
271     *
272     * @param {Object} [language]
273     * @param {Object} [conf]
274     * @param {Boolean} [displayError] Defaults to true
275     */
276    $.fn.isValid = function (language, conf, displayError) {
277
278        if ($.formUtils.isLoadingModules) {
279            var $self = this;
280            setTimeout(function () {
281                $self.isValid(language, conf, displayError);
282            }, 200);
283            return null;
284        }
285
286        conf = $.extend({}, $.formUtils.defaultConfig(), conf || {});
287        language = $.extend({}, $.formUtils.LANG, language || {});
288        displayError = displayError !== false;
289
290        $.formUtils.isValidatingEntireForm = true;
291        $.formUtils.haltValidation = false;
292
293        /**
294         * Adds message to error message stack if not already in the message stack
295         *
296         * @param {String} mess
297         * @para {jQuery} $elem
298         */
299        var addErrorMessage = function (mess, $elem) {
300            // validate server side will return null as error message before the server is requested
301            if (mess !== null) {
302                if ($.inArray(mess, errorMessages) < 0) {
303                    errorMessages.push(mess);
304                }
305                errorInputs.push($elem);
306                $elem.attr('current-error', mess);
307                if (displayError)
308                    _applyErrorStyle($elem, conf);
309            }
310        },
311                /** Error messages for this validation */
312                errorMessages = [],
313                /** Input elements which value was not valid */
314                errorInputs = [],
315                /** Form instance */
316                $form = this,
317                /**
318                 * Tells whether or not to validate element with this name and of this type
319                 *
320                 * @param {String} name
321                 * @param {String} type
322                 * @return {Boolean}
323                 */
324                ignoreInput = function (name, type) {
325                    if (type === 'submit' || type === 'button' || type == 'reset') {
326                        return true;
327                    }
328                    return $.inArray(name, conf.ignore || []) > -1;
329                };
330
331        // Reset style and remove error class
332        if (displayError) {
333            $form.find('.' + conf.errorMessageClass + '.alert').remove();
334            _removeErrorStyle($form.find('.' + conf.errorElementClass + ',.valid'), conf);
335        }
336
337        // Validate element values
338        $form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function () {
339            var $elem = $(this);
340            var elementType = $elem.attr('type');
341            if (!ignoreInput($elem.attr('name'), elementType)) {
342
343                var validation = $.formUtils.validateInput(
344                        $elem,
345                        language,
346                        conf,
347                        $form,
348                        'submit'
349                        );
350
351                // Run element validation callback
352                if (typeof conf.onElementValidate == 'function') {
353                    conf.onElementValidate((validation === true), $elem, $form, validation);
354                }
355
356                if (validation !== true) {
357                    addErrorMessage(validation, $elem);
358                } else {
359                    $elem
360                            .valAttr('current-error', false)
361                            .addClass('valid')
362                            .parent()
363                            .addClass('has-success');
364                }
365            }
366
367        });
368
369        // Run validation callback
370        if (typeof conf.onValidate == 'function') {
371            var errors = conf.onValidate($form);
372            if ($.isArray(errors)) {
373                $.each(errors, function (i, err) {
374                    addErrorMessage(err.message, err.element);
375                });
376            }
377            else if (errors && errors.element && errors.message) {
378                addErrorMessage(errors.message, errors.element);
379            }
380        }
381
382        // Reset form validation flag
383        $.formUtils.isValidatingEntireForm = false;
384
385        // Validation failed
386        if (!$.formUtils.haltValidation && errorInputs.length > 0) {
387
388            if (displayError) {
389                // display all error messages in top of form
390                if (conf.errorMessagePosition === 'top') {
391                    _templateMessage($form, language.errorTitle, errorMessages, conf);
392                }
393                // Customize display message
394                else if (conf.errorMessagePosition === 'custom') {
395                    if (typeof conf.errorMessageCustom === 'function') {
396                        conf.errorMessageCustom($form, language.errorTitle, errorMessages, conf);
397                    }
398                }
399                // Display error message below input field or in defined container
400                else {
401                    $.each(errorInputs, function (i, $input) {
402                        _setInlineErrorMessage($input, $input.attr('current-error'), conf, conf.errorMessagePosition);
403                    });
404                }
405
406                if (conf.scrollToTopOnError) {
407                    $window.scrollTop($form.offset().top - 20);
408                }
409            }
410
411            return false;
412        }
413
414        return !$.formUtils.haltValidation;
415    };
416
417    /**
418     * @deprecated
419     * @param language
420     * @param conf
421     */
422    $.fn.validateForm = function (language, conf) {
423        if (window.console && typeof window.console.warn == 'function') {
424            window.console.warn('Use of deprecated function $.validateForm, use $.isValid instead');
425        }
426        return this.isValid(language, conf, true);
427    }
428
429    /**
430     * Plugin for displaying input length restriction
431     */
432    $.fn.restrictLength = function (maxLengthElement) {
433        new $.formUtils.lengthRestriction(this, maxLengthElement);
434        return this;
435    };
436
437    /**
438     * Add suggestion dropdown to inputs having data-suggestions with a comma
439     * separated string with suggestions
440     * @param {Array} [settings]
441     * @returns {jQuery}
442     */
443    $.fn.addSuggestions = function (settings) {
444        var sugs = false;
445        this.find('input').each(function () {
446            var $field = $(this);
447
448            sugs = $.split($field.attr('data-suggestions'));
449
450            if (sugs.length > 0 && !$field.hasClass('has-suggestions')) {
451                $.formUtils.suggest($field, sugs, settings);
452                $field.addClass('has-suggestions');
453            }
454        });
455        return this;
456    };
457
458    /**
459     * A bit smarter split function
460     * @param {String} val
461     * @param {Function|String} [func]
462     * @param {String} [delim]
463     * @returns {Array|void}
464     */
465    $.split = function (val, func, delim) {
466        if (typeof func != 'function') {
467            // return string
468            if (!val)
469                return [];
470            var values = [];
471            $.each(val.split(func ? func : ','), function (i, str) {
472                str = $.trim(str);
473                if (str.length)
474                    values.push(str);
475            });
476            return values;
477        } else if (val) {
478            // use callback on each
479            if (!delim)
480                delim = ',';
481            $.each(val.split(delim), function (i, str) {
482                str = $.trim(str);
483                if (str.length)
484                    return func(str, i);
485            });
486        }
487    };
488
489    /**
490     * Short hand function that makes the validation setup require less code
491     * @param conf
492     */
493    $.validate = function (conf) {
494
495        var defaultConf = $.extend($.formUtils.defaultConfig(), {
496            form: 'form',
497            /*
498             * Enable custom event for validation
499             */
500            validateOnEvent: true,
501            validateOnBlur: true,
502            showHelpOnFocus: true,
503            addSuggestions: true,
504            modules: '',
505            onModulesLoaded: null,
506            language: false,
507            onSuccess: false,
508            onError: false,
509            onElementValidate: false
510        });
511
512        conf = $.extend(defaultConf, conf || {});
513
514        // Add validation to forms
515        $(conf.form).each(function (i, form) {
516
517            var $form = $(form);
518            $window.trigger('formValidationSetup', [$form]);
519
520            // Remove all event listeners previously added
521            $form.find('.has-help-txt')
522                    .unbind('focus.validation')
523                    .unbind('blur.validation');
524            $form
525                    .removeClass('has-validation-callback')
526                    .unbind('submit.validation')
527                    .unbind('reset.validation')
528                    .find('input[data-validation],textarea[data-validation]')
529                    .unbind('blur.validation');
530
531            // Validate when submitted
532            $form.bind('submit.validation', function () {
533                var $form = $(this);
534
535                if ($.formUtils.isLoadingModules) {
536                    setTimeout(function () {
537                        $form.trigger('submit.validation');
538                    }, 200);
539                    return false;
540                }
541                var valid = $form.isValid(conf.language, conf);
542                if (valid && typeof conf.onSuccess == 'function') {
543                    var callbackResponse = conf.onSuccess($form);
544                    if (callbackResponse === false)
545                        return false;
546                } else if (!valid && typeof conf.onError == 'function') {
547                    conf.onError($form);
548                    return false;
549                } else {
550                    return valid;
551                }
552            })
553                    .bind('reset.validation', function () {
554                        // remove messages
555                        $(this).find('.' + conf.errorMessageClass + '.alert').remove();
556                        _removeErrorStyle($(this).find('.' + conf.errorElementClass + ',.valid'), conf);
557                    })
558                    .addClass('has-validation-callback');
559
560            if (conf.showHelpOnFocus) {
561                $form.showHelpOnFocus();
562            }
563            if (conf.addSuggestions) {
564                $form.addSuggestions();
565            }
566            if (conf.validateOnBlur) {
567                $form.validateOnBlur(conf.language, conf);
568                $form.bind('html5ValidationAttrsFound', function () {
569                    $form.validateOnBlur(conf.language, conf);
570                })
571            }
572            if (conf.validateOnEvent) {
573                $form.validateOnEvent(conf.language, conf);
574            }
575
576        });
577
578        if (conf.modules != '') {
579            if (typeof conf.onModulesLoaded == 'function') {
580                $window.one('validatorsLoaded', conf.onModulesLoaded);
581            }
582            $.formUtils.loadModules(conf.modules);
583        }
584    };
585
586    /**
587     * Object containing utility methods for this plugin
588     */
589    $.formUtils = {
590        /**
591         * Default config for $(...).isValid();
592         */
593        defaultConfig: function () {
594            return {
595                ignore: [], // Names of inputs not to be validated even though node attribute containing the validation rules tells us to
596                errorElementClass: 'error', // Class that will be put on elements which value is invalid
597                borderColorOnError: 'red', // Border color of elements which value is invalid, empty string to not change border color
598                errorMessageClass: 'form-error', // class name of div containing error messages when validation fails
599                validationRuleAttribute: 'data-validation', // name of the attribute holding the validation rules
600                validationErrorMsgAttribute: 'data-validation-error-msg', // define custom err msg inline with element
601                errorMessagePosition: 'element', // Can be either "top" or "element" or "custom"
602                errorMessageTemplate: {
603                    container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>',
604                    messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
605                    field: '<li>{msg}</li>'
606                },
607                errorMessageCustom: _templateMessage,
608                scrollToTopOnError: true,
609                dateFormat: 'yyyy-mm-dd',
610                addValidClassOnAll: false, // whether or not to apply class="valid" even if the input wasn't validated
611                decimalSeparator: '.'
612            }
613        },
614        /**
615         * Available validators
616         */
617        validators: {},
618        /**
619         * Events triggered by form validator
620         */
621        _events: {load: [], valid: [], invalid: []},
622        /**
623         * Setting this property to true during validation will
624         * stop further validation from taking place and form will
625         * not be sent
626         */
627        haltValidation: false,
628        /**
629         * This variable will be true $.fn.isValid() is called
630         * and false when $.fn.validateOnBlur is called
631         */
632        isValidatingEntireForm: false,
633        /**
634         * Function for adding a validator
635         * @param {Object} validator
636         */
637        addValidator: function (validator) {
638            // prefix with "validate_" for backward compatibility reasons
639            var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_' + validator.name;
640            if (validator.validateOnKeyUp === undefined)
641                validator.validateOnKeyUp = true;
642            this.validators[name] = validator;
643        },
644        /**
645         * @var {Boolean}
646         */
647        isLoadingModules: false,
648        /**
649         * @var {Object}
650         */
651        loadedModules: {},
652        /**
653         * @example
654         *  $.formUtils.loadModules('date, security.dev');
655         *
656         * Will load the scripts date.js and security.dev.js from the
657         * directory where this script resides. If you want to load
658         * the modules from another directory you can use the
659         * path argument.
660         *
661         * The script will be cached by the browser unless the module
662         * name ends with .dev
663         *
664         * @param {String} modules - Comma separated string with module file names (no directory nor file extension)
665         * @param {String} [path] - Optional, path where the module files is located if their not in the same directory as the core modules
666         * @param {Boolean} [fireEvent] - Optional, whether or not to fire event 'load' when modules finished loading
667         */
668        loadModules: function (modules, path, fireEvent) {
669
670            if (fireEvent === undefined)
671                fireEvent = true;
672
673            if ($.formUtils.isLoadingModules) {
674                setTimeout(function () {
675                    $.formUtils.loadModules(modules, path, fireEvent);
676                });
677                return;
678            }
679
680            var hasLoadedAnyModule = false,
681                    loadModuleScripts = function (modules, path) {
682
683                        var moduleList = $.split(modules),
684                                numModules = moduleList.length,
685                                moduleLoadedCallback = function () {
686                                    numModules--;
687                                    if (numModules == 0) {
688                                        $.formUtils.isLoadingModules = false;
689                                        if (fireEvent && hasLoadedAnyModule) {
690                                            $window.trigger('validatorsLoaded');
691                                        }
692                                    }
693                                };
694
695                        if (numModules > 0) {
696                            $.formUtils.isLoadingModules = true;
697                        }
698
699                        var cacheSuffix = '?__=' + (new Date().getTime()),
700                                appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0];
701
702                        $.each(moduleList, function (i, modName) {
703                            modName = $.trim(modName);
704                            if (modName.length == 0) {
705                                moduleLoadedCallback();
706                            }
707                            else {
708                                var scriptUrl = path + modName + (modName.substr(-3) == '.js' ? '' : '.js'),
709                                        script = document.createElement('SCRIPT');
710
711                                if (scriptUrl in $.formUtils.loadedModules) {
712                                    // already loaded
713                                    moduleLoadedCallback();
714                                }
715                                else {
716
717                                    // Remember that this script is loaded
718                                    $.formUtils.loadedModules[scriptUrl] = 1;
719                                    hasLoadedAnyModule = true;
720
721                                    // Load the script
722                                    script.type = 'text/javascript';
723                                    script.onload = moduleLoadedCallback;
724                                    script.src = scriptUrl + (scriptUrl.substr(-7) == '.dev.js' ? cacheSuffix : '');
725                                    script.onreadystatechange = function () {
726                                        // IE 7 fix
727                                        if (this.readyState == 'complete' || this.readyState == 'loaded') {
728                                            moduleLoadedCallback();
729                                            // Handle memory leak in IE
730                                            this.onload = null;
731                                            this.onreadystatechange = null;
732                                        }
733                                    };
734                                    appendToElement.appendChild(script);
735                                }
736                            }
737                        });
738                    };
739
740            if (path) {
741                loadModuleScripts(modules, path);
742            } else {
743                var findScriptPathAndLoadModules = function () {
744                    var foundPath = false;
745                    $('script').each(function () {
746                        if (this.src) {
747                            var scriptName = this.src.substr(this.src.lastIndexOf('/') + 1, this.src.length);
748                            if (scriptName.indexOf('jquery.form-validator.js') > -1 || scriptName.indexOf('jquery.form-validator.min.js') > -1) {
749                                foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
750                                if (foundPath == '/')
751                                    foundPath = '';
752                                return false;
753                            }
754                        }
755                    });
756
757                    if (foundPath !== false) {
758                        loadModuleScripts(modules, foundPath);
759                        return true;
760                    }
761                    return false;
762                };
763
764                if (!findScriptPathAndLoadModules()) {
765                    $(findScriptPathAndLoadModules);
766                }
767            }
768        },
769        /**
770         * Validate the value of given element according to the validation rules
771         * found in the attribute data-validation. Will return null if no validation
772         * should take place, returns true if valid or error message if not valid
773         *
774         * @param {jQuery} $elem
775         * @param {Object} language ($.formUtils.LANG)
776         * @param {Object} conf
777         * @param {jQuery} $form
778         * @param {String} [eventContext]
779         * @return {String|Boolean}
780         */
781        validateInput: function ($elem, language, conf, $form, eventContext) {
782
783            if ($elem.attr('disabled'))
784                return null; // returning null will prevent that the valid class gets applied to the element
785
786            $elem.trigger('beforeValidation');
787
788            var value = $elem.val() || '',
789                    optional = $elem.valAttr('optional'),
790                    // test if a checkbox forces this element to be validated
791                    validationDependsOnCheckedInput = false,
792                    validationDependentInputIsChecked = false,
793                    validateIfCheckedElement = false,
794                    // get value of this element's attribute "... if-checked"
795                    validateIfCheckedElementName = $elem.valAttr("if-checked");
796
797            // make sure we can proceed
798            if (validateIfCheckedElementName != null) {
799
800                // Set the boolean telling us that the validation depends
801                // on another input being checked
802                validationDependsOnCheckedInput = true;
803
804                // select the checkbox type element in this form
805                validateIfCheckedElement = $form.find('input[name="' + validateIfCheckedElementName + '"]');
806
807                // test if it's property "checked" is checked
808                if (validateIfCheckedElement.prop('checked')) {
809                    // set value for validation checkpoint
810                    validationDependentInputIsChecked = true;
811                }
812            }
813
814            // validation checkpoint
815            // if empty AND optional attribute is present
816            // OR depending on a checkbox being checked AND checkbox is checked, return true
817            if ((!value && optional === 'true') || (validationDependsOnCheckedInput && !validationDependentInputIsChecked)) {
818                return conf.addValidClassOnAll ? true : null;
819            }
820
821            var validationRules = $elem.attr(conf.validationRuleAttribute),
822                    // see if form element has inline err msg attribute
823                    validationErrorMsg = true;
824
825            if (!validationRules) {
826                return conf.addValidClassOnAll ? true : null;
827            }
828
829            $.split(validationRules, function (rule) {
830                if (rule.indexOf('validate_') !== 0) {
831                    rule = 'validate_' + rule;
832                }
833
834                var validator = $.formUtils.validators[rule];
835
836                if (validator && typeof validator['validatorFunction'] == 'function') {
837                    // special change of element for checkbox_group rule
838                    if (rule == 'validate_checkbox_group') {
839                        // set element to first in group, so error msg is set only once
840                        $elem = $("[name='" + $elem.attr('name') + "']:eq(0)");
841                    }
842
843                    var isValid = null;
844                    if (eventContext != 'keyup' || validator.validateOnKeyUp) {
845                        isValid = validator.validatorFunction(value, $elem, conf, language, $form);
846                    }
847
848                    if (!isValid) {
849                        validationErrorMsg = null;
850                        if (isValid !== null) {
851                            validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute + '-' + rule.replace('validate_', ''));
852                            if (!validationErrorMsg) {
853                                validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
854                                if (!validationErrorMsg) {
855                                    validationErrorMsg = language[validator.errorMessageKey];
856                                    if (!validationErrorMsg)
857                                        validationErrorMsg = validator.errorMessage;
858                                }
859                            }
860                        }
861                        return false; // breaks the iteration
862                    }
863
864                } else {
865                    throw new Error('Using undefined validator "' + rule + '"');
866                }
867
868            }, ' ');
869
870            if (typeof validationErrorMsg == 'string') {
871                $elem.trigger('validation', false);
872                return validationErrorMsg;
873            } else if (validationErrorMsg === null && !conf.addValidClassOnAll) {
874                return null;
875            } else {
876                $elem.trigger('validation', true);
877                return true;
878            }
879        },
880        /**
881         * Is it a correct date according to given dateFormat. Will return false if not, otherwise
882         * an array 0=>year 1=>month 2=>day
883         *
884         * @param {String} val
885         * @param {String} dateFormat
886         * @return {Array}|{Boolean}
887         */
888        parseDate: function (val, dateFormat) {
889            var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0, 1),
890                    regexp = '^',
891                    formatParts = dateFormat.split(divider),
892                    matches, day, month, year;
893
894            $.each(formatParts, function (i, part) {
895                regexp += (i > 0 ? '\\' + divider : '') + '(\\d{' + part.length + '})';
896            });
897
898            regexp += '$';
899
900            matches = val.match(new RegExp(regexp));
901            if (matches === null) {
902                return false;
903            }
904
905            var findDateUnit = function (unit, formatParts, matches) {
906                for (var i = 0; i < formatParts.length; i++) {
907                    if (formatParts[i].substring(0, 1) === unit) {
908                        return $.formUtils.parseDateInt(matches[i + 1]);
909                    }
910                }
911                return -1;
912            };
913
914            month = findDateUnit('m', formatParts, matches);
915            day = findDateUnit('d', formatParts, matches);
916            year = findDateUnit('y', formatParts, matches);
917
918            if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0))
919                    || (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0))
920                    || month > 12 || month === 0) {
921                return false;
922            }
923            if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) {
924                return false;
925            }
926
927            return [year, month, day];
928        },
929        /**
930         * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt?
931         *
932         * @param {String} val
933         * @param {Number}
934         */
935        parseDateInt: function (val) {
936            if (val.indexOf('0') === 0) {
937                val = val.replace('0', '');
938            }
939            return parseInt(val, 10);
940        },
941        /**
942         * Has month only 30 days?
943         *
944         * @param {Number} m
945         * @return {Boolean}
946         */
947        isShortMonth: function (m) {
948            return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
949        },
950        /**
951         * Restrict input length
952         *
953         * @param {jQuery} $inputElement Jquery Html object
954         * @param {jQuery} $maxLengthElement jQuery Html Object
955         * @return void
956         */
957        lengthRestriction: function ($inputElement, $maxLengthElement) {
958            // read maxChars from counter display initial text value
959            var maxChars = parseInt($maxLengthElement.text(), 10),
960                    charsLeft = 0,
961                    // internal function does the counting and sets display value
962                    countCharacters = function () {
963                        var numChars = $inputElement.val().length;
964                        if (numChars > maxChars) {
965                            // get current scroll bar position
966                            var currScrollTopPos = $inputElement.scrollTop();
967                            // trim value to max length
968                            $inputElement.val($inputElement.val().substring(0, maxChars));
969                            $inputElement.scrollTop(currScrollTopPos);
970                        }
971                        charsLeft = maxChars - numChars;
972                        if (charsLeft < 0)
973                            charsLeft = 0;
974
975                        // set counter text
976                        $maxLengthElement.text(charsLeft);
977                    };
978
979            // bind events to this element
980            // setTimeout is needed, cut or paste fires before val is available
981            $($inputElement).bind('keydown keyup keypress focus blur', countCharacters)
982                    .bind('cut paste', function () {
983                        setTimeout(countCharacters, 100);
984                    });
985
986            // count chars on pageload, if there are prefilled input-values
987            $(document).bind("ready", countCharacters);
988        },
989        /**
990         * Test numeric against allowed range
991         *
992         * @param $value int
993         * @param $rangeAllowed str; (1-2, min1, max2)
994         * @return array 
995         */
996        numericRangeCheck: function (value, rangeAllowed)
997        {
998            // split by dash
999            var range = $.split(rangeAllowed, '-');
1000            // min or max
1001            var minmax = parseInt(rangeAllowed.substr(3), 10)
1002            // range ?
1003            if (range.length == 2 && (value < parseInt(range[0], 10) || value > parseInt(range[1], 10)))
1004            {
1005                return ["out", range[0], range[1]];
1006            } // value is out of range
1007            else if (rangeAllowed.indexOf('min') === 0 && (value < minmax)) // min
1008            {
1009                return ["min", minmax];
1010            } // value is below min
1011            else if (rangeAllowed.indexOf('max') === 0 && (value > minmax)) // max
1012            {
1013                return ["max", minmax];
1014            } // value is above max
1015            // since no other returns executed, value is in allowed range
1016            return ["ok"];
1017        },
1018        _numSuggestionElements: 0,
1019        _selectedSuggestion: null,
1020        _previousTypedVal: null,
1021        /**
1022         * Utility function that can be used to create plugins that gives
1023         * suggestions when inputs is typed into
1024         * @param {jQuery} $elem
1025         * @param {Array} suggestions
1026         * @param {Object} settings - Optional
1027         * @return {jQuery}
1028         */
1029        suggest: function ($elem, suggestions, settings) {
1030            var conf = {
1031                css: {
1032                    maxHeight: '150px',
1033                    background: '#FFF',
1034                    lineHeight: '150%',
1035                    textDecoration: 'underline',
1036                    overflowX: 'hidden',
1037                    overflowY: 'auto',
1038                    border: '#CCC solid 1px',
1039                    borderTop: 'none',
1040                    cursor: 'pointer'
1041                },
1042                activeSuggestionCSS: {
1043                    background: '#E9E9E9'
1044                }
1045            },
1046            setSuggsetionPosition = function ($suggestionContainer, $input) {
1047                var offset = $input.offset();
1048                $suggestionContainer.css({
1049                    width: $input.outerWidth(),
1050                    left: offset.left + 'px',
1051                    top: (offset.top + $input.outerHeight()) + 'px'
1052                });
1053            };
1054
1055            if (settings)
1056                $.extend(conf, settings);
1057
1058            conf.css['position'] = 'absolute';
1059            conf.css['z-index'] = 9999;
1060            $elem.attr('autocomplete', 'off');
1061
1062            if (this._numSuggestionElements === 0) {
1063                // Re-position suggestion container if window size changes
1064                $window.bind('resize', function () {
1065                    $('.jquery-form-suggestions').each(function () {
1066                        var $container = $(this),
1067                                suggestID = $container.attr('data-suggest-container');
1068                        setSuggsetionPosition($container, $('.suggestions-' + suggestID).eq(0));
1069                    });
1070                });
1071            }
1072
1073            this._numSuggestionElements++;
1074
1075            var onSelectSuggestion = function ($el) {
1076                var suggestionId = $el.valAttr('suggestion-nr');
1077                $.formUtils._selectedSuggestion = null;
1078                $.formUtils._previousTypedVal = null;
1079                $('.jquery-form-suggestion-' + suggestionId).fadeOut('fast');
1080            };
1081
1082            $elem
1083                    .data('suggestions', suggestions)
1084                    .valAttr('suggestion-nr', this._numSuggestionElements)
1085                    .unbind('focus.suggest')
1086                    .bind('focus.suggest', function () {
1087                        $(this).trigger('keyup');
1088                        $.formUtils._selectedSuggestion = null;
1089                    })
1090                    .unbind('keyup.suggest')
1091                    .bind('keyup.suggest', function () {
1092                        var $input = $(this),
1093                                foundSuggestions = [],
1094                                val = $.trim($input.val()).toLocaleLowerCase();
1095
1096                        if (val == $.formUtils._previousTypedVal) {
1097                            return;
1098                        }
1099                        else {
1100                            $.formUtils._previousTypedVal = val;
1101                        }
1102
1103                        var hasTypedSuggestion = false,
1104                                suggestionId = $input.valAttr('suggestion-nr'),
1105                                $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1106
1107                        $suggestionContainer.scrollTop(0);
1108
1109                        // Find the right suggestions
1110                        if (val != '') {
1111                            var findPartial = val.length > 2;
1112                            $.each($input.data('suggestions'), function (i, suggestion) {
1113                                var lowerCaseVal = suggestion.toLocaleLowerCase();
1114                                if (lowerCaseVal == val) {
1115                                    foundSuggestions.push('<strong>' + suggestion + '</strong>');
1116                                    hasTypedSuggestion = true;
1117                                    return false;
1118                                } else if (lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) {
1119                                    foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>'));
1120                                }
1121                            });
1122                        }
1123
1124                        // Hide suggestion container
1125                        if (hasTypedSuggestion || (foundSuggestions.length == 0 && $suggestionContainer.length > 0)) {
1126                            $suggestionContainer.hide();
1127                        }
1128
1129                        // Create suggestion container if not already exists
1130                        else if (foundSuggestions.length > 0 && $suggestionContainer.length == 0) {
1131                            $suggestionContainer = $('<div></div>').css(conf.css).appendTo('body');
1132                            $elem.addClass('suggestions-' + suggestionId);
1133                            $suggestionContainer
1134                                    .attr('data-suggest-container', suggestionId)
1135                                    .addClass('jquery-form-suggestions')
1136                                    .addClass('jquery-form-suggestion-' + suggestionId);
1137                        }
1138
1139                        // Show hidden container
1140                        else if (foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) {
1141                            $suggestionContainer.show();
1142                        }
1143
1144                        // add suggestions
1145                        if (foundSuggestions.length > 0 && val.length != foundSuggestions[0].length) {
1146
1147                            // put container in place every time, just in case
1148                            setSuggsetionPosition($suggestionContainer, $input);
1149
1150                            // Add suggestions HTML to container
1151                            $suggestionContainer.html('');
1152                            $.each(foundSuggestions, function (i, text) {
1153                                $('<div></div>')
1154                                        .append(text)
1155                                        .css({
1156                                            overflow: 'hidden',
1157                                            textOverflow: 'ellipsis',
1158                                            whiteSpace: 'nowrap',
1159                                            padding: '5px'
1160                                        })
1161                                        .addClass('form-suggest-element')
1162                                        .appendTo($suggestionContainer)
1163                                        .click(function () {
1164                                            $input.focus();
1165                                            $input.val($(this).text());
1166                                            onSelectSuggestion($input);
1167                                        });
1168                            });
1169                        }
1170                    })
1171                    .unbind('keydown.validation')
1172                    .bind('keydown.validation', function (e) {
1173                        var code = (e.keyCode ? e.keyCode : e.which),
1174                                suggestionId,
1175                                $suggestionContainer,
1176                                $input = $(this);
1177
1178                        if (code == 13 && $.formUtils._selectedSuggestion !== null) {
1179                            suggestionId = $input.valAttr('suggestion-nr');
1180                            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1181                            if ($suggestionContainer.length > 0) {
1182                                var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
1183                                $input.val(newText);
1184                                onSelectSuggestion($input);
1185                                e.preventDefault();
1186                            }
1187                        }
1188                        else {
1189                            suggestionId = $input.valAttr('suggestion-nr');
1190                            $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId);
1191                            var $suggestions = $suggestionContainer.children();
1192                            if ($suggestions.length > 0 && $.inArray(code, [38, 40]) > -1) {
1193                                if (code == 38) { // key up
1194                                    if ($.formUtils._selectedSuggestion === null)
1195                                        $.formUtils._selectedSuggestion = $suggestions.length - 1;
1196                                    else
1197                                        $.formUtils._selectedSuggestion--;
1198                                    if ($.formUtils._selectedSuggestion < 0)
1199                                        $.formUtils._selectedSuggestion = $suggestions.length - 1;
1200                                }
1201                                else if (code == 40) { // key down
1202                                    if ($.formUtils._selectedSuggestion === null)
1203                                        $.formUtils._selectedSuggestion = 0;
1204                                    else
1205                                        $.formUtils._selectedSuggestion++;
1206                                    if ($.formUtils._selectedSuggestion > ($suggestions.length - 1))
1207                                        $.formUtils._selectedSuggestion = 0;
1208
1209                                }
1210
1211                                // Scroll in suggestion window
1212                                var containerInnerHeight = $suggestionContainer.innerHe
1212ight(),
1213                                        containerScrollTop = $suggestionContainer.scrollTop(),
1214                                        suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(),
1215                                        activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion);
1216
1217                                if (activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop + containerInnerHeight)) {
1218                                    $suggestionContainer.scrollTop(activeSuggestionPosY);
1219                                }
1220
1221                                $suggestions
1222                                        .removeClass('active-suggestion')
1223                                        .css('background', 'none')
1224                                        .eq($.formUtils._selectedSuggestion)
1225                                        .addClass('active-suggestion')
1226                                        .css(conf.activeSuggestionCSS);
1227
1228                                e.preventDefault();
1229                                return false;
1230                            }
1231                        }
1232                    })
1233                    .unbind('blur.suggest')
1234                    .bind('blur.suggest', function () {
1235                        onSelectSuggestion($(this));
1236                    });
1237
1238            return $elem;
1239        },
1240        /**
1241         * Error dialogs
1242         *
1243         * @var {Object}
1244         */
1245        LANG: {
1246            errorTitle: 'Form submission failed!',
1247            requiredFields: 'You have not answered all required fields',
1248            badTime: 'You have not given a correct time',
1249            badEmail: 'You have not given a correct e-mail address',
1250            badTelephone: 'You have not given a correct phone number',
1251            badSecurityAnswer: 'You have not given a correct answer to the security question',
1252            badDate: 'You have not given a correct date',
1253            lengthBadStart: 'The input value must be between ',
1254            lengthBadEnd: ' characters',
1255            lengthTooLongStart: 'The input value is longer than ',
1256            lengthTooShortStart: 'The input value is shorter than ',
1257            notConfirmed: 'Input values could not be confirmed',
1258            badDomain: 'Incorrect domain value',
1259            badUrl: 'The input value is not a correct URL',
1260            badCustomVal: 'The input value is incorrect',
1261            badInt: 'The input value was not a correct number',
1262            badSecurityNumber: 'Your social security number was incorrect',
1263            badUKVatAnswer: 'Incorrect UK VAT Number',
1264            badStrength: 'The password isn\'t strong enough',
1265            badNumberOfSelectedOptionsStart: 'You have to choose at least ',
1266            badNumberOfSelectedOptionsEnd: ' answers',
1267            badAlphaNumeric: 'The input value can only contain alphanumeric characters ',
1268            badAlphaNumericExtra: ' and ',
1269            wrongFileSize: 'The file you are trying to upload is too large',
1270            wrongFileType: 'The file you are trying to upload is of the wrong type',
1271            groupCheckedRangeStart: 'Please choose between ',
1272            groupCheckedTooFewStart: 'Please choose at least ',
1273            groupCheckedTooManyStart: 'Please choose a maximum of ',
1274            groupCheckedEnd: ' item(s)',
1275            badCreditCard: 'The credit card number is not correct',
1276            badCVV: 'The CVV number was not correct'
1277        }
1278    };
1279
1280
1281    /* * * * * * * * * * * * * * * * * * * * * *
1282     CORE VALIDATORS
1283     * * * * * * * * * * * * * * * * * * * * */
1284
1285
1286    /*
1287     * Validate email
1288     */
1289    $.formUtils.addValidator({
1290        name: 'email',
1291        validatorFunction: function (email) {
1292
1293            var emailParts = email.toLowerCase().split('@');
1294            if (emailParts.length == 2) {
1295				var regex = /^[a-zA-Z0-9.'!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
1296				return regex.test(email)
1297
1298                return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
1299                        !(/[^\w\+\.\-]/.test(emailParts[0]));
1300            }
1301
1302            return false;
1303        },
1304        errorMessage: '',
1305        errorMessageKey: 'badEmail'
1306    });
1307
1308    /*
1309     * Validate domain name
1310     */
1311    $.formUtils.addValidator({
1312        name: 'domain',
1313        validatorFunction: function (val, $input) {
1314
1315            var topDomains = ['.ac', '.ad', '.ae', '.aero', '.af', '.ag', '.ai', '.al', '.am', '.an', '.ao',
1316                '.aq', '.ar', '.arpa', '.as', '.asia', '.at', '.au', '.aw', '.ax', '.az', '.ba', '.bb',
1317                '.bd', '.be', '.bf', '.bg', '.bh', '.bi', '.bike', '.biz', '.bj', '.bm', '.bn', '.bo',
1318                '.br', '.bs', '.bt', '.bv', '.bw', '.by', '.bz', '.ca', '.camera', '.cat', '.cc', '.cd',
1319                '.cf', '.cg', '.ch', '.ci', '.ck', '.cl', '.clothing', '.cm', '.cn', '.co', '.com',
1320                '.construction', '.contractors', '.coop', '.cr', '.cu', '.cv', '.cw', '.cx', '.cy', '.cz',
1321                '.de', '.diamonds', '.directory', '.dj', '.dk', '.dm', '.do', '.dz', '.ec', '.edu', '.ee',
1322                '.eg', '.enterprises', '.equipment', '.er', '.es', '.estate', '.et', '.eu', '.fi', '.fj',
1323                '.fk', '.fm', '.fo', '.fr', '.ga', '.gallery', '.gb', '.gd', '.ge', '.gf', '.gg', '.gh',
1324                '.gi', '.gl', '.gm', '.gn', '.gov', '.gp', '.gq', '.gr', '.graphics', '.gs', '.gt', '.gu',
1325                '.guru', '.gw', '.gy', '.hk', '.hm', '.hn', '.holdings', '.hr', '.ht', '.hu', '.id', '.ie',
1326                '.il', '.im', '.in', '.info', '.int', '.io', '.iq', '.ir', '.is', '.it', '.je', '.jm', '.jo',
1327                '.jobs', '.jp', '.ke', '.kg', '.kh', '.ki', '.kitchen', '.km', '.kn', '.kp', '.kr', '.kw',
1328                '.ky', '.kz', '.la', '.land', '.lb', '.lc', '.li', '.lighting', '.lk', '.lr', '.ls', '.lt',
1329                '.lu', '.lv', '.ly', '.ma', '.mc', '.md', '.me', '.menu', '.mg', '.mh', '.mil', '.mk', '.ml',
1330                '.mm', '.mn', '.mo', '.mobi', '.mp', '.mq', '.mr', '.ms', '.mt', '.mu', '.museum', '.mv',
1331                '.mw', '.mx', '.my', '.mz', '.na', '.name', '.nc', '.ne', '.net', '.nf', '.ng', '.ni',
1332                '.nl', '.no', '.np', '.nr', '.nu', '.nz', '.om', '.org', '.pa', '.pe', '.pf', '.pg', '.ph',
1333                '.photography', '.pk', '.pl', '.plumbing', '.pm', '.pn', '.post', '.pr', '.pro', '.ps', '.pt',
1334                '.pw', '.py', '.qa', '.re', '.ro', '.rs', '.ru', '.rw', '.sa', '.sb', '.sc', '.sd', '.se',
1335                '.sexy', '.sg', '.sh', '.si', '.singles', '.sj', '.sk', '.sl', '.sm', '.sn', '.so', '.sr',
1336                '.st', '.su', '.sv', '.sx', '.sy', '.sz', '.tattoo', '.tc', '.td', '.technology', '.tel', '.tf',
1337                '.tg', '.th', '.tips', '.tj', '.tk', '.tl', '.tm', '.tn', '.to', '.today', '.tp', '.tr', '.travel',
1338                '.tt', '.tv', '.tw', '.tz', '.ua', '.ug', '.uk', '.uno', '.us', '.uy', '.uz', '.va', '.vc', '.ve',
1339                '.ventures', '.vg', '.vi', '.vn', '.voyage', '.vu', '.wf', '.ws', '.xn--3e0b707e', '.xn--45brj9c',
1340                '.xn--80ao21a', '.xn--80asehdb', '.xn--80aswg', '.xn--90a3ac', '.xn--clchc0ea0b2g2a9gcd', '.xn--fiqs8s',
1341                '.xn--fiqz9s', '.xn--fpcrj9c3d', '.xn--fzc2c9e2c', '.xn--gecrj9c', '.xn--h2brj9c', '.xn--j1amh',
1342                '.xn--j6w193g', '.xn--kprw13d', '.xn--kpry57d', '.xn--l1acc', '.xn--lgbbat1ad8j', '.xn--mgb9awbf',
1343                '.xn--mgba3a4f16a', '.xn--mgbaam7a8h', '.xn--mgbayh7gpa', '.xn--mgbbh1a71e', '.xn--mgbc0a9azcg',
1344                '.xn--mgberp4a5d4ar', '.xn--mgbx4cd0ab', '.xn--ngbc5azd', '.xn--o3cw4h', '.xn--ogbpf8fl', '.xn--p1ai',
1345                '.xn--pgbs0dh', '.xn--q9jyb4c', '.xn--s9brj9c', '.xn--unup4y', '.xn--wgbh1c', '.xn--wgbl6a',
1346                '.xn--xkc2al3hye2a', '.xn--xkc2dl3a5ee0h', '.xn--yfro4i67o', '.xn--ygbi2ammx', '.xxx', '.ye',
1347                '.yt', '.za', '.zm', '.zw'],
1348                    ukTopDomains = ['co', 'me', 'ac', 'gov', 'judiciary', 'ltd', 'mod', 'net', 'nhs', 'nic',
1349                        'org', 'parliament', 'plc', 'police', 'sch', 'bl', 'british-library', 'jet', 'nls'],
1350                    dot = val.lastIndexOf('.'),
1351                    domain = val.substring(0, dot),
1352                    ext = val.substring(dot, val.length),
1353                    hasTopDomain = false;
1354
1355            for (var i = 0; i < topDomains.length; i++) {
1356                if (topDomains[i] === ext) {
1357                    if (ext === '.uk') {
1358                        //Run Extra Checks for UK Domain Names
1359                        var domainParts = val.split('.');
1360                        var tld2 = domainParts[domainParts.length - 2];
1361                        for (var j = 0; j < ukTopDomains.length; j++) {
1362                            if (ukTopDomains[j] === tld2) {
1363                                hasTopDomain = true;
1364                                break;
1365                            }
1366                        }
1367
1368                        if (hasTopDomain)
1369                            break;
1370
1371                    } else {
1372                        hasTopDomain = true;
1373                        break;
1374                    }
1375                }
1376            }
1377
1378            if (!hasTopDomain) {
1379                return false;
1380            } else if (dot < 2 || dot > 57) {
1381                return $.inArray(val, ['i.net', 'q.com', 'q.net', 'x.com', 'x.org', 'z.com', 'w.org']) > -1;
1382            } else {
1383                var firstChar = domain.substring(0, 1),
1384                        lastChar = domain.substring(domain.length - 1, domain.length);
1385
1386                if (firstChar === '-' || firstChar === '.' || lastChar === '-' || lastChar === '.') {
1387                    return false;
1388                }
1389                if (domain.split('..').length > 1) {
1390                    return false;
1391                }
1392                if (domain.replace(/[-\da-z\.]/g, '') !== '') {
1393                    return false;
1394                }
1395            }
1396
1397            if (typeof $input !== 'undefined') {
1398                $input.val(val);
1399            }
1400
1401            return true;
1402        },
1403        errorMessage: '',
1404        errorMessageKey: 'badDomain'
1405    });
1406
1407    /*
1408     * Validate required
1409     */
1410    $.formUtils.addValidator({
1411        name: 'required',
1412        validatorFunction: function (val, $el, config, language, $form) {
1413            switch ($el.attr('type')) {
1414                case 'checkbox':
1415                    return $el.is(':checked');
1416                case 'radio':
1417                    return $form.find('input[name="' + $el.attr('name') + '"]').filter(':checked').length > 0;
1418                default:
1419                    return $.trim(val) !== '';
1420            }
1421        },
1422        errorMessage: '',
1423        errorMessageKey: 'requiredFields'
1424    });
1425
1426    /*
1427     * Validate length range
1428     */
1429    $.formUtils.addValidator({
1430        name: 'length',
1431        validatorFunction: function (val, $el, conf, lang) {
1432            var lengthAllowed = $el.valAttr('length'),
1433                    type = $el.attr('type');
1434
1435            if (lengthAllowed == undefined) {
1436                var elementType = $el.get(0).nodeName;
1437                alert('Please add attribute "data-validation-length" to ' + elementType + ' named ' + $el.attr('name'));
1438                return true;
1439            }
1440
1441            // check if length is above min, below max or within range.
1442            var len = type == 'file' && $el.get(0).files !== undefined ? $el.get(0).files.length : val.length,
1443                    lengthCheckResults = $.formUtils.numericRangeCheck(len, lengthAllowed),
1444                    checkResult;
1445
1446            switch (lengthCheckResults[0])
1447            {   // outside of allowed range
1448                case "out":
1449                    this.errorMessage = lang.lengthBadStart + lengthAllowed + lang.lengthBadEnd;
1450                    checkResult = false;
1451                    break;
1452                    // too short
1453                case "min":
1454                    this.errorMessage = lang.lengthTooShortStart + lengthCheckResults[1] + lang.lengthBadEnd;
1455                    checkResult = false;
1456                    break;
1457                    // too long
1458                case "max":
1459                    this.errorMessage = lang.lengthTooLongStart + lengthCheckResults[1] + lang.lengthBadEnd;
1460                    checkResult = false;
1461                    break;
1462                    // ok
1463                default:
1464                    checkResult = true;
1465            }
1466
1467            return checkResult;
1468        },
1469        errorMessage: '',
1470        errorMessageKey: ''
1471    });
1472
1473    /*
1474     * Validate url
1475     */
1476    $.formUtils.addValidator({
1477        name: 'url',
1478        validatorFunction: function (url) {
1479            // written by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1480            // - Victor Jonsson added support for arrays in the url ?arg[]=sdfsdf
1481            // - General improvements made by Stéphane Moureau <https://github.com/TraderStf>
1482            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;
1483            if (urlFilter.test(url)) {
1484                var domain = url.split('://')[1];
1485                var domainSlashPos = domain.indexOf('/');
1486                if (domainSlashPos > -1)
1487                    domain = domain.substr(0, domainSlashPos);
1488
1489                return $.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add support for IP-addresses
1490            }
1491            return false;
1492        },
1493        errorMessage: '',
1494        errorMessageKey: 'badUrl'
1495    });
1496
1497    /*
1498     * Validate number (floating or integer)
1499     */
1500    $.formUtils.addValidator({
1501        name: 'number',
1502        validatorFunction: function (val, $el, conf) {
1503            if (val !== '') {
1504                var allowing = $el.valAttr('allowing') || '',
1505                        decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator,
1506                        allowsRange = false,
1507                        begin, end,
1508                        steps = $el.valAttr('step') || '',
1509                        allowsSteps = false;
1510
1511                if (allowing.indexOf('number') == -1)
1512                    allowing += ',number';
1513
1514                if (allowing.indexOf('negative') > -1 && val.indexOf('-') === 0) {
1515                    val = val.substr(1);
1516                }
1517
1518                if (allowing.indexOf('range') > -1)
1519                {
1520                    begin = parseFloat(allowing.substring(allowing.indexOf("[") + 1, allowing.indexOf(";")));
1521                    end = parseFloat(allowing.substring(allowing.indexOf(";") + 1, allowing.indexOf("]")));
1522                    allowsRange = true;
1523                }
1524
1525                if (steps != "")
1526                {
1527                    allowsSteps = true;
1528                }
1529
1530                if (decimalSeparator == ',') {
1531                    if (val.indexOf('.') > -1) {
1532                        return false;
1533                    }
1534                    // Fix for checking range with floats using ,
1535                    val = val.replace(',', '.');
1536                }
1537
1538                if (allowing.indexOf('number') > -1 && val.replace(/[0-9]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps == 0))) {
1539                    return true;
1540                }
1541                if (allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps == 0))) {
1542                    return true;
1543                }
1544            }
1545            return false;
1546        },
1547        errorMessage: '',
1548        errorMessageKey: 'badInt'
1549    });
1550
1551    /*
1552     * Validate alpha numeric
1553     */
1554    $.formUtils.addValidator({
1555        name: 'alphanumeric',
1556        validatorFunction: function (val, $el, conf, language) {
1557            var patternStart = '^([a-zA-Z0-9',
1558                    patternEnd = ']+)$',
1559                    additionalChars = $el.attr('data-validation-allowing'),
1560                    pattern = '';
1561
1562            if (additionalChars) {
1563                pattern = patternStart + additionalChars + patternEnd;
1564                var extra = additionalChars.replace(/\\/g, '');
1565                if (extra.indexOf(' ') > -1) {
1566                    extra = extra.replace(' ', '');
1567                    extra += ' and spaces ';
1568                }
1569                this.errorMessage = language.badAlphaNumeric + language.badAlphaNumericExtra + extra;
1570            } else {
1571                pattern = patternStart + patternEnd;
1572                this.errorMessage = language.badAlphaNumeric;
1573            }
1574
1575            return new RegExp(pattern).test(val);
1576        },
1577        errorMessage: '',
1578        errorMessageKey: ''
1579    });
1580
1581    /*
1582     * Validate against regexp
1583     */
1584    $.formUtils.addValidator({
1585        name: 'custom',
1586        validatorFunction: function (val, $el, conf) {
1587            var regexp = new RegExp($el.valAttr('regexp'));
1588            return regexp.test(val);
1589        },
1590        errorMessage: '',
1591        errorMessageKey: 'badCustomVal'
1592    });
1593
1594    /*
1595     * Validate date
1596     */
1597    $.formUtils.addValidator({
1598        name: 'date',
1599        validatorFunction: function (date, $el, conf) {
1600            var dateFormat = 'yyyy-mm-dd';
1601            if ($el.valAttr('format')) {
1602                dateFormat = $el.valAttr('format');
1603            }
1604            else if (conf.dateFormat) {
1605                dateFormat = conf.dateFormat;
1606            }
1607
1608            return $.formUtils.parseDate(date, dateFormat) !== false;
1609        },
1610        errorMessage: '',
1611        errorMessageKey: 'badDate'
1612    });
1613
1614
1615    /*
1616     * Validate group of checkboxes, validate qty required is checked
1617     * written by Steve Wasiura : http://stevewasiura.waztech.com
1618     * element attrs
1619     *    data-validation="checkbox_group"
1620     *    data-validation-qty="1-2"  // min 1 max 2
1621     *    data-validation-error-msg="chose min 1, max of 2 checkboxes"
1622     */
1623    $.formUtils.addValidator({
1624        name: 'checkbox_group',
1625        validatorFunction: function (val, $el, conf, lang, $form)
1626        {   // preset return var
1627            var checkResult = true;
1628            // get name of element. since it is a checkbox group, all checkboxes will have same name
1629            var elname = $el.attr('name');
1630            // get count of checked checkboxes with this name
1631            var checkedCount = $("input[type=checkbox][name^='" + elname + "']:checked", $form).length;
1632            // get el attr that specs qty required / allowed
1633            var qtyAllowed = $el.valAttr('qty');
1634            if (qtyAllowed == undefined) {
1635                var elementType = $el.get(0).nodeName;
1636                alert('Attribute "data-validation-qty" is missing from ' + elementType + ' named ' + $el.attr('name'));
1637            }
1638            // call Utility function to check if count is above min, below max, within range etc.
1639            var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed);
1640            // results will be array, [0]=result str, [1]=qty int
1641            switch (qtyCheckResults[0]) {
1642                // outside allowed range
1643                case "out":
1644                    this.errorMessage = lang.groupCheckedRangeStart + qtyAllowed + lang.groupCheckedEnd;
1645                    checkResult = false;
1646                    break;
1647                    // below min qty
1648                case "min":
1649                    this.errorMessage = lang.groupCheckedTooFewStart + qtyCheckResults[1] + lang.groupCheckedEnd;
1650                    checkResult = false;
1651                    break;
1652                    // above max qty
1653                case "max":
1654                    this.errorMessage = lang.groupCheckedTooManyStart + qtyCheckResults[1] + lang.groupCheckedEnd;
1655                    checkResult = false;
1656                    break;
1657                    // ok
1658                default:
1659                    checkResult = true;
1660            }
1661
1662            return checkResult;
1663
1664        }
1665        //   errorMessage : '', // set above in switch statement
1666        //   errorMessageKey: '' // not used
1667    });
1668
1669})(jQuery);

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.