➔ Nette.validateControl   F
last analyzed

Complexity

Conditions 31
Paths 1944

Size

Total Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 72
c 0
b 0
f 0
cc 31
nc 1944
nop 5
rs 2.6624

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like live-form-validation.js ➔ ... ➔ Nette.validateControl often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * Live Form Validation for Nette Forms 2.4
3
 *
4
 * @author Robert Pösel, zakrava, Radek Ježdík, MartyIX, David Grudl
5
 * @version 1.9.0-dev
6
 * @url https://github.com/Robyer/nette-live-form-validation/
7
 */
8
9
var 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 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
15
		messageParentClass: false,
16
17
		// CSS class for an invalid control
18
		controlErrorClass: 'has-error',
19
20
		// CSS class for a valid control
21
		controlValidClass: 'has-success',
22
23
		// CSS class for an error message
24
		messageErrorClass: 'help-block text-danger',
25
26
		// 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)
27
		enableHiddenMessageClass: 'show-hidden-error',
28
29
		// control with this CSS class will have disabled live validation
30
		disableLiveValidationClass: 'no-live-validation',
31
32
		// control with this CSS class will not show valid message
33
		disableShowValidClass: 'no-show-valid',
34
35
		// tag that will hold the error/valid message
36
		messageTag: 'span',
37
38
		// message element id = control id + this postfix
39
		messageIdPostfix: '_message',
40
41
		// show this html before error message itself
42
		messageErrorPrefix: '&nbsp;<i class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></i>&nbsp;',
43
44
		// show all errors when submitting form; or use "false" to show only first error
45
		showAllErrors: true,
46
47
		// show message when valid
48
		showValid: false,
49
50
		// delay in ms before validating on keyup/keydown; or use "false" to disable it
51
		wait: false,
52
53
		// 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
54
		focusScreenOffsetY: false
55
	},
56
57
	forms: { }
58
};
59
60
LiveForm.setOptions = function(userOptions) {
61
	for (prop in userOptions) {
0 ignored issues
show
Bug introduced by
The variable prop seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.prop.
Loading history...
62
		if (Object.prototype.hasOwnProperty.call(this.options, prop)) {
63
			this.options[prop] = userOptions[prop];
64
		}
65
	}
66
}
67
68
// Allow setting options before loading the script just by creating global LiveFormOptions object with options.
69
if (typeof window.LiveFormOptions !== 'undefined') {
70
	LiveForm.setOptions(window.LiveFormOptions);
71
}
72
73
LiveForm.isSpecialKey = function(k) {
74
	// http://stackoverflow.com/questions/7770561/jquery-javascript-reject-control-keys-on-keydown-event
75
	return (k == 20 /* Caps lock */
76
		|| k == 16 /* Shift */
77
		|| k == 9 /* Tab */
78
		|| k == 27 /* Escape Key */
79
		|| k == 17 /* Control Key */
80
		|| k == 91 /* Windows Command Key */
81
		|| k == 19 /* Pause Break */
82
		|| k == 18 /* Alt Key */
83
		|| k == 93 /* Right Click Point Key */
84
		|| (k >= 35 && k <= 40) /* Home, End, Arrow Keys */
85
		|| k == 45 /* Insert Key */
86
		|| (k >= 33 && k <= 34) /*Page Down, Page Up */
87
		|| (k >= 112 && k <= 123) /* F1 - F12 */
88
		|| (k >= 144 && k <= 145)); /* Num Lock, Scroll Lock */
89
}
90
91
/**
92
 * Handlers for all the events that trigger validation
93
 * YOU CAN CHANGE these handlers (ie. to use jQuery events instead)
94
 */
95
LiveForm.setupHandlers = function(el) {
96
	if (this.hasClass(el, this.options.disableLiveValidationClass))
97
		return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
98
99
	// Check if element was already initialized
100
	if (el.getAttribute("data-lfv-initialized"))
101
		return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
102
103
	// Remember we initialized this element so we won't do it again
104
	el.setAttribute('data-lfv-initialized', 'true');
105
106
	var handler = function(event) {
107
		event = event || window.event;
108
		Nette.validateControl(event.target ? event.target : event.srcElement);
0 ignored issues
show
Bug introduced by
The variable Nette seems to be never declared. If this is a global, consider adding a /** global: Nette */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
109
	};
110
111
	var self = this;
112
113
	Nette.addEvent(el, "change", handler);
114
	Nette.addEvent(el, "blur", handler);
115
	Nette.addEvent(el, "keydown", function (event) {
116
		if (!self.isSpecialKey(event.which) && (self.options.wait === false || self.options.wait >= 200)) {
117
			// Hide validation span tag.
118
			self.removeClass(self.getGroupElement(this), self.options.controlErrorClass);
119
			self.removeClass(self.getGroupElement(this), self.options.controlValidClass);
120
121
			var messageEl = self.getMessageElement(this);
122
			messageEl.innerHTML = '';
123
			messageEl.className = '';
124
125
			// Cancel timeout to run validation handler
126
			if (self.timeout) {
127
				clearTimeout(self.timeout);
128
			}
129
		}
130
	});
131
	Nette.addEvent(el, "keyup", function(event) {
0 ignored issues
show
Bug introduced by
The variable Nette seems to be never declared. If this is a global, consider adding a /** global: Nette */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
132
		if (self.options.wait !== false) {
133
			event = event || window.event;
134
			if (event.keyCode !== 9) {
135
				if (self.timeout) clearTimeout(self.timeout);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
136
					self.timeout = setTimeout(function() {
137
					handler(event);
138
				}, self.options.wait);
139
			}
140
		}
141
	});
142
};
143
144
LiveForm.processServerErrors = function(el) {
145
	var messageEl = this.getMessageElement(el);
146
	var parentEl = this.getMessageParent(el); // This is parent element which contain the error elements
147
148
	var errors = [];
149
150
	// Find existing error elements by class (from server-validation)
151
	var errorEls = parentEl.getElementsByClassName(this.options.messageErrorClass);
152
	for (var i = errorEls.length - 1; i > -1; i--) {
153
		// Don't touch our main message element
154
		if (errorEls[i] == messageEl)
155
			continue;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
156
157
		// Remove only direct children
158
		var errorParent = errorEls[i].parentNode;
159
		if (errorParent == parentEl) {
160
			errors.push(errorEls[i].outerHTML);
161
			errorParent.removeChild(errorEls[i]);
162
		}
163
	}
164
165
	// Wrap all server errors into one element
166
	if (errors.length > 0) {
167
		messageEl.innerHTML = errors.join("");
168
	}
169
};
170
171
LiveForm.addError = function(el, message) {
172
	// Ignore elements with disabled live validation
173
	if (this.hasClass(el, this.options.disableLiveValidationClass))
174
		return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
175
176
	var groupEl = this.getGroupElement(el);
177
	this.setFormProperty(el.form, "hasError", true);
178
	this.addClass(groupEl, this.options.controlErrorClass);
179
180
	if (this.options.showValid) {
181
		this.removeClass(groupEl, this.options.controlValidClass);
182
	}
183
184
	if (!message) {
185
		message = '&nbsp;';
186
	} else {
187
		message = this.options.messageErrorPrefix + message;
188
	}
189
190
	var messageEl = this.getMessageElement(el);
191
	messageEl.innerHTML = message;
192
	messageEl.className = this.options.messageErrorClass;
193
};
194
195
LiveForm.removeError = function(el) {
196
	// We don't want to remove any errors during onLoadValidation
197
	if (this.getFormProperty(el.form, "onLoadValidation"))
198
		return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
199
200
	var groupEl = this.getGroupElement(el);
201
	this.removeClass(groupEl, this.options.controlErrorClass);
202
203
	var id = el.getAttribute('data-lfv-message-id');
204
	if (id) {
205
		var messageEl = this.getMessageElement(el);
206
		messageEl.innerHTML = '';
207
		messageEl.className = '';
208
	}
209
210
	if (this.options.showValid) {
211
		if (this.showValid(el))
212
			this.addClass(groupEl, this.options.controlValidClass);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
213
		else
214
			this.removeClass(groupEl, this.options.controlValidClass);
215
	}
216
};
217
218
LiveForm.showValid = function(el) {
219
	if (el.type) {
220
		var type = el.type.toLowerCase();
221
		if (type == 'checkbox' || type == 'radio') {
222
			return false;
223
		}
224
	}
225
226
	var rules = Nette.parseJSON(el.getAttribute('data-nette-rules'));
0 ignored issues
show
Bug introduced by
The variable Nette seems to be never declared. If this is a global, consider adding a /** global: Nette */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
227
	if (rules.length == 0) {
228
		return false;
229
	}
230
231
	if (Nette.getEffectiveValue(el) == '') {
232
		return false;
233
	}
234
235
	if (this.hasClass(el, this.options.disableShowValidClass)) {
236
		return false;
237
	}
238
239
	return true;
240
};
241
242
LiveForm.getGroupElement = function(el) {
243
	if (this.options.showMessageClassOnParent === false)
244
		return el;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
245
246
	var groupEl = el;
247
248
	while (!this.hasClass(groupEl, this.options.showMessageClassOnParent)) {
249
		groupEl = groupEl.parentNode;
250
251
		if (groupEl === null) {
252
			return el;
253
		}
254
	}
255
256
	return groupEl;
257
}
258
259
LiveForm.getMessageId = function(el) {
260
	var tmp = el.id + this.options.messageIdPostfix;
261
262
	// For elements without ID, or multi elements (with same name), we must generate whole ID ourselves
263
	if (el.name && (!el.id || !el.form.elements[el.name].tagName)) {
264
		// Strip possible [] from name
265
		var name = el.name.match(/\[\]$/) ? el.name.match(/(.*)\[\]$/)[1] : el.name;
266
		// Generate new ID based on form ID, element name and messageIdPostfix from options
267
		tmp = (el.form.id ? el.form.id : 'frm') + '-' + name + this.options.messageIdPostfix;
268
	}
269
270
	// We want unique ID which doesn't exist yet
271
	var id = tmp,
272
	    i = 0;
273
	while (document.getElementById(id)) {
274
		id = id + '_' + ++i;
275
	}
276
277
	return id;
278
}
279
280
LiveForm.getMessageElement = function(el) {
281
	// For multi elements (with same name) work only with first element attributes
282
	if (el.name && el.name.match(/\[\]$/)) {
283
		el = el.form.elements[el.name].tagName ? el : el.form.elements[el.name][0];
284
	}
285
286
	var id = el.getAttribute('data-lfv-message-id');
287
	if (!id) {
288
		// ID is not specified yet, let's create a new one
289
		id = this.getMessageId(el);
290
291
		// Remember this id for next use
292
		el.setAttribute('data-lfv-message-id', id);
293
	}
294
295
	var messageEl = document.getElementById(id);
296
	if (!messageEl) {
297
		// Message element doesn't exist, lets create a new one
298
		messageEl = document.createElement(this.options.messageTag);
299
		messageEl.id = id;
300
		if (el.style.display == 'none' && !this.hasClass(el, this.options.enableHiddenMessageClass)) {
301
			messageEl.style.display = 'none';
302
		}
303
304
		var parentEl = this.getMessageParent(el);
305
		if (parentEl) {
306
			parentEl.appendChild(messageEl);
307
		}
308
	}
309
310
	return messageEl;
311
};
312
313
LiveForm.getMessageParent = function(el) {
314
	var parentEl = el.parentNode;
315
	var parentFound = false;
316
317
	if (this.options.messageParentClass !== false) {
318
		parentFound = true;
319
		while (!this.hasClass(parentEl, this.options.messageParentClass)) {
320
			parentEl = parentEl.parentNode;
321
322
			if (parentEl === null) {
323
				// We didn't found wanted parent, so use element's direct parent
324
				parentEl = el.parentNode;
325
				parentFound = false;
326
				break;
327
			}
328
		}
329
	}
330
331
	// Don't append error message to radio/checkbox input's label, but along label
332
	if (el.type) {
333
		var type = el.type.toLowerCase();
334
		if ((type == 'checkbox' || type == 'radio') && parentEl.tagName == 'LABEL') {
335
			parentEl = parentEl.parentNode;
336
		}
337
	}
338
339
	// For multi elements (with same name) use parent's parent as parent (if wanted one is not found)
340
	if (!parentFound && el.name && !el.form.elements[el.name].tagName) {
341
		parentEl = parentEl.parentNode;
342
	}
343
344
	return parentEl;
345
}
346
347
LiveForm.addClass = function(el, className) {
348
	if (!el.className) {
349
		el.className = className;
350
	} else if (!this.hasClass(el, className)) {
351
		el.className += ' ' + className;
352
	}
353
};
354
355
LiveForm.hasClass = function(el, className) {
356
	if (el.className)
357
		return el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
358
	return false;
359
};
360
361
LiveForm.removeClass = function(el, className) {
362
	if (this.hasClass(el, className)) {
363
		var reg = new RegExp('(\\s|^)'+ className + '(\\s|$)');
364
		var m = el.className.match(reg);
365
		el.className = el.className.replace(reg, (m[1] == ' ' && m[2] == ' ') ? ' ' : '');
366
	}
367
};
368
369
LiveForm.getFormProperty = function(form, propertyName) {
370
	if (form == null || this.forms[form.id] == null)
371
		return false;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
372
373
	return this.forms[form.id][propertyName];
374
};
375
376
LiveForm.setFormProperty = function(form, propertyName, value) {
377
	if (form == null)
378
		return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
379
380
	if (this.forms[form.id] == null)
381
		this.forms[form.id] = {};
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
382
383
	this.forms[form.id][propertyName] = value;
384
};
385
386
////////////////////////////   modified netteForms.js   ///////////////////////////////////
387
388
/**
389
 * NetteForms - simple form validation.
390
 *
391
 * This file is part of the Nette Framework (https://nette.org)
392
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
393
 */
394
395
(function(global, factory) {
396
	if (!global.JSON) {
397
		return;
398
	}
399
400
	if (typeof define === 'function' && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
401
		define(function() {
402
			return factory(global);
403
		});
404
	} else if (typeof module === 'object' && typeof module.exports === 'object') {
405
		module.exports = factory(global);
406
	} else {
407
		var init = !global.Nette || !global.Nette.noInit;
408
		global.Nette = factory(global);
409
		if (init) {
410
			global.Nette.initOnLoad();
411
		}
412
	}
413
414
}(typeof window !== 'undefined' ? window : this, function(window) {
415
416
'use strict';
417
418
var Nette = {};
419
420
// LiveForm: original netteForms.js code
421
// Nette.formErrors = [];
422
Nette.version = '2.4';
423
424
425
/**
426
 * Attaches a handler to an event for the element.
427
 */
428
Nette.addEvent = function(element, on, callback) {
429
	if (element.addEventListener) {
430
		element.addEventListener(on, callback);
431
	} else if (on === 'DOMContentLoaded') {
432
		element.attachEvent('onreadystatechange', function() {
433
			if (element.readyState === 'complete') {
434
				callback.call(this);
435
			}
436
		});
437
	} else {
438
		element.attachEvent('on' + on, getHandler(callback));
439
	}
440
};
441
442
443
function getHandler(callback) {
444
	return function(e) {
445
		return callback.call(this, e);
446
	};
447
}
448
449
450
/**
451
 * Returns the value of form element.
452
 */
453
Nette.getValue = function(elem) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
454
	var i;
455
	if (!elem) {
456
		return null;
457
458
	} else if (!elem.tagName) { // RadioNodeList, HTMLCollection, array
459
		return elem[0] ? Nette.getValue(elem[0]) : null;
460
461
	} else if (elem.type === 'radio') {
462
		var elements = elem.form.elements; // prevents problem with name 'item' or 'namedItem'
463
		for (i = 0; i < elements.length; i++) {
464
			if (elements[i].name === elem.name && elements[i].checked) {
465
				return elements[i].value;
466
			}
467
		}
468
		return null;
469
470
	} else if (elem.type === 'file') {
471
		return elem.files || elem.value;
472
473
	} else if (elem.tagName.toLowerCase() === 'select') {
474
		var index = elem.selectedIndex,
475
			options = elem.options,
476
			values = [];
477
478
		if (elem.type === 'select-one') {
479
			return index < 0 ? null : options[index].value;
480
		}
481
482
		for (i = 0; i < options.length; i++) {
483
			if (options[i].selected) {
484
				values.push(options[i].value);
485
			}
486
		}
487
		return values;
488
489
	} else if (elem.name && elem.name.match(/\[\]$/)) { // multiple elements []
490
		var elements = elem.form.elements[elem.name].tagName ? [elem] : elem.form.elements[elem.name],
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable elements already seems to be declared on line 462. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
491
			values = [];
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable values already seems to be declared on line 476. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
492
493
		for (i = 0; i < elements.length; i++) {
494
			// LiveForm: original netteForms.js code
495
			/*if (elements[i].type !== 'checkbox' || elements[i].checked) {
496
				values.push(elements[i].value);
497
			}*/
498
			// LiveForm: addition
499
			var value = elements[i].value;
500
			if (elements[i].type === 'checkbox' && elements[i].checked) {
501
				values.push(value);
502
			} else if (elements[i].type !== 'checkbox' && value !== '') {
503
				values.push(value);
504
			}
505
		}
506
		return values;
507
508
	} else if (elem.type === 'checkbox') {
509
		return elem.checked;
510
511
	} else if (elem.tagName.toLowerCase() === 'textarea') {
512
		return elem.value.replace("\r", '');
513
514
	} else {
515
		return elem.value.replace("\r", '').replace(/^\s+|\s+$/g, '');
516
	}
517
};
518
519
520
/**
521
 * Returns the effective value of form element.
522
 */
523
Nette.getEffectiveValue = function(elem) {
524
	var val = Nette.getValue(elem);
525
	if (elem.getAttribute) {
526
		if (val === elem.getAttribute('data-nette-empty-value')) {
527
			val = '';
528
		}
529
	}
530
	return val;
531
};
532
533
534
/**
535
 * Validates form element against given rules.
536
 */
537
Nette.validateControl = function(elem, rules, onlyCheck, value, emptyOptional) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
538
	// LiveForm: addition
539
	// Fix for CheckboxList - validation rules are present always only on first input
540
	if (elem.name && elem.name.match(/\[\]$/) && elem.type.toLowerCase() == 'checkbox') {
541
		elem = elem.form.elements[elem.name].tagName ? elem : elem.form.elements[elem.name][0];
542
	}
543
544
	elem = elem.tagName ? elem : elem[0]; // RadioNodeList
545
	rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
546
	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
547
548
	for (var id = 0, len = rules.length; id < len; id++) {
549
		var rule = rules[id],
550
			op = rule.op.match(/(~)?([^?]+)/),
551
			curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
552
553
		rule.neg = op[1];
554
		rule.op = op[2];
555
		rule.condition = !!rule.rules;
556
557
		if (!curElem) {
558
			continue;
559
		} else if (rule.op === 'optional') {
560
			emptyOptional = !Nette.validateRule(elem, ':filled', null, value);
561
			continue;
562
		} else if (emptyOptional && !rule.condition && rule.op !== ':filled') {
563
			continue;
564
		}
565
566
		curElem = curElem.tagName ? curElem : curElem[0]; // RadioNodeList
567
		var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)},
568
			success = Nette.validateRule(curElem, rule.op, rule.arg, curValue);
569
570
		if (success === null) {
571
			continue;
572
		} else if (rule.neg) {
573
			success = !success;
574
		}
575
576
		if (rule.condition && success) {
577
			if (!Nette.validateControl(elem, rule.rules, onlyCheck, value, rule.op === ':blank' ? false : emptyOptional)) {
578
				return false;
579
			}
580
		} else if (!rule.condition && !success) {
581
			if (Nette.isDisabled(curElem)) {
582
				continue;
583
			}
584
			if (!onlyCheck) {
585
				var arr = Nette.isArray(rule.arg) ? rule.arg : [rule.arg],
586
					message = rule.msg.replace(/%(value|\d+)/g, function(foo, m) {
587
						return Nette.getValue(m === 'value' ? curElem : elem.form.elements.namedItem(arr[m].control));
0 ignored issues
show
Bug introduced by
The variable curElem is changed as part of the for loop for example by curElem.tagName ? curElem: curElem.0 on line 566. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
Bug introduced by
The variable arr is changed as part of the for loop for example by Nette.isArray(rule.arg) ? rule.arg: [rule.arg] on line 585. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
588
					});
589
				Nette.addError(curElem, message);
590
			}
591
			return false;
592
		}
593
	}
594
595
	if (elem.type === 'number' && !elem.validity.valid) {
596
		if (!onlyCheck) {
597
			Nette.addError(elem, 'Please enter a valid value.');
598
		}
599
		return false;
600
	}
601
602
	// LiveForm: addition
603
	if (!onlyCheck) {
604
		LiveForm.removeError(elem);
605
	}
606
607
	return true;
608
};
609
610
611
/**
612
 * Validates whole form.
613
 */
614
Nette.validateForm = function(sender, onlyCheck) {
0 ignored issues
show
Unused Code introduced by
The parameter onlyCheck is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
615
	var form = sender.form || sender,
616
		scope = false;
617
618
	// LiveForm: addition
619
	LiveForm.setFormProperty(form, "hasError", false);
620
621
	// LiveForm: original netteForms.js code
622
	// Nette.formErrors = [];
623
624
	if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) {
625
		var scopeArr = Nette.parseJSON(form['nette-submittedBy'].getAttribute('data-nette-validation-scope'));
626
		if (scopeArr.length) {
627
			scope = new RegExp('^(' + scopeArr.join('-|') + '-)');
628
		} else {
629
			// LiveForm: original netteForms.js code
630
			// Nette.showFormErrors(form, []);
631
			return true;
632
		}
633
	}
634
635
	var radios = {}, i, elem;
636
	// LiveForm: addition
637
	var success = true;
638
639
	for (i = 0; i < form.elements.length; i++) {
640
		elem = form.elements[i];
641
642
		if (elem.tagName && !(elem.tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1})) {
643
			continue;
644
645
		} else if (elem.type === 'radio') {
646
			if (radios[elem.name]) {
647
				continue;
648
			}
649
			radios[elem.name] = true;
650
		}
651
652
		if ((scope && !elem.name.replace(/]\[|\[|]|$/g, '-').match(scope)) || Nette.isDisabled(elem)) {
653
			continue;
654
		}
655
656
		// LiveForm: addition
657
		success = Nette.validateControl(elem) && success;
658
		if (!success && !LiveForm.options.showAllErrors) {
659
			break;
660
		}
661
		// LiveForm: original netteForms.js code
662
		/*if (!Nette.validateControl(elem, null, onlyCheck) && !Nette.formErrors.length) {
663
			return false;
664
		}*/
665
	}
666
	// LiveForm: change
667
	return success;
668
669
	// LiveForm: original netteForms.js code
670
	/*var success = !Nette.formErrors.length;
671
	Nette.showFormErrors(form, Nette.formErrors);
672
	return success;*/
673
};
674
675
676
/**
677
 * Check if input is disabled.
678
 */
679
Nette.isDisabled = function(elem) {
680
	if (elem.type === 'radio') {
681
		for (var i = 0, elements = elem.form.elements; i < elements.length; i++) {
682
			if (elements[i].name === elem.name && !elements[i].disabled) {
683
				return false;
684
			}
685
		}
686
		return true;
687
	}
688
	return elem.disabled;
689
};
690
691
// LiveForm: change
692
/**
693
 * Display error message.
694
 */
695
Nette.addError = function(elem, message) {
696
	// LiveForm: addition
697
	var noLiveValidation = LiveForm.hasClass(elem, LiveForm.options.disableLiveValidationClass);
698
	// User explicitly disabled live-validation so we want to show simple alerts
699
	if (noLiveValidation) {
700
		// notify errors for elements with disabled live validation (but only errors and not during onLoadValidation)
701
		if (message && !LiveForm.getFormProperty(elem.form, "hasError") && !LiveForm.getFormProperty(elem.form, "onLoadValidation")) {
702
			alert(message);
703
		}
704
	}
705
	if (elem.focus && !LiveForm.getFormProperty(elem.form, "hasError")) {
706
		if (!LiveForm.focusing) {
707
			LiveForm.focusing = true;
708
			elem.focus();
709
			setTimeout(function() {
710
				LiveForm.focusing = false;
711
712
				// Scroll by defined offset (if enabled)
713
				// NOTE: We use it with setTimetout because IE9 doesn't always catch instant scrollTo request
714
				var focusOffsetY = LiveForm.options.focusScreenOffsetY;
715
				if (focusOffsetY !== false && elem.getBoundingClientRect().top < focusOffsetY) {
716
					window.scrollBy(0, elem.getBoundingClientRect().top - focusOffsetY);
717
				}
718
			}, 10);
719
		}
720
	}
721
	if (!noLiveValidation) {
722
		LiveForm.addError(elem, message);
723
	}
724
};
725
726
727
// LiveForm: original netteForms.js code
728
/**
729
 * Adds error message to the queue.
730
 */
731
/*Nette.addError = function(elem, message) {
732
	Nette.formErrors.push({
733
		element: elem,
734
		message: message
735
	});
736
};*/
737
738
739
// LiveForm: original netteForms.js code
740
/**
741
 * Display error messages.
742
 */
743
/*Nette.showFormErrors = function(form, errors) {
744
	var messages = [],
745
		focusElem;
746
747
	for (var i = 0; i < errors.length; i++) {
748
		var elem = errors[i].element,
749
			message = errors[i].message;
750
751
		if (!Nette.inArray(messages, message)) {
752
			messages.push(message);
753
754
			if (!focusElem && elem.focus) {
755
				focusElem = elem;
756
			}
757
		}
758
	}
759
760
	if (messages.length) {
761
		alert(messages.join('\n'));
762
763
		if (focusElem) {
764
			focusElem.focus();
765
		}
766
	}
767
};*/
768
769
770
/**
771
 * Expand rule argument.
772
 */
773
Nette.expandRuleArgument = function(form, arg) {
774
	if (arg && arg.control) {
775
		var control = form.elements.namedItem(arg.control),
776
			value = {value: Nette.getEffectiveValue(control)};
777
		Nette.validateControl(control, null, true, value);
778
		arg = value.value;
779
	}
780
	return arg;
781
};
782
783
784
/**
785
 * Validates single rule.
786
 */
787
Nette.validateRule = function(elem, op, arg, value) {
788
	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
789
790
	if (op.charAt(0) === ':') {
791
		op = op.substr(1);
792
	}
793
	op = op.replace('::', '_');
794
	op = op.replace(/\\/g, '');
795
796
	var arr = Nette.isArray(arg) ? arg.slice(0) : [arg];
797
	for (var i = 0, len = arr.length; i < len; i++) {
798
		arr[i] = Nette.expandRuleArgument(elem.form, arr[i]);
799
	}
800
	return Nette.validators[op]
801
		? Nette.validators[op](elem, Nette.isArray(arg) ? arr : arr[0], value.value, value)
802
		: null;
803
};
804
805
806
Nette.validators = {
807
	filled: function(elem, arg, val) {
808
		if (elem.type === 'number' && elem.validity.badInput) {
809
			return true;
810
		}
811
		return val !== '' && val !== false && val !== null
812
			&& (!Nette.isArray(val) || !!val.length)
813
			&& (!window.FileList || !(val instanceof window.FileList) || val.length);
814
	},
815
816
	blank: function(elem, arg, val) {
817
		return !Nette.validators.filled(elem, arg, val);
818
	},
819
820
	valid: function(elem, arg, val) {
0 ignored issues
show
Unused Code introduced by
The parameter arg is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter val is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
821
		return Nette.validateControl(elem, null, true);
822
	},
823
824
	equal: function(elem, arg, val) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
825
		if (arg === undefined) {
826
			return null;
827
		}
828
829
		function toString(val) {
830
			if (typeof val === 'number' || typeof val === 'string') {
831
				return '' + val;
832
			} else {
833
				return val === true ? '1' : '';
834
			}
835
		}
836
837
		val = Nette.isArray(val) ? val : [val];
838
		arg = Nette.isArray(arg) ? arg : [arg];
839
		loop:
840
		for (var i1 = 0, len1 = val.length; i1 < len1; i1++) {
841
			for (var i2 = 0, len2 = arg.length; i2 < len2; i2++) {
842
				if (toString(val[i1]) === toString(arg[i2])) {
843
					continue loop;
844
				}
845
			}
846
			return false;
847
		}
848
		return true;
849
	},
850
851
	notEqual: function(elem, arg, val) {
852
		return arg === undefined ? null : !Nette.validators.equal(elem, arg, val);
853
	},
854
855
	minLength: function(elem, arg, val) {
856
		if (elem.type === 'number') {
857
			if (elem.validity.tooShort) {
858
				return false
859
			} else if (elem.validity.badInput) {
860
				return null;
861
			}
862
		}
863
		return val.length >= arg;
864
	},
865
866
	maxLength: function(elem, arg, val) {
867
		if (elem.type === 'number') {
868
			if (elem.validity.tooLong) {
869
				return false
870
			} else if (elem.validity.badInput) {
871
				return null;
872
			}
873
		}
874
		return val.length <= arg;
875
	},
876
877
	length: function(elem, arg, val) {
878
		if (elem.type === 'number') {
879
			if (elem.validity.tooShort || elem.validity.tooLong) {
880
				return false
881
			} else if (elem.validity.badInput) {
882
				return null;
883
			}
884
		}
885
		arg = Nette.isArray(arg) ? arg : [arg, arg];
886
		return (arg[0] === null || val.length >= arg[0]) && (arg[1] === null || val.length <= arg[1]);
887
	},
888
889
	email: function(elem, arg, val) {
890
		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);
891
	},
892
893
	url: function(elem, arg, val, value) {
894
		if (!(/^[a-z\d+.-]+:/).test(val)) {
895
			val = 'http://' + val;
896
		}
897
		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)) {
898
			value.value = val;
899
			return true;
900
		}
901
		return false;
902
	},
903
904
	regexp: function(elem, arg, val) {
905
		var parts = typeof arg === 'string' ? arg.match(/^\/(.*)\/([imu]*)$/) : false;
906
		try {
907
			return parts && (new RegExp(parts[1], parts[2].replace('u', ''))).test(val);
908
		} catch (e) {}
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
909
	},
910
911
	pattern: function(elem, arg, val) {
912
		try {
913
			return typeof arg === 'string' ? (new RegExp('^(?:' + arg + ')$')).test(val) : null;
914
		} catch (e) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
915
	},
916
917
	integer: function(elem, arg, val) {
918
		if (elem.type === 'number' && elem.validity.badInput) {
919
			return false;
920
		}
921
		return (/^-?[0-9]+$/).test(val);
922
	},
923
924
	'float': function(elem, arg, val, value) {
925
		if (elem.type === 'number' && elem.validity.badInput) {
926
			return false;
927
		}
928
		val = val.replace(' ', '').replace(',', '.');
929
		if ((/^-?[0-9]*[.,]?[0-9]+$/).test(val)) {
930
			value.value = val;
931
			return true;
932
		}
933
		return false;
934
	},
935
936
	min: function(elem, arg, val) {
937
		if (elem.type === 'number') {
938
			if (elem.validity.rangeUnderflow) {
939
				return false
940
			} else if (elem.validity.badInput) {
941
				return null;
942
			}
943
		}
944
		return Nette.validators.range(elem, [arg, null], val);
945
	},
946
947
	max: function(elem, arg, val) {
948
		if (elem.type === 'number') {
949
			if (elem.validity.rangeOverflow) {
950
				return false
951
			} else if (elem.validity.badInput) {
952
				return null;
953
			}
954
		}
955
		return Nette.validators.range(elem, [null, arg], val);
956
	},
957
958
	range: function(elem, arg, val) {
959
		if (elem.type === 'number') {
960
			if (elem.validity.rangeUnderflow || elem.validity.rangeOverflow) {
961
				return false
962
			} else if (elem.validity.badInput) {
963
				return null;
964
			}
965
		}
966
		return Nette.isArray(arg) ?
967
			((arg[0] === null || parseFloat(val) >= arg[0]) && (arg[1] === null || parseFloat(val) <= arg[1])) : null;
968
	},
969
970
	submitted: function(elem, arg, val) {
0 ignored issues
show
Unused Code introduced by
The parameter val is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter arg is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
971
		return elem.form['nette-submittedBy'] === elem;
972
	},
973
974
	fileSize: function(elem, arg, val) {
975
		if (window.FileList) {
976
			for (var i = 0; i < val.length; i++) {
977
				if (val[i].size > arg) {
978
					return false;
979
				}
980
			}
981
		}
982
		return true;
983
	},
984
985
	image: function (elem, arg, val) {
986
		if (window.FileList && val instanceof window.FileList) {
987
			for (var i = 0; i < val.length; i++) {
988
				var type = val[i].type;
989
				if (type && type !== 'image/gif' && type !== 'image/png' && type !== 'image/jpeg') {
990
					return false;
991
				}
992
			}
993
		}
994
		return true;
995
	}
996
};
997
998
999
/**
1000
 * Process all toggles in form.
1001
 */
1002
Nette.toggleForm = function(form, elem) {
1003
	var i;
1004
	Nette.toggles = {};
1005
	for (i = 0; i < form.elements.length; i++) {
1006
		if (form.elements[i].tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
1007
			Nette.toggleControl(form.elements[i], null, null, !elem);
1008
		}
1009
	}
1010
1011
	for (i in Nette.toggles) {
1012
		Nette.toggle(i, Nette.toggles[i], elem);
1013
	}
1014
};
1015
1016
1017
/**
1018
 * Process toggles on form element.
1019
 */
1020
Nette.toggleControl = function(elem, rules, success, firsttime, value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1021
	rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
1022
	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
1023
1024
	var has = false,
1025
		handled = [],
1026
		handler = function () {
1027
			Nette.toggleForm(elem.form, elem);
1028
		},
1029
		curSuccess;
1030
1031
	for (var id = 0, len = rules.length; id < len; id++) {
1032
		var rule = rules[id],
1033
			op = rule.op.match(/(~)?([^?]+)/),
1034
			curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
1035
1036
		if (!curElem) {
1037
			continue;
1038
		}
1039
1040
		curSuccess = success;
1041
		if (success !== false) {
1042
			rule.neg = op[1];
1043
			rule.op = op[2];
1044
			var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)};
1045
			curSuccess = Nette.validateRule(curElem, rule.op, rule.arg, curValue);
1046
			if (curSuccess === null) {
1047
				continue;
1048
1049
			} else if (rule.neg) {
1050
				curSuccess = !curSuccess;
1051
			}
1052
			if (!rule.rules) {
1053
				success = curSuccess;
1054
			}
1055
		}
1056
1057
		if ((rule.rules && Nette.toggleControl(elem, rule.rules, curSuccess, firsttime, value)) || rule.toggle) {
1058
			has = true;
1059
			if (firsttime) {
1060
				var oldIE = !document.addEventListener, // IE < 9
1061
					name = curElem.tagName ? curElem.name : curElem[0].name,
1062
					els = curElem.tagName ? curElem.form.elements : curElem;
1063
1064
				for (var i = 0; i < els.length; i++) {
1065
					if (els[i].name === name && !Nette.inArray(handled, els[i])) {
1066
						Nette.addEvent(els[i], oldIE && els[i].type in {checkbox: 1, radio: 1} ? 'click' : 'change', handler);
1067
						handled.push(els[i]);
1068
					}
1069
				}
1070
			}
1071
			for (var id2 in rule.toggle || []) {
1072
				if (Object.prototype.hasOwnProperty.call(rule.toggle, id2)) {
1073
					Nette.toggles[id2] = Nette.toggles[id2] || (rule.toggle[id2] ? curSuccess : !curSuccess);
1074
				}
1075
			}
1076
		}
1077
	}
1078
	return has;
1079
};
1080
1081
1082
Nette.parseJSON = function(s) {
1083
	return (s || '').substr(0, 3) === '{op'
1084
		? eval('[' + s + ']') // backward compatibility with Nette 2.0.x
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
1085
		: JSON.parse(s || '[]');
1086
};
1087
1088
1089
/**
1090
 * Displays or hides HTML element.
1091
 */
1092
Nette.toggle = function(id, visible, srcElement) {
0 ignored issues
show
Unused Code introduced by
The parameter srcElement is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1093
	var elem = document.getElementById(id);
1094
	if (elem) {
1095
		elem.style.display = visible ? '' : 'none';
1096
	}
1097
};
1098
1099
1100
/**
1101
 * Setup handlers.
1102
 */
1103
Nette.initForm = function(form) {
1104
	form.noValidate = 'novalidate';
1105
1106
	// LiveForm: addition
1107
	LiveForm.forms[form.id] = {
1108
		hasError: false,
1109
		onLoadValidation: false
1110
	};
1111
1112
	Nette.addEvent(form, 'submit', function(e) {
1113
		if (!Nette.validateForm(form)) {
1114
			if (e && e.stopPropagation) {
1115
				e.stopPropagation();
1116
				e.preventDefault();
1117
			} else if (window.event) {
1118
				event.cancelBubble = true;
0 ignored issues
show
Bug introduced by
The variable event seems to be never declared. If this is a global, consider adding a /** global: event */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1119
				event.returnValue = false;
1120
			}
1121
		}
1122
	});
1123
1124
	Nette.toggleForm(form);
1125
1126
	// LiveForm: addition
1127
	for (var i = 0; i < form.elements.length; i++) {
1128
		LiveForm.setupHandlers(form.elements[i]);
1129
		LiveForm.processServerErrors(form.elements[i]);
1130
	}
1131
};
1132
1133
1134
/**
1135
 * @private
1136
 */
1137
Nette.initOnLoad = function() {
1138
	Nette.addEvent(document, 'DOMContentLoaded', function() {
1139
		for (var i = 0; i < document.forms.length; i++) {
1140
			var form = document.forms[i];
1141
			for (var j = 0; j < form.elements.length; j++) {
1142
				if (form.elements[j].getAttribute('data-nette-rules')) {
1143
					Nette.initForm(form);
1144
1145
					// LiveForm: addition
1146
					if (LiveForm.hasClass(form, 'validate-on-load')) {
1147
						// This is not so nice way, but I don't want to spoil validateForm, validateControl and other methods with another parameter
1148
						LiveForm.setFormProperty(form, "onLoadValidation", true);
1149
						Nette.validateForm(form);
1150
						LiveForm.setFormProperty(form, "onLoadValidation", false);
1151
					}
1152
1153
					break;
1154
				}
1155
			}
1156
		}
1157
1158
		Nette.addEvent(document.body, 'click', function(e) {
1159
			var target = e.target || e.srcElement;
1160
			if (target.form && target.type in {submit: 1, image: 1}) {
1161
				target.form['nette-submittedBy'] = target;
1162
			}
1163
		});
1164
	});
1165
};
1166
1167
1168
/**
1169
 * Determines whether the argument is an array.
1170
 */
1171
Nette.isArray = function(arg) {
1172
	return Object.prototype.toString.call(arg) === '[object Array]';
1173
};
1174
1175
1176
/**
1177
 * Search for a specified value within an array.
1178
 */
1179
Nette.inArray = function(arr, val) {
1180
	if ([].indexOf) {
1181
		return arr.indexOf(val) > -1;
1182
	} else {
1183
		for (var i = 0; i < arr.length; i++) {
1184
			if (arr[i] === val) {
1185
				return true;
1186
			}
1187
		}
1188
		return false;
1189
	}
1190
};
1191
1192
1193
/**
1194
 * Converts string to web safe characters [a-z0-9-] text.
1195
 */
1196
Nette.webalize = function(s) {
1197
	s = s.toLowerCase();
1198
	var res = '', i, ch;
1199
	for (i = 0; i < s.length; i++) {
1200
		ch = Nette.webalizeTable[s.charAt(i)];
1201
		res += ch ? ch : s.charAt(i);
1202
	}
1203
	return res.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
1204
};
1205
1206
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'};
1207
1208
return Nette;
1209
}));
1210