PageSourceSearch

https://www.asm.cz/js/live-form-validation.js

js asm.cz collected 2026-10-08 12:17:31 UTC 25,727 bytes, 981 lines download raw bytes

1/**
2 * Live Form Validation for Nette Forms 2.3
3 *
4 * @author Robert Pösel, zakrava, Radek Ježdík, MartyIX, David Grudl
5 * @version 1.6.0
6 * @url https://github.com/Robyer/nette-live-form-validation/
7 */
8
9var LiveForm = {
10	options: {
11		// CSS class of control's parent where error/valid class should be added; or "false" to use control directly
12		showMessageClassOnParent: 'form-group',
13
14		// CSS class for an invalid control
15		controlErrorClass: 'has-error',
16
17		// CSS class for a valid control
18		controlValidClass: 'has-success',
19
20		// CSS class for an error message
21		messageErrorClass: 'help-block text-danger',
22
23		// 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)
24		enableHiddenMessageClass: 'show-hidden-error',
25
26		// control with this CSS class will have disabled live validation
27		disableLiveValidationClass: 'no-live-validation',
28
29		// control with this CSS class will not show valid message
30		disableShowValidClass: 'no-show-valid',
31
32		// tag that will hold the error/valid message
33		messageTag: 'span',
34
35		// message element id = control id + this postfix
36		messageIdPostfix: '_message',
37
38		// show this html before error message itself
39		messageErrorPrefix: '&nbsp;<i class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></i>&nbsp;',
40
41		// show all errors when submitting form; or use "false" to show only first error
42		showAllErrors: true,
43
44		// show message when valid
45		showValid: false,
46
47		// delay in ms before validating on keyup/keydown; or use "false" to disable it
48		wait: false
49	},
50
51	forms: { }
52};
53
54LiveForm.isSpecialKey = function(k) {
55	// http://stackoverflow.com/questions/7770561/jquery-javascript-reject-control-keys-on-keydown-event
56	return (k == 20 /* Caps lock */
57		|| k == 16 /* Shift */
58		|| k == 9 /* Tab */
59		|| k == 27 /* Escape Key */
60		|| k == 17 /* Control Key */
61		|| k == 91 /* Windows Command Key */
62		|| k == 19 /* Pause Break */
63		|| k == 18 /* Alt Key */
64		|| k == 93 /* Right Click Point Key */
65		|| (k >= 35 && k <= 40) /* Home, End, Arrow Keys */
66		|| k == 45 /* Insert Key */
67		|| (k >= 33 && k <= 34) /*Page Down, Page Up */
68		|| (k >= 112 && k <= 123) /* F1 - F12 */
69		|| (k >= 144 && k <= 145)); /* Num Lock, Scroll Lock */
70}
71
72/**
73 * Handlers for all the events that trigger validation
74 * YOU CAN CHANGE these handlers (ie. to use jQuery events instead)
75 */
76LiveForm.setupHandlers = function(el) {
77	if (this.hasClass(el, this.options.disableLiveValidationClass))
78		return;
79
80	// Check if element was already initialized
81	if (el.getAttribute("data-lfv-initialized"))
82		return;
83
84	// Remember we initialized this element so we won't do it again
85	el.setAttribute('data-lfv-initialized', 'true');
86
87	var handler = function(event) {
88		event = event || window.event;
89		Nette.validateControl(event.target ? event.target : event.srcElement);
90	};
91
92	var self = this;
93
94	Nette.addEvent(el, "change", handler);
95	Nette.addEvent(el, "blur", handler);
96	Nette.addEvent(el, "keydown", function (event) {
97		if (!self.isSpecialKey(event.which) && (self.options.wait === false || self.options.wait >= 200)) {
98			// Hide validation span tag.
99			self.removeClass(self.getGroupElement(this), self.options.controlErrorClass);
100			self.removeClass(self.getGroupElement(this), self.options.controlValidClass);
101
102			var messageEl = self.getMessageElement(this);
103			messageEl.innerHTML = '';
104			messageEl.className = '';
105
106			// Cancel timeout to run validation handler
107			if (self.timeout) {
108				clearTimeout(self.timeout);
109			}
110		}
111	});
112	Nette.addEvent(el, "keyup", function(event) {
113		if (self.options.wait !== false) {
114			event = event || window.event;
115			if (event.keyCode !== 9) {
116				if (self.timeout) clearTimeout(self.timeout);
117					self.timeout = setTimeout(function() {
118					handler(event);
119				}, self.options.wait);
120			}
121		}
122	});
123};
124
125LiveForm.processServerErrors = function(el) {
126	var messageEl = this.getMessageElement(el);
127	var parentEl = this.getMessageParent(el); // This is parent element which contain the error elements
128
129	var errors = [];
130
131	// Find existing error elements by class (from server-validation)
132	var errorEls = parentEl.getElementsByClassName(this.options.messageErrorClass);
133	for (var i = errorEls.length - 1; i > -1; i--) {
134		// Don't touch our main message element
135		if (errorEls[i] == messageEl)
136			continue;
137
138		// Remove only direct children
139		var errorParent = errorEls[i].parentNode;
140		if (errorParent == parentEl) {
141			errors.push(errorEls[i].outerHTML);
142			errorParent.removeChild(errorEls[i]);
143		}
144	}
145
146	// Wrap all server errors into one element
147	if (errors.length > 0) {
148		messageEl.innerHTML = errors.join("");
149	}
150};
151
152LiveForm.addError = function(el, message) {
153	// Ignore elements with disabled live validation
154	if (this.hasClass(el, this.options.disableLiveValidationClass))
155		return;
156
157	this.setFormProperty(el.form, "hasError", true);
158	this.addClass(this.getGroupElement(el), this.options.controlErrorClass);
159
160	if (this.options.showValid && this.showValid(el)) {
161		this.removeClass(this.getGroupElement(el), this.options.controlValidClass);
162	}
163
164	if (!message) {
165		message = '&nbsp;';
166	} else {
167		message = this.options.messageErrorPrefix + message;
168	}
169
170	var messageEl = this.getMessageElement(el);
171	messageEl.innerHTML = message;
172	messageEl.className = this.options.messageErrorClass;
173};
174
175LiveForm.removeError = function(el) {
176	// We don't want to remove any errors during onLoadValidation
177	if (this.getFormProperty(el.form, "onLoadValidation"))
178		return;
179
180	var groupEl = this.getGroupElement(el);
181	this.removeClass(groupEl, this.options.controlErrorClass);
182
183	var id = el.getAttribute('data-lfv-message-id');
184	if (id) {
185		var messageEl = this.getMessageElement(el);
186		messageEl.innerHTML = '';
187		messageEl.className = '';
188	}
189
190	if (this.options.showValid && this.showValid(el)) {
191		this.addClass(groupEl, this.options.controlValidClass);
192		return;
193	}
194};
195
196LiveForm.showValid = function(el) {
197	if (el.type) {
198		var type = el.type.toLowerCase();
199		if (type == 'checkbox' || type == 'radio') {
200			return false;
201		}
202	}
203
204	var rules = Nette.parseJSON(el.getAttribute('data-nette-rules'));
205	if (rules.length == 0) {
206		return false;
207	}
208
209	if (this.hasClass(el, this.options.disableShowValidClass)) {
210		return false;
211	}
212
213	return true;
214};
215
216LiveForm.getGroupElement = function(el) {
217	if (this.options.showMessageClassOnParent === false)
218		return el;
219
220	var groupEl = el;
221
222	while (!this.hasClass(groupEl, this.options.showMessageClassOnParent)) {
223		groupEl = groupEl.parentNode;
224
225		if (groupEl === null) {
226			return el;
227		}
228	}
229
230	return groupEl;
231}
232
233LiveForm.getMessageElement = function(el) {
234	var id = el.getAttribute('data-lfv-message-id');
235	if (!id) {
236		// Id is not specified yet, let's create a new one
237		id = el.id + this.options.messageIdPostfix;
238
239		var i = 0;
240		while (document.getElementById(id)) {
241			// We want unique ID which doesn't exist yet
242			id = el.id + this.options.messageIdPostfix + '_' + ++i;
243		}
244
245		// Remember this id for next use
246		el.setAttribute('data-lfv-message-id', id);
247	}
248
249	var messageEl = document.getElementById(id);
250	if (!messageEl) {
251		// Message element doesn't exist, lets create a new one
252		messageEl = document.createElement(this.options.messageTag);
253		messageEl.id = id;
254		if (el.style.display == 'none' && !this.hasClass(el, this.options.enableHiddenMessageClass)) {
255			messageEl.style.display = 'none';
256		}
257
258		var parentEl = this.getMessageParent(el);
259		if (parentEl) {
260			parentEl.appendChild(messageEl);
261		}
262	}
263
264	return messageEl;
265};
266
267LiveForm.getMessageParent = function(el) {
268	var parentEl = el.parentNode;
269
270	// Don't append error message to radio/checkbox input's label, but along label
271	if (el.type) {
272		var type = el.type.toLowerCase();
273		if ((type == 'checkbox' || type == 'radio') && parentEl.tagName == 'LABEL') {
274			parentEl = parentEl.parentNode;
275		}
276	}
277
278	return parentEl;
279}
280
281LiveForm.addClass = function(el, className) {
282	if (!el.className) {
283		el.className = className;
284	} else if (!this.hasClass(el, className)) {
285		el.className += ' ' + className;
286	}
287};
288
289LiveForm.hasClass = function(el, className) {
290	if (el.className)
291		return el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
292	return false;
293};
294
295LiveForm.removeClass = function(el, className) {
296	if (this.hasClass(el, className)) {
297		var reg = new RegExp('(\\s|^)'+ className + '(\\s|$)');
298		var m = el.className.match(reg);
299		el.className = el.className.replace(reg, (m[1] == ' ' && m[2] == ' ') ? ' ' : '');
300	}
301};
302
303LiveForm.getFormProperty = function(form, propertyName) {
304	if (form == null || this.forms[form.id] == null)
305		return false;
306
307	return this.forms[form.id][propertyName];
308};
309
310LiveForm.setFormProperty = function(form, propertyName, value) {
311	if (form == null)
312		return;
313
314	if (this.forms[form.id] == null)
315		this.forms[form.id] = {};
316
317	this.forms[form.id][propertyName] = value;
318};
319
320////////////////////////////   modified netteForms.js   ///////////////////////////////////
321
322/**
323 * NetteForms - simple form validation.
324 *
325 * This file is part of the Nette Framework (http://nette.org)
326 * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
327 */
328
329(function(global, factory) {
330	if (typeof define === 'function' && define.amd) {
331		define(function() {
332			return factory(global);
333		});
334	} else if (typeof module === 'object' && typeof module.exports === 'object') {
335		module.exports = factory(global);
336	} else {
337		global.Nette = factory(global);
338		global.Nette.initOnLoad();
339	}
340
341}(typeof window !== 'undefined' ? window : this, function(window) {
342
343'use strict';
344
345var Nette = {};
346
347/**
348 * Attaches a handler to an event for the element.
349 */
350Nette.addEvent = function(element, on, callback) {
351	var original = element['on' + on];
352	element['on' + on] = function() {
353		if (typeof original === 'function' && original.apply(element, arguments) === false) {
354			return false;
355		}
356		return callback.apply(element, arguments);
357	};
358};
359
360
361/**
362 * Returns the value of form element.
363 */
364Nette.getValue = function(elem) {
365	var i;
366	if (!elem) {
367		return null;
368
369	} else if (!elem.tagName) { // RadioNodeList, HTMLCollection, array
370		return elem[0] ? Nette.getValue(elem[0]) : null;
371
372	} else if (elem.type === 'radio') {
373		var elements = elem.form.elements; // prevents problem with name 'item' or 'namedItem'
374		for (i = 0; i < elements.length; i++) {
375			if (elements[i].name === elem.name && elements[i].checked) {
376				return elements[i].value;
377			}
378		}
379		return null;
380
381	} else if (elem.type === 'file') {
382		return elem.files || elem.value;
383
384	} else if (elem.tagName.toLowerCase() === 'select') {
385		var index = elem.selectedIndex,
386			options = elem.options,
387			values = [];
388
389		if (elem.type === 'select-one') {
390			return index < 0 ? null : options[index].value;
391		}
392
393		for (i = 0; i < options.length; i++) {
394			if (options[i].selected) {
395				values.push(options[i].value);
396			}
397		}
398		return values;
399
400	} else if (elem.name && elem.name.match(/\[\]$/)) { // multiple elements []
401		var elements = elem.form.elements[elem.name].tagName ? [elem] : elem.form.elements[elem.name],
402			values = [];
403
404		for (i = 0; i < elements.length; i++) {
405			if (elements[i].type !== 'checkbox' || elements[i].checked) {
406				values.push(elements[i].value);
407			}
408		}
409		return values;
410
411	} else if (elem.type === 'checkbox') {
412		return elem.checked;
413
414	} else if (elem.tagName.toLowerCase() === 'textarea') {
415		return elem.value.replace("\r", '');
416
417	} else {
418		return elem.value.replace("\r", '').replace(/^\s+|\s+$/g, '');
419	}
420};
421
422
423/**
424 * Returns the effective value of form element.
425 */
426Nette.getEffectiveValue = function(elem) {
427	var val = Nette.getValue(elem);
428	if (elem.getAttribute) {
429		if (val === elem.getAttribute('data-nette-empty-value')) {
430			val = '';
431		}
432	}
433	return val;
434};
435
436
437/**
438 * Validates form element against given rules.
439 */
440Nette.validateControl = function(elem, rules, onlyCheck, value) {
441	elem = elem.tagName ? elem : elem[0]; // RadioNodeList
442	rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
443	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
444
445	for (var id = 0, len = rules.length; id < len; id++) {
446		var rule = rules[id],
447			op = rule.op.match(/(~)?([^?]+)/),
448			curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
449
450		if (!curElem) {
451			continue;
452		}
453
454		rule.neg = op[1];
455		rule.op = op[2];
456		rule.condition = !!rule.rules;
457		curElem = curElem.tagName ? curElem : curElem[0]; // RadioNodeList
458
459		var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)},
460			success = Nette.validateRule(curElem, rule.op, rule.arg, curValue);
461
462		if (success === null) {
463			continue;
464		} else if (rule.neg) {
465			success = !success;
466		}
467
468		if (rule.condition && success) {
469			if (!Nette.validateControl(elem, rule.rules, onlyCheck, value)) {
470				return false;
471			}
472		} else if (!rule.condition && !success) {
473			if (Nette.isDisabled(curElem)) {
474				continue;
475			}
476			if (!onlyCheck) {
477				var arr = Nette.isArray(rule.arg) ? rule.arg : [rule.arg],
478					message = rule.msg.replace(/%(value|\d+)/g, function(foo, m) {
479						return Nette.getValue(m === 'value' ? curElem : elem.form.elements.namedItem(arr[m].control));
480					});
481				Nette.addError(curElem, message);
482			}
483			return false;
484		}
485	}
486
487	// LiveForm: addition
488	if (!onlyCheck) {
489		LiveForm.removeError(elem);
490	}
491
492	return true;
493};
494
495
496/**
497 * Validates whole form.
498 */
499Nette.validateForm = function(sender) {
500	var form = sender.form || sender,
501		scope = false;
502
503	// LiveForm: addition
504	LiveForm.setFormProperty(form, "hasError", false);
505
506	if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) {
507		var scopeArr = Nette.parseJSON(form['nette-submittedBy'].getAttribute('data-nette-validation-scope'));
508		if (scopeArr.length) {
509			scope = new RegExp('^(' + scopeArr.join('-|') + '-)');
510		} else {
511			return true;
512		}
513	}
514
515	// LiveForm: addition
516	var success = true;
517
518	var radios = {}, i, elem;
519
520	for (i = 0; i < form.elements.length; i++) {
521		elem = form.elements[i];
522
523		if (elem.tagName && !(elem.tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1})) {
524			continue;
525
526		} else if (elem.type === 'radio') {
527			if (radios[elem.name]) {
528				continue;
529			}
530			radios[elem.name] = true;
531		}
532
533		if ((scope && !elem.name.replace(/]\[|\[|]|$/g, '-').match(scope)) || Nette.isDisabled(elem)) {
534			continue;
535		}
536
537		if (!Nette.validateControl(elem)) {
538			// LiveForm: change
539			success = false;
540
541			// LiveForm: addition
542			if (!LiveForm.options.showAllErrors)
543				break;
544		}
545	}
546
547	// LiveForm: change
548	return success;
549};
550
551
552/**
553 * Check if input is disabled.
554 */
555Nette.isDisabled = function(elem) {
556	if (elem.type === 'radio') {
557		for (var i = 0, elements = elem.form.elements; i < elements.length; i++) {
558			if (elements[i].name === elem.name && !elements[i].disabled) {
559				return false;
560			}
561		}
562		return true;
563	}
564	return elem.disabled;
565};
566
567
568/**
569 * Display error message.
570 */
571Nette.addError = function(elem, message) {
572	// LiveForm: addition
573	var noLiveValidation = LiveForm.hasClass(elem, LiveForm.options.disableLiveValidationClass);
574	// User explicitly disabled live-validation so we want to show simple alerts
575	if (noLiveValidation) {
576		// notify errors for elements with disabled live validation (but only errors and not during onLoadValidation)
577		if (message && !LiveForm.getFormProperty(elem.form, "hasError") && !LiveForm.getFormProperty(elem.form, "onLoadValidation")) {
578			alert(message);
579		}
580	}
581	if (elem.focus && !LiveForm.getFormProperty(elem.form, "hasError")) {
582		if (!LiveForm.focusing) {
583			LiveForm.focusing = true;
584			elem.focus();
585			setTimeout(function() { LiveForm.focusing = false; }, 10);
586		}
587	}
588	if (!noLiveValidation) {
589		LiveForm.addError(elem, message);
590	}
591
592	// LiveForm: original netteForms.js code
593	/*
594	if (message) {
595		alert(message);
596	}
597	if (elem.focus) {
598		elem.focus();
599	}
600	*/
601};
602
603
604/**
605 * Expand rule argument.
606 */
607Nette.expandRuleArgument = function(form, arg) {
608	if (arg && arg.control) {
609		arg = Nette.getEffectiveValue(form.elements.namedItem(arg.control));
610	}
611	return arg;
612};
613
614
615/**
616 * Validates single rule.
617 */
618Nette.validateRule = function(elem, op, arg, value) {
619	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
620
621	if (op.charAt(0) === ':') {
622		op = op.substr(1);
623	}
624	op = op.replace('::', '_');
625	op = op.replace(/\\/g, '');
626
627	var arr = Nette.isArray(arg) ? arg.slice(0) : [arg];
628	for (var i = 0, len = arr.length; i < len; i++) {
629		arr[i] = Nette.expandRuleArgument(elem.form, arr[i]);
630	}
631	return Nette.validators[op]
632		? Nette.validators[op](elem, Nette.isArray(arg) ? arr : arr[0], value.value, value)
633		: null;
634};
635
636
637Nette.validators = {
638	filled: function(elem, arg, val) {
639		return val !== '' && val !== false && val !== null
640			&& (!Nette.isArray(val) || !!val.length)
641			&& (!window.FileList || !(val instanceof window.FileList) || val.length);
642	},
643
644	blank: function(elem, arg, val) {
645		return !Nette.validators.filled(elem, arg, val);
646	},
647
648	valid: function(elem, arg, val) {
649		return Nette.validateControl(elem, null, true);
650	},
651
652	equal: function(elem, arg, val) {
653		if (arg === undefined) {
654			return null;
655		}
656		val = Nette.isArray(val) ? val : [val];
657		arg = Nette.isArray(arg) ? arg : [arg];
658		loop:
659		for (var i1 = 0, len1 = val.length; i1 < len1; i1++) {
660			for (var i2 = 0, len2 = arg.length; i2 < len2; i2++) {
661				/* jshint eqeqeq: false */
662				if (val[i1] == arg[i2]) {
663					continue loop;
664				}
665			}
666			return false;
667		}
668		return true;
669	},
670
671	notEqual: function(elem, arg, val) {
672		return arg === undefined ? null : !Nette.validators.equal(elem, arg, val);
673	},
674
675	minLength: function(elem, arg, val) {
676		return val.length >= arg;
677	},
678
679	maxLength: function(elem, arg, val) {
680		return val.length <= arg;
681	},
682
683	length: function(elem, arg, val) {
684		arg = Nette.isArray(arg) ? arg : [arg, arg];
685		return (arg[0] === null || val.length >= arg[0]) && (arg[1] === null || val.length <= arg[1]);
686	},
687
688	email: function(elem, arg, val) {
689		return (/^("([ !\x23-\x5B\x5D-\x7E]*|\\[ -~])+"|[-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);
690	},
691
692	url: function(elem, arg, val, value) {
693		if (!(/^[a-z\d+.-]+:/).test(val)) {
694			val = 'http://' + val;
695		}
696		if ((/^https?:\/\/([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)) {
697			value.value = val;
698			return true;
699		}
700		return false;
701	},
702
703	regexp: function(elem, arg, val) {
704		var parts = typeof arg === 'string' ? arg.match(/^\/(.*)\/([imu]*)$/) : false;
705		try {
706			return parts && (new RegExp(parts[1], parts[2].replace('u', ''))).test(val);
707		} catch (e) {}
708	},
709
710	pattern: function(elem, arg, val) {
711		try {
712			return typeof arg === 'string' ? (new RegExp('^(' + arg + ')$')).test(val) : null;
713		} catch (e) {}
714	},
715
716	integer: function(elem, arg, val) {
717		return (/^-?[0-9]+$/).test(val);
718	},
719
720	'float': function(elem, arg, val, value) {
721		val = val.replace(' ', '').replace(',', '.');
722		if ((/^-?[0-9]*[.,]?[0-9]+$/).test(val)) {
723			value.value = val;
724			return true;
725		}
726		return false;
727	},
728
729	min: function(elem, arg, val) {
730		return Nette.validators.range(elem, [arg, null], val);
731	},
732
733	max: function(elem, arg, val) {
734		return Nette.validators.range(elem, [null, arg], val);
735	},
736
737	range: function(elem, arg, val) {
738		return Nette.isArray(arg) ?
739			((arg[0] === null || parseFloat(val) >= arg[0]) && (arg[1] === null || parseFloat(val) <= arg[1])) : null;
740	},
741
742	submitted: function(elem, arg, val) {
743		return elem.form['nette-submittedBy'] === elem;
744	},
745
746	fileSize: function(elem, arg, val) {
747		if (window.FileList) {
748			for (var i = 0; i < val.length; i++) {
749				if (val[i].size > arg) {
750					return false;
751				}
752			}
753		}
754		return true;
755	},
756
757	image: function (elem, arg, val) {
758		if (window.FileList && val instanceof window.FileList) {
759			for (var i = 0; i < val.length; i++) {
760				var type = val[i].type;
761				if (type && type !== 'image/gif' && type !== 'image/png' && type !== 'image/jpeg') {
762					return false;
763				}
764			}
765		}
766		return true;
767	}
768};
769
770
771/**
772 * Process all toggles in form.
773 */
774Nette.toggleForm = function(form, elem) {
775	var i;
776	Nette.toggles = {};
777	for (i = 0; i < form.elements.length; i++) {
778		if (form.elements[i].tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
779			Nette.toggleControl(form.elements[i], null, null, !elem);
780		}
781	}
782
783	for (i in Nette.toggles) {
784		Nette.toggle(i, Nette.toggles[i], elem);
785	}
786};
787
788
789/**
790 * Process toggles on form element.
791 */
792Nette.toggleControl = function(elem, rules, success, firsttime, value) {
793	rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
794	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
795
796	var has = false,
797		handled = [],
798		handler = function () {
799			Nette.toggleForm(elem.form, elem);
800		},
801		curSuccess;
802
803	for (var id = 0, len = rules.length; id < len; id++) {
804		var rule = rules[id],
805			op = rule.op.match(/(~)?([^?]+)/),
806			curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
807
808		if (!curElem) {
809			continue;
810		}
811
812		curSuccess = success;
813		if (success !== false) {
814			rule.neg = op[1];
815			rule.op = op[2];
816			var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)};
817			curSuccess = Nette.validateRule(curElem, rule.op, rule.arg, curValue);
818			if (curSuccess === null) {
819				continue;
820
821			} else if (rule.neg) {
822				curSuccess = !curSuccess;
823			}
824			if (!rule.rules) {
825				success = curSuccess;
826			}
827		}
828
829		if ((rule.rules && Nette.toggleControl(elem, rule.rules, curSuccess, firsttime, value)) || rule.toggle) {
830			has = true;
831			if (firsttime) {
832				var oldIE = !document.addEventListener, // IE < 9
833					name = curElem.tagName ? curElem.name : curElem[0].name,
834					els = curElem.tagName ? curElem.form.elements : curElem;
835
836				for (var i = 0; i < els.length; i++) {
837					if (els[i].name === name && !Nette.inArray(handled, els[i])) {
838						Nette.addEvent(els[i], oldIE && els[i].type in {checkbox: 1, radio: 1} ? 'click' : 'change', handler);
839						handled.push(els[i]);
840					}
841				}
842			}
843			for (var id2 in rule.toggle || []) {
844				if (Object.prototype.hasOwnProperty.call(rule.toggle, id2)) {
845					Nette.toggles[id2] = Nette.toggles[id2] || (rule.toggle[id2] ? curSuccess : !curSuccess);
846				}
847			}
848		}
849	}
850	return has;
851};
852
853
854Nette.parseJSON = function(s) {
855	s = s || '[]';
856	if (s.substr(0, 3) === '{op') {
857		return eval('[' + s + ']'); // backward compatibility
858	}
859	return window.JSON && window.JSON.parse ? JSON.parse(s) : eval(s);
860};
861
862
863/**
864 * Displays or hides HTML element.
865 */
866Nette.toggle = function(id, visible, srcElement) {
867	var elem = document.getElementById(id);
868	if (elem) {
869		elem.style.display = visible ? '' : 'none';
870	}
871};
872
873
874/**
875 * Setup handlers.
876 */
877Nette.initForm = function(form) {
878	
879
880	// LiveForm: addition
881	LiveForm.forms[form.id] = {
882		hasError: false,
883		onLoadValidation: false
884	};
885
886	Nette.addEvent(form, 'submit', function(e) {
887		if (!Nette.validateForm(form)) {
888			if (e && e.stopPropagation) {
889				e.stopPropagation();
890			} else if (window.event) {
891				event.cancelBubble = true;
892			}
893			return false;
894		}
895	});
896
897	Nette.addEvent(form, 'click', function(e) {
898		e = e || event;
899		var target = e.target || e.srcElement;
900		form['nette-submittedBy'] = (target.type in {submit: 1, image: 1}) ? target : null;
901	});
902
903	Nette.toggleForm(form);
904
905	// LiveForm: addition
906	for (var i = 0; i < form.elements.length; i++) {
907		LiveForm.setupHandlers(form.elements[i]);
908		LiveForm.processServerErrors(form.elements[i]);
909	}
910};
911
912
913/**
914 * @private
915 */
916Nette.initOnLoad = function() {
917	Nette.addEvent(window, 'load', function() {
918		for (var i = 0; i < document.forms.length; i++) {
919			var form = document.forms[i];
920			for (var j = 0; j < form.elements.length; j++) {
921				if (form.elements[j].getAttribute('data-nette-rules')) {
922					Nette.initForm(form);
923
924					// LiveForm: addition
925					if (LiveForm.hasClass(form, 'validate-on-load')) {
926						// This is not so nice way, but I don't want to spoil validateForm, validateControl and other methods with another parameter
927						LiveForm.setFormProperty(form, "onLoadValidation", true);
928						Nette.validateForm(form);
929						LiveForm.setFormProperty(form, "onLoadValidation", false);
930					}
931
932					break;
933				}
934			}
935		}
936	});
937};
938
939
940/**
941 * Determines whether the argument is an array.
942 */
943Nette.isArray = function(arg) {
944	return Object.prototype.toString.call(arg) === '[object Array]';
945};
946
947
948/**
949 * Search for a specified value within an array.
950 */
951Nette.inArray = function(arr, val) {
952	if ([].indexOf) {
953		return arr.indexOf(val) > -1;
954	} else {
955		for (var i = 0; i < arr.length; i++) {
956			if (arr[i] === val) {
957				return true;
958			}
959		}
960		return false;
961	}
962};
963
964
965/**
966 * Converts string to web safe characters [a-z0-9-] text.
967 */
968Nette.webalize = function(s) {
969	s = s.toLowerCase();
970	var res = '', i, ch;
971	for (i = 0; i < s.length; i++) {
972		ch = Nette.webalizeTable[s.charAt(i)];
973		res += ch ? ch : s.charAt(i);
974	}
975	return res.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
976};
977
978Nette.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'};
979
980return Nette;
981}));

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.