1//Variablen aus header_global_js.elem.php 2/** @var string formValidationError */ 3/** @var string formValidationErrorDateTooOld */ 4/** @var string formValidationErrorDateTooYoung */ 5 6 7$(document).ready(function () { 8 const $form = $('.defaultform'); 9 let liveValidationActive = false; 10 // Alle Eingabefelder im Formular auswählen 11 $form.find('input:not(.validate-fields)').on('keypress', function (event) { 12 if (event.key === 'Enter') { 13 event.preventDefault(); 14 } 15 }); 16 17 function validateField($input) { 18 const element = $input.get(0); 19 const type = $input.attr('type'); 20 const name = $input.attr('name'); 21 const isCheckboxOrRadio = type === 'radio' || type === 'checkbox'; 22 const isFile = type === 'file'; 23 let valueValid = true; 24 let errorType = ''; 25 26 if (isCheckboxOrRadio) { 27 valueValid = $form.find(`input[name="${name}"]:checked`).length > 0; 28 } else if (isFile) { 29 valueValid = $input.get(0).files.length > 0; 30 } else { 31 valueValid = $input.get(0).checkValidity(); 32 33 // IBAN prüfen 34 if (valueValid && $input.hasClass('validation-iban')) { 35 valueValid = isValidGermanIban(element.value); 36 37 if (!valueValid) { 38 errorType = 'ibanChecksumInvalid'; 39 } 40 } 41 if (!valueValid && !errorType) { 42 const v = element.validity; 43 44 if (v.valueMissing) errorType = 'valueMissing'; 45 else if (v.patternMismatch) errorType = 'patternMismatch'; 46 else if (v.rangeUnderflow) errorType = 'rangeUnderflow'; 47 else if (v.rangeOverflow) errorType = 'rangeOverflow'; 48 else errorType = 'invalid'; 49 } 50 } 51 52 const $container = $input.closest('.form-row, fieldset'); 53 let $label; 54 55 if (isCheckboxOrRadio) { 56 $label = $container.find('legend'); 57 58 } else if (isFile) { 59 const cleanName = name.replace(/\[\]$/, ''); 60 $label = $container.find(`label[for="${cleanName}"]`); 61 } else { 62 $label = $container.find(`label[for="${$input.attr('id')}"]`); 63 } 64 65 if (valueValid) { 66 $input.removeClass('error').removeAttr('aria-invalid'); 67 if (isCheckboxOrRadio) { 68 let container = $($input.parents('.form-row').first()); 69 $(container).find('input').removeClass('error').removeAttr('aria-invalid'); 70 } 71 if ($label.length && $label.data('original')) { 72 $label.text($label.data('original')); 73 } 74 } else { 75 if ($label.length && !$label.data('original')) { 76 $label.data('original', $label.text()); 77 } 78 let errorMsg = formValidationError; 79 if (errorType === 'rangeUnderflow') { 80 errorMsg = formValidationErrorDateTooOld; 81 } 82 if (errorType === 'rangeOverflow') { 83 errorMsg = formValidationErrorDateTooYoung; 84 } 85 if (errorType === 'ibanChecksumInvalid') { 86 errorMsg = formValidationErrorIbanChecksumInvalid; 87 } 88 89 if ($label.length) { 90 $label.text(`${$label.data('original')} â ${errorMsg}`); 91 } 92 93 $input.addClass('error').attr('aria-invalid', 'true'); 94 } 95 96 return valueValid; 97 } 98 99 function validateDate($input) { 100 const element = $input.get(0); 101 let valueValid = true; 102 let errorType = ''; 103 104 105 valueValid = $input.get(0).checkValidity(); 106 107 if (!valueValid) { 108 const v = element.validity; 109 110 if (v.rangeUnderflow) errorType = 'rangeUnderflow'; 111 else if (v.rangeOverflow) errorType = 'rangeOverflow'; 112 } 113 114 115 const $container = $input.closest('.form-row, fieldset'); 116 let $label; 117 118 $label = $container.find(`label[for="${$input.attr('id')}"]`); 119 120 121 if (valueValid) { 122 $input.removeClass('error').removeAttr('aria-invalid'); 123 if ($label.length && $label.data('original')) { 124 $label.text($label.data('original')); 125 } 126 } else { 127 if ($label.length && !$label.data('original')) { 128 $label.data('original', $label.text()); 129 } 130 let errorMsg = formValidationError; 131 if (errorType === 'rangeUnderflow') { 132 errorMsg = formValidationErrorDateTooOld; 133 } 134 if (errorType === 'rangeOverflow') { 135 errorMsg = formValidationErrorDateTooYoung; 136 } 137 138 if ($label.length) { 139 $label.text(`${$label.data('original')} â ${errorMsg}`); 140 } 141 142 $input.addClass('error').attr('aria-invalid', 'true'); 143 } 144 145 return valueValid; 146 } 147 148 $form.find('.validate-fields').on('click', function (e) { 149 let isValid = true; 150 151 // Fehler zurücksetzen 152 $form.find('.form-row').each(function () { 153 const $container = $(this); 154 const $input = $container.find('input, select, textarea').first(); 155 const isCheckboxOrRadio = $input.is(':checkbox') || $input.is(':radio'); 156 const isFile = $input.is('[type="file"]'); 157 158 let $label; 159 if (isCheckboxOrRadio) { 160 $label = $container.find('legend'); 161 $container.find('input').removeClass('error').removeAttr('aria-invalid'); 162 } else if (isFile) { 163 $label = $container.find(`label[for="${$container.find('.filepond--root').attr('id')}"]`); 164 $input.removeClass('error').removeAttr('aria-invalid'); 165 } else { 166 $label = $container.find(`label[for="${$input.attr('id')}"]`); 167 $input.removeClass('error').removeAttr('aria-invalid'); 168 } 169 170 if ($label.length && $label.data('original')) { 171 $label.text($label.data('original')); 172 } 173 }); 174 175 // Validierung aller required Felder 176 $form.find('input[required], select[required], textarea[required]').each(function () { 177 if (!validateField($(this))) { 178 isValid = false; 179 } 180 }); 181 182 // Ãberprüfung für korrekte Angabe von Date-Feldern die nicht wegen required gecheckt wurden 183 $form.find('input[type="date"]:not([required])').each(function () { 184 if (!validateDate($(this))) { 185 isValid = false; 186 } 187 }); 188 189 // Live-Validierung aktivieren nach dem ersten Klick 190 if (!liveValidationActive) { 191 liveValidationActive = true; 192 $form.on('blur change', 'input[required], select[required], textarea[required]', function () { 193 if (liveValidationActive) { 194 validateField($(this)); 195 } 196 }); 197 198 $form.on('blur change', 'input[type="date"]:not([required])', function () { 199 if (liveValidationActive) { 200 validateDate($(this)); 201 } 202 }); 203 } 204 205 let buttonIsSubmit = $(this).is('button[type="submit"], input[type="submit"]'); 206 if (!isValid && !buttonIsSubmit) { 207 $('.error').first().focus(); 208 } 209 210 211 // Wenn du ein tatsächliches `submit` verhindern willst, kannst du hier `e.preventDefault()` verwenden 212 // if (!isValid) e.preventDefault(); 213 });
214}); 215 216function isValidGermanIban(value) { 217 const iban = value.replace(/\s+/g, '').toUpperCase(); 218 219 // Deutsche IBAN: DE + 2 Prüfziffern + 18 Ziffern = 22 Zeichen 220 if (!/^DE\d{20}$/.test(iban)) { 221 return false; 222 } 223 224 // IBAN-Prüfung: 225 // 1. Erste 4 Zeichen nach hinten 226 // 2. Buchstaben in Zahlen umwandeln: A=10, B=11, ..., Z=35 227 const rearranged = iban.slice(4) + iban.slice(0, 4); 228 229 const numeric = rearranged.replace(/[A-Z]/g, char => { 230 return String(char.charCodeAt(0) - 55); 231 }); 232 233 // Modulo 97 iterativ berechnen, weil die Zahl zu groà für JS Number ist 234 let remainder = 0; 235 236 for (const digit of numeric) { 237 remainder = (remainder * 10 + Number(digit)) % 97; 238 } 239 return remainder === 1; 240}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.