|
20 | 20 | } else if (typeof module === 'object' && typeof module.exports === 'object') { |
21 | 21 | module.exports = factory(global); |
22 | 22 | } else { |
23 | | - let init = !global.Nette || !global.Nette.noInit; |
| 23 | + let init = !global.Nette?.noInit; |
24 | 24 | global.Nette = factory(global); |
25 | 25 | if (init) { |
26 | 26 | global.Nette.initOnLoad(); |
|
79 | 79 | * @return {*} |
80 | 80 | */ |
81 | 81 | Nette.getValue = function (elem) { |
82 | | - if (!elem) { |
83 | | - return null; |
84 | | - |
85 | | - } else if (!elem.tagName) { // RadioNodeList |
86 | | - return elem[0] ? Nette.getValue(elem[0]) : null; |
87 | | - |
88 | | - } else if (elem.type === 'radio') { |
89 | | - return expandRadioElement(elem) |
90 | | - .find((input) => input.checked) |
91 | | - ?.value ?? null; |
92 | | - |
93 | | - } else if (elem.type === 'file') { |
94 | | - return elem.files || elem.value; |
| 82 | + if (elem instanceof HTMLInputElement) { |
| 83 | + if (elem.type === 'radio') { |
| 84 | + return expandRadioElement(elem) |
| 85 | + .find((input) => input.checked) |
| 86 | + ?.value ?? null; |
| 87 | + |
| 88 | + } else if (elem.type === 'file') { |
| 89 | + return elem.files; |
| 90 | + |
| 91 | + } else if (elem.type === 'checkbox') { |
| 92 | + return elem.name.endsWith('[]') // checkbox list |
| 93 | + ? expandRadioElement(elem) |
| 94 | + .filter((input) => input.checked) |
| 95 | + .map((input) => input.value) |
| 96 | + : elem.checked; |
95 | 97 |
|
96 | | - } else if (elem.tagName.toLowerCase() === 'select') { |
97 | | - let index = elem.selectedIndex, |
98 | | - options = elem.options, |
99 | | - values = []; |
100 | | - |
101 | | - if (elem.type === 'select-one') { |
102 | | - return index < 0 ? null : options[index].value; |
103 | | - } |
104 | | - |
105 | | - for (let i = 0; i < options.length; i++) { |
106 | | - if (options[i].selected) { |
107 | | - values.push(options[i].value); |
108 | | - } |
| 98 | + } else { |
| 99 | + return elem.value.trim(); |
109 | 100 | } |
110 | | - return values; |
111 | 101 |
|
112 | | - } else if (elem.name && elem.name.endsWith('[]')) { // multiple elements [] |
113 | | - return expandRadioElement(elem) |
114 | | - .filter((input) => input.checked) |
115 | | - .map((input) => input.value); |
| 102 | + } else if (elem instanceof HTMLSelectElement) { |
| 103 | + return elem.multiple |
| 104 | + ? Array.from(elem.selectedOptions, (option) => option.value) |
| 105 | + : elem.selectedOptions[0]?.value ?? null; |
116 | 106 |
|
117 | | - } else if (elem.type === 'checkbox') { |
118 | | - return elem.checked; |
| 107 | + } else if (elem instanceof HTMLTextAreaElement) { |
| 108 | + return elem.value; |
119 | 109 |
|
120 | | - } else if (elem.tagName.toLowerCase() === 'textarea') { |
121 | | - return elem.value.replace('\r', ''); |
| 110 | + } else if (elem instanceof RadioNodeList) { |
| 111 | + return Nette.getValue(elem[0]); |
122 | 112 |
|
123 | 113 | } else { |
124 | | - return elem.value.replace('\r', '').replace(/^\s+|\s+$/g, ''); |
| 114 | + return null; |
125 | 115 | } |
126 | 116 | }; |
127 | 117 |
|
|
132 | 122 | * @param {boolean} filter |
133 | 123 | * @return {*} |
134 | 124 | */ |
135 | | - Nette.getEffectiveValue = function (elem, filter) { |
| 125 | + Nette.getEffectiveValue = function (elem, filter = false) { |
136 | 126 | let val = Nette.getValue(elem); |
137 | 127 | if (val === elem.getAttribute('data-nette-empty-value')) { |
138 | 128 | val = ''; |
|
157 | 147 | * @param {?boolean} emptyOptional |
158 | 148 | * @return {boolean} |
159 | 149 | */ |
160 | | - Nette.validateControl = function (elem, rules, onlyCheck, value, emptyOptional) { |
161 | | - rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]'); |
162 | | - value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value; |
163 | | - emptyOptional = emptyOptional === undefined ? !Nette.validateRule(elem, ':filled', null, value) : emptyOptional; |
164 | | - |
165 | | - for (let id = 0, len = rules.length; id < len; id++) { |
166 | | - let rule = rules[id], |
167 | | - op = rule.op.match(/(~)?([^?]+)/), |
| 150 | + Nette.validateControl = function (elem, rules, onlyCheck = false, value = null, emptyOptional = null) { |
| 151 | + rules ??= JSON.parse(elem.getAttribute('data-nette-rules') ?? '[]'); |
| 152 | + value ??= {value: Nette.getEffectiveValue(elem)}; |
| 153 | + emptyOptional ??= !Nette.validateRule(elem, ':filled', null, value); |
| 154 | + |
| 155 | + for (let rule of rules) { |
| 156 | + let op = rule.op.match(/(~)?([^?]+)/), |
168 | 157 | curElem = rule.control ? getFormElement(elem.form, rule.control) : elem; |
169 | 158 |
|
170 | 159 | rule.neg = op[1]; |
|
214 | 203 | * @param {boolean} onlyCheck |
215 | 204 | * @return {boolean} |
216 | 205 | */ |
217 | | - Nette.validateForm = function (sender, onlyCheck) { |
218 | | - let form = sender.form || sender, |
| 206 | + Nette.validateForm = function (sender, onlyCheck = false) { |
| 207 | + let form = sender.form ?? sender, |
219 | 208 | scope; |
220 | 209 |
|
221 | 210 | Nette.formErrors = []; |
222 | 211 |
|
223 | 212 | if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) { |
224 | | - let scopeArr = JSON.parse(form['nette-submittedBy'].getAttribute('data-nette-validation-scope') || '[]'); |
| 213 | + let scopeArr = JSON.parse(form['nette-submittedBy'].getAttribute('data-nette-validation-scope') ?? '[]'); |
225 | 214 | if (scopeArr.length) { |
226 | 215 | scope = new RegExp('^(' + scopeArr.join('-|') + '-)'); |
227 | 216 | } else { |
|
290 | 279 | let messages = [], |
291 | 280 | focusElem; |
292 | 281 |
|
293 | | - for (let i = 0; i < errors.length; i++) { |
294 | | - let elem = errors[i].element, |
295 | | - message = errors[i].message; |
296 | | - |
297 | | - if (messages.indexOf(message) < 0) { |
298 | | - messages.push(message); |
| 282 | + for (let error of errors) { |
| 283 | + if (messages.indexOf(error.message) < 0) { |
| 284 | + messages.push(error.message); |
299 | 285 |
|
300 | | - if (!focusElem && elem.focus) { |
301 | | - focusElem = elem; |
| 286 | + if (!focusElem && error.element.focus) { |
| 287 | + focusElem = error.element; |
302 | 288 | } |
303 | 289 | } |
304 | 290 | } |
|
357 | 343 | return op === ':filled'; |
358 | 344 | } |
359 | 345 |
|
360 | | - value = value === undefined ? {value: Nette.getEffectiveValue(elem, true)} : value; |
| 346 | + value ??= {value: Nette.getEffectiveValue(elem, true)}; |
361 | 347 |
|
362 | | - if (op.charAt(0) === ':') { |
363 | | - op = op.substring(1); |
364 | | - } |
365 | | - op = op.replace('::', '_'); |
366 | | - op = op.replace(/\\/g, ''); |
367 | | - |
368 | | - let arr = Array.isArray(arg) ? arg.slice(0) : [arg]; |
369 | | - for (let i = 0, len = arr.length; i < len; i++) { |
370 | | - if (arr[i] && arr[i].control) { |
371 | | - let control = getFormElement(elem.form, arr[i].control); |
372 | | - arr[i] = control === elem ? value.value : Nette.getEffectiveValue(control, true); |
| 348 | + let method = op.charAt(0) === ':' ? op.substring(1) : op; |
| 349 | + method = method.replace('::', '_').replaceAll('\\', ''); |
| 350 | + |
| 351 | + let args = Array.isArray(arg) ? arg : [arg]; |
| 352 | + args = args.map((arg) => { |
| 353 | + if (arg?.control) { |
| 354 | + let control = getFormElement(elem.form, arg.control); |
| 355 | + return control === elem ? value.value : Nette.getEffectiveValue(control, true); |
373 | 356 | } |
374 | | - } |
| 357 | + return arg; |
| 358 | + }); |
375 | 359 |
|
376 | | - return Nette.validators[op] |
377 | | - ? Nette.validators[op](elem, Array.isArray(arg) ? arr : arr[0], value.value, value) |
| 360 | + return Nette.validators[method] |
| 361 | + ? Nette.validators[method](elem, Array.isArray(arg) ? args : args[0], value.value, value) |
378 | 362 | : null; |
379 | 363 | }; |
380 | 364 |
|
|
410 | 394 | val = Array.isArray(val) ? val : [val]; |
411 | 395 | arg = Array.isArray(arg) ? arg : [arg]; |
412 | 396 | loop: |
413 | | - for (let i1 = 0, len1 = val.length; i1 < len1; i1++) { |
414 | | - for (let i2 = 0, len2 = arg.length; i2 < len2; i2++) { |
415 | | - if (toString(val[i1]) === toString(arg[i2])) { |
| 397 | + for (let a of val) { |
| 398 | + for (let b of arg) { |
| 399 | + if (toString(a) === toString(b)) { |
416 | 400 | continue loop; |
417 | 401 | } |
418 | 402 | } |
|
476 | 460 | regExp = new RegExp('^(?:' + arg + ')$', caseInsensitive ? 'i' : ''); |
477 | 461 | } |
478 | 462 |
|
479 | | - if (val instanceof FileList) { |
480 | | - for (let i = 0; i < val.length; i++) { |
481 | | - if (!regExp.test(val[i].name)) { |
482 | | - return false; |
483 | | - } |
484 | | - } |
485 | | - |
486 | | - return true; |
487 | | - } |
488 | | - |
489 | | - return regExp.test(val); |
| 463 | + return val instanceof FileList |
| 464 | + ? Array.from(val).every((file) => regExp.test(file.name)) |
| 465 | + : regExp.test(val); |
490 | 466 | } catch {} // eslint-disable-line no-empty |
491 | 467 | }, |
492 | 468 |
|
|
544 | 520 | }, |
545 | 521 |
|
546 | 522 | fileSize: function (elem, arg, val) { |
547 | | - for (let i = 0; i < val.length; i++) { |
548 | | - if (val[i].size > arg) { |
549 | | - return false; |
550 | | - } |
551 | | - } |
552 | | - return true; |
| 523 | + return Array.from(val).every((file) => file.size <= arg); |
553 | 524 | }, |
554 | 525 |
|
555 | | - mimeType: function (elem, arg, val) { |
| 526 | + mimeType: function (elem, args, val) { |
556 | 527 | let re = []; |
557 | | - arg = Array.isArray(arg) ? arg : [arg]; |
558 | | - for (let i = 0, len = arg.length; i < len; i++) { |
559 | | - re.push('^' + arg[i].replace(/([^\w])/g, '\\$1').replace('\\*', '.*') + '$'); |
560 | | - } |
| 528 | + args = Array.isArray(args) ? args : [args]; |
| 529 | + args.forEach((arg) => re.push('^' + arg.replace(/([^\w])/g, '\\$1').replace('\\*', '.*') + '$')); |
561 | 530 | re = new RegExp(re.join('|')); |
562 | | - |
563 | | - if (val instanceof FileList) { |
564 | | - for (let i = 0; i < val.length; i++) { |
565 | | - if (val[i].type && !re.test(val[i].type)) { |
566 | | - return false; |
567 | | - } else if (elem.validity.badInput) { |
568 | | - return null; |
569 | | - } |
570 | | - } |
571 | | - } |
572 | | - return true; |
| 531 | + return Array.from(val).every((file) => !file.type || re.test(file.type)); |
573 | 532 | }, |
574 | 533 |
|
575 | 534 | image: function (elem, arg, val) { |
576 | | - return Nette.validators.mimeType(elem, arg || ['image/gif', 'image/png', 'image/jpeg', 'image/webp'], val); |
| 535 | + return Nette.validators.mimeType(elem, arg ?? ['image/gif', 'image/png', 'image/jpeg', 'image/webp'], val); |
577 | 536 | }, |
578 | 537 |
|
579 | 538 | 'static': function (elem, arg) { |
|
587 | 546 | * @param {HTMLFormElement} form |
588 | 547 | * @param {?Event} event |
589 | 548 | */ |
590 | | - Nette.toggleForm = function (form, event) { |
| 549 | + Nette.toggleForm = function (form, event = null) { |
591 | 550 | formToggles = {}; |
592 | 551 | for (let elem of Array.from(form.elements)) { |
593 | 552 | if (elem.getAttribute('data-nette-rules')) { |
|
611 | 570 | * @param {?boolean} emptyOptional |
612 | 571 | * @return {boolean} |
613 | 572 | */ |
614 | | - Nette.toggleControl = function (elem, rules, success, firsttime, value, emptyOptional) { |
615 | | - rules = rules || JSON.parse(elem.getAttribute('data-nette-rules') || '[]'); |
616 | | - value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value; |
617 | | - emptyOptional = emptyOptional === undefined ? !Nette.validateRule(elem, ':filled', null, value) : emptyOptional; |
| 573 | + Nette.toggleControl = function (elem, rules, success, firsttime, value = null, emptyOptional = null) { |
| 574 | + rules ??= JSON.parse(elem.getAttribute('data-nette-rules') ?? '[]'); |
| 575 | + value ??= {value: Nette.getEffectiveValue(elem)}; |
| 576 | + emptyOptional ??= !Nette.validateRule(elem, ':filled', null, value); |
618 | 577 |
|
619 | 578 | let has = false, |
620 | | - handler = (e) => Nette.toggleForm(elem.form, e), |
621 | 579 | curSuccess; |
622 | 580 |
|
623 | | - for (let id = 0, len = rules.length; id < len; id++) { |
624 | | - let rule = rules[id], |
625 | | - op = rule.op.match(/(~)?([^?]+)/), |
| 581 | + for (let rule of rules) { |
| 582 | + let op = rule.op.match(/(~)?([^?]+)/), |
626 | 583 | curElem = rule.control ? getFormElement(elem.form, rule.control) : elem; |
627 | 584 |
|
628 | 585 | rule.neg = op[1]; |
|
655 | 612 | expandRadioElement(curElem) |
656 | 613 | .filter((el) => !toggleListeners.has(el)) |
657 | 614 | .forEach((el) => { |
658 | | - el.addEventListener('change', handler); |
| 615 | + el.addEventListener('change', (e) => Nette.toggleForm(elem.form, e)); |
659 | 616 | toggleListeners.set(el, null); |
660 | 617 | }); |
661 | 618 | } |
662 | | - for (let toggleId in rule.toggle || []) { |
663 | | - formToggles[toggleId] = formToggles[toggleId] || {elem: elem}; |
664 | | - formToggles[toggleId].state = formToggles[toggleId].state || (rule.toggle[toggleId] ? curSuccess : !curSuccess); |
| 619 | + for (let id in rule.toggle ?? []) { |
| 620 | + formToggles[id] ??= {elem: elem, state: rule.toggle[id] ? curSuccess : !curSuccess}; |
665 | 621 | } |
666 | 622 | } |
667 | 623 | } |
|
680 | 636 | if (/^\w[\w.:-]*$/.test(selector)) { // id |
681 | 637 | selector = '#' + selector; |
682 | 638 | } |
683 | | - let elems = document.querySelectorAll(selector); |
684 | | - for (let i = 0; i < elems.length; i++) { |
685 | | - elems[i].hidden = !visible; |
686 | | - } |
| 639 | + Array.from(document.querySelectorAll(selector)) |
| 640 | + .forEach((elem) => elem.hidden = !visible); |
687 | 641 | }; |
688 | 642 |
|
689 | 643 |
|
|
718 | 672 | form.addEventListener('formdata', (e) => Nette.compactCheckboxes(form, e.formData)); |
719 | 673 | } |
720 | 674 |
|
721 | | - check: { |
722 | | - for (let i = 0; i < form.elements.length; i++) { |
723 | | - if (form.elements[i].getAttribute('data-nette-rules')) { |
724 | | - break check; |
725 | | - } |
726 | | - } |
| 675 | + if (!Array.from(form.elements).some((elem) => elem.getAttribute('data-nette-rules'))) { |
727 | 676 | return; |
728 | 677 | } |
729 | 678 |
|
|
752 | 701 | */ |
753 | 702 | Nette.initOnLoad = function () { |
754 | 703 | Nette.onDocumentReady(() => { |
755 | | - for (let i = 0; i < document.forms.length; i++) { |
756 | | - Nette.initForm(document.forms[i]); |
757 | | - } |
| 704 | + Array.from(document.forms) |
| 705 | + .forEach((form) => Nette.initForm(form)); |
758 | 706 |
|
759 | 707 | document.body.addEventListener('click', (e) => { |
760 | 708 | let target = e.target; |
|
0 commit comments