PluginProbe
Packeta / trunk
Packeta vtrunk
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / deps / nette / forms / src / assets / netteForms.js

netteForms.js in Packeta trunk, at deps/nette/forms/src/assets/netteForms.js

820 lines 21.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**!
2 * NetteForms - simple form validation.
3 *
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7
8 (function(global, factory) {
9 if (!global.JSON) {
10 return;
11 }
12
13 if (typeof define === 'function' && define.amd) {
14 define(function() {
15 return factory(global);
16 });
17 } else if (typeof module === 'object' && typeof module.exports === 'object') {
18 module.exports = factory(global);
19 } else {
20 var init = !global.Nette || !global.Nette.noInit;
21 global.Nette = factory(global);
22 if (init) {
23 global.Nette.initOnLoad();
24 }
25 }
26
27 }(typeof window !== 'undefined' ? window : this, function(window) {
28
29 'use strict';
30
31 var Nette = {};
32 var preventFiltering = {};
33 var formToggles = {};
34 var toggleListeners = new window.WeakMap();
35
36 Nette.formErrors = [];
37 Nette.version = '3.3.0';
38 Nette.invalidNumberMessage = 'Please enter a valid value.';
39
40
41 /**
42 * Function to execute when the DOM is fully loaded.
43 * @private
44 */
45 Nette.onDocumentReady = function(callback) {
46 if (document.readyState !== 'loading') {
47 callback.call(this);
48 } else {
49 document.addEventListener('DOMContentLoaded', callback);
50 }
51 };
52
53
54 /**
55 * Returns the value of form element.
56 */
57 Nette.getValue = function(elem) {
58 var i;
59 if (!elem) {
60 return null;
61
62 } else if (!elem.tagName) { // RadioNodeList, HTMLCollection, array
63 return elem[0] ? Nette.getValue(elem[0]) : null;
64
65 } else if (elem.type === 'radio') {
66 var elements = elem.form.elements; // prevents problem with name 'item' or 'namedItem'
67 for (i = 0; i < elements.length; i++) {
68 if (elements[i].name === elem.name && elements[i].checked) {
69 return elements[i].value;
70 }
71 }
72 return null;
73
74 } else if (elem.type === 'file') {
75 return elem.files || elem.value;
76
77 } else if (elem.tagName.toLowerCase() === 'select') {
78 var index = elem.selectedIndex,
79 options = elem.options,
80 values = [];
81
82 if (elem.type === 'select-one') {
83 return index < 0 ? null : options[index].value;
84 }
85
86 for (i = 0; i < options.length; i++) {
87 if (options[i].selected) {
88 values.push(options[i].value);
89 }
90 }
91 return values;
92
93 } else if (elem.name && elem.name.substr(-2) === '[]') { // multiple elements []
94 elements = elem.form.elements[elem.name].tagName ? [elem] : elem.form.elements[elem.name];
95 values = [];
96
97 for (i = 0; i < elements.length; i++) {
98 if (elements[i].type !== 'checkbox' || elements[i].checked) {
99 values.push(elements[i].value);
100 }
101 }
102 return values;
103
104 } else if (elem.type === 'checkbox') {
105 return elem.checked;
106
107 } else if (elem.tagName.toLowerCase() === 'textarea') {
108 return elem.value.replace('\r', '');
109
110 } else {
111 return elem.value.replace('\r', '').replace(/^\s+|\s+$/g, '');
112 }
113 };
114
115
116 /**
117 * Returns the effective value of form element.
118 */
119 Nette.getEffectiveValue = function(elem, filter) {
120 var val = Nette.getValue(elem);
121 if (elem.getAttribute) {
122 if (val === elem.getAttribute('data-nette-empty-value')) {
123 val = '';
124 }
125 }
126 if (filter && preventFiltering[elem.name] === undefined) {
127 preventFiltering[elem.name] = true;
128 var ref = {value: val};
129 Nette.validateControl(elem, null, true, ref);
130 val = ref.value;
131 delete preventFiltering[elem.name];
132 }
133 return val;
134 };
135
136
137 /**
138 * Validates form element against given rules.
139 */
140 Nette.validateControl = function(elem, rules, onlyCheck, value, emptyOptional) {
141 var top = !rules;
142 elem = elem.tagName ? elem : elem[0]; // RadioNodeList
143 rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
144 value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
145 emptyOptional = emptyOptional === undefined ? !Nette.validateRule(elem, ':filled', null, value) : emptyOptional;
146
147 for (var id = 0, len = rules.length; id < len; id++) {
148 var rule = rules[id],
149 op = rule.op.match(/(~)?([^?]+)/),
150 curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
151
152 rule.neg = op[1];
153 rule.op = op[2];
154 rule.condition = !!rule.rules;
155
156 if (!curElem) {
157 continue;
158 } else if (emptyOptional && !rule.condition && rule.op !== ':filled') {
159 continue;
160 }
161
162 curElem = curElem.tagName ? curElem : curElem[0]; // RadioNodeList
163 var success = Nette.validateRule(curElem, rule.op, rule.arg, elem === curElem ? value : undefined);
164
165 if (success === null) {
166 continue;
167 } else if (rule.neg) {
168 success = !success;
169 }
170
171 if (rule.condition && success) {
172 if (!Nette.validateControl(elem, rule.rules, onlyCheck, value, rule.op === ':blank' ? false : emptyOptional)) {
173 return false;
174 }
175 } else if (!rule.condition && !success) {
176 if (Nette.isDisabled(curElem)) {
177 continue;
178 }
179 if (!onlyCheck) {
180 var arr = Array.isArray(rule.arg) ? rule.arg : [rule.arg],
181 message = rule.msg.replace(/%(value|\d+)/g, function(foo, m) {
182 return Nette.getValue(m === 'value' ? curElem : elem.form.elements.namedItem(arr[m].control));
183 });
184 Nette.addError(curElem, message);
185 }
186 return false;
187 }
188 }
189
190 if (elem.type === 'number' && !elem.validity.valid) {
191 if (top && !onlyCheck) {
192 Nette.addError(elem, Nette.invalidNumberMessage);
193 }
194 return false;
195 }
196
197 return true;
198 };
199
200
201 /**
202 * Validates whole form.
203 */
204 Nette.validateForm = function(sender, onlyCheck) {
205 var form = sender.form || sender,
206 scope = false;
207
208 Nette.formErrors = [];
209
210 if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) {
211 var scopeArr = JSON.parse(form['nette-submittedBy'].getAttribute('data-nette-validation-scope') || '[]');
212 if (scopeArr.length) {
213 scope = new RegExp('^(' + scopeArr.join('-|') + '-)');
214 } else {
215 Nette.showFormErrors(form, []);
216 return true;
217 }
218 }
219
220 var radios = {}, i, elem;
221
222 for (i = 0; i < form.elements.length; i++) {
223 elem = form.elements[i];
224
225 if (elem.tagName && !(elem.tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1})) {
226 continue;
227
228 } else if (elem.type === 'radio') {
229 if (radios[elem.name]) {
230 continue;
231 }
232 radios[elem.name] = true;
233 }
234
235 if ((scope && !elem.name.replace(/]\[|\[|]|$/g, '-').match(scope)) || Nette.isDisabled(elem)) {
236 continue;
237 }
238
239 if (!Nette.validateControl(elem, null, onlyCheck) && !Nette.formErrors.length) {
240 return false;
241 }
242 }
243 var success = !Nette.formErrors.length;
244 Nette.showFormErrors(form, Nette.formErrors);
245 return success;
246 };
247
248
249 /**
250 * Check if input is disabled.
251 */
252 Nette.isDisabled = function(elem) {
253 if (elem.type === 'radio') {
254 for (var i = 0, elements = elem.form.elements; i < elements.length; i++) {
255 if (elements[i].name === elem.name && !elements[i].disabled) {
256 return false;
257 }
258 }
259 return true;
260 }
261 return elem.disabled;
262 };
263
264
265 /**
266 * Adds error message to the queue.
267 */
268 Nette.addError = function(elem, message) {
269 Nette.formErrors.push({
270 element: elem,
271 message: message
272 });
273 };
274
275
276 /**
277 * Display error messages.
278 */
279 Nette.showFormErrors = function(form, errors) {
280 var messages = [],
281 focusElem;
282
283 for (var i = 0; i < errors.length; i++) {
284 var elem = errors[i].element,
285 message = errors[i].message;
286
287 if (messages.indexOf(message) < 0) {
288 messages.push(message);
289
290 if (!focusElem && elem.focus) {
291 focusElem = elem;
292 }
293 }
294 }
295
296 if (messages.length) {
297 Nette.showModal(messages.join('\n'), function () {
298 if (focusElem) {
299 focusElem.focus();
300 }
301 });
302 }
303 };
304
305
306 /**
307 * Display modal window.
308 */
309 Nette.showModal = function(message, onclose) {
310 var dialog = document.createElement('dialog'),
311 ua = navigator.userAgentData;
312
313 if (ua && dialog.showModal
314 && ua.brands.some(function(item) { return item.brand === 'Opera' || (item.brand === 'Chromium' && ua.mobile); })
315 ) {
316 var style = document.createElement('style');
317 style.innerText = '.netteFormsModal { text-align: center; margin: auto; border: 2px solid black; padding: 1rem } .netteFormsModal button { padding: .1em 2em }';
318
319 var button = document.createElement('button');
320 button.innerText = 'OK';
321 button.onclick = function () {
322 dialog.remove();
323 onclose();
324 };
325
326 dialog.setAttribute('class', 'netteFormsModal');
327 dialog.innerText = message + '\n\n';
328 dialog.appendChild(style);
329 dialog.appendChild(button);
330 document.body.appendChild(dialog);
331 dialog.showModal();
332 return;
333 }
334
335 alert(message);
336 onclose();
337 };
338
339
340 /**
341 * Validates single rule.
342 */
343 Nette.validateRule = function(elem, op, arg, value) {
344 value = value === undefined ? {value: Nette.getEffectiveValue(elem, true)} : value;
345
346 if (op.charAt(0) === ':') {
347 op = op.substr(1);
348 }
349 op = op.replace('::', '_');
350 op = op.replace(/\\/g, '');
351
352 var arr = Array.isArray(arg) ? arg.slice(0) : [arg];
353 for (var i = 0, len = arr.length; i < len; i++) {
354 if (arr[i] && arr[i].control) {
355 var control = elem.form.elements.namedItem(arr[i].control);
356 arr[i] = control === elem ? value.value : Nette.getEffectiveValue(control, true);
357 }
358 }
359
360 return Nette.validators[op]
361 ? Nette.validators[op](elem, Array.isArray(arg) ? arr : arr[0], value.value, value)
362 : null;
363 };
364
365
366 Nette.validators = {
367 filled: function(elem, arg, val) {
368 if (elem.type === 'number' && elem.validity.badInput) {
369 return true;
370 }
371 return val !== '' && val !== false && val !== null
372 && (!Array.isArray(val) || !!val.length)
373 && (!window.FileList || !(val instanceof window.FileList) || val.length);
374 },
375
376 blank: function(elem, arg, val) {
377 return !Nette.validators.filled(elem, arg, val);
378 },
379
380 valid: function(elem) {
381 return Nette.validateControl(elem, null, true);
382 },
383
384 equal: function(elem, arg, val) {
385 if (arg === undefined) {
386 return null;
387 }
388
389 var toString = function(val) {
390 if (typeof val === 'number' || typeof val === 'string') {
391 return '' + val;
392 } else {
393 return val === true ? '1' : '';
394 }
395 };
396
397 val = Array.isArray(val) ? val : [val];
398 arg = Array.isArray(arg) ? arg : [arg];
399 loop:
400 for (var i1 = 0, len1 = val.length; i1 < len1; i1++) {
401 for (var i2 = 0, len2 = arg.length; i2 < len2; i2++) {
402 if (toString(val[i1]) === toString(arg[i2])) {
403 continue loop;
404 }
405 }
406 return false;
407 }
408 return val.length > 0;
409 },
410
411 notEqual: function(elem, arg, val) {
412 return arg === undefined ? null : !Nette.validators.equal(elem, arg, val);
413 },
414
415 minLength: function(elem, arg, val) {
416 if (elem.type === 'number') {
417 if (elem.validity.tooShort) {
418 return false;
419 } else if (elem.validity.badInput) {
420 return null;
421 }
422 }
423 return val.length >= arg;
424 },
425
426 maxLength: function(elem, arg, val) {
427 if (elem.type === 'number') {
428 if (elem.validity.tooLong) {
429 return false;
430 } else if (elem.validity.badInput) {
431 return null;
432 }
433 }
434 return val.length <= arg;
435 },
436
437 length: function(elem, arg, val) {
438 if (elem.type === 'number') {
439 if (elem.validity.tooShort || elem.validity.tooLong) {
440 return false;
441 } else if (elem.validity.badInput) {
442 return null;
443 }
444 }
445 arg = Array.isArray(arg) ? arg : [arg, arg];
446 return (arg[0] === null || val.length >= arg[0]) && (arg[1] === null || val.length <= arg[1]);
447 },
448
449 email: function(elem, arg, val) {
450 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);
451 },
452
453 url: function(elem, arg, val, value) {
454 if (!(/^[a-z\d+.-]+:/).test(val)) {
455 val = 'https://' + val;
456 }
457 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)) {
458 value.value = val;
459 return true;
460 }
461 return false;
462 },
463
464 regexp: function(elem, arg, val) {
465 var parts = typeof arg === 'string' ? arg.match(/^\/(.*)\/([imu]*)$/) : false;
466 try {
467 return parts && (new RegExp(parts[1], parts[2].replace('u', ''))).test(val);
468 } catch (e) {} // eslint-disable-line no-empty
469 },
470
471 pattern: function(elem, arg, val, value, caseInsensitive) {
472 if (typeof arg !== 'string') {
473 return null;
474 }
475
476 try {
477 try {
478 var regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'ui' : 'u');
479 } catch (e) {
480 regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'i' : '');
481 }
482
483 if (window.FileList && val instanceof FileList) {
484 for (var i = 0; i < val.length; i++) {
485 if (!regExp.test(val[i].name)) {
486 return false;
487 }
488 }
489
490 return true;
491 }
492
493 return regExp.test(val);
494 } catch (e) {} // eslint-disable-line no-empty
495 },
496
497 patternCaseInsensitive: function(elem, arg, val) {
498 return Nette.validators.pattern(elem, arg, val, null, true);
499 },
500
501 numeric: function(elem, arg, val) {
502 if (elem.type === 'number' && elem.validity.badInput) {
503 return false;
504 }
505 return (/^[0-9]+$/).test(val);
506 },
507
508 integer: function(elem, arg, val) {
509 if (elem.type === 'number' && elem.validity.badInput) {
510 return false;
511 }
512 return (/^-?[0-9]+$/).test(val);
513 },
514
515 'float': function(elem, arg, val, value) {
516 if (elem.type === 'number' && elem.validity.badInput) {
517 return false;
518 }
519 val = val.replace(/ +/g, '').replace(/,/g, '.');
520 if ((/^-?[0-9]*\.?[0-9]+$/).test(val)) {
521 value.value = val;
522 return true;
523 }
524 return false;
525 },
526
527 min: function(elem, arg, val) {
528 if (elem.type === 'number') {
529 if (elem.validity.rangeUnderflow) {
530 return false;
531 } else if (elem.validity.badInput) {
532 return null;
533 }
534 }
535 return arg === null || parseFloat(val) >= arg;
536 },
537
538 max: function(elem, arg, val) {
539 if (elem.type === 'number') {
540 if (elem.validity.rangeOverflow) {
541 return false;
542 } else if (elem.validity.badInput) {
543 return null;
544 }
545 }
546 return arg === null || parseFloat(val) <= arg;
547 },
548
549 range: function(elem, arg, val) {
550 if (elem.type === 'number') {
551 if (elem.validity.rangeUnderflow || elem.validity.rangeOverflow) {
552 return false;
553 } else if (elem.validity.badInput) {
554 return null;
555 }
556 }
557 return Array.isArray(arg) ?
558 ((arg[0] === null || parseFloat(val) >= arg[0]) && (arg[1] === null || parseFloat(val) <= arg[1])) : null;
559 },
560
561 submitted: function(elem) {
562 return elem.form['nette-submittedBy'] === elem;
563 },
564
565 fileSize: function(elem, arg, val) {
566 if (window.FileList) {
567 for (var i = 0; i < val.length; i++) {
568 if (val[i].size > arg) {
569 return false;
570 }
571 }
572 }
573 return true;
574 },
575
576 mimeType: function (elem, arg, val) {
577 arg = Array.isArray(arg) ? arg : [arg];
578 for (var i = 0, len = arg.length, re = []; i < len; i++) {
579 re.push('^' + arg[i].replace(/([^\w])/g, '\\$1').replace('\\*', '.*') + '$');
580 }
581 re = new RegExp(re.join('|'));
582
583 if (window.FileList && val instanceof FileList) {
584 for (i = 0; i < val.length; i++) {
585 if (val[i].type && !re.test(val[i].type)) {
586 return false;
587 } else if (elem.validity.badInput) {
588 return null;
589 }
590 }
591 }
592 return true;
593 },
594
595 image: function (elem, arg, val) {
596 return Nette.validators.mimeType(elem, ['image/gif', 'image/png', 'image/jpeg', 'image/webp'], val);
597 },
598
599 'static': function (elem, arg) {
600 return arg;
601 }
602 };
603
604
605 /**
606 * Process all toggles in form.
607 */
608 Nette.toggleForm = function(form, event) {
609 var i;
610 formToggles = {};
611 for (i = 0; i < form.elements.length; i++) {
612 if (form.elements[i].tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
613 Nette.toggleControl(form.elements[i], null, null, !event);
614 }
615 }
616
617 for (i in formToggles) {
618 Nette.toggle(i, formToggles[i].state, formToggles[i].elem, event);
619 }
620 };
621
622
623 /**
624 * Process toggles on form element.
625 */
626 Nette.toggleControl = function(elem, rules, success, firsttime, value, emptyOptional) {
627 rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]');
628 value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
629 emptyOptional = emptyOptional === undefined ? !Nette.validateRule(elem, ':filled', null, value) : emptyOptional;
630
631 var has = false,
632 handler = function (e) {
633 Nette.toggleForm(elem.form, e);
634 },
635 curSuccess;
636
637 for (var id = 0, len = rules.length; id < len; id++) {
638 var rule = rules[id],
639 op = rule.op.match(/(~)?([^?]+)/),
640 curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
641
642 rule.neg = op[1];
643 rule.op = op[2];
644 rule.condition = !!rule.rules;
645
646 if (!curElem) {
647 continue;
648 } else if (emptyOptional && !rule.condition && rule.op !== ':filled') {
649 continue;
650 }
651
652 curSuccess = success;
653 if (success !== false) {
654 curSuccess = Nette.validateRule(curElem, rule.op, rule.arg, elem === curElem ? value : undefined);
655 if (curSuccess === null) {
656 continue;
657
658 } else if (rule.neg) {
659 curSuccess = !curSuccess;
660 }
661 if (!rule.condition) {
662 success = curSuccess;
663 }
664 }
665
666 if ((rule.condition && Nette.toggleControl(elem, rule.rules, curSuccess, firsttime, value, rule.op === ':blank' ? false : emptyOptional)) || rule.toggle) {
667 has = true;
668 if (firsttime) {
669 var name = curElem.tagName ? curElem.name : curElem[0].name,
670 els = curElem.tagName ? curElem.form.elements : curElem;
671
672 for (var i = 0; i < els.length; i++) {
673 if (els[i].name === name && !toggleListeners.has(els[i])) {
674 els[i].addEventListener('change', handler);
675 toggleListeners.set(els[i], null);
676 }
677 }
678 }
679 for (var toggleId in rule.toggle || []) {
680 formToggles[toggleId] = formToggles[toggleId] || {elem: elem};
681 formToggles[toggleId].state = formToggles[toggleId].state || (rule.toggle[toggleId] ? curSuccess : !curSuccess);
682 }
683 }
684 }
685 return has;
686 };
687
688
689 /**
690 * Displays or hides HTML element.
691 */
692 Nette.toggle = function(selector, visible, srcElement, event) { // eslint-disable-line no-unused-vars
693 if (/^\w[\w.:-]*$/.test(selector)) { // id
694 selector = '#' + selector;
695 }
696 var elems = document.querySelectorAll(selector);
697 for (var i = 0; i < elems.length; i++) {
698 elems[i].hidden = !visible;
699 }
700 };
701
702
703 /**
704 * Compact checkboxes
705 */
706 Nette.compactCheckboxes = function(form) {
707 var name, i, elem, values = {};
708
709 for (i = 0; i < form.elements.length; i++) {
710 elem = form.elements[i];
711 if (elem.tagName
712 && elem.tagName.toLowerCase() === 'input'
713 && elem.type === 'checkbox'
714 ) {
715 if (elem.name
716 && elem.name.substr(-2) === '[]'
717 ) {
718 name = elem.name.substr(0, elem.name.length - 2);
719 elem.removeAttribute('name');
720 elem.setAttribute('data-nette-name', name);
721 }
722
723 if (name = elem.getAttribute('data-nette-name')) { // eslint-disable-line no-cond-assign
724 values[name] = values[name] || [];
725 if (elem.checked && !elem.disabled) {
726 values[name].push(elem.value);
727 }
728 }
729 }
730 }
731
732 for (name in values) {
733 if (form.elements[name] === undefined) {
734 elem = document.createElement('input');
735 elem.setAttribute('name', name);
736 elem.setAttribute('type', 'hidden');
737 form.appendChild(elem);
738 }
739 form.elements[name].value = values[name].join(',');
740 form.elements[name].disabled = values[name].length === 0;
741 }
742 };
743
744
745 /**
746 * Setup handlers.
747 */
748 Nette.initForm = function(form) {
749 if (form.method === 'get' && form.hasAttribute('data-nette-compact')) {
750 form.addEventListener('submit', function() {
751 Nette.compactCheckboxes(form);
752 });
753 }
754
755 check: {
756 for (var i = 0; i < form.elements.length; i++) {
757 if (form.elements[i].getAttribute('data-nette-rules')) {
758 break check;
759 }
760 }
761 return;
762 }
763
764 Nette.toggleForm(form);
765
766 if (form.noValidate) {
767 return;
768 }
769 form.noValidate = true;
770
771 form.addEventListener('submit', function(e) {
772 if (!Nette.validateForm(form)) {
773 e.stopPropagation();
774 e.preventDefault();
775 }
776 });
777 };
778
779
780 /**
781 * @private
782 */
783 Nette.initOnLoad = function() {
784 Nette.onDocumentReady(function() {
785 for (var i = 0; i < document.forms.length; i++) {
786 Nette.initForm(document.forms[i]);
787 }
788
789 document.body.addEventListener('click', function(e) {
790 var target = e.target;
791 while (target) {
792 if (target.form && target.type in {submit: 1, image: 1}) {
793 target.form['nette-submittedBy'] = target;
794 break;
795 }
796 target = target.parentNode;
797 }
798 });
799 });
800 };
801
802
803 /**
804 * Converts string to web safe characters [a-z0-9-] text.
805 */
806 Nette.webalize = function(s) {
807 s = s.toLowerCase();
808 var res = '', i, ch;
809 for (i = 0; i < s.length; i++) {
810 ch = Nette.webalizeTable[s.charAt(i)];
811 res += ch ? ch : s.charAt(i);
812 }
813 return res.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
814 };
815
816 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'};
817
818 return Nette;
819 }));
820