PageSourceSearch

https://www.kaumberg.gv.at/site/modules/RockForms/live-form-validation.js?m=1789974245

js kaumberg.gv.at collected 2026-10-02 20:49:36 UTC 44,786 bytes, 1,299 lines download raw bytes

1/**
2 * Live Form Validation for Nette Forms 3.0
3 *
4 * @author Robert Pösel, zakrava, Radek Ježdík, MartyIX, David Grudl
5 * @version 2.0-dev
6 * @url https://github.com/Robyer/nette-live-form-validation/
7 */
8
9(function (global, factoryLiveValidation, factoryNetteForm) {
10
11    if (typeof define === 'function' && define.amd) {
12        // AMD
13        define(function () {
14            return {
15                LiveForm: factoryLiveValidation(global),
16                Nette: factoryNetteForm(global)
17            }
18        })
19    } else if (typeof exports === 'object') {
20        // Node, CommonJS-like
21        module.exports = {
22            LiveForm: factoryLiveValidation(global),
23            Nette: factoryNetteForm(global)
24        }
25    } else {
26        global.LiveForm = factoryLiveValidation(global);
27        // Browser globals (root is window)
28        var init = !global.Nette || !global.Nette.noInit;
29        global.Nette = factoryNetteForm(global);
30        if (init) {
31            global.Nette.initOnLoad();
32        }
33    }
34
35
36}(typeof window !== 'undefined' ? window : this, function (window) {
37    'use strict'
38
39
40    var LiveForm = {
41        options: {
42            // CSS class of control's parent where error/valid class should be added; or "false" to use control directly
43            showMessageClassOnParent: 'form-group',
44
45            // CSS class of control's parent where error/valid message should be added (fallback to direct parent if not found); or "false" to use control's direct parent
46            messageParentClass: false,
47
48            // CSS class for an invalid control
49            controlErrorClass: 'has-error',
50
51            // CSS class for a valid control
52            controlValidClass: 'has-success',
53
54            // CSS class for an error message
55            messageErrorClass: 'help-block text-danger',
56
57            // control with this CSS class will show error/valid message even when control itself is hidden (useful for controls which are hidden and wrapped into special component)
58            enableHiddenMessageClass: 'show-hidden-error',
59
60            // control with this CSS class will have disabled live validation
61            disableLiveValidationClass: 'no-live-validation',
62
63            // control with this CSS class will not show valid message
64            disableShowValidClass: 'no-show-valid',
65
66            // tag that will hold the error/valid message
67            messageTag: 'span',
68
69            // message element id = control id + this postfix
70            messageIdPostfix: '_message',
71
72            // show this html before error message itself
73            messageErrorPrefix: '&nbsp;<i class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></i>&nbsp;',
74
75            // show all errors when submitting form; or use "false" to show only first error
76            showAllErrors: true,
77
78            // show message when valid
79            showValid: false,
80
81            // delay in ms before validating on keyup/keydown; or use "false" to disable it
82            wait: false,
83
84            // vertical screen offset in px to scroll after focusing element with error (useful when using fixed navbar menu which may otherwise obscure the element in focus); or use "false" for default behavior
85            focusScreenOffsetY: false
86        },
87
88        forms: {}
89    };
90
91    LiveForm.setOptions = function (userOptions) {
92        for (var prop in userOptions) {
93            if (Object.prototype.hasOwnProperty.call(this.options, prop)) {
94                this.options[prop] = userOptions[prop];
95            }
96        }
97    }
98
99// Allow setting options before loading the script just by creating global LiveFormOptions object with options.
100    if (typeof window.LiveFormOptions !== 'undefined') {
101        LiveForm.setOptions(window.LiveFormOptions);
102    }
103
104    LiveForm.isSpecialKey = function (k) {
105        // http://stackoverflow.com/questions/7770561/jquery-javascript-reject-control-keys-on-keydown-event
106        return (k == 20 /* Caps lock */
107            || k == 16 /* Shift */
108            || k == 9 /* Tab */
109            || k == 27 /* Escape Key */
110            || k == 17 /* Control Key */
111            || k == 91 /* Windows Command Key */
112            || k == 19 /* Pause Break */
113            || k == 18 /* Alt Key */
114            || k == 93 /* Right Click Point Key */
115            || (k >= 35 && k <= 40) /* Home, End, Arrow Keys */
116            || k == 45 /* Insert Key */
117            || (k >= 33 && k <= 34) /*Page Down, Page Up */
118            || (k >= 112 && k <= 123) /* F1 - F12 */
119            || (k >= 144 && k <= 145)); /* Num Lock, Scroll Lock */
120    }
121
122    /**
123     * Handlers for all the events that trigger validation
124     * YOU CAN CHANGE these handlers (ie. to use jQuery events instead)
125     */
126    LiveForm.setupHandlers = function (el) {
127        if (this.hasClass(el, this.options.disableLiveValidationClass))
128            return;
129
130        // Check if element was already initialized
131        if (el.getAttribute("data-lfv-initialized"))
132            return;
133
134        // Remember we initialized this element so we won't do it again
135        el.setAttribute('data-lfv-initialized', 'true');
136
137        var handler = function (event) {
138            event = event || window.event;
139            Nette.validateControl(event.target ? event.target : event.srcElement);
140        };
141
142        var self = this;
143
144        el.addEventListener('change', handler);
145        el.addEventListener('blur', handler);
146        el.addEventListener('keydown', function (event) {
147            if (!self.isSpecialKey(event.which) && (self.options.wait === false || self.options.wait >= 200)) {
148                // Hide validation span tag.
149                self.removeClass(self.getGroupElement(this), self.options.controlErrorClass);
150                self.removeClass(self.getGroupElement(this), self.options.controlValidClass);
151
152                var messageEl = self.getMessageElement(this);
153                messageEl.innerHTML = '';
154                messageEl.className = '';
155
156                // Cancel timeout to run validation handler
157                if (self.timeout) {
158                    clearTimeout(self.timeout);
159                }
160            }
161        });
162        el.addEventListener('keyup', function (event) {
163            if (self.options.wait !== false) {
164                event = event || window.event;
165                if (event.keyCode !== 9) {
166                    if (self.timeout) clearTimeout(self.timeout);
167                    self.timeout = setTimeout(function () {
168                        handler(event);
169                    }, self.options.wait);
170                }
171            }
172        });
173    };
174
175    LiveForm.processServerErrors = function (el) {
176        var messageEl = this.getMessageElement(el);
177        var parentEl = this.getMessageParent(el); // This is parent element which contain the error elements
178
179        var errors = [];
180
181        // Find existing error elements by class (from server-validation)
182        var errorEls = parentEl.getElementsByClassName(this.options.messageErrorClass);
183        for (var i = errorEls.length - 1; i > -1; i--) {
184            // Don't touch our main message element
185            if (errorEls[i] == messageEl)
186                continue;
187
188            // Remove only direct children
189            var errorParent = errorEls[i].parentNode;
190            if (errorParent == parentEl) {
191                errors.push(errorEls[i].outerHTML);
192                errorParent.removeChild(errorEls[i]);
193            }
194        }
195
196        // Wrap all server errors into one element
197        if (errors.length > 0) {
198            messageEl.innerHTML = errors.join("");
199        }
200    };
201
202    LiveForm.addError = function (el, message) {
203        // Ignore elements with disabled live validation
204        if (this.hasClass(el, this.options.disableLiveValidationClass))
205            return;
206
207        var groupEl = this.getGroupElement(el);
208        this.setFormProperty(el.form, "hasError", true);
209        this.addClass(groupEl, this.options.controlErrorClass);
210
211        if (this.options.showValid) {
212            this.removeClass(groupEl, this.options.controlValidClass);
213        }
214
215        if (!message) {
216            message = '&nbsp;';
217        } else {
218            message = this.options.messageErrorPrefix + message;
219        }
220
221        var messageEl = this.getMessageElement(el);
222        messageEl.innerHTML = message;
223        messageEl.className = this.options.messageErrorClass;
224    };
225
226    LiveForm.removeError = function (el) {
227        // We don't want to remove any errors during onLoadValidation
228        if (this.getFormProperty(el.form, "onLoadValidation"))
229            return;
230
231        var groupEl = this.getGroupElement(el);
232        this.removeClass(groupEl, this.options.controlErrorClass);
233
234        var id = el.getAttribute('data-lfv-message-id');
235        if (id) {
236            var messageEl = this.getMessageElement(el);
237            messageEl.innerHTML = '';
238            messageEl.className = '';
239        }
240
241        if (this.options.showValid) {
242            if (this.showValid(el))
243                this.addClass(groupEl, this.options.controlValidClass);
244            else
245                this.removeClass(groupEl, this.options.controlValidClass);
246        }
247    };
248
249    LiveForm.showValid = function (el) {
250        if (el.type) {
251            var type = el.type.toLowerCase();
252            if (type == 'checkbox' || type == 'radio') {
253                return false;
254            }
255        }
256
257        var rules = JSON.parse(el.getAttribute('data-nette-rules'));
258        if (rules === null || rules.length == 0) {
259            return false;
260        }
261
262        if (Nette.getEffectiveValue(el) == '') {
263            return false;
264        }
265
266        if (this.hasClass(el, this.options.disableShowValidClass)) {
267            return false;
268        }
269
270        return true;
271    };
272
273    LiveForm.getGroupElement = function (el) {
274        if (this.options.showMessageClassOnParent === false)
275            return el;
276
277        var groupEl = el;
278
279        while (!this.hasClass(groupEl, this.options.showMessageClassOnParent)) {
280            groupEl = groupEl.parentNode;
281
282            if (groupEl === null) {
283                return el;
284            }
285        }
286
287        return groupEl;
288    }
289
290    LiveForm.getMessageId = function (el) {
291        var tmp = el.id + this.options.messageIdPostfix;
292
293        // For elements without ID, or multi elements (with same name), we must generate whole ID ourselves
294        if (el.name && (!el.id || !el.form.elements[el.name].tagName)) {
295            // Strip possible [] from name
296            var name = el.name.match(/\[\]$/) ? el.name.match(/(.*)\[\]$/)[1] : el.name;
297            // Generate new ID based on form ID, element name and messageIdPostfix from options
298            tmp = (el.form.id ? el.form.id : 'frm') + '-' + name + this.options.messageIdPostfix;
299        }
300
301        // We want unique ID which doesn't exist yet
302        var id = tmp,
303            i = 0;
304        while (document.getElementById(id)) {
305            id = id + '_' + ++i;
306        }
307
308        return id;
309    }
310
311    LiveForm.getMessageElement = function (el) {
312        // For multi elements (with same name) work only with first element attributes
313        if (el.name && el.name.match(/\[\]$/)) {
314            el = el.form.elements[el.name].tagName ? el : el.form.elements[el.name][0];
315        }
316
317        var id = el.getAttribute('data-lfv-message-id');
318        if (!id) {
319            // ID is not specified yet, let's create a new one
320            id = this.getMessageId(el);
321
322            // Remember this id for next use
323            el.setAttribute('data-lfv-message-id', id);
324        }
325
326        var messageEl = document.getElementById(id);
327        if (!messageEl) {
328            // Message element doesn't exist, lets create a new one
329            messageEl = document.createElement(this.options.messageTag);
330            messageEl.id = id;
331            if (el.style.display == 'none' && !this.hasClass(el, this.options.enableHiddenMessageClass)) {
332                messageEl.style.display = 'none';
333            }
334
335            var parentEl = this.getMessageParent(el);
336            if (parentEl === el.parentNode) {
337                parentEl.insertBefore(messageEl, el.nextSibling);
338            } else if (parentEl) {
339                typeof parentEl.append === 'function' ? parentEl.append(messageEl) : parentEl.appendChild(messageEl);
340            }
341        }
342
343        return messageEl;
344    };
345
346    LiveForm.getMessageParent = function (el) {
347        var parentEl = el.parentNode;
348        var parentFound = false;
349
350        if (this.options.messageParentClass !== false) {
351            parentFound = true;
352            while (!this.hasClass(parentEl, this.options.messageParentClass)) {
353                parentEl = parentEl.parentNode;
354
355                if (parentEl === null) {
356                    // We didn't found wanted parent, so use element's direct parent
357                    parentEl = el.parentNode;
358                    parentFound = false;
359                    break;
360                }
361            }
362        }
363
364        // Don't append error message to radio/checkbox input's label, but along label
365        if (el.type) {
366            var type = el.type.toLowerCase();
367            if ((type == 'checkbox' || type == 'radio') && parentEl.tagName == 'LABEL') {
368                parentEl = parentEl.parentNode;
369            }
370        }
371
372        // For multi elements (with same name) use parent's parent as parent (if wanted one is not found)
373        if (!parentFound && el.name && !el.form.elements[el.name].tagName) {
374            parentEl = parentEl.parentNode;
375        }
376
377        return parentEl;
378    }
379
380    LiveForm.addClass = function (el, className) {
381        if (!el.className) {
382            el.className = className;
383        } else if (!this.hasClass(el, className)) {
384            el.className += ' ' + className;
385        }
386    };
387
388    LiveForm.hasClass = function (el, className) {
389        if (el.className)
390            return el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
391        return false;
392    };
393
394    LiveForm.removeClass = function (el, className) {
395        if (this.hasClass(el, className)) {
396            var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
397            var m = el.className.match(reg);
398            el.className = el.className.replace(reg, (m[1] == ' ' && m[2] == ' ') ? ' ' : '');
399        }
400    };
401
402    LiveForm.getFormProperty = function (form, propertyName) {
403        if (form == null || this.forms[form.id] == null)
404            return false;
405
406        return this.forms[form.id][propertyName];
407    };
408
409    LiveForm.setFormProperty = function (form, propertyName, value) {
410        if (form == null)
411            return;
412
413        if (this.forms[form.id] == null)
414            this.forms[form.id] = {};
415
416        this.forms[form.id][propertyName] = value;
417    };
418
419    return LiveForm;
420
421////////////////////////////   modified netteForms.js   ///////////////////////////////////
422
423    /**
424     * NetteForms - simple form validation.
425     *
426     * This file is part of the Nette Framework (https://nette.org)
427     * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
428     */
429    /*
430    (function(global, factory) {
431        if (!global.JSON) {
432            return;
433        }
434        if (typeof define === 'function' && define.amd) {
435            define(function() {
436                return factory(global);
437            });
438        } else if (typeof module === 'object' && typeof module.exports === 'object') {
439            module.exports = factory(global);
440        } else {
441            var init = !global.Nette || !global.Nette.noInit;
442            global.Nette = factory(global);
443            if (init) {
444                global.Nette.initOnLoad();
445            }
446        }
447    }(typeof window !== 'undefined' ? window : this, function(window) {
448    */
449
450}, function (window) {
451    'use strict';
452
453    var Nette = {};
454    var preventFiltering = {};
455    var formToggles = {};
456
457    // LiveForm: original netteForms.js code
458    // Nette.formErrors = [];
459    Nette.version = '3.0';
460
461
462    /**
463     * Function to execute when the DOM is fully loaded.
464     * @private
465     */
466    Nette.onDocumentReady = function (callback) {
467        if (document.readyState !== 'loading') {
468            callback.call(this);
469        } else {
470            document.addEventListener('DOMContentLoaded', callback);
471        }
472    };
473
474
475    /**
476     * Attaches a handler to an event for the element.
477     */
478    Nette.addEvent = function (element, on, callback) {
479        if (element.addEventListener) {
480            element.addEventListener(on, callback);
481        } else if (on === 'DOMContentLoaded') {
482            element.attachEvent('onreadystatechange', function () {
483                if (element.readyState === 'complete') {
484                    callback.call(this);
485                }
486            });
487        } else {
488            element.attachEvent('on' + on, getHandler(callback));
489        }
490    };
491
492    /**
493     * Returns the value of form element.
494     */
495    Nette.getValue = function (elem) {
496        var i;
497        if (!elem) {
498            return null;
499
500        } else if (!elem.tagName) { // RadioNodeList, HTMLCollection, array
501            return elem[0] ? Nette.getValue(elem[0]) : null;
502
503        } else if (elem.type === 'radio') {
504            var elements = elem.form.elements; // prevents problem with name 'item' or 'namedItem'
505            for (i = 0; i < elements.length; i++) {
506                if (elements[i].name === elem.name && elements[i].checked) {
507                    return elements[i].value;
508                }
509            }
510            return null;
511
512        } else if (elem.type === 'file') {
513            return elem.files || elem.value;
514
515        } else if (elem.tagName.toLowerCase() === 'select') {
516            var index = elem.selectedIndex,
517                options = elem.options,
518                values = [];
519
520            if (elem.type === 'select-one') {
521                return index < 0 ? null : options[index].value;
522            }
523
524            for (i = 0; i < options.length; i++) {
525                if (options[i].selected) {
526                    values.push(options[i].value);
527                }
528            }
529            return values;
530
531        } else if (elem.name && elem.name.match(/\[\]$/)) { // multiple elements []
532            elements = elem.form.elements[elem.name].tagName ? [elem] : elem.form.elements[elem.name];
533            values = [];
534
535            for (i = 0; i < elements.length; i++) {
536                // LiveForm: original netteForms.js code
537                /*if (elements[i].type !== 'checkbox' || elements[i].checked) {
538                    values.push(elements[i].value);
539                }*/
540                // LiveForm: addition
541                var value = elements[i].value;
542                if (elements[i].type === 'checkbox' && elements[i].checked) {
543                    values.push(value);
544                } else if (elements[i].type !== 'checkbox' && value !== '') {
545                    values.push(value);
546                }
547            }
548            return values;
549
550        } else if (elem.type === 'checkbox') {
551            return elem.checked;
552
553        } else if (elem.tagName.toLowerCase() === 'textarea') {
554            return elem.value.replace('\r', '');
555
556        } else {
557            return elem.value.replace('\r', '').replace(/^\s+|\s+$/g, '');
558        }
559    };
560
561
562    /**
563     * Returns the effective value of form element.
564     */
565    Nette.getEffectiveValue = function (elem, filter) {
566        var val = Nette.getValue(elem);
567        if (elem.getAttribute) {
568            if (val === elem.getAttribute('data-nette-empty-value')) {
569                val = '';
570            }
571        }
572        if (filter && preventFiltering[elem.name] === undefined) {
573            preventFiltering[elem.name] = true;
574            var ref = {value: val};
575            Nette.validateControl(elem, null, true, ref);
576            val = ref.value;
577            delete preventFiltering[elem.name];
578        }
579        return val;
580    };
581
582
583    /**
584     * Validates form element against given rules.
585     */
586    Nette.validateControl = function (elem, rules, onlyCheck, value, emptyOptional) {
587        // LiveForm: addition
588        // Fix for CheckboxList - validation rules are present always only on first input
589        if (elem.name && elem.name.match(/\[\]$/) && elem.type.toLowerCase() == 'checkbox') {
590            elem = elem.form.elements[elem.name].tagName ? elem : elem.form.elements[elem.name][0];
591        }
592
593        elem = elem.tagName ? elem : elem[0]; // RadioNodeList
594        rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
595        value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
596        emptyOptional = emptyOptional || !Nette.validateRule(elem, ':filled', null, value);
597
598        for (var id = 0, len = rules.length; id < len; id++) {
599            var rule = rules[id],
600                op = rule.op.match(/(~)?([^?]+)/),
601                curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
602
603            rule.neg = op[1];
604            rule.op = op[2];
605            rule.condition = !!rule.rules;
606
607            if (!curElem) {
608                continue;
609            } else if (emptyOptional && !rule.condition && rule.op !== ':filled') {
610                continue;
611            }
612
613            curElem = curElem.tagName ? curElem : curElem[0]; // RadioNodeList
614            var success = Nette.validateRule(curElem, rule.op, rule.arg, elem === curElem ? value : undefined);
615
616            if (success === null) {
617                continue;
618            } else if (rule.neg) {
619                success = !success;
620            }
621
622            if (rule.condition && success) {
623                if (!Nette.validateControl(elem, rule.rules, onlyCheck, value, rule.op === ':blank' ? false : emptyOptional)) {
624                    return false;
625                }
626            } else if (!rule.condition && !success) {
627                if (Nette.isDisabled(curElem)) {
628                    continue;
629                }
630                if (!onlyCheck) {
631                    var arr = Array.isArray(rule.arg) ? rule.arg : [rule.arg],
632                        message = rule.msg.replace(/%(value|\d+)/g, function (foo, m) {
633                            return Nette.getValue(m === 'value' ? curElem : elem.form.elements.namedItem(arr[m].control));
634                        });
635                    Nette.addError(curElem, message);
636                }
637                return false;
638            }
639        }
640
641        if (elem.type === 'number' && !elem.validity.valid) {
642            if (!onlyCheck) {
643                Nette.addError(elem, 'Please enter a valid value.');
644            }
645            return false;
646        }
647
648        // LiveForm: addition
649        if (!onlyCheck) {
650            LiveForm.removeError(elem);
651        }
652
653        return true;
654    };
655
656
657    /**
658     * Validates whole form.
659     */
660    Nette.validateForm = function (sender, onlyCheck) {
661        var form = sender.form || sender,
662            scope = false;
663
664        // LiveForm: addition
665        LiveForm.setFormProperty(form, "hasError", false);
666
667        // LiveForm: original netteForms.js code
668        // Nette.formErrors = [];
669
670        if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) {
671            var scopeArr = JSON.parse(form['nette-submittedBy'].getAttribute('data-nette-validation-scope') || '[]');
672            if (scopeArr.length) {
673                scope = new RegExp('^(' + scopeArr.join('-|') + '-)');
674            } else {
675                // LiveForm: original netteForms.js code
676                // Nette.showFormErrors(form, []);
677                return true;
678            }
679        }
680
681        var radios = {}, i, elem;
682        // LiveForm: addition
683        var success = true;
684
685        for (i = 0; i < form.elements.length; i++) {
686            elem = form.elements[i];
687
688            if (elem.tagName && !(elem.tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1})) {
689                continue;
690
691            } else if (elem.type === 'radio') {
692                if (radios[elem.name]) {
693                    continue;
694                }
695                radios[elem.name] = true;
696            }
697
698            if ((scope && !elem.name.replace(/]\[|\[|]|$/g, '-').match(scope)) || Nette.isDisabled(elem)) {
699                continue;
700            }
701
702            // LiveForm: addition
703            success = Nette.validateControl(elem) && success;
704            if (!success && !LiveForm.options.showAllErrors) {
705                break;
706            }
707            // LiveForm: original netteForms.js code
708            /*if (!Nette.validateControl(elem, null, onlyCheck) && !Nette.formErrors.length) {
709                return false;
710            }*/
711        }
712
713        // LiveForm: change
714        return success;
715
716        // LiveForm: original netteForms.js code
717        /*var success = !Nette.formErrors.length;
718        Nette.showFormErrors(form, Nette.formErrors);
719        return success;*/
720    };
721
722
723    /**
724     * Check if input is disabled.
725     */
726    Nette.isDisabled = function (elem) {
727        if (elem.type === 'radio') {
728            for (var i = 0, elements = elem.form.elements; i < elements.length; i++) {
729                if (elements[i].name === elem.name && !elements[i].disabled) {
730                    return false;
731                }
732            }
733            return true;
734        }
735        return elem.disabled;
736    };
737
738
739    // LiveForm: change
740    /**
741     * Display error message.
742     */
743    Nette.addError = function (elem, message) {
744        // LiveForm: addition
745        var noLiveValidation = LiveForm.hasClass(elem, LiveForm.options.disableLiveValidationClass);
746        // User explicitly disabled live-validation so we want to show simple alerts
747        if (noLiveValidation) {
748            // notify errors for elements with disabled live validation (but only errors and not during onLoadValidation)
749            if (message && !LiveForm.getFormProperty(elem.form, "hasError") && !LiveForm.getFormProperty(elem.form, "onLoadValidation")) {
750                alert(message);
751            }
752        }
753        if (elem.focus && !LiveForm.getFormProperty(elem.form, "hasError")) {
754            if (!LiveForm.focusing) {
755                LiveForm.focusing = true;
756                elem.focus();
757                setTimeout(function () {
758                    LiveForm.focusing = false;
759
760                    // Scroll by defined offset (if enabled)
761                    // NOTE: We use it with setTimetout because IE9 doesn't always catch instant scrollTo request
762                    var focusOffsetY = LiveForm.options.focusScreenOffsetY;
763                    if (focusOffsetY !== false && elem.getBoundingClientRect().top < focusOffsetY) {
764                        window.scrollBy(0, elem.getBoundingClientRect().top - focusOffsetY);
765                    }
766                }, 10);
767            }
768        }
769        if (!noLiveValidation) {
770            LiveForm.addError(elem, message);
771        }
772    };
773
774
775    // LiveForm: original netteForms.js code
776    /*/!**
777     * Adds error message to the queue.
778     *!/
779    Nette.addError = function(elem, message) {
780        Nette.formErrors.push({
781            element: elem,
782            message: message
783        });
784    };*/
785
786
787    // LiveForm: original netteForms.js code
788    /*/!**
789     * Display error messages.
790     *!/
791    Nette.showFormErrors = function(form, errors) {
792        var messages = [],
793            focusElem;
794        for (var i = 0; i < errors.length; i++) {
795            var elem = errors[i].element,
796                message = errors[i].message;
797            if (messages.indexOf(message) < 0) {
798                messages.push(message);
799                if (!focusElem && elem.focus) {
800                    focusElem = elem;
801                }
802            }
803        }
804        if (messages.length) {
805            alert(messages.join('\n'));
806            if (focusElem) {
807                focusElem.focus();
808            }
809        }
810    };*/
811
812
813    /**
814     * Validates single rule.
815     */
816    Nette.validateRule = function (elem, op, arg, value) {
817        value = value === undefined ? {value: Nette.getEffectiveValue(elem, true)} : value;
818
819        if (op.charAt(0) === ':') {
820            op = op.substr(1);
821        }
822        op = op.replace('::', '_');
823        op = op.replace(/\\/g, '');
824
825        var arr = Array.isArray(arg) ? arg.slice(0) : [arg];
826        for (var i = 0, len = arr.length; i < len; i++) {
827            if (arr[i] && arr[i].control) {
828                var control = elem.form.elements.namedItem(arr[i].control);
829                arr[i] = control === elem ? value.value : Nette.getEffectiveValue(control, true);
830            }
831        }
832
833        return Nette.validators[op]
834            ? Nette.validators[op](elem, Array.isArray(arg) ? arr : arr[0], value.value, value)
835            : null;
836    };
837
838
839    Nette.validators = {
840        filled: function (elem, arg, val) {
841            if (elem.type === 'number' && elem.validity.badInput) {
842                return true;
843            }
844            return val !== '' && val !== false && val !== null
845                && (!Array.isArray(val) || !!val.length)
846                && (!window.FileList || !(val instanceof window.FileList) || val.length);
847        },
848
849        blank: function (elem, arg, val) {
850            return !Nette.validators.filled(elem, arg, val);
851        },
852
853        valid: function (elem) {
854            return Nette.validateControl(elem, null, true);
855        },
856
857        equal: function (elem, arg, val) {
858            if (arg === undefined) {
859                return null;
860            }
861
862            function toString(val) {
863                if (typeof val === 'number' || typeof val === 'string') {
864                    return '' + val;
865                } else {
866                    return val === true ? '1' : '';
867                }
868            }
869
870            val = Array.isArray(val) ? val : [val];
871            arg = Array.isArray(arg) ? arg : [arg];
872            loop:
873                for (var i1 = 0, len1 = val.length; i1 < len1; i1++) {
874                    for (var i2 = 0, len2 = arg.length; i2 < len2; i2++) {
875                        if (toString(val[i1]) === toString(arg[i2])) {
876                            continue loop;
877                        }
878                    }
879                    return false;
880                }
881            return true;
882        },
883
884        notEqual: function (elem, arg, val) {
885            return arg === undefined ? null : !Nette.validators.equal(elem, arg, val);
886        },
887
888        minLength: function (elem, arg, val) {
889            if (elem.type === 'number') {
890                if (elem.validity.tooShort) {
891                    return false;
892                } else if (elem.validity.badInput) {
893                    return null;
894                }
895            }
896            return val.length >= arg;
897        },
898
899        maxLength: function (elem, arg, val) {
900            if (elem.type === 'number') {
901                if (elem.validity.tooLong) {
902                    return false;
903                } else if (elem.validity.badInput) {
904                    return null;
905                }
906            }
907            return val.length <= arg;
908        },
909
910        length: function (elem, arg, val) {
911            if (elem.type === 'number') {
912                if (elem.validity.tooShort || elem.validity.tooLong) {
913                    return false;
914                } else if (elem.validity.badInput) {
915                    return null;
916                }
917            }
918            arg = Array.isArray(arg) ? arg : [arg, arg];
919            return (arg[0] === null || val.length >= arg[0]) && (arg[1] === null || val.length <= arg[1]);
920        },
921
922        email: function (elem, arg, val) {
923            return (/^("([ !#-[\]-~]|\\[ -~])+"|[-a-z0-9!#$%&'*+/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*)@([0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)+[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?$/i).test(val);
924        },
925
926        url: function (elem, arg, val, value) {
927            if (!(/^[a-z\d+.-]+:/).test(val)) {
928                val = 'http://' + val;
929            }
930            if ((/^https?:\/\/((([-_0-9a-z\u00C0-\u02FF\u0370-\u1EFF]+\.)*[0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)?[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[0-9a-f:]{3,39}\])(:\d{1,5})?(\/\S*)?$/i).test(val)) {
931                value.value = val;
932                return true;
933            }
934            return false;
935        },
936
937        regexp: function (elem, arg, val) {
938            var parts = typeof arg === 'string' ? arg.match(/^\/(.*)\/([imu]*)$/) : false;
939            try {
940                return parts && (new RegExp(parts[1], parts[2].replace('u', ''))).test(val);
941            } catch (e) {
942            } // eslint-disable-line no-empty
943        },
944
945        pattern: function (elem, arg, val, value, caseInsensitive) {
946            if (typeof arg !== 'string') {
947                return null;
948            }
949
950            try {
951                try {
952                    var regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'ui' : 'u');
953                } catch (e) {
954                    regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'i' : '');
955                }
956
957                if (window.FileList && val instanceof FileList) {
958                    for (var i = 0; i < val.length; i++) {
959                        if (!regExp.test(val[i].name)) {
960                            return false;
961                        }
962                    }
963
964                    return true;
965                }
966
967                return regExp.test(val);
968            } catch (e) {
969            } // eslint-disable-line no-empty
970        },
971
972        patternCaseInsensitive: function (elem, arg, val) {
973            return Nette.validators.pattern(elem, arg, val, null, true);
974        },
975
976        numeric: function (elem, arg, val) {
977            if (elem.type === 'number' && elem.validity.badInput) {
978                return false;
979            }
980            return (/^[0-9]+$/).test(val);
981        },
982
983        integer: function (elem, arg, val) {
984            if (elem.type === 'number' && elem.validity.badInput) {
985                return false;
986            }
987            return (/^-?[0-9]+$/).test(val);
988        },
989
990        'float': function (elem, arg, val, value) {
991            if (elem.type === 'number' && elem.validity.badInput) {
992                return false;
993            }
994            val = val.replace(/ +/g, '').replace(/,/g, '.');
995            if ((/^-?[0-9]*\.?[0-9]+$/).test(val)) {
996                value.value = val;
997                return true;
998            }
999            return false;
1000        },
1001
1002        min: function (elem, arg, val) {
1003            if (elem.type === 'number') {
1004                if (elem.validity.rangeUnderflow) {
1005                    return false;
1006                } else if (elem.validity.badInput) {
1007                    return null;
1008                }
1009            }
1010            return arg === null || parseFloat(val) >= arg;
1011        },
1012
1013        max: function (elem, arg, val) {
1014            if (elem.type === 'number') {
1015                if (elem.validity.rangeOverflow) {
1016                    return false;
1017                } else if (elem.validity.badInput) {
1018                    return null;
1019                }
1020            }
1021            return arg === null || parseFloat(val) <= arg;
1022        },
1023
1024        range: function (elem, arg, val) {
1025            if (elem.type === 'number') {
1026                if (elem.validity.rangeUnderflow || elem.validity.rangeOverflow) {
1027                    return false;
1028                } else if (elem.validity.badInput) {
1029                    return null;
1030                }
1031            }
1032            return Array.isArray(arg) ?
1033                ((arg[0] === null || parseFloat(val) >= arg[0]) && (arg[1] === null || parseFloat(val) <= arg[1])) : null;
1034        },
1035
1036        submitted: function (elem) {
1037            return elem.form['nette-submittedBy'] === elem;
1038        },
1039
1040        fileSize: function (elem, arg, val) {
1041            if (window.FileList) {
1042                for (var i = 0; i < val.length; i++) {
1043                    if (val[i].size > arg) {
1044                        return false;
1045                    }
1046                }
1047            }
1048            return true;
1049        },
1050
1051        image: function (elem, arg, val) {
1052            if (window.FileList && val instanceof window.FileList) {
1053                for (var i = 0; i < val.length; i++) {
1054                    var type = val[i].type;
1055                    if (type && type !== 'image/gif' && type !== 'image/png' && type !== '
1055image/jpeg') {
1056                        return false;
1057                    }
1058                }
1059            }
1060            return true;
1061        },
1062
1063        'static': function (elem, arg) {
1064            return arg;
1065        }
1066    };
1067
1068
1069    /**
1070     * Process all toggles in form.
1071     */
1072    Nette.toggleForm = function (form, elem) {
1073        var i;
1074        formToggles = {};
1075        for (i = 0; i < form.elements.length; i++) {
1076            if (form.elements[i].tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
1077                Nette.toggleControl(form.elements[i], null, null, !elem);
1078            }
1079        }
1080
1081        for (i in formToggles) {
1082            Nette.toggle(i, formToggles[i], elem);
1083        }
1084    };
1085
1086
1087    /**
1088     * Process toggles on form element.
1089     */
1090    Nette.toggleControl = function (elem, rules, success, firsttime, value) {
1091        rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
1092        value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
1093
1094        var has = false,
1095            handled = [],
1096            handler = function () {
1097                Nette.toggleForm(elem.form, elem);
1098            },
1099            curSuccess;
1100
1101        for (var id = 0, len = rules.length; id < len; id++) {
1102            var rule = rules[id],
1103                op = rule.op.match(/(~)?([^?]+)/),
1104                curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
1105
1106            if (!curElem) {
1107                continue;
1108            }
1109
1110            curSuccess = success;
1111            if (success !== false) {
1112                rule.neg = op[1];
1113                rule.op = op[2];
1114                curSuccess = Nette.validateRule(curElem, rule.op, rule.arg, elem === curElem ? value : undefined);
1115                if (curSuccess === null) {
1116                    continue;
1117
1118                } else if (rule.neg) {
1119                    curSuccess = !curSuccess;
1120                }
1121                if (!rule.rules) {
1122                    success = curSuccess;
1123                }
1124            }
1125
1126            if ((rule.rules && Nette.toggleControl(elem, rule.rules, curSuccess, firsttime, value)) || rule.toggle) {
1127                has = true;
1128                if (firsttime) {
1129                    var name = curElem.tagName ? curElem.name : curElem[0].name,
1130                        els = curElem.tagName ? curElem.form.elements : curElem;
1131
1132                    for (var i = 0; i < els.length; i++) {
1133                        if (els[i].name === name && handled.indexOf(els[i]) < 0) {
1134                            els[i].addEventListener('change', handler);
1135                            handled.push(els[i]);
1136                        }
1137                    }
1138                }
1139                for (var id2 in rule.toggle || []) {
1140                    if (Object.prototype.hasOwnProperty.call(rule.toggle, id2)) {
1141                        formToggles[id2] = formToggles[id2] || (rule.toggle[id2] ? curSuccess : !curSuccess);
1142                    }
1143                }
1144            }
1145        }
1146        return has;
1147    };
1148
1149
1150    /**
1151     * Displays or hides HTML element.
1152     */
1153    Nette.toggle = function (selector, visible, srcElement) { // eslint-disable-line no-unused-vars
1154        if (/^\w[\w.:-]*$/.test(selector)) { // id
1155            selector = '#' + selector;
1156        }
1157        var elems = document.querySelectorAll(selector);
1158        for (var i = 0; i < elems.length; i++) {
1159            elems[i].hidden = !visible;
1160        }
1161    };
1162
1163
1164    /**
1165     * Setup handlers.
1166     */
1167    Nette.initForm = function (form) {
1168        Nette.toggleForm(form);
1169
1170        if (form.noValidate) {
1171            return;
1172        }
1173
1174        form.noValidate = true;
1175
1176        // LiveForm: addition
1177        LiveForm.forms[form.id] = {
1178            hasError: false,
1179            onLoadValidation: false
1180        };
1181
1182        form.addEventListener('submit', function (e) {
1183            if (!Nette.validateForm(form)) {
1184                e.stopPropagation();
1185                e.preventDefault();
1186            }
1187        });
1188
1189        // LiveForm: addition
1190        for (var i = 0; i < form.elements.length; i++) {
1191            LiveForm.setupHandlers(form.elements[i]);
1192            LiveForm.processServerErrors(form.elements[i]);
1193        }
1194    };
1195
1196    /**
1197     * @private
1198     */
1199    Nette.initOnLoad = function () {
1200        Nette.addEvent(document, 'DOMContentLoaded', function () {
1201            // LiveForm: original netteForms.js code
1202            /*
1203                    for (var i = 0; i < document.forms.length; i++) {
1204                        var form = document.forms[i];
1205                        for (var j = 0; j < form.elements.length; j++) {
1206                            if (form.elements[j].getAttribute('data-nette-rules')) {
1207                                Nette.initForm(form);
1208                                break;
1209                            }
1210                        }
1211                    }
1212                    Nette.addEvent(document.body, 'click', function(e) {
1213                        var target = e.target || e.srcElement;
1214                        if (target.form && target.type in {submit: 1, image: 1}) {
1215                            target.form['nette-submittedBy'] = target;
1216                        }
1217                    });
1218            */
1219            // LiveForm: addition
1220            Nette.init();
1221        });
1222    };
1223
1224    // LiveForm: addition
1225    /**
1226     * Init function to be called in case usage as module
1227     *
1228     * @public
1229     */
1230    Nette.init = function () {
1231        for (var i = 0; i < document.forms.length; i++) {
1232            var form = document.forms[i];
1233            for (var j = 0; j < form.elements.length; j++) {
1234                if (form.elements[j].getAttribute('data-nette-rules')) {
1235                    Nette.initForm(form);
1236
1237                    if (LiveForm.hasClass(form, 'validate-on-load')) {
1238                        // This is not so nice way, but I don't want to spoil validateForm, validateControl and other methods with another parameter
1239                        LiveForm.setFormProperty(form, "onLoadValidation", true);
1240                        Nette.validateForm(form);
1241                        LiveForm.setFormProperty(form, "onLoadValidation", false);
1242                    }
1243
1244                    break;
1245                }
1246            }
1247        }
1248
1249        Nette.addEvent(document.body, 'click', function (e) {
1250            var target = e.target || e.srcElement;
1251            if (target.form && target.type in {submit: 1, image: 1}) {
1252                target.form['nette-submittedBy'] = target;
1253            }
1254        });
1255    };
1256
1257
1258    /**
1259     * Determines whether the argument is an array.
1260     */
1261    Nette.isArray = function (arg) {
1262        return Object.prototype.toString.call(arg) === '[object Array]';
1263    };
1264
1265
1266    /**
1267     * Search for a specified value within an array.
1268     */
1269    Nette.inArray = function (arr, val) {
1270        if ([].indexOf) {
1271            return arr.indexOf(val) > -1;
1272        } else {
1273            for (var i = 0; i < arr.length; i++) {
1274                if (arr[i] === val) {
1275                    return true;
1276                }
1277            }
1278            return false;
1279        }
1280    };
1281
1282
1283    /**
1284     * Converts string to web safe characters [a-z0-9-] text.
1285     */
1286    Nette.webalize = function (s) {
1287        s = s.toLowerCase();
1288        var res = '', i, ch;
1289        for (i = 0; i < s.length; i++) {
1290            ch = Nette.webalizeTable[s.charAt(i)];
1291            res += ch ? ch : s.charAt(i);
1292        }
1293        return res.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
1294    };
1295
1296    Nette.webalizeTable = {\u00e1: 'a', \u00e4: 'a', \u010d: 'c', \u010f: 'd', \u00e9: 'e', \u011b: 'e', \u00ed: 'i', \u013e: 'l', \u0148: 'n', \u00f3: 'o', \u00f4: 'o', \u0159: 'r', \u0161: 's', \u0165: 't', \u00fa: 'u', \u016f: 'u', \u00fd: 'y', \u017e: 'z'};
1297
1298    return Nette;
1299}));

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.