1(function (global) { 2 'use strict'; 3 4 var RULES = { 5 name: { min: 2, max: 70 }, 6 subject: { min: 10, max: 100 }, 7 message: { min: 20, max: 1500 } 8 }; 9 10 var FIELD_LABELS = { 11 name: 'Name', 12 subject: 'Subject', 13 message: 'Message' 14 }; 15 16 var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 17 18 function getRule(fieldName, overrides) { 19 var baseRule = RULES[fieldName] || {}; 20 var overrideRule = overrides && overrides[fieldName] ? overrides[fieldName] : {}; 21 22 return { 23 min: typeof overrideRule.min === 'number' ? overrideRule.min : baseRule.min, 24 max: typeof overrideRule.max === 'number' ? overrideRule.max : baseRule.max 25 }; 26 } 27 28 function toText(value) { 29 if (value === null || value === undefined) { 30 return ''; 31 } 32 return String(value).trim(); 33 } 34 35 function inRange(value, min, max) { 36 var len = toText(value).length; 37 return len >= min && len <= max; 38 } 39 40 function validateName(value, ruleOverrides) { 41 var text = toText(value); 42 var rule = getRule('name', ruleOverrides); 43 44 if (!inRange(text, rule.min, rule.max)) { 45 return 'Name: ' + rule.min + ' and ' + rule.max + ' characters.'; 46 } 47 return ''; 48 } 49 50 function validateEmail(value) { 51 var text = toText(value); 52 if (!EMAIL_REGEX.test(text)) { 53 return 'Please enter a valid email address.'; 54 } 55 return ''; 56 } 57 58 function validateSubject(value, required, ruleOverrides) { 59 var text = toText(value); 60 var rule = getRule('subject', ruleOverrides); 61 62 if (!required && text.length === 0) { 63 return ''; 64 } 65 if (!inRange(text, rule.min, rule.max)) { 66 return 'Subject: ' + rule.min + ' and ' + rule.max + ' characters.'; 67 } 68 return ''; 69 } 70 71 function validateMessage(value, ruleOverrides) { 72 var text = toText(value); 73 var rule = getRule('message', ruleOverrides); 74 75 if (!inRange(text, rule.min, rule.max)) { 76 return 'Message: ' + rule.min + ' and ' + rule.max + ' characters.'; 77 } 78 return ''; 79 } 80 81 function getLimitMessage(fieldName, value, ruleOverrides) { 82 var fieldRule = getRule(fieldName, ruleOverrides); 83 var fieldLabel = FIELD_LABELS[fieldName]; 84 var text = toText(value); 85 86 if (!fieldRule || !fieldRule.max || !fieldLabel) { 87 return ''; 88 } 89 90 if (text.length >= fieldRule.max) { 91 return fieldLabel + ' character limit reached (' + fieldRule.max + ').'; 92 } 93 94 return ''; 95 } 96 97 function validateForm(values, options) { 98 var opts = options || {}; 99 var subjectRequired = !!opts.subjectRequired; 100 var ruleOverrides = opts.ruleOverrides || {}; 101 102 var errors = { 103 name: validateName(values && values.name, ruleOverrides), 104 email: validateEmail(values && values.email), 105 subject: validateSubject(values && values.subject, subjectRequired, ruleOverrides), 106 message: validateMessage(values && values.message, ruleOverrides) 107 }; 108 109 var isValid = !errors.name && !errors.email && !errors.subject && !errors.message; 110 111 return { 112 isValid: isValid, 113 errors: errors, 114 rules: { 115 name: getRule('name', ruleOverrides), 116 subject: getRule('subject', ruleOverrides), 117 message: getRule('message', ruleOverrides) 118 } 119 }; 120 } 121 122 function getElement(selectorOrElement) { 123 if (!selectorOrElement) { 124 return null; 125 } 126 127 if (typeof selectorOrElement === 'string') { 128 return document.querySelector(selectorOrElement); 129 } 130 131 return selectorOrElement; 132 } 133 134 function setFieldError(fieldSelector, errorSelector, message) { 135 var field = getElement(fieldSelector); 136 var error = getElement(errorSelector); 137 138 if (field) { 139 field.classList.add('field-error'); 140 } 141 142 if (error) { 143 error.textContent = message || ''; 144 error.style.display = message ? 'block' : 'none'; 145 } 146 } 147 148 function clearFieldError(fieldSelector, errorSelector) { 149 var field = getElement(fieldSelector); 150 var error = getElement(errorSelector); 151 152 if (field) { 153 field.classList.remove('field-error'); 154 } 155 156 if (error) { 157 error.textContent = ''; 158 error.style.display = 'none'; 159 } 160 } 161 162 function clearErrors(fieldMap) { 163 Object.keys(fieldMap || {}
163).forEach(function (key) { 164 clearFieldError(fieldMap[key].field, fieldMap[key].error); 165 }); 166 } 167 168 function hasErrors(errors) { 169 return Object.keys(errors || {}).some(function (key) { 170 return !!errors[key]; 171 }); 172 } 173 174 function focusFirstInvalidField(fieldOrder, fieldMap, errors) { 175 var order = fieldOrder || []; 176 177 for (var index = 0; index < order.length; index += 1) { 178 var key = order[index]; 179 if (errors && errors[key]) { 180 var field = fieldMap && fieldMap[key] ? getElement(fieldMap[key].field) : null; 181 if (field && typeof field.focus === 'function') { 182 field.focus(); 183 } 184 return; 185 } 186 } 187 } 188 189 function bindFieldClearOnInput(fieldMap) { 190 Object.keys(fieldMap || {}).forEach(function (key) { 191 var config = fieldMap[key]; 192 var field = getElement(config.field); 193 194 if (!field) { 195 return; 196 } 197 198 ['input', 'change', 'keydown'].forEach(function (eventName) { 199 field.addEventListener(eventName, function () { 200 clearFieldError(config.field, config.error); 201 }); 202 }); 203 }); 204 } 205 206 function autoResizeTextarea(element) { 207 if (!element) return; 208 209 element.style.minHeight = '70px'; 210 element.style.height = 'auto'; 211 element.style.height = Math.max(element.scrollHeight, 70) + 'px'; 212 } 213 214 function initTextareaAutoResize(selector) { 215 var textareas = document.querySelectorAll(selector); 216 217 textareas.forEach(function(textarea) { 218 textarea.style.minHeight = '70px'; 219 textarea.style.overflowY = 'hidden'; 220 textarea.style.resize = 'none'; 221 222 // Auto-resize on input 223 textarea.addEventListener('input', function() { 224 autoResizeTextarea(this); 225 }); 226 227 // Initial resize 228 autoResizeTextarea(textarea); 229 }); 230 } 231 232 global.CommonFormValidation = { 233 rules: RULES, 234 validateName: validateName, 235 validateEmail: validateEmail, 236 validateSubject: validateSubject, 237 validateMessage: validateMessage, 238 getLimitMessage: getLimitMessage, 239 validateForm: validateForm, 240 setFieldError: setFieldError, 241 clearFieldError: clearFieldError, 242 clearErrors: clearErrors, 243 hasErrors: hasErrors, 244 focusFirstInvalidField: focusFirstInvalidField, 245 bindFieldClearOnInput: bindFieldClearOnInput, 246 autoResizeTextarea: autoResizeTextarea, 247 initTextareaAutoResize: initTextareaAutoResize 248 }; 249})(window);
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.